relq 1.0.5 → 1.0.7

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.
Files changed (86) hide show
  1. package/dist/cjs/cli/commands/add.cjs +257 -17
  2. package/dist/cjs/cli/commands/commit.cjs +13 -2
  3. package/dist/cjs/cli/commands/export.cjs +25 -19
  4. package/dist/cjs/cli/commands/import.cjs +219 -100
  5. package/dist/cjs/cli/commands/init.cjs +86 -14
  6. package/dist/cjs/cli/commands/pull.cjs +104 -23
  7. package/dist/cjs/cli/commands/push.cjs +38 -3
  8. package/dist/cjs/cli/index.cjs +9 -1
  9. package/dist/cjs/cli/utils/ast/codegen/builder.cjs +297 -0
  10. package/dist/cjs/cli/utils/ast/codegen/constraints.cjs +185 -0
  11. package/dist/cjs/cli/utils/ast/codegen/defaults.cjs +311 -0
  12. package/dist/cjs/cli/utils/ast/codegen/index.cjs +24 -0
  13. package/dist/cjs/cli/utils/ast/codegen/type-map.cjs +116 -0
  14. package/dist/cjs/cli/utils/ast/codegen/utils.cjs +69 -0
  15. package/dist/cjs/cli/utils/ast/index.cjs +19 -0
  16. package/dist/cjs/cli/utils/ast/transformer/helpers.cjs +154 -0
  17. package/dist/cjs/cli/utils/ast/transformer/index.cjs +25 -0
  18. package/dist/cjs/cli/utils/ast/types.cjs +2 -0
  19. package/dist/cjs/cli/utils/ast-codegen.cjs +949 -0
  20. package/dist/cjs/cli/utils/ast-transformer.cjs +916 -0
  21. package/dist/cjs/cli/utils/change-tracker.cjs +50 -1
  22. package/dist/cjs/cli/utils/cli-utils.cjs +151 -0
  23. package/dist/cjs/cli/utils/fast-introspect.cjs +149 -23
  24. package/dist/cjs/cli/utils/pg-parser.cjs +1 -0
  25. package/dist/cjs/cli/utils/repo-manager.cjs +121 -4
  26. package/dist/cjs/cli/utils/schema-comparator.cjs +98 -14
  27. package/dist/cjs/cli/utils/schema-introspect.cjs +56 -19
  28. package/dist/cjs/cli/utils/snapshot-manager.cjs +0 -1
  29. package/dist/cjs/cli/utils/sql-generator.cjs +353 -64
  30. package/dist/cjs/cli/utils/type-generator.cjs +114 -15
  31. package/dist/cjs/config/config.cjs +29 -10
  32. package/dist/cjs/core/relq-client.cjs +22 -6
  33. package/dist/cjs/schema-definition/column-types.cjs +149 -13
  34. package/dist/cjs/schema-definition/defaults.cjs +72 -0
  35. package/dist/cjs/schema-definition/index.cjs +15 -1
  36. package/dist/cjs/schema-definition/introspection.cjs +7 -3
  37. package/dist/cjs/schema-definition/pg-relations.cjs +169 -0
  38. package/dist/cjs/schema-definition/pg-view.cjs +30 -0
  39. package/dist/cjs/schema-definition/table-definition.cjs +110 -4
  40. package/dist/cjs/types/config-types.cjs +13 -4
  41. package/dist/cjs/utils/aws-dsql.cjs +177 -0
  42. package/dist/config.d.ts +147 -2
  43. package/dist/esm/cli/commands/add.js +255 -18
  44. package/dist/esm/cli/commands/commit.js +13 -2
  45. package/dist/esm/cli/commands/export.js +25 -19
  46. package/dist/esm/cli/commands/import.js +221 -102
  47. package/dist/esm/cli/commands/init.js +86 -14
  48. package/dist/esm/cli/commands/pull.js +106 -25
  49. package/dist/esm/cli/commands/push.js +39 -4
  50. package/dist/esm/cli/index.js +9 -1
  51. package/dist/esm/cli/utils/ast/codegen/builder.js +291 -0
  52. package/dist/esm/cli/utils/ast/codegen/constraints.js +176 -0
  53. package/dist/esm/cli/utils/ast/codegen/defaults.js +305 -0
  54. package/dist/esm/cli/utils/ast/codegen/index.js +6 -0
  55. package/dist/esm/cli/utils/ast/codegen/type-map.js +111 -0
  56. package/dist/esm/cli/utils/ast/codegen/utils.js +60 -0
  57. package/dist/esm/cli/utils/ast/index.js +3 -0
  58. package/dist/esm/cli/utils/ast/transformer/helpers.js +141 -0
  59. package/dist/esm/cli/utils/ast/transformer/index.js +2 -0
  60. package/dist/esm/cli/utils/ast/types.js +1 -0
  61. package/dist/esm/cli/utils/ast-codegen.js +945 -0
  62. package/dist/esm/cli/utils/ast-transformer.js +907 -0
  63. package/dist/esm/cli/utils/change-tracker.js +50 -1
  64. package/dist/esm/cli/utils/cli-utils.js +147 -0
  65. package/dist/esm/cli/utils/fast-introspect.js +149 -23
  66. package/dist/esm/cli/utils/pg-parser.js +1 -0
  67. package/dist/esm/cli/utils/repo-manager.js +114 -4
  68. package/dist/esm/cli/utils/schema-comparator.js +98 -14
  69. package/dist/esm/cli/utils/schema-introspect.js +56 -19
  70. package/dist/esm/cli/utils/snapshot-manager.js +0 -1
  71. package/dist/esm/cli/utils/sql-generator.js +353 -64
  72. package/dist/esm/cli/utils/type-generator.js +114 -15
  73. package/dist/esm/config/config.js +29 -10
  74. package/dist/esm/core/relq-client.js +23 -7
  75. package/dist/esm/schema-definition/column-types.js +146 -12
  76. package/dist/esm/schema-definition/defaults.js +69 -0
  77. package/dist/esm/schema-definition/index.js +3 -0
  78. package/dist/esm/schema-definition/introspection.js +7 -3
  79. package/dist/esm/schema-definition/pg-relations.js +161 -0
  80. package/dist/esm/schema-definition/pg-view.js +24 -0
  81. package/dist/esm/schema-definition/table-definition.js +110 -4
  82. package/dist/esm/types/config-types.js +12 -4
  83. package/dist/esm/utils/aws-dsql.js +139 -0
  84. package/dist/index.d.ts +159 -1
  85. package/dist/schema-builder.d.ts +1314 -32
  86. package/package.json +1 -1
@@ -37,7 +37,8 @@ exports.importCommand = importCommand;
37
37
  const fs = __importStar(require("fs"));
38
38
  const path = __importStar(require("path"));
39
39
  const sql_parser_1 = require("../utils/sql-parser.cjs");
40
- const type_generator_1 = require("../utils/type-generator.cjs");
40
+ const ast_codegen_1 = require("../utils/ast-codegen.cjs");
41
+ const ast_transformer_1 = require("../utils/ast-transformer.cjs");
41
42
  const repo_manager_1 = require("../utils/repo-manager.cjs");
42
43
  const schema_comparator_1 = require("../utils/schema-comparator.cjs");
43
44
  const change_tracker_1 = require("../utils/change-tracker.cjs");
@@ -102,7 +103,7 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
102
103
  }
103
104
  }
104
105
  spinner.start('Parsing SQL schema');
105
- const parsedSchema = (0, sql_parser_1.parseSqlFile)(sqlContent);
106
+ const parsedSchema = await (0, ast_transformer_1.parseSQL)(sqlContent);
106
107
  const functions = includeFunctions ? (0, sql_parser_1.parseFunctions)(sqlContent) : [];
107
108
  const triggers = includeTriggers ? (0, sql_parser_1.parseTriggers)(sqlContent) : [];
108
109
  const comments = (0, sql_parser_1.parseComments)(sqlContent);
@@ -190,13 +191,6 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
190
191
  }
191
192
  return true;
192
193
  });
193
- const filteredCompositeTypes = parsedSchema.compositeTypes.filter(c => {
194
- if ((0, relqignore_1.isCompositeTypeIgnored)(c.name, ignorePatterns).ignored) {
195
- ignoredCount++;
196
- return false;
197
- }
198
- return true;
199
- });
200
194
  const filteredSequences = parsedSchema.sequences.filter(s => {
201
195
  if ((0, relqignore_1.isSequenceIgnored)(s.name, ignorePatterns).ignored) {
202
196
  ignoredCount++;
@@ -215,15 +209,11 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
215
209
  tables: filteredTables,
216
210
  enums: filteredEnums,
217
211
  domains: filteredDomains,
218
- compositeTypes: filteredCompositeTypes,
219
212
  sequences: filteredSequences,
220
- collations: parsedSchema.collations,
221
- foreignTables: parsedSchema.foreignTables,
222
213
  views: parsedSchema.views,
223
- materializedViews: parsedSchema.materializedViews,
224
- foreignServers: parsedSchema.foreignServers,
214
+ functions: parsedSchema.functions,
215
+ triggers: parsedSchema.triggers,
225
216
  extensions: parsedSchema.extensions,
226
- partitions: parsedSchema.partitions,
227
217
  };
228
218
  if (ignoredCount > 0) {
229
219
  console.log(`${ignoredCount} object(s) ignored by .relqignore`);
@@ -233,14 +223,14 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
233
223
  name: t.name,
234
224
  columns: t.columns.map(c => ({
235
225
  name: c.name,
236
- type: c.dataType,
226
+ type: c.type,
237
227
  default: c.defaultValue,
238
228
  })),
239
229
  })),
240
230
  enums: parsedSchema.enums,
241
231
  domains: parsedSchema.domains,
242
232
  sequences: parsedSchema.sequences,
243
- compositeTypes: parsedSchema.compositeTypes,
233
+ compositeTypes: [],
244
234
  }, ignorePatterns);
245
235
  if (dependencyErrors.length > 0) {
246
236
  spinner.stop();
@@ -249,12 +239,6 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
249
239
  return;
250
240
  }
251
241
  spinner.start('Generating TypeScript schema');
252
- const dbSchema = convertToDbSchema(filteredSchema, filteredFunctions, triggers, comments);
253
- const typescriptContent = (0, type_generator_1.generateTypeScript)(dbSchema, {
254
- camelCase: true,
255
- includeFunctions,
256
- includeTriggers,
257
- });
258
242
  spinner.succeed('Generated TypeScript schema');
259
243
  const incomingSchema = convertToNormalizedSchema(filteredSchema, filteredFunctions, triggers);
260
244
  const existingSnapshot = (0, repo_manager_1.loadSnapshot)(projectRoot);
@@ -318,8 +302,91 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
318
302
  changes = [];
319
303
  console.log(`${git_utils_1.colors.cyan('First import')} - creating initial snapshot`);
320
304
  }
321
- const mergedDbSchema = snapshotToDbSchemaForGeneration(mergedSchema);
322
- const finalTypescriptContent = (0, type_generator_1.generateTypeScript)(mergedDbSchema, {
305
+ const astSchema = (0, ast_transformer_1.normalizedToParsedSchema)({
306
+ tables: mergedSchema.tables.map(t => ({
307
+ name: t.name,
308
+ schema: t.schema,
309
+ columns: t.columns.map(c => ({
310
+ name: c.name,
311
+ type: c.type,
312
+ nullable: c.nullable,
313
+ default: c.default,
314
+ primaryKey: c.primaryKey,
315
+ unique: c.unique,
316
+ check: c.check,
317
+ checkName: c.checkName,
318
+ references: c.references,
319
+ comment: c.comment,
320
+ isGenerated: c.isGenerated,
321
+ generatedExpression: c.generationExpression,
322
+ generatedExpressionAst: c.generatedExpressionAst,
323
+ })),
324
+ indexes: t.indexes.map(i => ({
325
+ name: i.name,
326
+ columns: i.columns,
327
+ unique: i.unique,
328
+ type: i.type,
329
+ definition: i.definition,
330
+ whereClause: i.whereClause,
331
+ whereClauseAst: i.whereClauseAst,
332
+ })),
333
+ constraints: t.constraints?.map(c => ({
334
+ name: c.name,
335
+ type: c.type,
336
+ columns: c.columns,
337
+ definition: c.definition,
338
+ references: c.references,
339
+ })),
340
+ isPartitioned: t.isPartitioned,
341
+ partitionType: t.partitionType,
342
+ partitionKey: t.partitionKey,
343
+ comment: t.comment,
344
+ })),
345
+ enums: mergedSchema.enums.map(e => ({
346
+ name: e.name,
347
+ schema: e.schema,
348
+ values: e.values,
349
+ })),
350
+ domains: mergedSchema.domains?.map(d => ({
351
+ name: d.name,
352
+ baseType: d.baseType,
353
+ notNull: d.notNull,
354
+ default: d.default ?? undefined,
355
+ check: d.check ?? undefined,
356
+ checkName: d.checkName,
357
+ })),
358
+ sequences: mergedSchema.sequences?.map(s => ({
359
+ name: s.name,
360
+ start: s.start,
361
+ increment: s.increment,
362
+ minValue: s.minValue,
363
+ maxValue: s.maxValue,
364
+ cache: s.cache,
365
+ cycle: s.cycle,
366
+ })),
367
+ extensions: mergedSchema.extensions?.map(e => e.name),
368
+ functions: includeFunctions ? mergedSchema.functions?.map(f => ({
369
+ name: f.name,
370
+ schema: f.schema,
371
+ args: f.args || [],
372
+ returnType: f.returnType,
373
+ language: f.language,
374
+ body: f.body,
375
+ volatility: f.volatility,
376
+ isStrict: f.isStrict,
377
+ securityDefiner: f.securityDefiner,
378
+ })) : [],
379
+ triggers: includeTriggers ? mergedSchema.triggers?.map(t => ({
380
+ name: t.name,
381
+ table: t.table,
382
+ timing: t.timing,
383
+ events: t.events,
384
+ level: t.level,
385
+ functionName: t.functionName,
386
+ when: t.when,
387
+ })) : [],
388
+ });
389
+ const finalTypescriptContent = (0, ast_codegen_1.generateTypeScriptFromAST)(astSchema, {
323
390
  camelCase: true,
324
391
  includeFunctions,
325
392
  includeTriggers,
@@ -347,6 +414,7 @@ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cw
347
414
  }
348
415
  fs.writeFileSync(absoluteOutputPath, finalTypescriptContent, 'utf-8');
349
416
  console.log(`Written ${git_utils_1.colors.cyan(absoluteOutputPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(finalTypescriptContent.length)})`)}`);
417
+ applyTrackingIdsToSnapshot(finalTypescriptContent, mergedSchema);
350
418
  (0, repo_manager_1.saveSnapshot)(mergedSchema, projectRoot);
351
419
  if (changes.length > 0) {
352
420
  (0, repo_manager_1.addUnstagedChanges)(changes, projectRoot);
@@ -395,36 +463,50 @@ function convertToDbSchema(parsed, functions = [], triggers = [], comments = [])
395
463
  return {
396
464
  tables: parsed.tables.map(t => ({
397
465
  name: t.name,
398
- schema: t.schema,
466
+ schema: t.schema || 'public',
399
467
  comment: tableComments.get(t.name) || null,
400
- columns: t.columns.map(c => ({
468
+ columns: t.columns
469
+ .filter(c => {
470
+ if (!c.type) {
471
+ console.warn(`Warning: Skipping column ${t.name}.${c.name} (no type)`);
472
+ return false;
473
+ }
474
+ return true;
475
+ })
476
+ .map(c => ({
401
477
  name: c.name,
402
- dataType: c.dataType,
403
- udtName: c.dataType,
478
+ dataType: c.type,
479
+ udtName: c.type,
404
480
  isNullable: c.isNullable,
405
- defaultValue: c.defaultValue,
481
+ defaultValue: c.defaultValue ?? null,
406
482
  isPrimaryKey: c.isPrimaryKey,
407
483
  isUnique: c.isUnique,
408
- maxLength: c.maxLength,
409
- precision: c.precision,
410
- scale: c.scale,
484
+ maxLength: c.typeParams?.length ?? null,
485
+ precision: c.typeParams?.precision ?? null,
486
+ scale: c.typeParams?.scale ?? null,
411
487
  references: c.references ? `${c.references.table}.${c.references.column}` : null,
412
488
  comment: columnComments.get(`${t.name}.${c.name}`) || c.comment || null,
413
489
  isGenerated: c.isGenerated || false,
414
- generationExpression: c.generationExpression || null,
490
+ generationExpression: c.generatedExpression || null,
415
491
  })),
416
492
  indexes: t.indexes.map(idx => ({
417
493
  name: idx.name,
418
494
  columns: idx.columns,
419
495
  isUnique: idx.isUnique,
420
- isPrimary: idx.isPrimary,
421
- type: idx.type,
422
- definition: idx.definition,
496
+ isPrimary: false,
497
+ type: idx.method || 'btree',
498
+ definition: idx.expressions?.join(', ') || idx.columns.join(', '),
423
499
  whereClause: idx.whereClause,
424
- expression: idx.expression,
500
+ whereClauseAst: idx.whereClauseAst,
501
+ expression: idx.expressions?.[0],
425
502
  comment: indexComments.get(idx.name) || null,
426
503
  })),
427
- constraints: t.constraints,
504
+ constraints: t.constraints.map(c => ({
505
+ name: c.name,
506
+ type: c.type,
507
+ columns: c.columns,
508
+ definition: c.expression || c.columns.join(', '),
509
+ })),
428
510
  rowCount: 0,
429
511
  isPartitioned: t.isPartitioned,
430
512
  partitionType: t.partitionType,
@@ -434,34 +516,31 @@ function convertToDbSchema(parsed, functions = [], triggers = [], comments = [])
434
516
  name: e.name,
435
517
  values: e.values,
436
518
  })),
437
- domains: parsed.domains?.map((d) => ({
519
+ domains: parsed.domains.map(d => ({
438
520
  name: d.name,
439
521
  baseType: d.baseType,
440
522
  isNotNull: d.notNull || false,
441
- defaultValue: d.default || null,
442
- checkExpression: d.check || null,
443
- check: d.check,
444
- default: d.default,
523
+ defaultValue: d.defaultValue || null,
524
+ checkExpression: d.checkExpression || null,
525
+ check: d.checkExpression,
526
+ default: d.defaultValue,
445
527
  notNull: d.notNull,
446
- })) || [],
447
- compositeTypes: parsed.compositeTypes?.map((c) => ({
448
- name: c.name,
449
- attributes: c.attributes || [],
450
- })) || [],
451
- sequences: parsed.sequences?.map((s) => ({
528
+ })),
529
+ compositeTypes: [],
530
+ sequences: parsed.sequences.map(s => ({
452
531
  name: s.name,
453
- dataType: s.dataType,
454
- start: s.start,
532
+ dataType: 'bigint',
533
+ start: s.startValue,
455
534
  increment: s.increment,
456
535
  minValue: s.minValue,
457
536
  maxValue: s.maxValue,
458
537
  cache: s.cache,
459
538
  cycle: s.cycle,
460
- ownedBy: s.ownedBy,
461
- })) || [],
539
+ ownedBy: s.ownedBy ? `${s.ownedBy.table}.${s.ownedBy.column}` : undefined,
540
+ })),
462
541
  collations: [],
463
542
  extensions: parsed.extensions,
464
- partitions: parsed.partitions,
543
+ partitions: [],
465
544
  functions: functions.map(f => ({
466
545
  ...f,
467
546
  comment: functionComments.get(f.name) || null,
@@ -476,79 +555,95 @@ function convertToDbSchema(parsed, functions = [], triggers = [], comments = [])
476
555
  };
477
556
  }
478
557
  function convertToNormalizedSchema(parsed, functions = [], triggers = []) {
558
+ const regularViews = parsed.views.filter(v => !v.isMaterialized);
559
+ const materializedViews = parsed.views.filter(v => v.isMaterialized);
479
560
  return {
480
561
  extensions: parsed.extensions.map(ext => ({ name: ext })),
481
562
  enums: parsed.enums.map(e => ({
482
563
  name: e.name,
483
- schema: 'public',
564
+ schema: e.schema || 'public',
484
565
  values: e.values,
485
566
  })),
486
567
  domains: parsed.domains.map(d => ({
487
568
  name: d.name,
488
- schema: 'public',
569
+ schema: d.schema || 'public',
489
570
  baseType: d.baseType,
490
571
  notNull: d.notNull || false,
491
- default: d.default || null,
492
- check: d.check || null,
493
- })),
494
- compositeTypes: parsed.compositeTypes.map(c => ({
495
- name: c.name,
496
- schema: 'public',
497
- attributes: c.attributes,
572
+ default: d.defaultValue || null,
573
+ check: d.checkExpression || null,
498
574
  })),
575
+ compositeTypes: [],
499
576
  sequences: parsed.sequences.map(s => ({
500
577
  name: s.name,
501
- schema: 'public',
578
+ schema: s.schema || 'public',
502
579
  dataType: 'bigint',
503
- startValue: s.start || 1,
580
+ startValue: s.startValue || 1,
504
581
  increment: s.increment || 1,
505
582
  minValue: s.minValue || null,
506
583
  maxValue: s.maxValue || null,
507
- cache: 1,
508
- cycle: false,
509
- ownedBy: null,
584
+ cache: s.cache || 1,
585
+ cycle: s.cycle || false,
586
+ ownedBy: s.ownedBy ? `${s.ownedBy.table}.${s.ownedBy.column}` : null,
510
587
  })),
511
588
  collations: [],
512
589
  tables: parsed.tables.map(t => {
513
- const childPartitions = parsed.partitions.filter(p => p.parentTable === t.name);
514
590
  return {
515
591
  name: t.name,
516
- schema: t.schema,
517
- columns: t.columns.map(c => ({
518
- name: c.name,
519
- tsName: toCamelCase(c.name),
520
- type: c.dataType,
521
- nullable: c.isNullable,
522
- default: c.defaultValue,
523
- primaryKey: c.isPrimaryKey,
524
- unique: c.isUnique,
525
- identity: c.identityGeneration ? {
526
- type: c.identityGeneration,
527
- } : undefined,
528
- isGenerated: c.isGenerated,
529
- generationExpression: c.generationExpression,
530
- })),
592
+ schema: t.schema || 'public',
593
+ columns: t.columns.map(c => {
594
+ const col = {
595
+ name: c.name,
596
+ tsName: toCamelCase(c.name),
597
+ type: c.type,
598
+ nullable: c.isNullable,
599
+ default: c.defaultValue,
600
+ primaryKey: c.isPrimaryKey,
601
+ unique: c.isUnique,
602
+ isGenerated: c.isGenerated,
603
+ generationExpression: c.generatedExpression,
604
+ generatedExpressionAst: c.generatedExpressionAst,
605
+ };
606
+ return col;
607
+ }),
531
608
  indexes: t.indexes.map(idx => ({
532
609
  name: idx.name,
533
610
  columns: idx.columns,
534
611
  unique: idx.isUnique,
535
- type: idx.type || 'btree',
536
- definition: idx.definition,
612
+ type: idx.method || 'btree',
613
+ definition: idx.expressions?.join(', ') || idx.columns.join(', '),
537
614
  whereClause: idx.whereClause,
538
- expression: idx.expression,
539
- })),
540
- constraints: t.constraints.map(c => ({
541
- name: c.name,
542
- type: c.type,
543
- definition: c.definition,
615
+ whereClauseAst: idx.whereClauseAst,
616
+ expression: idx.expressions?.[0],
544
617
  })),
618
+ constraints: t.constraints.map(c => {
619
+ const base = {
620
+ name: c.name,
621
+ type: c.type,
622
+ definition: c.expression || c.columns.join(', '),
623
+ columns: c.columns,
624
+ };
625
+ if (c.type === 'FOREIGN KEY' && c.references) {
626
+ base.referencedTable = c.references.table;
627
+ base.referencedColumns = c.references.columns;
628
+ if (c.references.onDelete)
629
+ base.onDelete = c.references.onDelete;
630
+ if (c.references.onUpdate)
631
+ base.onUpdate = c.references.onUpdate;
632
+ if (c.references.match)
633
+ base.matchType = c.references.match;
634
+ if (c.references.deferrable)
635
+ base.deferrable = c.references.deferrable;
636
+ if (c.references.initiallyDeferred)
637
+ base.initiallyDeferred = c.references.initiallyDeferred;
638
+ }
639
+ if (c.type === 'CHECK' && c.expression) {
640
+ base.checkExpression = c.expression;
641
+ }
642
+ return base;
643
+ }),
545
644
  isPartitioned: t.isPartitioned,
546
645
  partitionType: t.partitionType,
547
646
  partitionKey: t.partitionKey,
548
- partitions: childPartitions.length > 0 ? childPartitions.map(p => ({
549
- name: p.name,
550
- bound: p.partitionBound || '',
551
- })) : undefined,
552
647
  };
553
648
  }),
554
649
  functions: functions.map(f => ({
@@ -565,16 +660,16 @@ function convertToNormalizedSchema(parsed, functions = [], triggers = []) {
565
660
  forEach: 'STATEMENT',
566
661
  functionName: t.functionName || '',
567
662
  })),
568
- views: parsed.views.map(v => ({
663
+ views: regularViews.map(v => ({
569
664
  name: v.name,
570
665
  schema: v.schema || 'public',
571
666
  definition: v.definition,
572
667
  })),
573
- materializedViews: parsed.materializedViews.map(mv => ({
668
+ materializedViews: materializedViews.map(mv => ({
574
669
  name: mv.name,
575
670
  schema: mv.schema || 'public',
576
671
  definition: mv.definition,
577
- withData: mv.withData ?? true,
672
+ withData: true,
578
673
  })),
579
674
  };
580
675
  }
@@ -686,6 +781,7 @@ function snapshotToDbSchemaForGeneration(snapshot) {
686
781
  type: i.type || 'btree',
687
782
  definition: i.definition,
688
783
  whereClause: i.whereClause,
784
+ whereClauseAst: i.whereClauseAst,
689
785
  comment: null,
690
786
  })),
691
787
  constraints: t.constraints?.map(c => ({
@@ -785,4 +881,27 @@ function mergeSchemas(existing, incoming, replaceAll = false) {
785
881
  foreignTables: mergeByName(existing.foreignTables || [], incoming.foreignTables || []),
786
882
  };
787
883
  }
884
+ function applyTrackingIdsToSnapshot(typescript, snapshot) {
885
+ for (const table of snapshot.tables) {
886
+ const tablePattern = new RegExp(`defineTable\\s*\\(\\s*['"]${table.name}['"]\\s*,\\s*\\{[^}]+\\}\\s*,\\s*\\{[^}]*\\$trackingId:\\s*['"]([^'"]+)['"]`, 's');
887
+ const tableMatch = typescript.match(tablePattern);
888
+ if (tableMatch) {
889
+ table.trackingId = tableMatch[1];
890
+ }
891
+ for (const col of table.columns) {
892
+ const colPattern = new RegExp(`(?:${col.tsName}|${col.name}):\\s*\\w+\\([^)]*\\)[^\\n]*\\.\\\$id\\(['"]([^'"]+)['"]\\)`);
893
+ const colMatch = typescript.match(colPattern);
894
+ if (colMatch) {
895
+ col.trackingId = colMatch[1];
896
+ }
897
+ }
898
+ for (const idx of table.indexes) {
899
+ const idxPattern = new RegExp(`index\\s*\\(\\s*['"]${idx.name}['"]\\s*\\)[^\\n]*\\.\\\$id\\(['"]([^'"]+)['"]\\)`);
900
+ const idxMatch = typescript.match(idxPattern);
901
+ if (idxMatch) {
902
+ idx.trackingId = idxMatch[1];
903
+ }
904
+ }
905
+ }
906
+ }
788
907
  exports.default = importCommand;
@@ -84,21 +84,69 @@ function checkEnvVars() {
84
84
  DATABASE_NAME: process.env.DATABASE_NAME,
85
85
  DATABASE_USER: process.env.DATABASE_USER,
86
86
  DATABASE_PASSWORD: process.env.DATABASE_PASSWORD,
87
+ DATABASE_REGION: process.env.DATABASE_REGION,
88
+ AWS_DATABASE_HOST: process.env.AWS_DATABASE_HOST,
89
+ AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
90
+ AWS_DATABASE_USER: process.env.AWS_DATABASE_USER,
91
+ AWS_DATABASE_NAME: process.env.AWS_DATABASE_NAME,
92
+ AWS_DATABASE_PORT: process.env.AWS_DATABASE_PORT,
93
+ AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
87
94
  RELQ_PG_CONN_URL: process.env.RELQ_PG_CONN_URL,
88
95
  };
89
96
  const hasConnUrl = !!vars.RELQ_PG_CONN_URL;
90
- const hasIndividual = !!(vars.DATABASE_HOST && vars.DATABASE_NAME);
97
+ const hasIndividual = !!(vars.DATABASE_HOST && vars.DATABASE_NAME && vars.DATABASE_USER && vars.DATABASE_PASSWORD);
98
+ const hasAws = !!(vars.AWS_ACCESS_KEY_ID && vars.AWS_SECRET_ACCESS_KEY && vars.DATABASE_REGION && vars.AWS_DATABASE_NAME && vars.AWS_DATABASE_HOST);
91
99
  return {
92
- found: hasConnUrl || hasIndividual,
100
+ found: hasConnUrl || hasIndividual || hasAws,
101
+ hasConnUrl,
102
+ hasIndividual,
103
+ hasAws,
93
104
  vars,
94
105
  };
95
106
  }
107
+ async function askConnectionType(rl, options) {
108
+ const choices = [];
109
+ if (options.hasConnUrl) {
110
+ choices.push({ key: String(choices.length + 1), label: 'Connection URL (RELQ_PG_CONN_URL)', value: 'url' });
111
+ }
112
+ if (options.hasIndividual) {
113
+ choices.push({ key: String(choices.length + 1), label: 'Individual Config (DATABASE_HOST, DATABASE_NAME, ...)', value: 'individual' });
114
+ }
115
+ if (options.hasAws) {
116
+ choices.push({ key: String(choices.length + 1), label: 'AWS DSQL (AWS_ACCESS_KEY_ID, DATABASE_REGION, ...)', value: 'aws' });
117
+ }
118
+ if (choices.length === 1) {
119
+ return choices[0].value;
120
+ }
121
+ console.log('Multiple connection options found:');
122
+ console.log('');
123
+ for (const choice of choices) {
124
+ console.log(` ${cli_utils_1.colors.cyan(choice.key)}. ${choice.label}`);
125
+ }
126
+ console.log('');
127
+ const answer = await ask(rl, `Which connection type? [${choices.map(c => c.key).join('/')}]`, '1');
128
+ const selected = choices.find(c => c.key === answer);
129
+ return selected?.value ?? choices[0].value;
130
+ }
96
131
  function generateConfig(options) {
97
132
  let connectionBlock;
98
133
  if (options.useEnv) {
99
- if (process.env.RELQ_PG_CONN_URL) {
134
+ if (options.connectionType === 'url') {
100
135
  connectionBlock = ` connection: {
101
136
  url: process.env.RELQ_PG_CONN_URL,
137
+ },`;
138
+ }
139
+ else if (options.connectionType === 'aws') {
140
+ connectionBlock = ` connection: {
141
+ database: process.env.AWS_DATABASE_NAME,
142
+ aws: {
143
+ hostname: process.env.AWS_DATABASE_HOST!,
144
+ region: process.env.DATABASE_REGION!,
145
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
146
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
147
+ user: process.env.AWS_DATABASE_USER || 'admin',
148
+ port: parseInt(process.env.AWS_DATABASE_PORT || '5432'),
149
+ },
102
150
  },`;
103
151
  }
104
152
  else {
@@ -323,30 +371,53 @@ async function initCommand(context) {
323
371
  console.log('');
324
372
  const envCheck = checkEnvVars();
325
373
  let useEnv = false;
374
+ let connectionType = 'individual';
326
375
  let host = 'localhost';
327
376
  let port = '5432';
328
377
  let database = '';
329
378
  let user = 'postgres';
330
379
  let password = '';
331
380
  if (envCheck.found) {
332
- console.log('Found database environment variables:');
333
- if (envCheck.vars.RELQ_PG_CONN_URL) {
334
- console.log(' RELQ_PG_CONN_URL');
381
+ console.log('Found database connection options:');
382
+ console.log('');
383
+ if (envCheck.hasConnUrl) {
384
+ console.log(` ${cli_utils_1.colors.cyan('Connection URL')}`);
385
+ console.log(` RELQ_PG_CONN_URL: ${envCheck.vars.RELQ_PG_CONN_URL?.substring(0, 40)}...`);
335
386
  }
336
- else {
387
+ if (envCheck.hasIndividual) {
388
+ console.log(` ${cli_utils_1.colors.cyan('Individual Config')}`);
337
389
  if (envCheck.vars.DATABASE_HOST)
338
- console.log(` DATABASE_HOST: ${envCheck.vars.DATABASE_HOST}`);
339
- if (envCheck.vars.DATABASE_PORT)
340
- console.log(` DATABASE_PORT: ${envCheck.vars.DATABASE_PORT}`);
390
+ console.log(` DATABASE_HOST: ${envCheck.vars.DATABASE_HOST}`);
341
391
  if (envCheck.vars.DATABASE_NAME)
342
- console.log(` DATABASE_NAME: ${envCheck.vars.DATABASE_NAME}`);
392
+ console.log(` DATABASE_NAME: ${envCheck.vars.DATABASE_NAME}`);
343
393
  if (envCheck.vars.DATABASE_USER)
344
- console.log(` DATABASE_USER: ${envCheck.vars.DATABASE_USER}`);
394
+ console.log(` DATABASE_USER: ${envCheck.vars.DATABASE_USER}`);
345
395
  if (envCheck.vars.DATABASE_PASSWORD)
346
- console.log(' DATABASE_PASSWORD: ***');
396
+ console.log(' DATABASE_PASSWORD: ***');
397
+ }
398
+ if (envCheck.hasAws) {
399
+ console.log(` ${cli_utils_1.colors.cyan('AWS DSQL')}`);
400
+ if (envCheck.vars.AWS_DATABASE_HOST)
401
+ console.log(` AWS_DATABASE_HOST: ${envCheck.vars.AWS_DATABASE_HOST}`);
402
+ if (envCheck.vars.DATABASE_REGION)
403
+ console.log(` DATABASE_REGION: ${envCheck.vars.DATABASE_REGION}`);
404
+ if (envCheck.vars.AWS_DATABASE_NAME)
405
+ console.log(` AWS_DATABASE_NAME: ${envCheck.vars.AWS_DATABASE_NAME}`);
406
+ if (envCheck.vars.AWS_ACCESS_KEY_ID)
407
+ console.log(` AWS_ACCESS_KEY_ID: ${envCheck.vars.AWS_ACCESS_KEY_ID?.substring(0, 8)}...`);
408
+ console.log(' AWS_SECRET_ACCESS_KEY: ***');
347
409
  }
348
410
  console.log('');
349
- useEnv = await askYesNo(rl, 'Use these environment variables?', true);
411
+ const optionCount = [envCheck.hasConnUrl, envCheck.hasIndividual, envCheck.hasAws].filter(Boolean).length;
412
+ if (optionCount > 1) {
413
+ connectionType = await askConnectionType(rl, envCheck);
414
+ console.log('');
415
+ useEnv = await askYesNo(rl, `Use ${connectionType === 'aws' ? 'AWS DSQL' : connectionType === 'url' ? 'Connection URL' : 'Individual Config'} from environment?`, true);
416
+ }
417
+ else {
418
+ connectionType = envCheck.hasConnUrl ? 'url' : envCheck.hasAws ? 'aws' : 'individual';
419
+ useEnv = await askYesNo(rl, 'Use these environment variables?', true);
420
+ }
350
421
  console.log('');
351
422
  }
352
423
  if (!useEnv) {
@@ -380,6 +451,7 @@ async function initCommand(context) {
380
451
  if (!fs.existsSync(configPath)) {
381
452
  const configContent = generateConfig({
382
453
  useEnv,
454
+ connectionType,
383
455
  host,
384
456
  port,
385
457
  database,