@atscript/db 0.1.63 → 0.1.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{db-readable-D3bZPucw.d.cts → db-readable-BZN2QKud.d.cts} +35 -0
- package/dist/{db-readable-Dj9to0bC.d.mts → db-readable-vjbawUvu.d.mts} +35 -0
- package/dist/{db-space-CK11BW4j.d.cts → db-space-CxGLp-no.d.mts} +2 -2
- package/dist/{db-space-Dy4GqZrK.d.mts → db-space-Dnjxe6Bt.d.cts} +2 -2
- package/dist/{db-view-Jj46sTBk.cjs → db-view-B028LhoI.cjs} +59 -1
- package/dist/{db-view-T2BrLhwh.mjs → db-view-DiItd0YG.mjs} +59 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/plugin.cjs +120 -8
- package/dist/plugin.mjs +120 -8
- package/dist/rel.d.cts +1 -1
- package/dist/rel.d.mts +1 -1
- package/dist/shared.cjs +3 -1
- package/dist/shared.d.cts +8 -1
- package/dist/shared.d.mts +8 -1
- package/dist/shared.mjs +2 -2
- package/dist/sync.cjs +1 -1
- package/dist/sync.d.cts +2 -2
- package/dist/sync.d.mts +2 -2
- package/dist/sync.mjs +1 -1
- package/dist/{validation-utils-B9WJv9aH.cjs → validation-utils-Bs1yOXNx.cjs} +59 -6
- package/dist/{validation-utils-Bh7RVrVl.mjs → validation-utils-eaBuT39W.mjs} +48 -7
- package/package.json +3 -3
|
@@ -83,6 +83,8 @@ declare class TableMetadata {
|
|
|
83
83
|
columnMap: Map<string, string>;
|
|
84
84
|
dimensions: string[];
|
|
85
85
|
measures: string[];
|
|
86
|
+
/** path → sibling-ref path for `@db.amount.currency.ref` / `@db.unit.ref`. */
|
|
87
|
+
quantityRefByField: Map<string, string>;
|
|
86
88
|
pathToPhysical: Map<string, string>;
|
|
87
89
|
physicalToPath: Map<string, string>;
|
|
88
90
|
flattenedParents: Set<string>;
|
|
@@ -394,6 +396,14 @@ interface TDbFieldMeta {
|
|
|
394
396
|
collate?: TDbCollation;
|
|
395
397
|
/** Whether this field participates in any index (@db.index.plain, @db.index.unique, @db.index.fulltext). */
|
|
396
398
|
isIndexed?: boolean;
|
|
399
|
+
/** Literal currency code from `@db.amount.currency 'EUR'`. */
|
|
400
|
+
currencyCode?: string;
|
|
401
|
+
/** Sibling field path from `@db.amount.currency.ref 'fieldName'`. */
|
|
402
|
+
currencyRefField?: string;
|
|
403
|
+
/** Literal unit-of-measure from `@db.unit 'kg'`. */
|
|
404
|
+
unitCode?: string;
|
|
405
|
+
/** Sibling field path from `@db.unit.ref 'fieldName'`. */
|
|
406
|
+
unitRefField?: string;
|
|
397
407
|
/**
|
|
398
408
|
* For FK fields: the resolved field metadata of the referenced (target) PK column.
|
|
399
409
|
* Adapters use this in `typeMapper` to produce matching DB types for FK columns
|
|
@@ -738,6 +748,27 @@ declare abstract class BaseDbAdapter {
|
|
|
738
748
|
* by finding child records and deleting/nullifying them before the parent.
|
|
739
749
|
*/
|
|
740
750
|
supportsNativeForeignKeys(): boolean;
|
|
751
|
+
/**
|
|
752
|
+
* Whether this adapter can apply equality/range filters on a given field.
|
|
753
|
+
* Default: scalar columns yes, JSON-stored columns (arrays, `@db.json`
|
|
754
|
+
* objects) no — most SQL engines cannot filter into a raw JSON value.
|
|
755
|
+
*
|
|
756
|
+
* Adapters that natively understand JSON storage (e.g. MongoDB filters arrays
|
|
757
|
+
* with implicit `$in` and dot-paths into embedded documents) override to
|
|
758
|
+
* return `true` for `storage === 'json'`.
|
|
759
|
+
*
|
|
760
|
+
* Used by `AsDbReadableController.buildMetaResponse()` to gate the
|
|
761
|
+
* `filterable` flag exposed to UIs — the adapter's answer is a hard gate
|
|
762
|
+
* even when the field carries `@db.column.filterable`.
|
|
763
|
+
*/
|
|
764
|
+
canFilterField(fd: TDbFieldMeta): boolean;
|
|
765
|
+
/**
|
|
766
|
+
* Whether this adapter can sort by a given field.
|
|
767
|
+
* Default: scalar columns yes, JSON-stored columns no. Mongo's array sort
|
|
768
|
+
* (min/max element) is a footgun for generic UI sort headers, so the default
|
|
769
|
+
* stays conservative even for adapters that technically support it.
|
|
770
|
+
*/
|
|
771
|
+
canSortField(fd: TDbFieldMeta): boolean;
|
|
741
772
|
/**
|
|
742
773
|
* Whether this adapter handles `$with` relation loading natively.
|
|
743
774
|
* When `true`, the table layer delegates to {@link loadRelations}
|
|
@@ -1322,6 +1353,10 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
|
|
|
1322
1353
|
aggregate(query: AggregateQuery): Promise<Array<Record<string, unknown>>>;
|
|
1323
1354
|
/** Whether the underlying adapter supports text search. */
|
|
1324
1355
|
isSearchable(): boolean;
|
|
1356
|
+
/** Whether the adapter can filter on a given field (proxies adapter capability). */
|
|
1357
|
+
canFilterField(fd: TDbFieldMeta): boolean;
|
|
1358
|
+
/** Whether the adapter can sort by a given field (proxies adapter capability). */
|
|
1359
|
+
canSortField(fd: TDbFieldMeta): boolean;
|
|
1325
1360
|
/** Returns available search indexes from the adapter. */
|
|
1326
1361
|
getSearchIndexes(): TSearchIndexInfo[];
|
|
1327
1362
|
/**
|
|
@@ -83,6 +83,8 @@ declare class TableMetadata {
|
|
|
83
83
|
columnMap: Map<string, string>;
|
|
84
84
|
dimensions: string[];
|
|
85
85
|
measures: string[];
|
|
86
|
+
/** path → sibling-ref path for `@db.amount.currency.ref` / `@db.unit.ref`. */
|
|
87
|
+
quantityRefByField: Map<string, string>;
|
|
86
88
|
pathToPhysical: Map<string, string>;
|
|
87
89
|
physicalToPath: Map<string, string>;
|
|
88
90
|
flattenedParents: Set<string>;
|
|
@@ -394,6 +396,14 @@ interface TDbFieldMeta {
|
|
|
394
396
|
collate?: TDbCollation;
|
|
395
397
|
/** Whether this field participates in any index (@db.index.plain, @db.index.unique, @db.index.fulltext). */
|
|
396
398
|
isIndexed?: boolean;
|
|
399
|
+
/** Literal currency code from `@db.amount.currency 'EUR'`. */
|
|
400
|
+
currencyCode?: string;
|
|
401
|
+
/** Sibling field path from `@db.amount.currency.ref 'fieldName'`. */
|
|
402
|
+
currencyRefField?: string;
|
|
403
|
+
/** Literal unit-of-measure from `@db.unit 'kg'`. */
|
|
404
|
+
unitCode?: string;
|
|
405
|
+
/** Sibling field path from `@db.unit.ref 'fieldName'`. */
|
|
406
|
+
unitRefField?: string;
|
|
397
407
|
/**
|
|
398
408
|
* For FK fields: the resolved field metadata of the referenced (target) PK column.
|
|
399
409
|
* Adapters use this in `typeMapper` to produce matching DB types for FK columns
|
|
@@ -738,6 +748,27 @@ declare abstract class BaseDbAdapter {
|
|
|
738
748
|
* by finding child records and deleting/nullifying them before the parent.
|
|
739
749
|
*/
|
|
740
750
|
supportsNativeForeignKeys(): boolean;
|
|
751
|
+
/**
|
|
752
|
+
* Whether this adapter can apply equality/range filters on a given field.
|
|
753
|
+
* Default: scalar columns yes, JSON-stored columns (arrays, `@db.json`
|
|
754
|
+
* objects) no — most SQL engines cannot filter into a raw JSON value.
|
|
755
|
+
*
|
|
756
|
+
* Adapters that natively understand JSON storage (e.g. MongoDB filters arrays
|
|
757
|
+
* with implicit `$in` and dot-paths into embedded documents) override to
|
|
758
|
+
* return `true` for `storage === 'json'`.
|
|
759
|
+
*
|
|
760
|
+
* Used by `AsDbReadableController.buildMetaResponse()` to gate the
|
|
761
|
+
* `filterable` flag exposed to UIs — the adapter's answer is a hard gate
|
|
762
|
+
* even when the field carries `@db.column.filterable`.
|
|
763
|
+
*/
|
|
764
|
+
canFilterField(fd: TDbFieldMeta): boolean;
|
|
765
|
+
/**
|
|
766
|
+
* Whether this adapter can sort by a given field.
|
|
767
|
+
* Default: scalar columns yes, JSON-stored columns no. Mongo's array sort
|
|
768
|
+
* (min/max element) is a footgun for generic UI sort headers, so the default
|
|
769
|
+
* stays conservative even for adapters that technically support it.
|
|
770
|
+
*/
|
|
771
|
+
canSortField(fd: TDbFieldMeta): boolean;
|
|
741
772
|
/**
|
|
742
773
|
* Whether this adapter handles `$with` relation loading natively.
|
|
743
774
|
* When `true`, the table layer delegates to {@link loadRelations}
|
|
@@ -1322,6 +1353,10 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
|
|
|
1322
1353
|
aggregate(query: AggregateQuery): Promise<Array<Record<string, unknown>>>;
|
|
1323
1354
|
/** Whether the underlying adapter supports text search. */
|
|
1324
1355
|
isSearchable(): boolean;
|
|
1356
|
+
/** Whether the adapter can filter on a given field (proxies adapter capability). */
|
|
1357
|
+
canFilterField(fd: TDbFieldMeta): boolean;
|
|
1358
|
+
/** Whether the adapter can sort by a given field (proxies adapter capability). */
|
|
1359
|
+
canSortField(fd: TDbFieldMeta): boolean;
|
|
1325
1360
|
/** Returns available search indexes from the adapter. */
|
|
1326
1361
|
getSearchIndexes(): TSearchIndexInfo[];
|
|
1327
1362
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
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-
|
|
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-vjbawUvu.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 { 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-
|
|
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-BZN2QKud.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
|
/**
|
|
@@ -64,6 +64,8 @@ var TableMetadata = class {
|
|
|
64
64
|
columnMap = /* @__PURE__ */ new Map();
|
|
65
65
|
dimensions = [];
|
|
66
66
|
measures = [];
|
|
67
|
+
/** path → sibling-ref path for `@db.amount.currency.ref` / `@db.unit.ref`. */
|
|
68
|
+
quantityRefByField = /* @__PURE__ */ new Map();
|
|
67
69
|
pathToPhysical = /* @__PURE__ */ new Map();
|
|
68
70
|
physicalToPath = /* @__PURE__ */ new Map();
|
|
69
71
|
flattenedParents = /* @__PURE__ */ new Set();
|
|
@@ -361,6 +363,12 @@ var TableMetadata = class {
|
|
|
361
363
|
const fromLocal = this._columnFromMap.get(path);
|
|
362
364
|
let renamedFrom;
|
|
363
365
|
if (fromLocal) renamedFrom = isFlattened ? this._flattenedPrefix(path) + fromLocal : fromLocal;
|
|
366
|
+
const currencyCode = type.metadata.get("db.amount.currency");
|
|
367
|
+
const currencyRefField = type.metadata.get("db.amount.currency.ref");
|
|
368
|
+
const unitCode = type.metadata.get("db.unit");
|
|
369
|
+
const unitRefField = type.metadata.get("db.unit.ref");
|
|
370
|
+
const quantityRef = currencyRefField ?? unitRefField;
|
|
371
|
+
if (quantityRef) this.quantityRefByField.set(path, quantityRef);
|
|
364
372
|
descriptors.push({
|
|
365
373
|
path,
|
|
366
374
|
type,
|
|
@@ -374,7 +382,11 @@ var TableMetadata = class {
|
|
|
374
382
|
flattenedFrom: isFlattened ? path : void 0,
|
|
375
383
|
renamedFrom,
|
|
376
384
|
collate: this._collateMap.get(path),
|
|
377
|
-
isIndexed: indexedFields.has(path) || void 0
|
|
385
|
+
isIndexed: indexedFields.has(path) || void 0,
|
|
386
|
+
currencyCode,
|
|
387
|
+
currencyRefField,
|
|
388
|
+
unitCode,
|
|
389
|
+
unitRefField
|
|
378
390
|
});
|
|
379
391
|
}
|
|
380
392
|
this._resolveFkTargetFields(descriptors);
|
|
@@ -1407,6 +1419,19 @@ var AtscriptDbReadable = class {
|
|
|
1407
1419
|
}]);
|
|
1408
1420
|
}
|
|
1409
1421
|
}
|
|
1422
|
+
const { quantityRefByField } = this._meta;
|
|
1423
|
+
if ($select && quantityRefByField.size > 0) {
|
|
1424
|
+
const groupBySet = new Set($groupBy);
|
|
1425
|
+
for (const item of $select) {
|
|
1426
|
+
if (typeof item === "string") continue;
|
|
1427
|
+
if (item.$field === "*") continue;
|
|
1428
|
+
const refField = quantityRefByField.get(item.$field);
|
|
1429
|
+
if (refField && !groupBySet.has(refField)) throw new require_db_error.DbError("INVALID_QUERY", [{
|
|
1430
|
+
path: "$select",
|
|
1431
|
+
message: `Aggregate "${item.$fn}(${item.$field})" requires "${refField}" in $groupBy — quantity-ref-tagged fields must be grouped by their dimension`
|
|
1432
|
+
}]);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1410
1435
|
const dbQuery = this._fieldMapper.translateAggregateQuery(query, this._meta);
|
|
1411
1436
|
return (await this.adapter.aggregate(dbQuery)).map((row) => {
|
|
1412
1437
|
const mapped = {};
|
|
@@ -1422,6 +1447,14 @@ var AtscriptDbReadable = class {
|
|
|
1422
1447
|
isSearchable() {
|
|
1423
1448
|
return this.adapter.isSearchable();
|
|
1424
1449
|
}
|
|
1450
|
+
/** Whether the adapter can filter on a given field (proxies adapter capability). */
|
|
1451
|
+
canFilterField(fd) {
|
|
1452
|
+
return this.adapter.canFilterField(fd);
|
|
1453
|
+
}
|
|
1454
|
+
/** Whether the adapter can sort by a given field (proxies adapter capability). */
|
|
1455
|
+
canSortField(fd) {
|
|
1456
|
+
return this.adapter.canSortField(fd);
|
|
1457
|
+
}
|
|
1425
1458
|
/** Returns available search indexes from the adapter. */
|
|
1426
1459
|
getSearchIndexes() {
|
|
1427
1460
|
return this.adapter.getSearchIndexes();
|
|
@@ -1821,6 +1854,31 @@ var BaseDbAdapter = class {
|
|
|
1821
1854
|
return false;
|
|
1822
1855
|
}
|
|
1823
1856
|
/**
|
|
1857
|
+
* Whether this adapter can apply equality/range filters on a given field.
|
|
1858
|
+
* Default: scalar columns yes, JSON-stored columns (arrays, `@db.json`
|
|
1859
|
+
* objects) no — most SQL engines cannot filter into a raw JSON value.
|
|
1860
|
+
*
|
|
1861
|
+
* Adapters that natively understand JSON storage (e.g. MongoDB filters arrays
|
|
1862
|
+
* with implicit `$in` and dot-paths into embedded documents) override to
|
|
1863
|
+
* return `true` for `storage === 'json'`.
|
|
1864
|
+
*
|
|
1865
|
+
* Used by `AsDbReadableController.buildMetaResponse()` to gate the
|
|
1866
|
+
* `filterable` flag exposed to UIs — the adapter's answer is a hard gate
|
|
1867
|
+
* even when the field carries `@db.column.filterable`.
|
|
1868
|
+
*/
|
|
1869
|
+
canFilterField(fd) {
|
|
1870
|
+
return fd.storage !== "json";
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Whether this adapter can sort by a given field.
|
|
1874
|
+
* Default: scalar columns yes, JSON-stored columns no. Mongo's array sort
|
|
1875
|
+
* (min/max element) is a footgun for generic UI sort headers, so the default
|
|
1876
|
+
* stays conservative even for adapters that technically support it.
|
|
1877
|
+
*/
|
|
1878
|
+
canSortField(fd) {
|
|
1879
|
+
return fd.storage !== "json";
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1824
1882
|
* Whether this adapter handles `$with` relation loading natively.
|
|
1825
1883
|
* When `true`, the table layer delegates to {@link loadRelations}
|
|
1826
1884
|
* instead of using the generic batch-loading strategy.
|
|
@@ -64,6 +64,8 @@ var TableMetadata = class {
|
|
|
64
64
|
columnMap = /* @__PURE__ */ new Map();
|
|
65
65
|
dimensions = [];
|
|
66
66
|
measures = [];
|
|
67
|
+
/** path → sibling-ref path for `@db.amount.currency.ref` / `@db.unit.ref`. */
|
|
68
|
+
quantityRefByField = /* @__PURE__ */ new Map();
|
|
67
69
|
pathToPhysical = /* @__PURE__ */ new Map();
|
|
68
70
|
physicalToPath = /* @__PURE__ */ new Map();
|
|
69
71
|
flattenedParents = /* @__PURE__ */ new Set();
|
|
@@ -361,6 +363,12 @@ var TableMetadata = class {
|
|
|
361
363
|
const fromLocal = this._columnFromMap.get(path);
|
|
362
364
|
let renamedFrom;
|
|
363
365
|
if (fromLocal) renamedFrom = isFlattened ? this._flattenedPrefix(path) + fromLocal : fromLocal;
|
|
366
|
+
const currencyCode = type.metadata.get("db.amount.currency");
|
|
367
|
+
const currencyRefField = type.metadata.get("db.amount.currency.ref");
|
|
368
|
+
const unitCode = type.metadata.get("db.unit");
|
|
369
|
+
const unitRefField = type.metadata.get("db.unit.ref");
|
|
370
|
+
const quantityRef = currencyRefField ?? unitRefField;
|
|
371
|
+
if (quantityRef) this.quantityRefByField.set(path, quantityRef);
|
|
364
372
|
descriptors.push({
|
|
365
373
|
path,
|
|
366
374
|
type,
|
|
@@ -374,7 +382,11 @@ var TableMetadata = class {
|
|
|
374
382
|
flattenedFrom: isFlattened ? path : void 0,
|
|
375
383
|
renamedFrom,
|
|
376
384
|
collate: this._collateMap.get(path),
|
|
377
|
-
isIndexed: indexedFields.has(path) || void 0
|
|
385
|
+
isIndexed: indexedFields.has(path) || void 0,
|
|
386
|
+
currencyCode,
|
|
387
|
+
currencyRefField,
|
|
388
|
+
unitCode,
|
|
389
|
+
unitRefField
|
|
378
390
|
});
|
|
379
391
|
}
|
|
380
392
|
this._resolveFkTargetFields(descriptors);
|
|
@@ -1407,6 +1419,19 @@ var AtscriptDbReadable = class {
|
|
|
1407
1419
|
}]);
|
|
1408
1420
|
}
|
|
1409
1421
|
}
|
|
1422
|
+
const { quantityRefByField } = this._meta;
|
|
1423
|
+
if ($select && quantityRefByField.size > 0) {
|
|
1424
|
+
const groupBySet = new Set($groupBy);
|
|
1425
|
+
for (const item of $select) {
|
|
1426
|
+
if (typeof item === "string") continue;
|
|
1427
|
+
if (item.$field === "*") continue;
|
|
1428
|
+
const refField = quantityRefByField.get(item.$field);
|
|
1429
|
+
if (refField && !groupBySet.has(refField)) throw new DbError("INVALID_QUERY", [{
|
|
1430
|
+
path: "$select",
|
|
1431
|
+
message: `Aggregate "${item.$fn}(${item.$field})" requires "${refField}" in $groupBy — quantity-ref-tagged fields must be grouped by their dimension`
|
|
1432
|
+
}]);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1410
1435
|
const dbQuery = this._fieldMapper.translateAggregateQuery(query, this._meta);
|
|
1411
1436
|
return (await this.adapter.aggregate(dbQuery)).map((row) => {
|
|
1412
1437
|
const mapped = {};
|
|
@@ -1422,6 +1447,14 @@ var AtscriptDbReadable = class {
|
|
|
1422
1447
|
isSearchable() {
|
|
1423
1448
|
return this.adapter.isSearchable();
|
|
1424
1449
|
}
|
|
1450
|
+
/** Whether the adapter can filter on a given field (proxies adapter capability). */
|
|
1451
|
+
canFilterField(fd) {
|
|
1452
|
+
return this.adapter.canFilterField(fd);
|
|
1453
|
+
}
|
|
1454
|
+
/** Whether the adapter can sort by a given field (proxies adapter capability). */
|
|
1455
|
+
canSortField(fd) {
|
|
1456
|
+
return this.adapter.canSortField(fd);
|
|
1457
|
+
}
|
|
1425
1458
|
/** Returns available search indexes from the adapter. */
|
|
1426
1459
|
getSearchIndexes() {
|
|
1427
1460
|
return this.adapter.getSearchIndexes();
|
|
@@ -1821,6 +1854,31 @@ var BaseDbAdapter = class {
|
|
|
1821
1854
|
return false;
|
|
1822
1855
|
}
|
|
1823
1856
|
/**
|
|
1857
|
+
* Whether this adapter can apply equality/range filters on a given field.
|
|
1858
|
+
* Default: scalar columns yes, JSON-stored columns (arrays, `@db.json`
|
|
1859
|
+
* objects) no — most SQL engines cannot filter into a raw JSON value.
|
|
1860
|
+
*
|
|
1861
|
+
* Adapters that natively understand JSON storage (e.g. MongoDB filters arrays
|
|
1862
|
+
* with implicit `$in` and dot-paths into embedded documents) override to
|
|
1863
|
+
* return `true` for `storage === 'json'`.
|
|
1864
|
+
*
|
|
1865
|
+
* Used by `AsDbReadableController.buildMetaResponse()` to gate the
|
|
1866
|
+
* `filterable` flag exposed to UIs — the adapter's answer is a hard gate
|
|
1867
|
+
* even when the field carries `@db.column.filterable`.
|
|
1868
|
+
*/
|
|
1869
|
+
canFilterField(fd) {
|
|
1870
|
+
return fd.storage !== "json";
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Whether this adapter can sort by a given field.
|
|
1874
|
+
* Default: scalar columns yes, JSON-stored columns no. Mongo's array sort
|
|
1875
|
+
* (min/max element) is a footgun for generic UI sort headers, so the default
|
|
1876
|
+
* stays conservative even for adapters that technically support it.
|
|
1877
|
+
*/
|
|
1878
|
+
canSortField(fd) {
|
|
1879
|
+
return fd.storage !== "json";
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1824
1882
|
* Whether this adapter handles `$with` relation loading natively.
|
|
1825
1883
|
* When `true`, the table layer delegates to {@link loadRelations}
|
|
1826
1884
|
* instead of using the generic batch-loading strategy.
|
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-
|
|
3
|
+
const require_db_view = require("./db-view-B028LhoI.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 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-
|
|
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-BZN2QKud.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-
|
|
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-Dnjxe6Bt.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";
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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-
|
|
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-vjbawUvu.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-
|
|
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-CxGLp-no.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";
|
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-
|
|
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-DiItd0YG.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
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_validation_utils = require("./validation-utils-
|
|
5
|
+
const require_validation_utils = require("./validation-utils-Bs1yOXNx.cjs");
|
|
6
6
|
let _atscript_core = require("@atscript/core");
|
|
7
7
|
//#region src/plugin/annotations/agg.ts
|
|
8
8
|
const dbAggAnnotations = { agg: {
|
|
@@ -63,6 +63,59 @@ const dbAggAnnotations = { agg: {
|
|
|
63
63
|
})
|
|
64
64
|
} };
|
|
65
65
|
//#endregion
|
|
66
|
+
//#region src/plugin/annotations/amount.ts
|
|
67
|
+
const CURRENCY_CODE_PATTERN = /^[A-Z0-9]{2,10}$/;
|
|
68
|
+
const dbAmountAnnotations = { amount: { currency: {
|
|
69
|
+
$self: new _atscript_core.AnnotationSpec({
|
|
70
|
+
description: "Hard-coded **currency code** for this amount field. Use when a table stores amounts in a single, fixed currency.\n\nFor per-row currency, use `@db.amount.currency.ref 'fieldName'` instead.\n\nOnly valid on `decimal` fields — money in floating-point is wrong.\n\n**Example:**\n```atscript\n@db.amount.currency 'EUR'\namount: decimal\n```\n",
|
|
71
|
+
nodeType: ["prop"],
|
|
72
|
+
multiple: false,
|
|
73
|
+
argument: {
|
|
74
|
+
name: "code",
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "Currency code — uppercase 2–10 alphanumerics (ISO 4217 or custom: 'EUR', 'USD', 'BTC')."
|
|
77
|
+
},
|
|
78
|
+
validate(token, args, doc) {
|
|
79
|
+
const errors = [];
|
|
80
|
+
errors.push(...require_validation_utils.validateFieldBaseType(token, doc, "@db.amount.currency", "decimal"));
|
|
81
|
+
errors.push(...require_validation_utils.validateExclusiveWith(token, "@db.amount.currency", [{
|
|
82
|
+
key: "db.amount.currency.ref",
|
|
83
|
+
displayName: "@db.amount.currency.ref"
|
|
84
|
+
}]));
|
|
85
|
+
const code = args[0]?.text;
|
|
86
|
+
if (code && !CURRENCY_CODE_PATTERN.test(code)) errors.push({
|
|
87
|
+
message: `@db.amount.currency '${code}': invalid currency code (expected 2–10 uppercase letters or digits)`,
|
|
88
|
+
severity: 1,
|
|
89
|
+
range: token.range
|
|
90
|
+
});
|
|
91
|
+
return errors;
|
|
92
|
+
}
|
|
93
|
+
}),
|
|
94
|
+
ref: new _atscript_core.AnnotationSpec({
|
|
95
|
+
description: "Binds this amount to a **sibling field** that holds its currency code. Use when each row may have a different currency.\n\nThe referenced field should be of type `db.currencyCode` (or at least a `string`).\n\nOnly valid on `decimal` fields.\n\n**Example:**\n```atscript\ncurrency: db.currencyCode\n@db.amount.currency.ref 'currency'\namount: decimal\n```\n",
|
|
96
|
+
nodeType: ["prop"],
|
|
97
|
+
multiple: false,
|
|
98
|
+
argument: {
|
|
99
|
+
name: "fieldName",
|
|
100
|
+
type: "string",
|
|
101
|
+
description: "Name of the sibling property holding the currency code."
|
|
102
|
+
},
|
|
103
|
+
validate(token, args, doc) {
|
|
104
|
+
const errors = [];
|
|
105
|
+
errors.push(...require_validation_utils.validateFieldBaseType(token, doc, "@db.amount.currency.ref", "decimal"));
|
|
106
|
+
errors.push(...require_validation_utils.validateExclusiveWith(token, "@db.amount.currency.ref", [{
|
|
107
|
+
key: "db.amount.currency",
|
|
108
|
+
displayName: "@db.amount.currency"
|
|
109
|
+
}, {
|
|
110
|
+
key: "db.unit.ref",
|
|
111
|
+
displayName: "@db.unit.ref"
|
|
112
|
+
}]));
|
|
113
|
+
errors.push(...require_validation_utils.validateSiblingStringField(token, args, doc, "@db.amount.currency.ref"));
|
|
114
|
+
return errors;
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
} } };
|
|
118
|
+
//#endregion
|
|
66
119
|
//#region src/plugin/annotations/column.ts
|
|
67
120
|
const dbColumnAnnotations = {
|
|
68
121
|
patch: { strategy: new _atscript_core.AnnotationSpec({
|
|
@@ -927,6 +980,53 @@ Writing the annotation explicitly as \`@db.table.${capability} 'auto'\` has the
|
|
|
927
980
|
});
|
|
928
981
|
}
|
|
929
982
|
//#endregion
|
|
983
|
+
//#region src/plugin/annotations/unit.ts
|
|
984
|
+
const UNIT_HOST_TYPES = ["decimal", "number"];
|
|
985
|
+
const dbUnitAnnotations = { unit: {
|
|
986
|
+
$self: new _atscript_core.AnnotationSpec({
|
|
987
|
+
description: "Hard-coded **unit of measure** for this quantity field. Use when a table stores all values for this field in a single, fixed unit.\n\nFor per-row units, use `@db.unit.ref 'fieldName'` instead.\n\nValid on `decimal` and `number` fields. Unlike `@db.amount.currency`, the unit code is free-form (`'kg'`, `'rpm'`, `'qps'`, …) — no ISO-style validation.\n\nAggregations on a unit-tagged field do not need grouping when the unit is a fixed literal — the constraint is satisfied schema-wide.\n\n**Example:**\n```atscript\n@db.unit 'kg'\nweight: decimal\n```\n",
|
|
988
|
+
nodeType: ["prop"],
|
|
989
|
+
multiple: false,
|
|
990
|
+
argument: {
|
|
991
|
+
name: "code",
|
|
992
|
+
type: "string",
|
|
993
|
+
description: "Unit code (free-form: 'kg', 'g', 'lb', 'm', 'rpm', 'qps', etc.)."
|
|
994
|
+
},
|
|
995
|
+
validate(token, _args, doc) {
|
|
996
|
+
const errors = [];
|
|
997
|
+
errors.push(...require_validation_utils.validateFieldBaseType(token, doc, "@db.unit", UNIT_HOST_TYPES));
|
|
998
|
+
errors.push(...require_validation_utils.validateExclusiveWith(token, "@db.unit", [{
|
|
999
|
+
key: "db.unit.ref",
|
|
1000
|
+
displayName: "@db.unit.ref"
|
|
1001
|
+
}]));
|
|
1002
|
+
return errors;
|
|
1003
|
+
}
|
|
1004
|
+
}),
|
|
1005
|
+
ref: new _atscript_core.AnnotationSpec({
|
|
1006
|
+
description: "Binds this quantity to a **sibling field** that holds its unit. Use when different rows may carry different units (e.g. mixed kg/lb measurements).\n\nThe referenced field must be a `string`.\n\nValid on `decimal` and `number` fields. Aggregating this field forces the referenced unit field into `$groupBy` at runtime — summing rows with different units is rejected.\n\n**Example:**\n```atscript\nunit: string\n@db.unit.ref 'unit'\nweight: decimal\n```\n",
|
|
1007
|
+
nodeType: ["prop"],
|
|
1008
|
+
multiple: false,
|
|
1009
|
+
argument: {
|
|
1010
|
+
name: "fieldName",
|
|
1011
|
+
type: "string",
|
|
1012
|
+
description: "Name of the sibling property holding the unit code."
|
|
1013
|
+
},
|
|
1014
|
+
validate(token, args, doc) {
|
|
1015
|
+
const errors = [];
|
|
1016
|
+
errors.push(...require_validation_utils.validateFieldBaseType(token, doc, "@db.unit.ref", UNIT_HOST_TYPES));
|
|
1017
|
+
errors.push(...require_validation_utils.validateExclusiveWith(token, "@db.unit.ref", [{
|
|
1018
|
+
key: "db.unit",
|
|
1019
|
+
displayName: "@db.unit"
|
|
1020
|
+
}, {
|
|
1021
|
+
key: "db.amount.currency.ref",
|
|
1022
|
+
displayName: "@db.amount.currency.ref"
|
|
1023
|
+
}]));
|
|
1024
|
+
errors.push(...require_validation_utils.validateSiblingStringField(token, args, doc, "@db.unit.ref"));
|
|
1025
|
+
return errors;
|
|
1026
|
+
}
|
|
1027
|
+
})
|
|
1028
|
+
} };
|
|
1029
|
+
//#endregion
|
|
930
1030
|
//#region src/plugin/annotations/view.ts
|
|
931
1031
|
const dbViewAnnotations = { view: {
|
|
932
1032
|
$self: new _atscript_core.AnnotationSpec({
|
|
@@ -1121,15 +1221,27 @@ const dbPlugin = () => ({
|
|
|
1121
1221
|
rel: dbRelAnnotations.rel,
|
|
1122
1222
|
view: dbViewAnnotations.view,
|
|
1123
1223
|
agg: dbAggAnnotations.agg,
|
|
1124
|
-
search: dbSearchAnnotations.search
|
|
1224
|
+
search: dbSearchAnnotations.search,
|
|
1225
|
+
amount: dbAmountAnnotations.amount,
|
|
1226
|
+
unit: dbUnitAnnotations.unit
|
|
1125
1227
|
} },
|
|
1126
|
-
primitives: { db: { extensions: {
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1228
|
+
primitives: { db: { extensions: {
|
|
1229
|
+
vector: {
|
|
1230
|
+
type: {
|
|
1231
|
+
kind: "array",
|
|
1232
|
+
of: "number"
|
|
1233
|
+
},
|
|
1234
|
+
documentation: "Represents a **vector embedding** (array of numbers) for **similarity search**.\n\n- Equivalent to `number[]` but explicitly marks the field as a vector embedding.\n- Each adapter maps this to its native vector type:\n - **MongoDB** → BSON array\n - **MySQL 9+** → `VECTOR(N)`\n - **PostgreSQL** → pgvector `vector(N)`\n - **SQLite** → JSON\n\n**Example:**\n```atscript\n@db.search.vector 1536, \"cosine\"\nembedding: db.vector\n```\n"
|
|
1130
1235
|
},
|
|
1131
|
-
|
|
1132
|
-
|
|
1236
|
+
currencyCode: {
|
|
1237
|
+
type: "string",
|
|
1238
|
+
documentation: "Represents a **currency code** — typically ISO 4217 (`'USD'`, `'EUR'`, `'JPY'`) but accepts any uppercase alphanumeric code 2–10 chars long, so crypto and custom codes (`'BTC'`, `'USDC'`, `'POINTS'`) fit too.\n\nPair with `@db.amount.currency.ref 'fieldName'` on a `decimal` field to bind the amount to its row-level currency. The validator checks that the ref target resolves to this type (or a plain `string`).\n\n**Example:**\n```atscript\ncurrency: db.currencyCode\n@db.amount.currency.ref 'currency'\namount: decimal\n```\n",
|
|
1239
|
+
annotations: { "expect.pattern": [{
|
|
1240
|
+
pattern: "^[A-Z0-9]{2,10}$",
|
|
1241
|
+
message: "Invalid currency code (expected 2–10 uppercase letters or digits)"
|
|
1242
|
+
}] }
|
|
1243
|
+
}
|
|
1244
|
+
} } }
|
|
1133
1245
|
};
|
|
1134
1246
|
}
|
|
1135
1247
|
});
|
package/dist/plugin.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getAnnotationAlias, c as getParentStruct, d as validateFieldBaseType, i as validateRefArgument, l as getParentTypeName, n as hasAnyViewAnnotation, o as getDbTableOwner, r as validateQueryScope, s as getNavTargetTypeName, t as findFKFieldsPointingTo, u as refActionAnnotation } from "./validation-utils-
|
|
1
|
+
import { a as getAnnotationAlias, c as getParentStruct, d as validateExclusiveWith, f as validateFieldBaseType, i as validateRefArgument, l as getParentTypeName, n as hasAnyViewAnnotation, o as getDbTableOwner, p as validateSiblingStringField, r as validateQueryScope, s as getNavTargetTypeName, t as findFKFieldsPointingTo, u as refActionAnnotation } from "./validation-utils-eaBuT39W.mjs";
|
|
2
2
|
import { AnnotationSpec, isArray, isInterface, isPrimitive, isRef, isStructure } from "@atscript/core";
|
|
3
3
|
//#region src/plugin/annotations/agg.ts
|
|
4
4
|
const dbAggAnnotations = { agg: {
|
|
@@ -59,6 +59,59 @@ const dbAggAnnotations = { agg: {
|
|
|
59
59
|
})
|
|
60
60
|
} };
|
|
61
61
|
//#endregion
|
|
62
|
+
//#region src/plugin/annotations/amount.ts
|
|
63
|
+
const CURRENCY_CODE_PATTERN = /^[A-Z0-9]{2,10}$/;
|
|
64
|
+
const dbAmountAnnotations = { amount: { currency: {
|
|
65
|
+
$self: new AnnotationSpec({
|
|
66
|
+
description: "Hard-coded **currency code** for this amount field. Use when a table stores amounts in a single, fixed currency.\n\nFor per-row currency, use `@db.amount.currency.ref 'fieldName'` instead.\n\nOnly valid on `decimal` fields — money in floating-point is wrong.\n\n**Example:**\n```atscript\n@db.amount.currency 'EUR'\namount: decimal\n```\n",
|
|
67
|
+
nodeType: ["prop"],
|
|
68
|
+
multiple: false,
|
|
69
|
+
argument: {
|
|
70
|
+
name: "code",
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "Currency code — uppercase 2–10 alphanumerics (ISO 4217 or custom: 'EUR', 'USD', 'BTC')."
|
|
73
|
+
},
|
|
74
|
+
validate(token, args, doc) {
|
|
75
|
+
const errors = [];
|
|
76
|
+
errors.push(...validateFieldBaseType(token, doc, "@db.amount.currency", "decimal"));
|
|
77
|
+
errors.push(...validateExclusiveWith(token, "@db.amount.currency", [{
|
|
78
|
+
key: "db.amount.currency.ref",
|
|
79
|
+
displayName: "@db.amount.currency.ref"
|
|
80
|
+
}]));
|
|
81
|
+
const code = args[0]?.text;
|
|
82
|
+
if (code && !CURRENCY_CODE_PATTERN.test(code)) errors.push({
|
|
83
|
+
message: `@db.amount.currency '${code}': invalid currency code (expected 2–10 uppercase letters or digits)`,
|
|
84
|
+
severity: 1,
|
|
85
|
+
range: token.range
|
|
86
|
+
});
|
|
87
|
+
return errors;
|
|
88
|
+
}
|
|
89
|
+
}),
|
|
90
|
+
ref: new AnnotationSpec({
|
|
91
|
+
description: "Binds this amount to a **sibling field** that holds its currency code. Use when each row may have a different currency.\n\nThe referenced field should be of type `db.currencyCode` (or at least a `string`).\n\nOnly valid on `decimal` fields.\n\n**Example:**\n```atscript\ncurrency: db.currencyCode\n@db.amount.currency.ref 'currency'\namount: decimal\n```\n",
|
|
92
|
+
nodeType: ["prop"],
|
|
93
|
+
multiple: false,
|
|
94
|
+
argument: {
|
|
95
|
+
name: "fieldName",
|
|
96
|
+
type: "string",
|
|
97
|
+
description: "Name of the sibling property holding the currency code."
|
|
98
|
+
},
|
|
99
|
+
validate(token, args, doc) {
|
|
100
|
+
const errors = [];
|
|
101
|
+
errors.push(...validateFieldBaseType(token, doc, "@db.amount.currency.ref", "decimal"));
|
|
102
|
+
errors.push(...validateExclusiveWith(token, "@db.amount.currency.ref", [{
|
|
103
|
+
key: "db.amount.currency",
|
|
104
|
+
displayName: "@db.amount.currency"
|
|
105
|
+
}, {
|
|
106
|
+
key: "db.unit.ref",
|
|
107
|
+
displayName: "@db.unit.ref"
|
|
108
|
+
}]));
|
|
109
|
+
errors.push(...validateSiblingStringField(token, args, doc, "@db.amount.currency.ref"));
|
|
110
|
+
return errors;
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
} } };
|
|
114
|
+
//#endregion
|
|
62
115
|
//#region src/plugin/annotations/column.ts
|
|
63
116
|
const dbColumnAnnotations = {
|
|
64
117
|
patch: { strategy: new AnnotationSpec({
|
|
@@ -923,6 +976,53 @@ Writing the annotation explicitly as \`@db.table.${capability} 'auto'\` has the
|
|
|
923
976
|
});
|
|
924
977
|
}
|
|
925
978
|
//#endregion
|
|
979
|
+
//#region src/plugin/annotations/unit.ts
|
|
980
|
+
const UNIT_HOST_TYPES = ["decimal", "number"];
|
|
981
|
+
const dbUnitAnnotations = { unit: {
|
|
982
|
+
$self: new AnnotationSpec({
|
|
983
|
+
description: "Hard-coded **unit of measure** for this quantity field. Use when a table stores all values for this field in a single, fixed unit.\n\nFor per-row units, use `@db.unit.ref 'fieldName'` instead.\n\nValid on `decimal` and `number` fields. Unlike `@db.amount.currency`, the unit code is free-form (`'kg'`, `'rpm'`, `'qps'`, …) — no ISO-style validation.\n\nAggregations on a unit-tagged field do not need grouping when the unit is a fixed literal — the constraint is satisfied schema-wide.\n\n**Example:**\n```atscript\n@db.unit 'kg'\nweight: decimal\n```\n",
|
|
984
|
+
nodeType: ["prop"],
|
|
985
|
+
multiple: false,
|
|
986
|
+
argument: {
|
|
987
|
+
name: "code",
|
|
988
|
+
type: "string",
|
|
989
|
+
description: "Unit code (free-form: 'kg', 'g', 'lb', 'm', 'rpm', 'qps', etc.)."
|
|
990
|
+
},
|
|
991
|
+
validate(token, _args, doc) {
|
|
992
|
+
const errors = [];
|
|
993
|
+
errors.push(...validateFieldBaseType(token, doc, "@db.unit", UNIT_HOST_TYPES));
|
|
994
|
+
errors.push(...validateExclusiveWith(token, "@db.unit", [{
|
|
995
|
+
key: "db.unit.ref",
|
|
996
|
+
displayName: "@db.unit.ref"
|
|
997
|
+
}]));
|
|
998
|
+
return errors;
|
|
999
|
+
}
|
|
1000
|
+
}),
|
|
1001
|
+
ref: new AnnotationSpec({
|
|
1002
|
+
description: "Binds this quantity to a **sibling field** that holds its unit. Use when different rows may carry different units (e.g. mixed kg/lb measurements).\n\nThe referenced field must be a `string`.\n\nValid on `decimal` and `number` fields. Aggregating this field forces the referenced unit field into `$groupBy` at runtime — summing rows with different units is rejected.\n\n**Example:**\n```atscript\nunit: string\n@db.unit.ref 'unit'\nweight: decimal\n```\n",
|
|
1003
|
+
nodeType: ["prop"],
|
|
1004
|
+
multiple: false,
|
|
1005
|
+
argument: {
|
|
1006
|
+
name: "fieldName",
|
|
1007
|
+
type: "string",
|
|
1008
|
+
description: "Name of the sibling property holding the unit code."
|
|
1009
|
+
},
|
|
1010
|
+
validate(token, args, doc) {
|
|
1011
|
+
const errors = [];
|
|
1012
|
+
errors.push(...validateFieldBaseType(token, doc, "@db.unit.ref", UNIT_HOST_TYPES));
|
|
1013
|
+
errors.push(...validateExclusiveWith(token, "@db.unit.ref", [{
|
|
1014
|
+
key: "db.unit",
|
|
1015
|
+
displayName: "@db.unit"
|
|
1016
|
+
}, {
|
|
1017
|
+
key: "db.amount.currency.ref",
|
|
1018
|
+
displayName: "@db.amount.currency.ref"
|
|
1019
|
+
}]));
|
|
1020
|
+
errors.push(...validateSiblingStringField(token, args, doc, "@db.unit.ref"));
|
|
1021
|
+
return errors;
|
|
1022
|
+
}
|
|
1023
|
+
})
|
|
1024
|
+
} };
|
|
1025
|
+
//#endregion
|
|
926
1026
|
//#region src/plugin/annotations/view.ts
|
|
927
1027
|
const dbViewAnnotations = { view: {
|
|
928
1028
|
$self: new AnnotationSpec({
|
|
@@ -1117,15 +1217,27 @@ const dbPlugin = () => ({
|
|
|
1117
1217
|
rel: dbRelAnnotations.rel,
|
|
1118
1218
|
view: dbViewAnnotations.view,
|
|
1119
1219
|
agg: dbAggAnnotations.agg,
|
|
1120
|
-
search: dbSearchAnnotations.search
|
|
1220
|
+
search: dbSearchAnnotations.search,
|
|
1221
|
+
amount: dbAmountAnnotations.amount,
|
|
1222
|
+
unit: dbUnitAnnotations.unit
|
|
1121
1223
|
} },
|
|
1122
|
-
primitives: { db: { extensions: {
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1224
|
+
primitives: { db: { extensions: {
|
|
1225
|
+
vector: {
|
|
1226
|
+
type: {
|
|
1227
|
+
kind: "array",
|
|
1228
|
+
of: "number"
|
|
1229
|
+
},
|
|
1230
|
+
documentation: "Represents a **vector embedding** (array of numbers) for **similarity search**.\n\n- Equivalent to `number[]` but explicitly marks the field as a vector embedding.\n- Each adapter maps this to its native vector type:\n - **MongoDB** → BSON array\n - **MySQL 9+** → `VECTOR(N)`\n - **PostgreSQL** → pgvector `vector(N)`\n - **SQLite** → JSON\n\n**Example:**\n```atscript\n@db.search.vector 1536, \"cosine\"\nembedding: db.vector\n```\n"
|
|
1126
1231
|
},
|
|
1127
|
-
|
|
1128
|
-
|
|
1232
|
+
currencyCode: {
|
|
1233
|
+
type: "string",
|
|
1234
|
+
documentation: "Represents a **currency code** — typically ISO 4217 (`'USD'`, `'EUR'`, `'JPY'`) but accepts any uppercase alphanumeric code 2–10 chars long, so crypto and custom codes (`'BTC'`, `'USDC'`, `'POINTS'`) fit too.\n\nPair with `@db.amount.currency.ref 'fieldName'` on a `decimal` field to bind the amount to its row-level currency. The validator checks that the ref target resolves to this type (or a plain `string`).\n\n**Example:**\n```atscript\ncurrency: db.currencyCode\n@db.amount.currency.ref 'currency'\namount: decimal\n```\n",
|
|
1235
|
+
annotations: { "expect.pattern": [{
|
|
1236
|
+
pattern: "^[A-Z0-9]{2,10}$",
|
|
1237
|
+
message: "Invalid currency code (expected 2–10 uppercase letters or digits)"
|
|
1238
|
+
}] }
|
|
1239
|
+
}
|
|
1240
|
+
} } }
|
|
1129
1241
|
};
|
|
1130
1242
|
}
|
|
1131
1243
|
});
|
package/dist/rel.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-
|
|
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-BZN2QKud.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 { F as TDbForeignKey, H as TDbRelation, dt as TableMetadata, it as TTableResolver, o as BaseDbAdapter, ot as TWriteTableResolver, pt as TGenericLogger } from "./db-readable-
|
|
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-vjbawUvu.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/shared.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_validation_utils = require("./validation-utils-
|
|
2
|
+
const require_validation_utils = require("./validation-utils-Bs1yOXNx.cjs");
|
|
3
3
|
exports.findFKFieldsPointingTo = require_validation_utils.findFKFieldsPointingTo;
|
|
4
4
|
exports.getAnnotationAlias = require_validation_utils.getAnnotationAlias;
|
|
5
5
|
exports.getDbTableOwner = require_validation_utils.getDbTableOwner;
|
|
@@ -8,6 +8,8 @@ exports.getParentStruct = require_validation_utils.getParentStruct;
|
|
|
8
8
|
exports.getParentTypeName = require_validation_utils.getParentTypeName;
|
|
9
9
|
exports.hasAnyViewAnnotation = require_validation_utils.hasAnyViewAnnotation;
|
|
10
10
|
exports.refActionAnnotation = require_validation_utils.refActionAnnotation;
|
|
11
|
+
exports.validateExclusiveWith = require_validation_utils.validateExclusiveWith;
|
|
11
12
|
exports.validateFieldBaseType = require_validation_utils.validateFieldBaseType;
|
|
12
13
|
exports.validateQueryScope = require_validation_utils.validateQueryScope;
|
|
13
14
|
exports.validateRefArgument = require_validation_utils.validateRefArgument;
|
|
15
|
+
exports.validateSiblingStringField = require_validation_utils.validateSiblingStringField;
|
package/dist/shared.d.cts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { AnnotationSpec, AtscriptDoc, SemanticInterfaceNode, SemanticNode, SemanticPropNode, SemanticStructureNode, TMessages, Token } from "@atscript/core";
|
|
2
2
|
|
|
3
3
|
//#region src/shared/annotation-utils.d.ts
|
|
4
|
+
/** Asserts the field carrying this annotation does not also carry any of `others`. */
|
|
5
|
+
declare function validateExclusiveWith(token: Token, selfName: string, others: Array<{
|
|
6
|
+
key: string;
|
|
7
|
+
displayName?: string;
|
|
8
|
+
}>): TMessages;
|
|
9
|
+
/** Asserts `args[0]` names a sibling property whose primitive base type is `string`. */
|
|
10
|
+
declare function validateSiblingStringField(token: Token, args: Token[], doc: AtscriptDoc, selfName: string): TMessages;
|
|
4
11
|
/**
|
|
5
12
|
* Traverse from annotation token → prop → structure → interface
|
|
6
13
|
* to check if the parent interface has @db.table.
|
|
@@ -68,4 +75,4 @@ declare function hasAnyViewAnnotation(node: SemanticNode): boolean;
|
|
|
68
75
|
*/
|
|
69
76
|
declare function validateQueryScope(queryToken: Token, allowedTypes: string[], unqualifiedTarget: string | null, doc: AtscriptDoc): TMessages;
|
|
70
77
|
//#endregion
|
|
71
|
-
export { TFKFieldMatch, findFKFieldsPointingTo, getAnnotationAlias, getDbTableOwner, getNavTargetTypeName, getParentStruct, getParentTypeName, hasAnyViewAnnotation, refActionAnnotation, validateFieldBaseType, validateQueryScope, validateRefArgument };
|
|
78
|
+
export { TFKFieldMatch, findFKFieldsPointingTo, getAnnotationAlias, getDbTableOwner, getNavTargetTypeName, getParentStruct, getParentTypeName, hasAnyViewAnnotation, refActionAnnotation, validateExclusiveWith, validateFieldBaseType, validateQueryScope, validateRefArgument, validateSiblingStringField };
|
package/dist/shared.d.mts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { AnnotationSpec, AtscriptDoc, SemanticInterfaceNode, SemanticNode, SemanticPropNode, SemanticStructureNode, TMessages, Token } from "@atscript/core";
|
|
2
2
|
|
|
3
3
|
//#region src/shared/annotation-utils.d.ts
|
|
4
|
+
/** Asserts the field carrying this annotation does not also carry any of `others`. */
|
|
5
|
+
declare function validateExclusiveWith(token: Token, selfName: string, others: Array<{
|
|
6
|
+
key: string;
|
|
7
|
+
displayName?: string;
|
|
8
|
+
}>): TMessages;
|
|
9
|
+
/** Asserts `args[0]` names a sibling property whose primitive base type is `string`. */
|
|
10
|
+
declare function validateSiblingStringField(token: Token, args: Token[], doc: AtscriptDoc, selfName: string): TMessages;
|
|
4
11
|
/**
|
|
5
12
|
* Traverse from annotation token → prop → structure → interface
|
|
6
13
|
* to check if the parent interface has @db.table.
|
|
@@ -68,4 +75,4 @@ declare function hasAnyViewAnnotation(node: SemanticNode): boolean;
|
|
|
68
75
|
*/
|
|
69
76
|
declare function validateQueryScope(queryToken: Token, allowedTypes: string[], unqualifiedTarget: string | null, doc: AtscriptDoc): TMessages;
|
|
70
77
|
//#endregion
|
|
71
|
-
export { TFKFieldMatch, findFKFieldsPointingTo, getAnnotationAlias, getDbTableOwner, getNavTargetTypeName, getParentStruct, getParentTypeName, hasAnyViewAnnotation, refActionAnnotation, validateFieldBaseType, validateQueryScope, validateRefArgument };
|
|
78
|
+
export { TFKFieldMatch, findFKFieldsPointingTo, getAnnotationAlias, getDbTableOwner, getNavTargetTypeName, getParentStruct, getParentTypeName, hasAnyViewAnnotation, refActionAnnotation, validateExclusiveWith, validateFieldBaseType, validateQueryScope, validateRefArgument, validateSiblingStringField };
|
package/dist/shared.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as getAnnotationAlias, c as getParentStruct, d as validateFieldBaseType, i as validateRefArgument, l as getParentTypeName, n as hasAnyViewAnnotation, o as getDbTableOwner, r as validateQueryScope, s as getNavTargetTypeName, t as findFKFieldsPointingTo, u as refActionAnnotation } from "./validation-utils-
|
|
2
|
-
export { findFKFieldsPointingTo, getAnnotationAlias, getDbTableOwner, getNavTargetTypeName, getParentStruct, getParentTypeName, hasAnyViewAnnotation, refActionAnnotation, validateFieldBaseType, validateQueryScope, validateRefArgument };
|
|
1
|
+
import { a as getAnnotationAlias, c as getParentStruct, d as validateExclusiveWith, f as validateFieldBaseType, i as validateRefArgument, l as getParentTypeName, n as hasAnyViewAnnotation, o as getDbTableOwner, p as validateSiblingStringField, r as validateQueryScope, s as getNavTargetTypeName, t as findFKFieldsPointingTo, u as refActionAnnotation } from "./validation-utils-eaBuT39W.mjs";
|
|
2
|
+
export { findFKFieldsPointingTo, getAnnotationAlias, getDbTableOwner, getNavTargetTypeName, getParentStruct, getParentTypeName, hasAnyViewAnnotation, refActionAnnotation, validateExclusiveWith, validateFieldBaseType, validateQueryScope, validateRefArgument, validateSiblingStringField };
|
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-
|
|
2
|
+
const require_db_view = require("./db-view-B028LhoI.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 { 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-
|
|
2
|
-
import { r as AtscriptDbView, t as DbSpace } from "./db-space-
|
|
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-BZN2QKud.cjs";
|
|
2
|
+
import { r as AtscriptDbView, t as DbSpace } from "./db-space-Dnjxe6Bt.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 { 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-
|
|
2
|
-
import { r as AtscriptDbView, t as DbSpace } from "./db-space-
|
|
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-vjbawUvu.mjs";
|
|
2
|
+
import { r as AtscriptDbView, t as DbSpace } from "./db-space-CxGLp-no.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,5 +1,49 @@
|
|
|
1
1
|
let _atscript_core = require("@atscript/core");
|
|
2
2
|
//#region src/shared/annotation-utils.ts
|
|
3
|
+
/** Asserts the field carrying this annotation does not also carry any of `others`. */
|
|
4
|
+
function validateExclusiveWith(token, selfName, others) {
|
|
5
|
+
const errors = [];
|
|
6
|
+
const field = token.parentNode;
|
|
7
|
+
for (const { key, displayName } of others) if (field.countAnnotations(key) > 0) errors.push({
|
|
8
|
+
message: `${selfName} cannot coexist with ${displayName ?? `@${key}`} on the same field — pick one form, not both`,
|
|
9
|
+
severity: 1,
|
|
10
|
+
range: token.range
|
|
11
|
+
});
|
|
12
|
+
return errors;
|
|
13
|
+
}
|
|
14
|
+
/** Resolves a field/prop's primitive base type, or `undefined` if it isn't a ref-to-primitive. */
|
|
15
|
+
function getPrimitiveBaseType(node, doc) {
|
|
16
|
+
const def = node.getDefinition();
|
|
17
|
+
if (!def || !(0, _atscript_core.isRef)(def)) return void 0;
|
|
18
|
+
const unwound = doc.unwindType(def.id, def.chain);
|
|
19
|
+
if (!unwound || !(0, _atscript_core.isPrimitive)(unwound.def)) return void 0;
|
|
20
|
+
const ct = unwound.def.config.type;
|
|
21
|
+
return typeof ct === "object" ? ct.kind === "final" ? ct.value : ct.kind : ct;
|
|
22
|
+
}
|
|
23
|
+
/** Asserts `args[0]` names a sibling property whose primitive base type is `string`. */
|
|
24
|
+
function validateSiblingStringField(token, args, doc, selfName) {
|
|
25
|
+
const errors = [];
|
|
26
|
+
const fieldName = args[0]?.text;
|
|
27
|
+
if (!fieldName) return errors;
|
|
28
|
+
const struct = getParentStruct(token);
|
|
29
|
+
if (!struct) return errors;
|
|
30
|
+
const sibling = struct.props.get(fieldName);
|
|
31
|
+
if (!sibling) {
|
|
32
|
+
errors.push({
|
|
33
|
+
message: `${selfName} '${fieldName}': no sibling field named '${fieldName}' on this type`,
|
|
34
|
+
severity: 1,
|
|
35
|
+
range: token.range
|
|
36
|
+
});
|
|
37
|
+
return errors;
|
|
38
|
+
}
|
|
39
|
+
const baseType = getPrimitiveBaseType(sibling, doc);
|
|
40
|
+
if (baseType !== void 0 && baseType !== "string") errors.push({
|
|
41
|
+
message: `${selfName} '${fieldName}': sibling field must be a string, got '${baseType}'`,
|
|
42
|
+
severity: 1,
|
|
43
|
+
range: token.range
|
|
44
|
+
});
|
|
45
|
+
return errors;
|
|
46
|
+
}
|
|
3
47
|
/**
|
|
4
48
|
* Traverse from annotation token → prop → structure → interface
|
|
5
49
|
* to check if the parent interface has @db.table.
|
|
@@ -31,12 +75,9 @@ function getParentTypeName(token) {
|
|
|
31
75
|
*/
|
|
32
76
|
function validateFieldBaseType(token, doc, annotationName, expectedType) {
|
|
33
77
|
const errors = [];
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!unwound || !(0, _atscript_core.isPrimitive)(unwound.def)) return errors;
|
|
38
|
-
const ct = unwound.def.config.type;
|
|
39
|
-
const baseType = typeof ct === "object" ? ct.kind === "final" ? ct.value : ct.kind : ct;
|
|
78
|
+
const field = token.parentNode;
|
|
79
|
+
const baseType = getPrimitiveBaseType(field, doc);
|
|
80
|
+
if (baseType === void 0) return errors;
|
|
40
81
|
const allowed = Array.isArray(expectedType) ? expectedType : [expectedType];
|
|
41
82
|
if (!allowed.includes(baseType)) errors.push({
|
|
42
83
|
message: `${annotationName} is not compatible with type "${baseType}" — requires ${allowed.join(" or ")}`,
|
|
@@ -316,6 +357,12 @@ Object.defineProperty(exports, "refActionAnnotation", {
|
|
|
316
357
|
return refActionAnnotation;
|
|
317
358
|
}
|
|
318
359
|
});
|
|
360
|
+
Object.defineProperty(exports, "validateExclusiveWith", {
|
|
361
|
+
enumerable: true,
|
|
362
|
+
get: function() {
|
|
363
|
+
return validateExclusiveWith;
|
|
364
|
+
}
|
|
365
|
+
});
|
|
319
366
|
Object.defineProperty(exports, "validateFieldBaseType", {
|
|
320
367
|
enumerable: true,
|
|
321
368
|
get: function() {
|
|
@@ -334,3 +381,9 @@ Object.defineProperty(exports, "validateRefArgument", {
|
|
|
334
381
|
return validateRefArgument;
|
|
335
382
|
}
|
|
336
383
|
});
|
|
384
|
+
Object.defineProperty(exports, "validateSiblingStringField", {
|
|
385
|
+
enumerable: true,
|
|
386
|
+
get: function() {
|
|
387
|
+
return validateSiblingStringField;
|
|
388
|
+
}
|
|
389
|
+
});
|
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
import { AnnotationSpec, isArray, isInterface, isPrimitive, isQueryComparison, isQueryLogical, isRef, isStructure } from "@atscript/core";
|
|
2
2
|
//#region src/shared/annotation-utils.ts
|
|
3
|
+
/** Asserts the field carrying this annotation does not also carry any of `others`. */
|
|
4
|
+
function validateExclusiveWith(token, selfName, others) {
|
|
5
|
+
const errors = [];
|
|
6
|
+
const field = token.parentNode;
|
|
7
|
+
for (const { key, displayName } of others) if (field.countAnnotations(key) > 0) errors.push({
|
|
8
|
+
message: `${selfName} cannot coexist with ${displayName ?? `@${key}`} on the same field — pick one form, not both`,
|
|
9
|
+
severity: 1,
|
|
10
|
+
range: token.range
|
|
11
|
+
});
|
|
12
|
+
return errors;
|
|
13
|
+
}
|
|
14
|
+
/** Resolves a field/prop's primitive base type, or `undefined` if it isn't a ref-to-primitive. */
|
|
15
|
+
function getPrimitiveBaseType(node, doc) {
|
|
16
|
+
const def = node.getDefinition();
|
|
17
|
+
if (!def || !isRef(def)) return void 0;
|
|
18
|
+
const unwound = doc.unwindType(def.id, def.chain);
|
|
19
|
+
if (!unwound || !isPrimitive(unwound.def)) return void 0;
|
|
20
|
+
const ct = unwound.def.config.type;
|
|
21
|
+
return typeof ct === "object" ? ct.kind === "final" ? ct.value : ct.kind : ct;
|
|
22
|
+
}
|
|
23
|
+
/** Asserts `args[0]` names a sibling property whose primitive base type is `string`. */
|
|
24
|
+
function validateSiblingStringField(token, args, doc, selfName) {
|
|
25
|
+
const errors = [];
|
|
26
|
+
const fieldName = args[0]?.text;
|
|
27
|
+
if (!fieldName) return errors;
|
|
28
|
+
const struct = getParentStruct(token);
|
|
29
|
+
if (!struct) return errors;
|
|
30
|
+
const sibling = struct.props.get(fieldName);
|
|
31
|
+
if (!sibling) {
|
|
32
|
+
errors.push({
|
|
33
|
+
message: `${selfName} '${fieldName}': no sibling field named '${fieldName}' on this type`,
|
|
34
|
+
severity: 1,
|
|
35
|
+
range: token.range
|
|
36
|
+
});
|
|
37
|
+
return errors;
|
|
38
|
+
}
|
|
39
|
+
const baseType = getPrimitiveBaseType(sibling, doc);
|
|
40
|
+
if (baseType !== void 0 && baseType !== "string") errors.push({
|
|
41
|
+
message: `${selfName} '${fieldName}': sibling field must be a string, got '${baseType}'`,
|
|
42
|
+
severity: 1,
|
|
43
|
+
range: token.range
|
|
44
|
+
});
|
|
45
|
+
return errors;
|
|
46
|
+
}
|
|
3
47
|
/**
|
|
4
48
|
* Traverse from annotation token → prop → structure → interface
|
|
5
49
|
* to check if the parent interface has @db.table.
|
|
@@ -31,12 +75,9 @@ function getParentTypeName(token) {
|
|
|
31
75
|
*/
|
|
32
76
|
function validateFieldBaseType(token, doc, annotationName, expectedType) {
|
|
33
77
|
const errors = [];
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!unwound || !isPrimitive(unwound.def)) return errors;
|
|
38
|
-
const ct = unwound.def.config.type;
|
|
39
|
-
const baseType = typeof ct === "object" ? ct.kind === "final" ? ct.value : ct.kind : ct;
|
|
78
|
+
const field = token.parentNode;
|
|
79
|
+
const baseType = getPrimitiveBaseType(field, doc);
|
|
80
|
+
if (baseType === void 0) return errors;
|
|
40
81
|
const allowed = Array.isArray(expectedType) ? expectedType : [expectedType];
|
|
41
82
|
if (!allowed.includes(baseType)) errors.push({
|
|
42
83
|
message: `${annotationName} is not compatible with type "${baseType}" — requires ${allowed.join(" or ")}`,
|
|
@@ -268,4 +309,4 @@ function validateQueryScope(queryToken, allowedTypes, unqualifiedTarget, doc) {
|
|
|
268
309
|
return errors;
|
|
269
310
|
}
|
|
270
311
|
//#endregion
|
|
271
|
-
export { getAnnotationAlias as a, getParentStruct as c,
|
|
312
|
+
export { getAnnotationAlias as a, getParentStruct as c, validateExclusiveWith as d, validateFieldBaseType as f, validateRefArgument as i, getParentTypeName as l, hasAnyViewAnnotation as n, getDbTableOwner as o, validateSiblingStringField as p, validateQueryScope as r, getNavTargetTypeName as s, findFKFieldsPointingTo as t, refActionAnnotation as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.65",
|
|
4
4
|
"description": "Database adapter utilities for atscript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -69,13 +69,13 @@
|
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@atscript/core": "^0.1.50",
|
|
71
71
|
"@atscript/typescript": "^0.1.50",
|
|
72
|
-
"@uniqu/core": "^0.1.
|
|
72
|
+
"@uniqu/core": "^0.1.6",
|
|
73
73
|
"unplugin-atscript": "^0.1.50"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@atscript/core": "^0.1.50",
|
|
77
77
|
"@atscript/typescript": "^0.1.50",
|
|
78
|
-
"@uniqu/core": "^0.1.
|
|
78
|
+
"@uniqu/core": "^0.1.6"
|
|
79
79
|
},
|
|
80
80
|
"scripts": {
|
|
81
81
|
"postinstall": "asc -f dts",
|