@atscript/db 0.1.38 → 0.1.40

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 (64) hide show
  1. package/README.md +42 -303
  2. package/dist/agg.cjs +8 -3
  3. package/dist/agg.d.cts +7 -0
  4. package/dist/agg.d.mts +7 -0
  5. package/dist/agg.mjs +7 -3
  6. package/dist/control-DRgryKeg.cjs +14 -0
  7. package/dist/{control_as-bjmwe24C.mjs → control-IANbnfjG.mjs} +6 -18
  8. package/dist/db-readable-BQQzfguJ.d.cts +1249 -0
  9. package/dist/db-readable-Bbr4CjMb.d.mts +1249 -0
  10. package/dist/db-space-BUrQ5BFm.d.mts +309 -0
  11. package/dist/db-space-Vxpcnyt5.d.cts +309 -0
  12. package/dist/db-validator-plugin-07kDiis2.d.cts +22 -0
  13. package/dist/db-validator-plugin-CiqsHTI_.d.mts +22 -0
  14. package/dist/db-view-BntnAmXO.cjs +3071 -0
  15. package/dist/db-view-ZsoN91-q.mjs +2970 -0
  16. package/dist/index.cjs +95 -2801
  17. package/dist/index.d.cts +137 -0
  18. package/dist/index.d.mts +137 -0
  19. package/dist/index.mjs +55 -2761
  20. package/dist/{nested-writer-BkqL7cp3.cjs → nested-writer-BDXsDMPP.cjs} +196 -150
  21. package/dist/{nested-writer-NEN51mnR.mjs → nested-writer-Dmm1gbZV.mjs} +118 -70
  22. package/dist/ops-BdRAFLKY.d.mts +67 -0
  23. package/dist/ops-DXJ4Zw0P.d.cts +67 -0
  24. package/dist/ops.cjs +123 -0
  25. package/dist/ops.d.cts +2 -0
  26. package/dist/ops.d.mts +2 -0
  27. package/dist/ops.mjs +112 -0
  28. package/dist/plugin.cjs +90 -109
  29. package/dist/plugin.d.cts +6 -0
  30. package/dist/plugin.d.mts +6 -0
  31. package/dist/plugin.mjs +29 -49
  32. package/dist/rel.cjs +20 -20
  33. package/dist/rel.d.cts +119 -0
  34. package/dist/rel.d.mts +119 -0
  35. package/dist/rel.mjs +4 -5
  36. package/dist/{relation-helpers-guFL_oRf.cjs → relation-helpers-BYvsE1tR.cjs} +26 -22
  37. package/dist/{relation-helpers-DyBIlQnB.mjs → relation-helpers-CLasawQq.mjs} +11 -6
  38. package/dist/{relation-loader-Dv7qXYq7.mjs → relation-loader-BEOTXNcq.mjs} +63 -43
  39. package/dist/{relation-loader-CpnDRf9k.cjs → relation-loader-CRC5LcqM.cjs} +74 -49
  40. package/dist/shared.cjs +13 -13
  41. package/dist/{shared.d.ts → shared.d.cts} +14 -13
  42. package/dist/shared.d.mts +71 -0
  43. package/dist/shared.mjs +2 -3
  44. package/dist/sync.cjs +300 -252
  45. package/dist/sync.d.cts +369 -0
  46. package/dist/sync.d.mts +369 -0
  47. package/dist/sync.mjs +284 -233
  48. package/dist/{validation-utils-DEoCMmEb.cjs → validation-utils-DVJDijnB.cjs} +141 -109
  49. package/dist/{validation-utils-DhR_mtKa.mjs → validation-utils-DhjIjP1-.mjs} +71 -37
  50. package/package.json +31 -30
  51. package/LICENSE +0 -21
  52. package/dist/agg-BJFJ3dFQ.mjs +0 -8
  53. package/dist/agg-DnUWAOK8.cjs +0 -14
  54. package/dist/agg.d.ts +0 -13
  55. package/dist/chunk-CrpGerW8.cjs +0 -31
  56. package/dist/control_as-BFPERAF_.cjs +0 -28
  57. package/dist/index.d.ts +0 -1706
  58. package/dist/logger-B7oxCfLQ.mjs +0 -12
  59. package/dist/logger-Dt2v_-wb.cjs +0 -18
  60. package/dist/plugin.d.ts +0 -5
  61. package/dist/rel.d.ts +0 -1305
  62. package/dist/relation-loader-D4mTw6yH.cjs +0 -4
  63. package/dist/relation-loader-Ggy1ujwR.mjs +0 -4
  64. package/dist/sync.d.ts +0 -1878
@@ -0,0 +1,369 @@
1
+ import { A as TDbForeignKey, B as TExistingColumn, D as TDbDefaultValue, J as TTableOptionDiff, R as TDbStorageType, V as TExistingTableOption, k as TDbFieldMeta, l as TGenericLogger, t as AtscriptDbReadable, w as TColumnDiff } from "./db-readable-BQQzfguJ.cjs";
2
+ import { r as AtscriptDbView, t as DbSpace } from "./db-space-Vxpcnyt5.cjs";
3
+ import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
4
+
5
+ //#region src/schema/sync-entry.d.ts
6
+ interface TSyncColors {
7
+ green(s: string): string;
8
+ red(s: string): string;
9
+ cyan(s: string): string;
10
+ yellow(s: string): string;
11
+ bold(s: string): string;
12
+ dim(s: string): string;
13
+ underline(s: string): string;
14
+ }
15
+ type TSyncEntryStatus = "create" | "alter" | "drop" | "in-sync" | "error";
16
+ interface TSyncEntryInit {
17
+ name: string;
18
+ /** 'V' = virtual view, 'M' = materialized view, 'E' = external view, undefined = table */
19
+ viewType?: "V" | "M" | "E";
20
+ status: TSyncEntryStatus;
21
+ syncMethod?: "drop" | "recreate";
22
+ columnsToAdd?: TDbFieldMeta[];
23
+ columnsToRename?: Array<{
24
+ from: string;
25
+ to: string;
26
+ }>;
27
+ typeChanges?: Array<{
28
+ column: string;
29
+ fromType: string;
30
+ toType: string;
31
+ }>;
32
+ nullableChanges?: Array<{
33
+ column: string;
34
+ toNullable: boolean;
35
+ }>;
36
+ defaultChanges?: Array<{
37
+ column: string;
38
+ oldDefault?: string;
39
+ newDefault?: string;
40
+ }>;
41
+ columnsToDrop?: string[];
42
+ optionChanges?: TTableOptionDiff["changed"];
43
+ fkAdded?: Array<{
44
+ fields: string[];
45
+ targetTable: string;
46
+ }>;
47
+ fkRemoved?: Array<{
48
+ fields: string[];
49
+ targetTable: string;
50
+ }>;
51
+ fkChanged?: Array<{
52
+ fields: string[];
53
+ targetTable: string;
54
+ details: string;
55
+ }>;
56
+ columnsAdded?: string[];
57
+ columnsRenamed?: string[];
58
+ columnsDropped?: string[];
59
+ recreated?: boolean;
60
+ errors?: string[];
61
+ renamedFrom?: string;
62
+ }
63
+ declare class SyncEntry {
64
+ readonly name: string;
65
+ /** 'V' = virtual view, 'M' = materialized view, 'E' = external view, undefined = table */
66
+ readonly viewType?: "V" | "M" | "E";
67
+ readonly status: TSyncEntryStatus;
68
+ readonly syncMethod?: "drop" | "recreate";
69
+ readonly columnsToAdd: TDbFieldMeta[];
70
+ readonly columnsToRename: Array<{
71
+ from: string;
72
+ to: string;
73
+ }>;
74
+ readonly typeChanges: Array<{
75
+ column: string;
76
+ fromType: string;
77
+ toType: string;
78
+ }>;
79
+ readonly nullableChanges: Array<{
80
+ column: string;
81
+ toNullable: boolean;
82
+ }>;
83
+ readonly defaultChanges: Array<{
84
+ column: string;
85
+ oldDefault?: string;
86
+ newDefault?: string;
87
+ }>;
88
+ readonly columnsToDrop: string[];
89
+ readonly optionChanges: TTableOptionDiff["changed"];
90
+ readonly fkAdded: Array<{
91
+ fields: string[];
92
+ targetTable: string;
93
+ }>;
94
+ readonly fkRemoved: Array<{
95
+ fields: string[];
96
+ targetTable: string;
97
+ }>;
98
+ readonly fkChanged: Array<{
99
+ fields: string[];
100
+ targetTable: string;
101
+ details: string;
102
+ }>;
103
+ readonly columnsAdded: string[];
104
+ readonly columnsRenamed: string[];
105
+ readonly columnsDropped: string[];
106
+ readonly recreated: boolean;
107
+ readonly errors: string[];
108
+ readonly renamedFrom?: string;
109
+ constructor(init: TSyncEntryInit);
110
+ /** Whether this entry involves destructive operations */
111
+ get destructive(): boolean;
112
+ /** Whether this entry represents any change (not in-sync) */
113
+ get hasChanges(): boolean;
114
+ /** Whether this entry has errors */
115
+ get hasErrors(): boolean;
116
+ /** Render this entry for display */
117
+ print(mode: "plan" | "result", colors?: TSyncColors): string[];
118
+ private labelAndPrefix;
119
+ private printError;
120
+ private printPlan;
121
+ private printResult;
122
+ private printInSync;
123
+ }
124
+ //#endregion
125
+ //#region src/schema/schema-hash.d.ts
126
+ interface TFieldSnapshot {
127
+ physicalName: string;
128
+ designType: string;
129
+ optional: boolean;
130
+ isPrimaryKey: boolean;
131
+ storage: TDbStorageType;
132
+ defaultValue?: TDbDefaultValue;
133
+ /** Adapter-specific mapped type (e.g., "VARCHAR(255)", "INTEGER"). */
134
+ mappedType?: string;
135
+ }
136
+ interface TIndexSnapshot {
137
+ key: string;
138
+ type: string;
139
+ fields: Array<{
140
+ name: string;
141
+ sort: string;
142
+ }>;
143
+ }
144
+ interface TForeignKeySnapshot {
145
+ fields: string[];
146
+ targetTable: string;
147
+ targetFields: string[];
148
+ onDelete?: string;
149
+ onUpdate?: string;
150
+ }
151
+ interface TTableSnapshot {
152
+ tableName: string;
153
+ fields: TFieldSnapshot[];
154
+ indexes: TIndexSnapshot[];
155
+ foreignKeys: TForeignKeySnapshot[];
156
+ /** Adapter-specific table-level options (e.g., MySQL engine/charset, MongoDB capped). */
157
+ tableOptions?: TExistingTableOption[];
158
+ }
159
+ interface TViewSnapshot {
160
+ tableName: string;
161
+ viewType: "V" | "M" | "E";
162
+ entryTable?: string;
163
+ joinTables?: string[];
164
+ filterHash?: string;
165
+ materialized?: boolean;
166
+ fields: TFieldSnapshot[];
167
+ }
168
+ /**
169
+ * Extracts a canonical, serializable snapshot from a readable's metadata.
170
+ * Sorted deterministically so the hash is stable across runs.
171
+ *
172
+ * @param readable - The table/view readable.
173
+ * @param typeMapper - Optional adapter-specific type mapper. When provided,
174
+ * each field's mapped type (e.g., "VARCHAR(255)") is stored in the snapshot
175
+ * for precise type change detection.
176
+ */
177
+ declare function computeTableSnapshot(readable: AtscriptDbReadable, typeMapper?: (field: TDbFieldMeta) => string, tableOptions?: TExistingTableOption[]): TTableSnapshot;
178
+ /**
179
+ * Extracts a canonical, serializable snapshot from a view's metadata.
180
+ * Captures view plan (entry table, joins, filter, materialization) for
181
+ * detecting view definition changes.
182
+ */
183
+ declare function computeViewSnapshot(view: AtscriptDbView): TViewSnapshot;
184
+ /**
185
+ * Computes a deterministic hash string from multiple table snapshots.
186
+ * Uses FNV-1a for speed — not cryptographic, just needs stability + collision resistance.
187
+ */
188
+ declare function computeSchemaHash(snapshots: Array<TTableSnapshot | TViewSnapshot>): string;
189
+ /**
190
+ * Computes a hash for a single table/view snapshot.
191
+ * Used for per-table change detection via stored snapshots.
192
+ */
193
+ declare function computeTableHash(snapshot: TTableSnapshot | TViewSnapshot): string;
194
+ /**
195
+ * Converts stored snapshot fields to `TExistingColumn[]` format
196
+ * for use with `computeColumnDiff`. Used by adapters that lack
197
+ * native column introspection (e.g., MongoDB).
198
+ *
199
+ * The `type` field uses `mappedType` when available (adapter-specific),
200
+ * falling back to `designType`.
201
+ */
202
+ declare function snapshotToExistingColumns(snapshot: TTableSnapshot): TExistingColumn[];
203
+ /**
204
+ * Extracts table options from a stored snapshot for diff comparison.
205
+ * Used as fallback when an adapter lacks native table option introspection.
206
+ */
207
+ declare function snapshotToExistingTableOptions(snapshot: TTableSnapshot): TExistingTableOption[];
208
+ //#endregion
209
+ //#region src/schema/sync-store.d.ts
210
+ /**
211
+ * Reads a stored table snapshot from the control table.
212
+ * Use this for introspection/test utilities without coupling to control table internals.
213
+ */
214
+ declare function readStoredSnapshot(space: DbSpace, tableName: string): Promise<TTableSnapshot | null>;
215
+ declare function readStoredSnapshot(space: DbSpace, tableName: string, asView: true): Promise<TViewSnapshot | null>;
216
+ //#endregion
217
+ //#region src/schema/schema-sync.d.ts
218
+ interface TSyncPlan {
219
+ status: "up-to-date" | "changes-needed";
220
+ schemaHash: string;
221
+ entries: SyncEntry[];
222
+ }
223
+ interface TSyncOptions {
224
+ /** Pod/instance identifier for distributed locking. Default: random UUID. */
225
+ podId?: string;
226
+ /** Lock TTL in milliseconds. Default: 30000 (30s). */
227
+ lockTtlMs?: number;
228
+ /** How long to wait for another pod's lock before giving up. Default: 60000 (60s). */
229
+ waitTimeoutMs?: number;
230
+ /** Poll interval when waiting for lock. Default: 500ms. */
231
+ pollIntervalMs?: number;
232
+ /** Force sync even if hash matches. Default: false. */
233
+ force?: boolean;
234
+ /** Safe mode — skip destructive operations (column drops, table drops). Default: false. */
235
+ safe?: boolean;
236
+ }
237
+ interface TSyncResult {
238
+ status: "up-to-date" | "synced" | "synced-by-peer";
239
+ schemaHash: string;
240
+ entries: SyncEntry[];
241
+ }
242
+ declare class SchemaSync {
243
+ private readonly space;
244
+ private readonly store;
245
+ private readonly logger;
246
+ constructor(space: DbSpace, logger?: TGenericLogger);
247
+ /**
248
+ * Resolves types into categorized readables and computes the schema hash.
249
+ * Passes each adapter's typeMapper for precise type tracking in snapshots.
250
+ */
251
+ private resolveAndHash;
252
+ /**
253
+ * Checks an external view: verifies it exists in the DB and columns match.
254
+ * Returns a SyncEntry with status 'in-sync' or 'error'.
255
+ */
256
+ private checkExternalView;
257
+ /**
258
+ * Detects tables/views present in the previous sync but absent from the current schema.
259
+ * Returns SyncEntry instances with status 'drop'.
260
+ */
261
+ private detectRemoved;
262
+ /**
263
+ * Starts a periodic heartbeat that extends the lock's TTL while sync runs.
264
+ * Returns a handle with `stop()` to cancel and `getAbortReason()` to check
265
+ * whether the lock was stolen or unexpectedly removed.
266
+ */
267
+ private startHeartbeat;
268
+ /** Throws if the heartbeat detected a stolen/missing lock. */
269
+ private assertLockHeld;
270
+ /**
271
+ * Runs schema synchronization with distributed locking.
272
+ */
273
+ run(types: TAtscriptAnnotatedType[], opts?: TSyncOptions): Promise<TSyncResult>;
274
+ /**
275
+ * Computes a dry-run plan showing what `run()` would do, without executing any DDL.
276
+ */
277
+ plan(types: TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
278
+ /** Fallback typeMapper for snapshot-based Path B: compares designType directly, skips unions. */
279
+ private resolveTypeMapper;
280
+ private planTable;
281
+ /**
282
+ * Populates plan init from a column diff (shared by Path A and Path B).
283
+ */
284
+ private populatePlanFromDiff;
285
+ /**
286
+ * Computes table option diff using DB-first introspection with snapshot fallback.
287
+ * Returns null if the adapter has no table options.
288
+ */
289
+ private diffTableOptions;
290
+ private planView;
291
+ private buildExecutorDeps;
292
+ }
293
+ //#endregion
294
+ //#region src/schema/column-diff.d.ts
295
+ /**
296
+ * Computes the difference between desired schema fields and existing database columns.
297
+ *
298
+ * @param desired - Field descriptors from the Atscript type (after flattening).
299
+ * @param existing - Columns currently in the database (from introspection).
300
+ * @param typeMapper - Optional function to map field metadata to DB-native type strings.
301
+ * Receives the full field meta (design type, annotations, PK status, etc.)
302
+ * so adapters can produce context-aware types (e.g., `VARCHAR(255)` from maxLength).
303
+ * Required for type change detection.
304
+ */
305
+ declare function computeColumnDiff(desired: readonly TDbFieldMeta[], existing: TExistingColumn[], typeMapper?: (field: TDbFieldMeta) => string): TColumnDiff;
306
+ //#endregion
307
+ //#region src/schema/table-option-diff.d.ts
308
+ /**
309
+ * Computes the difference between desired and existing table options.
310
+ *
311
+ * Options present in desired but absent from existing are ignored (initial state).
312
+ * Options present in existing but absent from desired are ignored (sticky options).
313
+ * Only value changes on matching keys are tracked.
314
+ *
315
+ * @param desired - Options from Atscript annotations (via adapter.getDesiredTableOptions()).
316
+ * @param existing - Options from DB introspection or snapshot fallback.
317
+ * @param destructiveKeys - Option keys where a value change requires table recreation.
318
+ */
319
+ declare function computeTableOptionDiff(desired: readonly TExistingTableOption[], existing: readonly TExistingTableOption[], destructiveKeys?: ReadonlySet<string>): TTableOptionDiff;
320
+ //#endregion
321
+ //#region src/schema/fk-diff.d.ts
322
+ interface TForeignKeyDiff {
323
+ /** FKs present in desired but not in stored snapshot (new). */
324
+ added: TDbForeignKey[];
325
+ /** FKs present in stored snapshot but not in desired (removed). */
326
+ removed: TForeignKeySnapshot[];
327
+ /** FKs where fields match but target, onDelete, or onUpdate differ. */
328
+ changed: Array<{
329
+ desired: TDbForeignKey;
330
+ existing: TForeignKeySnapshot;
331
+ }>;
332
+ }
333
+ /** Canonical key for an FK: sorted local field names, comma-joined. */
334
+ declare function fkKey(fields: readonly string[]): string;
335
+ /**
336
+ * Compares desired FK constraints against stored snapshot to detect
337
+ * additions, removals, and property changes (target table, target fields,
338
+ * onDelete, onUpdate).
339
+ */
340
+ declare function computeForeignKeyDiff(desired: ReadonlyMap<string, TDbForeignKey>, existingSnapshot: readonly TForeignKeySnapshot[]): TForeignKeyDiff;
341
+ /** Whether the FK diff contains any changes. */
342
+ declare function hasForeignKeyChanges(diff: TForeignKeyDiff): boolean;
343
+ //#endregion
344
+ //#region src/sync.d.ts
345
+ /**
346
+ * Synchronizes database schema with distributed locking.
347
+ * Safe to call from multiple concurrent processes/pods.
348
+ *
349
+ * ```typescript
350
+ * import { syncSchema } from '@atscript/db/sync'
351
+ *
352
+ * const db = new DbSpace(() => new SqliteAdapter(driver))
353
+ * await syncSchema(db, [UsersType, PostsType, CommentsType])
354
+ * ```
355
+ *
356
+ * The function:
357
+ * 1. Creates an `__atscript_control` table for lock coordination
358
+ * 2. Computes a schema hash — skips entirely if nothing changed
359
+ * 3. Acquires a distributed lock so only one process syncs
360
+ * 4. Creates tables, adds new columns, syncs indexes
361
+ * 5. Stores the new hash and releases the lock
362
+ *
363
+ * @param space - The DbSpace containing the adapter factory.
364
+ * @param types - Atscript annotated types to synchronize.
365
+ * @param opts - Lock TTL, wait timeout, force mode, etc.
366
+ */
367
+ declare function syncSchema(space: DbSpace, types: TAtscriptAnnotatedType[], opts?: TSyncOptions): Promise<TSyncResult>;
368
+ //#endregion
369
+ export { SchemaSync, SyncEntry, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TSyncColors, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TTableSnapshot, type TViewSnapshot, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema };