@happyvertical/smrt-core 0.40.70 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/AGENTS.md +3 -3
  2. package/agents/change-feed.md +1 -1
  3. package/agents/schema-paths.md +561 -32
  4. package/dist/browser.js +5 -4
  5. package/dist/cascade.d.ts +120 -0
  6. package/dist/cascade.d.ts.map +1 -0
  7. package/dist/cascade.js +430 -0
  8. package/dist/cascade.js.map +1 -0
  9. package/dist/change-feed.d.ts +34 -2
  10. package/dist/change-feed.d.ts.map +1 -1
  11. package/dist/change-feed.js +54 -13
  12. package/dist/change-feed.js.map +1 -1
  13. package/dist/change-signals.d.ts.map +1 -1
  14. package/dist/change-signals.js +8 -1
  15. package/dist/change-signals.js.map +1 -1
  16. package/dist/class.d.ts +36 -3
  17. package/dist/class.d.ts.map +1 -1
  18. package/dist/class.js +69 -14
  19. package/dist/class.js.map +1 -1
  20. package/dist/collection-cache.js +0 -0
  21. package/dist/collection-cache.js.map +1 -1
  22. package/dist/collection.d.ts +29 -0
  23. package/dist/collection.d.ts.map +1 -1
  24. package/dist/collection.js +68 -16
  25. package/dist/collection.js.map +1 -1
  26. package/dist/config.d.ts +10 -0
  27. package/dist/config.d.ts.map +1 -1
  28. package/dist/config.js.map +1 -1
  29. package/dist/decorators/index.d.ts +63 -5
  30. package/dist/decorators/index.d.ts.map +1 -1
  31. package/dist/decorators/index.js +37 -5
  32. package/dist/decorators/index.js.map +1 -1
  33. package/dist/dispatch/collections/Dispatches.d.ts.map +1 -1
  34. package/dist/dispatch/collections/Dispatches.js +21 -6
  35. package/dist/dispatch/collections/Dispatches.js.map +1 -1
  36. package/dist/dispatch/models/Dispatch.d.ts +1 -1
  37. package/dist/dispatch/models/Dispatch.d.ts.map +1 -1
  38. package/dist/dispatch/models/Dispatch.js +3 -2
  39. package/dist/dispatch/models/Dispatch.js.map +1 -1
  40. package/dist/dispatch/models/DispatchSubscription.d.ts +1 -1
  41. package/dist/dispatch/models/DispatchSubscription.d.ts.map +1 -1
  42. package/dist/dispatch/models/DispatchSubscription.js +2 -1
  43. package/dist/dispatch/models/DispatchSubscription.js.map +1 -1
  44. package/dist/dispatch/types.d.ts +5 -0
  45. package/dist/dispatch/types.d.ts.map +1 -1
  46. package/dist/embedded-write-queue.d.ts +46 -0
  47. package/dist/embedded-write-queue.d.ts.map +1 -0
  48. package/dist/embedded-write-queue.js +66 -0
  49. package/dist/embedded-write-queue.js.map +1 -0
  50. package/dist/embeddings/storage.d.ts +7 -0
  51. package/dist/embeddings/storage.d.ts.map +1 -1
  52. package/dist/embeddings/storage.js +31 -13
  53. package/dist/embeddings/storage.js.map +1 -1
  54. package/dist/errors.d.ts +1 -1
  55. package/dist/hierarchical.js +1 -1
  56. package/dist/index.d.ts +2 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +8 -6
  59. package/dist/interceptors.d.ts +21 -0
  60. package/dist/interceptors.d.ts.map +1 -1
  61. package/dist/interceptors.js +27 -1
  62. package/dist/interceptors.js.map +1 -1
  63. package/dist/learning/memory.d.ts.map +1 -1
  64. package/dist/learning/memory.js +5 -4
  65. package/dist/learning/memory.js.map +1 -1
  66. package/dist/manifest/generator.d.ts.map +1 -1
  67. package/dist/manifest/generator.js +4 -7
  68. package/dist/manifest/generator.js.map +1 -1
  69. package/dist/manifest/static-manifest.js +10 -10
  70. package/dist/manifest/static-manifest.js.map +1 -1
  71. package/dist/manifest/store.js +1 -1
  72. package/dist/manifest/store.js.map +1 -1
  73. package/dist/manifest.json +19 -19
  74. package/dist/migrations/differ.d.ts +9 -1
  75. package/dist/migrations/differ.d.ts.map +1 -1
  76. package/dist/migrations/differ.js +12 -7
  77. package/dist/migrations/differ.js.map +1 -1
  78. package/dist/migrations/index.d.ts +2 -0
  79. package/dist/migrations/index.d.ts.map +1 -1
  80. package/dist/migrations/index.js +3 -1
  81. package/dist/migrations/integer-width.d.ts +99 -0
  82. package/dist/migrations/integer-width.d.ts.map +1 -0
  83. package/dist/migrations/integer-width.js +237 -0
  84. package/dist/migrations/integer-width.js.map +1 -0
  85. package/dist/migrations/minor-units.d.ts +162 -0
  86. package/dist/migrations/minor-units.d.ts.map +1 -0
  87. package/dist/migrations/minor-units.js +383 -0
  88. package/dist/migrations/minor-units.js.map +1 -0
  89. package/dist/migrations/tracker.d.ts.map +1 -1
  90. package/dist/migrations/tracker.js +28 -20
  91. package/dist/migrations/tracker.js.map +1 -1
  92. package/dist/migrations.js +3 -1
  93. package/dist/object.d.ts +98 -5
  94. package/dist/object.d.ts.map +1 -1
  95. package/dist/object.js +138 -30
  96. package/dist/object.js.map +1 -1
  97. package/dist/query-bounds.d.ts +5 -1
  98. package/dist/query-bounds.d.ts.map +1 -1
  99. package/dist/query-bounds.js +5 -1
  100. package/dist/query-bounds.js.map +1 -1
  101. package/dist/registry/class-registration.d.ts.map +1 -1
  102. package/dist/registry/class-registration.js +3 -1
  103. package/dist/registry/class-registration.js.map +1 -1
  104. package/dist/registry/manifest-field-merge.d.ts +12 -0
  105. package/dist/registry/manifest-field-merge.d.ts.map +1 -1
  106. package/dist/registry/manifest-field-merge.js +14 -2
  107. package/dist/registry/manifest-field-merge.js.map +1 -1
  108. package/dist/registry/schema-builder.d.ts +22 -1
  109. package/dist/registry/schema-builder.d.ts.map +1 -1
  110. package/dist/registry/schema-builder.js +205 -165
  111. package/dist/registry/schema-builder.js.map +1 -1
  112. package/dist/registry/types.d.ts +3 -2
  113. package/dist/registry/types.d.ts.map +1 -1
  114. package/dist/registry.d.ts +41 -46
  115. package/dist/registry.d.ts.map +1 -1
  116. package/dist/registry.js +61 -83
  117. package/dist/registry.js.map +1 -1
  118. package/dist/scanner/manifest-generator.d.ts +45 -0
  119. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  120. package/dist/scanner/manifest-generator.js +92 -28
  121. package/dist/scanner/manifest-generator.js.map +1 -1
  122. package/dist/schema/conflict-target.d.ts +104 -0
  123. package/dist/schema/conflict-target.d.ts.map +1 -0
  124. package/dist/schema/conflict-target.js +129 -0
  125. package/dist/schema/conflict-target.js.map +1 -0
  126. package/dist/schema/ddl/duckdb-strategy.d.ts.map +1 -1
  127. package/dist/schema/ddl/duckdb-strategy.js +3 -1
  128. package/dist/schema/ddl/duckdb-strategy.js.map +1 -1
  129. package/dist/schema/ddl/postgres-strategy.d.ts.map +1 -1
  130. package/dist/schema/ddl/postgres-strategy.js +14 -1
  131. package/dist/schema/ddl/postgres-strategy.js.map +1 -1
  132. package/dist/schema/generator.d.ts +245 -41
  133. package/dist/schema/generator.d.ts.map +1 -1
  134. package/dist/schema/generator.js +397 -241
  135. package/dist/schema/generator.js.map +1 -1
  136. package/dist/schema/index-utils.d.ts +120 -0
  137. package/dist/schema/index-utils.d.ts.map +1 -1
  138. package/dist/schema/index-utils.js +242 -1
  139. package/dist/schema/index-utils.js.map +1 -1
  140. package/dist/schema/index.d.ts +2 -3
  141. package/dist/schema/index.d.ts.map +1 -1
  142. package/dist/schema/index.js +2 -3
  143. package/dist/schema/live-parity.d.ts +3 -1
  144. package/dist/schema/live-parity.d.ts.map +1 -1
  145. package/dist/schema/live-parity.js +23 -2
  146. package/dist/schema/live-parity.js.map +1 -1
  147. package/dist/schema/system-table-shapes.d.ts +13 -0
  148. package/dist/schema/system-table-shapes.d.ts.map +1 -1
  149. package/dist/schema/system-table-shapes.js +14 -1
  150. package/dist/schema/system-table-shapes.js.map +1 -1
  151. package/dist/schema/types.d.ts +17 -10
  152. package/dist/schema/types.d.ts.map +1 -1
  153. package/dist/schema/utils.d.ts +1 -1
  154. package/dist/schema/utils.d.ts.map +1 -1
  155. package/dist/schema/utils.js +3 -3
  156. package/dist/schema/utils.js.map +1 -1
  157. package/dist/schema.js +2 -3
  158. package/dist/smrt-knowledge.json +9 -9
  159. package/dist/system/compatibility.d.ts +42 -0
  160. package/dist/system/compatibility.d.ts.map +1 -1
  161. package/dist/system/compatibility.js +182 -9
  162. package/dist/system/compatibility.js.map +1 -1
  163. package/dist/system/index.d.ts +1 -0
  164. package/dist/system/index.d.ts.map +1 -1
  165. package/dist/system/index.js +3 -2
  166. package/dist/system/retention.d.ts +237 -0
  167. package/dist/system/retention.d.ts.map +1 -0
  168. package/dist/system/retention.js +497 -0
  169. package/dist/system/retention.js.map +1 -0
  170. package/dist/system/schema.d.ts +102 -16
  171. package/dist/system/schema.d.ts.map +1 -1
  172. package/dist/system/schema.js +85 -47
  173. package/dist/system/schema.js.map +1 -1
  174. package/dist/system/types.d.ts +0 -2
  175. package/dist/system/types.d.ts.map +1 -1
  176. package/dist/testing/database.d.ts.map +1 -1
  177. package/dist/testing/database.js.map +1 -1
  178. package/dist/utils/safe-integer.d.ts +19 -0
  179. package/dist/utils/safe-integer.d.ts.map +1 -0
  180. package/dist/utils/safe-integer.js +31 -0
  181. package/dist/utils/safe-integer.js.map +1 -0
  182. package/dist/utils.d.ts +2 -1
  183. package/dist/utils.d.ts.map +1 -1
  184. package/dist/utils.js +6 -3
  185. package/dist/utils.js.map +1 -1
  186. package/dist/vite-plugin/index.d.ts.map +1 -1
  187. package/dist/vite-plugin/index.js +4 -62
  188. package/dist/vite-plugin/index.js.map +1 -1
  189. package/package.json +4 -4
  190. package/dist/schema/override-system.d.ts +0 -43
  191. package/dist/schema/override-system.d.ts.map +0 -1
  192. package/dist/schema/override-system.js +0 -205
  193. package/dist/schema/override-system.js.map +0 -1
@@ -0,0 +1,99 @@
1
+ import { DatabaseInterface } from '@happyvertical/sql';
2
+ import { SchemaDefinition } from '../schema/types.js';
3
+ /** A table and its SMRT-owned integer columns. */
4
+ export interface IntegerWidthTarget {
5
+ table: string;
6
+ columns: string[];
7
+ }
8
+ /** The width state of one declared integer column. */
9
+ export type IntegerWidthColumnState = 'pending' | 'current' | 'missing' | 'unexpected';
10
+ /** Preflight finding for one declared integer column. */
11
+ export interface IntegerWidthColumnReport {
12
+ table: string;
13
+ column: string;
14
+ state: IntegerWidthColumnState;
15
+ /** Live `information_schema.columns.data_type`, when the column exists. */
16
+ declaredType: string | null;
17
+ }
18
+ /** Preflight findings for a single SMRT-owned table. */
19
+ export interface IntegerWidthTableReport {
20
+ table: string;
21
+ /** Number of rows when at least one column still needs widening. */
22
+ rowCount: number | null;
23
+ columns: IntegerWidthColumnReport[];
24
+ }
25
+ /** Read-only assessment of a deployment's legacy int4 columns. */
26
+ export interface IntegerWidthPreflightResult {
27
+ engine: string;
28
+ /** False for SQLite and adapters without a native 32-bit integer width. */
29
+ supported: boolean;
30
+ tables: IntegerWidthTableReport[];
31
+ pendingColumns: number;
32
+ currentColumns: number;
33
+ missingColumns: number;
34
+ unexpectedColumns: number;
35
+ /** Tables that need a maintenance-window table rewrite. */
36
+ pendingTables: number;
37
+ /** Human-readable output suitable for an operator change record. */
38
+ summary: string;
39
+ }
40
+ /** Shared options for the read-only preflight and mutating widening pass. */
41
+ export interface IntegerWidthOptions {
42
+ /** Adapter hint when its URL does not identify the engine. */
43
+ engineHint?: string;
44
+ }
45
+ /** Options that make the widening pass safely repeatable. */
46
+ export interface IntegerWidthWidenOptions extends IntegerWidthOptions {
47
+ /** Stable `_smrt_backfills` audit marker, unique to this migration owner. */
48
+ backfillName: string;
49
+ /** Package recorded alongside the marker. */
50
+ packageName?: string;
51
+ /** PostgreSQL lock timeout in milliseconds (defaults to 30 seconds). */
52
+ lockTimeout?: number;
53
+ /** PostgreSQL statement timeout in milliseconds (defaults to 60 seconds). */
54
+ statementTimeout?: number;
55
+ }
56
+ /** Result of {@link widenIntegerColumnsToBigInt}. */
57
+ export interface IntegerWidthWidenResult {
58
+ /** False when no legacy columns remain or the engine is unsupported. */
59
+ ran: boolean;
60
+ preflight: IntegerWidthPreflightResult;
61
+ widenedColumns: Array<{
62
+ table: string;
63
+ column: string;
64
+ }>;
65
+ statements: string[];
66
+ }
67
+ /**
68
+ * Collect every integer column owned by loaded application schemas and, when
69
+ * requested, by hand-written core system-table DDL.
70
+ */
71
+ export declare function collectIntegerWidthTargets(schemas: Record<string, SchemaDefinition>, options?: {
72
+ includeSystemTables?: boolean;
73
+ }): IntegerWidthTarget[];
74
+ /** Build the exact, lossless ALTER statement for one target column. */
75
+ export declare function buildIntegerWidthStatements(engine: string, table: string, column: string): string[];
76
+ /**
77
+ * Build lossless widening statements for every pending column in one table.
78
+ *
79
+ * PostgreSQL performs a table rewrite for an integer-width change, so all of
80
+ * one table's pending columns must share one ALTER TABLE and one lock window.
81
+ * DuckDB keeps its one-column form because its ALTER COLUMN grammar is not
82
+ * equivalently composable across supported adapter versions.
83
+ */
84
+ export declare function buildIntegerWidthTableStatements(engine: string, table: string, columns: string[]): string[];
85
+ /**
86
+ * Inspect explicit SMRT-owned integer targets without changing the database.
87
+ *
88
+ * PostgreSQL and DuckDB expose their live widths through
89
+ * `information_schema.columns`. SQLite is deliberately a no-op because its
90
+ * INTEGER storage class already holds signed 64-bit values.
91
+ */
92
+ export declare function preflightIntegerWidthWidening(db: DatabaseInterface, targets: IntegerWidthTarget[], options?: IntegerWidthOptions): Promise<IntegerWidthPreflightResult>;
93
+ /**
94
+ * Widen legacy int4 columns to BIGINT and record a marker after every ALTER
95
+ * succeeds. This is intentionally never called by normal schema migration or
96
+ * framework bootstrap: PostgreSQL rewrites each altered table.
97
+ */
98
+ export declare function widenIntegerColumnsToBigInt(db: DatabaseInterface, targets: IntegerWidthTarget[], options: IntegerWidthWidenOptions): Promise<IntegerWidthWidenResult>;
99
+ //# sourceMappingURL=integer-width.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integer-width.d.ts","sourceRoot":"","sources":["../../src/migrations/integer-width.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,237 @@
1
+ import { toSafeInteger } from "../utils/safe-integer.js";
2
+ import { detectEngine } from "../schema/ddl/index.js";
3
+ import { getSystemTableShapes } from "../schema/system-table-shapes.js";
4
+ import { parsePostgresTimeoutMs } from "../postgres-timeouts.js";
5
+ import { BackfillTracker } from "./backfill-tracker.js";
6
+ //#region src/migrations/integer-width.ts
7
+ var DEFAULT_POSTGRES_LOCK_TIMEOUT_MS = 3e4;
8
+ var DEFAULT_POSTGRES_STATEMENT_TIMEOUT_MS = 6e4;
9
+ /**
10
+ * Collect every integer column owned by loaded application schemas and, when
11
+ * requested, by hand-written core system-table DDL.
12
+ */
13
+ function collectIntegerWidthTargets(schemas, options = {}) {
14
+ const byTable = /* @__PURE__ */ new Map();
15
+ const add = (table, column) => {
16
+ if (!byTable.has(table)) byTable.set(table, /* @__PURE__ */ new Set());
17
+ byTable.get(table)?.add(column);
18
+ };
19
+ for (const [key, schema] of Object.entries(schemas)) {
20
+ const table = schema?.tableName || key;
21
+ for (const [column, definition] of Object.entries(schema?.columns ?? {})) if (definition.type === "INTEGER") add(table, column);
22
+ }
23
+ if (options.includeSystemTables ?? true) {
24
+ for (const shape of getSystemTableShapes("postgres").values()) for (const column of shape.columns) if (isBigIntType(column.type)) add(shape.tableName, column.name);
25
+ }
26
+ return [...byTable].map(([table, columns]) => ({
27
+ table,
28
+ columns: [...columns].sort()
29
+ })).sort((left, right) => left.table.localeCompare(right.table));
30
+ }
31
+ /** Build the exact, lossless ALTER statement for one target column. */
32
+ function buildIntegerWidthStatements(engine, table, column) {
33
+ return buildIntegerWidthTableStatements(engine, table, [column]);
34
+ }
35
+ /**
36
+ * Build lossless widening statements for every pending column in one table.
37
+ *
38
+ * PostgreSQL performs a table rewrite for an integer-width change, so all of
39
+ * one table's pending columns must share one ALTER TABLE and one lock window.
40
+ * DuckDB keeps its one-column form because its ALTER COLUMN grammar is not
41
+ * equivalently composable across supported adapter versions.
42
+ */
43
+ function buildIntegerWidthTableStatements(engine, table, columns) {
44
+ const quotedTable = quoteIdentifier(table);
45
+ const quotedColumns = columns.map(quoteIdentifier);
46
+ if (quotedColumns.length === 0) return [];
47
+ if (engine !== "postgres" && engine !== "duckdb") return [];
48
+ if (engine === "postgres") return [`ALTER TABLE ${quotedTable} ${quotedColumns.map((column) => `ALTER COLUMN ${column} TYPE BIGINT`).join(", ")}`];
49
+ return quotedColumns.map((column) => `ALTER TABLE ${quotedTable} ALTER COLUMN ${column} TYPE BIGINT`);
50
+ }
51
+ /**
52
+ * Inspect explicit SMRT-owned integer targets without changing the database.
53
+ *
54
+ * PostgreSQL and DuckDB expose their live widths through
55
+ * `information_schema.columns`. SQLite is deliberately a no-op because its
56
+ * INTEGER storage class already holds signed 64-bit values.
57
+ */
58
+ async function preflightIntegerWidthWidening(db, targets, options = {}) {
59
+ const engine = resolveEngine(db, options.engineHint);
60
+ const normalizedTargets = normalizeTargets(targets);
61
+ if (engine !== "postgres" && engine !== "duckdb") return {
62
+ engine,
63
+ supported: false,
64
+ tables: [],
65
+ pendingColumns: 0,
66
+ currentColumns: 0,
67
+ missingColumns: 0,
68
+ unexpectedColumns: 0,
69
+ pendingTables: 0,
70
+ summary: `Integer-width widening preflight (engine=${engine}): not applicable; this engine does not expose a distinct native int4 storage type.`
71
+ };
72
+ const tables = [];
73
+ for (const target of normalizedTargets) {
74
+ const types = await readColumnTypes(db, engine, target.table);
75
+ const columns = target.columns.map((column) => {
76
+ const declaredType = types.get(column) ?? null;
77
+ return {
78
+ table: target.table,
79
+ column,
80
+ declaredType,
81
+ state: classifyIntegerWidth(declaredType)
82
+ };
83
+ });
84
+ const needsWidening = columns.some((column) => column.state === "pending");
85
+ tables.push({
86
+ table: target.table,
87
+ rowCount: needsWidening ? await countRows(db, target.table) : null,
88
+ columns
89
+ });
90
+ }
91
+ const allColumns = tables.flatMap((table) => table.columns);
92
+ const result = {
93
+ engine,
94
+ supported: true,
95
+ tables,
96
+ pendingColumns: allColumns.filter((column) => column.state === "pending").length,
97
+ currentColumns: allColumns.filter((column) => column.state === "current").length,
98
+ missingColumns: allColumns.filter((column) => column.state === "missing").length,
99
+ unexpectedColumns: allColumns.filter((column) => column.state === "unexpected").length,
100
+ pendingTables: tables.filter((table) => table.columns.some((column) => column.state === "pending")).length
101
+ };
102
+ return {
103
+ ...result,
104
+ summary: renderSummary(result)
105
+ };
106
+ }
107
+ /**
108
+ * Widen legacy int4 columns to BIGINT and record a marker after every ALTER
109
+ * succeeds. This is intentionally never called by normal schema migration or
110
+ * framework bootstrap: PostgreSQL rewrites each altered table.
111
+ */
112
+ async function widenIntegerColumnsToBigInt(db, targets, options) {
113
+ const preflight = await preflightIntegerWidthWidening(db, targets, options);
114
+ if (!preflight.supported) return {
115
+ ran: false,
116
+ preflight,
117
+ widenedColumns: [],
118
+ statements: []
119
+ };
120
+ if (preflight.unexpectedColumns > 0) throw new Error("Integer-width widening refused because declared integer columns have unexpected live types. Resolve ordinary schema drift first.\n" + preflight.summary);
121
+ if (preflight.pendingColumns === 0) return {
122
+ ran: false,
123
+ preflight,
124
+ widenedColumns: [],
125
+ statements: []
126
+ };
127
+ const statements = [];
128
+ const widenedColumns = [];
129
+ await new BackfillTracker({ db }).initialize();
130
+ const applyWidening = async (writeDb) => {
131
+ for (const table of preflight.tables) {
132
+ const pendingColumns = table.columns.filter((column) => column.state === "pending").map((column) => column.column);
133
+ if (pendingColumns.length === 0) continue;
134
+ for (const sql of buildIntegerWidthTableStatements(preflight.engine, table.table, pendingColumns)) {
135
+ await writeDb.query(sql);
136
+ statements.push(sql);
137
+ }
138
+ widenedColumns.push(...pendingColumns.map((column) => ({
139
+ table: table.table,
140
+ column
141
+ })));
142
+ }
143
+ await new BackfillTracker({ db: writeDb }).recordApplied(options.backfillName, {
144
+ description: "Widened legacy int4 SMRT columns to BIGINT after #2373 changed fresh-schema defaults.",
145
+ packageName: options.packageName
146
+ });
147
+ };
148
+ if (preflight.engine === "postgres") {
149
+ if (!db.transaction) throw new Error("Integer-width widening on PostgreSQL requires transaction support.");
150
+ const lockTimeout = parsePostgresTimeoutMs(options.lockTimeout, DEFAULT_POSTGRES_LOCK_TIMEOUT_MS);
151
+ const statementTimeout = parsePostgresTimeoutMs(options.statementTimeout, DEFAULT_POSTGRES_STATEMENT_TIMEOUT_MS);
152
+ await db.transaction(async (tx) => {
153
+ const txDb = {
154
+ ...tx,
155
+ transaction: async (callback) => callback(tx)
156
+ };
157
+ BackfillTracker.inheritInitialization(txDb, db);
158
+ await txDb.query(`SET LOCAL lock_timeout = '${formatPostgresTimeout(lockTimeout)}'`);
159
+ await txDb.query(`SET LOCAL statement_timeout = '${formatPostgresTimeout(statementTimeout)}'`);
160
+ await applyWidening(txDb);
161
+ });
162
+ } else await applyWidening(db);
163
+ return {
164
+ ran: true,
165
+ preflight,
166
+ widenedColumns,
167
+ statements
168
+ };
169
+ }
170
+ function resolveEngine(db, engineHint) {
171
+ const dbWithConfig = db;
172
+ return detectEngine(db.url || dbWithConfig.config?.url || "", engineHint);
173
+ }
174
+ function normalizeTargets(targets) {
175
+ const byTable = /* @__PURE__ */ new Map();
176
+ for (const target of targets) {
177
+ quoteIdentifier(target.table);
178
+ if (!byTable.has(target.table)) byTable.set(target.table, /* @__PURE__ */ new Set());
179
+ for (const column of target.columns) {
180
+ quoteIdentifier(column);
181
+ byTable.get(target.table)?.add(column);
182
+ }
183
+ }
184
+ return [...byTable].map(([table, columns]) => ({
185
+ table,
186
+ columns: [...columns].sort()
187
+ })).sort((left, right) => left.table.localeCompare(right.table));
188
+ }
189
+ function quoteIdentifier(name) {
190
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) throw new Error(`Integer-width widening: '${name}' is not a plain SQL identifier.`);
191
+ return `"${name}"`;
192
+ }
193
+ function formatPostgresTimeout(milliseconds) {
194
+ return `${milliseconds}ms`;
195
+ }
196
+ function isLegacyInt4Type(type) {
197
+ return /^(INTEGER|INT|INT4)$/i.test(type.trim());
198
+ }
199
+ function isBigIntType(type) {
200
+ return /^(BIGINT|INT8)$/i.test(type.trim());
201
+ }
202
+ function classifyIntegerWidth(type) {
203
+ if (type === null) return "missing";
204
+ if (isLegacyInt4Type(type)) return "pending";
205
+ if (isBigIntType(type)) return "current";
206
+ return "unexpected";
207
+ }
208
+ async function readColumnTypes(db, engine, table) {
209
+ const result = await db.query(engine === "postgres" ? `SELECT column_name, data_type
210
+ FROM information_schema.columns
211
+ WHERE table_schema = current_schema() AND table_name = ?` : `SELECT column_name, data_type
212
+ FROM information_schema.columns
213
+ WHERE table_name = ?`, table);
214
+ const types = /* @__PURE__ */ new Map();
215
+ for (const row of result.rows) if (typeof row.column_name === "string") types.set(row.column_name, String(row.data_type ?? ""));
216
+ return types;
217
+ }
218
+ async function countRows(db, table) {
219
+ return toSafeInteger((await db.query(`SELECT COUNT(*) AS row_count FROM ${quoteIdentifier(table)}`)).rows?.[0]?.row_count ?? 0, `Integer-width row count for ${table}`);
220
+ }
221
+ function renderSummary(result) {
222
+ const lines = [
223
+ `Integer-width widening preflight (engine=${result.engine})`,
224
+ ` tables: ${result.pendingTables} pending`,
225
+ ` columns: ${result.pendingColumns} pending, ${result.currentColumns} already BIGINT, ${result.missingColumns} missing, ${result.unexpectedColumns} unexpected`
226
+ ];
227
+ for (const table of result.tables) {
228
+ const pending = table.columns.filter((column) => column.state === "pending");
229
+ if (pending.length === 0) continue;
230
+ lines.push(` - ${table.table}: ${table.rowCount ?? 0} row(s); ${pending.map((column) => `${column.column} (${column.declaredType})`).join(", ")}`);
231
+ }
232
+ return lines.join("\n");
233
+ }
234
+ //#endregion
235
+ export { buildIntegerWidthStatements, buildIntegerWidthTableStatements, collectIntegerWidthTargets, preflightIntegerWidthWidening, widenIntegerColumnsToBigInt };
236
+
237
+ //# sourceMappingURL=integer-width.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integer-width.js","names":[],"sources":["../../src/migrations/integer-width.ts"],"sourcesContent":["/**\n * Explicit one-time widening for deployments created before #2373.\n *\n * Fresh PostgreSQL and DuckDB schemas now materialize SMRT's abstract\n * `INTEGER` as `BIGINT`. The migration differ deliberately treats int4 and\n * int8 as equivalent, so existing deployments need this separate, operator\n * initiated maintenance-window migration rather than an automatic repair.\n */\n\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { parsePostgresTimeoutMs } from '../postgres-timeouts.js';\nimport { detectEngine } from '../schema/ddl/index.js';\nimport { getSystemTableShapes } from '../schema/system-table-shapes.js';\nimport type { SchemaDefinition } from '../schema/types.js';\nimport { toSafeInteger } from '../utils/safe-integer.js';\nimport { BackfillTracker } from './backfill-tracker.js';\n\nconst DEFAULT_POSTGRES_LOCK_TIMEOUT_MS = 30_000;\nconst DEFAULT_POSTGRES_STATEMENT_TIMEOUT_MS = 60_000;\n\n/** A table and its SMRT-owned integer columns. */\nexport interface IntegerWidthTarget {\n table: string;\n columns: string[];\n}\n\n/** The width state of one declared integer column. */\nexport type IntegerWidthColumnState =\n | 'pending'\n | 'current'\n | 'missing'\n | 'unexpected';\n\n/** Preflight finding for one declared integer column. */\nexport interface IntegerWidthColumnReport {\n table: string;\n column: string;\n state: IntegerWidthColumnState;\n /** Live `information_schema.columns.data_type`, when the column exists. */\n declaredType: string | null;\n}\n\n/** Preflight findings for a single SMRT-owned table. */\nexport interface IntegerWidthTableReport {\n table: string;\n /** Number of rows when at least one column still needs widening. */\n rowCount: number | null;\n columns: IntegerWidthColumnReport[];\n}\n\n/** Read-only assessment of a deployment's legacy int4 columns. */\nexport interface IntegerWidthPreflightResult {\n engine: string;\n /** False for SQLite and adapters without a native 32-bit integer width. */\n supported: boolean;\n tables: IntegerWidthTableReport[];\n pendingColumns: number;\n currentColumns: number;\n missingColumns: number;\n unexpectedColumns: number;\n /** Tables that need a maintenance-window table rewrite. */\n pendingTables: number;\n /** Human-readable output suitable for an operator change record. */\n summary: string;\n}\n\n/** Shared options for the read-only preflight and mutating widening pass. */\nexport interface IntegerWidthOptions {\n /** Adapter hint when its URL does not identify the engine. */\n engineHint?: string;\n}\n\n/** Options that make the widening pass safely repeatable. */\nexport interface IntegerWidthWidenOptions extends IntegerWidthOptions {\n /** Stable `_smrt_backfills` audit marker, unique to this migration owner. */\n backfillName: string;\n /** Package recorded alongside the marker. */\n packageName?: string;\n /** PostgreSQL lock timeout in milliseconds (defaults to 30 seconds). */\n lockTimeout?: number;\n /** PostgreSQL statement timeout in milliseconds (defaults to 60 seconds). */\n statementTimeout?: number;\n}\n\n/** Result of {@link widenIntegerColumnsToBigInt}. */\nexport interface IntegerWidthWidenResult {\n /** False when no legacy columns remain or the engine is unsupported. */\n ran: boolean;\n preflight: IntegerWidthPreflightResult;\n widenedColumns: Array<{ table: string; column: string }>;\n statements: string[];\n}\n\n/**\n * Collect every integer column owned by loaded application schemas and, when\n * requested, by hand-written core system-table DDL.\n */\nexport function collectIntegerWidthTargets(\n schemas: Record<string, SchemaDefinition>,\n options: { includeSystemTables?: boolean } = {},\n): IntegerWidthTarget[] {\n const byTable = new Map<string, Set<string>>();\n const add = (table: string, column: string) => {\n if (!byTable.has(table)) byTable.set(table, new Set());\n byTable.get(table)?.add(column);\n };\n\n for (const [key, schema] of Object.entries(schemas)) {\n const table = schema?.tableName || key;\n for (const [column, definition] of Object.entries(schema?.columns ?? {})) {\n if (definition.type === 'INTEGER') add(table, column);\n }\n }\n\n if (options.includeSystemTables ?? true) {\n for (const shape of getSystemTableShapes('postgres').values()) {\n for (const column of shape.columns) {\n if (isBigIntType(column.type)) add(shape.tableName, column.name);\n }\n }\n }\n\n return [...byTable]\n .map(([table, columns]) => ({ table, columns: [...columns].sort() }))\n .sort((left, right) => left.table.localeCompare(right.table));\n}\n\n/** Build the exact, lossless ALTER statement for one target column. */\nexport function buildIntegerWidthStatements(\n engine: string,\n table: string,\n column: string,\n): string[] {\n return buildIntegerWidthTableStatements(engine, table, [column]);\n}\n\n/**\n * Build lossless widening statements for every pending column in one table.\n *\n * PostgreSQL performs a table rewrite for an integer-width change, so all of\n * one table's pending columns must share one ALTER TABLE and one lock window.\n * DuckDB keeps its one-column form because its ALTER COLUMN grammar is not\n * equivalently composable across supported adapter versions.\n */\nexport function buildIntegerWidthTableStatements(\n engine: string,\n table: string,\n columns: string[],\n): string[] {\n const quotedTable = quoteIdentifier(table);\n const quotedColumns = columns.map(quoteIdentifier);\n if (quotedColumns.length === 0) return [];\n if (engine !== 'postgres' && engine !== 'duckdb') return [];\n if (engine === 'postgres') {\n return [\n `ALTER TABLE ${quotedTable} ${quotedColumns\n .map((column) => `ALTER COLUMN ${column} TYPE BIGINT`)\n .join(', ')}`,\n ];\n }\n return quotedColumns.map(\n (column) => `ALTER TABLE ${quotedTable} ALTER COLUMN ${column} TYPE BIGINT`,\n );\n}\n\n/**\n * Inspect explicit SMRT-owned integer targets without changing the database.\n *\n * PostgreSQL and DuckDB expose their live widths through\n * `information_schema.columns`. SQLite is deliberately a no-op because its\n * INTEGER storage class already holds signed 64-bit values.\n */\nexport async function preflightIntegerWidthWidening(\n db: DatabaseInterface,\n targets: IntegerWidthTarget[],\n options: IntegerWidthOptions = {},\n): Promise<IntegerWidthPreflightResult> {\n const engine = resolveEngine(db, options.engineHint);\n const normalizedTargets = normalizeTargets(targets);\n if (engine !== 'postgres' && engine !== 'duckdb') {\n const result = {\n engine,\n supported: false,\n tables: [],\n pendingColumns: 0,\n currentColumns: 0,\n missingColumns: 0,\n unexpectedColumns: 0,\n pendingTables: 0,\n };\n return {\n ...result,\n summary:\n `Integer-width widening preflight (engine=${engine}): not applicable; ` +\n 'this engine does not expose a distinct native int4 storage type.',\n };\n }\n\n const tables: IntegerWidthTableReport[] = [];\n for (const target of normalizedTargets) {\n const types = await readColumnTypes(db, engine, target.table);\n const columns = target.columns.map((column) => {\n const declaredType = types.get(column) ?? null;\n return {\n table: target.table,\n column,\n declaredType,\n state: classifyIntegerWidth(declaredType),\n };\n });\n const needsWidening = columns.some((column) => column.state === 'pending');\n tables.push({\n table: target.table,\n rowCount: needsWidening ? await countRows(db, target.table) : null,\n columns,\n });\n }\n\n const allColumns = tables.flatMap((table) => table.columns);\n const result = {\n engine,\n supported: true,\n tables,\n pendingColumns: allColumns.filter((column) => column.state === 'pending')\n .length,\n currentColumns: allColumns.filter((column) => column.state === 'current')\n .length,\n missingColumns: allColumns.filter((column) => column.state === 'missing')\n .length,\n unexpectedColumns: allColumns.filter(\n (column) => column.state === 'unexpected',\n ).length,\n pendingTables: tables.filter((table) =>\n table.columns.some((column) => column.state === 'pending'),\n ).length,\n };\n return { ...result, summary: renderSummary(result) };\n}\n\n/**\n * Widen legacy int4 columns to BIGINT and record a marker after every ALTER\n * succeeds. This is intentionally never called by normal schema migration or\n * framework bootstrap: PostgreSQL rewrites each altered table.\n */\nexport async function widenIntegerColumnsToBigInt(\n db: DatabaseInterface,\n targets: IntegerWidthTarget[],\n options: IntegerWidthWidenOptions,\n): Promise<IntegerWidthWidenResult> {\n const preflight = await preflightIntegerWidthWidening(db, targets, options);\n if (!preflight.supported) {\n return { ran: false, preflight, widenedColumns: [], statements: [] };\n }\n if (preflight.unexpectedColumns > 0) {\n throw new Error(\n 'Integer-width widening refused because declared integer columns have unexpected live types. Resolve ordinary schema drift first.\\n' +\n preflight.summary,\n );\n }\n\n // Current declared widths are the idempotency guard. A fixed marker cannot\n // safely be the guard because a later successful discovery may reveal a\n // package/table absent from the earlier target set.\n if (preflight.pendingColumns === 0) {\n return { ran: false, preflight, widenedColumns: [], statements: [] };\n }\n\n const statements: string[] = [];\n const widenedColumns: Array<{ table: string; column: string }> = [];\n await new BackfillTracker({ db }).initialize();\n\n const applyWidening = async (writeDb: DatabaseInterface) => {\n for (const table of preflight.tables) {\n const pendingColumns = table.columns\n .filter((column) => column.state === 'pending')\n .map((column) => column.column);\n if (pendingColumns.length === 0) continue;\n for (const sql of buildIntegerWidthTableStatements(\n preflight.engine,\n table.table,\n pendingColumns,\n )) {\n await writeDb.query(sql);\n statements.push(sql);\n }\n widenedColumns.push(\n ...pendingColumns.map((column) => ({ table: table.table, column })),\n );\n }\n\n await new BackfillTracker({ db: writeDb }).recordApplied(\n options.backfillName,\n {\n description:\n 'Widened legacy int4 SMRT columns to BIGINT after #2373 changed fresh-schema defaults.',\n packageName: options.packageName,\n },\n );\n };\n\n if (preflight.engine === 'postgres') {\n if (!db.transaction) {\n throw new Error(\n 'Integer-width widening on PostgreSQL requires transaction support.',\n );\n }\n const lockTimeout = parsePostgresTimeoutMs(\n options.lockTimeout,\n DEFAULT_POSTGRES_LOCK_TIMEOUT_MS,\n );\n const statementTimeout = parsePostgresTimeoutMs(\n options.statementTimeout,\n DEFAULT_POSTGRES_STATEMENT_TIMEOUT_MS,\n );\n await db.transaction(async (tx) => {\n const txDb = {\n ...tx,\n transaction: async <T>(\n callback: (transactionDb: DatabaseInterface) => Promise<T>,\n ) => callback(tx as DatabaseInterface),\n } as DatabaseInterface;\n BackfillTracker.inheritInitialization(txDb, db);\n await txDb.query(\n `SET LOCAL lock_timeout = '${formatPostgresTimeout(lockTimeout)}'`,\n );\n await txDb.query(\n `SET LOCAL statement_timeout = '${formatPostgresTimeout(statementTimeout)}'`,\n );\n await applyWidening(txDb);\n });\n } else {\n await applyWidening(db);\n }\n\n return { ran: true, preflight, widenedColumns, statements };\n}\n\nfunction resolveEngine(db: DatabaseInterface, engineHint?: string): string {\n const dbWithConfig = db as DatabaseInterface & { config?: { url?: string } };\n return detectEngine(db.url || dbWithConfig.config?.url || '', engineHint);\n}\n\nfunction normalizeTargets(targets: IntegerWidthTarget[]): IntegerWidthTarget[] {\n const byTable = new Map<string, Set<string>>();\n for (const target of targets) {\n quoteIdentifier(target.table);\n if (!byTable.has(target.table)) byTable.set(target.table, new Set());\n for (const column of target.columns) {\n quoteIdentifier(column);\n byTable.get(target.table)?.add(column);\n }\n }\n return [...byTable]\n .map(([table, columns]) => ({ table, columns: [...columns].sort() }))\n .sort((left, right) => left.table.localeCompare(right.table));\n}\n\nfunction quoteIdentifier(name: string): string {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {\n throw new Error(\n `Integer-width widening: '${name}' is not a plain SQL identifier.`,\n );\n }\n return `\"${name}\"`;\n}\n\nfunction formatPostgresTimeout(milliseconds: number): string {\n return `${milliseconds}ms`;\n}\n\nfunction isLegacyInt4Type(type: string): boolean {\n return /^(INTEGER|INT|INT4)$/i.test(type.trim());\n}\n\nfunction isBigIntType(type: string): boolean {\n return /^(BIGINT|INT8)$/i.test(type.trim());\n}\n\nfunction classifyIntegerWidth(type: string | null): IntegerWidthColumnState {\n if (type === null) return 'missing';\n if (isLegacyInt4Type(type)) return 'pending';\n if (isBigIntType(type)) return 'current';\n return 'unexpected';\n}\n\nasync function readColumnTypes(\n db: DatabaseInterface,\n engine: string,\n table: string,\n): Promise<Map<string, string>> {\n const result = await db.query(\n engine === 'postgres'\n ? `SELECT column_name, data_type\n FROM information_schema.columns\n WHERE table_schema = current_schema() AND table_name = ?`\n : `SELECT column_name, data_type\n FROM information_schema.columns\n WHERE table_name = ?`,\n table,\n );\n const types = new Map<string, string>();\n for (const row of result.rows as {\n column_name?: unknown;\n data_type?: unknown;\n }[]) {\n if (typeof row.column_name === 'string') {\n types.set(row.column_name, String(row.data_type ?? ''));\n }\n }\n return types;\n}\n\nasync function countRows(\n db: DatabaseInterface,\n table: string,\n): Promise<number> {\n const result = await db.query(\n `SELECT COUNT(*) AS row_count FROM ${quoteIdentifier(table)}`,\n );\n return toSafeInteger(\n result.rows?.[0]?.row_count ?? 0,\n `Integer-width row count for ${table}`,\n );\n}\n\nfunction renderSummary(\n result: Omit<IntegerWidthPreflightResult, 'summary'>,\n): string {\n const lines = [\n `Integer-width widening preflight (engine=${result.engine})`,\n ` tables: ${result.pendingTables} pending`,\n ` columns: ${result.pendingColumns} pending, ${result.currentColumns} already BIGINT, ${result.missingColumns} missing, ${result.unexpectedColumns} unexpected`,\n ];\n for (const table of result.tables) {\n const pending = table.columns.filter(\n (column) => column.state === 'pending',\n );\n if (pending.length === 0) continue;\n lines.push(\n ` - ${table.table}: ${table.rowCount ?? 0} row(s); ${pending\n .map((column) => `${column.column} (${column.declaredType})`)\n .join(', ')}`,\n );\n }\n return lines.join('\\n');\n}\n"],"mappings":"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"}
@@ -0,0 +1,162 @@
1
+ import { DatabaseInterface } from './types.js';
2
+ /** A table and the money columns on it that must move to minor units. */
3
+ export interface MoneyColumnTarget {
4
+ /** Physical table name, e.g. `payments`. */
5
+ table: string;
6
+ /** Physical column names, e.g. `['amount', 'native_amount']`. */
7
+ columns: string[];
8
+ }
9
+ /** What the preflight found about one column. */
10
+ export type MinorUnitsColumnState =
11
+ /** Floating-point today: needs converting. */
12
+ 'pending'
13
+ /** Already an integer column: nothing to do. */
14
+ | 'converted'
15
+ /** Table or column absent (package not installed, older schema). */
16
+ | 'missing';
17
+ /** One row that cannot be converted without losing information. */
18
+ export interface MinorUnitsProblemRow {
19
+ /** Primary key, when the table has an `id` column. */
20
+ id: string | null;
21
+ /** The stored major-unit value. */
22
+ value: number;
23
+ /** `value * scale`, before rounding. */
24
+ scaled: number;
25
+ }
26
+ /** Preflight findings for a single column. */
27
+ export interface MinorUnitsColumnReport {
28
+ table: string;
29
+ column: string;
30
+ state: MinorUnitsColumnState;
31
+ /** Declared column type as the database reports it, when resolvable. */
32
+ declaredType: string | null;
33
+ /** Non-null values inspected. `0` unless `state` is `pending`. */
34
+ inspectedRows: number;
35
+ /** Values whose scaled form is not a whole number — rounding loses money. */
36
+ nonIntegral: MinorUnitsProblemRow[];
37
+ /** Values whose scaled form exceeds JavaScript's safe integer range. */
38
+ overflow: MinorUnitsProblemRow[];
39
+ }
40
+ /** Result of {@link preflightMinorUnitsRescale}. */
41
+ export interface MinorUnitsPreflightResult {
42
+ engine: string;
43
+ scale: number;
44
+ columns: MinorUnitsColumnReport[];
45
+ /** Columns still holding floating-point major units. */
46
+ pendingColumns: number;
47
+ /** Columns already integer. */
48
+ convertedColumns: number;
49
+ /** Columns whose table/column does not exist. */
50
+ missingColumns: number;
51
+ /** Total rows that would be rounded. */
52
+ nonIntegralRows: number;
53
+ /** Total rows that would exceed JavaScript's safe integer range. */
54
+ overflowRows: number;
55
+ /** No row would lose information. */
56
+ ok: boolean;
57
+ /** Human-readable report, suitable for pasting into a migration log or PR. */
58
+ summary: string;
59
+ }
60
+ /** Options shared by the preflight and the rescale. */
61
+ export interface MinorUnitsOptions {
62
+ /** Minor units per major unit. Default `100` (cents). */
63
+ scale?: number;
64
+ /** Engine hint for adapters whose URL does not identify the engine. */
65
+ engineHint?: string;
66
+ /** Problem rows recorded per column before truncating. Default `20`. */
67
+ maxProblemRows?: number;
68
+ }
69
+ /** Options for {@link rescaleMoneyColumnsToMinorUnits}. */
70
+ export interface MinorUnitsRescaleOptions extends MinorUnitsOptions {
71
+ /**
72
+ * Stable marker name recorded in `_smrt_backfills`, e.g.
73
+ * `@happyvertical/smrt-commerce:money-minor-units:v1`.
74
+ *
75
+ * This is what makes the migration idempotent on SQLite, where the rescale
76
+ * is an `UPDATE` no column type can distinguish from an unconverted table.
77
+ */
78
+ backfillName: string;
79
+ /** Package recorded alongside the marker. */
80
+ packageName?: string;
81
+ /**
82
+ * Convert even when the preflight found rows that would be rounded or
83
+ * overflow. Off by default: silently rounding a half-cent away is exactly
84
+ * the failure this migration exists to prevent.
85
+ */
86
+ force?: boolean;
87
+ }
88
+ /** Result of {@link rescaleMoneyColumnsToMinorUnits}. */
89
+ export interface MinorUnitsRescaleResult {
90
+ /** `false` when the backfill marker was already present. */
91
+ ran: boolean;
92
+ engine: string;
93
+ scale: number;
94
+ /** The preflight that gated the run. */
95
+ preflight: MinorUnitsPreflightResult;
96
+ /** Columns whose values were rescaled. */
97
+ rescaledColumns: Array<{
98
+ table: string;
99
+ column: string;
100
+ }>;
101
+ /** Statements executed, in order — useful for logs and tests. */
102
+ statements: string[];
103
+ /**
104
+ * Columns whose values are now minor units but whose *declared* type is
105
+ * still floating-point. Only ever populated on SQLite, which cannot alter a
106
+ * column type in place; clearing it needs the table-rebuild path (#2370).
107
+ */
108
+ declaredTypeChangePending: Array<{
109
+ table: string;
110
+ column: string;
111
+ }>;
112
+ }
113
+ /**
114
+ * A money-losing preflight finding blocked the conversion.
115
+ *
116
+ * Carries the full preflight so a caller can print the summary, fix the data,
117
+ * and retry rather than re-deriving what went wrong.
118
+ */
119
+ export declare class MinorUnitsPreflightError extends Error {
120
+ readonly preflight: MinorUnitsPreflightResult;
121
+ constructor(preflight: MinorUnitsPreflightResult);
122
+ }
123
+ /**
124
+ * The statements that convert one column, for one engine.
125
+ *
126
+ * Exported so the emitted DDL can be asserted without a live PostgreSQL or
127
+ * DuckDB connection; each owning package's `test:postgres` lane then proves the
128
+ * same SQL runs against a real server.
129
+ *
130
+ * @param engine - `postgres`, `duckdb`, or anything SQLite-shaped.
131
+ * @param table - Physical table name.
132
+ * @param column - Physical column name.
133
+ * @param scale - Minor units per major unit.
134
+ * @returns Statements in execution order.
135
+ */
136
+ export declare function buildMinorUnitsStatements(engine: string, table: string, column: string, scale: number): string[];
137
+ /**
138
+ * Report what {@link rescaleMoneyColumnsToMinorUnits} would do, without
139
+ * writing anything.
140
+ *
141
+ * @param db - Root database handle.
142
+ * @param targets - Tables and money columns owned by the calling package.
143
+ * @param options - Scale, engine hint, problem-row cap.
144
+ * @returns Per-column state plus the rows that would lose information.
145
+ */
146
+ export declare function preflightMinorUnitsRescale(db: DatabaseInterface, targets: MoneyColumnTarget[], options?: MinorUnitsOptions): Promise<MinorUnitsPreflightResult>;
147
+ /**
148
+ * Convert floating-point major-unit money columns to integer minor units.
149
+ *
150
+ * Idempotent: the run is wrapped in a {@link BackfillTracker} marker, so a
151
+ * second call is a no-op even on SQLite where the column type cannot record
152
+ * that the conversion already happened.
153
+ *
154
+ * @param db - Root database handle (must support `query`).
155
+ * @param targets - Tables and money columns owned by the calling package.
156
+ * @param options - Marker name, scale, and whether to convert despite
157
+ * information-losing rows.
158
+ * @throws {MinorUnitsPreflightError} when the preflight found rows that would
159
+ * be rounded or overflow and `force` was not set.
160
+ */
161
+ export declare function rescaleMoneyColumnsToMinorUnits(db: DatabaseInterface, targets: MoneyColumnTarget[], options: MinorUnitsRescaleOptions): Promise<MinorUnitsRescaleResult>;
162
+ //# sourceMappingURL=minor-units.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minor-units.d.ts","sourceRoot":"","sources":["../../src/migrations/minor-units.ts"],"names":[],"mappings":"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"}