@atscript/db 0.1.39 → 0.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +18 -18
  2. package/dist/agg.cjs +8 -3
  3. package/dist/agg.d.cts +7 -0
  4. package/dist/agg.d.mts +7 -0
  5. package/dist/agg.mjs +7 -3
  6. package/dist/control-DRgryKeg.cjs +14 -0
  7. package/dist/{control_as-bjmwe24C.mjs → control-IANbnfjG.mjs} +6 -18
  8. package/dist/db-readable-BQQzfguJ.d.cts +1249 -0
  9. package/dist/db-readable-Bbr4CjMb.d.mts +1249 -0
  10. package/dist/db-space-BUrQ5BFm.d.mts +309 -0
  11. package/dist/db-space-Vxpcnyt5.d.cts +309 -0
  12. package/dist/db-validator-plugin-07kDiis2.d.cts +22 -0
  13. package/dist/db-validator-plugin-CiqsHTI_.d.mts +22 -0
  14. package/dist/db-view-BntnAmXO.cjs +3071 -0
  15. package/dist/db-view-ZsoN91-q.mjs +2970 -0
  16. package/dist/index.cjs +95 -2801
  17. package/dist/index.d.cts +137 -0
  18. package/dist/index.d.mts +137 -0
  19. package/dist/index.mjs +55 -2761
  20. package/dist/{nested-writer-BkqL7cp3.cjs → nested-writer-BDXsDMPP.cjs} +196 -150
  21. package/dist/{nested-writer-NEN51mnR.mjs → nested-writer-Dmm1gbZV.mjs} +118 -70
  22. package/dist/ops-BdRAFLKY.d.mts +67 -0
  23. package/dist/ops-DXJ4Zw0P.d.cts +67 -0
  24. package/dist/ops.cjs +123 -0
  25. package/dist/ops.d.cts +2 -0
  26. package/dist/ops.d.mts +2 -0
  27. package/dist/ops.mjs +112 -0
  28. package/dist/plugin.cjs +90 -109
  29. package/dist/plugin.d.cts +6 -0
  30. package/dist/plugin.d.mts +6 -0
  31. package/dist/plugin.mjs +29 -49
  32. package/dist/rel.cjs +20 -20
  33. package/dist/rel.d.cts +119 -0
  34. package/dist/rel.d.mts +119 -0
  35. package/dist/rel.mjs +4 -5
  36. package/dist/{relation-helpers-guFL_oRf.cjs → relation-helpers-BYvsE1tR.cjs} +26 -22
  37. package/dist/{relation-helpers-DyBIlQnB.mjs → relation-helpers-CLasawQq.mjs} +11 -6
  38. package/dist/{relation-loader-Dv7qXYq7.mjs → relation-loader-BEOTXNcq.mjs} +63 -43
  39. package/dist/{relation-loader-CpnDRf9k.cjs → relation-loader-CRC5LcqM.cjs} +74 -49
  40. package/dist/shared.cjs +13 -13
  41. package/dist/{shared.d.ts → shared.d.cts} +14 -13
  42. package/dist/shared.d.mts +71 -0
  43. package/dist/shared.mjs +2 -3
  44. package/dist/sync.cjs +300 -252
  45. package/dist/sync.d.cts +369 -0
  46. package/dist/sync.d.mts +369 -0
  47. package/dist/sync.mjs +284 -233
  48. package/dist/{validation-utils-DEoCMmEb.cjs → validation-utils-DVJDijnB.cjs} +141 -109
  49. package/dist/{validation-utils-DhR_mtKa.mjs → validation-utils-DhjIjP1-.mjs} +71 -37
  50. package/package.json +30 -29
  51. package/LICENSE +0 -21
  52. package/dist/agg-BJFJ3dFQ.mjs +0 -8
  53. package/dist/agg-DnUWAOK8.cjs +0 -14
  54. package/dist/agg.d.ts +0 -13
  55. package/dist/chunk-CrpGerW8.cjs +0 -31
  56. package/dist/control_as-BFPERAF_.cjs +0 -28
  57. package/dist/index.d.ts +0 -1706
  58. package/dist/logger-B7oxCfLQ.mjs +0 -12
  59. package/dist/logger-Dt2v_-wb.cjs +0 -18
  60. package/dist/plugin.d.ts +0 -5
  61. package/dist/rel.d.ts +0 -1305
  62. package/dist/relation-loader-D4mTw6yH.cjs +0 -4
  63. package/dist/relation-loader-Ggy1ujwR.mjs +0 -4
  64. package/dist/sync.d.ts +0 -1878
@@ -0,0 +1,1249 @@
1
+ import { u as TFieldOps } from "./ops-DXJ4Zw0P.cjs";
2
+ 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";
3
+ import { FlatOf, NavPropsOf, NavPropsOf as NavPropsOf$1, OwnPropsOf, OwnPropsOf as OwnPropsOf$1, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, TAtscriptTypeObject, TMetadataMap, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
4
+
5
+ //#region src/query/uniqu-select.d.ts
6
+ /**
7
+ * Wraps a raw `$select` value and provides lazy-cached conversions
8
+ * to the forms different adapters need.
9
+ *
10
+ * Only instantiated when `$select` is actually provided —
11
+ * `controls.$select` is `UniquSelect | undefined`.
12
+ *
13
+ * For exclusion → inclusion inversion, pass `allFields` (physical field names).
14
+ */
15
+ declare class UniquSelect {
16
+ private static readonly UNRESOLVED;
17
+ private _raw;
18
+ private _allFields?;
19
+ private _array;
20
+ private _projection;
21
+ private _aggregates;
22
+ constructor(raw: UniqueryControls["$select"], allFields?: string[]);
23
+ /** Type guard: checks if a value is an AggregateExpr ({$fn, $field}). */
24
+ private static _isAggregateExpr;
25
+ /**
26
+ * Resolved inclusion array of plain field names (strings only).
27
+ * AggregateExpr objects are filtered out.
28
+ * For exclusion form, inverts using `allFields` from constructor.
29
+ */
30
+ get asArray(): string[] | undefined;
31
+ /**
32
+ * Record projection preserving original semantics.
33
+ * Returns original object as-is if raw was object.
34
+ * Converts `string[]` to `{field: 1}` inclusion object.
35
+ * AggregateExpr objects in array form are ignored.
36
+ */
37
+ get asProjection(): Record<string, 0 | 1> | undefined;
38
+ /**
39
+ * Extracts AggregateExpr entries from array-form $select.
40
+ * Returns undefined if no aggregates present or if $select is object form.
41
+ */
42
+ get aggregates(): AggregateExpr[] | undefined;
43
+ /** Whether the $select contains any AggregateExpr entries. */
44
+ get hasAggregates(): boolean;
45
+ }
46
+ //#endregion
47
+ //#region src/types.d.ts
48
+ /** Controls with resolved projection. Used in the adapter interface. */
49
+ interface DbControls extends Omit<UniqueryControls, "$select"> {
50
+ $select?: UniquSelect;
51
+ }
52
+ /** Query object with resolved projection. Passed to adapter methods. */
53
+ interface DbQuery {
54
+ filter: FilterExpr;
55
+ controls: DbControls;
56
+ /** Pre-computed query insights (field → operators). Adapters may use this to apply query-time behaviour (e.g. collation). */
57
+ insights?: UniqueryInsights;
58
+ }
59
+ /** Describes an available search index exposed by a database adapter. */
60
+ interface TSearchIndexInfo {
61
+ /** Index name. Empty string or 'DEFAULT' for the default index. */
62
+ name: string;
63
+ /** Human-readable label for UI display. */
64
+ description?: string;
65
+ /** Index type: text search or vector similarity search. */
66
+ type?: "text" | "vector";
67
+ }
68
+ interface TDbInsertResult {
69
+ insertedId: unknown;
70
+ }
71
+ interface TDbInsertManyResult {
72
+ insertedCount: number;
73
+ insertedIds: unknown[];
74
+ }
75
+ interface TDbUpdateResult {
76
+ matchedCount: number;
77
+ modifiedCount: number;
78
+ }
79
+ interface TDbDeleteResult {
80
+ deletedCount: number;
81
+ }
82
+ type TDbIndexType = "plain" | "unique" | "fulltext";
83
+ interface TDbIndexField {
84
+ name: string;
85
+ sort: "asc" | "desc";
86
+ weight?: number;
87
+ }
88
+ interface TDbIndex {
89
+ /** Unique key used for identity/diffing (e.g., "atscript__plain__email") */
90
+ key: string;
91
+ /** Human-readable index name. */
92
+ name: string;
93
+ /** Index type. */
94
+ type: TDbIndexType;
95
+ /** Ordered list of fields in the index. */
96
+ fields: TDbIndexField[];
97
+ }
98
+ type TDbDefaultFn = "increment" | "uuid" | "now";
99
+ type TDbCollation = "binary" | "nocase" | "unicode";
100
+ type TDbDefaultValue = {
101
+ kind: "value";
102
+ value: string;
103
+ } | {
104
+ kind: "fn";
105
+ fn: TDbDefaultFn;
106
+ start?: number;
107
+ };
108
+ interface TIdDescriptor {
109
+ /** Field names that form the primary key. */
110
+ fields: string[];
111
+ /** Whether this is a composite key (multiple fields). */
112
+ isComposite: boolean;
113
+ }
114
+ type TDbStorageType = "column" | "flattened" | "json";
115
+ interface TDbFieldMeta {
116
+ /** The dot-notation path to this field (logical name). */
117
+ path: string;
118
+ /** The annotated type for this field. */
119
+ type: TAtscriptAnnotatedType;
120
+ /** Physical column/field name (from @db.column, __-separated for flattened, or same as path). */
121
+ physicalName: string;
122
+ /** Resolved design type: 'string', 'number', 'boolean', 'object', 'json', etc. */
123
+ designType: string;
124
+ /** Whether the field is optional. */
125
+ optional: boolean;
126
+ /** Whether this field is part of the primary key (@meta.id). */
127
+ isPrimaryKey: boolean;
128
+ /** Whether this field is excluded from the DB (@db.ignore). */
129
+ ignored: boolean;
130
+ /** Default value from @db.default.* */
131
+ defaultValue?: TDbDefaultValue;
132
+ /**
133
+ * How this field is stored in the database.
134
+ * - 'column': a standard scalar column (default for primitives)
135
+ * - 'flattened': a leaf scalar from a flattened nested object
136
+ * - 'json': stored as a single JSON column (arrays, @db.json fields)
137
+ */
138
+ storage: TDbStorageType;
139
+ /**
140
+ * For flattened fields: the dot-notation path (same as `path`).
141
+ * E.g., for physicalName 'contact__email', this is 'contact.email'.
142
+ * Undefined for non-flattened fields.
143
+ */
144
+ flattenedFrom?: string;
145
+ /** Old physical column name from @db.column.renamed (for rename migration). */
146
+ renamedFrom?: string;
147
+ /** Collation from @db.column.collate (e.g. 'nocase', 'binary', 'unicode'). */
148
+ collate?: TDbCollation;
149
+ /** Whether this field participates in any index (@db.index.plain, @db.index.unique, @db.index.fulltext). */
150
+ isIndexed?: boolean;
151
+ /**
152
+ * For FK fields: the resolved field metadata of the referenced (target) PK column.
153
+ * Adapters use this in `typeMapper` to produce matching DB types for FK columns
154
+ * (e.g., `typeMapper(field.fkTargetField)` to inherit the target PK's DB type).
155
+ * Undefined for non-FK fields or when the target cannot be resolved.
156
+ */
157
+ fkTargetField?: TDbFieldMeta;
158
+ }
159
+ interface TValueFormatterPair {
160
+ /** Converts a JS value to storage representation (write + filter paths). */
161
+ toStorage: (value: unknown) => unknown;
162
+ /** Converts a storage value back to JS representation (read path). */
163
+ fromStorage: (value: unknown) => unknown;
164
+ }
165
+ type TDbReferentialAction = "cascade" | "restrict" | "noAction" | "setNull" | "setDefault";
166
+ interface TDbForeignKey {
167
+ /** FK field names on this table (local columns). */
168
+ fields: string[];
169
+ /** Target table name (from the chain ref's type @db.table annotation). */
170
+ targetTable: string;
171
+ /** Target field names on the referenced table. */
172
+ targetFields: string[];
173
+ /** Lazy reference to the target annotated type (for on-demand table resolution). */
174
+ targetTypeRef?: () => TAtscriptAnnotatedType;
175
+ /** Alias grouping FK fields (if any). */
176
+ alias?: string;
177
+ /** Referential action on delete. */
178
+ onDelete?: TDbReferentialAction;
179
+ /** Referential action on update. */
180
+ onUpdate?: TDbReferentialAction;
181
+ }
182
+ /** Describes an existing column in the database (from introspection). */
183
+ interface TExistingColumn {
184
+ name: string;
185
+ type: string;
186
+ notnull: boolean;
187
+ pk: boolean;
188
+ /** Serialized default value (e.g., "'active'", "NULL"). */
189
+ dflt_value?: string;
190
+ }
191
+ /** Result of comparing desired schema against existing database columns. */
192
+ interface TColumnDiff {
193
+ added: TDbFieldMeta[];
194
+ removed: TExistingColumn[];
195
+ renamed: Array<{
196
+ field: TDbFieldMeta;
197
+ oldName: string;
198
+ }>;
199
+ typeChanged: Array<{
200
+ field: TDbFieldMeta;
201
+ existingType: string;
202
+ }>;
203
+ nullableChanged: Array<{
204
+ field: TDbFieldMeta;
205
+ wasNullable: boolean;
206
+ }>;
207
+ defaultChanged: Array<{
208
+ field: TDbFieldMeta;
209
+ oldDefault?: string;
210
+ newDefault?: string;
211
+ }>;
212
+ conflicts: Array<{
213
+ field: TDbFieldMeta;
214
+ oldName: string;
215
+ conflictsWith: string;
216
+ }>;
217
+ }
218
+ /** Result of applying column diff to the database. */
219
+ interface TSyncColumnResult {
220
+ added: string[];
221
+ renamed: string[];
222
+ }
223
+ /** A single table-level option in unified key-value format. */
224
+ interface TExistingTableOption {
225
+ key: string;
226
+ value: string;
227
+ }
228
+ /** Result of comparing desired table options against existing ones. */
229
+ interface TTableOptionDiff {
230
+ changed: Array<{
231
+ key: string;
232
+ oldValue: string;
233
+ newValue: string; /** Whether applying this change requires dropping and recreating the table. */
234
+ destructive: boolean;
235
+ }>;
236
+ }
237
+ /**
238
+ * Adapter-provided metadata adjustments applied atomically during the
239
+ * build pipeline, before field descriptors are built.
240
+ *
241
+ * Replaces the old pattern where adapters mutated metadata via
242
+ * back-references (`this._table.addPrimaryKey()`, etc.).
243
+ */
244
+ interface TMetadataOverrides {
245
+ /** Fields to add as primary keys. */
246
+ addPrimaryKeys?: string[];
247
+ /** Fields to remove from primary keys. */
248
+ removePrimaryKeys?: string[];
249
+ /** Fields to register as having a unique constraint. */
250
+ addUniqueFields?: string[];
251
+ /** Synthetic fields to inject into flatMap (e.g. MongoDB's `_id`). */
252
+ injectFields?: Array<{
253
+ path: string;
254
+ type: TAtscriptAnnotatedType;
255
+ }>;
256
+ }
257
+ /**
258
+ * Callback that resolves an annotated type to a queryable table instance.
259
+ * Required for `$with` relation loading — each table needs to query related tables.
260
+ *
261
+ * Typically provided by the driver/registry (e.g. `DbSpace.getTable`).
262
+ */
263
+ type TTableResolver = (type: TAtscriptAnnotatedType) => Pick<AtscriptDbTableLike, "findMany" | "loadRelations" | "primaryKeys" | "relations" | "foreignKeys"> | undefined;
264
+ /** Minimal table interface used by the table resolver. Avoids circular dependency with AtscriptDbTable. */
265
+ interface AtscriptDbTableLike {
266
+ findMany(query: unknown): Promise<Array<Record<string, unknown>>>;
267
+ loadRelations(rows: Array<Record<string, unknown>>, withRelations: WithRelation[]): Promise<void>;
268
+ primaryKeys: readonly string[];
269
+ relations: ReadonlyMap<string, TDbRelation>;
270
+ foreignKeys: ReadonlyMap<string, TDbForeignKey>;
271
+ }
272
+ /** Minimal writable table interface for nested creation/update. */
273
+ interface AtscriptDbWritable {
274
+ insertOne(payload: Record<string, unknown>, opts?: {
275
+ maxDepth?: number;
276
+ }): Promise<TDbInsertResult>;
277
+ insertMany(payloads: Array<Record<string, unknown>>, opts?: {
278
+ maxDepth?: number;
279
+ _depth?: number;
280
+ }): Promise<TDbInsertManyResult>;
281
+ replaceOne(payload: Record<string, unknown>, opts?: {
282
+ maxDepth?: number;
283
+ }): Promise<TDbUpdateResult>;
284
+ bulkReplace(payloads: Array<Record<string, unknown>>, opts?: {
285
+ maxDepth?: number;
286
+ _depth?: number;
287
+ }): Promise<TDbUpdateResult>;
288
+ updateOne(payload: Record<string, unknown>, opts?: {
289
+ maxDepth?: number;
290
+ }): Promise<TDbUpdateResult>;
291
+ bulkUpdate(payloads: Array<Record<string, unknown>>, opts?: {
292
+ maxDepth?: number;
293
+ _depth?: number;
294
+ }): Promise<TDbUpdateResult>;
295
+ findOne(query: unknown): Promise<Record<string, unknown> | null>;
296
+ count(query: {
297
+ filter: Record<string, unknown>;
298
+ }): Promise<number>;
299
+ deleteMany(filter: unknown): Promise<TDbDeleteResult>;
300
+ /** Pre-validate items (type + FK constraints) without inserting them. */
301
+ preValidateItems(items: Array<Record<string, unknown>>, opts?: {
302
+ excludeFkTargetTable?: string;
303
+ }): Promise<void>;
304
+ }
305
+ /**
306
+ * Callback that resolves an annotated type to a writable table instance.
307
+ * Used for nested creation — inserting related records inline.
308
+ */
309
+ type TWriteTableResolver = (type: TAtscriptAnnotatedType) => (AtscriptDbTableLike & AtscriptDbWritable) | undefined;
310
+ /**
311
+ * A child table that may need cascade/setNull processing when a parent is deleted.
312
+ * Returned by the cascade resolver.
313
+ */
314
+ interface TCascadeTarget {
315
+ /** FK on the child table that references the parent being deleted. */
316
+ fk: TDbForeignKey;
317
+ /** Name of the child table that holds this FK. */
318
+ childTable: string;
319
+ /** Delete matching child records (goes through AtscriptDbTable for recursive cascade). */
320
+ deleteMany(filter: Record<string, unknown>): Promise<TDbDeleteResult>;
321
+ /** Update matching child records (for setNull — sets FK fields to null). */
322
+ updateMany(filter: Record<string, unknown>, data: Record<string, unknown>): Promise<TDbUpdateResult>;
323
+ /** Count matching child records (for restrict — check existence before delete). */
324
+ count(filter: Record<string, unknown>): Promise<number>;
325
+ }
326
+ /**
327
+ * Callback that finds all child tables with FKs pointing to a given parent table.
328
+ * Used by AtscriptDbTable to implement application-level cascade deletes.
329
+ */
330
+ type TCascadeResolver = (tableName: string) => TCascadeTarget[];
331
+ /**
332
+ * Minimal interface for querying a target table during FK validation.
333
+ * Only `count` is needed — we check if the referenced record exists.
334
+ */
335
+ interface TFkLookupTarget {
336
+ count(filter: Record<string, unknown>): Promise<number>;
337
+ }
338
+ /**
339
+ * Callback that resolves a table name to a queryable target for FK validation.
340
+ * Returns undefined if the target table is not registered in the space.
341
+ */
342
+ type TFkLookupResolver = (tableName: string) => TFkLookupTarget | undefined;
343
+ interface TDbRelation {
344
+ /** Direction: 'to' (FK is local), 'from' (FK is remote), or 'via' (M:N junction). */
345
+ direction: "to" | "from" | "via";
346
+ /** The alias used for pairing (if any). */
347
+ alias?: string;
348
+ /** Target type's annotated type reference. */
349
+ targetType: () => TAtscriptAnnotatedType;
350
+ /** Whether this is an array relation (one-to-many). */
351
+ isArray: boolean;
352
+ /** Junction type reference for 'via' (M:N) relations. */
353
+ viaType?: () => TAtscriptAnnotatedType;
354
+ }
355
+ //#endregion
356
+ //#region src/logger.d.ts
357
+ interface TGenericLogger {
358
+ error(...messages: any[]): void;
359
+ warn(...messages: any[]): void;
360
+ log(...messages: any[]): void;
361
+ info(...messages: any[]): void;
362
+ debug(...messages: any[]): void;
363
+ }
364
+ declare const NoopLogger: TGenericLogger;
365
+ //#endregion
366
+ //#region src/table/table-metadata.d.ts
367
+ /**
368
+ * Computed metadata for a database table or view.
369
+ *
370
+ * Contains all field metadata, physical mapping indexes, relation definitions,
371
+ * and constraint information derived from Atscript annotations. Built lazily
372
+ * on first access via {@link build}, then immutable.
373
+ *
374
+ * This class owns the build pipeline that was previously part of
375
+ * `AtscriptDbReadable._flatten()`. The Readable delegates all metadata
376
+ * access to this class.
377
+ */
378
+ declare class TableMetadata {
379
+ readonly nestedObjects: boolean;
380
+ flatMap: Map<string, TAtscriptAnnotatedType>;
381
+ fieldDescriptors: readonly TDbFieldMeta[];
382
+ primaryKeys: string[];
383
+ originalMetaIdFields: string[];
384
+ indexes: Map<string, TDbIndex>;
385
+ foreignKeys: Map<string, TDbForeignKey>;
386
+ relations: Map<string, TDbRelation>;
387
+ navFields: Set<string>;
388
+ ignoredFields: Set<string>;
389
+ uniqueProps: Set<string>;
390
+ defaults: Map<string, TDbDefaultValue>;
391
+ columnMap: Map<string, string>;
392
+ dimensions: string[];
393
+ measures: string[];
394
+ pathToPhysical: Map<string, string>;
395
+ physicalToPath: Map<string, string>;
396
+ flattenedParents: Set<string>;
397
+ jsonFields: Set<string>;
398
+ selectExpansion: Map<string, string[]>;
399
+ booleanFields: Set<string>;
400
+ decimalFields: Set<string>;
401
+ allPhysicalFields: string[];
402
+ requiresMappings: boolean;
403
+ toStorageFormatters?: Map<string, (value: unknown) => unknown>;
404
+ fromStorageFormatters?: Map<string, (value: unknown) => unknown>;
405
+ /** Leaf field descriptors indexed by physical column name (read path). */
406
+ leafByPhysical: Map<string, TDbFieldMeta>;
407
+ /** Leaf field descriptors indexed by logical path (write/patch/filter paths). */
408
+ leafByLogical: Map<string, TDbFieldMeta>;
409
+ private _built;
410
+ private _collateMap;
411
+ private _columnFromMap;
412
+ constructor(nestedObjects: boolean);
413
+ get isBuilt(): boolean;
414
+ /**
415
+ * Runs the full metadata compilation pipeline. Called once by
416
+ * `AtscriptDbReadable._ensureBuilt()` on first metadata access.
417
+ *
418
+ * Pipeline steps:
419
+ * 1. `adapter.onBeforeFlatten(type)` — adapter hook
420
+ * 2. `flattenAnnotatedType()` — collect field tuples, detect nav fields eagerly
421
+ * 3. Replay non-nav-descendant tuples through annotation scanning + adapter.onFieldScanned
422
+ * 4. Classify fields and build path maps (skipped for nested-objects adapters)
423
+ * 5. `adapter.getMetadataOverrides()` → `_applyOverrides()` (PK/unique/inject adjustments)
424
+ * 6. Build field descriptors (TDbFieldMeta[])
425
+ * 7. Build leaf field indexes (skipped for nested-objects adapters)
426
+ * 8. Finalize indexes (resolve field names to physical)
427
+ * 9. `adapter.onAfterFlatten()` — adapter hook (read-only bookkeeping)
428
+ * 10. Build allPhysicalFields list
429
+ */
430
+ build(type: TAtscriptAnnotatedType<TAtscriptTypeObject>, adapter: BaseDbAdapter, logger: TGenericLogger): void;
431
+ /**
432
+ * Applies adapter-provided metadata overrides atomically.
433
+ * Processing order: injectFields → removePrimaryKeys → addPrimaryKeys → addUniqueFields.
434
+ */
435
+ private _applyOverrides;
436
+ /**
437
+ * Scans `@db.*` and `@meta.id` annotations on a field during flattening.
438
+ */
439
+ private _scanGenericAnnotations;
440
+ private _addIndexField;
441
+ /**
442
+ * Classifies each field as column, flattened, json, or parent-object.
443
+ * Builds the bidirectional pathToPhysical / physicalToPath maps.
444
+ */
445
+ private _classifyFields;
446
+ /** Returns the `__`-separated parent prefix for a dot-separated path, or empty string for top-level paths. */
447
+ private _flattenedPrefix;
448
+ /**
449
+ * Indexes `fieldDescriptors` into two lookup maps for unified
450
+ * read/write field classification in the RelationalFieldMapper.
451
+ */
452
+ private _buildLeafIndexes;
453
+ /**
454
+ * Builds field descriptors, physical-name lookup, and value formatters.
455
+ * Called once during build() — everything it needs
456
+ * (flatMap, indexes, columnMap, etc.) is already populated.
457
+ */
458
+ private _buildFieldDescriptors;
459
+ /**
460
+ * Resolves `fkTargetField` for FK fields in field descriptors.
461
+ */
462
+ private _resolveFkTargetFields;
463
+ private _finalizeIndexes;
464
+ }
465
+ //#endregion
466
+ //#region src/base-adapter.d.ts
467
+ /**
468
+ * Abstract base class for database adapters.
469
+ *
470
+ * Adapter instances are 1:1 with readable instances (tables or views).
471
+ * When an {@link AtscriptDbReadable} is created with an adapter, it calls
472
+ * {@link registerReadable} to establish a bidirectional relationship:
473
+ *
474
+ * ```
475
+ * AtscriptDbReadable ──delegates ops──▶ BaseDbAdapter
476
+ * ◀──reads metadata── (via this._table)
477
+ * ```
478
+ *
479
+ * Adapter authors can access all computed metadata through `this._table`:
480
+ * - `this._table.tableName` — resolved table/collection/view name
481
+ * - `this._table.flatMap` — all fields as dot-notation paths
482
+ * - `this._table.indexes` — computed index definitions
483
+ * - `this._table.primaryKeys` — primary key field names
484
+ * - `this._table.columnMap` — logical → physical column mappings
485
+ * - `this._table.defaults` — default value configurations
486
+ * - `this._table.ignoredFields` — fields excluded from DB
487
+ * - `this._table.uniqueProps` — single-field unique index properties
488
+ * - `this._table.isView` — whether this is a view (vs a table)
489
+ */
490
+ declare abstract class BaseDbAdapter {
491
+ protected _table: AtscriptDbReadable<any, any, any, any, any, any, any>;
492
+ private _metaIdPhysical;
493
+ /**
494
+ * Returns the physical column name of the single @meta.id field (if any).
495
+ * Used to return the user's logical ID instead of the DB-generated ID on insert.
496
+ */
497
+ protected _getMetaIdPhysical(): string | null;
498
+ /**
499
+ * Resolves the correct insertedId: prefers the user-supplied PK value
500
+ * from the data over the DB-generated fallback (e.g. rowid, _id).
501
+ */
502
+ protected _resolveInsertedId(data: Record<string, unknown>, dbGeneratedId: unknown): unknown;
503
+ /** Logger instance — set via {@link registerReadable} from the readable's logger. */
504
+ protected logger: TGenericLogger;
505
+ /** When true, adapter logs DB calls via `logger.debug`. Off by default. */
506
+ protected _verbose: boolean;
507
+ /**
508
+ * Called by {@link AtscriptDbReadable} constructor. Gives the adapter access
509
+ * to the readable's computed metadata for internal use in query rendering,
510
+ * index sync, etc.
511
+ */
512
+ registerReadable(readable: AtscriptDbReadable<any, any, any, any, any, any, any>, logger?: TGenericLogger): void;
513
+ /**
514
+ * Enables or disables verbose (debug-level) logging for this adapter.
515
+ * When disabled, no log strings are constructed — zero overhead.
516
+ */
517
+ setVerbose(enabled: boolean): void;
518
+ /**
519
+ * Logs a debug message if verbose mode is enabled.
520
+ * Adapters call this to log DB operations with zero overhead when disabled.
521
+ */
522
+ protected _log(...args: unknown[]): void;
523
+ /**
524
+ * Runs `fn` inside a database transaction. Nested calls (from related tables
525
+ * within the same async chain) reuse the existing transaction automatically.
526
+ *
527
+ * The generic layer handles nesting detection via `AsyncLocalStorage`.
528
+ * Adapters override `_beginTransaction`, `_commitTransaction`, and
529
+ * `_rollbackTransaction` to provide raw DB-specific transaction primitives.
530
+ */
531
+ withTransaction<T>(fn: () => Promise<T>): Promise<T>;
532
+ /**
533
+ * Returns the opaque transaction state from the current async context.
534
+ * Adapters use this to retrieve DB-specific state (e.g., MongoDB `ClientSession`).
535
+ */
536
+ protected _getTransactionState(): unknown;
537
+ /**
538
+ * Runs `fn` inside the transaction ALS context with the given state.
539
+ * Adapters that override `withTransaction` (e.g., to use MongoDB's
540
+ * `session.withTransaction()` Convenient API) use this to set up the
541
+ * shared context so that nested adapters see the same session.
542
+ * If a context already exists (nesting), it's reused.
543
+ */
544
+ protected _runInTransactionContext<T>(state: unknown, fn: () => Promise<T>): Promise<T>;
545
+ /**
546
+ * Starts a raw transaction. Returns opaque state stored in the async context.
547
+ * Override in adapters that support transactions.
548
+ */
549
+ protected _beginTransaction(): Promise<unknown>;
550
+ /** Commits the raw transaction. Override in adapters that support transactions. */
551
+ protected _commitTransaction(_state: unknown): Promise<void>;
552
+ /** Rolls back the raw transaction. Override in adapters that support transactions. */
553
+ protected _rollbackTransaction(_state: unknown): Promise<void>;
554
+ /**
555
+ * Returns additional validator plugins for this adapter.
556
+ * These are merged with the built-in Atscript validators.
557
+ *
558
+ * Example: MongoDB adapter returns ObjectId validation plugin.
559
+ */
560
+ getValidatorPlugins(): TValidatorPlugin[];
561
+ /**
562
+ * Transforms an ID value for the database.
563
+ * Override to convert string → ObjectId, parse numeric IDs, etc.
564
+ *
565
+ * @param id - The raw ID value.
566
+ * @param fieldType - The annotated type of the ID field.
567
+ * @returns The transformed ID value.
568
+ */
569
+ prepareId(id: unknown, _fieldType: TAtscriptAnnotatedType): unknown;
570
+ /**
571
+ * Whether this adapter supports native patch operations.
572
+ * When `true`, {@link AtscriptDbTable} delegates patch payloads to
573
+ * {@link nativePatch} instead of using the generic decomposition.
574
+ */
575
+ supportsNativePatch(): boolean;
576
+ /**
577
+ * Whether this adapter handles nested objects natively.
578
+ * When `true`, the generic layer skips flattening and
579
+ * passes nested objects as-is to the adapter.
580
+ * MongoDB returns `true`; relational adapters return `false` (default).
581
+ */
582
+ supportsNestedObjects(): boolean;
583
+ /**
584
+ * Whether the DB engine handles static `@db.default "value"` natively
585
+ * via column-level DEFAULT clauses in CREATE TABLE.
586
+ * When `true`, `_applyDefaults()` skips client-side value defaults,
587
+ * letting the DB apply its own DEFAULT. SQL adapters return `true`;
588
+ * document stores (MongoDB) return `false` and apply defaults client-side.
589
+ */
590
+ supportsNativeValueDefaults(): boolean;
591
+ /**
592
+ * Function default names handled natively by this adapter's DB engine.
593
+ * Fields with these defaults are omitted from INSERT when no value is provided,
594
+ * letting the DB apply its own DEFAULT expression (e.g. CURRENT_TIMESTAMP, UUID()).
595
+ *
596
+ * Override in adapters whose DB engine supports function defaults.
597
+ * The generic layer checks this in `_applyDefaults()` to decide whether
598
+ * to generate the value client-side or leave it for the DB.
599
+ */
600
+ nativeDefaultFns(): ReadonlySet<TDbDefaultFn>;
601
+ /**
602
+ * Whether this adapter enforces foreign key constraints natively.
603
+ * When `true`, the generic layer skips application-level cascade/setNull
604
+ * on delete — the DB engine handles it (e.g. SQLite `ON DELETE CASCADE`).
605
+ * When `false` (default), the generic layer implements cascade logic
606
+ * by finding child records and deleting/nullifying them before the parent.
607
+ */
608
+ supportsNativeForeignKeys(): boolean;
609
+ /**
610
+ * Whether this adapter handles `$with` relation loading natively.
611
+ * When `true`, the table layer delegates to {@link loadRelations}
612
+ * instead of using the generic batch-loading strategy.
613
+ *
614
+ * Adapters can use this to implement SQL JOINs, MongoDB `$lookup`,
615
+ * or other DB-native relation loading optimizations.
616
+ *
617
+ * Default: `false` — the table layer uses application-level batch loading.
618
+ */
619
+ supportsNativeRelations(): boolean;
620
+ /**
621
+ * Loads relations onto result rows using adapter-native operations.
622
+ * Only called when {@link supportsNativeRelations} returns `true`.
623
+ *
624
+ * The adapter receives the rows to enrich, the `$with` relation specs,
625
+ * and the table's relation/FK metadata for resolution.
626
+ *
627
+ * @param rows - The result rows to enrich (mutable — add relation properties in place).
628
+ * @param withRelations - The `$with` specs from the query.
629
+ * @param relations - This table's relation metadata (from `@db.rel.to`/`@db.rel.from`).
630
+ * @param foreignKeys - This table's FK metadata (from `@db.rel.FK`).
631
+ * @param tableResolver - Optional callback to resolve annotated types to table metadata (needed for FROM/VIA relations).
632
+ */
633
+ loadRelations(_rows: Array<Record<string, unknown>>, _withRelations: WithRelation[], _relations: ReadonlyMap<string, TDbRelation>, _foreignKeys: ReadonlyMap<string, TDbForeignKey>, _tableResolver?: TTableResolver): Promise<void>;
634
+ /**
635
+ * Applies a patch payload using native database operations.
636
+ * Only called when {@link supportsNativePatch} returns `true`.
637
+ *
638
+ * @param filter - Filter identifying the record to patch.
639
+ * @param patch - The patch payload with array operations.
640
+ * @returns Update result.
641
+ */
642
+ nativePatch(_filter: FilterExpr, _patch: unknown, _ops?: TFieldOps): Promise<TDbUpdateResult>;
643
+ /**
644
+ * Called before field flattening begins.
645
+ * Use to extract table-level adapter-specific annotations.
646
+ *
647
+ * Example: MongoDB adapter extracts `@db.mongo.search.dynamic`.
648
+ */
649
+ onBeforeFlatten?(type: TAtscriptAnnotatedType): void;
650
+ /**
651
+ * Called for each non-nav-descendant field during the build pipeline.
652
+ * Fields nested under navigation relations (`@db.rel.to/from/via`) are
653
+ * never delivered to this callback — adapters do not need to filter them.
654
+ *
655
+ * Use to extract field-level adapter-specific annotations.
656
+ * Example: MongoDB adapter extracts `@db.mongo.search.vector`, `@db.mongo.search.text`.
657
+ */
658
+ onFieldScanned?(field: string, type: TAtscriptAnnotatedType, metadata: TMetadataMap<AtscriptMetadata>): void;
659
+ /**
660
+ * Returns metadata overrides applied during the build pipeline.
661
+ * Called after field scanning/classification, before field descriptors are built.
662
+ *
663
+ * Use this to adjust primary keys, inject synthetic fields, or register
664
+ * unique constraints — instead of mutating metadata via back-references.
665
+ *
666
+ * @param meta - The table metadata (direct reference, not through readable getters).
667
+ */
668
+ getMetadataOverrides?(meta: TableMetadata): TMetadataOverrides | undefined;
669
+ /**
670
+ * Called after all fields are scanned.
671
+ * Use to finalize adapter-specific computed state.
672
+ * Access table metadata via `this._table`.
673
+ */
674
+ onAfterFlatten?(): void;
675
+ /**
676
+ * Returns an adapter-specific table name.
677
+ * For example, MongoDB reads from `@db.mongo.collection`.
678
+ * Return `undefined` to fall back to `@db.table` or the interface name.
679
+ */
680
+ getAdapterTableName?(type: TAtscriptAnnotatedType): string | undefined;
681
+ /**
682
+ * Returns the metadata tag used to mark top-level arrays during flattening.
683
+ * Default: `'db.__topLevelArray'`
684
+ *
685
+ * Override to use adapter-specific tags (e.g., `'db.mongo.__topLevelArray'`).
686
+ */
687
+ getTopLevelArrayTag?(): string;
688
+ /**
689
+ * Resolves the full table name, optionally including the schema prefix.
690
+ * Override for databases that don't support schemas (e.g., SQLite).
691
+ *
692
+ * @param includeSchema - Whether to prepend `schema.` prefix (default: true).
693
+ */
694
+ resolveTableName(includeSchema?: boolean): string;
695
+ /**
696
+ * Template method for index synchronization.
697
+ * Implements the diff algorithm (list → compare → create/drop).
698
+ * Adapters provide the three DB-specific primitives.
699
+ *
700
+ * @example
701
+ * ```typescript
702
+ * async syncIndexes() {
703
+ * await this.syncIndexesWithDiff({
704
+ * listExisting: async () => this.driver.all('PRAGMA index_list(...)'),
705
+ * createIndex: async (index) => this.driver.exec('CREATE INDEX ...'),
706
+ * dropIndex: async (name) => this.driver.exec('DROP INDEX ...'),
707
+ * shouldSkipType: (type) => type === 'fulltext',
708
+ * })
709
+ * }
710
+ * ```
711
+ */
712
+ protected syncIndexesWithDiff(opts: {
713
+ listExisting(): Promise<Array<{
714
+ name: string;
715
+ }>>;
716
+ createIndex(index: TDbIndex): Promise<void>;
717
+ dropIndex(name: string): Promise<void>;
718
+ prefix?: string;
719
+ shouldSkipType?(type: TDbIndex["type"]): boolean;
720
+ }): Promise<void>;
721
+ /**
722
+ * Returns available search indexes for this adapter.
723
+ * UI uses this to show index picker. Override in adapters that support search.
724
+ */
725
+ getSearchIndexes(): TSearchIndexInfo[];
726
+ /**
727
+ * Whether this adapter supports text search.
728
+ * Default: `true` when {@link getSearchIndexes} returns any entries.
729
+ */
730
+ isSearchable(): boolean;
731
+ /**
732
+ * Whether this adapter supports vector similarity search.
733
+ * Override in adapters that support vector search.
734
+ */
735
+ isVectorSearchable(): boolean;
736
+ /**
737
+ * Full-text search. Override in adapters that support search.
738
+ *
739
+ * @param text - Search text.
740
+ * @param query - Filter, sort, limit, etc.
741
+ * @param indexName - Optional search index to target.
742
+ */
743
+ search(_text: string, _query: DbQuery, _indexName?: string): Promise<Array<Record<string, unknown>>>;
744
+ /**
745
+ * Full-text search with count (for paginated search results).
746
+ *
747
+ * @param text - Search text.
748
+ * @param query - Filter, sort, limit, etc.
749
+ * @param indexName - Optional search index to target.
750
+ */
751
+ searchWithCount(_text: string, _query: DbQuery, _indexName?: string): Promise<{
752
+ data: Array<Record<string, unknown>>;
753
+ count: number;
754
+ }>;
755
+ /**
756
+ * Vector similarity search. Override in adapters that support vector search.
757
+ *
758
+ * @param vector - Pre-computed embedding vector.
759
+ * @param query - Filter, sort, limit, etc.
760
+ * @param indexName - Optional vector index to target (for multi-vector documents).
761
+ */
762
+ vectorSearch(_vector: number[], _query: DbQuery, _indexName?: string): Promise<Array<Record<string, unknown>>>;
763
+ /**
764
+ * Vector similarity search with count (for paginated results).
765
+ *
766
+ * @param vector - Pre-computed embedding vector.
767
+ * @param query - Filter, sort, limit, etc.
768
+ * @param indexName - Optional vector index to target (for multi-vector documents).
769
+ */
770
+ vectorSearchWithCount(_vector: number[], _query: DbQuery, _indexName?: string): Promise<{
771
+ data: Array<Record<string, unknown>>;
772
+ count: number;
773
+ }>;
774
+ /**
775
+ * Fetches records and total count in one call.
776
+ * Default: two parallel calls. Adapters may override for single-query optimization.
777
+ */
778
+ findManyWithCount(query: DbQuery): Promise<{
779
+ data: Array<Record<string, unknown>>;
780
+ count: number;
781
+ }>;
782
+ /**
783
+ * Executes an aggregate query (GROUP BY + aggregate functions).
784
+ * Default throws — override in adapters that support aggregation.
785
+ */
786
+ aggregate(_query: DbQuery): Promise<Array<Record<string, unknown>>>;
787
+ abstract insertOne(data: Record<string, unknown>): Promise<TDbInsertResult>;
788
+ abstract insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
789
+ abstract replaceOne(filter: FilterExpr, data: Record<string, unknown>): Promise<TDbUpdateResult>;
790
+ abstract updateOne(filter: FilterExpr, data: Record<string, unknown>, ops?: TFieldOps): Promise<TDbUpdateResult>;
791
+ abstract deleteOne(filter: FilterExpr): Promise<TDbDeleteResult>;
792
+ abstract findOne(query: DbQuery): Promise<Record<string, unknown> | null>;
793
+ abstract findMany(query: DbQuery): Promise<Array<Record<string, unknown>>>;
794
+ abstract count(query: DbQuery): Promise<number>;
795
+ abstract updateMany(filter: FilterExpr, data: Record<string, unknown>, ops?: TFieldOps): Promise<TDbUpdateResult>;
796
+ abstract replaceMany(filter: FilterExpr, data: Record<string, unknown>): Promise<TDbUpdateResult>;
797
+ abstract deleteMany(filter: FilterExpr): Promise<TDbDeleteResult>;
798
+ /**
799
+ * Synchronizes indexes between the Atscript definitions and the database.
800
+ * Uses `this._table.indexes` for the full index definitions.
801
+ */
802
+ abstract syncIndexes(): Promise<void>;
803
+ /**
804
+ * Ensures the table exists in the database, creating it if needed.
805
+ * Uses `this._table.tableName`, `this._table.schema`, etc.
806
+ */
807
+ abstract ensureTable(): Promise<void>;
808
+ /**
809
+ * Synchronizes foreign key constraints between Atscript definitions and the database.
810
+ * Uses `this._table.foreignKeys` for the full FK definitions.
811
+ * Optional — only relational adapters need to implement this.
812
+ */
813
+ /**
814
+ * Post-sync hook called after all table operations (columns, indexes, FKs)
815
+ * are complete. Adapters can use this for finalization work such as
816
+ * resetting auto-increment sequences to match existing data.
817
+ * Optional — most adapters don't need this.
818
+ */
819
+ afterSyncTable?(): Promise<void>;
820
+ syncForeignKeys?(): Promise<void>;
821
+ /**
822
+ * Drops FK constraints identified by their canonical local column key.
823
+ * Called by the sync executor before column operations to remove stale FKs
824
+ * that would otherwise block ALTER COLUMN.
825
+ *
826
+ * @param fkFieldKeys - Canonical FK keys (sorted local field names, comma-joined).
827
+ */
828
+ dropForeignKeys?(fkFieldKeys: string[]): Promise<void>;
829
+ /**
830
+ * Returns the desired table options from Atscript annotations.
831
+ * Called after onBeforeFlatten/onAfterFlatten, so adapter-specific state
832
+ * (e.g., engine, charset, capped options) is populated.
833
+ *
834
+ * Values are stringified for consistent comparison.
835
+ * Returns undefined if the adapter has no table-level options.
836
+ */
837
+ getDesiredTableOptions?(): TExistingTableOption[];
838
+ /**
839
+ * Returns the current table options from the live database.
840
+ * Primary source for option diffing (DB-first strategy).
841
+ *
842
+ * Returns undefined if the adapter cannot introspect table options.
843
+ * In that case, schema sync falls back to stored snapshot.
844
+ */
845
+ getExistingTableOptions?(): Promise<TExistingTableOption[]>;
846
+ /**
847
+ * Applies non-destructive table option changes (e.g., MySQL ALTER TABLE ENGINE=X).
848
+ * Called for each non-destructive change in the diff.
849
+ * Destructive changes go through dropTable+ensureTable or recreateTable.
850
+ */
851
+ applyTableOptions?(changes: TTableOptionDiff["changed"]): Promise<void>;
852
+ /**
853
+ * Returns the set of option keys where a value change requires table recreation.
854
+ * Default: empty (all changes are non-destructive).
855
+ */
856
+ destructiveOptionKeys?(): ReadonlySet<string>;
857
+ /**
858
+ * Checks whether the table/collection already exists in the database.
859
+ * Used by schema sync to determine create vs in-sync status for
860
+ * adapters that don't implement column introspection (e.g. MongoDB).
861
+ */
862
+ tableExists?(): Promise<boolean>;
863
+ /**
864
+ * Returns existing columns from the database via introspection.
865
+ * Used by schema sync for column diffing.
866
+ * Optional — schema-less adapters (MongoDB) skip this.
867
+ */
868
+ getExistingColumns?(): Promise<TExistingColumn[]>;
869
+ /**
870
+ * When true, the adapter can handle column type changes in-place
871
+ * (e.g. MySQL's ALTER TABLE MODIFY COLUMN) without requiring table recreation.
872
+ * The generic sync layer will delegate type changes to {@link syncColumns}
873
+ * instead of requiring `@db.sync.method "recreate"` or `"drop"`.
874
+ */
875
+ supportsColumnModify?: boolean;
876
+ /**
877
+ * Applies column diff (ALTER TABLE ADD COLUMN, etc.).
878
+ * The generic layer computes the diff; adapters execute DB-specific DDL.
879
+ * Optional — only relational adapters implement this.
880
+ */
881
+ syncColumns?(diff: TColumnDiff): Promise<TSyncColumnResult>;
882
+ /**
883
+ * Recreates the table losslessly: create temp → copy data → drop old → rename.
884
+ * Used by `@db.sync.method "recreate"` when structural changes can't be ALTER'd.
885
+ * Optional — only relational adapters implement this.
886
+ */
887
+ recreateTable?(): Promise<void>;
888
+ /**
889
+ * Drops the table entirely.
890
+ * Used by `@db.sync.method "drop"` for tables with ephemeral data.
891
+ * Optional — only relational adapters implement this.
892
+ */
893
+ dropTable?(): Promise<void>;
894
+ /**
895
+ * Drops one or more columns from the table.
896
+ * Used by schema sync to remove stale columns no longer in the schema.
897
+ * Optional — only relational adapters implement this.
898
+ */
899
+ dropColumns?(columns: string[]): Promise<void>;
900
+ /**
901
+ * Drops a table by name (without needing a registered readable).
902
+ * Used by schema sync to remove tables no longer in the schema.
903
+ * Optional — only relational adapters implement this.
904
+ */
905
+ dropTableByName?(tableName: string): Promise<void>;
906
+ /**
907
+ * Drops a view by name (without needing a registered readable).
908
+ * Used by schema sync to remove views no longer in the schema.
909
+ * Optional — only relational adapters implement this.
910
+ */
911
+ dropViewByName?(viewName: string): Promise<void>;
912
+ /**
913
+ * Renames a table/collection from `oldName` to the adapter's current table name.
914
+ * Used by schema sync when `@db.table.renamed` is present.
915
+ * Optional — only relational adapters implement this.
916
+ */
917
+ renameTable?(oldName: string): Promise<void>;
918
+ /**
919
+ * Introspects columns for an arbitrary table name (not the adapter's own table).
920
+ * Used by schema sync `plan()` to inspect a table under its old name before rename.
921
+ * Optional — only relational adapters implement this.
922
+ */
923
+ getExistingColumnsForTable?(tableName: string): Promise<TExistingColumn[]>;
924
+ /**
925
+ * Maps a field's metadata to the adapter's native column type string.
926
+ * Receives the full field descriptor (design type, annotations, PK status, etc.)
927
+ * so adapters can produce context-aware types (e.g., `VARCHAR(255)` from maxLength).
928
+ * Used by schema sync to detect column type changes.
929
+ * Optional — adapters that don't implement this skip type change detection.
930
+ */
931
+ typeMapper?(field: TDbFieldMeta): string;
932
+ /**
933
+ * Returns a value formatter for a field, or undefined if no formatting is needed.
934
+ * Called once per field during build. The returned formatter(s) are cached and
935
+ * applied during write preparation, filter translation, and read reconstruction.
936
+ *
937
+ * Can return:
938
+ * - A bare function: used as `toStorage` only (write + filter paths)
939
+ * - A `TValueFormatterPair`: `toStorage` for writes/filters, `fromStorage` for reads
940
+ * - `undefined`: no formatting needed
941
+ *
942
+ * This avoids per-value method dispatch — only fields that need formatting
943
+ * get a formatter function, and the generic layer skips fields without one.
944
+ *
945
+ * Example: MySQL returns a pair for TIMESTAMP-mapped fields (epoch ms ↔ datetime string).
946
+ */
947
+ formatValue?(field: TDbFieldMeta): TValueFormatterPair | ((value: unknown) => unknown) | undefined;
948
+ }
949
+ //#endregion
950
+ //#region src/strategies/field-mapping.d.ts
951
+ /**
952
+ * Strategy for mapping data between logical field shapes and physical storage.
953
+ * Two implementations: {@link DocumentFieldMapper} (nested objects, NoSQL)
954
+ * and `RelationalFieldMapper` (flattened columns, SQL).
955
+ */
956
+ declare abstract class FieldMappingStrategy {
957
+ abstract reconstructFromRead(row: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
958
+ abstract translateQuery(query: Uniquery, meta: TableMetadata): DbQuery;
959
+ abstract translateAggregateQuery(query: AggregateQuery, meta: TableMetadata): DbQuery;
960
+ /**
961
+ * Recursively walks a filter expression, applying adapter-specific value
962
+ * formatting via `formatFilterValue`. Shared by both document and relational
963
+ * mappers (relational adds key-renaming via `translateFilterWithRename`).
964
+ */
965
+ translateFilter(filter: FilterExpr, meta: TableMetadata): FilterExpr;
966
+ abstract prepareForWrite(payload: Record<string, unknown>, meta: TableMetadata, adapter: BaseDbAdapter): Record<string, unknown>;
967
+ abstract translatePatchKeys(update: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
968
+ /**
969
+ * Coerces field values from storage representation to JS types
970
+ * (booleans from 0/1, decimals from number to string).
971
+ */
972
+ protected coerceFieldValues(row: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
973
+ /**
974
+ * Applies adapter-specific fromStorage formatting to a row read from the database.
975
+ * Converts storage representations back to JS values (e.g. Date → epoch ms).
976
+ */
977
+ protected applyFromStorageFormatters(row: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
978
+ /**
979
+ * Sets a value at a dot-notation path, creating intermediate objects as needed.
980
+ */
981
+ protected setNestedValue(obj: Record<string, unknown>, dotPath: string, value: unknown): void;
982
+ /**
983
+ * If all children of a flattened parent are null, collapse the parent to null.
984
+ */
985
+ protected reconstructNullParent(obj: Record<string, unknown>, parentPath: string, meta: TableMetadata): void;
986
+ /**
987
+ * Applies adapter-specific value formatting to a single filter value.
988
+ * Handles direct values, operator objects ({$gt: v}), and $in/$nin arrays.
989
+ */
990
+ protected formatFilterValue(physicalName: string, value: unknown, meta: TableMetadata): unknown;
991
+ /**
992
+ * Applies adapter-specific value formatting to prepared (physical-named) data.
993
+ */
994
+ protected formatWriteValues(data: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
995
+ /**
996
+ * Prepares primary key values and strips ignored fields.
997
+ * Shared pre-processing for both document and relational write paths.
998
+ */
999
+ protected prepareCommon(data: Record<string, unknown>, meta: TableMetadata, adapter: BaseDbAdapter): void;
1000
+ }
1001
+ /**
1002
+ * Field mapper for document-oriented adapters (e.g. MongoDB).
1003
+ * Nested objects are preserved as-is. Only applies column renames and
1004
+ * value coercion.
1005
+ */
1006
+ declare class DocumentFieldMapper extends FieldMappingStrategy {
1007
+ reconstructFromRead(row: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
1008
+ translateQuery(query: Uniquery, meta: TableMetadata): DbQuery;
1009
+ translateAggregateQuery(query: AggregateQuery, meta: TableMetadata): DbQuery;
1010
+ prepareForWrite(payload: Record<string, unknown>, meta: TableMetadata, adapter: BaseDbAdapter): Record<string, unknown>;
1011
+ translatePatchKeys(update: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
1012
+ }
1013
+ //#endregion
1014
+ //#region src/table/db-readable.d.ts
1015
+ /**
1016
+ * Extracts nav prop names from a query's `$with` array.
1017
+ * Returns `never` when `$with` is absent → all nav props stripped from response.
1018
+ */
1019
+ type ExtractWith<Q> = Q extends {
1020
+ controls: {
1021
+ $with: Array<{
1022
+ name: infer N extends string;
1023
+ }>;
1024
+ };
1025
+ } ? N : never;
1026
+ /**
1027
+ * Computes the response type for a query:
1028
+ * - Strips all nav props from the base DataType
1029
+ * - Adds back only the nav props requested via `$with`
1030
+ *
1031
+ * When no `$with` is provided, result is `Omit<DataType, keyof NavType>`.
1032
+ * When `$with: [{ name: 'author' }]`, result includes `author` from DataType.
1033
+ * When the query type is not a literal (e.g. a variable typed as `Uniquery`),
1034
+ * falls back to `DataType` (all nav props optional, as declared).
1035
+ */
1036
+ type DbResponse<Data, Nav, Q> = [keyof Nav] extends [never] ? Data : Omit<Data, keyof Nav & string> & Pick<Data, ExtractWith<Q> & keyof Data & string>;
1037
+ /**
1038
+ * Resolves the design type from an annotated type.
1039
+ * Encapsulates the `kind === ''` check and fallback logic that
1040
+ * otherwise trips up every adapter author.
1041
+ *
1042
+ * For union types (e.g., from flattened `{...} | {...}` objects):
1043
+ * - If all members resolve to the same type → returns that type (strong type)
1044
+ * - If members disagree → returns `'union'` (out of scope for type management)
1045
+ */
1046
+ declare function resolveDesignType(fieldType: TAtscriptAnnotatedType): string;
1047
+ /**
1048
+ * Shared read-only database abstraction driven by Atscript annotations.
1049
+ *
1050
+ * Contains all field metadata computation, read operations, query translation,
1051
+ * relation loading, and result reconstruction. Extended by both
1052
+ * {@link AtscriptDbTable} (adds write operations) and {@link AtscriptDbView}
1053
+ * (adds view plan/DDL).
1054
+ */
1055
+ 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>> {
1056
+ protected readonly _type: T;
1057
+ protected readonly adapter: A;
1058
+ protected readonly logger: TGenericLogger;
1059
+ protected readonly _tableResolver?: TTableResolver | undefined;
1060
+ /** Resolved table/collection/view name. */
1061
+ readonly tableName: string;
1062
+ /** Database schema/namespace from `@db.schema` (if set). */
1063
+ readonly schema: string | undefined;
1064
+ /** Sync method from `@db.sync.method` ('drop' | 'recreate' | undefined). */
1065
+ protected readonly _syncMethod: "drop" | "recreate" | undefined;
1066
+ /** Previous table/view name from `@db.table.renamed` or `@db.view.renamed`. */
1067
+ readonly renamedFrom: string | undefined;
1068
+ /** Computed metadata for this table/view. Built lazily on first access. */
1069
+ protected readonly _meta: TableMetadata;
1070
+ /** Strategy for mapping between logical field shapes and physical storage. */
1071
+ protected readonly _fieldMapper: FieldMappingStrategy;
1072
+ protected _writeTableResolver?: TWriteTableResolver;
1073
+ constructor(_type: T, adapter: A, logger?: TGenericLogger, _tableResolver?: TTableResolver | undefined);
1074
+ /** Ensures metadata is built. Called before any metadata access. */
1075
+ protected _ensureBuilt(): void;
1076
+ /** Whether this readable is a view (overridden in AtscriptDbView). */
1077
+ get isView(): boolean;
1078
+ /** Returns the underlying adapter with its concrete type preserved. */
1079
+ getAdapter(): A;
1080
+ /** The raw annotated type. */
1081
+ get type(): TAtscriptAnnotatedType<TAtscriptTypeObject>;
1082
+ /** Lazily-built flat map of all fields (dot-notation paths → annotated types). */
1083
+ get flatMap(): Map<string, TAtscriptAnnotatedType>;
1084
+ /** All computed indexes from `@db.index.*` annotations. */
1085
+ get indexes(): Map<string, TDbIndex>;
1086
+ /** Primary key field names from `@meta.id`. */
1087
+ get primaryKeys(): readonly string[];
1088
+ /** Original `@meta.id` field names as declared in the schema (before adapter manipulation). */
1089
+ get originalMetaIdFields(): readonly string[];
1090
+ /** Dimension fields from `@db.column.dimension`. */
1091
+ get dimensions(): readonly string[];
1092
+ /** Measure fields from `@db.column.measure`. */
1093
+ get measures(): readonly string[];
1094
+ /** Sync method for structural changes: 'drop' (lossy), 'recreate' (lossless), or undefined (manual). */
1095
+ get syncMethod(): "drop" | "recreate" | undefined;
1096
+ /** Logical → physical column name mapping from `@db.column`. */
1097
+ get columnMap(): ReadonlyMap<string, string>;
1098
+ /** Default values from `@db.default.*`. */
1099
+ get defaults(): ReadonlyMap<string, TDbDefaultValue>;
1100
+ /** Fields excluded from DB via `@db.ignore`. */
1101
+ get ignoredFields(): ReadonlySet<string>;
1102
+ /** Navigational fields (`@db.rel.to` / `@db.rel.from`) — not stored as columns. */
1103
+ get navFields(): ReadonlySet<string>;
1104
+ /** Single-field unique index properties. */
1105
+ get uniqueProps(): ReadonlySet<string>;
1106
+ /** Foreign key constraints from `@db.rel.FK` annotations. */
1107
+ get foreignKeys(): ReadonlyMap<string, TDbForeignKey>;
1108
+ /** Navigational relation metadata from `@db.rel.to` / `@db.rel.from`. */
1109
+ get relations(): ReadonlyMap<string, TDbRelation>;
1110
+ /** The underlying database adapter instance. */
1111
+ get dbAdapter(): A;
1112
+ /**
1113
+ * Enables or disables verbose (debug-level) DB call logging for this table/view.
1114
+ * When disabled (default), no log strings are constructed — zero overhead.
1115
+ */
1116
+ setVerbose(enabled: boolean): void;
1117
+ /** Precomputed logical dot-path → physical column name map. */
1118
+ get pathToPhysical(): ReadonlyMap<string, string>;
1119
+ /** Precomputed physical column name → logical dot-path map (inverse). */
1120
+ get physicalToPath(): ReadonlyMap<string, string>;
1121
+ /** Descriptor for the primary ID field(s). */
1122
+ getIdDescriptor(): TIdDescriptor;
1123
+ /**
1124
+ * Pre-computed field metadata for adapter use.
1125
+ */
1126
+ get fieldDescriptors(): readonly TDbFieldMeta[];
1127
+ /**
1128
+ * Creates a new validator with custom options.
1129
+ */
1130
+ createValidator(opts?: Partial<TValidatorOptions>): Validator<T, DataType>;
1131
+ /**
1132
+ * Finds a single record matching the query.
1133
+ * The return type automatically excludes nav props unless they are
1134
+ * explicitly requested via `$with`.
1135
+ */
1136
+ findOne<Q extends Uniquery<OwnProps, NavType>>(query: Q): Promise<DbResponse<DataType, NavType, Q> | null>;
1137
+ /**
1138
+ * Finds all records matching the query.
1139
+ * The return type automatically excludes nav props unless they are
1140
+ * explicitly requested via `$with`.
1141
+ */
1142
+ findMany<Q extends Uniquery<OwnProps, NavType>>(query: Q): Promise<Array<DbResponse<DataType, NavType, Q>>>;
1143
+ /**
1144
+ * Counts records matching the query.
1145
+ */
1146
+ count(query?: Uniquery<OwnProps, NavType>): Promise<number>;
1147
+ /**
1148
+ * Finds records and total count in a single logical call.
1149
+ */
1150
+ findManyWithCount<Q extends Uniquery<OwnProps, NavType>>(query: Q): Promise<{
1151
+ data: Array<DbResponse<DataType, NavType, Q>>;
1152
+ count: number;
1153
+ }>;
1154
+ /**
1155
+ * Executes an aggregate query with GROUP BY and aggregate functions.
1156
+ *
1157
+ * Validates:
1158
+ * - Plain fields in $select are a subset of $groupBy
1159
+ * - When dimensions/measures are defined (strict mode): $groupBy fields
1160
+ * must be dimensions, aggregate $field values must be measures (or '*')
1161
+ *
1162
+ * Translates field names, delegates to adapter.aggregate(),
1163
+ * then reverse-maps and applies fromStorage formatters on results.
1164
+ */
1165
+ aggregate(query: AggregateQuery): Promise<Array<Record<string, unknown>>>;
1166
+ /** Whether the underlying adapter supports text search. */
1167
+ isSearchable(): boolean;
1168
+ /** Returns available search indexes from the adapter. */
1169
+ getSearchIndexes(): TSearchIndexInfo[];
1170
+ /**
1171
+ * Full-text search with query translation and result reconstruction.
1172
+ */
1173
+ search<Q extends Uniquery<OwnProps, NavType>>(text: string, query: Q, indexName?: string): Promise<Array<DbResponse<DataType, NavType, Q>>>;
1174
+ /**
1175
+ * Full-text search with count for paginated search results.
1176
+ */
1177
+ searchWithCount<Q extends Uniquery<OwnProps, NavType>>(text: string, query: Q, indexName?: string): Promise<{
1178
+ data: Array<DbResponse<DataType, NavType, Q>>;
1179
+ count: number;
1180
+ }>;
1181
+ /** Whether the underlying adapter supports vector similarity search. */
1182
+ isVectorSearchable(): boolean;
1183
+ /**
1184
+ * Vector similarity search with query translation and result reconstruction.
1185
+ *
1186
+ * Overloads:
1187
+ * - `vectorSearch(vector, query?)` — uses default vector index
1188
+ * - `vectorSearch(indexName, vector, query?)` — targets a specific vector index
1189
+ */
1190
+ vectorSearch<Q extends Uniquery<OwnProps, NavType>>(vectorOrIndex: number[] | string, maybeVectorOrQuery?: number[] | Q, maybeQuery?: Q): Promise<Array<DbResponse<DataType, NavType, Q>>>;
1191
+ /**
1192
+ * Vector similarity search with count for paginated results.
1193
+ *
1194
+ * Overloads:
1195
+ * - `vectorSearchWithCount(vector, query?)` — uses default vector index
1196
+ * - `vectorSearchWithCount(indexName, vector, query?)` — targets a specific vector index
1197
+ */
1198
+ vectorSearchWithCount<Q extends Uniquery<OwnProps, NavType>>(vectorOrIndex: number[] | string, maybeVectorOrQuery?: number[] | Q, maybeQuery?: Q): Promise<{
1199
+ data: Array<DbResponse<DataType, NavType, Q>>;
1200
+ count: number;
1201
+ }>;
1202
+ /** Resolves overloaded vector search arguments into canonical form. */
1203
+ private _resolveVectorSearchArgs;
1204
+ /**
1205
+ * Finds a single record by any type-compatible identifier — primary key
1206
+ * or single-field unique index.
1207
+ * The return type excludes nav props unless `$with` is provided in controls.
1208
+ *
1209
+ * ```typescript
1210
+ * // Without relations — nav props stripped from result
1211
+ * const user = await table.findById('123')
1212
+ *
1213
+ * // With relations — only requested nav props appear
1214
+ * const user = await table.findById('123', { controls: { $with: [{ name: 'posts' }] } })
1215
+ * ```
1216
+ */
1217
+ findById<Q extends {
1218
+ controls?: UniqueryControls<OwnProps, NavType>;
1219
+ } = Record<string, never>>(id: IdType, query?: Q): Promise<DbResponse<DataType, NavType, Q> | null>;
1220
+ /**
1221
+ * Resolves an id value into a filter expression.
1222
+ */
1223
+ protected _resolveIdFilter(id: unknown): FilterExpr | null;
1224
+ /**
1225
+ * Attempts to build a single-field filter `{ field: preparedId }`.
1226
+ */
1227
+ private _tryFieldFilter;
1228
+ /**
1229
+ * Public entry point for relation loading. Used by adapters for nested $with delegation.
1230
+ */
1231
+ loadRelations(rows: Array<Record<string, unknown>>, withRelations: WithRelation[]): Promise<void>;
1232
+ /**
1233
+ * Finds the FK entry that connects a `@db.rel.to` relation to its target.
1234
+ * Thin wrapper — delegates to relation-loader for shared use with db-table.ts write path.
1235
+ */
1236
+ protected _findFKForRelation(relation: TDbRelation): {
1237
+ localFields: string[];
1238
+ targetFields: string[];
1239
+ } | undefined;
1240
+ /**
1241
+ * Finds a FK on a remote table that points back to this table.
1242
+ * Thin wrapper — delegates to relation-loader for shared use with db-table.ts write path.
1243
+ */
1244
+ protected _findRemoteFK(targetTable: {
1245
+ foreignKeys: ReadonlyMap<string, TDbForeignKey>;
1246
+ }, thisTableName: string, alias?: string): TDbForeignKey | undefined;
1247
+ }
1248
+ //#endregion
1249
+ export { Uniquery$1 as $, TDbForeignKey as A, TExistingColumn as B, TCascadeTarget as C, TDbDefaultValue as D, TDbDefaultFn as E, TDbInsertResult as F, TMetadataOverrides as G, TFkLookupResolver as H, TDbReferentialAction as I, TTableOptionDiff as J, TSearchIndexInfo as K, TDbRelation as L, TDbIndexField as M, TDbIndexType as N, TDbDeleteResult as O, TDbInsertManyResult as P, TypedWithRelation as Q, TDbStorageType as R, TCascadeResolver as S, TDbCollation as T, TFkLookupTarget as U, TExistingTableOption as V, TIdDescriptor as W, TValueFormatterPair as X, TTableResolver as Y, TWriteTableResolver as Z, DbQuery as _, FieldMappingStrategy as a, NavPropsOf$1 as b, NoopLogger as c, AggregateExpr$1 as d, UniqueryControls$1 as et, AggregateFn as f, DbControls as g, AtscriptDbWritable as h, DocumentFieldMapper as i, TDbIndex as j, TDbFieldMeta as k, TGenericLogger as l, AggregateResult as m, DbResponse as n, UniquSelect as nt, BaseDbAdapter as o, AggregateQuery$1 as p, TSyncColumnResult as q, resolveDesignType as r, TableMetadata as s, AtscriptDbReadable as t, WithRelation$1 as tt, AggregateControls as u, FieldOpsFor as v, TColumnDiff as w, OwnPropsOf$1 as x, FilterExpr$1 as y, TDbUpdateResult as z };