@atscript/db 0.1.140 → 0.1.142
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.
- package/dist/agg.d.cts +1 -1
- package/dist/agg.d.mts +1 -1
- package/dist/{buckets-C-27xmtq.d.cts → buckets-Bv4pah66.d.cts} +225 -22
- package/dist/{buckets-BFG2RYRW.d.mts → buckets-CjL7F-hp.d.mts} +225 -22
- package/dist/{column-diff-CgxgFKzx.cjs → column-diff-CfPNcP6e.cjs} +663 -239
- package/dist/{column-diff-BwOA5101.mjs → column-diff-CmFNXV8C.mjs} +638 -220
- package/dist/column-diff-DiBbXyLA.d.cts +211 -0
- package/dist/column-diff-n-k5KY0u.d.mts +211 -0
- package/dist/derived-rules-0sKn4f5C.mjs +44 -0
- package/dist/derived-rules-YstgIxG-.cjs +67 -0
- package/dist/index.cjs +38 -4
- package/dist/index.d.cts +23 -6
- package/dist/index.d.mts +23 -6
- package/dist/index.mjs +34 -4
- package/dist/{nested-writer-FWD5oOYh.mjs → nested-writer-BO3vhbkP.mjs} +8 -4
- package/dist/{nested-writer-BZNCuqI6.cjs → nested-writer-DYsRxZ5f.cjs} +8 -4
- package/dist/object-DSN0h9lB.d.cts +30 -0
- package/dist/object-DSN0h9lB.d.mts +30 -0
- package/dist/plugin.cjs +392 -139
- package/dist/plugin.mjs +392 -139
- package/dist/rel.cjs +2 -2
- package/dist/rel.d.cts +2 -2
- package/dist/rel.d.mts +2 -2
- package/dist/rel.mjs +2 -2
- package/dist/{relation-helpers-D3Zu0Mta.d.mts → relation-helpers-B59to_dG.d.mts} +5 -4
- package/dist/{relation-helpers-DxrvS6ar.d.cts → relation-helpers-DQ_nRsV9.d.cts} +5 -4
- package/dist/{relation-loader-6ZB_5KFq.cjs → relation-loader-CgJ8bK6X.cjs} +1 -1
- package/dist/{relation-loader-CTFaZpVa.mjs → relation-loader-CuhEBzFU.mjs} +1 -1
- package/dist/shared.cjs +6 -1
- package/dist/shared.d.cts +48 -9
- package/dist/shared.d.mts +48 -9
- package/dist/shared.mjs +2 -2
- package/dist/sync.cjs +331 -105
- package/dist/sync.d.cts +62 -163
- package/dist/sync.d.mts +62 -163
- package/dist/sync.mjs +331 -105
- package/dist/{validation-utils-B4h-GW4d.mjs → validation-utils-CMR4fe2M.mjs} +99 -34
- package/dist/{validation-utils-Dg0hW6dn.cjs → validation-utils-DOsB4e6G.cjs} +128 -33
- package/dist/{validator-Drb2N-YL.d.cts → validator-Bw6ks9Hy.d.cts} +1 -11
- package/dist/{validator-Drb2N-YL.d.mts → validator-Bw6ks9Hy.d.mts} +1 -11
- package/dist/{validator-Ch7UIQl9.mjs → validator-D8bPsXPN.mjs} +54 -2
- package/dist/{validator-BtZbcLN2.cjs → validator-DASnXf1j.cjs} +77 -1
- package/dist/validator.cjs +1 -1
- package/dist/validator.d.cts +2 -1
- package/dist/validator.d.mts +2 -1
- package/dist/validator.mjs +1 -1
- package/package.json +6 -6
- package/dist/column-diff-BmqvgBWw.d.cts +0 -24
- package/dist/column-diff-DPkbZIVE.d.mts +0 -24
package/dist/sync.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as computeColumnDiff } from "./column-diff-
|
|
1
|
+
import { G as TDbObjectKind, Lt as DbSpace, R as TDbFieldMeta, _t as TReferencingForeignKey, gt as TPrimaryKeyChange, it as TEnsureTableOptions, nt as TDerivedChangeReason, ot as TExistingForeignKey, st as TExistingTableOption, un as TGenericLogger, xt as TTableOptionDiff, z as TDbForeignKey } from "./buckets-Bv4pah66.cjs";
|
|
2
|
+
import { a as TTableSnapshot, c as TViewSnapshot, d as computeTableHash, f as computeTableSnapshot, h as snapshotToExistingTableOptions, i as TForeignKeySnapshot, l as canonicalizeQueryNode, m as snapshotToExistingColumns, o as TViewColumnSnapshot, p as computeViewSnapshot, r as TFieldSnapshot, s as TViewJoinSnapshot, t as computeColumnDiff, u as computeSchemaHash } from "./column-diff-DiBbXyLA.cjs";
|
|
3
3
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/sync-entry.d.ts
|
|
@@ -19,7 +19,17 @@ type TSyncEntryStatus = "create" | "alter" | "drop" | "in-sync" | "error";
|
|
|
19
19
|
* recreate a destructive table-option change needs, and nullable/default
|
|
20
20
|
* changes on adapters that need DDL for them.
|
|
21
21
|
*/
|
|
22
|
-
type TSyncSkippedWork = "pk-rebuild" | "recreate" | "table-options" | "nullable-defaults";
|
|
22
|
+
type TSyncSkippedWork = "pk-rebuild" | "recreate" | "table-options" | "nullable-defaults" /** A derived column's drop + add (kind / expression / type change) — since 0.1.141. */ | "derived";
|
|
23
|
+
/**
|
|
24
|
+
* One derived-column rebuild as plan and run entries report it (since 0.1.141):
|
|
25
|
+
* `reason` as the column diff classified it, `derived` whether the MODEL side
|
|
26
|
+
* is the derived one (`kind` reads `regular → derived` / `derived → regular`).
|
|
27
|
+
*/
|
|
28
|
+
interface TSyncDerivedChange {
|
|
29
|
+
column: string;
|
|
30
|
+
reason: TDerivedChangeReason;
|
|
31
|
+
derived: boolean;
|
|
32
|
+
}
|
|
23
33
|
interface TSyncEntryInit {
|
|
24
34
|
name: string;
|
|
25
35
|
/** 'V' = virtual view, 'M' = materialized view, 'E' = external view, undefined = table */
|
|
@@ -60,6 +70,13 @@ interface TSyncEntryInit {
|
|
|
60
70
|
targetTable: string;
|
|
61
71
|
details: string;
|
|
62
72
|
}>;
|
|
73
|
+
/**
|
|
74
|
+
* Derived columns the run drops and re-adds (a generated column's
|
|
75
|
+
* expression cannot be altered in place) — kept on the entry when safe
|
|
76
|
+
* mode skipped the rebuild (`skipped` includes `'derived'`).
|
|
77
|
+
* @since 0.1.141
|
|
78
|
+
*/
|
|
79
|
+
derivedChanges?: TSyncDerivedChange[];
|
|
63
80
|
columnsAdded?: string[];
|
|
64
81
|
columnsRenamed?: string[];
|
|
65
82
|
columnsDropped?: string[];
|
|
@@ -107,6 +124,13 @@ interface TSyncEntryInit {
|
|
|
107
124
|
* @since 0.1.128
|
|
108
125
|
*/
|
|
109
126
|
refused?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Managed views this view reads whose recreate forces this view's own
|
|
129
|
+
* drop-and-recreate (its definition is unchanged). Printed as
|
|
130
|
+
* `· upstream view "x" recreated`.
|
|
131
|
+
* @since 0.1.141
|
|
132
|
+
*/
|
|
133
|
+
cascadeFrom?: string[];
|
|
110
134
|
}
|
|
111
135
|
declare class SyncEntry {
|
|
112
136
|
readonly name: string;
|
|
@@ -148,6 +172,8 @@ declare class SyncEntry {
|
|
|
148
172
|
targetTable: string;
|
|
149
173
|
details: string;
|
|
150
174
|
}>;
|
|
175
|
+
/** @since 0.1.141 — see {@link TSyncEntryInit.derivedChanges}. */
|
|
176
|
+
readonly derivedChanges: TSyncDerivedChange[];
|
|
151
177
|
readonly columnsAdded: string[];
|
|
152
178
|
readonly columnsRenamed: string[];
|
|
153
179
|
readonly columnsDropped: string[];
|
|
@@ -168,6 +194,8 @@ declare class SyncEntry {
|
|
|
168
194
|
readonly dropGroup?: string[];
|
|
169
195
|
/** @since 0.1.128 — see {@link TSyncEntryInit.refused}. */
|
|
170
196
|
readonly refused: boolean;
|
|
197
|
+
/** @since 0.1.141 — see {@link TSyncEntryInit.cascadeFrom}. */
|
|
198
|
+
readonly cascadeFrom: string[];
|
|
171
199
|
constructor(init: TSyncEntryInit);
|
|
172
200
|
/**
|
|
173
201
|
* The init object this entry was built from — lets callers derive a
|
|
@@ -208,6 +236,11 @@ declare class SyncEntry {
|
|
|
208
236
|
* mode)` in plan and result when the `'drop'` recreate was skipped.
|
|
209
237
|
*/
|
|
210
238
|
private printTypeChanges;
|
|
239
|
+
/**
|
|
240
|
+
* `~ col — derived column (expression changed) — drop + add` (plan) /
|
|
241
|
+
* `— rebuilt` (result), or `! … — skipped (safe mode)` when pending.
|
|
242
|
+
*/
|
|
243
|
+
private printDerivedChanges;
|
|
211
244
|
/** `~ col — nullable` / `~ col — default a → b`, `— skipped (safe mode)` when pending. */
|
|
212
245
|
private printNullableDefaults;
|
|
213
246
|
/**
|
|
@@ -218,165 +251,14 @@ declare class SyncEntry {
|
|
|
218
251
|
private printOptionChanges;
|
|
219
252
|
/** `· after: a, b` (plan only — the executor already runs in this order). */
|
|
220
253
|
private printDependsOn;
|
|
254
|
+
/** `· upstream view "x" recreated` — why an unchanged view is recreated. */
|
|
255
|
+
private printCascade;
|
|
221
256
|
private printDropGroup;
|
|
222
257
|
private printPlan;
|
|
223
258
|
private printResult;
|
|
224
259
|
private printInSync;
|
|
225
260
|
}
|
|
226
261
|
//#endregion
|
|
227
|
-
//#region src/schema/schema-hash.d.ts
|
|
228
|
-
interface TFieldSnapshot {
|
|
229
|
-
physicalName: string;
|
|
230
|
-
designType: string;
|
|
231
|
-
optional: boolean;
|
|
232
|
-
isPrimaryKey: boolean;
|
|
233
|
-
storage: TDbStorageType;
|
|
234
|
-
defaultValue?: TDbDefaultValue;
|
|
235
|
-
/** Adapter-specific mapped type (e.g., "VARCHAR(255)", "INTEGER"). */
|
|
236
|
-
mappedType?: string;
|
|
237
|
-
/** `@db.encrypted` — toggling encryption changes the snapshot hash on every adapter. */
|
|
238
|
-
encrypted?: boolean;
|
|
239
|
-
}
|
|
240
|
-
interface TIndexSnapshot {
|
|
241
|
-
key: string;
|
|
242
|
-
type: string;
|
|
243
|
-
fields: Array<{
|
|
244
|
-
name: string;
|
|
245
|
-
sort: string;
|
|
246
|
-
}>;
|
|
247
|
-
}
|
|
248
|
-
interface TForeignKeySnapshot {
|
|
249
|
-
fields: string[];
|
|
250
|
-
targetTable: string;
|
|
251
|
-
targetFields: string[];
|
|
252
|
-
onDelete?: string;
|
|
253
|
-
onUpdate?: string;
|
|
254
|
-
}
|
|
255
|
-
interface TTableSnapshot {
|
|
256
|
-
tableName: string;
|
|
257
|
-
fields: TFieldSnapshot[];
|
|
258
|
-
indexes: TIndexSnapshot[];
|
|
259
|
-
foreignKeys: TForeignKeySnapshot[];
|
|
260
|
-
/** Adapter-specific table-level options (e.g., MySQL engine/charset, MongoDB capped). */
|
|
261
|
-
tableOptions?: TExistingTableOption[];
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* One join of a managed view as stored in its snapshot.
|
|
265
|
-
* @since 0.1.128 — `joinTables` elements were bare target-table names before;
|
|
266
|
-
* the ON predicate is now part of the view definition.
|
|
267
|
-
*/
|
|
268
|
-
interface TViewJoinSnapshot {
|
|
269
|
-
targetTable: string;
|
|
270
|
-
/** Canonical JSON of the join condition (see {@link canonicalizeQueryNode}). */
|
|
271
|
-
condition: string;
|
|
272
|
-
/** Emitted only for `"left"` — an inner join (the default) carries no key. @since 0.1.136 */
|
|
273
|
-
kind?: "inner" | "left";
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* One column of a managed view as stored in its snapshot — the PHYSICAL
|
|
277
|
-
* source it reads, so a source rename (`@db.column`, flattening, a moved
|
|
278
|
-
* JSON leaf) or an aggregate change recreates the view.
|
|
279
|
-
* @since 0.1.136
|
|
280
|
-
*/
|
|
281
|
-
interface TViewColumnSnapshot {
|
|
282
|
-
column: string;
|
|
283
|
-
sourceTable: string;
|
|
284
|
-
sourceColumn: string;
|
|
285
|
-
/** JSON array of the path segments inside a JSON source column. */
|
|
286
|
-
jsonPath?: string;
|
|
287
|
-
jsonType?: string;
|
|
288
|
-
aggFn?: string;
|
|
289
|
-
aggField?: string;
|
|
290
|
-
/** Canonical JSON of a conditional aggregate's predicate. */
|
|
291
|
-
aggFilter?: string;
|
|
292
|
-
}
|
|
293
|
-
interface TViewSnapshot {
|
|
294
|
-
tableName: string;
|
|
295
|
-
viewType: "V" | "M" | "E";
|
|
296
|
-
entryTable?: string;
|
|
297
|
-
/**
|
|
298
|
-
* Joins in declaration order. The key keeps its historical name so a
|
|
299
|
-
* join-less view (`[]`) serializes byte-identically to older snapshots.
|
|
300
|
-
*/
|
|
301
|
-
joinTables?: TViewJoinSnapshot[];
|
|
302
|
-
/** @since 0.1.136 — view columns and their physical sources, sorted by `column`. */
|
|
303
|
-
columns?: TViewColumnSnapshot[];
|
|
304
|
-
filterHash?: string;
|
|
305
|
-
/** @since 0.1.128 — hash of the canonical `@db.view.having` predicate. */
|
|
306
|
-
havingHash?: string;
|
|
307
|
-
materialized?: boolean;
|
|
308
|
-
/**
|
|
309
|
-
* @since 0.1.137 — the adapter's `viewRenderRevision()`, present only when
|
|
310
|
-
* the adapter defines one (managed views only).
|
|
311
|
-
*/
|
|
312
|
-
renderRevision?: string;
|
|
313
|
-
fields: TFieldSnapshot[];
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Extracts a canonical, serializable snapshot from a readable's metadata.
|
|
317
|
-
* Sorted deterministically so the hash is stable across runs.
|
|
318
|
-
*
|
|
319
|
-
* @param readable - The table/view readable.
|
|
320
|
-
* @param typeMapper - Optional adapter-specific type mapper. When provided,
|
|
321
|
-
* each field's mapped type (e.g., "VARCHAR(255)") is stored in the snapshot
|
|
322
|
-
* for precise type change detection.
|
|
323
|
-
*/
|
|
324
|
-
declare function computeTableSnapshot(readable: AtscriptDbReadable, typeMapper?: (field: TDbFieldMeta) => string, tableOptions?: TExistingTableOption[]): TTableSnapshot;
|
|
325
|
-
/**
|
|
326
|
-
* Extracts a canonical, serializable snapshot from a view's metadata.
|
|
327
|
-
* Captures view plan (entry table, joins, filter, materialization) for
|
|
328
|
-
* detecting view definition changes.
|
|
329
|
-
*/
|
|
330
|
-
declare function computeViewSnapshot(view: AtscriptDbView): TViewSnapshot;
|
|
331
|
-
/** Canonical (table-qualified, fixed-key-order) form of a view predicate. */
|
|
332
|
-
type TCanonicalQueryNode = {
|
|
333
|
-
and: TCanonicalQueryNode[];
|
|
334
|
-
} | {
|
|
335
|
-
or: TCanonicalQueryNode[];
|
|
336
|
-
} | {
|
|
337
|
-
not: TCanonicalQueryNode;
|
|
338
|
-
} /** `r` is `{ f: "<table>.<field>" }` for a field-to-field comparison, else the literal. */ | {
|
|
339
|
-
l: string;
|
|
340
|
-
op: string;
|
|
341
|
-
r?: unknown;
|
|
342
|
-
};
|
|
343
|
-
/**
|
|
344
|
-
* Converts a view predicate (join condition, `@db.view.filter`,
|
|
345
|
-
* `@db.view.having`) into a serializable structure whose JSON is a stable
|
|
346
|
-
* function of its MEANING: field refs become `qualify(ref)` — the view's
|
|
347
|
-
* `resolveFieldRef(ref, (n) => n)`, i.e. `"<table>.<field>"`, so a predicate
|
|
348
|
-
* retargeted to another table with the same field name changes — operators
|
|
349
|
-
* and literal values are kept as-is, `$and`/`$or` keep declaration order, and
|
|
350
|
-
* no function references survive. Two identical models produce byte-identical
|
|
351
|
-
* JSON.
|
|
352
|
-
* @since 0.1.128
|
|
353
|
-
*/
|
|
354
|
-
declare function canonicalizeQueryNode(node: AtscriptQueryNode$1, qualify: (ref: AtscriptQueryFieldRef$1) => string): TCanonicalQueryNode;
|
|
355
|
-
/**
|
|
356
|
-
* Computes a deterministic hash string from multiple table snapshots.
|
|
357
|
-
* Uses FNV-1a for speed — not cryptographic, just needs stability + collision resistance.
|
|
358
|
-
*/
|
|
359
|
-
declare function computeSchemaHash(snapshots: Array<TTableSnapshot | TViewSnapshot>): string;
|
|
360
|
-
/**
|
|
361
|
-
* Computes a hash for a single table/view snapshot.
|
|
362
|
-
* Used for per-table change detection via stored snapshots.
|
|
363
|
-
*/
|
|
364
|
-
declare function computeTableHash(snapshot: TTableSnapshot | TViewSnapshot): string;
|
|
365
|
-
/**
|
|
366
|
-
* Converts stored snapshot fields to `TExistingColumn[]` format
|
|
367
|
-
* for use with `computeColumnDiff`. Used by adapters that lack
|
|
368
|
-
* native column introspection (e.g., MongoDB).
|
|
369
|
-
*
|
|
370
|
-
* The `type` field uses `mappedType` when available (adapter-specific),
|
|
371
|
-
* falling back to `designType`.
|
|
372
|
-
*/
|
|
373
|
-
declare function snapshotToExistingColumns(snapshot: TTableSnapshot): TExistingColumn[];
|
|
374
|
-
/**
|
|
375
|
-
* Extracts table options from a stored snapshot for diff comparison.
|
|
376
|
-
* Used as fallback when an adapter lacks native table option introspection.
|
|
377
|
-
*/
|
|
378
|
-
declare function snapshotToExistingTableOptions(snapshot: TTableSnapshot): TExistingTableOption[];
|
|
379
|
-
//#endregion
|
|
380
262
|
//#region src/schema/sync-store.d.ts
|
|
381
263
|
/**
|
|
382
264
|
* Reads a stored table snapshot from the control table.
|
|
@@ -465,10 +347,27 @@ declare class SchemaSync {
|
|
|
465
347
|
* Starts a periodic heartbeat that extends the lock's TTL while sync runs.
|
|
466
348
|
* Returns a handle with `stop()` to cancel and `getAbortReason()` to check
|
|
467
349
|
* whether the lock was stolen or unexpectedly removed.
|
|
350
|
+
*
|
|
351
|
+
* At most one refresh is in flight; `stop()` resolves once it has settled,
|
|
352
|
+
* so the lock is released only after the last refresh — a late refresh must
|
|
353
|
+
* never race the release (or the next holder's lock).
|
|
468
354
|
*/
|
|
469
355
|
private startHeartbeat;
|
|
356
|
+
/**
|
|
357
|
+
* Acquires the sync lock, waiting for a peer that holds it. Resolves
|
|
358
|
+
* `"acquired"`, or `"synced-by-peer"` when a non-forced run finds, after a
|
|
359
|
+
* wait, that the peer stored this schema's hash. A forced run never
|
|
360
|
+
* short-circuits — it waits its turn and runs. Losing the race for a freed
|
|
361
|
+
* lock to another waiter just waits again, within the same `waitTimeoutMs`.
|
|
362
|
+
*/
|
|
363
|
+
private acquireLock;
|
|
470
364
|
/** Throws if the heartbeat detected a stolen/missing lock. */
|
|
471
365
|
private assertLockHeld;
|
|
366
|
+
/**
|
|
367
|
+
* Releases the lock without masking the run's outcome: a failed release is
|
|
368
|
+
* logged (the row expires after `lockTtlMs`, blocking peers until then).
|
|
369
|
+
*/
|
|
370
|
+
private releaseLock;
|
|
472
371
|
/**
|
|
473
372
|
* Runs schema synchronization with distributed locking, in three phases:
|
|
474
373
|
*
|
|
@@ -477,12 +376,12 @@ declare class SchemaSync {
|
|
|
477
376
|
* 2. **Pre-flight** (pure): every change that no order of DDL can apply
|
|
478
377
|
* safely becomes a refusal. One refusal → `status: "refused"`, no DDL,
|
|
479
378
|
* nothing persisted, lock released.
|
|
480
|
-
* 3. **Execute** in dependency order:
|
|
481
|
-
*
|
|
482
|
-
* blocks a table's drop-and-recreate
|
|
483
|
-
* before it) → deferred FKs of cycles →
|
|
484
|
-
*
|
|
485
|
-
* snapshots/tracking/hash.
|
|
379
|
+
* 3. **Execute** in dependency order: removed views, then stale views
|
|
380
|
+
* (dependents first) → inbound FKs of key-changing tables → tables
|
|
381
|
+
* (parents first; a removed table that blocks a table's drop-and-recreate
|
|
382
|
+
* or key rebuild is dropped right before it) → deferred FKs of cycles →
|
|
383
|
+
* managed views (upstream views first) → external-view checks →
|
|
384
|
+
* remaining removed tables (children first) → snapshots/tracking/hash.
|
|
486
385
|
*/
|
|
487
386
|
run(types: readonly TAtscriptAnnotatedType[], opts?: TSyncOptions): Promise<TSyncResult>;
|
|
488
387
|
private discover;
|
|
@@ -661,4 +560,4 @@ declare function syncSchema(space: DbSpace, types: readonly TAtscriptAnnotatedTy
|
|
|
661
560
|
*/
|
|
662
561
|
declare function planSchema(space: DbSpace, types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
|
|
663
562
|
//#endregion
|
|
664
|
-
export { SchemaSync, SyncEntry, type TDbObjectKind, type TDependencyEdge, type TEnsureTableOptions, type TExistingForeignKey, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TPrimaryKeyChange, type TReferencingForeignKey, type TSyncColors, type TSyncEntryInit, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TSyncSkippedWork, type TTableSnapshot, type TViewColumnSnapshot, type TViewJoinSnapshot, type TViewSnapshot, canonicalizeQueryNode, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, planSchema, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema, topoOrder };
|
|
563
|
+
export { SchemaSync, SyncEntry, type TDbObjectKind, type TDependencyEdge, type TEnsureTableOptions, type TExistingForeignKey, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TPrimaryKeyChange, type TReferencingForeignKey, type TSyncColors, type TSyncDerivedChange, type TSyncEntryInit, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TSyncSkippedWork, type TTableSnapshot, type TViewColumnSnapshot, type TViewJoinSnapshot, type TViewSnapshot, canonicalizeQueryNode, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, planSchema, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema, topoOrder };
|
package/dist/sync.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as computeColumnDiff } from "./column-diff-
|
|
1
|
+
import { G as TDbObjectKind, Lt as DbSpace, R as TDbFieldMeta, _t as TReferencingForeignKey, gt as TPrimaryKeyChange, it as TEnsureTableOptions, nt as TDerivedChangeReason, ot as TExistingForeignKey, st as TExistingTableOption, un as TGenericLogger, xt as TTableOptionDiff, z as TDbForeignKey } from "./buckets-CjL7F-hp.mjs";
|
|
2
|
+
import { a as TTableSnapshot, c as TViewSnapshot, d as computeTableHash, f as computeTableSnapshot, h as snapshotToExistingTableOptions, i as TForeignKeySnapshot, l as canonicalizeQueryNode, m as snapshotToExistingColumns, o as TViewColumnSnapshot, p as computeViewSnapshot, r as TFieldSnapshot, s as TViewJoinSnapshot, t as computeColumnDiff, u as computeSchemaHash } from "./column-diff-n-k5KY0u.mjs";
|
|
3
3
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/sync-entry.d.ts
|
|
@@ -19,7 +19,17 @@ type TSyncEntryStatus = "create" | "alter" | "drop" | "in-sync" | "error";
|
|
|
19
19
|
* recreate a destructive table-option change needs, and nullable/default
|
|
20
20
|
* changes on adapters that need DDL for them.
|
|
21
21
|
*/
|
|
22
|
-
type TSyncSkippedWork = "pk-rebuild" | "recreate" | "table-options" | "nullable-defaults";
|
|
22
|
+
type TSyncSkippedWork = "pk-rebuild" | "recreate" | "table-options" | "nullable-defaults" /** A derived column's drop + add (kind / expression / type change) — since 0.1.141. */ | "derived";
|
|
23
|
+
/**
|
|
24
|
+
* One derived-column rebuild as plan and run entries report it (since 0.1.141):
|
|
25
|
+
* `reason` as the column diff classified it, `derived` whether the MODEL side
|
|
26
|
+
* is the derived one (`kind` reads `regular → derived` / `derived → regular`).
|
|
27
|
+
*/
|
|
28
|
+
interface TSyncDerivedChange {
|
|
29
|
+
column: string;
|
|
30
|
+
reason: TDerivedChangeReason;
|
|
31
|
+
derived: boolean;
|
|
32
|
+
}
|
|
23
33
|
interface TSyncEntryInit {
|
|
24
34
|
name: string;
|
|
25
35
|
/** 'V' = virtual view, 'M' = materialized view, 'E' = external view, undefined = table */
|
|
@@ -60,6 +70,13 @@ interface TSyncEntryInit {
|
|
|
60
70
|
targetTable: string;
|
|
61
71
|
details: string;
|
|
62
72
|
}>;
|
|
73
|
+
/**
|
|
74
|
+
* Derived columns the run drops and re-adds (a generated column's
|
|
75
|
+
* expression cannot be altered in place) — kept on the entry when safe
|
|
76
|
+
* mode skipped the rebuild (`skipped` includes `'derived'`).
|
|
77
|
+
* @since 0.1.141
|
|
78
|
+
*/
|
|
79
|
+
derivedChanges?: TSyncDerivedChange[];
|
|
63
80
|
columnsAdded?: string[];
|
|
64
81
|
columnsRenamed?: string[];
|
|
65
82
|
columnsDropped?: string[];
|
|
@@ -107,6 +124,13 @@ interface TSyncEntryInit {
|
|
|
107
124
|
* @since 0.1.128
|
|
108
125
|
*/
|
|
109
126
|
refused?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Managed views this view reads whose recreate forces this view's own
|
|
129
|
+
* drop-and-recreate (its definition is unchanged). Printed as
|
|
130
|
+
* `· upstream view "x" recreated`.
|
|
131
|
+
* @since 0.1.141
|
|
132
|
+
*/
|
|
133
|
+
cascadeFrom?: string[];
|
|
110
134
|
}
|
|
111
135
|
declare class SyncEntry {
|
|
112
136
|
readonly name: string;
|
|
@@ -148,6 +172,8 @@ declare class SyncEntry {
|
|
|
148
172
|
targetTable: string;
|
|
149
173
|
details: string;
|
|
150
174
|
}>;
|
|
175
|
+
/** @since 0.1.141 — see {@link TSyncEntryInit.derivedChanges}. */
|
|
176
|
+
readonly derivedChanges: TSyncDerivedChange[];
|
|
151
177
|
readonly columnsAdded: string[];
|
|
152
178
|
readonly columnsRenamed: string[];
|
|
153
179
|
readonly columnsDropped: string[];
|
|
@@ -168,6 +194,8 @@ declare class SyncEntry {
|
|
|
168
194
|
readonly dropGroup?: string[];
|
|
169
195
|
/** @since 0.1.128 — see {@link TSyncEntryInit.refused}. */
|
|
170
196
|
readonly refused: boolean;
|
|
197
|
+
/** @since 0.1.141 — see {@link TSyncEntryInit.cascadeFrom}. */
|
|
198
|
+
readonly cascadeFrom: string[];
|
|
171
199
|
constructor(init: TSyncEntryInit);
|
|
172
200
|
/**
|
|
173
201
|
* The init object this entry was built from — lets callers derive a
|
|
@@ -208,6 +236,11 @@ declare class SyncEntry {
|
|
|
208
236
|
* mode)` in plan and result when the `'drop'` recreate was skipped.
|
|
209
237
|
*/
|
|
210
238
|
private printTypeChanges;
|
|
239
|
+
/**
|
|
240
|
+
* `~ col — derived column (expression changed) — drop + add` (plan) /
|
|
241
|
+
* `— rebuilt` (result), or `! … — skipped (safe mode)` when pending.
|
|
242
|
+
*/
|
|
243
|
+
private printDerivedChanges;
|
|
211
244
|
/** `~ col — nullable` / `~ col — default a → b`, `— skipped (safe mode)` when pending. */
|
|
212
245
|
private printNullableDefaults;
|
|
213
246
|
/**
|
|
@@ -218,165 +251,14 @@ declare class SyncEntry {
|
|
|
218
251
|
private printOptionChanges;
|
|
219
252
|
/** `· after: a, b` (plan only — the executor already runs in this order). */
|
|
220
253
|
private printDependsOn;
|
|
254
|
+
/** `· upstream view "x" recreated` — why an unchanged view is recreated. */
|
|
255
|
+
private printCascade;
|
|
221
256
|
private printDropGroup;
|
|
222
257
|
private printPlan;
|
|
223
258
|
private printResult;
|
|
224
259
|
private printInSync;
|
|
225
260
|
}
|
|
226
261
|
//#endregion
|
|
227
|
-
//#region src/schema/schema-hash.d.ts
|
|
228
|
-
interface TFieldSnapshot {
|
|
229
|
-
physicalName: string;
|
|
230
|
-
designType: string;
|
|
231
|
-
optional: boolean;
|
|
232
|
-
isPrimaryKey: boolean;
|
|
233
|
-
storage: TDbStorageType;
|
|
234
|
-
defaultValue?: TDbDefaultValue;
|
|
235
|
-
/** Adapter-specific mapped type (e.g., "VARCHAR(255)", "INTEGER"). */
|
|
236
|
-
mappedType?: string;
|
|
237
|
-
/** `@db.encrypted` — toggling encryption changes the snapshot hash on every adapter. */
|
|
238
|
-
encrypted?: boolean;
|
|
239
|
-
}
|
|
240
|
-
interface TIndexSnapshot {
|
|
241
|
-
key: string;
|
|
242
|
-
type: string;
|
|
243
|
-
fields: Array<{
|
|
244
|
-
name: string;
|
|
245
|
-
sort: string;
|
|
246
|
-
}>;
|
|
247
|
-
}
|
|
248
|
-
interface TForeignKeySnapshot {
|
|
249
|
-
fields: string[];
|
|
250
|
-
targetTable: string;
|
|
251
|
-
targetFields: string[];
|
|
252
|
-
onDelete?: string;
|
|
253
|
-
onUpdate?: string;
|
|
254
|
-
}
|
|
255
|
-
interface TTableSnapshot {
|
|
256
|
-
tableName: string;
|
|
257
|
-
fields: TFieldSnapshot[];
|
|
258
|
-
indexes: TIndexSnapshot[];
|
|
259
|
-
foreignKeys: TForeignKeySnapshot[];
|
|
260
|
-
/** Adapter-specific table-level options (e.g., MySQL engine/charset, MongoDB capped). */
|
|
261
|
-
tableOptions?: TExistingTableOption[];
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* One join of a managed view as stored in its snapshot.
|
|
265
|
-
* @since 0.1.128 — `joinTables` elements were bare target-table names before;
|
|
266
|
-
* the ON predicate is now part of the view definition.
|
|
267
|
-
*/
|
|
268
|
-
interface TViewJoinSnapshot {
|
|
269
|
-
targetTable: string;
|
|
270
|
-
/** Canonical JSON of the join condition (see {@link canonicalizeQueryNode}). */
|
|
271
|
-
condition: string;
|
|
272
|
-
/** Emitted only for `"left"` — an inner join (the default) carries no key. @since 0.1.136 */
|
|
273
|
-
kind?: "inner" | "left";
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* One column of a managed view as stored in its snapshot — the PHYSICAL
|
|
277
|
-
* source it reads, so a source rename (`@db.column`, flattening, a moved
|
|
278
|
-
* JSON leaf) or an aggregate change recreates the view.
|
|
279
|
-
* @since 0.1.136
|
|
280
|
-
*/
|
|
281
|
-
interface TViewColumnSnapshot {
|
|
282
|
-
column: string;
|
|
283
|
-
sourceTable: string;
|
|
284
|
-
sourceColumn: string;
|
|
285
|
-
/** JSON array of the path segments inside a JSON source column. */
|
|
286
|
-
jsonPath?: string;
|
|
287
|
-
jsonType?: string;
|
|
288
|
-
aggFn?: string;
|
|
289
|
-
aggField?: string;
|
|
290
|
-
/** Canonical JSON of a conditional aggregate's predicate. */
|
|
291
|
-
aggFilter?: string;
|
|
292
|
-
}
|
|
293
|
-
interface TViewSnapshot {
|
|
294
|
-
tableName: string;
|
|
295
|
-
viewType: "V" | "M" | "E";
|
|
296
|
-
entryTable?: string;
|
|
297
|
-
/**
|
|
298
|
-
* Joins in declaration order. The key keeps its historical name so a
|
|
299
|
-
* join-less view (`[]`) serializes byte-identically to older snapshots.
|
|
300
|
-
*/
|
|
301
|
-
joinTables?: TViewJoinSnapshot[];
|
|
302
|
-
/** @since 0.1.136 — view columns and their physical sources, sorted by `column`. */
|
|
303
|
-
columns?: TViewColumnSnapshot[];
|
|
304
|
-
filterHash?: string;
|
|
305
|
-
/** @since 0.1.128 — hash of the canonical `@db.view.having` predicate. */
|
|
306
|
-
havingHash?: string;
|
|
307
|
-
materialized?: boolean;
|
|
308
|
-
/**
|
|
309
|
-
* @since 0.1.137 — the adapter's `viewRenderRevision()`, present only when
|
|
310
|
-
* the adapter defines one (managed views only).
|
|
311
|
-
*/
|
|
312
|
-
renderRevision?: string;
|
|
313
|
-
fields: TFieldSnapshot[];
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Extracts a canonical, serializable snapshot from a readable's metadata.
|
|
317
|
-
* Sorted deterministically so the hash is stable across runs.
|
|
318
|
-
*
|
|
319
|
-
* @param readable - The table/view readable.
|
|
320
|
-
* @param typeMapper - Optional adapter-specific type mapper. When provided,
|
|
321
|
-
* each field's mapped type (e.g., "VARCHAR(255)") is stored in the snapshot
|
|
322
|
-
* for precise type change detection.
|
|
323
|
-
*/
|
|
324
|
-
declare function computeTableSnapshot(readable: AtscriptDbReadable, typeMapper?: (field: TDbFieldMeta) => string, tableOptions?: TExistingTableOption[]): TTableSnapshot;
|
|
325
|
-
/**
|
|
326
|
-
* Extracts a canonical, serializable snapshot from a view's metadata.
|
|
327
|
-
* Captures view plan (entry table, joins, filter, materialization) for
|
|
328
|
-
* detecting view definition changes.
|
|
329
|
-
*/
|
|
330
|
-
declare function computeViewSnapshot(view: AtscriptDbView): TViewSnapshot;
|
|
331
|
-
/** Canonical (table-qualified, fixed-key-order) form of a view predicate. */
|
|
332
|
-
type TCanonicalQueryNode = {
|
|
333
|
-
and: TCanonicalQueryNode[];
|
|
334
|
-
} | {
|
|
335
|
-
or: TCanonicalQueryNode[];
|
|
336
|
-
} | {
|
|
337
|
-
not: TCanonicalQueryNode;
|
|
338
|
-
} /** `r` is `{ f: "<table>.<field>" }` for a field-to-field comparison, else the literal. */ | {
|
|
339
|
-
l: string;
|
|
340
|
-
op: string;
|
|
341
|
-
r?: unknown;
|
|
342
|
-
};
|
|
343
|
-
/**
|
|
344
|
-
* Converts a view predicate (join condition, `@db.view.filter`,
|
|
345
|
-
* `@db.view.having`) into a serializable structure whose JSON is a stable
|
|
346
|
-
* function of its MEANING: field refs become `qualify(ref)` — the view's
|
|
347
|
-
* `resolveFieldRef(ref, (n) => n)`, i.e. `"<table>.<field>"`, so a predicate
|
|
348
|
-
* retargeted to another table with the same field name changes — operators
|
|
349
|
-
* and literal values are kept as-is, `$and`/`$or` keep declaration order, and
|
|
350
|
-
* no function references survive. Two identical models produce byte-identical
|
|
351
|
-
* JSON.
|
|
352
|
-
* @since 0.1.128
|
|
353
|
-
*/
|
|
354
|
-
declare function canonicalizeQueryNode(node: AtscriptQueryNode$1, qualify: (ref: AtscriptQueryFieldRef$1) => string): TCanonicalQueryNode;
|
|
355
|
-
/**
|
|
356
|
-
* Computes a deterministic hash string from multiple table snapshots.
|
|
357
|
-
* Uses FNV-1a for speed — not cryptographic, just needs stability + collision resistance.
|
|
358
|
-
*/
|
|
359
|
-
declare function computeSchemaHash(snapshots: Array<TTableSnapshot | TViewSnapshot>): string;
|
|
360
|
-
/**
|
|
361
|
-
* Computes a hash for a single table/view snapshot.
|
|
362
|
-
* Used for per-table change detection via stored snapshots.
|
|
363
|
-
*/
|
|
364
|
-
declare function computeTableHash(snapshot: TTableSnapshot | TViewSnapshot): string;
|
|
365
|
-
/**
|
|
366
|
-
* Converts stored snapshot fields to `TExistingColumn[]` format
|
|
367
|
-
* for use with `computeColumnDiff`. Used by adapters that lack
|
|
368
|
-
* native column introspection (e.g., MongoDB).
|
|
369
|
-
*
|
|
370
|
-
* The `type` field uses `mappedType` when available (adapter-specific),
|
|
371
|
-
* falling back to `designType`.
|
|
372
|
-
*/
|
|
373
|
-
declare function snapshotToExistingColumns(snapshot: TTableSnapshot): TExistingColumn[];
|
|
374
|
-
/**
|
|
375
|
-
* Extracts table options from a stored snapshot for diff comparison.
|
|
376
|
-
* Used as fallback when an adapter lacks native table option introspection.
|
|
377
|
-
*/
|
|
378
|
-
declare function snapshotToExistingTableOptions(snapshot: TTableSnapshot): TExistingTableOption[];
|
|
379
|
-
//#endregion
|
|
380
262
|
//#region src/schema/sync-store.d.ts
|
|
381
263
|
/**
|
|
382
264
|
* Reads a stored table snapshot from the control table.
|
|
@@ -465,10 +347,27 @@ declare class SchemaSync {
|
|
|
465
347
|
* Starts a periodic heartbeat that extends the lock's TTL while sync runs.
|
|
466
348
|
* Returns a handle with `stop()` to cancel and `getAbortReason()` to check
|
|
467
349
|
* whether the lock was stolen or unexpectedly removed.
|
|
350
|
+
*
|
|
351
|
+
* At most one refresh is in flight; `stop()` resolves once it has settled,
|
|
352
|
+
* so the lock is released only after the last refresh — a late refresh must
|
|
353
|
+
* never race the release (or the next holder's lock).
|
|
468
354
|
*/
|
|
469
355
|
private startHeartbeat;
|
|
356
|
+
/**
|
|
357
|
+
* Acquires the sync lock, waiting for a peer that holds it. Resolves
|
|
358
|
+
* `"acquired"`, or `"synced-by-peer"` when a non-forced run finds, after a
|
|
359
|
+
* wait, that the peer stored this schema's hash. A forced run never
|
|
360
|
+
* short-circuits — it waits its turn and runs. Losing the race for a freed
|
|
361
|
+
* lock to another waiter just waits again, within the same `waitTimeoutMs`.
|
|
362
|
+
*/
|
|
363
|
+
private acquireLock;
|
|
470
364
|
/** Throws if the heartbeat detected a stolen/missing lock. */
|
|
471
365
|
private assertLockHeld;
|
|
366
|
+
/**
|
|
367
|
+
* Releases the lock without masking the run's outcome: a failed release is
|
|
368
|
+
* logged (the row expires after `lockTtlMs`, blocking peers until then).
|
|
369
|
+
*/
|
|
370
|
+
private releaseLock;
|
|
472
371
|
/**
|
|
473
372
|
* Runs schema synchronization with distributed locking, in three phases:
|
|
474
373
|
*
|
|
@@ -477,12 +376,12 @@ declare class SchemaSync {
|
|
|
477
376
|
* 2. **Pre-flight** (pure): every change that no order of DDL can apply
|
|
478
377
|
* safely becomes a refusal. One refusal → `status: "refused"`, no DDL,
|
|
479
378
|
* nothing persisted, lock released.
|
|
480
|
-
* 3. **Execute** in dependency order:
|
|
481
|
-
*
|
|
482
|
-
* blocks a table's drop-and-recreate
|
|
483
|
-
* before it) → deferred FKs of cycles →
|
|
484
|
-
*
|
|
485
|
-
* snapshots/tracking/hash.
|
|
379
|
+
* 3. **Execute** in dependency order: removed views, then stale views
|
|
380
|
+
* (dependents first) → inbound FKs of key-changing tables → tables
|
|
381
|
+
* (parents first; a removed table that blocks a table's drop-and-recreate
|
|
382
|
+
* or key rebuild is dropped right before it) → deferred FKs of cycles →
|
|
383
|
+
* managed views (upstream views first) → external-view checks →
|
|
384
|
+
* remaining removed tables (children first) → snapshots/tracking/hash.
|
|
486
385
|
*/
|
|
487
386
|
run(types: readonly TAtscriptAnnotatedType[], opts?: TSyncOptions): Promise<TSyncResult>;
|
|
488
387
|
private discover;
|
|
@@ -661,4 +560,4 @@ declare function syncSchema(space: DbSpace, types: readonly TAtscriptAnnotatedTy
|
|
|
661
560
|
*/
|
|
662
561
|
declare function planSchema(space: DbSpace, types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
|
|
663
562
|
//#endregion
|
|
664
|
-
export { SchemaSync, SyncEntry, type TDbObjectKind, type TDependencyEdge, type TEnsureTableOptions, type TExistingForeignKey, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TPrimaryKeyChange, type TReferencingForeignKey, type TSyncColors, type TSyncEntryInit, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TSyncSkippedWork, type TTableSnapshot, type TViewColumnSnapshot, type TViewJoinSnapshot, type TViewSnapshot, canonicalizeQueryNode, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, planSchema, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema, topoOrder };
|
|
563
|
+
export { SchemaSync, SyncEntry, type TDbObjectKind, type TDependencyEdge, type TEnsureTableOptions, type TExistingForeignKey, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TPrimaryKeyChange, type TReferencingForeignKey, type TSyncColors, type TSyncDerivedChange, type TSyncEntryInit, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TSyncSkippedWork, type TTableSnapshot, type TViewColumnSnapshot, type TViewJoinSnapshot, type TViewSnapshot, canonicalizeQueryNode, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, planSchema, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema, topoOrder };
|