@atscript/db 0.1.58 → 0.1.60

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.
@@ -1,6 +1,6 @@
1
1
  import { u as TFieldOps } from "./ops-DXJ4Zw0P.cjs";
2
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, TSerializedAnnotatedType, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
3
+ 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";
4
4
 
5
5
  //#region src/query/uniqu-select.d.ts
6
6
  /**
@@ -71,6 +71,7 @@ declare class TableMetadata {
71
71
  flatMap: Map<string, TAtscriptAnnotatedType>;
72
72
  fieldDescriptors: readonly TDbFieldMeta[];
73
73
  primaryKeys: string[];
74
+ preferredId: string[];
74
75
  originalMetaIdFields: string[];
75
76
  indexes: Map<string, TDbIndex>;
76
77
  foreignKeys: Map<string, TDbForeignKey>;
@@ -102,6 +103,7 @@ declare class TableMetadata {
102
103
  /** Leaf field descriptors indexed by logical path (write/patch/filter paths). */
103
104
  leafByLogical: Map<string, TDbFieldMeta>;
104
105
  private _built;
106
+ private _identifications?;
105
107
  private _collateMap;
106
108
  private _columnFromMap;
107
109
  constructor(nestedObjects: boolean);
@@ -156,6 +158,16 @@ declare class TableMetadata {
156
158
  */
157
159
  private _resolveFkTargetFields;
158
160
  private _finalizeIndexes;
161
+ /**
162
+ * Captures legitimate row-identifier shapes from the metadata: primary key
163
+ * (when present) followed by every unique index. Must run BEFORE
164
+ * `_finalizeIndexes` rewrites `index.fields[i].name` from logical to
165
+ * physical, so the field lists stay logical.
166
+ */
167
+ private _buildIdentifications;
168
+ /** Legitimate row-identifier shapes — primary key first, then each unique index. */
169
+ getIdentifications(): readonly TIdentification[];
170
+ private _resolvePreferredId;
159
171
  }
160
172
  //#endregion
161
173
  //#region src/types.d.ts
@@ -205,6 +217,7 @@ interface TMetaResponse {
205
217
  vectorSearchable: boolean;
206
218
  searchIndexes: TSearchIndexInfo[];
207
219
  primaryKeys: string[];
220
+ preferredId: string[];
208
221
  relations: TRelationInfo[];
209
222
  fields: Record<string, TFieldMeta>;
210
223
  type: TSerializedAnnotatedType;
@@ -266,21 +279,13 @@ interface TDbActionInfo {
266
279
  /**
267
280
  * Stringified gate predicate (`fn.toString()`). Present only for `'row'`
268
281
  * and `'rows'` level actions whose decorator declared a `disabled` function.
269
- * The UI evaluates against a level-specific scope to grey-out / hide the
282
+ * The function is the batch shape `(rows: TRow[]) => boolean[]` (sync). The
283
+ * UI evaluates against a level-specific scope to grey-out / hide the
270
284
  * button. The server has already enforced this predicate before the
271
285
  * action's handler ran — the server is authoritative; this field is purely
272
286
  * a UI hint.
273
287
  */
274
288
  disabled?: string;
275
- /**
276
- * Optional dev-supplied list of dot-notation paths over the row that the
277
- * `disabled` predicate references. Plain `string[]` in v1 (a typed
278
- * `PathOf<TRow>[]` upgrade is a documented follow-up). The UI unions these
279
- * into `$select` across all actions on a table. When absent, the UI parses
280
- * `disabled` itself. When present, the UI uses this list verbatim — the
281
- * server does NOT auto-derive or merge.
282
- */
283
- requiredFields?: string[];
284
289
  }
285
290
  interface TDbInsertResult {
286
291
  insertedId: unknown;
@@ -328,6 +333,13 @@ interface TIdDescriptor {
328
333
  /** Whether this is a composite key (multiple fields). */
329
334
  isComposite: boolean;
330
335
  }
336
+ /** A legitimate row-identifier shape: primary key or a unique index. */
337
+ interface TIdentification {
338
+ /** Logical (path) field names that form this identifier. */
339
+ fields: readonly string[];
340
+ /** `'primaryKey'` for the PK; the unique-index name otherwise. */
341
+ source: string;
342
+ }
331
343
  type TDbStorageType = "column" | "flattened" | "json";
332
344
  interface TDbFieldMeta {
333
345
  /** The dot-notation path to this field (logical name). */
@@ -477,12 +489,13 @@ interface TMetadataOverrides {
477
489
  *
478
490
  * Typically provided by the driver/registry (e.g. `DbSpace.getTable`).
479
491
  */
480
- type TTableResolver = (type: TAtscriptAnnotatedType) => Pick<AtscriptDbTableLike, "findMany" | "loadRelations" | "primaryKeys" | "relations" | "foreignKeys"> | undefined;
492
+ type TTableResolver = (type: TAtscriptAnnotatedType) => Pick<AtscriptDbTableLike, "findMany" | "loadRelations" | "primaryKeys" | "preferredId" | "relations" | "foreignKeys"> | undefined;
481
493
  /** Minimal table interface used by the table resolver. Avoids circular dependency with AtscriptDbTable. */
482
494
  interface AtscriptDbTableLike {
483
495
  findMany(query: unknown): Promise<Array<Record<string, unknown>>>;
484
496
  loadRelations(rows: Array<Record<string, unknown>>, withRelations: WithRelation[]): Promise<void>;
485
497
  primaryKeys: readonly string[];
498
+ preferredId: readonly string[];
486
499
  relations: ReadonlyMap<string, TDbRelation>;
487
500
  foreignKeys: ReadonlyMap<string, TDbForeignKey>;
488
501
  getMetadata(): TableMetadata;
@@ -597,12 +610,6 @@ interface TDbRelation {
597
610
  */
598
611
  declare abstract class BaseDbAdapter {
599
612
  protected _table: AtscriptDbReadable<any, any, any, any, any, any, any>;
600
- private _metaIdPhysical;
601
- /**
602
- * Returns the physical column name of the single @meta.id field (if any).
603
- * Used to return the user's logical ID instead of the DB-generated ID on insert.
604
- */
605
- protected _getMetaIdPhysical(): string | null;
606
613
  /**
607
614
  * Resolves the correct insertedId: prefers the user-supplied PK value
608
615
  * from the data over the DB-generated fallback (e.g. rowid, _id).
@@ -1185,6 +1192,7 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
1185
1192
  /** Strategy for mapping between logical field shapes and physical storage. */
1186
1193
  protected readonly _fieldMapper: FieldMappingStrategy;
1187
1194
  protected _writeTableResolver?: TWriteTableResolver;
1195
+ private _metaIdPhysical;
1188
1196
  constructor(_type: T, adapter: A, logger?: TGenericLogger, _tableResolver?: TTableResolver | undefined);
1189
1197
  /** Ensures metadata is built. Called before any metadata access. */
1190
1198
  protected _ensureBuilt(): void;
@@ -1207,8 +1215,18 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
1207
1215
  get indexes(): Map<string, TDbIndex>;
1208
1216
  /** Primary key field names from `@meta.id`. */
1209
1217
  get primaryKeys(): readonly string[];
1210
- /** Original `@meta.id` field names as declared in the schema (before adapter manipulation). */
1211
- get originalMetaIdFields(): readonly string[];
1218
+ /** Preferred row identifier field names. Defaults to primary keys. */
1219
+ get preferredId(): readonly string[];
1220
+ /** Legitimate row-identifier shapes (primary key + every unique index). */
1221
+ get identifications(): readonly TIdentification[];
1222
+ /**
1223
+ * Physical column name of the single `@meta.id` field, or `null` when the
1224
+ * schema has zero or multiple `@meta.id` fields. Used by adapters to return
1225
+ * the user's logical ID instead of the DB-generated one on insert.
1226
+ *
1227
+ * @internal Adapter-facing surface; not part of the consumer API.
1228
+ */
1229
+ get metaIdPhysical(): string | null;
1212
1230
  /** Dimension fields from `@db.column.dimension`. */
1213
1231
  get dimensions(): readonly string[];
1214
1232
  /** Measure fields from `@db.column.measure`. */
@@ -1368,4 +1386,4 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
1368
1386
  }, thisTableName: string, alias?: string): TDbForeignKey | undefined;
1369
1387
  }
1370
1388
  //#endregion
1371
- export { TSyncColumnResult as $, TDbDefaultValue as A, TDbRelation as B, TCrudPermissions as C, TDbActionProcessor as D, TDbActionLevel as E, TDbIndexField as F, TFieldMeta as G, TDbUpdateResult as H, TDbIndexType as I, TIdDescriptor as J, TFkLookupResolver as K, TDbInsertManyResult as L, TDbFieldMeta as M, TDbForeignKey as N, TDbCollation as O, TDbIndex as P, TSearchIndexInfo as Q, TDbInsertResult as R, TCrudOp as S, TDbActionIntent as T, TExistingColumn as U, TDbStorageType as V, TExistingTableOption as W, TMetadataOverrides as X, TMetaResponse as Y, TRelationInfo as Z, NavPropsOf$1 as _, FieldMappingStrategy as a, Uniquery$1 as at, TCascadeTarget as b, AggregateExpr$1 as c, TableMetadata as ct, AggregateResult as d, UniquSelect as dt, TTableOptionDiff as et, AtscriptDbWritable as f, FilterExpr$1 as g, FieldOpsFor as h, DocumentFieldMapper as i, TypedWithRelation as it, TDbDeleteResult as j, TDbDefaultFn as k, AggregateFn as l, NoopLogger as lt, DbQuery as m, DbResponse as n, TValueFormatterPair as nt, BaseDbAdapter as o, UniqueryControls$1 as ot, DbControls as p, TFkLookupTarget as q, resolveDesignType as r, TWriteTableResolver as rt, AggregateControls as s, WithRelation$1 as st, AtscriptDbReadable as t, TTableResolver as tt, AggregateQuery$1 as u, TGenericLogger as ut, OwnPropsOf$1 as v, TDbActionInfo as w, TColumnDiff as x, TCascadeResolver as y, TDbReferentialAction as z };
1389
+ export { TMetadataOverrides as $, TDbCollation as A, TDbInsertResult as B, TColumnDiff as C, TDbActionIntent as D, TDbActionInfo as E, TDbForeignKey as F, TExistingColumn as G, TDbRelation as H, TDbIndex as I, TFkLookupResolver as J, TExistingTableOption as K, TDbIndexField as L, TDbDefaultValue as M, TDbDeleteResult as N, TDbActionLevel as O, TDbFieldMeta as P, TMetaResponse as Q, TDbIndexType as R, TCascadeTarget as S, TCrudPermissions as T, TDbStorageType as U, TDbReferentialAction as V, TDbUpdateResult as W, TIdDescriptor as X, TFkLookupTarget as Y, TIdentification as Z, FlatOf$1 as _, FieldMappingStrategy as a, TValueFormatterPair as at, PrimaryKeyOf$1 as b, AggregateExpr$1 as c, Uniquery$1 as ct, AggregateResult as d, TableMetadata as dt, TRelationInfo as et, AtscriptDbWritable as f, NoopLogger as ft, FilterExpr$1 as g, FieldOpsFor as h, DocumentFieldMapper as i, TTableResolver as it, TDbDefaultFn as j, TDbActionProcessor as k, AggregateFn as l, UniqueryControls$1 as lt, DbQuery as m, UniquSelect as mt, DbResponse as n, TSyncColumnResult as nt, BaseDbAdapter as o, TWriteTableResolver as ot, DbControls as p, TGenericLogger as pt, TFieldMeta as q, resolveDesignType as r, TTableOptionDiff as rt, AggregateControls as s, TypedWithRelation as st, AtscriptDbReadable as t, TSearchIndexInfo as tt, AggregateQuery$1 as u, WithRelation$1 as ut, NavPropsOf$1 as v, TCrudOp as w, TCascadeResolver as x, OwnPropsOf$1 as y, TDbInsertManyResult as z };
@@ -1,5 +1,5 @@
1
1
  import { u as TFieldOps } from "./ops-C61kelof.mjs";
2
- import { FlatOf, NavPropsOf, NavPropsOf as NavPropsOf$1, OwnPropsOf, OwnPropsOf as OwnPropsOf$1, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, TAtscriptTypeObject, TMetadataMap, TSerializedAnnotatedType, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
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
 
5
5
  //#region src/query/uniqu-select.d.ts
@@ -71,6 +71,7 @@ declare class TableMetadata {
71
71
  flatMap: Map<string, TAtscriptAnnotatedType>;
72
72
  fieldDescriptors: readonly TDbFieldMeta[];
73
73
  primaryKeys: string[];
74
+ preferredId: string[];
74
75
  originalMetaIdFields: string[];
75
76
  indexes: Map<string, TDbIndex>;
76
77
  foreignKeys: Map<string, TDbForeignKey>;
@@ -102,6 +103,7 @@ declare class TableMetadata {
102
103
  /** Leaf field descriptors indexed by logical path (write/patch/filter paths). */
103
104
  leafByLogical: Map<string, TDbFieldMeta>;
104
105
  private _built;
106
+ private _identifications?;
105
107
  private _collateMap;
106
108
  private _columnFromMap;
107
109
  constructor(nestedObjects: boolean);
@@ -156,6 +158,16 @@ declare class TableMetadata {
156
158
  */
157
159
  private _resolveFkTargetFields;
158
160
  private _finalizeIndexes;
161
+ /**
162
+ * Captures legitimate row-identifier shapes from the metadata: primary key
163
+ * (when present) followed by every unique index. Must run BEFORE
164
+ * `_finalizeIndexes` rewrites `index.fields[i].name` from logical to
165
+ * physical, so the field lists stay logical.
166
+ */
167
+ private _buildIdentifications;
168
+ /** Legitimate row-identifier shapes — primary key first, then each unique index. */
169
+ getIdentifications(): readonly TIdentification[];
170
+ private _resolvePreferredId;
159
171
  }
160
172
  //#endregion
161
173
  //#region src/types.d.ts
@@ -205,6 +217,7 @@ interface TMetaResponse {
205
217
  vectorSearchable: boolean;
206
218
  searchIndexes: TSearchIndexInfo[];
207
219
  primaryKeys: string[];
220
+ preferredId: string[];
208
221
  relations: TRelationInfo[];
209
222
  fields: Record<string, TFieldMeta>;
210
223
  type: TSerializedAnnotatedType;
@@ -266,21 +279,13 @@ interface TDbActionInfo {
266
279
  /**
267
280
  * Stringified gate predicate (`fn.toString()`). Present only for `'row'`
268
281
  * and `'rows'` level actions whose decorator declared a `disabled` function.
269
- * The UI evaluates against a level-specific scope to grey-out / hide the
282
+ * The function is the batch shape `(rows: TRow[]) => boolean[]` (sync). The
283
+ * UI evaluates against a level-specific scope to grey-out / hide the
270
284
  * button. The server has already enforced this predicate before the
271
285
  * action's handler ran — the server is authoritative; this field is purely
272
286
  * a UI hint.
273
287
  */
274
288
  disabled?: string;
275
- /**
276
- * Optional dev-supplied list of dot-notation paths over the row that the
277
- * `disabled` predicate references. Plain `string[]` in v1 (a typed
278
- * `PathOf<TRow>[]` upgrade is a documented follow-up). The UI unions these
279
- * into `$select` across all actions on a table. When absent, the UI parses
280
- * `disabled` itself. When present, the UI uses this list verbatim — the
281
- * server does NOT auto-derive or merge.
282
- */
283
- requiredFields?: string[];
284
289
  }
285
290
  interface TDbInsertResult {
286
291
  insertedId: unknown;
@@ -328,6 +333,13 @@ interface TIdDescriptor {
328
333
  /** Whether this is a composite key (multiple fields). */
329
334
  isComposite: boolean;
330
335
  }
336
+ /** A legitimate row-identifier shape: primary key or a unique index. */
337
+ interface TIdentification {
338
+ /** Logical (path) field names that form this identifier. */
339
+ fields: readonly string[];
340
+ /** `'primaryKey'` for the PK; the unique-index name otherwise. */
341
+ source: string;
342
+ }
331
343
  type TDbStorageType = "column" | "flattened" | "json";
332
344
  interface TDbFieldMeta {
333
345
  /** The dot-notation path to this field (logical name). */
@@ -477,12 +489,13 @@ interface TMetadataOverrides {
477
489
  *
478
490
  * Typically provided by the driver/registry (e.g. `DbSpace.getTable`).
479
491
  */
480
- type TTableResolver = (type: TAtscriptAnnotatedType) => Pick<AtscriptDbTableLike, "findMany" | "loadRelations" | "primaryKeys" | "relations" | "foreignKeys"> | undefined;
492
+ type TTableResolver = (type: TAtscriptAnnotatedType) => Pick<AtscriptDbTableLike, "findMany" | "loadRelations" | "primaryKeys" | "preferredId" | "relations" | "foreignKeys"> | undefined;
481
493
  /** Minimal table interface used by the table resolver. Avoids circular dependency with AtscriptDbTable. */
482
494
  interface AtscriptDbTableLike {
483
495
  findMany(query: unknown): Promise<Array<Record<string, unknown>>>;
484
496
  loadRelations(rows: Array<Record<string, unknown>>, withRelations: WithRelation[]): Promise<void>;
485
497
  primaryKeys: readonly string[];
498
+ preferredId: readonly string[];
486
499
  relations: ReadonlyMap<string, TDbRelation>;
487
500
  foreignKeys: ReadonlyMap<string, TDbForeignKey>;
488
501
  getMetadata(): TableMetadata;
@@ -597,12 +610,6 @@ interface TDbRelation {
597
610
  */
598
611
  declare abstract class BaseDbAdapter {
599
612
  protected _table: AtscriptDbReadable<any, any, any, any, any, any, any>;
600
- private _metaIdPhysical;
601
- /**
602
- * Returns the physical column name of the single @meta.id field (if any).
603
- * Used to return the user's logical ID instead of the DB-generated ID on insert.
604
- */
605
- protected _getMetaIdPhysical(): string | null;
606
613
  /**
607
614
  * Resolves the correct insertedId: prefers the user-supplied PK value
608
615
  * from the data over the DB-generated fallback (e.g. rowid, _id).
@@ -1185,6 +1192,7 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
1185
1192
  /** Strategy for mapping between logical field shapes and physical storage. */
1186
1193
  protected readonly _fieldMapper: FieldMappingStrategy;
1187
1194
  protected _writeTableResolver?: TWriteTableResolver;
1195
+ private _metaIdPhysical;
1188
1196
  constructor(_type: T, adapter: A, logger?: TGenericLogger, _tableResolver?: TTableResolver | undefined);
1189
1197
  /** Ensures metadata is built. Called before any metadata access. */
1190
1198
  protected _ensureBuilt(): void;
@@ -1207,8 +1215,18 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
1207
1215
  get indexes(): Map<string, TDbIndex>;
1208
1216
  /** Primary key field names from `@meta.id`. */
1209
1217
  get primaryKeys(): readonly string[];
1210
- /** Original `@meta.id` field names as declared in the schema (before adapter manipulation). */
1211
- get originalMetaIdFields(): readonly string[];
1218
+ /** Preferred row identifier field names. Defaults to primary keys. */
1219
+ get preferredId(): readonly string[];
1220
+ /** Legitimate row-identifier shapes (primary key + every unique index). */
1221
+ get identifications(): readonly TIdentification[];
1222
+ /**
1223
+ * Physical column name of the single `@meta.id` field, or `null` when the
1224
+ * schema has zero or multiple `@meta.id` fields. Used by adapters to return
1225
+ * the user's logical ID instead of the DB-generated one on insert.
1226
+ *
1227
+ * @internal Adapter-facing surface; not part of the consumer API.
1228
+ */
1229
+ get metaIdPhysical(): string | null;
1212
1230
  /** Dimension fields from `@db.column.dimension`. */
1213
1231
  get dimensions(): readonly string[];
1214
1232
  /** Measure fields from `@db.column.measure`. */
@@ -1368,4 +1386,4 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
1368
1386
  }, thisTableName: string, alias?: string): TDbForeignKey | undefined;
1369
1387
  }
1370
1388
  //#endregion
1371
- export { TSyncColumnResult as $, TDbDefaultValue as A, TDbRelation as B, TCrudPermissions as C, TDbActionProcessor as D, TDbActionLevel as E, TDbIndexField as F, TFieldMeta as G, TDbUpdateResult as H, TDbIndexType as I, TIdDescriptor as J, TFkLookupResolver as K, TDbInsertManyResult as L, TDbFieldMeta as M, TDbForeignKey as N, TDbCollation as O, TDbIndex as P, TSearchIndexInfo as Q, TDbInsertResult as R, TCrudOp as S, TDbActionIntent as T, TExistingColumn as U, TDbStorageType as V, TExistingTableOption as W, TMetadataOverrides as X, TMetaResponse as Y, TRelationInfo as Z, NavPropsOf$1 as _, FieldMappingStrategy as a, Uniquery$1 as at, TCascadeTarget as b, AggregateExpr$1 as c, TableMetadata as ct, AggregateResult as d, UniquSelect as dt, TTableOptionDiff as et, AtscriptDbWritable as f, FilterExpr$1 as g, FieldOpsFor as h, DocumentFieldMapper as i, TypedWithRelation as it, TDbDeleteResult as j, TDbDefaultFn as k, AggregateFn as l, NoopLogger as lt, DbQuery as m, DbResponse as n, TValueFormatterPair as nt, BaseDbAdapter as o, UniqueryControls$1 as ot, DbControls as p, TFkLookupTarget as q, resolveDesignType as r, TWriteTableResolver as rt, AggregateControls as s, WithRelation$1 as st, AtscriptDbReadable as t, TTableResolver as tt, AggregateQuery$1 as u, TGenericLogger as ut, OwnPropsOf$1 as v, TDbActionInfo as w, TColumnDiff as x, TCascadeResolver as y, TDbReferentialAction as z };
1389
+ export { TMetadataOverrides as $, TDbCollation as A, TDbInsertResult as B, TColumnDiff as C, TDbActionIntent as D, TDbActionInfo as E, TDbForeignKey as F, TExistingColumn as G, TDbRelation as H, TDbIndex as I, TFkLookupResolver as J, TExistingTableOption as K, TDbIndexField as L, TDbDefaultValue as M, TDbDeleteResult as N, TDbActionLevel as O, TDbFieldMeta as P, TMetaResponse as Q, TDbIndexType as R, TCascadeTarget as S, TCrudPermissions as T, TDbStorageType as U, TDbReferentialAction as V, TDbUpdateResult as W, TIdDescriptor as X, TFkLookupTarget as Y, TIdentification as Z, FlatOf$1 as _, FieldMappingStrategy as a, TValueFormatterPair as at, PrimaryKeyOf$1 as b, AggregateExpr$1 as c, Uniquery$1 as ct, AggregateResult as d, TableMetadata as dt, TRelationInfo as et, AtscriptDbWritable as f, NoopLogger as ft, FilterExpr$1 as g, FieldOpsFor as h, DocumentFieldMapper as i, TTableResolver as it, TDbDefaultFn as j, TDbActionProcessor as k, AggregateFn as l, UniqueryControls$1 as lt, DbQuery as m, UniquSelect as mt, DbResponse as n, TSyncColumnResult as nt, BaseDbAdapter as o, TWriteTableResolver as ot, DbControls as p, TGenericLogger as pt, TFieldMeta as q, resolveDesignType as r, TTableOptionDiff as rt, AggregateControls as s, TypedWithRelation as st, AtscriptDbReadable as t, TSearchIndexInfo as tt, AggregateQuery$1 as u, WithRelation$1 as ut, NavPropsOf$1 as v, TCrudOp as w, TCascadeResolver as x, OwnPropsOf$1 as y, TDbInsertManyResult as z };
@@ -1,6 +1,6 @@
1
- import { H as TDbUpdateResult, K as TFkLookupResolver, L as TDbInsertManyResult, R as TDbInsertResult, ct as TableMetadata, j as TDbDeleteResult, o as BaseDbAdapter, rt as TWriteTableResolver, t as AtscriptDbReadable, tt as TTableResolver, ut as TGenericLogger, y as TCascadeResolver } from "./db-readable-DN1CJRph.cjs";
2
- import { FilterExpr } from "@uniqu/core";
1
+ import { B as TDbInsertResult, J as TFkLookupResolver, N as TDbDeleteResult, W as TDbUpdateResult, dt as TableMetadata, it as TTableResolver, o as BaseDbAdapter, ot as TWriteTableResolver, pt as TGenericLogger, t as AtscriptDbReadable, x as TCascadeResolver, z as TDbInsertManyResult } from "./db-readable-CkeVx10t.mjs";
3
2
  import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
3
+ import { FilterExpr } from "@uniqu/core";
4
4
 
5
5
  //#region src/strategies/integrity.d.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
- import { H as TDbUpdateResult, K as TFkLookupResolver, L as TDbInsertManyResult, R as TDbInsertResult, ct as TableMetadata, j as TDbDeleteResult, o as BaseDbAdapter, rt as TWriteTableResolver, t as AtscriptDbReadable, tt as TTableResolver, ut as TGenericLogger, y as TCascadeResolver } from "./db-readable-CONS7NPu.mjs";
2
- import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
1
+ import { B as TDbInsertResult, J as TFkLookupResolver, N as TDbDeleteResult, W as TDbUpdateResult, dt as TableMetadata, it as TTableResolver, o as BaseDbAdapter, ot as TWriteTableResolver, pt as TGenericLogger, t as AtscriptDbReadable, x as TCascadeResolver, z as TDbInsertManyResult } from "./db-readable-CKQHMqVH.cjs";
3
2
  import { FilterExpr } from "@uniqu/core";
3
+ import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
4
4
 
5
5
  //#region src/strategies/integrity.d.ts
6
6
  /**
@@ -52,6 +52,7 @@ var TableMetadata = class {
52
52
  flatMap;
53
53
  fieldDescriptors;
54
54
  primaryKeys = [];
55
+ preferredId = [];
55
56
  originalMetaIdFields = [];
56
57
  indexes = /* @__PURE__ */ new Map();
57
58
  foreignKeys = /* @__PURE__ */ new Map();
@@ -83,6 +84,7 @@ var TableMetadata = class {
83
84
  /** Leaf field descriptors indexed by logical path (write/patch/filter paths). */
84
85
  leafByLogical = /* @__PURE__ */ new Map();
85
86
  _built = false;
87
+ _identifications;
86
88
  _collateMap = /* @__PURE__ */ new Map();
87
89
  _columnFromMap = /* @__PURE__ */ new Map();
88
90
  constructor(nestedObjects) {
@@ -133,6 +135,8 @@ var TableMetadata = class {
133
135
  if (overrides) this._applyOverrides(overrides);
134
136
  this._buildFieldDescriptors(adapter);
135
137
  if (!this.nestedObjects) this._buildLeafIndexes();
138
+ this._buildIdentifications();
139
+ this._resolvePreferredId(type);
136
140
  this._finalizeIndexes();
137
141
  this._collateMap.clear();
138
142
  this._columnFromMap.clear();
@@ -440,6 +444,38 @@ var TableMetadata = class {
440
444
  for (const index of this.indexes.values()) if (index.type === "unique" && index.fields.length === 1) this.uniqueProps.add(index.fields[0].name);
441
445
  for (const index of this.indexes.values()) for (const field of index.fields) field.name = this.pathToPhysical.get(field.name) ?? this.columnMap.get(field.name) ?? field.name;
442
446
  }
447
+ /**
448
+ * Captures legitimate row-identifier shapes from the metadata: primary key
449
+ * (when present) followed by every unique index. Must run BEFORE
450
+ * `_finalizeIndexes` rewrites `index.fields[i].name` from logical to
451
+ * physical, so the field lists stay logical.
452
+ */
453
+ _buildIdentifications() {
454
+ const out = [];
455
+ if (this.primaryKeys.length > 0) out.push({
456
+ fields: [...this.primaryKeys],
457
+ source: "primaryKey"
458
+ });
459
+ for (const index of this.indexes.values()) if (index.type === "unique") out.push({
460
+ fields: index.fields.map((field) => field.name),
461
+ source: index.name
462
+ });
463
+ this._identifications = out;
464
+ }
465
+ /** Legitimate row-identifier shapes — primary key first, then each unique index. */
466
+ getIdentifications() {
467
+ return this._identifications ?? [];
468
+ }
469
+ _resolvePreferredId(type) {
470
+ const preferred = type.metadata.get("db.table.preferredId.uniqueIndex");
471
+ if (preferred === void 0) {
472
+ this.preferredId = [...this.primaryKeys];
473
+ return;
474
+ }
475
+ const requestedName = typeof preferred === "string" ? preferred : void 0;
476
+ const selected = this.getIdentifications().find((id) => id.source !== "primaryKey" && (requestedName === void 0 || id.source === requestedName));
477
+ this.preferredId = selected ? [...selected.fields] : [...this.primaryKeys];
478
+ }
443
479
  };
444
480
  //#endregion
445
481
  //#region src/query/uniqu-select.ts
@@ -1073,6 +1109,7 @@ var AtscriptDbReadable = class {
1073
1109
  /** Strategy for mapping between logical field shapes and physical storage. */
1074
1110
  _fieldMapper;
1075
1111
  _writeTableResolver;
1112
+ _metaIdPhysical;
1076
1113
  constructor(_type, adapter, logger = NoopLogger, _tableResolver) {
1077
1114
  this._type = _type;
1078
1115
  this.adapter = adapter;
@@ -1139,10 +1176,33 @@ var AtscriptDbReadable = class {
1139
1176
  this._ensureBuilt();
1140
1177
  return this._meta.primaryKeys;
1141
1178
  }
1142
- /** Original `@meta.id` field names as declared in the schema (before adapter manipulation). */
1143
- get originalMetaIdFields() {
1179
+ /** Preferred row identifier field names. Defaults to primary keys. */
1180
+ get preferredId() {
1181
+ this._ensureBuilt();
1182
+ return this._meta.preferredId;
1183
+ }
1184
+ /** Legitimate row-identifier shapes (primary key + every unique index). */
1185
+ get identifications() {
1144
1186
  this._ensureBuilt();
1145
- return this._meta.originalMetaIdFields;
1187
+ return this._meta.getIdentifications();
1188
+ }
1189
+ /**
1190
+ * Physical column name of the single `@meta.id` field, or `null` when the
1191
+ * schema has zero or multiple `@meta.id` fields. Used by adapters to return
1192
+ * the user's logical ID instead of the DB-generated one on insert.
1193
+ *
1194
+ * @internal Adapter-facing surface; not part of the consumer API.
1195
+ */
1196
+ get metaIdPhysical() {
1197
+ this._ensureBuilt();
1198
+ if (this._metaIdPhysical === void 0) {
1199
+ const fields = this._meta.originalMetaIdFields;
1200
+ if (fields.length === 1) {
1201
+ const field = fields[0];
1202
+ this._metaIdPhysical = this._meta.columnMap.get(field) ?? field;
1203
+ } else this._metaIdPhysical = null;
1204
+ }
1205
+ return this._metaIdPhysical;
1146
1206
  }
1147
1207
  /** Dimension fields from `@db.column.dimension`. */
1148
1208
  get dimensions() {
@@ -1593,27 +1653,12 @@ const txStorage = new node_async_hooks.AsyncLocalStorage();
1593
1653
  */
1594
1654
  var BaseDbAdapter = class {
1595
1655
  _table;
1596
- _metaIdPhysical;
1597
- /**
1598
- * Returns the physical column name of the single @meta.id field (if any).
1599
- * Used to return the user's logical ID instead of the DB-generated ID on insert.
1600
- */
1601
- _getMetaIdPhysical() {
1602
- if (this._metaIdPhysical === void 0) {
1603
- const fields = this._table.originalMetaIdFields;
1604
- if (fields.length === 1) {
1605
- const field = fields[0];
1606
- this._metaIdPhysical = this._table.columnMap.get(field) ?? field;
1607
- } else this._metaIdPhysical = null;
1608
- }
1609
- return this._metaIdPhysical;
1610
- }
1611
1656
  /**
1612
1657
  * Resolves the correct insertedId: prefers the user-supplied PK value
1613
1658
  * from the data over the DB-generated fallback (e.g. rowid, _id).
1614
1659
  */
1615
1660
  _resolveInsertedId(data, dbGeneratedId) {
1616
- const metaIdPhysical = this._getMetaIdPhysical();
1661
+ const metaIdPhysical = this._table.metaIdPhysical;
1617
1662
  return metaIdPhysical ? data[metaIdPhysical] ?? dbGeneratedId : dbGeneratedId;
1618
1663
  }
1619
1664
  /** Logger instance — set via {@link registerReadable} from the readable's logger. */
@@ -52,6 +52,7 @@ var TableMetadata = class {
52
52
  flatMap;
53
53
  fieldDescriptors;
54
54
  primaryKeys = [];
55
+ preferredId = [];
55
56
  originalMetaIdFields = [];
56
57
  indexes = /* @__PURE__ */ new Map();
57
58
  foreignKeys = /* @__PURE__ */ new Map();
@@ -83,6 +84,7 @@ var TableMetadata = class {
83
84
  /** Leaf field descriptors indexed by logical path (write/patch/filter paths). */
84
85
  leafByLogical = /* @__PURE__ */ new Map();
85
86
  _built = false;
87
+ _identifications;
86
88
  _collateMap = /* @__PURE__ */ new Map();
87
89
  _columnFromMap = /* @__PURE__ */ new Map();
88
90
  constructor(nestedObjects) {
@@ -133,6 +135,8 @@ var TableMetadata = class {
133
135
  if (overrides) this._applyOverrides(overrides);
134
136
  this._buildFieldDescriptors(adapter);
135
137
  if (!this.nestedObjects) this._buildLeafIndexes();
138
+ this._buildIdentifications();
139
+ this._resolvePreferredId(type);
136
140
  this._finalizeIndexes();
137
141
  this._collateMap.clear();
138
142
  this._columnFromMap.clear();
@@ -440,6 +444,38 @@ var TableMetadata = class {
440
444
  for (const index of this.indexes.values()) if (index.type === "unique" && index.fields.length === 1) this.uniqueProps.add(index.fields[0].name);
441
445
  for (const index of this.indexes.values()) for (const field of index.fields) field.name = this.pathToPhysical.get(field.name) ?? this.columnMap.get(field.name) ?? field.name;
442
446
  }
447
+ /**
448
+ * Captures legitimate row-identifier shapes from the metadata: primary key
449
+ * (when present) followed by every unique index. Must run BEFORE
450
+ * `_finalizeIndexes` rewrites `index.fields[i].name` from logical to
451
+ * physical, so the field lists stay logical.
452
+ */
453
+ _buildIdentifications() {
454
+ const out = [];
455
+ if (this.primaryKeys.length > 0) out.push({
456
+ fields: [...this.primaryKeys],
457
+ source: "primaryKey"
458
+ });
459
+ for (const index of this.indexes.values()) if (index.type === "unique") out.push({
460
+ fields: index.fields.map((field) => field.name),
461
+ source: index.name
462
+ });
463
+ this._identifications = out;
464
+ }
465
+ /** Legitimate row-identifier shapes — primary key first, then each unique index. */
466
+ getIdentifications() {
467
+ return this._identifications ?? [];
468
+ }
469
+ _resolvePreferredId(type) {
470
+ const preferred = type.metadata.get("db.table.preferredId.uniqueIndex");
471
+ if (preferred === void 0) {
472
+ this.preferredId = [...this.primaryKeys];
473
+ return;
474
+ }
475
+ const requestedName = typeof preferred === "string" ? preferred : void 0;
476
+ const selected = this.getIdentifications().find((id) => id.source !== "primaryKey" && (requestedName === void 0 || id.source === requestedName));
477
+ this.preferredId = selected ? [...selected.fields] : [...this.primaryKeys];
478
+ }
443
479
  };
444
480
  //#endregion
445
481
  //#region src/query/uniqu-select.ts
@@ -1073,6 +1109,7 @@ var AtscriptDbReadable = class {
1073
1109
  /** Strategy for mapping between logical field shapes and physical storage. */
1074
1110
  _fieldMapper;
1075
1111
  _writeTableResolver;
1112
+ _metaIdPhysical;
1076
1113
  constructor(_type, adapter, logger = NoopLogger, _tableResolver) {
1077
1114
  this._type = _type;
1078
1115
  this.adapter = adapter;
@@ -1139,10 +1176,33 @@ var AtscriptDbReadable = class {
1139
1176
  this._ensureBuilt();
1140
1177
  return this._meta.primaryKeys;
1141
1178
  }
1142
- /** Original `@meta.id` field names as declared in the schema (before adapter manipulation). */
1143
- get originalMetaIdFields() {
1179
+ /** Preferred row identifier field names. Defaults to primary keys. */
1180
+ get preferredId() {
1181
+ this._ensureBuilt();
1182
+ return this._meta.preferredId;
1183
+ }
1184
+ /** Legitimate row-identifier shapes (primary key + every unique index). */
1185
+ get identifications() {
1144
1186
  this._ensureBuilt();
1145
- return this._meta.originalMetaIdFields;
1187
+ return this._meta.getIdentifications();
1188
+ }
1189
+ /**
1190
+ * Physical column name of the single `@meta.id` field, or `null` when the
1191
+ * schema has zero or multiple `@meta.id` fields. Used by adapters to return
1192
+ * the user's logical ID instead of the DB-generated one on insert.
1193
+ *
1194
+ * @internal Adapter-facing surface; not part of the consumer API.
1195
+ */
1196
+ get metaIdPhysical() {
1197
+ this._ensureBuilt();
1198
+ if (this._metaIdPhysical === void 0) {
1199
+ const fields = this._meta.originalMetaIdFields;
1200
+ if (fields.length === 1) {
1201
+ const field = fields[0];
1202
+ this._metaIdPhysical = this._meta.columnMap.get(field) ?? field;
1203
+ } else this._metaIdPhysical = null;
1204
+ }
1205
+ return this._metaIdPhysical;
1146
1206
  }
1147
1207
  /** Dimension fields from `@db.column.dimension`. */
1148
1208
  get dimensions() {
@@ -1593,27 +1653,12 @@ const txStorage = new AsyncLocalStorage();
1593
1653
  */
1594
1654
  var BaseDbAdapter = class {
1595
1655
  _table;
1596
- _metaIdPhysical;
1597
- /**
1598
- * Returns the physical column name of the single @meta.id field (if any).
1599
- * Used to return the user's logical ID instead of the DB-generated ID on insert.
1600
- */
1601
- _getMetaIdPhysical() {
1602
- if (this._metaIdPhysical === void 0) {
1603
- const fields = this._table.originalMetaIdFields;
1604
- if (fields.length === 1) {
1605
- const field = fields[0];
1606
- this._metaIdPhysical = this._table.columnMap.get(field) ?? field;
1607
- } else this._metaIdPhysical = null;
1608
- }
1609
- return this._metaIdPhysical;
1610
- }
1611
1656
  /**
1612
1657
  * Resolves the correct insertedId: prefers the user-supplied PK value
1613
1658
  * from the data over the DB-generated fallback (e.g. rowid, _id).
1614
1659
  */
1615
1660
  _resolveInsertedId(data, dbGeneratedId) {
1616
- const metaIdPhysical = this._getMetaIdPhysical();
1661
+ const metaIdPhysical = this._table.metaIdPhysical;
1617
1662
  return metaIdPhysical ? data[metaIdPhysical] ?? dbGeneratedId : dbGeneratedId;
1618
1663
  }
1619
1664
  /** Logger instance — set via {@link registerReadable} from the readable's logger. */
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_db_error = require("./db-error-D8tQhNgM.cjs");
3
- const require_db_view = require("./db-view-DIGN4079.cjs");
3
+ const require_db_view = require("./db-view-CuPkKCnU.cjs");
4
4
  const require_ops = require("./ops.cjs");
5
5
  const require_validator = require("./validator-BIuw_T0k.cjs");
6
6
  require("./nested-writer-v_LPR1yJ.cjs");
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { $ as TSyncColumnResult, A as TDbDefaultValue, B as TDbRelation, C as TCrudPermissions, D as TDbActionProcessor, E as TDbActionLevel, F as TDbIndexField, G as TFieldMeta, H as TDbUpdateResult, I as TDbIndexType, J as TIdDescriptor, K as TFkLookupResolver, L as TDbInsertManyResult, M as TDbFieldMeta, N as TDbForeignKey, O as TDbCollation, P as TDbIndex, Q as TSearchIndexInfo, R as TDbInsertResult, S as TCrudOp, T as TDbActionIntent, U as TExistingColumn, V as TDbStorageType, W as TExistingTableOption, X as TMetadataOverrides, Y as TMetaResponse, Z as TRelationInfo, _ as NavPropsOf, a as FieldMappingStrategy, at as Uniquery, b as TCascadeTarget, c as AggregateExpr, ct as TableMetadata, d as AggregateResult, dt as UniquSelect, et as TTableOptionDiff, f as AtscriptDbWritable, g as FilterExpr, h as FieldOpsFor, i as DocumentFieldMapper, it as TypedWithRelation, j as TDbDeleteResult, k as TDbDefaultFn, l as AggregateFn, lt as NoopLogger, m as DbQuery, n as DbResponse, nt as TValueFormatterPair, o as BaseDbAdapter, ot as UniqueryControls, p as DbControls, q as TFkLookupTarget, r as resolveDesignType, rt as TWriteTableResolver, s as AggregateControls, st as WithRelation, t as AtscriptDbReadable, tt as TTableResolver, u as AggregateQuery, ut as TGenericLogger, v as OwnPropsOf, w as TDbActionInfo, x as TColumnDiff, y as TCascadeResolver, z as TDbReferentialAction } from "./db-readable-DN1CJRph.cjs";
1
+ import { $ as TMetadataOverrides, A as TDbCollation, B as TDbInsertResult, C as TColumnDiff, D as TDbActionIntent, E as TDbActionInfo, F as TDbForeignKey, G as TExistingColumn, H as TDbRelation, I as TDbIndex, J as TFkLookupResolver, K as TExistingTableOption, L as TDbIndexField, M as TDbDefaultValue, N as TDbDeleteResult, O as TDbActionLevel, P as TDbFieldMeta, Q as TMetaResponse, R as TDbIndexType, S as TCascadeTarget, T as TCrudPermissions, U as TDbStorageType, V as TDbReferentialAction, W as TDbUpdateResult, X as TIdDescriptor, Y as TFkLookupTarget, Z as TIdentification, _ as FlatOf, a as FieldMappingStrategy, at as TValueFormatterPair, b as PrimaryKeyOf, c as AggregateExpr, ct as Uniquery, d as AggregateResult, dt as TableMetadata, et as TRelationInfo, f as AtscriptDbWritable, ft as NoopLogger, g as FilterExpr, h as FieldOpsFor, i as DocumentFieldMapper, it as TTableResolver, j as TDbDefaultFn, k as TDbActionProcessor, l as AggregateFn, lt as UniqueryControls, m as DbQuery, mt as UniquSelect, n as DbResponse, nt as TSyncColumnResult, o as BaseDbAdapter, ot as TWriteTableResolver, p as DbControls, pt as TGenericLogger, q as TFieldMeta, r as resolveDesignType, rt as TTableOptionDiff, s as AggregateControls, st as TypedWithRelation, t as AtscriptDbReadable, tt as TSearchIndexInfo, u as AggregateQuery, ut as WithRelation, v as NavPropsOf, w as TCrudOp, x as TCascadeResolver, y as OwnPropsOf, z as TDbInsertManyResult } from "./db-readable-CKQHMqVH.cjs";
2
2
  import { a as $remove, c as $upsert, d as getDbFieldOp, f as isDbFieldOp, i as $mul, l as TDbFieldOp, n as $inc, o as $replace, p as separateFieldOps, r as $insert, s as $update, t as $dec, u as TFieldOps } from "./ops-DXJ4Zw0P.cjs";
3
- import { a as AtscriptQueryComparison, c as AtscriptRef, d as translateQueryTree, f as AtscriptDbTable, i as TViewColumnMapping, l as TViewJoin, m as NativeIntegrity, n as TAdapterFactory, o as AtscriptQueryFieldRef, p as IntegrityStrategy, r as AtscriptDbView, s as AtscriptQueryNode, t as DbSpace, u as TViewPlan } from "./db-space-D1dfFoKL.cjs";
3
+ import { a as AtscriptQueryComparison, c as AtscriptRef, d as translateQueryTree, f as AtscriptDbTable, i as TViewColumnMapping, l as TViewJoin, m as NativeIntegrity, n as TAdapterFactory, o as AtscriptQueryFieldRef, p as IntegrityStrategy, r as AtscriptDbView, s as AtscriptQueryNode, t as DbSpace, u as TViewPlan } from "./db-space-Dycn4usM.cjs";
4
4
  import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-DRGMCEn3.cjs";
5
5
  import { c as TArrayPatch, i as buildValidationContext, l as TDbPatch, n as ValidatorMode, o as forceNavNonOptional, r as buildDbValidator, s as isNavRelation, t as ValidationContext, u as getKeyProps } from "./validator-_z_A3cKa.cjs";
6
6
  import { AggregateQuery as AggregateQuery$1, FilterExpr as FilterExpr$1, FilterVisitor, Uniquery as Uniquery$1, computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
@@ -114,4 +114,4 @@ declare class DbError extends Error {
114
114
  */
115
115
  declare function decomposePatch(payload: Record<string, unknown>, table: AtscriptDbTable): Record<string, unknown>;
116
116
  //#endregion
117
- export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, type DbControls, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithRelation, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, isDbFieldOp, isNavRelation, isPrimitive, resolveDesignType, separateFieldOps, translateQueryTree, walkFilter };
117
+ export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, type DbControls, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, type FlatOf, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, type PrimaryKeyOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TIdentification, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithRelation, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, isDbFieldOp, isNavRelation, isPrimitive, resolveDesignType, separateFieldOps, translateQueryTree, walkFilter };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { $ as TSyncColumnResult, A as TDbDefaultValue, B as TDbRelation, C as TCrudPermissions, D as TDbActionProcessor, E as TDbActionLevel, F as TDbIndexField, G as TFieldMeta, H as TDbUpdateResult, I as TDbIndexType, J as TIdDescriptor, K as TFkLookupResolver, L as TDbInsertManyResult, M as TDbFieldMeta, N as TDbForeignKey, O as TDbCollation, P as TDbIndex, Q as TSearchIndexInfo, R as TDbInsertResult, S as TCrudOp, T as TDbActionIntent, U as TExistingColumn, V as TDbStorageType, W as TExistingTableOption, X as TMetadataOverrides, Y as TMetaResponse, Z as TRelationInfo, _ as NavPropsOf, a as FieldMappingStrategy, at as Uniquery, b as TCascadeTarget, c as AggregateExpr, ct as TableMetadata, d as AggregateResult, dt as UniquSelect, et as TTableOptionDiff, f as AtscriptDbWritable, g as FilterExpr, h as FieldOpsFor, i as DocumentFieldMapper, it as TypedWithRelation, j as TDbDeleteResult, k as TDbDefaultFn, l as AggregateFn, lt as NoopLogger, m as DbQuery, n as DbResponse, nt as TValueFormatterPair, o as BaseDbAdapter, ot as UniqueryControls, p as DbControls, q as TFkLookupTarget, r as resolveDesignType, rt as TWriteTableResolver, s as AggregateControls, st as WithRelation, t as AtscriptDbReadable, tt as TTableResolver, u as AggregateQuery, ut as TGenericLogger, v as OwnPropsOf, w as TDbActionInfo, x as TColumnDiff, y as TCascadeResolver, z as TDbReferentialAction } from "./db-readable-CONS7NPu.mjs";
1
+ import { $ as TMetadataOverrides, A as TDbCollation, B as TDbInsertResult, C as TColumnDiff, D as TDbActionIntent, E as TDbActionInfo, F as TDbForeignKey, G as TExistingColumn, H as TDbRelation, I as TDbIndex, J as TFkLookupResolver, K as TExistingTableOption, L as TDbIndexField, M as TDbDefaultValue, N as TDbDeleteResult, O as TDbActionLevel, P as TDbFieldMeta, Q as TMetaResponse, R as TDbIndexType, S as TCascadeTarget, T as TCrudPermissions, U as TDbStorageType, V as TDbReferentialAction, W as TDbUpdateResult, X as TIdDescriptor, Y as TFkLookupTarget, Z as TIdentification, _ as FlatOf, a as FieldMappingStrategy, at as TValueFormatterPair, b as PrimaryKeyOf, c as AggregateExpr, ct as Uniquery, d as AggregateResult, dt as TableMetadata, et as TRelationInfo, f as AtscriptDbWritable, ft as NoopLogger, g as FilterExpr, h as FieldOpsFor, i as DocumentFieldMapper, it as TTableResolver, j as TDbDefaultFn, k as TDbActionProcessor, l as AggregateFn, lt as UniqueryControls, m as DbQuery, mt as UniquSelect, n as DbResponse, nt as TSyncColumnResult, o as BaseDbAdapter, ot as TWriteTableResolver, p as DbControls, pt as TGenericLogger, q as TFieldMeta, r as resolveDesignType, rt as TTableOptionDiff, s as AggregateControls, st as TypedWithRelation, t as AtscriptDbReadable, tt as TSearchIndexInfo, u as AggregateQuery, ut as WithRelation, v as NavPropsOf, w as TCrudOp, x as TCascadeResolver, y as OwnPropsOf, z as TDbInsertManyResult } from "./db-readable-CkeVx10t.mjs";
2
2
  import { a as $remove, c as $upsert, d as getDbFieldOp, f as isDbFieldOp, i as $mul, l as TDbFieldOp, n as $inc, o as $replace, p as separateFieldOps, r as $insert, s as $update, t as $dec, u as TFieldOps } from "./ops-C61kelof.mjs";
3
- import { a as AtscriptQueryComparison, c as AtscriptRef, d as translateQueryTree, f as AtscriptDbTable, i as TViewColumnMapping, l as TViewJoin, m as NativeIntegrity, n as TAdapterFactory, o as AtscriptQueryFieldRef, p as IntegrityStrategy, r as AtscriptDbView, s as AtscriptQueryNode, t as DbSpace, u as TViewPlan } from "./db-space-DQU38dHk.mjs";
3
+ import { a as AtscriptQueryComparison, c as AtscriptRef, d as translateQueryTree, f as AtscriptDbTable, i as TViewColumnMapping, l as TViewJoin, m as NativeIntegrity, n as TAdapterFactory, o as AtscriptQueryFieldRef, p as IntegrityStrategy, r as AtscriptDbView, s as AtscriptQueryNode, t as DbSpace, u as TViewPlan } from "./db-space-BAfXlRiV.mjs";
4
4
  import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-DDvYyv5t.mjs";
5
5
  import { c as TArrayPatch, i as buildValidationContext, l as TDbPatch, n as ValidatorMode, o as forceNavNonOptional, r as buildDbValidator, s as isNavRelation, t as ValidationContext, u as getKeyProps } from "./validator-DttN2e5_.mjs";
6
6
  import { AggregateQuery as AggregateQuery$1, FilterExpr as FilterExpr$1, FilterVisitor, Uniquery as Uniquery$1, computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
@@ -114,4 +114,4 @@ declare class DbError extends Error {
114
114
  */
115
115
  declare function decomposePatch(payload: Record<string, unknown>, table: AtscriptDbTable): Record<string, unknown>;
116
116
  //#endregion
117
- export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, type DbControls, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithRelation, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, isDbFieldOp, isNavRelation, isPrimitive, resolveDesignType, separateFieldOps, translateQueryTree, walkFilter };
117
+ export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, type DbControls, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, type FlatOf, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, type PrimaryKeyOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TIdentification, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithRelation, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, isDbFieldOp, isNavRelation, isPrimitive, resolveDesignType, separateFieldOps, translateQueryTree, walkFilter };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as DbError } from "./db-error-Cepx-RsQ.mjs";
2
- import { a as BaseDbAdapter, c as AtscriptDbReadable, d as DocumentFieldMapper, f as FieldMappingStrategy, h as NoopLogger, i as ApplicationIntegrity, l as resolveDesignType, m as TableMetadata, n as AtscriptDbTable, o as IntegrityStrategy, p as UniquSelect, r as decomposePatch, s as NativeIntegrity, t as AtscriptDbView, u as RelationalFieldMapper } from "./db-view-DNwX6_4x.mjs";
2
+ import { a as BaseDbAdapter, c as AtscriptDbReadable, d as DocumentFieldMapper, f as FieldMappingStrategy, h as NoopLogger, i as ApplicationIntegrity, l as resolveDesignType, m as TableMetadata, n as AtscriptDbTable, o as IntegrityStrategy, p as UniquSelect, r as decomposePatch, s as NativeIntegrity, t as AtscriptDbView, u as RelationalFieldMapper } from "./db-view-cBN0YqrV.mjs";
3
3
  import { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, getDbFieldOp, isDbFieldOp, separateFieldOps } from "./ops.mjs";
4
4
  import { a as isNavRelation, i as forceNavNonOptional, n as buildValidationContext, o as createDbValidatorPlugin, s as getKeyProps, t as buildDbValidator } from "./validator-BB5h1Le3.mjs";
5
5
  import "./nested-writer-CT2rLURx.mjs";
package/dist/plugin.cjs CHANGED
@@ -764,7 +764,53 @@ const dbTableAnnotations = {
764
764
  });
765
765
  return errors;
766
766
  }
767
- })
767
+ }),
768
+ preferredId: { uniqueIndex: new _atscript_core.AnnotationSpec({
769
+ description: "Selects a unique index as the table's preferred row identifier. When the unique-index name is omitted, the first declared unique-index group wins.\n\n**Example:**\n```atscript\n@db.table\n@db.table.preferredId.uniqueIndex \"by_slug\"\nexport interface Post {\n @db.index.unique \"by_slug\"\n slug: string\n}\n```\n",
770
+ nodeType: ["interface"],
771
+ multiple: false,
772
+ argument: {
773
+ optional: true,
774
+ name: "name",
775
+ type: "string",
776
+ description: "Unique-index group name. If omitted, the first declared group is used."
777
+ },
778
+ validate(token, args, _doc) {
779
+ const errors = [];
780
+ const owner = token.parentNode;
781
+ if (require_validation_utils.hasAnyViewAnnotation(owner)) errors.push({
782
+ message: "@db.table.preferredId.uniqueIndex is not supported on @db.view interfaces (views have no unique-index declarations).",
783
+ severity: 1,
784
+ range: token.range
785
+ });
786
+ if (owner.countAnnotations("db.table") === 0) errors.push({
787
+ message: "@db.table.preferredId.uniqueIndex requires @db.table on the same interface",
788
+ severity: 1,
789
+ range: token.range
790
+ });
791
+ const groups = collectUniqueIndexGroups(owner);
792
+ if (groups.length === 0) {
793
+ errors.push({
794
+ message: "@db.table.preferredId.uniqueIndex requires at least one @db.index.unique on a prop of this interface.",
795
+ severity: 1,
796
+ range: token.range
797
+ });
798
+ return errors;
799
+ }
800
+ const requestedName = args[0]?.text;
801
+ if (requestedName !== void 0 && !groups.some((group) => group === requestedName)) errors.push({
802
+ message: `@db.table.preferredId.uniqueIndex("${requestedName}") does not match any declared @db.index.unique on this interface; declared groups: ${JSON.stringify(groups)}.`,
803
+ severity: 1,
804
+ range: args[0].range
805
+ });
806
+ if (requestedName === void 0 && groups.length >= 2) errors.push({
807
+ message: "@db.table.preferredId.uniqueIndex without a name uses the first declared unique-index group; this can shift if props are reordered.",
808
+ severity: 2,
809
+ range: token.range
810
+ });
811
+ return errors;
812
+ }
813
+ }) }
768
814
  },
769
815
  schema: new _atscript_core.AnnotationSpec({
770
816
  description: "Assigns the entity to a database schema/namespace.\n\n**Example:**\n```atscript\n@db.table \"users\"\n@db.schema \"auth\"\nexport interface User { ... }\n```\n",
@@ -829,6 +875,24 @@ const dbTableAnnotations = {
829
875
  }
830
876
  }) }
831
877
  };
878
+ function collectUniqueIndexGroups(owner) {
879
+ if (!(0, _atscript_core.isInterface)(owner)) return [];
880
+ const definition = owner.getDefinition();
881
+ if (!(0, _atscript_core.isStructure)(definition)) return [];
882
+ const groups = [];
883
+ const seen = /* @__PURE__ */ new Set();
884
+ for (const [propName, prop] of definition.props) {
885
+ const annotations = prop.annotations?.filter((ann) => ann.name === "db.index.unique") ?? [];
886
+ for (const ann of annotations) {
887
+ const groupName = ann.args[0]?.text ?? propName;
888
+ if (!seen.has(groupName)) {
889
+ seen.add(groupName);
890
+ groups.push(groupName);
891
+ }
892
+ }
893
+ }
894
+ return groups;
895
+ }
832
896
  function tableCapability(capability) {
833
897
  const example = capability === "filterable" ? " @db.column.filterable\n email: string\n // other fields not filterable via the controller\n" : " @db.column.sortable\n createdAt: number.timestamp\n // other fields not sortable via the controller\n";
834
898
  const verb = capability === "filterable" ? "filter" : "sort";
package/dist/plugin.mjs CHANGED
@@ -760,7 +760,53 @@ const dbTableAnnotations = {
760
760
  });
761
761
  return errors;
762
762
  }
763
- })
763
+ }),
764
+ preferredId: { uniqueIndex: new AnnotationSpec({
765
+ description: "Selects a unique index as the table's preferred row identifier. When the unique-index name is omitted, the first declared unique-index group wins.\n\n**Example:**\n```atscript\n@db.table\n@db.table.preferredId.uniqueIndex \"by_slug\"\nexport interface Post {\n @db.index.unique \"by_slug\"\n slug: string\n}\n```\n",
766
+ nodeType: ["interface"],
767
+ multiple: false,
768
+ argument: {
769
+ optional: true,
770
+ name: "name",
771
+ type: "string",
772
+ description: "Unique-index group name. If omitted, the first declared group is used."
773
+ },
774
+ validate(token, args, _doc) {
775
+ const errors = [];
776
+ const owner = token.parentNode;
777
+ if (hasAnyViewAnnotation(owner)) errors.push({
778
+ message: "@db.table.preferredId.uniqueIndex is not supported on @db.view interfaces (views have no unique-index declarations).",
779
+ severity: 1,
780
+ range: token.range
781
+ });
782
+ if (owner.countAnnotations("db.table") === 0) errors.push({
783
+ message: "@db.table.preferredId.uniqueIndex requires @db.table on the same interface",
784
+ severity: 1,
785
+ range: token.range
786
+ });
787
+ const groups = collectUniqueIndexGroups(owner);
788
+ if (groups.length === 0) {
789
+ errors.push({
790
+ message: "@db.table.preferredId.uniqueIndex requires at least one @db.index.unique on a prop of this interface.",
791
+ severity: 1,
792
+ range: token.range
793
+ });
794
+ return errors;
795
+ }
796
+ const requestedName = args[0]?.text;
797
+ if (requestedName !== void 0 && !groups.some((group) => group === requestedName)) errors.push({
798
+ message: `@db.table.preferredId.uniqueIndex("${requestedName}") does not match any declared @db.index.unique on this interface; declared groups: ${JSON.stringify(groups)}.`,
799
+ severity: 1,
800
+ range: args[0].range
801
+ });
802
+ if (requestedName === void 0 && groups.length >= 2) errors.push({
803
+ message: "@db.table.preferredId.uniqueIndex without a name uses the first declared unique-index group; this can shift if props are reordered.",
804
+ severity: 2,
805
+ range: token.range
806
+ });
807
+ return errors;
808
+ }
809
+ }) }
764
810
  },
765
811
  schema: new AnnotationSpec({
766
812
  description: "Assigns the entity to a database schema/namespace.\n\n**Example:**\n```atscript\n@db.table \"users\"\n@db.schema \"auth\"\nexport interface User { ... }\n```\n",
@@ -825,6 +871,24 @@ const dbTableAnnotations = {
825
871
  }
826
872
  }) }
827
873
  };
874
+ function collectUniqueIndexGroups(owner) {
875
+ if (!isInterface(owner)) return [];
876
+ const definition = owner.getDefinition();
877
+ if (!isStructure(definition)) return [];
878
+ const groups = [];
879
+ const seen = /* @__PURE__ */ new Set();
880
+ for (const [propName, prop] of definition.props) {
881
+ const annotations = prop.annotations?.filter((ann) => ann.name === "db.index.unique") ?? [];
882
+ for (const ann of annotations) {
883
+ const groupName = ann.args[0]?.text ?? propName;
884
+ if (!seen.has(groupName)) {
885
+ seen.add(groupName);
886
+ groups.push(groupName);
887
+ }
888
+ }
889
+ }
890
+ return groups;
891
+ }
828
892
  function tableCapability(capability) {
829
893
  const example = capability === "filterable" ? " @db.column.filterable\n email: string\n // other fields not filterable via the controller\n" : " @db.column.sortable\n createdAt: number.timestamp\n // other fields not sortable via the controller\n";
830
894
  const verb = capability === "filterable" ? "filter" : "sort";
package/dist/rel.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as TDbRelation, N as TDbForeignKey, ct as TableMetadata, o as BaseDbAdapter, rt as TWriteTableResolver, tt as TTableResolver, ut as TGenericLogger } from "./db-readable-DN1CJRph.cjs";
1
+ import { F as TDbForeignKey, H as TDbRelation, dt as TableMetadata, it as TTableResolver, o as BaseDbAdapter, ot as TWriteTableResolver, pt as TGenericLogger } from "./db-readable-CKQHMqVH.cjs";
2
2
  import { t as DbValidationContext } from "./db-validator-plugin-DRGMCEn3.cjs";
3
3
  import { FilterExpr, WithRelation } from "@uniqu/core";
4
4
  import { Validator } from "@atscript/typescript/utils";
package/dist/rel.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as TDbRelation, N as TDbForeignKey, ct as TableMetadata, o as BaseDbAdapter, rt as TWriteTableResolver, tt as TTableResolver, ut as TGenericLogger } from "./db-readable-CONS7NPu.mjs";
1
+ import { F as TDbForeignKey, H as TDbRelation, dt as TableMetadata, it as TTableResolver, o as BaseDbAdapter, ot as TWriteTableResolver, pt as TGenericLogger } from "./db-readable-CkeVx10t.mjs";
2
2
  import { t as DbValidationContext } from "./db-validator-plugin-DDvYyv5t.mjs";
3
3
  import { Validator } from "@atscript/typescript/utils";
4
4
  import { FilterExpr, WithRelation } from "@uniqu/core";
package/dist/sync.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_db_view = require("./db-view-DIGN4079.cjs");
2
+ const require_db_view = require("./db-view-CuPkKCnU.cjs");
3
3
  require("./validator-BIuw_T0k.cjs");
4
4
  require("./nested-writer-v_LPR1yJ.cjs");
5
5
  //#region src/schema/schema-hash.ts
package/dist/sync.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as TDbDefaultValue, M as TDbFieldMeta, N as TDbForeignKey, U as TExistingColumn, V as TDbStorageType, W as TExistingTableOption, et as TTableOptionDiff, t as AtscriptDbReadable, ut as TGenericLogger, x as TColumnDiff } from "./db-readable-DN1CJRph.cjs";
2
- import { r as AtscriptDbView, t as DbSpace } from "./db-space-D1dfFoKL.cjs";
1
+ import { C as TColumnDiff, F as TDbForeignKey, G as TExistingColumn, K as TExistingTableOption, M as TDbDefaultValue, P as TDbFieldMeta, U as TDbStorageType, pt as TGenericLogger, rt as TTableOptionDiff, t as AtscriptDbReadable } from "./db-readable-CKQHMqVH.cjs";
2
+ import { r as AtscriptDbView, t as DbSpace } from "./db-space-Dycn4usM.cjs";
3
3
  import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
4
4
 
5
5
  //#region src/schema/sync-entry.d.ts
package/dist/sync.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as TDbDefaultValue, M as TDbFieldMeta, N as TDbForeignKey, U as TExistingColumn, V as TDbStorageType, W as TExistingTableOption, et as TTableOptionDiff, t as AtscriptDbReadable, ut as TGenericLogger, x as TColumnDiff } from "./db-readable-CONS7NPu.mjs";
2
- import { r as AtscriptDbView, t as DbSpace } from "./db-space-DQU38dHk.mjs";
1
+ import { C as TColumnDiff, F as TDbForeignKey, G as TExistingColumn, K as TExistingTableOption, M as TDbDefaultValue, P as TDbFieldMeta, U as TDbStorageType, pt as TGenericLogger, rt as TTableOptionDiff, t as AtscriptDbReadable } from "./db-readable-CkeVx10t.mjs";
2
+ import { r as AtscriptDbView, t as DbSpace } from "./db-space-BAfXlRiV.mjs";
3
3
  import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
4
4
 
5
5
  //#region src/schema/sync-entry.d.ts
package/dist/sync.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { h as NoopLogger } from "./db-view-DNwX6_4x.mjs";
1
+ import { h as NoopLogger } from "./db-view-cBN0YqrV.mjs";
2
2
  import "./validator-BB5h1Le3.mjs";
3
3
  import "./nested-writer-CT2rLURx.mjs";
4
4
  //#region src/schema/schema-hash.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db",
3
- "version": "0.1.58",
3
+ "version": "0.1.60",
4
4
  "description": "Database adapter utilities for atscript.",
5
5
  "keywords": [
6
6
  "atscript",