@lyku/lockstep-pg 0.1.1

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 (103) hide show
  1. package/LLMs.md +86 -0
  2. package/README.md +93 -0
  3. package/package.json +32 -0
  4. package/src/buildTableIndexCommand.d.ts +3 -0
  5. package/src/buildTableIndexCommand.d.ts.map +1 -0
  6. package/src/buildTableIndexCommand.js +46 -0
  7. package/src/buildTableIndexCommand.js.map +1 -0
  8. package/src/buildTableTriggerCommands.d.ts +3 -0
  9. package/src/buildTableTriggerCommands.d.ts.map +1 -0
  10. package/src/buildTableTriggerCommands.js +23 -0
  11. package/src/buildTableTriggerCommands.js.map +1 -0
  12. package/src/createTable.d.ts +3 -0
  13. package/src/createTable.d.ts.map +1 -0
  14. package/src/createTable.js +46 -0
  15. package/src/createTable.js.map +1 -0
  16. package/src/dateToPostgresString.d.ts +2 -0
  17. package/src/dateToPostgresString.d.ts.map +1 -0
  18. package/src/dateToPostgresString.js +7 -0
  19. package/src/dateToPostgresString.js.map +1 -0
  20. package/src/diff.d.ts +82 -0
  21. package/src/diff.d.ts.map +1 -0
  22. package/src/diff.js +218 -0
  23. package/src/diff.js.map +1 -0
  24. package/src/drift.d.ts +16 -0
  25. package/src/drift.d.ts.map +1 -0
  26. package/src/drift.js +299 -0
  27. package/src/drift.js.map +1 -0
  28. package/src/form.d.ts +3 -0
  29. package/src/form.d.ts.map +1 -0
  30. package/src/form.js +9 -0
  31. package/src/form.js.map +1 -0
  32. package/src/generateSql.d.ts +16 -0
  33. package/src/generateSql.d.ts.map +1 -0
  34. package/src/generateSql.js +306 -0
  35. package/src/generateSql.js.map +1 -0
  36. package/src/index.d.ts +16 -0
  37. package/src/index.d.ts.map +1 -0
  38. package/src/index.js +21 -0
  39. package/src/index.js.map +1 -0
  40. package/src/introspect.d.ts +56 -0
  41. package/src/introspect.d.ts.map +1 -0
  42. package/src/introspect.js +435 -0
  43. package/src/introspect.js.map +1 -0
  44. package/src/mapArrayType.d.ts +3 -0
  45. package/src/mapArrayType.d.ts.map +1 -0
  46. package/src/mapArrayType.js +41 -0
  47. package/src/mapArrayType.js.map +1 -0
  48. package/src/mapBigintType.d.ts +3 -0
  49. package/src/mapBigintType.d.ts.map +1 -0
  50. package/src/mapBigintType.js +17 -0
  51. package/src/mapBigintType.js.map +1 -0
  52. package/src/mapBigserialType.d.ts +3 -0
  53. package/src/mapBigserialType.d.ts.map +1 -0
  54. package/src/mapBigserialType.js +12 -0
  55. package/src/mapBigserialType.js.map +1 -0
  56. package/src/mapCharType.d.ts +3 -0
  57. package/src/mapCharType.d.ts.map +1 -0
  58. package/src/mapCharType.js +22 -0
  59. package/src/mapCharType.js.map +1 -0
  60. package/src/mapColumnType.d.ts +3 -0
  61. package/src/mapColumnType.d.ts.map +1 -0
  62. package/src/mapColumnType.js +63 -0
  63. package/src/mapColumnType.js.map +1 -0
  64. package/src/mapIntegerType.d.ts +3 -0
  65. package/src/mapIntegerType.d.ts.map +1 -0
  66. package/src/mapIntegerType.js +12 -0
  67. package/src/mapIntegerType.js.map +1 -0
  68. package/src/mapSerialType.d.ts +3 -0
  69. package/src/mapSerialType.d.ts.map +1 -0
  70. package/src/mapSerialType.js +12 -0
  71. package/src/mapSerialType.js.map +1 -0
  72. package/src/mapTextType.d.ts +3 -0
  73. package/src/mapTextType.d.ts.map +1 -0
  74. package/src/mapTextType.js +44 -0
  75. package/src/mapTextType.js.map +1 -0
  76. package/src/mapTimestamptzType.d.ts +3 -0
  77. package/src/mapTimestamptzType.d.ts.map +1 -0
  78. package/src/mapTimestamptzType.js +13 -0
  79. package/src/mapTimestamptzType.js.map +1 -0
  80. package/src/mapVarcharType.d.ts +3 -0
  81. package/src/mapVarcharType.d.ts.map +1 -0
  82. package/src/mapVarcharType.js +44 -0
  83. package/src/mapVarcharType.js.map +1 -0
  84. package/src/migrate.d.ts +13 -0
  85. package/src/migrate.d.ts.map +1 -0
  86. package/src/migrate.js +350 -0
  87. package/src/migrate.js.map +1 -0
  88. package/src/numberChecks.d.ts +11 -0
  89. package/src/numberChecks.d.ts.map +1 -0
  90. package/src/numberChecks.js +22 -0
  91. package/src/numberChecks.js.map +1 -0
  92. package/src/seed.d.ts +3 -0
  93. package/src/seed.d.ts.map +1 -0
  94. package/src/seed.js +56 -0
  95. package/src/seed.js.map +1 -0
  96. package/src/setupTable.d.ts +3 -0
  97. package/src/setupTable.d.ts.map +1 -0
  98. package/src/setupTable.js +41 -0
  99. package/src/setupTable.js.map +1 -0
  100. package/src/timestampChecks.d.ts +11 -0
  101. package/src/timestampChecks.d.ts.map +1 -0
  102. package/src/timestampChecks.js +22 -0
  103. package/src/timestampChecks.js.map +1 -0
@@ -0,0 +1,63 @@
1
+ import { mapArrayType } from './mapArrayType';
2
+ import { mapBigintType } from './mapBigintType';
3
+ import { mapIntegerType } from './mapIntegerType';
4
+ import { mapVarcharType } from './mapVarcharType';
5
+ import { mapTextType } from './mapTextType';
6
+ import { mapTimestamptzType } from './mapTimestamptzType';
7
+ import { mapCharType } from './mapCharType';
8
+ import { mapBigserialType } from './mapBigserialType';
9
+ import { mapSerialType } from './mapSerialType';
10
+ export function mapColumnType(name, columnSchema) {
11
+ // console.log('switching', columnSchema.type);
12
+ switch (columnSchema.type) {
13
+ case 'double precision':
14
+ case 'float8':
15
+ return 'DOUBLE PRECISION';
16
+ case 'real':
17
+ case 'float4':
18
+ return 'REAL';
19
+ case 'date':
20
+ return 'DATE';
21
+ case 'integer':
22
+ case 'int':
23
+ case 'int4':
24
+ return mapIntegerType(name, columnSchema);
25
+ case 'int2':
26
+ case 'smallint':
27
+ return 'SMALLINT';
28
+ case 'bigint':
29
+ return mapBigintType(name, columnSchema);
30
+ case 'bigserial':
31
+ return mapBigserialType(name, columnSchema);
32
+ case 'serial':
33
+ return mapSerialType(name, columnSchema);
34
+ case 'boolean':
35
+ return 'BOOLEAN';
36
+ case 'char':
37
+ case 'character':
38
+ case 'bpchar':
39
+ return mapCharType(name, columnSchema);
40
+ case 'text':
41
+ return mapTextType(name, columnSchema);
42
+ case 'varchar':
43
+ case 'character varying':
44
+ return mapVarcharType(name, columnSchema);
45
+ case 'timestamp':
46
+ return 'TIMESTAMP';
47
+ case 'timestamptz':
48
+ return mapTimestamptzType(name, columnSchema);
49
+ case 'numeric':
50
+ return 'NUMERIC';
51
+ case 'jsonb':
52
+ return 'JSONB';
53
+ case 'enum':
54
+ return `TEXT CHECK ("${name}" IN (${columnSchema.enum
55
+ .map((e) => `'${e}'`)
56
+ .join(', ')}))`;
57
+ case 'array':
58
+ return mapArrayType(name, columnSchema);
59
+ default:
60
+ throw new Error(`Unsupported column type: ${columnSchema.type}`);
61
+ }
62
+ }
63
+ //# sourceMappingURL=mapColumnType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapColumnType.js","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapColumnType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,UAAU,aAAa,CAC5B,IAAY,EACZ,YAAiC;IAEjC,+CAA+C;IAC/C,QAAQ,YAAY,CAAC,IAAI,EAAE,CAAC;QAC3B,KAAK,kBAAkB,CAAC;QACxB,KAAK,QAAQ;YACZ,OAAO,kBAAkB,CAAC;QAC3B,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ;YACZ,OAAO,MAAM,CAAC;QACf,KAAK,MAAM;YACV,OAAO,MAAM,CAAC;QACf,KAAK,SAAS,CAAC;QACf,KAAK,KAAK,CAAC;QACX,KAAK,MAAM;YACV,OAAO,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC3C,KAAK,MAAM,CAAC;QACZ,KAAK,UAAU;YACd,OAAO,UAAU,CAAC;QACnB,KAAK,QAAQ;YACZ,OAAO,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC1C,KAAK,WAAW;YACf,OAAO,gBAAgB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC7C,KAAK,QAAQ;YACZ,OAAO,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC1C,KAAK,SAAS;YACb,OAAO,SAAS,CAAC;QAClB,KAAK,MAAM,CAAC;QACZ,KAAK,WAAW,CAAC;QACjB,KAAK,QAAQ;YACZ,OAAO,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACxC,KAAK,MAAM;YACV,OAAO,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACxC,KAAK,SAAS,CAAC;QACf,KAAK,mBAAmB;YACvB,OAAO,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC3C,KAAK,WAAW;YACf,OAAO,WAAW,CAAC;QACpB,KAAK,aAAa;YACjB,OAAO,kBAAkB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC/C,KAAK,SAAS;YACb,OAAO,SAAS,CAAC;QAClB,KAAK,OAAO;YACX,OAAO,OAAO,CAAC;QAChB,KAAK,MAAM;YACV,OAAO,gBAAgB,IAAI,SAAS,YAAY,CAAC,IAAI;iBACnD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;iBACpB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAClB,KAAK,OAAO;YACX,OAAO,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACzC;YACC,MAAM,IAAI,KAAK,CAAC,4BAA4B,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;AACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { IntegerColumnModel } from '@lyku/lockstep-core';
2
+ export declare const mapIntegerType: (name: string, columnSchema: IntegerColumnModel) => string;
3
+ //# sourceMappingURL=mapIntegerType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapIntegerType.d.ts","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapIntegerType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,eAAO,MAAM,cAAc,GAC1B,MAAM,MAAM,EACZ,cAAc,kBAAkB,KAC9B,MAUF,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { numberChecks } from './numberChecks';
2
+ export const mapIntegerType = (name, columnSchema) => {
3
+ const constraints = numberChecks(name, columnSchema);
4
+ if (columnSchema.primaryKey) {
5
+ constraints.push('PRIMARY KEY');
6
+ }
7
+ if (columnSchema.unique) {
8
+ constraints.push('UNIQUE');
9
+ }
10
+ return `INTEGER${constraints.length ? ' ' + constraints.join(' ') : ''}`;
11
+ };
12
+ //# sourceMappingURL=mapIntegerType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapIntegerType.js","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapIntegerType.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,CAAC,MAAM,cAAc,GAAG,CAC7B,IAAY,EACZ,YAAgC,EACvB,EAAE;IACX,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAErD,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAC7B,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,UAAU,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC1E,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { SerialColumnModel } from '@lyku/lockstep-core';
2
+ export declare const mapSerialType: (name: string, columnSchema: SerialColumnModel) => string;
3
+ //# sourceMappingURL=mapSerialType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapSerialType.d.ts","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapSerialType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,eAAO,MAAM,aAAa,GACzB,MAAM,MAAM,EACZ,cAAc,iBAAiB,KAC7B,MAUF,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { numberChecks } from './numberChecks';
2
+ export const mapSerialType = (name, columnSchema) => {
3
+ const constraints = numberChecks(name, columnSchema);
4
+ if (columnSchema.primaryKey) {
5
+ constraints.push('PRIMARY KEY');
6
+ }
7
+ if (columnSchema.unique) {
8
+ constraints.push('UNIQUE');
9
+ }
10
+ return `SERIAL${constraints.length ? ' ' + constraints.join(' ') : ''}`;
11
+ };
12
+ //# sourceMappingURL=mapSerialType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapSerialType.js","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapSerialType.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,CAAC,MAAM,aAAa,GAAG,CAC5B,IAAY,EACZ,YAA+B,EACtB,EAAE;IACX,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAErD,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAC7B,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACzE,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { TextColumnModel } from '@lyku/lockstep-core';
2
+ export declare const mapTextType: (name: string, columnSchema: TextColumnModel) => string;
3
+ //# sourceMappingURL=mapTextType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapTextType.d.ts","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapTextType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAYtD,eAAO,MAAM,WAAW,GACvB,MAAM,MAAM,EACZ,cAAc,eAAe,KAC3B,MAwCF,CAAC"}
@@ -0,0 +1,44 @@
1
+ // Convert regex pattern like ^(a|b|c)$ to CHECK IN constraint
2
+ function patternToCheck(name, pattern) {
3
+ const match = pattern.match(/^\^\(([^)]+)\)\$$/);
4
+ if (match) {
5
+ const values = match[1].split('|').map((v) => `'${v}'`);
6
+ return `CHECK ("${name}" IN (${values.join(', ')}))`;
7
+ }
8
+ return null;
9
+ }
10
+ export const mapTextType = (name, columnSchema) => {
11
+ // console.log('mapping text', name, columnSchema, '/text');
12
+ const constraints = [];
13
+ if (columnSchema.primaryKey) {
14
+ constraints.push('PRIMARY KEY');
15
+ }
16
+ if (columnSchema.unique) {
17
+ constraints.push('UNIQUE');
18
+ }
19
+ if (columnSchema.generated) {
20
+ constraints.push(`GENERATED ALWAYS AS (${columnSchema.generated.as})${columnSchema.generated.stored ? ' STORED' : ''}`);
21
+ }
22
+ if (columnSchema.checks) {
23
+ constraints.push(...columnSchema.checks.map((check) => `CHECK (${check})`));
24
+ }
25
+ // Convert pattern to CHECK IN constraint for enum-like values
26
+ if ('pattern' in columnSchema && columnSchema.pattern) {
27
+ const check = patternToCheck(name, columnSchema.pattern);
28
+ if (check) {
29
+ constraints.push(check);
30
+ }
31
+ }
32
+ if (columnSchema.maxLength) {
33
+ constraints.push(`CHECK (length("${name}") <= ${columnSchema.maxLength})`);
34
+ }
35
+ if (columnSchema.minLength) {
36
+ constraints.push(`CHECK (length("${name}") >= ${columnSchema.minLength})`);
37
+ }
38
+ // if (columnSchema.default !== undefined) {
39
+ // constraints.push(`DEFAULT '${columnSchema.default}'`);
40
+ // }
41
+ const length = 'length' in columnSchema ? `(${columnSchema.length})` : '';
42
+ return `TEXT${length}${constraints.length ? ' ' + constraints.join(' ') : ''}`;
43
+ };
44
+ //# sourceMappingURL=mapTextType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapTextType.js","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapTextType.ts"],"names":[],"mappings":"AAEA,8DAA8D;AAC9D,SAAS,cAAc,CAAC,IAAY,EAAE,OAAe;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACjD,IAAI,KAAK,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxD,OAAO,WAAW,IAAI,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,CAC1B,IAAY,EACZ,YAA6B,EACpB,EAAE;IACX,4DAA4D;IAC5D,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAC7B,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IACD,IAAI,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CACf,wBAAwB,YAAY,CAAC,SAAS,CAAC,EAAE,IAChD,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAC7C,EAAE,CACF,CAAC;IACH,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC;IAC7E,CAAC;IACD,8DAA8D;IAC9D,IAAI,SAAS,IAAI,YAAY,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,OAAiB,CAAC,CAAC;QACnE,IAAI,KAAK,EAAE,CAAC;YACX,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IACF,CAAC;IACD,IAAI,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CAAC,kBAAkB,IAAI,SAAS,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CAAC,kBAAkB,IAAI,SAAS,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;IAC5E,CAAC;IACD,4CAA4C;IAC5C,6DAA6D;IAC7D,IAAI;IACJ,MAAM,MAAM,GAAG,QAAQ,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,OAAO,OAAO,MAAM,GACnB,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EACpD,EAAE,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Timestamptz } from '@lyku/lockstep-core';
2
+ export declare const mapTimestamptzType: (name: string, columnSchema: Timestamptz) => string;
3
+ //# sourceMappingURL=mapTimestamptzType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapTimestamptzType.d.ts","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapTimestamptzType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,eAAO,MAAM,kBAAkB,GAC9B,MAAM,MAAM,EACZ,cAAc,WAAW,KACvB,MAWF,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { timestampChecks } from './timestampChecks';
2
+ export const mapTimestamptzType = (name, columnSchema) => {
3
+ const constraints = timestampChecks(name, columnSchema);
4
+ if (columnSchema.primaryKey) {
5
+ constraints.push('PRIMARY KEY');
6
+ }
7
+ if (columnSchema.unique) {
8
+ constraints.push('UNIQUE');
9
+ }
10
+ // Note: DEFAULT is handled by migrate.ts to avoid duplication
11
+ return `TIMESTAMPTZ${constraints.length ? ' ' + constraints.join(' ') : ''}`;
12
+ };
13
+ //# sourceMappingURL=mapTimestamptzType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapTimestamptzType.js","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapTimestamptzType.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CACjC,IAAY,EACZ,YAAyB,EAChB,EAAE;IACX,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAExD,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAC7B,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IACD,8DAA8D;IAC9D,OAAO,cAAc,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC9E,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { VarcharColumnModel } from '@lyku/lockstep-core';
2
+ export declare const mapVarcharType: (name: string, columnSchema: VarcharColumnModel) => string;
3
+ //# sourceMappingURL=mapVarcharType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapVarcharType.d.ts","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapVarcharType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAYzD,eAAO,MAAM,cAAc,GAC1B,MAAM,MAAM,EACZ,cAAc,kBAAkB,KAC9B,MAwCF,CAAC"}
@@ -0,0 +1,44 @@
1
+ // Convert regex pattern like ^(a|b|c)$ to CHECK IN constraint
2
+ function patternToCheck(name, pattern) {
3
+ const match = pattern.match(/^\^\(([^)]+)\)\$$/);
4
+ if (match) {
5
+ const values = match[1].split('|').map((v) => `'${v}'`);
6
+ return `CHECK ("${name}" IN (${values.join(', ')}))`;
7
+ }
8
+ return null;
9
+ }
10
+ export const mapVarcharType = (name, columnSchema) => {
11
+ // console.log('mapping varchar', name, columnSchema, '/varchar');
12
+ const constraints = [];
13
+ if (columnSchema.primaryKey) {
14
+ constraints.push('PRIMARY KEY');
15
+ }
16
+ if (columnSchema.unique) {
17
+ constraints.push('UNIQUE');
18
+ }
19
+ if (columnSchema.generated) {
20
+ constraints.push(`GENERATED ALWAYS AS (${columnSchema.generated.as})${columnSchema.generated.stored ? ' STORED' : ''}`);
21
+ }
22
+ if (columnSchema.checks) {
23
+ constraints.push(...columnSchema.checks.map((check) => `CHECK (${check})`));
24
+ }
25
+ // Convert pattern to CHECK IN constraint for enum-like values
26
+ if ('pattern' in columnSchema && columnSchema.pattern) {
27
+ const check = patternToCheck(name, columnSchema.pattern);
28
+ if (check) {
29
+ constraints.push(check);
30
+ }
31
+ }
32
+ if (columnSchema.maxLength) {
33
+ constraints.push(`CHECK (length("${name}") <= ${columnSchema.maxLength})`);
34
+ }
35
+ if (columnSchema.minLength) {
36
+ constraints.push(`CHECK (length("${name}") >= ${columnSchema.minLength})`);
37
+ }
38
+ // if (columnSchema.default !== undefined) {
39
+ // constraints.push(`DEFAULT '${columnSchema.default}'`);
40
+ // }
41
+ const length = 'length' in columnSchema ? `(${columnSchema.length})` : '';
42
+ return `VARCHAR${length}${constraints.length ? ' ' + constraints.join(' ') : ''}`;
43
+ };
44
+ //# sourceMappingURL=mapVarcharType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapVarcharType.js","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/mapVarcharType.ts"],"names":[],"mappings":"AAEA,8DAA8D;AAC9D,SAAS,cAAc,CAAC,IAAY,EAAE,OAAe;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACjD,IAAI,KAAK,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxD,OAAO,WAAW,IAAI,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAC7B,IAAY,EACZ,YAAgC,EACvB,EAAE;IACX,kEAAkE;IAClE,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,IAAI,YAAY,CAAC,UAAU,EAAE,CAAC;QAC7B,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IACD,IAAI,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CACf,wBAAwB,YAAY,CAAC,SAAS,CAAC,EAAE,IAChD,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAC7C,EAAE,CACF,CAAC;IACH,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC;IAC7E,CAAC;IACD,8DAA8D;IAC9D,IAAI,SAAS,IAAI,YAAY,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,OAAiB,CAAC,CAAC;QACnE,IAAI,KAAK,EAAE,CAAC;YACX,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IACF,CAAC;IACD,IAAI,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CAAC,kBAAkB,IAAI,SAAS,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CAAC,kBAAkB,IAAI,SAAS,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;IAC5E,CAAC;IACD,4CAA4C;IAC5C,6DAA6D;IAC7D,IAAI;IACJ,MAAM,MAAM,GAAG,QAAQ,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,OAAO,UAAU,MAAM,GACtB,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EACpD,EAAE,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type DataformConfig, type Drift } from './drift';
2
+ interface MigrationResult {
3
+ safe: string[];
4
+ destructive: string[];
5
+ }
6
+ export declare function driftToSql(drifts: Drift[], config: DataformConfig): MigrationResult;
7
+ export declare function generateMigration(connectionString: string, config: DataformConfig): Promise<{
8
+ safe: string;
9
+ destructive: string;
10
+ driftCount: number;
11
+ }>;
12
+ export {};
13
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../../libs/lockstep-pg/src/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,cAAc,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAuBvE,UAAU,eAAe;IACxB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACtB;AAmBD,wBAAgB,UAAU,CACzB,MAAM,EAAE,KAAK,EAAE,EACf,MAAM,EAAE,cAAc,GACpB,eAAe,CAoXjB;AAED,wBAAsB,iBAAiB,CACtC,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,cAAc,GACpB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CA2CpE"}
package/src/migrate.js ADDED
@@ -0,0 +1,350 @@
1
+ import { detectDrift } from './drift';
2
+ import { mapColumnType } from './mapColumnType';
3
+ import { buildTableCreationCommand } from './createTable';
4
+ import { buildTableIndexCommands } from './buildTableIndexCommand';
5
+ import { buildTableTriggerCommands } from './buildTableTriggerCommands';
6
+ import { dateToPostgresString } from './dateToPostgresString';
7
+ const escapeString = (str) => {
8
+ if (str === undefined || str === null)
9
+ return 'NULL';
10
+ return `'${str.replace(/'/g, "''")}'`;
11
+ };
12
+ const formatSqlValue = (value) => {
13
+ if (value === undefined || value === null)
14
+ return 'NULL';
15
+ if (typeof value === 'bigint')
16
+ return value.toString();
17
+ if (typeof value === 'number')
18
+ return value.toString();
19
+ if (typeof value === 'boolean')
20
+ return value ? 'true' : 'false';
21
+ if (value instanceof Date)
22
+ return `'${dateToPostgresString(value)}'`;
23
+ if (typeof value === 'string')
24
+ return escapeString(value);
25
+ return 'NULL';
26
+ };
27
+ function formatDefault(def) {
28
+ if (def === null)
29
+ return 'NULL';
30
+ if (typeof def === 'object' && def !== null && 'sql' in def) {
31
+ return def.sql;
32
+ }
33
+ if (typeof def === 'string')
34
+ return `'${def}'`;
35
+ if (typeof def === 'boolean')
36
+ return def ? 'TRUE' : 'FALSE';
37
+ return String(def);
38
+ }
39
+ function getExpectedSqlType(columnName, schema) {
40
+ return mapColumnType(columnName, schema);
41
+ }
42
+ export function driftToSql(drifts, config) {
43
+ const safe = [];
44
+ const destructive = [];
45
+ for (const drift of drifts) {
46
+ switch (drift.type) {
47
+ case 'missing_table': {
48
+ const tableModel = config.tables[drift.table];
49
+ if (!tableModel) {
50
+ safe.push(`-- WARNING: Table "${drift.table}" not found in config`);
51
+ break;
52
+ }
53
+ safe.push(`-- Create table: ${drift.table}`);
54
+ safe.push(buildTableCreationCommand(drift.table, tableModel));
55
+ const indexCommands = buildTableIndexCommands(drift.table, tableModel);
56
+ if (indexCommands.length > 0) {
57
+ safe.push(...indexCommands);
58
+ }
59
+ const triggerCommands = buildTableTriggerCommands(drift.table, tableModel);
60
+ if (triggerCommands.length > 0) {
61
+ safe.push('');
62
+ safe.push(`-- Triggers for: ${drift.table}`);
63
+ safe.push(...triggerCommands);
64
+ }
65
+ safe.push('');
66
+ break;
67
+ }
68
+ case 'missing_column': {
69
+ const tableModel = config.tables[drift.table];
70
+ if (!tableModel || !('properties' in tableModel.schema)) {
71
+ safe.push(`-- WARNING: Cannot find schema for "${drift.table}"`);
72
+ break;
73
+ }
74
+ const columnName = drift.column;
75
+ if (!columnName) {
76
+ safe.push(`-- WARNING: Missing column name for drift in "${drift.table}"`);
77
+ break;
78
+ }
79
+ // eslint-disable-next-line security/detect-object-injection -- columnName is from schema
80
+ const colSchema = tableModel.schema.properties[columnName];
81
+ if (!colSchema) {
82
+ safe.push(`-- WARNING: Column "${columnName}" not found in schema for "${drift.table}"`);
83
+ break;
84
+ }
85
+ const required = 'required' in tableModel.schema
86
+ ? tableModel.schema.required
87
+ : [];
88
+ const isRequired = required.includes(columnName);
89
+ const sqlType = getExpectedSqlType(columnName, colSchema);
90
+ const hasDefault = 'default' in colSchema && colSchema.default !== undefined;
91
+ if (isRequired && !hasDefault) {
92
+ safe.push(`-- Add column "${columnName}" to "${drift.table}" (NOT NULL, requires backfill)`);
93
+ safe.push(`ALTER TABLE "${drift.table}" ADD COLUMN IF NOT EXISTS "${columnName}" ${sqlType};`);
94
+ safe.push(`-- TODO: Backfill existing rows with appropriate value:`);
95
+ safe.push(`-- UPDATE "${drift.table}" SET "${columnName}" = <default_value> WHERE "${columnName}" IS NULL;`);
96
+ safe.push(`ALTER TABLE "${drift.table}" ALTER COLUMN "${columnName}" SET NOT NULL;`);
97
+ }
98
+ else {
99
+ const notNull = isRequired ? ' NOT NULL' : '';
100
+ const defaultClause = hasDefault
101
+ ? ` DEFAULT ${formatDefault(colSchema.default)}`
102
+ : '';
103
+ safe.push(`-- Add column "${columnName}" to "${drift.table}"`);
104
+ safe.push(`ALTER TABLE "${drift.table}" ADD COLUMN IF NOT EXISTS "${columnName}" ${sqlType}${defaultClause}${notNull};`);
105
+ }
106
+ safe.push('');
107
+ break;
108
+ }
109
+ case 'missing_index': {
110
+ const match = drift.details.match(/column\(s\): (.+)$/);
111
+ if (match) {
112
+ const cols = match[1].split(', ').map((c) => c.trim());
113
+ const colNames = cols.map((c) => c.split(' ')[0]);
114
+ const indexName = `idx_${drift.table}_${colNames.join('_')}`;
115
+ const formattedCols = cols.map((c) => {
116
+ const parts = c.split(' ');
117
+ const colName = parts[0];
118
+ const modifiers = parts.slice(1).join(' ');
119
+ return modifiers ? `"${colName}" ${modifiers}` : `"${colName}"`;
120
+ });
121
+ safe.push(`-- Add missing index on "${drift.table}"`);
122
+ safe.push(`CREATE INDEX IF NOT EXISTS "${indexName}" ON "${drift.table}" (${formattedCols.join(', ')});`);
123
+ safe.push('');
124
+ }
125
+ break;
126
+ }
127
+ case 'column_type_mismatch': {
128
+ const columnName = drift.column ?? '';
129
+ let sqlType;
130
+ let castType;
131
+ if (drift.expected === 'array') {
132
+ const tableModel = config.tables[drift.table];
133
+ let arrayItemType = null;
134
+ if (tableModel && 'properties' in tableModel.schema) {
135
+ // eslint-disable-next-line security/detect-object-injection -- columnName is from schema
136
+ const colSchema = tableModel.schema.properties[columnName];
137
+ if (colSchema &&
138
+ colSchema.type === 'array' &&
139
+ 'items' in colSchema &&
140
+ colSchema.items &&
141
+ typeof colSchema.items === 'object') {
142
+ const items = colSchema.items;
143
+ if (items.type) {
144
+ arrayItemType = items.type;
145
+ if (arrayItemType === 'int8')
146
+ arrayItemType = 'bigint';
147
+ if (arrayItemType === 'int4' || arrayItemType === 'int')
148
+ arrayItemType = 'integer';
149
+ if (arrayItemType === 'int2')
150
+ arrayItemType = 'smallint';
151
+ if (arrayItemType === 'float8')
152
+ arrayItemType = 'double precision';
153
+ if (arrayItemType === 'float4')
154
+ arrayItemType = 'real';
155
+ if (arrayItemType === 'bool')
156
+ arrayItemType = 'boolean';
157
+ }
158
+ }
159
+ }
160
+ const simpleArrayTypes = new Set([
161
+ 'bigint',
162
+ 'integer',
163
+ 'smallint',
164
+ 'double precision',
165
+ 'real',
166
+ 'text',
167
+ 'varchar',
168
+ 'char',
169
+ 'boolean',
170
+ 'timestamptz',
171
+ 'timestamp',
172
+ 'date',
173
+ ]);
174
+ if (arrayItemType && simpleArrayTypes.has(arrayItemType)) {
175
+ const pgType = arrayItemType.toUpperCase();
176
+ sqlType = `${pgType}[]`;
177
+ castType = `${arrayItemType}[]`;
178
+ }
179
+ else {
180
+ sqlType = 'JSONB';
181
+ castType = 'jsonb';
182
+ }
183
+ }
184
+ else {
185
+ sqlType = drift.expected?.toUpperCase() ?? 'TEXT';
186
+ castType = drift.expected ?? 'text';
187
+ }
188
+ safe.push(`-- Type change for "${drift.table}"."${columnName}": ${drift.actual} → ${drift.expected}`);
189
+ safe.push(`-- WARNING: Verify data compatibility before running`);
190
+ safe.push(`ALTER TABLE "${drift.table}" ALTER COLUMN "${columnName}" TYPE ${sqlType} USING "${columnName}"::${castType};`);
191
+ safe.push('');
192
+ break;
193
+ }
194
+ case 'nullable_mismatch': {
195
+ const columnName = drift.column ?? '';
196
+ if (drift.expected === 'not null') {
197
+ safe.push(`-- Make "${drift.table}"."${columnName}" NOT NULL`);
198
+ safe.push(`-- WARNING: Ensure no NULL values exist first`);
199
+ safe.push(`ALTER TABLE "${drift.table}" ALTER COLUMN "${columnName}" SET NOT NULL;`);
200
+ }
201
+ else {
202
+ safe.push(`-- Make "${drift.table}"."${columnName}" nullable`);
203
+ safe.push(`ALTER TABLE "${drift.table}" ALTER COLUMN "${columnName}" DROP NOT NULL;`);
204
+ }
205
+ safe.push('');
206
+ break;
207
+ }
208
+ case 'extra_table': {
209
+ destructive.push(`-- Drop table "${drift.table}" (exists in DB but not in schema)`);
210
+ destructive.push(`DROP TABLE IF EXISTS "${drift.table}" CASCADE;`);
211
+ destructive.push('');
212
+ break;
213
+ }
214
+ case 'extra_column': {
215
+ const columnName = drift.column ?? '';
216
+ destructive.push(`-- Drop column "${columnName}" from "${drift.table}" (exists in DB but not in schema)`);
217
+ destructive.push(`ALTER TABLE "${drift.table}" DROP COLUMN IF EXISTS "${columnName}";`);
218
+ destructive.push('');
219
+ break;
220
+ }
221
+ case 'extra_index': {
222
+ destructive.push(`-- ${drift.details}`);
223
+ destructive.push(`-- DROP INDEX IF EXISTS "...";`);
224
+ destructive.push('');
225
+ break;
226
+ }
227
+ case 'missing_stock_doc': {
228
+ const tableModel = config.tables[drift.table];
229
+ if (!tableModel || !tableModel.docs) {
230
+ safe.push(`-- WARNING: Cannot find docs for table "${drift.table}"`);
231
+ break;
232
+ }
233
+ const primaryKey = tableModel.primaryKey || 'id';
234
+ const doc = tableModel.docs.find((d) => d &&
235
+ typeof d === 'object' &&
236
+ !Array.isArray(d) &&
237
+ 'id' in d &&
238
+ String(d['id']) ===
239
+ String(drift.docId));
240
+ if (!doc) {
241
+ safe.push(`-- WARNING: Stock doc id=${drift.docId} not found in config for "${drift.table}"`);
242
+ break;
243
+ }
244
+ const columns = Object.keys(doc);
245
+ const values = columns.map((col) =>
246
+ // eslint-disable-next-line security/detect-object-injection -- col is from Object.keys
247
+ formatSqlValue(doc[col]));
248
+ safe.push(`-- Insert missing stock doc: ${drift.details}`);
249
+ safe.push(`INSERT INTO "${drift.table}" (${columns.map((c) => `"${c}"`).join(', ')})`);
250
+ safe.push(`VALUES (${values.join(', ')})`);
251
+ safe.push(`ON CONFLICT ("${primaryKey}") DO NOTHING;`);
252
+ safe.push('');
253
+ break;
254
+ }
255
+ case 'check_constraint_mismatch': {
256
+ const columnName = drift.column ?? '';
257
+ const constraintName = drift.constraintName;
258
+ const tableModel = config.tables[drift.table];
259
+ if (!tableModel || !('properties' in tableModel.schema)) {
260
+ safe.push(`-- WARNING: Cannot find schema for "${drift.table}"`);
261
+ break;
262
+ }
263
+ // eslint-disable-next-line security/detect-object-injection -- columnName is from schema
264
+ const colSchema = tableModel.schema.properties[columnName];
265
+ if (!colSchema || colSchema.type !== 'enum' || !colSchema.enum) {
266
+ safe.push(`-- WARNING: Column "${columnName}" is not an enum in schema`);
267
+ break;
268
+ }
269
+ const newValues = colSchema.enum.map((v) => `'${v}'`).join(', ');
270
+ const newConstraintName = `${drift.table}_${columnName}_check`;
271
+ safe.push(`-- Update CHECK constraint for "${drift.table}"."${columnName}"`);
272
+ safe.push(`-- Old values: ${drift.actual}`);
273
+ safe.push(`-- New values: ${drift.expected}`);
274
+ if (constraintName) {
275
+ safe.push(`ALTER TABLE "${drift.table}" DROP CONSTRAINT IF EXISTS "${constraintName}";`);
276
+ }
277
+ if (constraintName !== newConstraintName) {
278
+ safe.push(`ALTER TABLE "${drift.table}" DROP CONSTRAINT IF EXISTS "${newConstraintName}";`);
279
+ }
280
+ safe.push(`ALTER TABLE "${drift.table}" ADD CONSTRAINT "${newConstraintName}" CHECK ("${columnName}" IN (${newValues}));`);
281
+ safe.push('');
282
+ break;
283
+ }
284
+ case 'missing_constraint': {
285
+ const columnName = drift.column ?? '';
286
+ const tableModel = config.tables[drift.table];
287
+ if (!tableModel || !('properties' in tableModel.schema)) {
288
+ safe.push(`-- WARNING: Cannot find schema for "${drift.table}"`);
289
+ break;
290
+ }
291
+ // eslint-disable-next-line security/detect-object-injection -- columnName is from schema
292
+ const colSchema = tableModel.schema.properties[columnName];
293
+ if (!colSchema || colSchema.type !== 'enum' || !colSchema.enum) {
294
+ safe.push(`-- WARNING: Column "${columnName}" is not an enum in schema`);
295
+ break;
296
+ }
297
+ const newValues = colSchema.enum.map((v) => `'${v}'`).join(', ');
298
+ const newConstraintName = `${drift.table}_${columnName}_check`;
299
+ safe.push(`-- Add missing CHECK constraint for "${drift.table}"."${columnName}"`);
300
+ safe.push(`ALTER TABLE "${drift.table}" DROP CONSTRAINT IF EXISTS "${newConstraintName}";`);
301
+ safe.push(`ALTER TABLE "${drift.table}" ADD CONSTRAINT "${newConstraintName}" CHECK ("${columnName}" IN (${newValues}));`);
302
+ safe.push('');
303
+ break;
304
+ }
305
+ default:
306
+ safe.push(`-- Unhandled drift type: ${drift.type}`);
307
+ safe.push(`-- ${drift.details}`);
308
+ safe.push('');
309
+ }
310
+ }
311
+ return { safe, destructive };
312
+ }
313
+ export async function generateMigration(connectionString, config) {
314
+ const drifts = await detectDrift(connectionString, config);
315
+ if (drifts.length === 0) {
316
+ return { safe: '', destructive: '', driftCount: 0 };
317
+ }
318
+ const { safe, destructive } = driftToSql(drifts, config);
319
+ const timestamp = new Date().toISOString();
320
+ const safeContent = safe.length > 0
321
+ ? [
322
+ '-- Schema Migration (Safe Operations)',
323
+ `-- Generated: ${timestamp}`,
324
+ `-- Drifts detected: ${drifts.length}`,
325
+ '',
326
+ 'BEGIN;',
327
+ '',
328
+ ...safe,
329
+ 'COMMIT;',
330
+ ].join('\n')
331
+ : '';
332
+ const destructiveContent = destructive.length > 0
333
+ ? [
334
+ '-- Schema Migration (DESTRUCTIVE Operations)',
335
+ `-- Generated: ${timestamp}`,
336
+ '-- WARNING: These operations will DELETE data!',
337
+ '',
338
+ 'BEGIN;',
339
+ '',
340
+ ...destructive,
341
+ 'COMMIT;',
342
+ ].join('\n')
343
+ : '';
344
+ return {
345
+ safe: safeContent,
346
+ destructive: destructiveContent,
347
+ driftCount: drifts.length,
348
+ };
349
+ }
350
+ //# sourceMappingURL=migrate.js.map