@atscript/db 0.1.163 → 0.1.165
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.cjs +1 -1
- package/dist/agg.d.cts +1 -1
- package/dist/agg.d.mts +1 -1
- package/dist/agg.mjs +1 -1
- package/dist/{aggregate-fns-DupYzFD7.cjs → aggregate-fns-CNtrSxGH.cjs} +1 -1
- package/dist/{aggregate-fns-DsS9UQVB.mjs → aggregate-fns-CmtSNIHm.mjs} +1 -1
- package/dist/{buckets-B8UOod-v.d.cts → buckets-BDxKfCNo.d.cts} +143 -13
- package/dist/{buckets-CHyspjYP.d.mts → buckets-CHUgky8T.d.mts} +143 -13
- package/dist/{column-diff-BfNIlMwX.mjs → column-diff-9pF0d8JP.mjs} +354 -31
- package/dist/{column-diff-BIGX3sRH.cjs → column-diff-DjeUj9kb.cjs} +371 -30
- package/dist/control-B5BJypqL.cjs +16 -0
- package/dist/control-CevYIJC4.mjs +16 -0
- package/dist/{db-error-hraC12B9.mjs → db-error-BMy4-OWq.mjs} +23 -1
- package/dist/{db-error-B_DRL1E9.d.cts → db-error-DQUw2cED.d.cts} +65 -9
- package/dist/{db-error-B_DRL1E9.d.mts → db-error-DQUw2cED.d.mts} +65 -9
- package/dist/{db-error-DmF1_xrz.cjs → db-error-G3sgvL87.cjs} +28 -0
- package/dist/{fk-diff-BNGawZi9.d.cts → fk-diff-DSM7O7hs.d.cts} +1 -1
- package/dist/{fk-diff-rj9N2QLw.d.mts → fk-diff-Dapr5Dk-.d.mts} +1 -1
- package/dist/index.cjs +17 -11
- package/dist/index.d.cts +38 -12
- package/dist/index.d.mts +38 -12
- package/dist/index.mjs +14 -12
- package/dist/{nested-writer-ClUX0DB0.mjs → nested-writer-BraWjS8a.mjs} +177 -26
- package/dist/{nested-writer-yCy6wGuN.cjs → nested-writer-DOvdbYG-.cjs} +194 -31
- package/dist/ops.cjs +1 -1
- package/dist/ops.mjs +1 -1
- package/dist/plugin.cjs +15 -12
- package/dist/plugin.mjs +15 -12
- 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-DloMywNs.d.cts → relation-helpers-C4UNWYQu.d.cts} +1 -1
- package/dist/{relation-helpers-zwt19E7r.d.mts → relation-helpers-hdbuqwjV.d.mts} +1 -1
- package/dist/{relation-loader-Qv3LrQ42.mjs → relation-loader-BOEVhcBe.mjs} +1 -1
- package/dist/{relation-loader-DujL_Mh9.cjs → relation-loader-BrkakVF_.cjs} +1 -1
- package/dist/shared.cjs +3 -1
- package/dist/shared.d.cts +13 -2
- package/dist/shared.d.mts +13 -2
- package/dist/shared.mjs +2 -2
- package/dist/sync.cjs +107 -25
- package/dist/sync.d.cts +53 -6
- package/dist/sync.d.mts +53 -6
- package/dist/sync.mjs +107 -25
- package/dist/{validator-DK9Ijpo7.cjs → validator-D7E7T0Oy.cjs} +1 -1
- package/dist/{validator-DuDWsIdQ.mjs → validator-UpgPhwvH.mjs} +1 -1
- package/dist/validator.cjs +2 -2
- package/dist/validator.d.cts +1 -1
- package/dist/validator.d.mts +1 -1
- package/dist/validator.mjs +2 -2
- package/dist/{view-validation-BiDLCYMw.cjs → view-validation-C0UVLx_H.cjs} +38 -10
- package/dist/{view-validation-BcgDq7M9.mjs → view-validation-KW77xIKn.mjs} +28 -12
- package/package.json +6 -6
- package/dist/control-D5cQmzFj.mjs +0 -14
- package/dist/control-jIVU2hkf.cjs +0 -14
package/dist/sync.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Ct as TEnsureTableOptions, Et as TExistingTableOption, G as TDbFieldMeta,
|
|
2
|
-
import { S as snapshotToExistingTableOptions, _ as computeSchemaHash, a as hasForeignKeyChanges, b as computeViewSnapshot, d as TForeignKeySnapshot, f as TTableSnapshot, g as canonicalizeQueryNode, h as TViewSnapshot, i as fkKey, l as sameDefaultValue, m as TViewJoinSnapshot, n as computeForeignKeyDiff, o as TColumnDiffOptions, p as TViewColumnSnapshot, s as computeColumnDiff, t as TForeignKeyDiff, u as TFieldSnapshot, v as computeTableHash, x as snapshotToExistingColumns, y as computeTableSnapshot } from "./fk-diff-
|
|
1
|
+
import { Bt as TPrimaryKeyChange, Ct as TEnsureTableOptions, Et as TExistingTableOption, G as TDbFieldMeta, Ht as TReferencingForeignKey, Jt as TTableOptionDiff, Pt as TIndexChange, Tt as TExistingForeignKey, at as TDbObjectKind, fr as TGenericLogger, xt as TDerivedChangeReason, yn as DbSpace } from "./buckets-BDxKfCNo.cjs";
|
|
2
|
+
import { S as snapshotToExistingTableOptions, _ as computeSchemaHash, a as hasForeignKeyChanges, b as computeViewSnapshot, d as TForeignKeySnapshot, f as TTableSnapshot, g as canonicalizeQueryNode, h as TViewSnapshot, i as fkKey, l as sameDefaultValue, m as TViewJoinSnapshot, n as computeForeignKeyDiff, o as TColumnDiffOptions, p as TViewColumnSnapshot, s as computeColumnDiff, t as TForeignKeyDiff, u as TFieldSnapshot, v as computeTableHash, x as snapshotToExistingColumns, y as computeTableSnapshot } from "./fk-diff-DSM7O7hs.cjs";
|
|
3
3
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/sync-entry.d.ts
|
|
@@ -329,6 +329,27 @@ interface TSyncPlan {
|
|
|
329
329
|
status: "up-to-date" | "changes-needed";
|
|
330
330
|
schemaHash: string;
|
|
331
331
|
entries: SyncEntry[];
|
|
332
|
+
/**
|
|
333
|
+
* Ids of the `dataSteps` passed to `planSchema` that have not run yet
|
|
334
|
+
* (since 0.1.165); a pending step makes the plan `"changes-needed"`.
|
|
335
|
+
* Absent when no steps were passed.
|
|
336
|
+
*/
|
|
337
|
+
pendingDataSteps?: string[];
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* A one-time data step of {@link TSyncOptions.dataSteps} (since 0.1.165) —
|
|
341
|
+
* a backfill or data fix that must run exactly once per database, after the
|
|
342
|
+
* schema change it needs.
|
|
343
|
+
*/
|
|
344
|
+
interface TDataStep {
|
|
345
|
+
/** Stable, unique id — the step is recorded under it (`data_step:<id>` in `__atscript_control`). */
|
|
346
|
+
id: string;
|
|
347
|
+
/**
|
|
348
|
+
* The step's work. Runs in its own transaction (on adapters with
|
|
349
|
+
* transactions), the record of the step committed in the same one: a step
|
|
350
|
+
* that throws is rolled back, not recorded, and runs again on the next sync.
|
|
351
|
+
*/
|
|
352
|
+
run(space: DbSpace): Promise<void> | void;
|
|
332
353
|
}
|
|
333
354
|
interface TSyncOptions {
|
|
334
355
|
/** Pod/instance identifier for distributed locking. Default: random UUID. */
|
|
@@ -365,6 +386,15 @@ interface TSyncOptions {
|
|
|
365
386
|
* - `"silent"` — legacy behavior: outcome is only observable on the result.
|
|
366
387
|
*/
|
|
367
388
|
onError?: "throw" | "warn" | "silent";
|
|
389
|
+
/**
|
|
390
|
+
* One-time data steps (since 0.1.165), run in order after the schema DDL,
|
|
391
|
+
* under the sync lock — also when the schema itself is up to date. Each
|
|
392
|
+
* step runs once per database: once it committed, its id is recorded and
|
|
393
|
+
* later syncs skip it. A step that throws stops the run (the error is
|
|
394
|
+
* rethrown after the lock is released); the steps after it stay pending.
|
|
395
|
+
* Steps do not run when the sync is refused or an entry errored.
|
|
396
|
+
*/
|
|
397
|
+
dataSteps?: readonly TDataStep[];
|
|
368
398
|
}
|
|
369
399
|
interface TSyncResult {
|
|
370
400
|
/**
|
|
@@ -379,6 +409,15 @@ interface TSyncResult {
|
|
|
379
409
|
status: "up-to-date" | "synced" | "synced-by-peer" | "refused";
|
|
380
410
|
schemaHash: string;
|
|
381
411
|
entries: SyncEntry[];
|
|
412
|
+
/**
|
|
413
|
+
* The {@link TSyncOptions.dataSteps} this call ran, and those still pending
|
|
414
|
+
* (a refused or errored run leaves them all pending). Absent when no steps
|
|
415
|
+
* were passed. @since 0.1.165
|
|
416
|
+
*/
|
|
417
|
+
dataSteps?: {
|
|
418
|
+
ran: string[];
|
|
419
|
+
pending: string[];
|
|
420
|
+
};
|
|
382
421
|
}
|
|
383
422
|
declare class SchemaSync {
|
|
384
423
|
private readonly space;
|
|
@@ -413,7 +452,8 @@ declare class SchemaSync {
|
|
|
413
452
|
/**
|
|
414
453
|
* Acquires the sync lock, waiting for a peer that holds it. Resolves
|
|
415
454
|
* `"acquired"`, or `"synced-by-peer"` when a non-forced run finds, after a
|
|
416
|
-
* wait, that the peer stored this schema's hash
|
|
455
|
+
* wait, that the peer stored this schema's hash (and `peerDone` agrees —
|
|
456
|
+
* no data step left pending). A forced run never
|
|
417
457
|
* short-circuits — it waits its turn and runs. Losing the race for a freed
|
|
418
458
|
* lock to another waiter just waits again, within the same `waitTimeoutMs`.
|
|
419
459
|
*/
|
|
@@ -425,6 +465,13 @@ declare class SchemaSync {
|
|
|
425
465
|
* logged (the row expires after `lockTtlMs`, blocking peers until then).
|
|
426
466
|
*/
|
|
427
467
|
private releaseLock;
|
|
468
|
+
/** Ids of the steps not recorded yet, in order. */
|
|
469
|
+
private pendingDataSteps;
|
|
470
|
+
/**
|
|
471
|
+
* Runs the pending steps in order, each with its record in one transaction.
|
|
472
|
+
* A throwing step propagates (rolled back, not recorded). Returns the ids run.
|
|
473
|
+
*/
|
|
474
|
+
private runDataSteps;
|
|
428
475
|
/**
|
|
429
476
|
* Runs schema synchronization with distributed locking, in three phases:
|
|
430
477
|
*
|
|
@@ -498,7 +545,7 @@ declare class SchemaSync {
|
|
|
498
545
|
* any DDL. Entries come back in execution order; pre-flight refusals appear
|
|
499
546
|
* as `error` entries (`refused: true`) exactly as `run()` would report them.
|
|
500
547
|
*/
|
|
501
|
-
plan(types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
|
|
548
|
+
plan(types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe" | "dataSteps">): Promise<TSyncPlan>;
|
|
502
549
|
/** Fallback typeMapper for snapshot-based Path B: compares designType directly, skips unions. */
|
|
503
550
|
private resolveTypeMapper;
|
|
504
551
|
/**
|
|
@@ -600,6 +647,6 @@ declare function syncSchema(space: DbSpace, types: readonly TAtscriptAnnotatedTy
|
|
|
600
647
|
* Note: reading the stored baseline still requires a live DB connection (the
|
|
601
648
|
* snapshot lives in the `__atscript_control` table).
|
|
602
649
|
*/
|
|
603
|
-
declare function planSchema(space: DbSpace, types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
|
|
650
|
+
declare function planSchema(space: DbSpace, types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe" | "dataSteps">): Promise<TSyncPlan>;
|
|
604
651
|
//#endregion
|
|
605
|
-
export { SchemaSync, SyncEntry, type TColumnDiffOptions, 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, sameDefaultValue, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema, topoOrder };
|
|
652
|
+
export { SchemaSync, SyncEntry, type TColumnDiffOptions, type TDataStep, 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, sameDefaultValue, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema, topoOrder };
|
package/dist/sync.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Ct as TEnsureTableOptions, Et as TExistingTableOption, G as TDbFieldMeta,
|
|
2
|
-
import { S as snapshotToExistingTableOptions, _ as computeSchemaHash, a as hasForeignKeyChanges, b as computeViewSnapshot, d as TForeignKeySnapshot, f as TTableSnapshot, g as canonicalizeQueryNode, h as TViewSnapshot, i as fkKey, l as sameDefaultValue, m as TViewJoinSnapshot, n as computeForeignKeyDiff, o as TColumnDiffOptions, p as TViewColumnSnapshot, s as computeColumnDiff, t as TForeignKeyDiff, u as TFieldSnapshot, v as computeTableHash, x as snapshotToExistingColumns, y as computeTableSnapshot } from "./fk-diff-
|
|
1
|
+
import { Bt as TPrimaryKeyChange, Ct as TEnsureTableOptions, Et as TExistingTableOption, G as TDbFieldMeta, Ht as TReferencingForeignKey, Jt as TTableOptionDiff, Pt as TIndexChange, Tt as TExistingForeignKey, at as TDbObjectKind, fr as TGenericLogger, xt as TDerivedChangeReason, yn as DbSpace } from "./buckets-CHUgky8T.mjs";
|
|
2
|
+
import { S as snapshotToExistingTableOptions, _ as computeSchemaHash, a as hasForeignKeyChanges, b as computeViewSnapshot, d as TForeignKeySnapshot, f as TTableSnapshot, g as canonicalizeQueryNode, h as TViewSnapshot, i as fkKey, l as sameDefaultValue, m as TViewJoinSnapshot, n as computeForeignKeyDiff, o as TColumnDiffOptions, p as TViewColumnSnapshot, s as computeColumnDiff, t as TForeignKeyDiff, u as TFieldSnapshot, v as computeTableHash, x as snapshotToExistingColumns, y as computeTableSnapshot } from "./fk-diff-Dapr5Dk-.mjs";
|
|
3
3
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/sync-entry.d.ts
|
|
@@ -329,6 +329,27 @@ interface TSyncPlan {
|
|
|
329
329
|
status: "up-to-date" | "changes-needed";
|
|
330
330
|
schemaHash: string;
|
|
331
331
|
entries: SyncEntry[];
|
|
332
|
+
/**
|
|
333
|
+
* Ids of the `dataSteps` passed to `planSchema` that have not run yet
|
|
334
|
+
* (since 0.1.165); a pending step makes the plan `"changes-needed"`.
|
|
335
|
+
* Absent when no steps were passed.
|
|
336
|
+
*/
|
|
337
|
+
pendingDataSteps?: string[];
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* A one-time data step of {@link TSyncOptions.dataSteps} (since 0.1.165) —
|
|
341
|
+
* a backfill or data fix that must run exactly once per database, after the
|
|
342
|
+
* schema change it needs.
|
|
343
|
+
*/
|
|
344
|
+
interface TDataStep {
|
|
345
|
+
/** Stable, unique id — the step is recorded under it (`data_step:<id>` in `__atscript_control`). */
|
|
346
|
+
id: string;
|
|
347
|
+
/**
|
|
348
|
+
* The step's work. Runs in its own transaction (on adapters with
|
|
349
|
+
* transactions), the record of the step committed in the same one: a step
|
|
350
|
+
* that throws is rolled back, not recorded, and runs again on the next sync.
|
|
351
|
+
*/
|
|
352
|
+
run(space: DbSpace): Promise<void> | void;
|
|
332
353
|
}
|
|
333
354
|
interface TSyncOptions {
|
|
334
355
|
/** Pod/instance identifier for distributed locking. Default: random UUID. */
|
|
@@ -365,6 +386,15 @@ interface TSyncOptions {
|
|
|
365
386
|
* - `"silent"` — legacy behavior: outcome is only observable on the result.
|
|
366
387
|
*/
|
|
367
388
|
onError?: "throw" | "warn" | "silent";
|
|
389
|
+
/**
|
|
390
|
+
* One-time data steps (since 0.1.165), run in order after the schema DDL,
|
|
391
|
+
* under the sync lock — also when the schema itself is up to date. Each
|
|
392
|
+
* step runs once per database: once it committed, its id is recorded and
|
|
393
|
+
* later syncs skip it. A step that throws stops the run (the error is
|
|
394
|
+
* rethrown after the lock is released); the steps after it stay pending.
|
|
395
|
+
* Steps do not run when the sync is refused or an entry errored.
|
|
396
|
+
*/
|
|
397
|
+
dataSteps?: readonly TDataStep[];
|
|
368
398
|
}
|
|
369
399
|
interface TSyncResult {
|
|
370
400
|
/**
|
|
@@ -379,6 +409,15 @@ interface TSyncResult {
|
|
|
379
409
|
status: "up-to-date" | "synced" | "synced-by-peer" | "refused";
|
|
380
410
|
schemaHash: string;
|
|
381
411
|
entries: SyncEntry[];
|
|
412
|
+
/**
|
|
413
|
+
* The {@link TSyncOptions.dataSteps} this call ran, and those still pending
|
|
414
|
+
* (a refused or errored run leaves them all pending). Absent when no steps
|
|
415
|
+
* were passed. @since 0.1.165
|
|
416
|
+
*/
|
|
417
|
+
dataSteps?: {
|
|
418
|
+
ran: string[];
|
|
419
|
+
pending: string[];
|
|
420
|
+
};
|
|
382
421
|
}
|
|
383
422
|
declare class SchemaSync {
|
|
384
423
|
private readonly space;
|
|
@@ -413,7 +452,8 @@ declare class SchemaSync {
|
|
|
413
452
|
/**
|
|
414
453
|
* Acquires the sync lock, waiting for a peer that holds it. Resolves
|
|
415
454
|
* `"acquired"`, or `"synced-by-peer"` when a non-forced run finds, after a
|
|
416
|
-
* wait, that the peer stored this schema's hash
|
|
455
|
+
* wait, that the peer stored this schema's hash (and `peerDone` agrees —
|
|
456
|
+
* no data step left pending). A forced run never
|
|
417
457
|
* short-circuits — it waits its turn and runs. Losing the race for a freed
|
|
418
458
|
* lock to another waiter just waits again, within the same `waitTimeoutMs`.
|
|
419
459
|
*/
|
|
@@ -425,6 +465,13 @@ declare class SchemaSync {
|
|
|
425
465
|
* logged (the row expires after `lockTtlMs`, blocking peers until then).
|
|
426
466
|
*/
|
|
427
467
|
private releaseLock;
|
|
468
|
+
/** Ids of the steps not recorded yet, in order. */
|
|
469
|
+
private pendingDataSteps;
|
|
470
|
+
/**
|
|
471
|
+
* Runs the pending steps in order, each with its record in one transaction.
|
|
472
|
+
* A throwing step propagates (rolled back, not recorded). Returns the ids run.
|
|
473
|
+
*/
|
|
474
|
+
private runDataSteps;
|
|
428
475
|
/**
|
|
429
476
|
* Runs schema synchronization with distributed locking, in three phases:
|
|
430
477
|
*
|
|
@@ -498,7 +545,7 @@ declare class SchemaSync {
|
|
|
498
545
|
* any DDL. Entries come back in execution order; pre-flight refusals appear
|
|
499
546
|
* as `error` entries (`refused: true`) exactly as `run()` would report them.
|
|
500
547
|
*/
|
|
501
|
-
plan(types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
|
|
548
|
+
plan(types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe" | "dataSteps">): Promise<TSyncPlan>;
|
|
502
549
|
/** Fallback typeMapper for snapshot-based Path B: compares designType directly, skips unions. */
|
|
503
550
|
private resolveTypeMapper;
|
|
504
551
|
/**
|
|
@@ -600,6 +647,6 @@ declare function syncSchema(space: DbSpace, types: readonly TAtscriptAnnotatedTy
|
|
|
600
647
|
* Note: reading the stored baseline still requires a live DB connection (the
|
|
601
648
|
* snapshot lives in the `__atscript_control` table).
|
|
602
649
|
*/
|
|
603
|
-
declare function planSchema(space: DbSpace, types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
|
|
650
|
+
declare function planSchema(space: DbSpace, types: readonly TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe" | "dataSteps">): Promise<TSyncPlan>;
|
|
604
651
|
//#endregion
|
|
605
|
-
export { SchemaSync, SyncEntry, type TColumnDiffOptions, 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, sameDefaultValue, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema, topoOrder };
|
|
652
|
+
export { SchemaSync, SyncEntry, type TColumnDiffOptions, type TDataStep, 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, sameDefaultValue, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema, topoOrder };
|
package/dist/sync.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import {
|
|
3
|
-
import { f as unionValueMembers } from "./validator-
|
|
1
|
+
import { A as fkKey, F as resolveDesignType, O as computeForeignKeyDiff, _t as relationalColumnName, a as computeSchemaHash, c as computeViewSnapshot, d as snapshotToExistingTableOptions, f as viewSnapshotSources, i as canonicalizeQueryNode, j as hasForeignKeyChanges, k as fkColumns, l as serializeDefaultValue, o as computeTableHash, r as sameDefaultValue, s as computeTableSnapshot, t as computeColumnDiff, u as snapshotToExistingColumns, vt as aliasTargetOf, wt as NoopLogger } from "./column-diff-9pF0d8JP.mjs";
|
|
2
|
+
import { r as DbError } from "./db-error-BMy4-OWq.mjs";
|
|
3
|
+
import { f as unionValueMembers } from "./validator-UpgPhwvH.mjs";
|
|
4
4
|
//#region src/schema/json-column-copy.ts
|
|
5
5
|
const NONE = {
|
|
6
6
|
copies: [],
|
|
@@ -322,11 +322,28 @@ var SyncStore = class {
|
|
|
322
322
|
}
|
|
323
323
|
async ensureControlTable() {
|
|
324
324
|
if (!this.controlTable) {
|
|
325
|
-
const { AtscriptControl } = await import("./control-
|
|
325
|
+
const { AtscriptControl } = await import("./control-CevYIJC4.mjs");
|
|
326
326
|
this.controlTable = this.space.getTable(AtscriptControl);
|
|
327
327
|
}
|
|
328
328
|
await this.controlTable.ensureTable();
|
|
329
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* Runs `fn` in a transaction of the control table's adapter family — the
|
|
332
|
+
* space's tables on the same driver join it (since 0.1.165, data steps).
|
|
333
|
+
*/
|
|
334
|
+
async inTransaction(fn) {
|
|
335
|
+
const { AtscriptControl } = await import("./control-CevYIJC4.mjs");
|
|
336
|
+
return this.space.getAdapter(AtscriptControl).withTransaction(fn);
|
|
337
|
+
}
|
|
338
|
+
/** Which of `ids` have a control row — one query (since 0.1.165, data steps). */
|
|
339
|
+
async presentControlIds(ids) {
|
|
340
|
+
if (ids.length === 0) return /* @__PURE__ */ new Set();
|
|
341
|
+
const rows = await this.controlTable.findMany({
|
|
342
|
+
filter: { _id: { $in: [...ids] } },
|
|
343
|
+
controls: { $select: ["_id"] }
|
|
344
|
+
});
|
|
345
|
+
return new Set(rows.map((r) => r._id));
|
|
346
|
+
}
|
|
330
347
|
async readControlValue(_id) {
|
|
331
348
|
return (await this.controlTable.findOne({
|
|
332
349
|
filter: { _id: { $eq: _id } },
|
|
@@ -494,7 +511,7 @@ function isExpired(lock, now) {
|
|
|
494
511
|
return expiresAt > 0 && expiresAt < now;
|
|
495
512
|
}
|
|
496
513
|
async function readStoredSnapshot(space, tableName, _asView) {
|
|
497
|
-
const { AtscriptControl } = await import("./control-
|
|
514
|
+
const { AtscriptControl } = await import("./control-CevYIJC4.mjs");
|
|
498
515
|
const table = space.getTable(AtscriptControl);
|
|
499
516
|
await table.ensureTable();
|
|
500
517
|
const value = (await table.findOne({
|
|
@@ -1570,6 +1587,33 @@ function removedBlockers(t, removedTables, removedTableSet, dropEdges) {
|
|
|
1570
1587
|
} else for (const r of removedTables) if (r.snapshot && "foreignKeys" in r.snapshot && r.snapshot.foreignKeys.some((fk) => fk.targetTable === t.dbName)) direct.push(r.name);
|
|
1571
1588
|
return reachable(direct, dropEdges);
|
|
1572
1589
|
}
|
|
1590
|
+
/** The `__atscript_control` key a data step is recorded under. */
|
|
1591
|
+
function dataStepKey(id) {
|
|
1592
|
+
return `data_step:${id}`;
|
|
1593
|
+
}
|
|
1594
|
+
/** The steps as given, after checking their ids are non-empty and unique. */
|
|
1595
|
+
function checkDataSteps(steps) {
|
|
1596
|
+
if (!steps?.length) return [];
|
|
1597
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1598
|
+
for (const step of steps) {
|
|
1599
|
+
if (typeof step.id !== "string" || step.id === "") throw new Error("syncSchema: every data step needs a non-empty id");
|
|
1600
|
+
if (seen.has(step.id)) throw new Error(`syncSchema: duplicate data step id "${step.id}"`);
|
|
1601
|
+
seen.add(step.id);
|
|
1602
|
+
}
|
|
1603
|
+
return steps;
|
|
1604
|
+
}
|
|
1605
|
+
/** `result` with its `dataSteps` report — unchanged when no steps were passed. */
|
|
1606
|
+
function withSteps(result, steps, ran) {
|
|
1607
|
+
if (steps.length === 0) return result;
|
|
1608
|
+
const done = new Set(ran);
|
|
1609
|
+
return {
|
|
1610
|
+
...result,
|
|
1611
|
+
dataSteps: {
|
|
1612
|
+
ran: [...ran],
|
|
1613
|
+
pending: steps.map((s) => s.id).filter((id) => !done.has(id))
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1573
1617
|
var SchemaSync = class {
|
|
1574
1618
|
space;
|
|
1575
1619
|
store;
|
|
@@ -1587,7 +1631,7 @@ var SchemaSync = class {
|
|
|
1587
1631
|
const tables = [];
|
|
1588
1632
|
const views = [];
|
|
1589
1633
|
const externalViews = [];
|
|
1590
|
-
for (const type of types) {
|
|
1634
|
+
for (const type of new Set(types)) {
|
|
1591
1635
|
if (aliasTargetOf(type)) continue;
|
|
1592
1636
|
const readable = this.space.get(type);
|
|
1593
1637
|
if (readable.isView) {
|
|
@@ -1715,7 +1759,8 @@ var SchemaSync = class {
|
|
|
1715
1759
|
/**
|
|
1716
1760
|
* Acquires the sync lock, waiting for a peer that holds it. Resolves
|
|
1717
1761
|
* `"acquired"`, or `"synced-by-peer"` when a non-forced run finds, after a
|
|
1718
|
-
* wait, that the peer stored this schema's hash
|
|
1762
|
+
* wait, that the peer stored this schema's hash (and `peerDone` agrees —
|
|
1763
|
+
* no data step left pending). A forced run never
|
|
1719
1764
|
* short-circuits — it waits its turn and runs. Losing the race for a freed
|
|
1720
1765
|
* lock to another waiter just waits again, within the same `waitTimeoutMs`.
|
|
1721
1766
|
*/
|
|
@@ -1723,7 +1768,7 @@ var SchemaSync = class {
|
|
|
1723
1768
|
const deadline = Date.now() + opts.waitTimeoutMs;
|
|
1724
1769
|
while (!await this.store.tryAcquireLock(podId, opts.lockTtlMs)) {
|
|
1725
1770
|
if (!await this.store.waitForLock(deadline - Date.now(), opts.pollIntervalMs)) throw new Error(`Schema sync lock wait timed out after ${opts.waitTimeoutMs}ms`);
|
|
1726
|
-
if (!opts.force && await this.store.readHash() === hash) return "synced-by-peer";
|
|
1771
|
+
if (!opts.force && await this.store.readHash() === hash && (!opts.peerDone || await opts.peerDone())) return "synced-by-peer";
|
|
1727
1772
|
}
|
|
1728
1773
|
return "acquired";
|
|
1729
1774
|
}
|
|
@@ -1743,6 +1788,30 @@ var SchemaSync = class {
|
|
|
1743
1788
|
this.logger.warn("[schema-sync] Failed to release the sync lock — peers wait until it expires:", error instanceof Error ? error.message : error);
|
|
1744
1789
|
}
|
|
1745
1790
|
}
|
|
1791
|
+
/** Ids of the steps not recorded yet, in order. */
|
|
1792
|
+
async pendingDataSteps(steps) {
|
|
1793
|
+
const done = await this.store.presentControlIds(steps.map((step) => dataStepKey(step.id)));
|
|
1794
|
+
return steps.filter((step) => !done.has(dataStepKey(step.id))).map((step) => step.id);
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* Runs the pending steps in order, each with its record in one transaction.
|
|
1798
|
+
* A throwing step propagates (rolled back, not recorded). Returns the ids run.
|
|
1799
|
+
*/
|
|
1800
|
+
async runDataSteps(steps, getAbortReason) {
|
|
1801
|
+
const ran = [];
|
|
1802
|
+
const pending = new Set(await this.pendingDataSteps(steps));
|
|
1803
|
+
for (const step of steps) {
|
|
1804
|
+
if (!pending.has(step.id)) continue;
|
|
1805
|
+
this.assertLockHeld(getAbortReason);
|
|
1806
|
+
await this.store.inTransaction(async () => {
|
|
1807
|
+
await step.run(this.space);
|
|
1808
|
+
await this.store.writeControlValue(dataStepKey(step.id), JSON.stringify({ ranAt: Date.now() }));
|
|
1809
|
+
});
|
|
1810
|
+
this.logger.info?.(`[schema-sync] data step "${step.id}" applied`);
|
|
1811
|
+
ran.push(step.id);
|
|
1812
|
+
}
|
|
1813
|
+
return ran;
|
|
1814
|
+
}
|
|
1746
1815
|
/**
|
|
1747
1816
|
* Runs schema synchronization with distributed locking, in three phases:
|
|
1748
1817
|
*
|
|
@@ -1767,21 +1836,25 @@ var SchemaSync = class {
|
|
|
1767
1836
|
const force = opts?.force ?? false;
|
|
1768
1837
|
const safe = opts?.safe ?? false;
|
|
1769
1838
|
const onError = opts?.onError ?? "warn";
|
|
1839
|
+
const steps = checkDataSteps(opts?.dataSteps);
|
|
1770
1840
|
const resolved = await this.resolveAndHash(types);
|
|
1771
1841
|
const { hash } = resolved;
|
|
1772
1842
|
await this.store.ensureControlTable();
|
|
1773
1843
|
if (!force) {
|
|
1774
|
-
if (await this.store.readHash() === hash)
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1844
|
+
if (await this.store.readHash() === hash) {
|
|
1845
|
+
if ((await this.pendingDataSteps(steps)).length === 0) return withSteps({
|
|
1846
|
+
status: "up-to-date",
|
|
1847
|
+
schemaHash: hash,
|
|
1848
|
+
entries: []
|
|
1849
|
+
}, steps, []);
|
|
1850
|
+
}
|
|
1779
1851
|
}
|
|
1780
1852
|
if (await this.acquireLock(podId, hash, {
|
|
1781
1853
|
lockTtlMs,
|
|
1782
1854
|
waitTimeoutMs,
|
|
1783
1855
|
pollIntervalMs,
|
|
1784
|
-
force
|
|
1856
|
+
force,
|
|
1857
|
+
peerDone: async () => (await this.pendingDataSteps(steps)).length === 0
|
|
1785
1858
|
}) === "synced-by-peer") return {
|
|
1786
1859
|
status: "synced-by-peer",
|
|
1787
1860
|
schemaHash: hash,
|
|
@@ -1790,11 +1863,14 @@ var SchemaSync = class {
|
|
|
1790
1863
|
const heartbeat = this.startHeartbeat(podId, lockTtlMs);
|
|
1791
1864
|
try {
|
|
1792
1865
|
if (!force) {
|
|
1793
|
-
if (await this.store.readHash() === hash)
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1866
|
+
if (await this.store.readHash() === hash) {
|
|
1867
|
+
const ran = await this.runDataSteps(steps, heartbeat.getAbortReason);
|
|
1868
|
+
return withSteps({
|
|
1869
|
+
status: ran.length > 0 ? "synced" : "synced-by-peer",
|
|
1870
|
+
schemaHash: hash,
|
|
1871
|
+
entries: []
|
|
1872
|
+
}, steps, ran);
|
|
1873
|
+
}
|
|
1798
1874
|
}
|
|
1799
1875
|
const d = await this.discover(resolved, safe);
|
|
1800
1876
|
this.assertLockHeld(heartbeat.getAbortReason);
|
|
@@ -1807,11 +1883,11 @@ var SchemaSync = class {
|
|
|
1807
1883
|
entries: this.buildPlanEntries(d, safe, refusals)
|
|
1808
1884
|
};
|
|
1809
1885
|
this.reportOutcome(result, onError);
|
|
1810
|
-
return result;
|
|
1886
|
+
return withSteps(result, steps, []);
|
|
1811
1887
|
}
|
|
1812
1888
|
const result = await this.execute(d, safe, heartbeat.getAbortReason);
|
|
1813
1889
|
this.reportOutcome(result, onError);
|
|
1814
|
-
return result;
|
|
1890
|
+
return withSteps(result, steps, result.entries.some((e) => e.status === "error") ? [] : await this.runDataSteps(steps, heartbeat.getAbortReason));
|
|
1815
1891
|
} finally {
|
|
1816
1892
|
await heartbeat.stop();
|
|
1817
1893
|
await this.releaseLock(podId);
|
|
@@ -2436,6 +2512,7 @@ var SchemaSync = class {
|
|
|
2436
2512
|
* as `error` entries (`refused: true`) exactly as `run()` would report them.
|
|
2437
2513
|
*/
|
|
2438
2514
|
async plan(types, opts) {
|
|
2515
|
+
const steps = checkDataSteps(opts?.dataSteps);
|
|
2439
2516
|
const force = opts?.force ?? false;
|
|
2440
2517
|
const safe = opts?.safe ?? false;
|
|
2441
2518
|
const resolved = await this.resolveAndHash(types);
|
|
@@ -2445,18 +2522,23 @@ var SchemaSync = class {
|
|
|
2445
2522
|
const refusals = this.preflight(d, safe);
|
|
2446
2523
|
await this.planLiveWork(d, safe);
|
|
2447
2524
|
const entries = this.buildPlanEntries(d, safe, refusals);
|
|
2525
|
+
const pending = steps.length > 0 ? await this.pendingDataSteps(steps) : void 0;
|
|
2526
|
+
const withPending = (plan) => pending ? {
|
|
2527
|
+
...plan,
|
|
2528
|
+
pendingDataSteps: pending
|
|
2529
|
+
} : plan;
|
|
2448
2530
|
if (!force) {
|
|
2449
|
-
if (await this.store.readHash() === hash) return {
|
|
2531
|
+
if (await this.store.readHash() === hash && !pending?.length) return withPending({
|
|
2450
2532
|
status: "up-to-date",
|
|
2451
2533
|
schemaHash: hash,
|
|
2452
2534
|
entries
|
|
2453
|
-
};
|
|
2535
|
+
});
|
|
2454
2536
|
}
|
|
2455
|
-
return {
|
|
2537
|
+
return withPending({
|
|
2456
2538
|
status: "changes-needed",
|
|
2457
2539
|
schemaHash: hash,
|
|
2458
2540
|
entries
|
|
2459
|
-
};
|
|
2541
|
+
});
|
|
2460
2542
|
}
|
|
2461
2543
|
/** Fallback typeMapper for snapshot-based Path B: compares designType directly, skips unions. */
|
|
2462
2544
|
resolveTypeMapper(adapter) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_db_error = require("./db-error-
|
|
1
|
+
const require_db_error = require("./db-error-G3sgvL87.cjs");
|
|
2
2
|
const require_ops = require("./ops.cjs");
|
|
3
3
|
let _atscript_typescript_utils = require("@atscript/typescript/utils");
|
|
4
4
|
//#region src/shared/union-shape.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as DepthLimitExceededError } from "./db-error-
|
|
1
|
+
import { i as DepthLimitExceededError } from "./db-error-BMy4-OWq.mjs";
|
|
2
2
|
import { getDbFieldOp } from "./ops.mjs";
|
|
3
3
|
import { createAnnotatedTypeNode, flattenAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
//#region src/shared/union-shape.ts
|
package/dist/validator.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_db_error = require("./db-error-
|
|
3
|
-
const require_validator = require("./validator-
|
|
2
|
+
const require_db_error = require("./db-error-G3sgvL87.cjs");
|
|
3
|
+
const require_validator = require("./validator-D7E7T0Oy.cjs");
|
|
4
4
|
const require_server_stamped = require("./server-stamped-B6XbUQ4p.cjs");
|
|
5
5
|
const require_object = require("./object-GjsuPNqo.cjs");
|
|
6
6
|
const require_ops = require("./ops.cjs");
|
package/dist/validator.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as DbError } from "./db-error-
|
|
1
|
+
import { r as DbError } from "./db-error-DQUw2cED.cjs";
|
|
2
2
|
import { a as $mul, c as $update, d as TDbFieldOp, g as separateCas, h as reconcileCas, i as $insert, l as $upsert, m as isDbFieldOp, n as $dec, o as $remove, r as $inc, s as $replace, t as $cas, u as TDbCas } from "./ops-AqhV7s9o.cjs";
|
|
3
3
|
import { a as isPlainObject, i as isEmptyObject } from "./object-Czia_qD4.cjs";
|
|
4
4
|
import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-wRqMYNBI.cjs";
|
package/dist/validator.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as DbError } from "./db-error-
|
|
1
|
+
import { r as DbError } from "./db-error-DQUw2cED.mjs";
|
|
2
2
|
import { a as $mul, c as $update, d as TDbFieldOp, g as separateCas, h as reconcileCas, i as $insert, l as $upsert, m as isDbFieldOp, n as $dec, o as $remove, r as $inc, s as $replace, t as $cas, u as TDbCas } from "./ops-AqhV7s9o.mjs";
|
|
3
3
|
import { a as isPlainObject, i as isEmptyObject } from "./object-Czia_qD4.mjs";
|
|
4
4
|
import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-wRqMYNBI.mjs";
|
package/dist/validator.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as DbError } from "./db-error-
|
|
2
|
-
import { a as forceNavNonOptional, c as getKeyProps, i as dbPlugin, n as buildPatchPartial, o as isNavRelation, r as buildValidationContext, s as createDbValidatorPlugin, t as buildDbValidator } from "./validator-
|
|
1
|
+
import { r as DbError } from "./db-error-BMy4-OWq.mjs";
|
|
2
|
+
import { a as forceNavNonOptional, c as getKeyProps, i as dbPlugin, n as buildPatchPartial, o as isNavRelation, r as buildValidationContext, s as createDbValidatorPlugin, t as buildDbValidator } from "./validator-UpgPhwvH.mjs";
|
|
3
3
|
import { n as isServerStampedOnUpdate, t as SERVER_STAMPED_ON_UPDATE_KEYS } from "./server-stamped-BoP56K9M.mjs";
|
|
4
4
|
import { a as isPlainObject, i as isEmptyObject } from "./object-PQ1J8jri.mjs";
|
|
5
5
|
import { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, isDbFieldOp, reconcileCas, separateCas } from "./ops.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_aggregate_fns = require("./aggregate-fns-
|
|
1
|
+
const require_aggregate_fns = require("./aggregate-fns-CNtrSxGH.cjs");
|
|
2
2
|
const require_search_fields = require("./search-fields-B49-RCWd.cjs");
|
|
3
3
|
let _atscript_core = require("@atscript/core");
|
|
4
4
|
//#region src/shared/annotation-utils.ts
|
|
@@ -62,17 +62,21 @@ function primitiveBaseType(def) {
|
|
|
62
62
|
return typeof ct === "object" ? ct.kind === "final" ? ct.value : ct.kind : ct;
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
+
* `null` in a type expression: the `null` reference or the `null` primitive
|
|
66
|
+
* (whose `config.type` is `"null"`).
|
|
67
|
+
*/
|
|
68
|
+
function isNullMember(node) {
|
|
69
|
+
return (0, _atscript_core.isRef)(node) && !node.hasChain && node.id === "null" || primitiveBaseType(node) === "null";
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
65
72
|
* Whether a definition is a union with a `null` member — `T | null`, or a
|
|
66
73
|
* ref to an alias of one (compile-time mirror of the runtime nullable union,
|
|
67
74
|
* since 0.1.155).
|
|
68
75
|
*/
|
|
69
76
|
function isNullableUnion(def, doc, depth = 0) {
|
|
70
77
|
if (!def || depth > 8) return false;
|
|
71
|
-
if ((
|
|
72
|
-
|
|
73
|
-
return isNullableUnion(doc.unwindType(def.id, def.chain)?.def, doc, depth + 1);
|
|
74
|
-
}
|
|
75
|
-
if (primitiveBaseType(def) === "null") return true;
|
|
78
|
+
if (isNullMember(def)) return true;
|
|
79
|
+
if ((0, _atscript_core.isRef)(def)) return isNullableUnion(doc.unwindType(def.id, def.chain)?.def, doc, depth + 1);
|
|
76
80
|
const group = def;
|
|
77
81
|
if (!group.isGroup || group.op !== "|" || (0, _atscript_core.isStructure)(def)) return false;
|
|
78
82
|
return group.unwrap().some((member) => isNullableUnion(member, doc, depth + 1));
|
|
@@ -369,6 +373,20 @@ function findViewCycle(owner, doc) {
|
|
|
369
373
|
return walk(owner, doc, [start]);
|
|
370
374
|
}
|
|
371
375
|
/**
|
|
376
|
+
* The chain reference (`User.id`) an `@db.rel.FK` field's type names, else
|
|
377
|
+
* `undefined`. `User.id | null` names it too (since 0.1.165) — the same
|
|
378
|
+
* optional foreign key as `field?: User.id`; any other union does not.
|
|
379
|
+
*/
|
|
380
|
+
function fkChainRef(def) {
|
|
381
|
+
if (def && (0, _atscript_core.isRef)(def)) return def.hasChain ? def : void 0;
|
|
382
|
+
if (!def || !(0, _atscript_core.isGroup)(def) || def.op !== "|") return void 0;
|
|
383
|
+
const members = def.unwrap();
|
|
384
|
+
const values = members.filter((m) => !isNullMember(m));
|
|
385
|
+
if (values.length !== 1 || values.length === members.length) return void 0;
|
|
386
|
+
const [only] = values;
|
|
387
|
+
return only && (0, _atscript_core.isRef)(only) && only.hasChain ? only : void 0;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
372
390
|
* Find all `@db.rel.FK` fields on a type that reference `targetTypeName`.
|
|
373
391
|
* Resolves `extends` to include inherited fields.
|
|
374
392
|
*/
|
|
@@ -383,10 +401,8 @@ function findFKFieldsPointingTo(doc, iface, targetTypeName, alias) {
|
|
|
383
401
|
if (!struct) return results;
|
|
384
402
|
for (const [name, prop] of struct.props) {
|
|
385
403
|
if (prop.countAnnotations("db.rel.FK") === 0) continue;
|
|
386
|
-
const
|
|
387
|
-
if (!
|
|
388
|
-
const ref = def;
|
|
389
|
-
if (!ref.hasChain) continue;
|
|
404
|
+
const ref = fkChainRef(prop.getDefinition());
|
|
405
|
+
if (!ref) continue;
|
|
390
406
|
const refTypeName = ref.id;
|
|
391
407
|
const refField = ref.chain.map((c) => c.text).join(".");
|
|
392
408
|
if (refTypeName !== targetTypeName) continue;
|
|
@@ -866,6 +882,12 @@ Object.defineProperty(exports, "findViewCycle", {
|
|
|
866
882
|
return findViewCycle;
|
|
867
883
|
}
|
|
868
884
|
});
|
|
885
|
+
Object.defineProperty(exports, "fkChainRef", {
|
|
886
|
+
enumerable: true,
|
|
887
|
+
get: function() {
|
|
888
|
+
return fkChainRef;
|
|
889
|
+
}
|
|
890
|
+
});
|
|
869
891
|
Object.defineProperty(exports, "forEachFieldRef", {
|
|
870
892
|
enumerable: true,
|
|
871
893
|
get: function() {
|
|
@@ -932,6 +954,12 @@ Object.defineProperty(exports, "isNavProp", {
|
|
|
932
954
|
return isNavProp;
|
|
933
955
|
}
|
|
934
956
|
});
|
|
957
|
+
Object.defineProperty(exports, "isNullMember", {
|
|
958
|
+
enumerable: true,
|
|
959
|
+
get: function() {
|
|
960
|
+
return isNullMember;
|
|
961
|
+
}
|
|
962
|
+
});
|
|
935
963
|
Object.defineProperty(exports, "isNullableUnion", {
|
|
936
964
|
enumerable: true,
|
|
937
965
|
get: function() {
|