@atscript/db 0.1.127 → 0.1.128

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 (33) hide show
  1. package/dist/{db-readable-BkAGccv9.d.mts → db-readable-BTl4NzNN.d.mts} +289 -16
  2. package/dist/{db-readable-C0nDKX8A.d.cts → db-readable-CkbZn_z-.d.cts} +289 -16
  3. package/dist/{db-space-B_ASuDaR.d.mts → db-space-BEB5Jl8M.d.mts} +81 -29
  4. package/dist/{db-space-CSntT6yS.d.cts → db-space-BevOyVrC.d.cts} +81 -29
  5. package/dist/{db-view-BP0Qbeux.cjs → db-view-C8-MsjND.cjs} +696 -97
  6. package/dist/{db-view-C8rZM5_N.mjs → db-view-Ck0I-PMI.mjs} +643 -98
  7. package/dist/index.cjs +46 -2
  8. package/dist/index.d.cts +162 -37
  9. package/dist/index.d.mts +162 -37
  10. package/dist/index.mjs +36 -4
  11. package/dist/{ops-DJRnNTVo.d.cts → ops-AqhV7s9o.d.cts} +24 -1
  12. package/dist/{ops-DJRnNTVo.d.mts → ops-AqhV7s9o.d.mts} +24 -1
  13. package/dist/ops.cjs +43 -0
  14. package/dist/ops.d.cts +2 -2
  15. package/dist/ops.d.mts +2 -2
  16. package/dist/ops.mjs +43 -1
  17. package/dist/plugin.cjs +12 -5
  18. package/dist/plugin.mjs +12 -5
  19. package/dist/rel.d.cts +1 -1
  20. package/dist/rel.d.mts +1 -1
  21. package/dist/sync.cjs +1096 -361
  22. package/dist/sync.d.cts +234 -15
  23. package/dist/sync.d.mts +234 -15
  24. package/dist/sync.mjs +1095 -362
  25. package/dist/{validator-CSGug4vg.cjs → validator-BNUHCXIE.cjs} +31 -2
  26. package/dist/{validator-BcBtg8yW.d.cts → validator-DuAmWc8L.d.cts} +38 -1
  27. package/dist/{validator-BcBtg8yW.d.mts → validator-DuAmWc8L.d.mts} +38 -1
  28. package/dist/{validator-0vRXN51D.mjs → validator-eKYWf3xf.mjs} +20 -3
  29. package/dist/validator.cjs +7 -1
  30. package/dist/validator.d.cts +3 -3
  31. package/dist/validator.d.mts +3 -3
  32. package/dist/validator.mjs +4 -3
  33. package/package.json +8 -8
@@ -1,4 +1,4 @@
1
- import { f as TFieldOps } from "./ops-DJRnNTVo.mjs";
1
+ import { f as TFieldOps } from "./ops-AqhV7s9o.mjs";
2
2
  import { FlatOf, FlatOf as FlatOf$1, NavPropsOf, NavPropsOf as NavPropsOf$1, OwnPropsOf, OwnPropsOf as OwnPropsOf$1, PrimaryKeyOf, PrimaryKeyOf as PrimaryKeyOf$1, TAtscriptAnnotatedType, TAtscriptDataType, TAtscriptTypeObject, TMetadataMap, TSerializedAnnotatedType, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
3
3
  import { AggregateControls, AggregateExpr, AggregateExpr as AggregateExpr$1, AggregateFn, AggregateQuery, AggregateQuery as AggregateQuery$1, AggregateResult, FieldOpsFor, FilterExpr, FilterExpr as FilterExpr$1, TypedWithRelation, Uniquery, Uniquery as Uniquery$1, UniqueryControls, UniqueryControls as UniqueryControls$1, UniqueryInsights, WithRelation, WithRelation as WithRelation$1 } from "@uniqu/core";
4
4
 
@@ -55,6 +55,12 @@ interface TGenericLogger {
55
55
  declare const NoopLogger: TGenericLogger;
56
56
  //#endregion
57
57
  //#region src/table/table-metadata.d.ts
58
+ /**
59
+ * Finds the nearest ancestor of `path` that belongs to `set`.
60
+ * Used by both the build pipeline (in `_classifyFields`) and
61
+ * runtime reconstruction on the Readable.
62
+ */
63
+ declare function findAncestorInSet(path: string, set: ReadonlySet<string>): string | undefined;
58
64
  /** Returns true if the annotated type IS the `db.geoPoint` primitive (tag-based). */
59
65
  declare function isGeoPointType(fieldType: TAtscriptAnnotatedType): boolean;
60
66
  /**
@@ -118,6 +124,22 @@ declare class TableMetadata {
118
124
  leafByPhysical: Map<string, TDbFieldMeta>;
119
125
  /** Leaf field descriptors indexed by logical path (write/patch/filter paths). */
120
126
  leafByLogical: Map<string, TDbFieldMeta>;
127
+ /**
128
+ * Non-ignored field descriptors keyed by logical path, excluding navigation
129
+ * relations and their descendants. Unlike `leafByLogical` (relational
130
+ * adapters only) this is built for every adapter, so the core path guard
131
+ * (`guardPaths`) can answer "does this path have physical storage here?"
132
+ * on nested-object adapters too.
133
+ */
134
+ descriptorByPath: Map<string, TDbFieldMeta>;
135
+ /**
136
+ * Logical paths stored as a single JSON column (`storage === 'json'`,
137
+ * non-ignored descriptors). Retained after build — unlike the build-time
138
+ * `jsonFields` set — so the path guard can classify JSON descendants on
139
+ * relational adapters. Empty on nested-object adapters (they keep native
140
+ * dotted paths as descriptors).
141
+ */
142
+ jsonParents: ReadonlySet<string>;
121
143
  private _built;
122
144
  private _identifications?;
123
145
  private _collateMap;
@@ -166,6 +188,14 @@ declare class TableMetadata {
166
188
  private _classifyFields;
167
189
  /** Returns the `__`-separated parent prefix for a dot-separated path, or empty string for top-level paths. */
168
190
  private _flattenedPrefix;
191
+ /** Nearest `@db.encrypted` ancestor of `path` (exclusive), or `undefined`. */
192
+ /**
193
+ * Indexes non-ignored descriptors by logical path and retains the JSON-parent
194
+ * set. Navigation relations and their descendants are skipped even when the
195
+ * adapter keeps them as descriptors (nested-object adapters do) — they are
196
+ * loaded with `$with`, never addressed as columns of this table.
197
+ */
198
+ private _buildGuardIndexes;
169
199
  /**
170
200
  * Indexes `fieldDescriptors` into two lookup maps for unified
171
201
  * read/write field classification in the RelationalFieldMapper.
@@ -244,6 +274,13 @@ interface TFieldMeta {
244
274
  * present in read responses. UIs render it as a set-only input.
245
275
  */
246
276
  writeOnly?: boolean;
277
+ /**
278
+ * Present (true) when the field is index-backed (explicit `@db.index*`,
279
+ * primary key or unique field). Advisory only — a hint for UIs that want to
280
+ * steer users toward cheap sort keys; it never affects whether a `$sort`
281
+ * is accepted (`sortable` does). Since 0.1.128.
282
+ */
283
+ indexed?: boolean;
247
284
  }
248
285
  /** Built-in CRUD operation names; map 1:1 to public method names. */
249
286
  type TCrudOp = "query" | "pages" | "one" | "geo" | "insert" | "update" | "replace" | "remove";
@@ -543,6 +580,57 @@ interface TColumnDiff {
543
580
  oldName: string;
544
581
  conflictsWith: string;
545
582
  }>;
583
+ /**
584
+ * The primary-key FIELD SET differs between the live table and the model
585
+ * (set semantics — a composite-key reorder is not a change, consistent with
586
+ * the schema hash). Column names are physical; a renamed PK column is
587
+ * compared under its new name. Only reported when the table exists.
588
+ * @since 0.1.128
589
+ */
590
+ primaryKeyChanged?: TPrimaryKeyChange;
591
+ }
592
+ /** Old and new primary-key column sets of a table whose key definition moved. */
593
+ interface TPrimaryKeyChange {
594
+ /** Physical PK columns currently in the database (after rename mapping). */
595
+ from: string[];
596
+ /** Physical PK columns the model declares. */
597
+ to: string[];
598
+ }
599
+ /**
600
+ * A live foreign-key constraint as introspected from the database
601
+ * (outbound: declared on the table that owns it).
602
+ */
603
+ interface TExistingForeignKey {
604
+ /** Local (referencing) columns, in constraint order. */
605
+ fields: string[];
606
+ /** Referenced table name. */
607
+ targetTable: string;
608
+ /** Referenced columns, in constraint order. */
609
+ targetFields: string[];
610
+ }
611
+ /**
612
+ * A live foreign key that REFERENCES a given table (inbound edge), as returned
613
+ * by `BaseDbAdapter.getReferencingForeignKeys(tableName)`.
614
+ */
615
+ interface TReferencingForeignKey {
616
+ /** The referencing (child) table. */
617
+ table: string;
618
+ /** Referencing columns on `table`, in constraint order. */
619
+ fields: string[];
620
+ /** Referenced columns on the queried table, in constraint order. */
621
+ targetFields: string[];
622
+ }
623
+ /** Kind of a physical database object, as returned by `BaseDbAdapter.getObjectKind`. */
624
+ type TDbObjectKind = "table" | "view" | "materialized";
625
+ /** Options accepted by `BaseDbAdapter.ensureTable`. */
626
+ interface TEnsureTableOptions {
627
+ /**
628
+ * Table names whose inline FOREIGN KEY constraints must be omitted from
629
+ * CREATE TABLE — the constraints are added afterwards by `syncForeignKeys()`.
630
+ * Schema sync passes the members of a foreign-key cycle so they can be
631
+ * created in any order.
632
+ */
633
+ deferForeignKeysTo?: ReadonlySet<string>;
546
634
  }
547
635
  /** Result of applying column diff to the database. */
548
636
  interface TSyncColumnResult {
@@ -684,6 +772,93 @@ interface TDbRelation {
684
772
  /** Junction type reference for 'via' (M:N) relations. */
685
773
  viaType?: () => TAtscriptAnnotatedType;
686
774
  }
775
+ /**
776
+ * Write payload for insert / patch paths: every key optional, and optional
777
+ * columns additionally accept `null` (an explicit NULL — `undefined` means
778
+ * "absent" and is dropped before the row reaches defaults or validation).
779
+ */
780
+ type DbPatch<D> = { [K in keyof D]?: undefined extends D[K] ? D[K] | null : D[K] } & Record<string, unknown>;
781
+ /**
782
+ * Write payload for full-row replace paths: required keys stay required,
783
+ * optional columns additionally accept `null` (explicit NULL).
784
+ */
785
+ type DbRow<D> = { [K in keyof D]: undefined extends D[K] ? D[K] | null : D[K] } & Record<string, unknown>;
786
+ /** Built-in write actions a moost-db `AsDbController` endpoint performs. */
787
+ type TDbWriteAction = "insert" | "insertMany" | "replace" | "replaceMany" | "update" | "updateMany";
788
+ /**
789
+ * Context handed to a write {@link TWriteOptions.guard} (since 0.1.128) — and
790
+ * through it to `AsDbController.guardWrite()`. The table invokes the guard
791
+ * exactly once, inside its own transaction, after `undefined`-pruning,
792
+ * defaults and validation and before encryption / nested-relation phases.
793
+ */
794
+ interface TDbWriteGuardContext<Row = Record<string, unknown>> {
795
+ /** The table method the guard runs for (`insertOne` → `insert`, `insertMany` → `insertMany`, …). */
796
+ readonly action: TDbWriteAction;
797
+ /**
798
+ * insert/replace: validated rows with SDK-side defaults applied (plaintext,
799
+ * nav data still attached); update: validated patches with the identifying
800
+ * PK/unique fields present and `$cas` removed. Mutate in place to enrich —
801
+ * the table re-validates the rows after the guard.
802
+ */
803
+ readonly rows: Row[];
804
+ /** Parallel to `rows`: expected version lifted from `$cas`, or `undefined`. */
805
+ readonly expectedVersions: ReadonlyArray<number | undefined>;
806
+ /**
807
+ * Lazy, memoised pre-image of `rows[i]` by its identifying filter, read
808
+ * inside the transaction. `null` when the row is missing OR when it carries
809
+ * no identifying key yet (e.g. auto-increment inserts) — never throws.
810
+ */
811
+ current(i: number): Promise<Row | null>;
812
+ }
813
+ /**
814
+ * Context handed to a delete {@link TDeleteOptions.guard} (since 0.1.128) —
815
+ * and through it to `AsDbController.guardRemove()`. Runs inside the table's
816
+ * transaction; an id that resolves to no filter never reaches the guard
817
+ * (`deleteOne` answers `{ deletedCount: 0 }`).
818
+ */
819
+ interface TDbRemoveGuardContext<Row = Record<string, unknown>> {
820
+ /** The id `deleteOne` was called with. */
821
+ readonly id: unknown;
822
+ /** `table.resolveIdFilter(id)` — never null here. */
823
+ readonly filter: FilterExpr;
824
+ /** Lazy, memoised pre-image of the row about to be deleted (`null` when missing). */
825
+ current(): Promise<Row | null>;
826
+ }
827
+ /** A validated-stage write guard — see {@link TWriteOptions.guard}. */
828
+ type TDbWriteGuard<Row = Record<string, unknown>> = (ctx: TDbWriteGuardContext<Row>) => void | Promise<void>;
829
+ /** A validated-stage delete guard — see {@link TDeleteOptions.guard}. */
830
+ type TDbRemoveGuard<Row = Record<string, unknown>> = (ctx: TDbRemoveGuardContext<Row>) => void | Promise<void>;
831
+ /** Options of `insertOne/Many`, `replaceOne` / `bulkReplace`, `updateOne` / `bulkUpdate`. */
832
+ interface TWriteOptions<Row = Record<string, unknown>> {
833
+ /** Nested-relation write recursion limit (default 3). */
834
+ maxDepth?: number;
835
+ /**
836
+ * Validated-stage guard (since 0.1.128): invoked exactly once inside the
837
+ * table's transaction, after defaults + validation and before encryption
838
+ * and nested-relation phases, with the rows the table is about to write.
839
+ * Rows may be enriched in place — they are validated again afterwards. A
840
+ * throw rolls the transaction back and propagates unchanged. Never runs
841
+ * for the nested re-entries a deep write performs on related tables.
842
+ */
843
+ guard?: TDbWriteGuard<Row>;
844
+ }
845
+ /** Options of `deleteOne`. */
846
+ interface TDeleteOptions<Row = Record<string, unknown>> {
847
+ /**
848
+ * Validated-stage guard (since 0.1.128): invoked inside the table's
849
+ * transaction after the id resolved to a filter and before cascade /
850
+ * delete. A throw rolls the transaction back and propagates unchanged.
851
+ */
852
+ guard?: TDbRemoveGuard<Row>;
853
+ }
854
+ /**
855
+ * Adds `null` to every optional property of `O`. Optional columns store SQL
856
+ * NULL / Mongo null, and the runtime validator accepts `null` for optional
857
+ * props — so filter shapes (`{ note: null }`, `{ note: { $ne: null } }`) and
858
+ * row shapes must admit it at the type level too. Homomorphic: keys and
859
+ * required properties are unchanged; applying it twice is a no-op.
860
+ */
861
+ type NullableOptional<O> = { [K in keyof O]: undefined extends O[K] ? O[K] | null : O[K] };
687
862
  //#endregion
688
863
  //#region src/base-adapter.d.ts
689
864
  /**
@@ -710,6 +885,15 @@ interface TDbRelation {
710
885
  * - `this._table.isView` — whether this is a view (vs a table)
711
886
  */
712
887
  declare abstract class BaseDbAdapter {
888
+ /**
889
+ * The readable this adapter serves. UNSET on an administrative adapter:
890
+ * `DbSpace` creates one from the factory without a readable for the
891
+ * name-taking schema-sync primitives (`dropTableByName`, `dropViewByName`,
892
+ * `dropTablesByName`, `getReferencingForeignKeys`, `getObjectKind`,
893
+ * `getExistingColumnsForTable`, `hasRows(tableName)`), so those must derive
894
+ * everything — the schema included — from the driver/connection, never from
895
+ * `this._table`.
896
+ */
713
897
  protected _table: AtscriptDbReadable<any, any, any, any, any, any, any>;
714
898
  /**
715
899
  * Resolves the correct insertedId: prefers the user-supplied PK value
@@ -738,7 +922,9 @@ declare abstract class BaseDbAdapter {
738
922
  protected _log(...args: unknown[]): void;
739
923
  /**
740
924
  * Runs `fn` inside a database transaction. Nested calls (from related tables
741
- * within the same async chain) reuse the existing transaction automatically.
925
+ * within the same async chain) reuse the existing transaction automatically
926
+ * — "existing" meaning a transaction of the same {@link _transactionOwner};
927
+ * inside another adapter family's transaction this opens its own.
742
928
  *
743
929
  * The generic layer handles nesting detection via `AsyncLocalStorage`.
744
930
  * Adapters override `_beginTransaction`, `_commitTransaction`, and
@@ -746,7 +932,17 @@ declare abstract class BaseDbAdapter {
746
932
  */
747
933
  withTransaction<T>(fn: () => Promise<T>): Promise<T>;
748
934
  /**
749
- * Returns the opaque transaction state from the current async context.
935
+ * The object a transaction state is branded with (since 0.1.128). Every
936
+ * adapter instance that returns the same owner shares one transaction —
937
+ * override to return the driver / pool / client the adapter was constructed
938
+ * with, so all tables of a space join it. The default (the adapter class)
939
+ * suits adapters without a connection object (in-memory, mocks).
940
+ */
941
+ protected _transactionOwner(): unknown;
942
+ /**
943
+ * Returns the opaque transaction state of THIS adapter's owner from the
944
+ * current async context — `undefined` when no transaction is open or only
945
+ * another adapter family's transaction is (its state is never handed out).
750
946
  * Adapters use this to retrieve DB-specific state (e.g., MongoDB `ClientSession`).
751
947
  */
752
948
  protected _getTransactionState(): unknown;
@@ -755,7 +951,7 @@ declare abstract class BaseDbAdapter {
755
951
  * Adapters that override `withTransaction` (e.g., to use MongoDB's
756
952
  * `session.withTransaction()` Convenient API) use this to set up the
757
953
  * shared context so that nested adapters see the same session.
758
- * If a context already exists (nesting), it's reused.
954
+ * If a context of the same owner already exists (nesting), it's reused.
759
955
  */
760
956
  protected _runInTransactionContext<T>(state: unknown, fn: () => Promise<T>): Promise<T>;
761
957
  /**
@@ -797,11 +993,14 @@ declare abstract class BaseDbAdapter {
797
993
  */
798
994
  supportsNestedObjects(): boolean;
799
995
  /**
800
- * Whether the DB engine handles static `@db.default "value"` natively
801
- * via column-level DEFAULT clauses in CREATE TABLE.
802
- * When `true`, `_applyDefaults()` skips client-side value defaults,
803
- * letting the DB apply its own DEFAULT. SQL adapters return `true`;
804
- * document stores (MongoDB) return `false` and apply defaults client-side.
996
+ * Whether the DB engine carries static `@db.default "value"` defaults in
997
+ * its DDL (`DEFAULT` clauses in `CREATE TABLE`).
998
+ *
999
+ * @deprecated since 0.1.128 — no longer consulted: the table layer fills
1000
+ * static value defaults SDK-side on every adapter before validation, and the
1001
+ * SQL adapters emit their DDL `DEFAULT` clauses regardless of this flag.
1002
+ * Kept as a capability hint for tooling; nothing in the generic layer
1003
+ * branches on it.
805
1004
  */
806
1005
  supportsNativeValueDefaults(): boolean;
807
1006
  /**
@@ -838,9 +1037,12 @@ declare abstract class BaseDbAdapter {
838
1037
  canFilterField(fd: TDbFieldMeta): boolean;
839
1038
  /**
840
1039
  * Whether this adapter can sort by a given field.
841
- * Default: scalar columns yes, JSON-stored columns no. Mongo's array sort
842
- * (min/max element) is a footgun for generic UI sort headers, so the default
843
- * stays conservative even for adapters that technically support it.
1040
+ * Default: scalar columns yes; JSON-stored columns, `@db.json` objects and
1041
+ * arrays no. Mongo's array sort (min/max element) is a footgun for generic
1042
+ * UI sort headers, so the default stays conservative even for adapters that
1043
+ * technically support it — the veto keys on `designType` as well as
1044
+ * `storage` because nested-object adapters keep arrays / `@db.json` values
1045
+ * inline as `storage: 'column'` (since 0.1.128).
844
1046
  */
845
1047
  canSortField(fd: TDbFieldMeta): boolean;
846
1048
  /**
@@ -961,6 +1163,14 @@ declare abstract class BaseDbAdapter {
961
1163
  dropIndex(name: string): Promise<void>;
962
1164
  prefix?: string;
963
1165
  shouldSkipType?(type: TDbIndex["type"]): boolean;
1166
+ /**
1167
+ * Renders one desired key part for the drift comparison, so adapters whose
1168
+ * `listExisting` reports more than a bare column name (e.g. MySQL's
1169
+ * `col(255)` key-length prefix) can render the model side identically.
1170
+ * Default: the column name.
1171
+ * @since 0.1.128
1172
+ */
1173
+ renderDesiredColumn?(index: TDbIndex, field: TDbIndex["fields"][number]): string;
964
1174
  /**
965
1175
  * Index types declared on the model but not supported by this adapter —
966
1176
  * warns and skips (models stay portable; sync never errors on these).
@@ -1090,8 +1300,14 @@ declare abstract class BaseDbAdapter {
1090
1300
  /**
1091
1301
  * Ensures the table exists in the database, creating it if needed.
1092
1302
  * Uses `this._table.tableName`, `this._table.schema`, etc.
1303
+ *
1304
+ * @param opts - Optional (since 0.1.128). Relational adapters that emit
1305
+ * inline FOREIGN KEY constraints must omit those whose target is in
1306
+ * `opts.deferForeignKeysTo` — schema sync adds them afterwards through
1307
+ * {@link syncForeignKeys} so a foreign-key cycle can be created in any
1308
+ * order. Adapters without inline constraints ignore the parameter.
1093
1309
  */
1094
- abstract ensureTable(): Promise<void>;
1310
+ abstract ensureTable(opts?: TEnsureTableOptions): Promise<void>;
1095
1311
  /**
1096
1312
  * Synchronizes foreign key constraints between Atscript definitions and the database.
1097
1313
  * Uses `this._table.foreignKeys` for the full FK definitions.
@@ -1128,8 +1344,13 @@ declare abstract class BaseDbAdapter {
1128
1344
  *
1129
1345
  * Returns undefined if the adapter cannot introspect table options.
1130
1346
  * In that case, schema sync falls back to stored snapshot.
1347
+ *
1348
+ * @param tableName - Introspect this table instead of the adapter's own
1349
+ * (schema sync passes the OLD name of a table that is about to be
1350
+ * renamed, as for `getExistingColumnsForTable`). Defaults to the bound
1351
+ * table.
1131
1352
  */
1132
- getExistingTableOptions?(): Promise<TExistingTableOption[]>;
1353
+ getExistingTableOptions?(tableName?: string): Promise<TExistingTableOption[]>;
1133
1354
  /**
1134
1355
  * Applies non-destructive table option changes (e.g., MySQL ALTER TABLE ENGINE=X).
1135
1356
  * Called for each non-destructive change in the diff.
@@ -1205,6 +1426,58 @@ declare abstract class BaseDbAdapter {
1205
1426
  * Optional — only relational adapters implement this.
1206
1427
  */
1207
1428
  dropViewByName?(viewName: string): Promise<void>;
1429
+ /**
1430
+ * Drops several tables that reference each other (a foreign-key cycle) as
1431
+ * one operation. Schema sync only calls this for cycles whose members are
1432
+ * ALL being removed. Default: {@link dropTableByName} in the given order —
1433
+ * enough for engines that tolerate it (SQLite with FK checks off, MySQL with
1434
+ * FOREIGN_KEY_CHECKS=0); PostgreSQL overrides it with one multi-table
1435
+ * `DROP TABLE a, b` statement.
1436
+ * @since 0.1.128
1437
+ */
1438
+ dropTablesByName(tableNames: string[]): Promise<void>;
1439
+ /**
1440
+ * Whether the table has at least one row. Schema sync uses it in the
1441
+ * pre-flight phase to refuse a primary-key change on a populated table.
1442
+ * Override with an EXISTS/LIMIT 1 probe — this default is `count() > 0`,
1443
+ * a full scan on some engines, and it can only answer for the adapter's
1444
+ * OWN table: for another `tableName` (or on an administrative adapter
1445
+ * without a readable) it returns `undefined` ("cannot tell"), which schema
1446
+ * sync treats as a refusal.
1447
+ *
1448
+ * @param tableName - Check this table instead of the adapter's own (schema
1449
+ * sync passes the OLD name of a table that is about to be renamed).
1450
+ * @returns `true`/`false`, or `undefined` when the adapter cannot tell.
1451
+ * @since 0.1.128
1452
+ */
1453
+ hasRows(tableName?: string): Promise<boolean | undefined>;
1454
+ /**
1455
+ * Live foreign keys that REFERENCE `tableName` (inbound edges), from any
1456
+ * table in the database — including tables whose models are no longer in
1457
+ * the sync inventory. Schema sync uses it to order drops (children before
1458
+ * parents), to refuse dropping a table that an unmanaged table still
1459
+ * references, and to refuse a primary-key change that a live FK depends on.
1460
+ * Optional — engines without physical foreign keys omit it.
1461
+ * @since 0.1.128
1462
+ */
1463
+ getReferencingForeignKeys?(tableName: string): Promise<TReferencingForeignKey[]>;
1464
+ /**
1465
+ * Kind of the physical object stored under `name`, or `undefined` when
1466
+ * nothing exists. Schema sync refuses a run when a physical table sits
1467
+ * where a managed view is declared (or a view where a table is declared)
1468
+ * instead of silently creating/skipping over it.
1469
+ * Optional — adapters without the method skip the check.
1470
+ * @since 0.1.128
1471
+ */
1472
+ getObjectKind?(name: string): Promise<TDbObjectKind | undefined>;
1473
+ /**
1474
+ * Rewrites the table's primary key from `change.from` to `change.to`.
1475
+ * Called only on an EMPTY table (schema sync refuses populated ones) after
1476
+ * new columns were added and before stale columns are dropped, so both
1477
+ * column sets exist. Adapters without it fall back to {@link recreateTable}.
1478
+ * @since 0.1.128
1479
+ */
1480
+ rebuildPrimaryKey?(change: TPrimaryKeyChange): Promise<void>;
1208
1481
  /**
1209
1482
  * Renames a table/collection from `oldName` to the adapter's current table name.
1210
1483
  * Used by schema sync when `@db.table.renamed` is present.
@@ -1422,7 +1695,7 @@ declare function resolveDesignType(fieldType: TAtscriptAnnotatedType): string;
1422
1695
  * {@link AtscriptDbTable} (adds write operations) and {@link AtscriptDbView}
1423
1696
  * (adds view plan/DDL).
1424
1697
  */
1425
- declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>, _FlatType = FlatOf<T>, A extends BaseDbAdapter = BaseDbAdapter, IdType = PrimaryKeyOf<T>, OwnProps = OwnPropsOf<T>, NavType extends Record<string, unknown> = NavPropsOf<T>> {
1698
+ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>, _FlatType = NullableOptional<FlatOf<T>>, A extends BaseDbAdapter = BaseDbAdapter, IdType = PrimaryKeyOf<T>, OwnProps = NullableOptional<OwnPropsOf<T>>, NavType extends Record<string, unknown> = NavPropsOf<T>> {
1426
1699
  protected readonly _type: T;
1427
1700
  protected readonly adapter: A;
1428
1701
  protected readonly logger: TGenericLogger;
@@ -1733,4 +2006,4 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
1733
2006
  }, thisTableName: string, alias?: string): TDbForeignKey | undefined;
1734
2007
  }
1735
2008
  //#endregion
1736
- export { TIdentification as $, TDbActionLevel as A, TDbIndexType as B, TCascadeResolver as C, TCrudPermissions as D, TCrudOp as E, TDbDeleteResult as F, TDbStorageType as G, TDbInsertResult as H, TDbFieldMeta as I, TExistingTableOption as J, TDbUpdateResult as K, TDbForeignKey as L, TDbCollation as M, TDbDefaultFn as N, TDbActionInfo as O, TDbDefaultValue as P, TIdDescriptor as Q, TDbIndex as R, PrimaryKeyOf$1 as S, TColumnDiff as T, TDbReferentialAction as U, TDbInsertManyResult as V, TDbRelation as W, TFkLookupResolver as X, TFieldMeta as Y, TFkLookupTarget as Z, FieldOpsFor as _, TGenericLogger as _t, TDbEncryptionOptions as a, TTableOptionDiff as at, NavPropsOf$1 as b, BaseDbAdapter as c, TWriteTableResolver as ct, AggregateFn as d, UniqueryControls$1 as dt, TMetaResponse as et, AggregateQuery$1 as f, WithRelation$1 as ft, DbQuery as g, NoopLogger as gt, DbControls as h, isGeoPointType as ht, DbEncryption as i, TSyncColumnResult as it, TDbActionProcessor as j, TDbActionIntent as k, AggregateControls as l, TypedWithRelation as lt, AtscriptDbWritable as m, isGeoIndexableType as mt, DbResponse as n, TRelationInfo as nt, DocumentFieldMapper as o, TTableResolver as ot, AggregateResult as p, TableMetadata as pt, TExistingColumn as q, resolveDesignType as r, TSearchIndexInfo as rt, FieldMappingStrategy as s, TValueFormatterPair as st, AtscriptDbReadable as t, TMetadataOverrides as tt, AggregateExpr$1 as u, Uniquery$1 as ut, FilterExpr$1 as v, UniquSelect as vt, TCascadeTarget as w, OwnPropsOf$1 as x, FlatOf$1 as y, TDbIndexField as z };
2009
+ export { TDbWriteAction as $, TCrudPermissions as A, isGeoIndexableType as At, TDbForeignKey as B, NullableOptional as C, TWriteTableResolver as Ct, TCascadeTarget as D, WithRelation$1 as Dt, TCascadeResolver as E, UniqueryControls$1 as Et, TDbCollation as F, TDbInsertResult as G, TDbIndexField as H, TDbDefaultFn as I, TDbRelation as J, TDbObjectKind as K, TDbDefaultValue as L, TDbActionIntent as M, NoopLogger as Mt, TDbActionLevel as N, TGenericLogger as Nt, TColumnDiff as O, TableMetadata as Ot, TDbActionProcessor as P, UniquSelect as Pt, TDbUpdateResult as Q, TDbDeleteResult as R, NavPropsOf$1 as S, TWriteOptions as St, PrimaryKeyOf$1 as T, Uniquery$1 as Tt, TDbIndexType as U, TDbIndex as V, TDbInsertManyResult as W, TDbRemoveGuardContext as X, TDbRemoveGuard as Y, TDbStorageType as Z, DbQuery as _, TSearchIndexInfo as _t, TDbEncryptionOptions as a, TExistingForeignKey as at, FilterExpr$1 as b, TTableResolver as bt, BaseDbAdapter as c, TFkLookupResolver as ct, AggregateFn as d, TIdentification as dt, TDbWriteGuard as et, AggregateQuery$1 as f, TMetaResponse as ft, DbPatch as g, TRelationInfo as gt, DbControls as h, TReferencingForeignKey as ht, DbEncryption as i, TExistingColumn as it, TDbActionInfo as j, isGeoPointType as jt, TCrudOp as k, findAncestorInSet as kt, AggregateControls as l, TFkLookupTarget as lt, AtscriptDbWritable as m, TPrimaryKeyChange as mt, DbResponse as n, TDeleteOptions as nt, DocumentFieldMapper as o, TExistingTableOption as ot, AggregateResult as p, TMetadataOverrides as pt, TDbReferentialAction as q, resolveDesignType as r, TEnsureTableOptions as rt, FieldMappingStrategy as s, TFieldMeta as st, AtscriptDbReadable as t, TDbWriteGuardContext as tt, AggregateExpr$1 as u, TIdDescriptor as ut, DbRow as v, TSyncColumnResult as vt, OwnPropsOf$1 as w, TypedWithRelation as wt, FlatOf$1 as x, TValueFormatterPair as xt, FieldOpsFor as y, TTableOptionDiff as yt, TDbFieldMeta as z };