@toichubek/pg-ddl-extractor 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Toichubek Zhamalidin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,417 @@
1
+ # 📦 PostgreSQL DDL Extractor
2
+
3
+ Extracts full database structure (DDL) from PostgreSQL and organizes it into a clean folder structure for Git version control.
4
+
5
+ ## 🚀 Installation
6
+
7
+ ### As npm package (recommended)
8
+
9
+ ```bash
10
+ # Install globally
11
+ npm install -g @toichubek/pg-ddl-extractor
12
+
13
+ # Or install locally in your project
14
+ npm install --save-dev @toichubek/pg-ddl-extractor
15
+ ```
16
+
17
+ ### From source
18
+
19
+ Clone this repository and use directly with npm scripts.
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ myproject/
25
+ ├── back/
26
+ ├── front/
27
+ ├── extract-db/ ← this tool
28
+ │ ├── src/
29
+ │ │ ├── extract.ts ← entry point
30
+ │ │ ├── extractor.ts ← SQL queries
31
+ │ │ ├── writer.ts ← file writer
32
+ │ │ └── config.ts ← DB config
33
+ │ ├── package.json
34
+ │ ├── tsconfig.json
35
+ │ └── .env
36
+ └── sql/ ← output goes here
37
+ ├── dev/
38
+ │ ├── _full_dump.sql
39
+ │ ├── schemas/
40
+ │ │ └── public.sql
41
+ │ ├── tables/
42
+ │ │ ├── public.users.sql
43
+ │ │ ├── public.orders.sql
44
+ │ │ └── ...
45
+ │ ├── functions/
46
+ │ │ ├── public.calculate_total.sql
47
+ │ │ └── ...
48
+ │ ├── views/
49
+ │ ├── materialized_views/
50
+ │ ├── sequences/
51
+ │ ├── triggers/
52
+ │ ├── types/
53
+ │ └── indexes/
54
+ └── prod/
55
+ └── ... (same structure)
56
+ ```
57
+
58
+ ## What Gets Extracted
59
+
60
+ | Object | Includes |
61
+ |--------------------|---------------------------------------------------|
62
+ | **Tables** | Columns, PK, FK, UNIQUE, CHECK, defaults, comments |
63
+ | **Functions** | Full `CREATE FUNCTION` via `pg_get_functiondef()` |
64
+ | **Views** | `CREATE OR REPLACE VIEW` |
65
+ | **Materialized Views** | `CREATE MATERIALIZED VIEW` |
66
+ | **Sequences** | INCREMENT, MIN, MAX, START, CYCLE |
67
+ | **Triggers** | Timing, events, action |
68
+ | **Types** | Enum and composite types |
69
+ | **Indexes** | Non-constraint indexes only |
70
+ | **Schemas** | `CREATE SCHEMA IF NOT EXISTS` |
71
+
72
+ ## Setup
73
+
74
+ ```bash
75
+ # Install dependencies
76
+ npm install
77
+
78
+ # Copy env template and fill in your DB credentials
79
+ cp .env.example .env
80
+ ```
81
+
82
+ Edit `.env`:
83
+
84
+ ```env
85
+ DEV_DB_HOST=localhost
86
+ DEV_DB_PORT=5432
87
+ DEV_DB_NAME=my_database
88
+ DEV_DB_USER=postgres
89
+ DEV_DB_PASSWORD=secret
90
+
91
+ PROD_DB_HOST=prod-server.example.com
92
+ PROD_DB_PORT=5432
93
+ PROD_DB_NAME=my_database
94
+ PROD_DB_USER=readonly_user
95
+ PROD_DB_PASSWORD=secret
96
+ ```
97
+
98
+ ## Configuration
99
+
100
+ ### Environment Variables
101
+
102
+ You can configure database connections using environment variables in a `.env` file or via your shell:
103
+
104
+ ```env
105
+ # DEV database
106
+ DEV_DB_HOST=localhost
107
+ DEV_DB_PORT=5432
108
+ DEV_DB_NAME=my_database
109
+ DEV_DB_USER=postgres
110
+ DEV_DB_PASSWORD=secret
111
+
112
+ # PROD database
113
+ PROD_DB_HOST=prod-server.example.com
114
+ PROD_DB_PORT=5432
115
+ PROD_DB_NAME=my_database
116
+ PROD_DB_USER=readonly_user
117
+ PROD_DB_PASSWORD=secret
118
+
119
+ # Optional: Custom output directory
120
+ SQL_OUTPUT_DIR=/path/to/sql
121
+ ```
122
+
123
+ ### CLI Flags
124
+
125
+ All commands support CLI flags to override environment variables:
126
+
127
+ **`pg-ddl-extract` Options:**
128
+ - `--env <environment>` - Environment name (dev or prod) - default: `dev`
129
+ - `--host <host>` - Database host
130
+ - `--port <port>` - Database port - default: `5432`
131
+ - `--database <database>` - Database name (required with --host)
132
+ - `--user <user>` - Database user (required with --host)
133
+ - `--password <password>` - Database password
134
+ - `--output <path>` - Custom output directory path
135
+ - `--help` - Display help
136
+ - `--version` - Display version
137
+
138
+ **`pg-ddl-diff` Options:**
139
+ - `--report` - Generate markdown and HTML reports
140
+ - `--sql-dir <path>` - Path to SQL directory - default: `./sql`
141
+ - `--dev <path>` - Path to dev schema directory
142
+ - `--prod <path>` - Path to prod schema directory
143
+ - `--help` - Display help
144
+ - `--version` - Display version
145
+
146
+ **`pg-ddl-migrate` Options:**
147
+ - `--sql-dir <path>` - Path to SQL directory - default: `./sql`
148
+ - `--dev <path>` - Path to dev schema directory
149
+ - `--prod <path>` - Path to prod schema directory
150
+ - `--help` - Display help
151
+ - `--version` - Display version
152
+
153
+ ## Usage
154
+
155
+ ### CLI Commands (after global install)
156
+
157
+ ```bash
158
+ # Extract DEV database → saves to ./sql/dev/
159
+ pg-ddl-extract --env dev
160
+
161
+ # Extract PROD database → saves to ./sql/prod/
162
+ pg-ddl-extract --env prod
163
+
164
+ # Extract with direct connection (no .env file needed)
165
+ pg-ddl-extract --host localhost --database mydb --user postgres --password secret
166
+
167
+ # Extract to custom output directory
168
+ pg-ddl-extract --env dev --output /custom/path
169
+
170
+ # Compare DEV vs PROD
171
+ pg-ddl-diff
172
+
173
+ # Compare and save reports
174
+ pg-ddl-diff --report
175
+
176
+ # Compare with custom directories
177
+ pg-ddl-diff --dev /path/to/dev --prod /path/to/prod
178
+
179
+ # Generate migration plan
180
+ pg-ddl-migrate
181
+
182
+ # Generate migration with custom SQL directory
183
+ pg-ddl-migrate --sql-dir /custom/sql
184
+ ```
185
+
186
+ ### Examples with Environment Variables
187
+
188
+ ```bash
189
+ # Unix/Linux/Mac - Pass env vars inline
190
+ DEV_DB_HOST=localhost DEV_DB_NAME=mydb DEV_DB_USER=postgres pg-ddl-extract --env dev
191
+
192
+ # Windows (PowerShell)
193
+ $env:DEV_DB_HOST="localhost"; $env:DEV_DB_NAME="mydb"; pg-ddl-extract --env dev
194
+
195
+ # Windows (cmd)
196
+ set DEV_DB_HOST=localhost && set DEV_DB_NAME=mydb && pg-ddl-extract --env dev
197
+ ```
198
+
199
+ ### Using npm scripts (local install or from source)
200
+
201
+ ```bash
202
+ # From your project root or extract-db/ folder
203
+ npm run extract:dev
204
+ npm run extract:prod
205
+ npm run diff
206
+ npm run diff:report
207
+ npm run migrate
208
+ ```
209
+
210
+ ### Programmatic API
211
+
212
+ ```typescript
213
+ import { Client } from "pg";
214
+ import {
215
+ SqlFileWriter,
216
+ DdlExtractor,
217
+ compareDdl,
218
+ generateMigration,
219
+ } from "@toichubek/pg-ddl-extractor";
220
+
221
+ // Extract database DDL
222
+ const client = new Client({ /* config */ });
223
+ await client.connect();
224
+
225
+ const writer = new SqlFileWriter("./sql/dev");
226
+ const extractor = new DdlExtractor(client, writer);
227
+ await extractor.extractAll();
228
+
229
+ // Compare environments
230
+ const summary = compareDdl("./sql");
231
+ console.log(summary);
232
+
233
+ // Generate migration
234
+ const migration = generateMigration("./sql");
235
+ ```
236
+
237
+ ## Compare DEV vs PROD
238
+
239
+ ```bash
240
+ # Print diff to console
241
+ npm run diff
242
+
243
+ # Print to console + save markdown report to sql/reports/
244
+ npm run diff:report
245
+ ```
246
+
247
+ ## Generate Migration Plan
248
+
249
+ ```bash
250
+ # Generate SQL migration file from DEV → PROD
251
+ npm run migrate
252
+ ```
253
+
254
+ This will:
255
+ - Analyze differences between DEV and PROD
256
+ - Generate SQL migration commands (CREATE, ALTER, DROP)
257
+ - Save to `sql/migrations/YYYYMMDD_HHmmss_dev_to_prod.sql`
258
+ - Organize commands in correct execution order
259
+ - Add safety comments for manual review
260
+
261
+ ⚠️ **Important**: Always review and test migrations before running on production!
262
+
263
+ Example output:
264
+ ```
265
+ ═══════════════════════════════════════════════════════════
266
+ Migration Plan Generated
267
+ ═══════════════════════════════════════════════════════════
268
+
269
+ 📄 File: /path/to/sql/migrations/20260207_052700_dev_to_prod.sql
270
+
271
+ Summary:
272
+ 🟢 Creates: 16
273
+ 🔴 Drops: 57
274
+ 🔄 Alters: 50
275
+ 📊 Total: 123 commands
276
+
277
+ ⚠️ Next Steps:
278
+ 1. Review the migration file carefully
279
+ 2. Test on staging environment
280
+ 3. Backup production database
281
+ 4. Run: psql -d your_db -f 20260207_052700_dev_to_prod.sql
282
+
283
+ ═══════════════════════════════════════════════════════════
284
+ ```
285
+
286
+ The generated migration file includes:
287
+ - **Sequences** - CREATE SEQUENCE for new sequences
288
+ - **Tables** - CREATE TABLE for new tables, with warnings for modified tables
289
+ - **Functions** - CREATE OR REPLACE FUNCTION for new/modified functions
290
+ - **Views** - CREATE OR REPLACE VIEW for new/modified views
291
+ - **Triggers** - CREATE TRIGGER (may need manual adjustment)
292
+ - **Indexes** - CREATE INDEX for new indexes
293
+ - **Drops** - DROP ... IF EXISTS CASCADE for removed objects
294
+
295
+ All commands are organized in correct dependency order.
296
+
297
+ Example diff output:
298
+ ```
299
+ ═══════════════════════════════════════════════════════════
300
+ DEV vs PROD — DDL Comparison Report
301
+ ═══════════════════════════════════════════════════════════
302
+
303
+ DEV objects: 48
304
+ PROD objects: 45
305
+
306
+ ✅ Identical: 40
307
+ 🔄 Modified: 3
308
+ 🟢 Only DEV: 5
309
+ 🔴 Only PROD: 2
310
+
311
+ ───────────────────────────────────────────────────────────
312
+ 🟢 EXISTS ONLY IN DEV (not yet in prod)
313
+ ───────────────────────────────────────────────────────────
314
+ [tables] public.student_drafts
315
+ [functions] public.fn_calculate_scores
316
+
317
+ ───────────────────────────────────────────────────────────
318
+ 🔄 MODIFIED (different between dev and prod)
319
+ ───────────────────────────────────────────────────────────
320
+
321
+ [tables] public.users
322
+ DEV [5]: email varchar(255) NOT NULL
323
+ PROD [5]: email varchar(150) NOT NULL
324
+ ```
325
+
326
+ ## Git Workflow
327
+
328
+ ```bash
329
+ # From project root
330
+ git add sql/
331
+ git commit -m "chore: update database DDL snapshot"
332
+ ```
333
+
334
+ ### Recommended: Add to root project scripts
335
+
336
+ In your root `package.json`:
337
+
338
+ ```json
339
+ {
340
+ "scripts": {
341
+ "db:snapshot:dev": "cd extract-db && npx ts-node src/extract.ts --env dev",
342
+ "db:snapshot:prod": "cd extract-db && npx ts-node src/extract.ts --env prod"
343
+ }
344
+ }
345
+ ```
346
+
347
+ ## Running Migrations
348
+
349
+ After generating a migration file:
350
+
351
+ 1. **Review carefully** - Open the generated SQL file and review all changes
352
+ 2. **Test on staging** - Run the migration on a staging database first
353
+ 3. **Backup production** - Create a full backup before running on production
354
+ 4. **Run migration**:
355
+ ```bash
356
+ psql -h prod-host -U db_user -d database_name -f sql/migrations/YYYYMMDD_HHmmss_dev_to_prod.sql
357
+ ```
358
+
359
+ ### Migration Safety
360
+
361
+ The generator includes safety features:
362
+ - Uses `IF EXISTS` for DROP commands
363
+ - Uses `CASCADE` where needed
364
+ - Adds `BEGIN`/`COMMIT` transaction wrapper
365
+ - Marks complex changes with ⚠️ for manual review
366
+ - Provides comments explaining each change
367
+
368
+ ### What Requires Manual Review
369
+
370
+ Some changes cannot be fully automated:
371
+ - **Table modifications** - May need custom ALTER TABLE logic to preserve data
372
+ - **Triggers** - May need table name specification
373
+ - **Complex renames** - Should be done manually to avoid data loss
374
+ - **Data migrations** - Any data transformation logic
375
+
376
+ ## Publishing to npm
377
+
378
+ ```bash
379
+ # 1. Update version in package.json
380
+ npm version patch # or minor, major
381
+
382
+ # 2. Build the package
383
+ npm run build
384
+
385
+ # 3. Test locally with npm link
386
+ npm link
387
+ pg-ddl-extract --help
388
+
389
+ # 4. Publish to npm
390
+ npm publish --access public
391
+
392
+ # 5. Or publish to private registry
393
+ npm publish --registry https://your-registry.com
394
+ ```
395
+
396
+ ## Development
397
+
398
+ ```bash
399
+ # Install dependencies
400
+ npm install
401
+
402
+ # Build TypeScript
403
+ npm run build
404
+
405
+ # Test locally
406
+ npm link
407
+ ```
408
+
409
+ ## Tips
410
+
411
+ - Run before each release to capture DB changes
412
+ - Use `git diff sql/` to review structural changes between commits
413
+ - The `_full_dump.sql` can be used to recreate the schema from scratch
414
+ - Use a **readonly** database user for PROD extraction
415
+ - Add to CI/CD to auto-snapshot on deploy
416
+ - Generate migration plan (`npm run migrate`) before each production deployment
417
+ - Keep migration files in version control for audit trail
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../diff";
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ require("../diff");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../extract";
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ require("../extract");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../migrate";
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ require("../migrate");
@@ -0,0 +1,22 @@
1
+ interface DiffItem {
2
+ category: string;
3
+ object: string;
4
+ status: "only_dev" | "only_prod" | "modified";
5
+ devFile?: string;
6
+ prodFile?: string;
7
+ diff?: string[];
8
+ }
9
+ interface DiffSummary {
10
+ total_dev: number;
11
+ total_prod: number;
12
+ only_dev: number;
13
+ only_prod: number;
14
+ modified: number;
15
+ identical: number;
16
+ items: DiffItem[];
17
+ }
18
+ export declare function compareDdl(sqlRoot: string): DiffSummary;
19
+ export declare function formatConsoleReport(summary: DiffSummary): string;
20
+ export declare function formatMarkdownReport(summary: DiffSummary): string;
21
+ export declare function formatHtmlReport(summary: DiffSummary): string;
22
+ export {};