@zmdb/migrations 1.0.0-beta.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 (114) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +36 -0
  3. package/dist/declarations/emit.d.ts +23 -0
  4. package/dist/declarations/emit.d.ts.map +1 -0
  5. package/dist/declarations/emit.js +581 -0
  6. package/dist/declarations/emit.js.map +1 -0
  7. package/dist/declarations/index.d.ts +3 -0
  8. package/dist/declarations/index.d.ts.map +1 -0
  9. package/dist/declarations/index.js +3 -0
  10. package/dist/declarations/index.js.map +1 -0
  11. package/dist/declarations/tagged-property.d.ts +33 -0
  12. package/dist/declarations/tagged-property.d.ts.map +1 -0
  13. package/dist/declarations/tagged-property.js +148 -0
  14. package/dist/declarations/tagged-property.js.map +1 -0
  15. package/dist/embedded.d.ts +25 -0
  16. package/dist/embedded.d.ts.map +1 -0
  17. package/dist/embedded.js +133 -0
  18. package/dist/embedded.js.map +1 -0
  19. package/dist/file-io.d.ts +15 -0
  20. package/dist/file-io.d.ts.map +1 -0
  21. package/dist/file-io.js +92 -0
  22. package/dist/file-io.js.map +1 -0
  23. package/dist/files.d.ts +11 -0
  24. package/dist/files.d.ts.map +1 -0
  25. package/dist/files.js +10 -0
  26. package/dist/files.js.map +1 -0
  27. package/dist/index.d.ts +70 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +350 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/introspect/common.d.ts +26 -0
  32. package/dist/introspect/common.d.ts.map +1 -0
  33. package/dist/introspect/common.js +155 -0
  34. package/dist/introspect/common.js.map +1 -0
  35. package/dist/introspect/drift.d.ts +45 -0
  36. package/dist/introspect/drift.d.ts.map +1 -0
  37. package/dist/introspect/drift.js +84 -0
  38. package/dist/introspect/drift.js.map +1 -0
  39. package/dist/introspect/index.d.ts +8 -0
  40. package/dist/introspect/index.d.ts.map +1 -0
  41. package/dist/introspect/index.js +10 -0
  42. package/dist/introspect/index.js.map +1 -0
  43. package/dist/operations/check.d.ts +16 -0
  44. package/dist/operations/check.d.ts.map +1 -0
  45. package/dist/operations/check.js +236 -0
  46. package/dist/operations/check.js.map +1 -0
  47. package/dist/operations/embed.d.ts +23 -0
  48. package/dist/operations/embed.d.ts.map +1 -0
  49. package/dist/operations/embed.js +52 -0
  50. package/dist/operations/embed.js.map +1 -0
  51. package/dist/operations/export.d.ts +9 -0
  52. package/dist/operations/export.d.ts.map +1 -0
  53. package/dist/operations/export.js +15 -0
  54. package/dist/operations/export.js.map +1 -0
  55. package/dist/operations/generate.d.ts +17 -0
  56. package/dist/operations/generate.d.ts.map +1 -0
  57. package/dist/operations/generate.js +115 -0
  58. package/dist/operations/generate.js.map +1 -0
  59. package/dist/operations/migrate.d.ts +23 -0
  60. package/dist/operations/migrate.d.ts.map +1 -0
  61. package/dist/operations/migrate.js +67 -0
  62. package/dist/operations/migrate.js.map +1 -0
  63. package/dist/operations/pull.d.ts +40 -0
  64. package/dist/operations/pull.d.ts.map +1 -0
  65. package/dist/operations/pull.js +100 -0
  66. package/dist/operations/pull.js.map +1 -0
  67. package/dist/operations/push.d.ts +20 -0
  68. package/dist/operations/push.d.ts.map +1 -0
  69. package/dist/operations/push.js +82 -0
  70. package/dist/operations/push.js.map +1 -0
  71. package/dist/operations/upgrade.d.ts +10 -0
  72. package/dist/operations/upgrade.d.ts.map +1 -0
  73. package/dist/operations/upgrade.js +38 -0
  74. package/dist/operations/upgrade.js.map +1 -0
  75. package/dist/project.d.ts +46 -0
  76. package/dist/project.d.ts.map +1 -0
  77. package/dist/project.js +42 -0
  78. package/dist/project.js.map +1 -0
  79. package/dist/runner.d.ts +59 -0
  80. package/dist/runner.d.ts.map +1 -0
  81. package/dist/runner.js +163 -0
  82. package/dist/runner.js.map +1 -0
  83. package/dist/testing/official-dialects.fixture.d.ts +16 -0
  84. package/dist/testing/official-dialects.fixture.d.ts.map +1 -0
  85. package/dist/testing/official-dialects.fixture.js +21 -0
  86. package/dist/testing/official-dialects.fixture.js.map +1 -0
  87. package/dist/testing.d.ts +8 -0
  88. package/dist/testing.d.ts.map +1 -0
  89. package/dist/testing.js +27 -0
  90. package/dist/testing.js.map +1 -0
  91. package/package.json +81 -0
  92. package/src/declarations/emit.ts +705 -0
  93. package/src/declarations/index.ts +13 -0
  94. package/src/declarations/tagged-property.ts +163 -0
  95. package/src/embedded.ts +192 -0
  96. package/src/file-io.ts +114 -0
  97. package/src/files.ts +34 -0
  98. package/src/index.ts +502 -0
  99. package/src/introspect/__fixtures__/mysql-8.4.11.json +371 -0
  100. package/src/introspect/common.ts +203 -0
  101. package/src/introspect/drift.ts +157 -0
  102. package/src/introspect/index.ts +33 -0
  103. package/src/operations/check.ts +309 -0
  104. package/src/operations/embed.ts +87 -0
  105. package/src/operations/export.ts +21 -0
  106. package/src/operations/generate.ts +144 -0
  107. package/src/operations/migrate.ts +110 -0
  108. package/src/operations/pull.ts +160 -0
  109. package/src/operations/push.ts +98 -0
  110. package/src/operations/upgrade.ts +56 -0
  111. package/src/project.ts +93 -0
  112. package/src/runner.ts +260 -0
  113. package/src/testing/official-dialects.fixture.ts +24 -0
  114. package/src/testing.ts +32 -0
@@ -0,0 +1,115 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import {} from '@zmdb/sql';
4
+ import { writeTextAtomically } from '../file-io.js';
5
+ import { diff, emitDown, emitUp, snapshot } from '../index.js';
6
+ import { migrationTarget } from '../project.js';
7
+ const EMPTY_SNAPSHOT = { version: 1, tables: [], extensions: [] };
8
+ /** Load declarations, diff once, emit the plan unchanged, and persist both artefacts. */
9
+ export async function generateMigration(project, options = {}) {
10
+ const next = snapshot(project.schemas);
11
+ const snapshotPath = join(project.outDir, 'snapshot.json');
12
+ const previous = await readSnapshot(snapshotPath);
13
+ const target = migrationTarget(project);
14
+ const ops = diff(previous, next, { dialect: target });
15
+ target.migrations.validatePlan({ before: previous, after: next, operations: ops });
16
+ if (ops.length === 0)
17
+ return { ops };
18
+ const name = migrationName(options.name, ops);
19
+ const versionText = migrationVersion(options.now ?? new Date());
20
+ const migrationPath = join(project.outDir, `${versionText}_${name}.sql`);
21
+ const up = ops.map(operation => configuredEmitUp(operation, target));
22
+ const down = downStatements(ops, previous, target);
23
+ const migration = `-- zmdb:up\n${statements(up)}-- zmdb:down\n${statements(down)}`;
24
+ await writeTextAtomically(migrationPath, migration);
25
+ await writeTextAtomically(snapshotPath, `${JSON.stringify(next, null, 2)}\n`);
26
+ return {
27
+ file: migrationPath,
28
+ version: Number(versionText),
29
+ name,
30
+ ops,
31
+ };
32
+ }
33
+ function downStatements(ops, previous, dialect) {
34
+ return ops
35
+ .toReversed()
36
+ .filter(operation => operation.kind !== 'create_extension')
37
+ .map(operation => {
38
+ if (operation.kind !== 'drop_foreign_key') {
39
+ return emitDown(operation, dialect);
40
+ }
41
+ const table = previous.tables.find(candidate => candidate.name === operation.table);
42
+ const foreignKey = table?.foreignKeys?.find(candidate => candidate.name === operation.name);
43
+ if (foreignKey === undefined) {
44
+ throw new Error(`cannot generate the down migration for foreign key "${operation.name}" on "${operation.table}": ` +
45
+ 'the previous snapshot does not contain its columns and referential actions');
46
+ }
47
+ return configuredEmitUp({ kind: 'add_foreign_key', table: operation.table, fk: foreignKey }, dialect);
48
+ });
49
+ }
50
+ function configuredEmitUp(operation, dialect) {
51
+ return emitUp(operation, dialect);
52
+ }
53
+ async function readSnapshot(path) {
54
+ try {
55
+ return JSON.parse(await readFile(path, 'utf8'));
56
+ }
57
+ catch (error) {
58
+ if (errorCode(error) === 'ENOENT')
59
+ return EMPTY_SNAPSHOT;
60
+ throw new Error(`could not read stored snapshot ${path}: ${error instanceof Error ? error.message : String(error)}`, {
61
+ cause: error,
62
+ });
63
+ }
64
+ }
65
+ function migrationVersion(now) {
66
+ return now.toISOString().replaceAll(/\D/g, '').slice(0, 14);
67
+ }
68
+ function migrationName(requested, ops) {
69
+ const source = requested ?? derivedName(ops);
70
+ const slug = source
71
+ .trim()
72
+ .toLowerCase()
73
+ .replaceAll(/[^a-z0-9]+/g, '_')
74
+ .replaceAll(/^_+|_+$/g, '');
75
+ if (slug.length === 0)
76
+ throw new Error(`migration name ${JSON.stringify(source)} has no letters or digits`);
77
+ return slug;
78
+ }
79
+ function derivedName(ops) {
80
+ if (ops.length !== 1)
81
+ return 'schema_change';
82
+ const operation = ops[0];
83
+ if (operation === undefined)
84
+ return 'schema_change';
85
+ switch (operation.kind) {
86
+ case 'create_extension':
87
+ return `create_${operation.name}_extension`;
88
+ case 'create_table':
89
+ return `create_${operation.table}`;
90
+ case 'drop_table':
91
+ return `drop_${operation.table}`;
92
+ case 'add_column':
93
+ return `add_${operation.table}_${operation.column.name}`;
94
+ case 'drop_column':
95
+ return `drop_${operation.table}_${operation.column}`;
96
+ case 'alter_column_type':
97
+ return `alter_${operation.table}_${operation.column}`;
98
+ case 'alter_primary_key':
99
+ return `alter_${operation.table}_primary_key`;
100
+ case 'add_foreign_key':
101
+ return `add_${operation.table}_${operation.fk.name}`;
102
+ case 'drop_foreign_key':
103
+ return `drop_${operation.table}_${operation.name}`;
104
+ }
105
+ }
106
+ function statements(values) {
107
+ return values.length === 0 ? '' : `${values.join(';\n')};\n`;
108
+ }
109
+ function errorCode(error) {
110
+ if (typeof error !== 'object' || error === null)
111
+ return undefined;
112
+ const code = Reflect.get(error, 'code');
113
+ return typeof code === 'string' ? code : undefined;
114
+ }
115
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/operations/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAmB,MAAM,WAAW,CAAC;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAsC,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,eAAe,EAAyB,MAAM,eAAe,CAAC;AAEvE,MAAM,cAAc,GAAmB,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;AAgBlF,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAyB,EACzB,OAAO,GAAoB,EAAE;IAE7B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IACnF,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAErC,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,WAAW,IAAI,IAAI,MAAM,CAAC,CAAC;IACzE,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IACrE,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,eAAe,UAAU,CAAC,EAAE,CAAC,iBAAiB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;IAEnF,MAAM,mBAAmB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACpD,MAAM,mBAAmB,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAE9E,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC;QAC5B,IAAI;QACJ,GAAG;KACJ,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,GAAwB,EAAE,QAAwB,EAAE,OAAmB;IAC7F,OAAO,GAAG;SACP,UAAU,EAAE;SACZ,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,kBAAkB,CAAC;SAC1D,GAAG,CAAC,SAAS,CAAC,EAAE;QACf,IAAI,SAAS,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAC1C,OAAO,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,CAAC,CAAC;QACpF,MAAM,UAAU,GAAG,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5F,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,uDAAuD,SAAS,CAAC,IAAI,SAAS,SAAS,CAAC,KAAK,KAAK;gBAChG,4EAA4E,CAC/E,CAAC;QACJ,CAAC;QACD,OAAO,gBAAgB,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;IACxG,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAmB,EAAE,OAAmB;IAChE,OAAO,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAY;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ;YAAE,OAAO,cAAc,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EACnG;YACE,KAAK,EAAE,KAAK;SACb,CACF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAS;IACjC,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,aAAa,CAAC,SAA6B,EAAE,GAAwB;IAC5E,MAAM,MAAM,GAAG,SAAS,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM;SAChB,IAAI,EAAE;SACN,WAAW,EAAE;SACb,UAAU,CAAC,aAAa,EAAE,GAAG,CAAC;SAC9B,UAAU,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAC5G,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,GAAwB;IAC3C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,eAAe,CAAC;IAC7C,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,eAAe,CAAC;IACpD,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;QACvB,KAAK,kBAAkB;YACrB,OAAO,UAAU,SAAS,CAAC,IAAI,YAAY,CAAC;QAC9C,KAAK,cAAc;YACjB,OAAO,UAAU,SAAS,CAAC,KAAK,EAAE,CAAC;QACrC,KAAK,YAAY;YACf,OAAO,QAAQ,SAAS,CAAC,KAAK,EAAE,CAAC;QACnC,KAAK,YAAY;YACf,OAAO,OAAO,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC3D,KAAK,aAAa;YAChB,OAAO,QAAQ,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;QACvD,KAAK,mBAAmB;YACtB,OAAO,SAAS,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;QACxD,KAAK,mBAAmB;YACtB,OAAO,SAAS,SAAS,CAAC,KAAK,cAAc,CAAC;QAChD,KAAK,iBAAiB;YACpB,OAAO,OAAO,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QACvD,KAAK,kBAAkB;YACrB,OAAO,QAAQ,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;IACvD,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAAyB;IAC3C,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC/D,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { type MigrationProject } from '../project.js';
2
+ import { type MigrationStatus } from '../runner.js';
3
+ export interface AppliedMigrationResult {
4
+ readonly version: number;
5
+ readonly name: string;
6
+ }
7
+ export interface MigrateResult {
8
+ readonly applied: readonly AppliedMigrationResult[];
9
+ }
10
+ export interface RollbackResult {
11
+ readonly reverted: AppliedMigrationResult | null;
12
+ readonly versions: readonly AppliedMigrationResult[];
13
+ }
14
+ export interface StatusResult {
15
+ readonly migrations: readonly MigrationStatus[];
16
+ }
17
+ export interface MigrationCommandOptions {
18
+ readonly progress: (text: string) => void;
19
+ }
20
+ export declare function migrate(project: MigrationProject, options: MigrationCommandOptions): Promise<MigrateResult>;
21
+ export declare function rollback(project: MigrationProject, target: number | undefined, options: MigrationCommandOptions): Promise<RollbackResult>;
22
+ export declare function migrationStatus(project: MigrationProject): Promise<StatusResult>;
23
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/operations/migrate.ts"],"names":[],"mappings":"AACA,OAAO,EAAmC,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACrD;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,QAAQ,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACtD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,aAAa,CAAC,CAkBjH;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,cAAc,CAAC,CAwBzB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAItF"}
@@ -0,0 +1,67 @@
1
+ import { readMigrations } from '../file-io.js';
2
+ import { migrationTarget, requiredDriver } from '../project.js';
3
+ import { down, downTo, driverMigrationConnection, status, up, } from '../runner.js';
4
+ export async function migrate(project, options) {
5
+ const migrations = await readMigrations(project.outDir);
6
+ const connection = connectionFor(project);
7
+ const before = await status(connection, migrations);
8
+ const pending = pendingMigrations(migrations, before);
9
+ for (const migration of pending)
10
+ options.progress(renderMigration('apply', migration));
11
+ const appliedVersions = await up(connection, migrations, {
12
+ onWarning: warning => options.progress(`warning: ${warning}\n`),
13
+ });
14
+ const byVersion = new Map(migrations.map(migration => [migration.version, migration]));
15
+ return {
16
+ applied: appliedVersions.map(version => {
17
+ const migration = byVersion.get(version);
18
+ if (migration === undefined)
19
+ throw new Error(`runner applied unknown migration ${String(version)}`);
20
+ return { version, name: migration.name };
21
+ }),
22
+ };
23
+ }
24
+ export async function rollback(project, target, options) {
25
+ const migrations = await readMigrations(project.outDir);
26
+ const connection = connectionFor(project);
27
+ const before = await status(connection, migrations);
28
+ const applied = before.filter(item => item.applied).toSorted((left, right) => right.version - left.version);
29
+ const selected = target === undefined ? applied.slice(0, 1) : applied.filter(item => item.version > target);
30
+ const byVersion = new Map(migrations.map(migration => [migration.version, migration]));
31
+ for (const item of selected) {
32
+ const migration = byVersion.get(item.version);
33
+ if (migration !== undefined)
34
+ options.progress(renderMigration('revert', migration));
35
+ }
36
+ const revertedVersions = target === undefined
37
+ ? ((version) => (version === undefined ? [] : [version]))(await down(connection, migrations))
38
+ : await downTo(connection, migrations, target);
39
+ const versions = revertedVersions.map(version => {
40
+ const migration = byVersion.get(version);
41
+ if (migration === undefined)
42
+ throw new Error(`runner reverted unknown migration ${String(version)}`);
43
+ return { version, name: migration.name };
44
+ });
45
+ return { reverted: versions[0] ?? null, versions };
46
+ }
47
+ export async function migrationStatus(project) {
48
+ const migrations = await readMigrations(project.outDir);
49
+ const connection = connectionFor(project);
50
+ return { migrations: await status(connection, migrations) };
51
+ }
52
+ function pendingMigrations(migrations, statuses) {
53
+ const applied = new Set(statuses.filter(item => item.applied).map(item => item.version));
54
+ return migrations.filter(migration => !applied.has(migration.version)).toSorted((a, b) => a.version - b.version);
55
+ }
56
+ function renderMigration(action, migration) {
57
+ const sql = action === 'apply' ? migration.up : migration.down;
58
+ return `${action} ${String(migration.version)} ${migration.name}\n${sql}${sql.endsWith('\n') ? '' : '\n'}`;
59
+ }
60
+ function connectionFor(project) {
61
+ const driver = requiredDriver(project);
62
+ return driverMigrationConnection(driver, migrationTarget(project), {
63
+ ...(project.migrations?.table === undefined ? {} : { table: project.migrations.table }),
64
+ ...(project.migrations?.schema === undefined ? {} : { schema: project.migrations.schema }),
65
+ });
66
+ }
67
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/operations/migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { CatalogWarning } from '../introspect/index.js';
2
+ import { type MigrationProject } from '../project.js';
3
+ export interface PullOptions {
4
+ /** Print the complete generated files and write nothing. */
5
+ readonly dryRun?: boolean;
6
+ /** Compare generated bytes with the staging tree and write nothing. */
7
+ readonly check?: boolean;
8
+ }
9
+ export interface PullFile {
10
+ readonly path: string;
11
+ readonly tables: readonly string[];
12
+ }
13
+ export interface PullSkippedFile {
14
+ readonly path: string;
15
+ readonly reason: string;
16
+ }
17
+ export interface PullResult {
18
+ readonly files: readonly PullFile[];
19
+ readonly skipped: readonly PullSkippedFile[];
20
+ }
21
+ export interface PullOutputFile extends PullFile {
22
+ readonly source: string;
23
+ readonly barrel: boolean;
24
+ }
25
+ export interface PullExecution {
26
+ readonly result: PullResult;
27
+ readonly warnings: readonly CatalogWarning[];
28
+ readonly outputs: readonly PullOutputFile[];
29
+ readonly exitCode: 0 | 1;
30
+ readonly mode: 'write' | 'dry-run' | 'check';
31
+ }
32
+ /**
33
+ * Read a live catalogue and reconcile the deterministic staging declarations.
34
+ *
35
+ * The staging tree is deliberately separate from application-owned schema
36
+ * files. A file is replaceable only when the emitter's two-line header proves
37
+ * that zmdb created it; `--check` and `--dry-run` never write.
38
+ */
39
+ export declare function pullDeclarations(project: MigrationProject, options?: PullOptions): Promise<PullExecution>;
40
+ //# sourceMappingURL=pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/operations/pull.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAoE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAExH,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,cAAe,SAAQ,QAAQ;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;CAC9C;AAUD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAmDnH"}
@@ -0,0 +1,100 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { dirname, join, relative } from 'node:path';
3
+ import { writeTextAtomically } from '../file-io.js';
4
+ import { requiredDeclarationEmitter, requiredDriver, requiredIntrospector } from '../project.js';
5
+ const GENERATED_HEADER = /^\/\/ Generated by zmdb introspection from a [^\r\n]+ database\. Do not edit; regenerate instead\.\r?\n\/\/ Snapshot version \d+\. Hand edits are overwritten wholesale\.\r?\n/;
6
+ /**
7
+ * Read a live catalogue and reconcile the deterministic staging declarations.
8
+ *
9
+ * The staging tree is deliberately separate from application-owned schema
10
+ * files. A file is replaceable only when the emitter's two-line header proves
11
+ * that zmdb created it; `--check` and `--dry-run` never write.
12
+ */
13
+ export async function pullDeclarations(project, options = {}) {
14
+ const driver = requiredDriver(project);
15
+ const snapshot = await requiredIntrospector(project).snapshot(driver, project.introspect);
16
+ const emitted = await requiredDeclarationEmitter(project)(snapshot, { dialect: project.dialect });
17
+ const projectRoot = dirname(project.configPath);
18
+ const outputRoot = join(projectRoot, '.zmdb', 'introspected');
19
+ const outputs = declarationOutputs(emitted.files, snapshot.tables.map(table => table.name), outputRoot, projectRoot);
20
+ const skipped = [];
21
+ const available = [];
22
+ const mode = options.check === true ? 'check' : options.dryRun === true ? 'dry-run' : 'write';
23
+ for (const output of outputs) {
24
+ const destination = join(projectRoot, output.path);
25
+ const current = await readText(destination);
26
+ if (current !== undefined && !GENERATED_HEADER.test(current)) {
27
+ skipped.push({
28
+ path: output.path,
29
+ reason: 'existing file has no zmdb introspection header; left it untouched',
30
+ });
31
+ continue;
32
+ }
33
+ if (mode === 'check') {
34
+ if (current === undefined) {
35
+ skipped.push({ path: output.path, reason: 'generated declaration is missing' });
36
+ continue;
37
+ }
38
+ if (current !== output.source) {
39
+ skipped.push({ path: output.path, reason: 'generated declaration differs from the live database' });
40
+ continue;
41
+ }
42
+ }
43
+ else if (mode === 'write') {
44
+ await writeTextAtomically(destination, output.source);
45
+ }
46
+ if (!output.barrel)
47
+ available.push({ path: output.path, tables: output.tables });
48
+ }
49
+ return {
50
+ result: { files: available, skipped },
51
+ warnings: emitted.warnings,
52
+ outputs,
53
+ exitCode: skipped.length === 0 ? 0 : 1,
54
+ mode,
55
+ };
56
+ }
57
+ function declarationOutputs(files, tableNames, outputRoot, projectRoot) {
58
+ const sortedTables = tableNames.toSorted();
59
+ let tableIndex = 0;
60
+ const outputs = files.map(file => {
61
+ const barrel = file.path === 'index.ts';
62
+ const tables = barrel ? sortedTables : [requiredTable(sortedTables, tableIndex, file.path)];
63
+ if (!barrel)
64
+ tableIndex += 1;
65
+ return {
66
+ path: relative(projectRoot, join(outputRoot, file.path)),
67
+ tables,
68
+ source: file.source,
69
+ barrel,
70
+ };
71
+ });
72
+ if (tableIndex !== sortedTables.length) {
73
+ throw new TypeError(`declaration emitter returned ${String(tableIndex)} table files for ${String(sortedTables.length)} tables`);
74
+ }
75
+ return outputs;
76
+ }
77
+ function requiredTable(tables, index, path) {
78
+ const table = tables[index];
79
+ if (table === undefined) {
80
+ throw new TypeError(`declaration emitter returned unexpected table file "${path}"`);
81
+ }
82
+ return table;
83
+ }
84
+ async function readText(path) {
85
+ try {
86
+ return await readFile(path, 'utf8');
87
+ }
88
+ catch (error) {
89
+ if (errorCode(error) === 'ENOENT')
90
+ return undefined;
91
+ throw error;
92
+ }
93
+ }
94
+ function errorCode(error) {
95
+ if (typeof error !== 'object' || error === null)
96
+ return undefined;
97
+ const code = Reflect.get(error, 'code');
98
+ return typeof code === 'string' ? code : undefined;
99
+ }
100
+ //# sourceMappingURL=pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/operations/pull.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type ChangeOp } from '../index.js';
2
+ import { type MigrationProject } from '../project.js';
3
+ import { type MigrationConnection, type MigrationDriver } from '../runner.js';
4
+ export interface PushPlan {
5
+ readonly ops: readonly ChangeOp[];
6
+ readonly statements: readonly string[];
7
+ readonly destructive: readonly string[];
8
+ readonly driver: MigrationDriver;
9
+ readonly connection: MigrationConnection;
10
+ }
11
+ export interface PushResult {
12
+ readonly ops: readonly ChangeOp[];
13
+ readonly statements: readonly string[];
14
+ readonly applied: boolean;
15
+ }
16
+ export declare function planPush(project: MigrationProject): Promise<PushPlan>;
17
+ export declare function applyPush(plan: PushPlan, warning: (message: string) => void): Promise<PushResult>;
18
+ /** Classify every current ChangeOp. New union members make this switch fail typechecking. */
19
+ export declare function isDestructive(operation: ChangeOp): boolean;
20
+ //# sourceMappingURL=push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/operations/push.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,QAAQ,EAA2C,MAAM,aAAa,CAAC;AAE7G,OAAO,EAAyD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7G,OAAO,EAA6B,KAAK,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzG,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,GAAG,EAAE,SAAS,QAAQ,EAAE,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,SAAS,QAAQ,EAAE,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwB3E;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAgBvG;AAED,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,SAAS,EAAE,QAAQ,GAAG,OAAO,CAe1D"}
@@ -0,0 +1,82 @@
1
+ import { diff, emitUp, snapshot } from '../index.js';
2
+ import { detectDrift } from '../introspect/index.js';
3
+ import { migrationTarget, requiredDriver, requiredIntrospector } from '../project.js';
4
+ import { driverMigrationConnection } from '../runner.js';
5
+ export async function planPush(project) {
6
+ const driver = requiredDriver(project);
7
+ const declared = declaredSnapshot(project);
8
+ const introspector = requiredIntrospector(project);
9
+ const live = introspector.normalizeForDrift(await introspector.snapshot(driver, project.introspect), 'live');
10
+ const normalizedDeclared = introspector.normalizeForDrift(declared, 'declared');
11
+ const target = migrationTarget(project);
12
+ const drift = detectDrift(live, normalizedDeclared, { dialect: project.dialect });
13
+ const ops = diff(live, normalizedDeclared, { dialect: target });
14
+ target.migrations.validatePlan({ before: live, after: normalizedDeclared, operations: ops });
15
+ const statements = ops.map(operation => emitUp(operation, target));
16
+ const destructive = ops
17
+ .map((operation, index) => (isDestructive(operation) ? statements[index] : undefined))
18
+ .filter(statement => statement !== undefined);
19
+ if (drift.clean !== (ops.length === 0)) {
20
+ throw new Error('push planning disagreed with the drift detector');
21
+ }
22
+ return {
23
+ ops,
24
+ statements,
25
+ destructive,
26
+ driver,
27
+ connection: driverMigrationConnection(driver, target),
28
+ };
29
+ }
30
+ export async function applyPush(plan, warning) {
31
+ if (plan.statements.length === 0)
32
+ return { ops: plan.ops, statements: plan.statements, applied: false };
33
+ if (plan.connection.transactionalDdl === false) {
34
+ const target = plan.connection.dialect;
35
+ const name = typeof target === 'string' ? target : (target?.name ?? 'database');
36
+ warning(`${name} does not support transactional DDL; a failed push may leave only part of the printed plan applied`);
37
+ }
38
+ const run = async (connection = plan.connection) => {
39
+ for (const statement of plan.statements)
40
+ await connection.exec(statement);
41
+ };
42
+ if (plan.connection.transaction === undefined)
43
+ await run();
44
+ else
45
+ await plan.connection.transaction(transaction => run(transaction ?? plan.connection));
46
+ return { ops: plan.ops, statements: plan.statements, applied: true };
47
+ }
48
+ /** Classify every current ChangeOp. New union members make this switch fail typechecking. */
49
+ export function isDestructive(operation) {
50
+ switch (operation.kind) {
51
+ case 'create_extension':
52
+ case 'create_table':
53
+ case 'add_column':
54
+ case 'alter_primary_key':
55
+ case 'add_foreign_key':
56
+ case 'drop_foreign_key':
57
+ return false;
58
+ case 'drop_table':
59
+ case 'drop_column':
60
+ return true;
61
+ case 'alter_column_type':
62
+ return narrowsType(operation.from, operation.to);
63
+ }
64
+ }
65
+ function narrowsType(from, to) {
66
+ if (typeof from !== 'string' || typeof to !== 'string')
67
+ return true;
68
+ if (from === to)
69
+ return false;
70
+ return !KNOWN_WIDENINGS.has(`${from}->${to}`);
71
+ }
72
+ const KNOWN_WIDENINGS = new Set([
73
+ 'integer->bigint',
74
+ 'integer->numeric',
75
+ 'bigint->numeric',
76
+ 'varchar->text',
77
+ 'date->timestamp',
78
+ ]);
79
+ function declaredSnapshot(project) {
80
+ return snapshot(project.schemas);
81
+ }
82
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/operations/push.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type MigrationProject } from '../project.js';
2
+ export interface UpgradeResult {
3
+ readonly from: number;
4
+ readonly to: 1;
5
+ readonly changed: boolean;
6
+ readonly backup?: string;
7
+ }
8
+ /** Upgrade known snapshot formats without touching the database. */
9
+ export declare function upgradeSnapshot(project: MigrationProject): Promise<UpgradeResult>;
10
+ //# sourceMappingURL=upgrade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/operations/upgrade.ts"],"names":[],"mappings":"AAKA,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE7E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IACf,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,oEAAoE;AACpE,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAiBvF"}
@@ -0,0 +1,38 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { writeTextAtomically } from '../file-io.js';
4
+ import { MigrationProjectError } from '../project.js';
5
+ /** Upgrade known snapshot formats without touching the database. */
6
+ export async function upgradeSnapshot(project) {
7
+ const path = join(project.outDir, 'snapshot.json');
8
+ const source = await readFile(path, 'utf8');
9
+ const parsed = snapshotRecord(JSON.parse(source), path);
10
+ const version = snapshotVersion(parsed, path);
11
+ if (version > 1) {
12
+ throw new MigrationProjectError(`snapshot ${path} uses version ${String(version)}, newer than this build's version 1`);
13
+ }
14
+ if (version === 1)
15
+ return { from: 1, to: 1, changed: false };
16
+ const upgraded = upgradeKnownVersion(parsed, version, path);
17
+ const backup = `${path}.bak`;
18
+ await writeTextAtomically(backup, source);
19
+ await writeTextAtomically(path, `${JSON.stringify(upgraded, null, 2)}\n`);
20
+ return { from: version, to: 1, changed: true, backup };
21
+ }
22
+ function upgradeKnownVersion(_snapshot, version, path) {
23
+ throw new MigrationProjectError(`snapshot ${path} uses version ${String(version)}, which this build cannot upgrade`);
24
+ }
25
+ function snapshotRecord(value, path) {
26
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
27
+ throw new MigrationProjectError(`snapshot ${path} must be a JSON object`);
28
+ }
29
+ return Object.fromEntries(Object.entries(value));
30
+ }
31
+ function snapshotVersion(snapshot, path) {
32
+ const version = snapshot.version;
33
+ if (typeof version !== 'number' || !Number.isSafeInteger(version)) {
34
+ throw new MigrationProjectError(`snapshot ${path} has no safe integer version`);
35
+ }
36
+ return version;
37
+ }
38
+ //# sourceMappingURL=upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/operations/upgrade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAyB,MAAM,eAAe,CAAC;AAS7E,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAyB;IAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC9C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,qBAAqB,CAC7B,YAAY,IAAI,iBAAiB,MAAM,CAAC,OAAO,CAAC,qCAAqC,CACtF,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAE7D,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC;IAC7B,MAAM,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,mBAAmB,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACzD,CAAC;AAED,SAAS,mBAAmB,CAC1B,SAA4C,EAC5C,OAAe,EACf,IAAY;IAEZ,MAAM,IAAI,qBAAqB,CAAC,YAAY,IAAI,iBAAiB,MAAM,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;AACvH,CAAC;AAED,SAAS,cAAc,CAAC,KAAc,EAAE,IAAY;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,qBAAqB,CAAC,YAAY,IAAI,wBAAwB,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,eAAe,CAAC,QAA2C,EAAE,IAAY;IAChF,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;IACjC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,qBAAqB,CAAC,YAAY,IAAI,8BAA8B,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { type Introspector, type IntrospectOptions, type SchemaSnapshot, type SqlDialect } from '@zmdb/sql';
2
+ import type { SnapshotableSchema } from './index.js';
3
+ import type { CatalogWarning } from './introspect/index.js';
4
+ import type { MigrationDriver } from './runner.js';
5
+ export interface MigrationProject {
6
+ readonly configPath: string;
7
+ readonly outDir: string;
8
+ readonly dialect: SqlDialect;
9
+ readonly schemas: readonly SnapshotableSchema[];
10
+ readonly migrations?: {
11
+ readonly table?: string;
12
+ readonly schema?: string;
13
+ };
14
+ readonly introspect?: IntrospectOptions;
15
+ readonly driver?: MigrationDriver;
16
+ /** Database-owned catalog reader selected by the caller. */
17
+ readonly introspector?: Introspector;
18
+ /**
19
+ * Declaration generation is injected so the root lifecycle graph does not
20
+ * acquire the formatter owned by `@zmdb/migrations/declarations`.
21
+ */
22
+ readonly emitDeclarations?: (snapshot: SchemaSnapshot, options: {
23
+ readonly dialect: SqlDialect;
24
+ }) => Promise<{
25
+ readonly files: readonly {
26
+ readonly path: string;
27
+ readonly source: string;
28
+ }[];
29
+ readonly warnings: readonly CatalogWarning[];
30
+ }>;
31
+ /**
32
+ * Generated migration modules are formatted by the caller. The CLI supplies
33
+ * its pinned formatter while non-CLI consumers may provide an equivalent
34
+ * deterministic implementation.
35
+ */
36
+ readonly formatSource?: (path: string, source: string) => Promise<string>;
37
+ }
38
+ export declare class MigrationProjectError extends Error {
39
+ constructor(message: string, options?: ErrorOptions);
40
+ }
41
+ export declare function requiredDriver(project: MigrationProject): MigrationDriver;
42
+ export declare function migrationTarget(project: MigrationProject): SqlDialect;
43
+ export declare function requiredDeclarationEmitter(project: MigrationProject): NonNullable<MigrationProject['emitDeclarations']>;
44
+ export declare function requiredIntrospector(project: MigrationProject): Introspector;
45
+ export declare function requiredSourceFormatter(project: MigrationProject): NonNullable<MigrationProject['formatSource']>;
46
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAChD,QAAQ,CAAC,UAAU,CAAC,EAAE;QACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAClC,4DAA4D;IAC5D,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAC1B,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;KAAE,KACtC,OAAO,CAAC;QACX,QAAQ,CAAC,KAAK,EAAE,SAAS;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC9E,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;KAC9C,CAAC,CAAC;IACH;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3E;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAWzE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU,CAErE;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,gBAAgB,GACxB,WAAW,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,CAMnD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,gBAAgB,GAAG,YAAY,CAM5E;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,gBAAgB,GAAG,WAAW,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAMhH"}