Name | pgdelta JSON |
Version |
0.1.0
JSON |
| download |
home_page | None |
Summary | PostgreSQL schema differ and DDL generator |
upload_time | 2025-07-18 14:52:17 |
maintainer | None |
docs_url | None |
author | Oliver Rice |
requires_python | >=3.13 |
license | Apache-2.0 |
keywords |
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# pgdelta
[](https://github.com/olirice/pgdelta/actions/workflows/ci.yml)
[](https://github.com/olirice/pgdelta/actions/workflows/security.yml)
[](https://coveralls.io/github/olirice/pgdelta?branch=master)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/Apache-2.0)
[](https://github.com/psf/black)
[](https://github.com/astral-sh/ruff)
A PostgreSQL schema differ and DDL generator that produces high-fidelity schema migrations.
## Development Status
**pgdelta is currently in early development (v0.1.0).**
## Feature Support Matrix
### Schemas
- ✅ **CREATE SCHEMA** - Basic schema creation
- ✅ **DROP SCHEMA** - Schema deletion
- ❌ **ALTER SCHEMA** - Schema modifications (planned)
- ❌ Owner to (planned)
- ✅ Rename (not applicable)
### Tables
- ✅ **CREATE TABLE** - Basic table creation
- ✅ Column definitions with data types
- ✅ NOT NULL constraints
- ✅ DEFAULT expressions
- ✅ Generated columns (GENERATED ALWAYS AS)
- ✅ Table inheritance (INHERITS)
- ✅ Storage parameters (WITH clause)
- ❌ Column STORAGE/COMPRESSION settings (not planned)
- ❌ Column COLLATE settings (not planned)
- ❌ LIKE clause (not planned)
- ❌ PARTITION BY clause (not planned)
- ❌ TABLESPACE clause (not planned)
- ❌ TEMPORARY/UNLOGGED tables (not applicable)
- ✅ **DROP TABLE** - Table deletion
- ✅ **ALTER TABLE** - Table modifications (partial)
- ✅ ADD COLUMN (with NOT NULL, DEFAULT)
- ✅ DROP COLUMN
- ✅ ALTER COLUMN TYPE (with USING expression)
- ✅ ALTER COLUMN SET/DROP DEFAULT
- ✅ ALTER COLUMN SET/DROP NOT NULL
- ❌ Table/column renaming (not planned - uses drop/recreate)
- ❌ RENAME TO (not planned - uses drop/recreate)
- ❌ SET SCHEMA (not planned - uses drop/recreate)
### Constraints
- ✅ **Primary Keys** - CREATE constraint
- ✅ **Unique Constraints** - CREATE constraint
- ✅ Multi-column unique constraints
- ✅ Partial unique constraints (WHERE clause)
- ✅ **Check Constraints** - CREATE constraint
- ✅ **Foreign Keys** - CREATE constraint
- ✅ Multi-column foreign keys
- ✅ ON DELETE/UPDATE actions (CASCADE, RESTRICT, SET NULL, SET DEFAULT)
- ✅ Constraint deferrability options
- ✅ **Exclusion Constraints** - CREATE constraint (basic)
- ✅ **DROP CONSTRAINT** - Constraint deletion
- ❌ **ALTER CONSTRAINT** - Constraint modifications (planned)
- ❌ **VALIDATE CONSTRAINT** - Constraint validation (planned)
### Indexes
- ✅ **CREATE INDEX** - Complete index creation
- ✅ Unique indexes
- ✅ Partial indexes (WHERE clause)
- ✅ Functional indexes (expressions)
- ✅ Multi-column indexes
- ✅ All index methods (btree, hash, gin, gist, etc.)
- ✅ Custom operator classes
- ✅ ASC/DESC ordering
- ✅ NULLS FIRST/LAST
- ❌ CONCURRENTLY option (not applicable)
- ✅ **DROP INDEX** - Index deletion
- ❌ **ALTER INDEX** - Index modifications (planned)
- ❌ **REINDEX** - Index rebuilding (not applicable)
### Views
- ✅ **CREATE VIEW** - Basic view creation
- ✅ Schema-qualified names
- ✅ View definition (AS query)
- ❌ RECURSIVE views (planned)
- ❌ Explicit column names (planned)
- ❌ WITH CHECK OPTION (planned)
- ✅ **DROP VIEW** - View deletion
- ✅ **CREATE OR REPLACE VIEW** - View replacement
- ❌ **ALTER VIEW** - View modifications (planned)
### Materialized Views
- ✅ **CREATE MATERIALIZED VIEW** - Materialized view creation
- ✅ **DROP MATERIALIZED VIEW** - Materialized view deletion
- ❌ **ALTER MATERIALIZED VIEW** - Materialized view modifications (planned)
- ❌ **REFRESH MATERIALIZED VIEW** - Not applicable for DDL
### Functions & Procedures
- ✅ **CREATE FUNCTION** - Function creation
- ✅ **CREATE PROCEDURE** - Procedure creation
- ✅ **DROP FUNCTION** - Function deletion
- ✅ **DROP PROCEDURE** - Procedure deletion
- ✅ **CREATE OR REPLACE FUNCTION** - Function replacement
- ❌ **ALTER FUNCTION** - Function modifications (planned)
- ❌ **ALTER PROCEDURE** - Procedure modifications (planned)
### Triggers
- ✅ **CREATE TRIGGER** - Trigger creation
- ✅ **DROP TRIGGER** - Trigger deletion
- ❌ **ALTER TRIGGER** - Trigger modifications (planned)
- ❌ **ENABLE/DISABLE TRIGGER** - Not applicable for DDL
### Sequences
- ✅ **CREATE SEQUENCE** - Sequence creation
- ✅ **DROP SEQUENCE** - Sequence deletion
- ✅ **ALTER SEQUENCE OWNED BY** - Sequence ownership
- ❌ **ALTER SEQUENCE** - Sequence modifications (planned)
### Types & Domains
- ✅ **CREATE TYPE** - Custom type creation (enums, composites)
- ✅ **DROP TYPE** - Type deletion
- ❌ **CREATE DOMAIN** - Domain creation (planned)
- ❌ **DROP DOMAIN** - Domain deletion (planned)
- ❌ **ALTER TYPE** - Type modifications (planned)
- ❌ **ALTER DOMAIN** - Domain modifications (planned)
### Security & Access Control
- ✅ **Row Level Security** - RLS policies
- ✅ **CREATE POLICY** - Policy creation
- ✅ **DROP POLICY** - Policy deletion
- ✅ **ALTER POLICY** - Policy modifications
- 🚫 **CREATE ROLE** - Role creation (environment-specific)
- 🚫 **GRANT/REVOKE** - Privilege management (environment-specific)
- 🚫 **ALTER DEFAULT PRIVILEGES** - Default privilege management (environment-specific)
### Other Features
- ❌ **Comments** - Object comments (not planned)
- ❌ **Event Triggers** - Event trigger support (not planned)
- ❌ **Extensions** - Extension management (not planned)
- ✅ **Dependency Resolution** - Automatic DDL ordering
- ✅ **Roundtrip Fidelity** - Extract → Diff → Generate → Apply cycles
**Note**: Extensions are not supported because they are environment-specific and require installation on the target database. pgdelta focuses on portable schema definitions that can be applied across different PostgreSQL environments.
The project focuses on schema structure diffing and DDL generation with comprehensive support for PostgreSQL objects including tables, constraints, indexes, views, functions, triggers, sequences, types, and RLS policies.
## Architecture
pgdelta uses a **three-phase approach** designed for correctness and testability:
### Phase 1: Extract
- **SQL-only access**: Database connections used exclusively during extraction
- **Immutable snapshots**: One-time catalog extraction into frozen dataclasses
- **Field metadata**: Distinguishes identity, data, and internal fields for semantic comparison
### Phase 2: Diff
- **Semantic comparison**: Uses field metadata to compare objects based on identity and data fields
- **Change detection**: Identifies create, drop, and alter operations
- **Pure comparison**: No database access, operates on immutable snapshots
### Phase 3: Generate
- **Pure functions**: SQL generation from change objects with no side effects
- **Deterministic output**: Same input always produces identical DDL
- **Type-safe**: Complete mypy coverage with structural pattern matching
- **Dependency resolution**: Constraint-based dependency ordering using NetworkX
### Testing Strategy
- **Roundtrip fidelity**: Generic integration tests that verify `Extract(DB) → Diff → Generate(SQL) → Apply(SQL) → Extract(DB)` produces semantically identical catalogs
- **Real PostgreSQL**: All tests use actual PostgreSQL instances via testcontainers
## Technical Decisions
- **Pure Functions**: All core logic uses pure functions with no side effects
- **Immutable Data**: Extract once, operate on immutable snapshots
- **Dependency Resolution**: Constraint-based dependency ordering using NetworkX
- **Type Safety**: Complete type safety with mypy and structural pattern matching
- **Roundtrip Fidelity**: Generates DDL that recreates schemas exactly
## Installation
**Note**: pgdelta is not yet published to PyPI. Install from source:
```bash
git clone https://github.com/olirice/pgdelta.git
cd pgdelta
pip install -e ".[dev]"
```
## Usage
### Python API
```python
from pgdelta import PgCatalog, generate_sql
from pgdelta.catalog import extract_catalog
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
# Connect to databases
source_engine = create_engine("postgresql://user:pass@localhost/source_db")
target_engine = create_engine("postgresql://user:pass@localhost/target_db")
with Session(source_engine) as source_session, Session(target_engine) as target_session:
# Extract schemas
source_catalog = extract_catalog(source_session)
target_catalog = extract_catalog(target_session)
# Generate migration from target to source
changes = target_catalog.diff(source_catalog)
# Generate SQL statements
sql_statements = [generate_sql(change) for change in changes]
for sql in sql_statements:
print(sql)
```
### Example Output
```sql
CREATE SCHEMA "analytics";
CREATE TABLE "analytics"."user_stats" (
"user_id" integer,
"post_count" integer DEFAULT 0,
"last_login" timestamp without time zone
);
```
## Development Setup
### Prerequisites
- Python 3.13+
- Docker (for running PostgreSQL test containers)
### Setup Instructions
1. **Clone the repository**
```bash
git clone https://github.com/olirice/pgdelta.git
cd pgdelta
```
2. **Create and activate a virtual environment**
```bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
```
3. **Install in editable mode with development dependencies**
```bash
pip install -e ".[dev]"
```
4. **Install pre-commit hooks**
```bash
pre-commit install
```
### Running Tests
The project uses pytest with real PostgreSQL databases via testcontainers:
```bash
# Run all tests
pytest
# Run tests in parallel (faster)
pytest -n auto
# Run specific test categories
pytest tests/unit/ # Unit tests only
pytest tests/integration/ # Integration tests only
# Run tests with coverage
pytest --cov=src/pgdelta --cov-report=html
# Run a specific test
pytest tests/unit/test_sql_generation.py::test_create_schema_basic
```
### Development Tools
```bash
# Type checking
mypy src/pgdelta
# Linting and formatting
ruff check
ruff format
# Run all pre-commit hooks
pre-commit run --all-files
```
### Test Requirements
- **Docker**: Required for PostgreSQL test containers
- **PostgreSQL 17**: Automatically managed via testcontainers
- **Real Database Testing**: All tests use real PostgreSQL instances, not mocks
## CI/CD
The project includes comprehensive GitHub Actions workflows:
- **CI Pipeline** (`ci.yml`): Runs pre-commit checks and tests on every push/PR
- **Security Scanning** (`security.yml`): Dependency and security analysis
- **Automated Releases** (`release.yml`): Builds and publishes to PyPI on tag push
All workflows use the latest action versions and follow security best practices with minimal permissions.
## Architecture Details
### Model Design
PostgreSQL catalog models are simplified and optimized for DDL generation:
- **Immutable dataclasses**: All models use `@dataclass(frozen=True)` for immutability
- **Essential fields only**: Only fields necessary for DDL generation are included
- **Stable identifiers**: Cross-database portable identifiers using stable_id (no pg_depend_id required)
- **Type safety**: Complete type annotations with mypy compliance
### Field Metadata System
Uses dataclass field metadata to categorize fields with wrapper functions:
- `identity()`: Fields that identify the object (used in semantic comparison)
- `data()`: Fields that represent object data (used in semantic comparison)
- `internal()`: Fields needed for dependency resolution (ignored in semantic comparison)
The wrapper functions generate the appropriate metadata dictionaries, making field categorization cleaner and more maintainable.
## Roadmap
### Phase 1 (Current - v0.1.x)
- ✅ Comprehensive schema and table DDL generation
- ✅ All constraint types (primary keys, foreign keys, unique, check, exclusion)
- ✅ Complete index support (all types, partial, functional)
- ✅ Views and materialized views
- ✅ Functions and triggers
- ✅ Sequences with ownership tracking
- ✅ Custom types (enums, composites)
- ✅ RLS policies
- ✅ Advanced dependency resolution
- ✅ Roundtrip fidelity
- ✅ CLI interface
### Phase 2 (v0.2.x)
- 🔄 ALTER operations for constraints and indexes
- 🔄 Domain types
- 🔄 Enhanced materialized view support
- 🔄 Advanced function features
### Phase 3 (v0.3.x)
- 🔄 Partitioning support
- 🔄 Performance optimizations
- 🔄 Streaming processing for large schemas
## License
Apache 2.0 - see [LICENSE](LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "pgdelta",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.13",
"maintainer_email": null,
"keywords": null,
"author": "Oliver Rice",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/68/92/08e8560440054c1558bf623c0719622aa92ba2fff22cf871a05b98c1e312/pgdelta-0.1.0.tar.gz",
"platform": null,
"description": "# pgdelta\n\n[](https://github.com/olirice/pgdelta/actions/workflows/ci.yml)\n[](https://github.com/olirice/pgdelta/actions/workflows/security.yml)\n[](https://coveralls.io/github/olirice/pgdelta?branch=master)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/Apache-2.0)\n[](https://github.com/psf/black)\n[](https://github.com/astral-sh/ruff)\n\nA PostgreSQL schema differ and DDL generator that produces high-fidelity schema migrations.\n\n## Development Status\n\n**pgdelta is currently in early development (v0.1.0).**\n\n## Feature Support Matrix\n\n### Schemas\n- \u2705 **CREATE SCHEMA** - Basic schema creation\n- \u2705 **DROP SCHEMA** - Schema deletion\n- \u274c **ALTER SCHEMA** - Schema modifications (planned)\n - \u274c Owner to (planned)\n - \u2705 Rename (not applicable)\n\n### Tables\n- \u2705 **CREATE TABLE** - Basic table creation\n - \u2705 Column definitions with data types\n - \u2705 NOT NULL constraints\n - \u2705 DEFAULT expressions\n - \u2705 Generated columns (GENERATED ALWAYS AS)\n - \u2705 Table inheritance (INHERITS)\n - \u2705 Storage parameters (WITH clause)\n - \u274c Column STORAGE/COMPRESSION settings (not planned)\n - \u274c Column COLLATE settings (not planned)\n - \u274c LIKE clause (not planned)\n - \u274c PARTITION BY clause (not planned)\n - \u274c TABLESPACE clause (not planned)\n - \u274c TEMPORARY/UNLOGGED tables (not applicable)\n- \u2705 **DROP TABLE** - Table deletion\n- \u2705 **ALTER TABLE** - Table modifications (partial)\n - \u2705 ADD COLUMN (with NOT NULL, DEFAULT)\n - \u2705 DROP COLUMN\n - \u2705 ALTER COLUMN TYPE (with USING expression)\n - \u2705 ALTER COLUMN SET/DROP DEFAULT\n - \u2705 ALTER COLUMN SET/DROP NOT NULL\n - \u274c Table/column renaming (not planned - uses drop/recreate)\n - \u274c RENAME TO (not planned - uses drop/recreate)\n - \u274c SET SCHEMA (not planned - uses drop/recreate)\n\n### Constraints\n- \u2705 **Primary Keys** - CREATE constraint\n- \u2705 **Unique Constraints** - CREATE constraint\n - \u2705 Multi-column unique constraints\n - \u2705 Partial unique constraints (WHERE clause)\n- \u2705 **Check Constraints** - CREATE constraint\n- \u2705 **Foreign Keys** - CREATE constraint\n - \u2705 Multi-column foreign keys\n - \u2705 ON DELETE/UPDATE actions (CASCADE, RESTRICT, SET NULL, SET DEFAULT)\n - \u2705 Constraint deferrability options\n- \u2705 **Exclusion Constraints** - CREATE constraint (basic)\n- \u2705 **DROP CONSTRAINT** - Constraint deletion\n- \u274c **ALTER CONSTRAINT** - Constraint modifications (planned)\n- \u274c **VALIDATE CONSTRAINT** - Constraint validation (planned)\n\n### Indexes\n- \u2705 **CREATE INDEX** - Complete index creation\n - \u2705 Unique indexes\n - \u2705 Partial indexes (WHERE clause)\n - \u2705 Functional indexes (expressions)\n - \u2705 Multi-column indexes\n - \u2705 All index methods (btree, hash, gin, gist, etc.)\n - \u2705 Custom operator classes\n - \u2705 ASC/DESC ordering\n - \u2705 NULLS FIRST/LAST\n - \u274c CONCURRENTLY option (not applicable)\n- \u2705 **DROP INDEX** - Index deletion\n- \u274c **ALTER INDEX** - Index modifications (planned)\n- \u274c **REINDEX** - Index rebuilding (not applicable)\n\n### Views\n- \u2705 **CREATE VIEW** - Basic view creation\n - \u2705 Schema-qualified names\n - \u2705 View definition (AS query)\n - \u274c RECURSIVE views (planned)\n - \u274c Explicit column names (planned)\n - \u274c WITH CHECK OPTION (planned)\n- \u2705 **DROP VIEW** - View deletion\n- \u2705 **CREATE OR REPLACE VIEW** - View replacement\n- \u274c **ALTER VIEW** - View modifications (planned)\n\n### Materialized Views\n- \u2705 **CREATE MATERIALIZED VIEW** - Materialized view creation\n- \u2705 **DROP MATERIALIZED VIEW** - Materialized view deletion\n- \u274c **ALTER MATERIALIZED VIEW** - Materialized view modifications (planned)\n- \u274c **REFRESH MATERIALIZED VIEW** - Not applicable for DDL\n\n### Functions & Procedures\n- \u2705 **CREATE FUNCTION** - Function creation\n- \u2705 **CREATE PROCEDURE** - Procedure creation\n- \u2705 **DROP FUNCTION** - Function deletion\n- \u2705 **DROP PROCEDURE** - Procedure deletion\n- \u2705 **CREATE OR REPLACE FUNCTION** - Function replacement\n- \u274c **ALTER FUNCTION** - Function modifications (planned)\n- \u274c **ALTER PROCEDURE** - Procedure modifications (planned)\n\n### Triggers\n- \u2705 **CREATE TRIGGER** - Trigger creation\n- \u2705 **DROP TRIGGER** - Trigger deletion\n- \u274c **ALTER TRIGGER** - Trigger modifications (planned)\n- \u274c **ENABLE/DISABLE TRIGGER** - Not applicable for DDL\n\n### Sequences\n- \u2705 **CREATE SEQUENCE** - Sequence creation\n- \u2705 **DROP SEQUENCE** - Sequence deletion\n- \u2705 **ALTER SEQUENCE OWNED BY** - Sequence ownership\n- \u274c **ALTER SEQUENCE** - Sequence modifications (planned)\n\n### Types & Domains\n- \u2705 **CREATE TYPE** - Custom type creation (enums, composites)\n- \u2705 **DROP TYPE** - Type deletion\n- \u274c **CREATE DOMAIN** - Domain creation (planned)\n- \u274c **DROP DOMAIN** - Domain deletion (planned)\n- \u274c **ALTER TYPE** - Type modifications (planned)\n- \u274c **ALTER DOMAIN** - Domain modifications (planned)\n\n### Security & Access Control\n- \u2705 **Row Level Security** - RLS policies\n- \u2705 **CREATE POLICY** - Policy creation\n- \u2705 **DROP POLICY** - Policy deletion\n- \u2705 **ALTER POLICY** - Policy modifications\n- \ud83d\udeab **CREATE ROLE** - Role creation (environment-specific)\n- \ud83d\udeab **GRANT/REVOKE** - Privilege management (environment-specific)\n- \ud83d\udeab **ALTER DEFAULT PRIVILEGES** - Default privilege management (environment-specific)\n\n### Other Features\n- \u274c **Comments** - Object comments (not planned)\n- \u274c **Event Triggers** - Event trigger support (not planned)\n- \u274c **Extensions** - Extension management (not planned)\n- \u2705 **Dependency Resolution** - Automatic DDL ordering\n- \u2705 **Roundtrip Fidelity** - Extract \u2192 Diff \u2192 Generate \u2192 Apply cycles\n\n**Note**: Extensions are not supported because they are environment-specific and require installation on the target database. pgdelta focuses on portable schema definitions that can be applied across different PostgreSQL environments.\n\nThe project focuses on schema structure diffing and DDL generation with comprehensive support for PostgreSQL objects including tables, constraints, indexes, views, functions, triggers, sequences, types, and RLS policies.\n\n## Architecture\n\npgdelta uses a **three-phase approach** designed for correctness and testability:\n\n### Phase 1: Extract\n- **SQL-only access**: Database connections used exclusively during extraction\n- **Immutable snapshots**: One-time catalog extraction into frozen dataclasses\n- **Field metadata**: Distinguishes identity, data, and internal fields for semantic comparison\n\n### Phase 2: Diff\n- **Semantic comparison**: Uses field metadata to compare objects based on identity and data fields\n- **Change detection**: Identifies create, drop, and alter operations\n- **Pure comparison**: No database access, operates on immutable snapshots\n\n### Phase 3: Generate\n- **Pure functions**: SQL generation from change objects with no side effects\n- **Deterministic output**: Same input always produces identical DDL\n- **Type-safe**: Complete mypy coverage with structural pattern matching\n- **Dependency resolution**: Constraint-based dependency ordering using NetworkX\n\n### Testing Strategy\n- **Roundtrip fidelity**: Generic integration tests that verify `Extract(DB) \u2192 Diff \u2192 Generate(SQL) \u2192 Apply(SQL) \u2192 Extract(DB)` produces semantically identical catalogs\n- **Real PostgreSQL**: All tests use actual PostgreSQL instances via testcontainers\n\n## Technical Decisions\n\n- **Pure Functions**: All core logic uses pure functions with no side effects\n- **Immutable Data**: Extract once, operate on immutable snapshots\n- **Dependency Resolution**: Constraint-based dependency ordering using NetworkX\n- **Type Safety**: Complete type safety with mypy and structural pattern matching\n- **Roundtrip Fidelity**: Generates DDL that recreates schemas exactly\n\n## Installation\n\n**Note**: pgdelta is not yet published to PyPI. Install from source:\n\n```bash\ngit clone https://github.com/olirice/pgdelta.git\ncd pgdelta\npip install -e \".[dev]\"\n```\n\n## Usage\n\n### Python API\n\n```python\nfrom pgdelta import PgCatalog, generate_sql\nfrom pgdelta.catalog import extract_catalog\nfrom sqlalchemy import create_engine\nfrom sqlalchemy.orm import Session\n\n# Connect to databases\nsource_engine = create_engine(\"postgresql://user:pass@localhost/source_db\")\ntarget_engine = create_engine(\"postgresql://user:pass@localhost/target_db\")\n\nwith Session(source_engine) as source_session, Session(target_engine) as target_session:\n # Extract schemas\n source_catalog = extract_catalog(source_session)\n target_catalog = extract_catalog(target_session)\n\n # Generate migration from target to source\n changes = target_catalog.diff(source_catalog)\n\n # Generate SQL statements\n sql_statements = [generate_sql(change) for change in changes]\n\n for sql in sql_statements:\n print(sql)\n```\n\n### Example Output\n\n```sql\nCREATE SCHEMA \"analytics\";\nCREATE TABLE \"analytics\".\"user_stats\" (\n \"user_id\" integer,\n \"post_count\" integer DEFAULT 0,\n \"last_login\" timestamp without time zone\n);\n```\n\n## Development Setup\n\n### Prerequisites\n\n- Python 3.13+\n- Docker (for running PostgreSQL test containers)\n\n### Setup Instructions\n\n1. **Clone the repository**\n ```bash\n git clone https://github.com/olirice/pgdelta.git\n cd pgdelta\n ```\n\n2. **Create and activate a virtual environment**\n ```bash\n python -m venv venv\n source venv/bin/activate # On Windows: venv\\Scripts\\activate\n ```\n\n3. **Install in editable mode with development dependencies**\n ```bash\n pip install -e \".[dev]\"\n ```\n\n4. **Install pre-commit hooks**\n ```bash\n pre-commit install\n ```\n\n### Running Tests\n\nThe project uses pytest with real PostgreSQL databases via testcontainers:\n\n```bash\n# Run all tests\npytest\n\n# Run tests in parallel (faster)\npytest -n auto\n\n# Run specific test categories\npytest tests/unit/ # Unit tests only\npytest tests/integration/ # Integration tests only\n\n# Run tests with coverage\npytest --cov=src/pgdelta --cov-report=html\n\n# Run a specific test\npytest tests/unit/test_sql_generation.py::test_create_schema_basic\n```\n\n### Development Tools\n\n```bash\n# Type checking\nmypy src/pgdelta\n\n# Linting and formatting\nruff check\nruff format\n\n# Run all pre-commit hooks\npre-commit run --all-files\n```\n\n### Test Requirements\n\n- **Docker**: Required for PostgreSQL test containers\n- **PostgreSQL 17**: Automatically managed via testcontainers\n- **Real Database Testing**: All tests use real PostgreSQL instances, not mocks\n\n## CI/CD\n\nThe project includes comprehensive GitHub Actions workflows:\n\n- **CI Pipeline** (`ci.yml`): Runs pre-commit checks and tests on every push/PR\n- **Security Scanning** (`security.yml`): Dependency and security analysis\n- **Automated Releases** (`release.yml`): Builds and publishes to PyPI on tag push\n\nAll workflows use the latest action versions and follow security best practices with minimal permissions.\n\n## Architecture Details\n\n### Model Design\n\nPostgreSQL catalog models are simplified and optimized for DDL generation:\n\n- **Immutable dataclasses**: All models use `@dataclass(frozen=True)` for immutability\n- **Essential fields only**: Only fields necessary for DDL generation are included\n- **Stable identifiers**: Cross-database portable identifiers using stable_id (no pg_depend_id required)\n- **Type safety**: Complete type annotations with mypy compliance\n\n### Field Metadata System\n\nUses dataclass field metadata to categorize fields with wrapper functions:\n- `identity()`: Fields that identify the object (used in semantic comparison)\n- `data()`: Fields that represent object data (used in semantic comparison)\n- `internal()`: Fields needed for dependency resolution (ignored in semantic comparison)\n\nThe wrapper functions generate the appropriate metadata dictionaries, making field categorization cleaner and more maintainable.\n\n## Roadmap\n\n### Phase 1 (Current - v0.1.x)\n- \u2705 Comprehensive schema and table DDL generation\n- \u2705 All constraint types (primary keys, foreign keys, unique, check, exclusion)\n- \u2705 Complete index support (all types, partial, functional)\n- \u2705 Views and materialized views\n- \u2705 Functions and triggers\n- \u2705 Sequences with ownership tracking\n- \u2705 Custom types (enums, composites)\n- \u2705 RLS policies\n- \u2705 Advanced dependency resolution\n- \u2705 Roundtrip fidelity\n- \u2705 CLI interface\n\n### Phase 2 (v0.2.x)\n- \ud83d\udd04 ALTER operations for constraints and indexes\n- \ud83d\udd04 Domain types\n- \ud83d\udd04 Enhanced materialized view support\n- \ud83d\udd04 Advanced function features\n\n### Phase 3 (v0.3.x)\n- \ud83d\udd04 Partitioning support\n- \ud83d\udd04 Performance optimizations\n- \ud83d\udd04 Streaming processing for large schemas\n\n## License\n\nApache 2.0 - see [LICENSE](LICENSE) file for details.\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "PostgreSQL schema differ and DDL generator",
"version": "0.1.0",
"project_urls": {
"Homepage": "https://github.com/olirice/pgdelta",
"Issues": "https://github.com/olirice/pgdelta/issues",
"Repository": "https://github.com/olirice/pgdelta.git"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "03ed1e20e8e21ff6b45e179800cae34981aae00e2a4ca52f39c364e7ad4d4d18",
"md5": "e5b985d9700c95c0d8cb5a720ffbd9c7",
"sha256": "74175f0ec26a5818a735ef8648cc9ea932d8774d4ff7bfb242f674d0ad39d065"
},
"downloads": -1,
"filename": "pgdelta-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e5b985d9700c95c0d8cb5a720ffbd9c7",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.13",
"size": 96301,
"upload_time": "2025-07-18T14:52:16",
"upload_time_iso_8601": "2025-07-18T14:52:16.330882Z",
"url": "https://files.pythonhosted.org/packages/03/ed/1e20e8e21ff6b45e179800cae34981aae00e2a4ca52f39c364e7ad4d4d18/pgdelta-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "689208e8560440054c1558bf623c0719622aa92ba2fff22cf871a05b98c1e312",
"md5": "25966f677ce73ddeb0484f17a740c6bd",
"sha256": "f94a44b1ca0dedeb595182edea0b48fbf4db08fc6c96987cadc4b416d6f862b2"
},
"downloads": -1,
"filename": "pgdelta-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "25966f677ce73ddeb0484f17a740c6bd",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.13",
"size": 115775,
"upload_time": "2025-07-18T14:52:17",
"upload_time_iso_8601": "2025-07-18T14:52:17.727555Z",
"url": "https://files.pythonhosted.org/packages/68/92/08e8560440054c1558bf623c0719622aa92ba2fff22cf871a05b98c1e312/pgdelta-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-18 14:52:17",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "olirice",
"github_project": "pgdelta",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "pgdelta"
}