uql-orm 0.66.0 → 0.67.1
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/browser/querier/httpQuerier.js +1 -8
- package/dist/browser/uql-browser.min.js.map +5 -5
- package/dist/bunSql/bunSql.util.d.ts +2 -6
- package/dist/bunSql/bunSql.util.js +2 -6
- package/dist/bunSql/bunSqlQuerier.d.ts +2 -5
- package/dist/bunSql/bunSqlQuerier.js +2 -5
- package/dist/cockroachdb/cockroachDialect.d.ts +4 -13
- package/dist/cockroachdb/cockroachDialect.js +4 -13
- package/dist/context/context.browser.js +2 -10
- package/dist/context/context.d.ts +4 -17
- package/dist/context/context.js +4 -17
- package/dist/dialect/abstractDialect.d.ts +4 -19
- package/dist/dialect/abstractDialect.js +2 -20
- package/dist/dialect/abstractSqlDialect.d.ts +47 -212
- package/dist/dialect/abstractSqlDialect.js +68 -222
- package/dist/dialect/aliases.d.ts +2 -12
- package/dist/dialect/aliases.js +4 -12
- package/dist/dialect/hydrateColumn.d.ts +2 -6
- package/dist/dialect/hydrateColumn.js +3 -13
- package/dist/dialect/jsonArrayElemMatchUtils.d.ts +1 -7
- package/dist/dialect/jsonArrayElemMatchUtils.js +1 -7
- package/dist/dialect/jsonSql.d.ts +6 -27
- package/dist/dialect/jsonSql.js +6 -27
- package/dist/dialect/mergeSqlDialect.d.ts +4 -22
- package/dist/dialect/mergeSqlDialect.js +4 -22
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +11 -37
- package/dist/dialect/mysqlLikeSqlDialect.js +35 -51
- package/dist/dialect/pgLikeSqlDialect.d.ts +8 -22
- package/dist/dialect/pgLikeSqlDialect.js +36 -39
- package/dist/dialect/queryContext.d.ts +4 -22
- package/dist/dialect/queryContext.js +4 -22
- package/dist/dialect/queryJoins.d.ts +3 -12
- package/dist/dialect/queryJoins.js +3 -12
- package/dist/dialect/vectorCast.d.ts +2 -12
- package/dist/dialect/vectorCast.js +3 -19
- package/dist/dialect/vectorSqlDialect.d.ts +8 -38
- package/dist/dialect/vectorSqlDialect.js +7 -38
- package/dist/entity/decorator/bag.d.ts +6 -19
- package/dist/entity/decorator/bag.js +6 -22
- package/dist/entity/decorator/entity.d.ts +2 -7
- package/dist/entity/decorator/entity.js +2 -7
- package/dist/entity/decorator/members.d.ts +7 -30
- package/dist/entity/decorator/members.js +3 -12
- package/dist/entity/metadata/definition.d.ts +2 -18
- package/dist/entity/metadata/definition.js +6 -28
- package/dist/http/handler.d.ts +2 -14
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/dist/libsql/libsqlDialect.d.ts +1 -8
- package/dist/libsql/libsqlDialect.js +1 -8
- package/dist/maria/mariaDialect.d.ts +3 -5
- package/dist/maria/mariaDialect.js +5 -5
- package/dist/maria/mariadbQuerier.js +2 -2
- package/dist/maria/mariadbQuerierPool.js +1 -6
- package/dist/migrate/builder/migrationBuilder.js +3 -19
- package/dist/migrate/builder/splitSqlStatements.d.ts +1 -14
- package/dist/migrate/builder/splitSqlStatements.js +2 -22
- package/dist/migrate/builder/types.d.ts +2 -15
- package/dist/migrate/cli-config.js +2 -11
- package/dist/migrate/cli.js +2 -7
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -15
- package/dist/migrate/codegen/entityCodeGenerator.js +15 -44
- package/dist/migrate/codegen/fieldOptionsSource.d.ts +1 -8
- package/dist/migrate/codegen/fieldOptionsSource.js +3 -22
- package/dist/migrate/ddl/indexDdl.d.ts +2 -5
- package/dist/migrate/ddl/indexDdl.js +2 -5
- package/dist/migrate/ddl/pgIndexDdl.d.ts +3 -13
- package/dist/migrate/ddl/pgIndexDdl.js +3 -13
- package/dist/migrate/generator/definitionToNode.d.ts +2 -9
- package/dist/migrate/generator/definitionToNode.js +3 -17
- package/dist/migrate/generator/indexNodeToSchema.d.ts +2 -3
- package/dist/migrate/generator/indexNodeToSchema.js +2 -3
- package/dist/migrate/generator/mongoCommand.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.js +1 -8
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +6 -26
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +9 -41
- package/dist/migrate/introspection/baseSqlIntrospector.js +0 -1
- package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
- package/dist/migrate/introspection/mongoIntrospector.js +48 -46
- package/dist/migrate/introspection/mssqlIntrospector.d.ts +4 -4
- package/dist/migrate/introspection/mssqlIntrospector.js +18 -27
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +7 -2
- package/dist/migrate/introspection/mysqlIntrospector.js +16 -14
- package/dist/migrate/introspection/postgresIntrospector.d.ts +24 -9
- package/dist/migrate/introspection/postgresIntrospector.js +68 -59
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -1
- package/dist/migrate/introspection/sqliteIntrospector.js +8 -10
- package/dist/migrate/migrator.d.ts +9 -53
- package/dist/migrate/migrator.js +32 -65
- package/dist/migrate/schemaGenerator.d.ts +16 -66
- package/dist/migrate/schemaGenerator.js +21 -74
- package/dist/mongo/mongoDialect.d.ts +21 -53
- package/dist/mongo/mongoDialect.js +25 -70
- package/dist/mongo/mongodbQuerier.d.ts +5 -8
- package/dist/mongo/mongodbQuerier.js +31 -65
- package/dist/mssql/mssqlDialect.d.ts +8 -34
- package/dist/mssql/mssqlDialect.js +37 -51
- package/dist/mssql/mssqlQuerier.d.ts +37 -4
- package/dist/mssql/mssqlQuerier.js +2 -2
- package/dist/mssql/mssqlWireTypes.d.ts +2 -14
- package/dist/mssql/mssqlWireTypes.js +2 -14
- package/dist/nestjs/uqlModule.js +2 -7
- package/dist/pglite/pgliteQuerier.d.ts +1 -9
- package/dist/pglite/pgliteQuerierPool.d.ts +4 -26
- package/dist/pglite/pgliteQuerierPool.js +3 -18
- package/dist/postgres/abstractPgQuerierPool.d.ts +1 -8
- package/dist/postgres/abstractPgQuerierPool.js +1 -8
- package/dist/postgres/pgNumericTypes.d.ts +3 -26
- package/dist/postgres/pgNumericTypes.js +3 -26
- package/dist/postgres/postgresDialect.d.ts +4 -10
- package/dist/postgres/postgresDialect.js +4 -10
- package/dist/querier/abstractQuerier.d.ts +35 -103
- package/dist/querier/abstractQuerier.js +105 -201
- package/dist/querier/abstractSharedHandleQuerierPool.d.ts +3 -17
- package/dist/querier/abstractSharedHandleQuerierPool.js +3 -17
- package/dist/querier/abstractSqlQuerier.d.ts +15 -36
- package/dist/querier/abstractSqlQuerier.js +49 -131
- package/dist/schema/canonicalType.d.ts +3 -21
- package/dist/schema/canonicalType.js +22 -67
- package/dist/schema/dependencyGraph.d.ts +2 -8
- package/dist/schema/dependencyGraph.js +2 -32
- package/dist/schema/index.d.ts +1 -25
- package/dist/schema/index.js +0 -26
- package/dist/schema/indexColumns.d.ts +1 -8
- package/dist/schema/indexColumns.js +1 -8
- package/dist/schema/indexDifferences.d.ts +7 -40
- package/dist/schema/indexDifferences.js +6 -31
- package/dist/schema/schemaAST.d.ts +8 -175
- package/dist/schema/schemaAST.js +13 -365
- package/dist/schema/schemaASTBuilder.d.ts +2 -24
- package/dist/schema/schemaASTBuilder.js +2 -30
- package/dist/schema/schemaASTDiffer.d.ts +6 -46
- package/dist/schema/schemaASTDiffer.js +8 -56
- package/dist/schema/types.d.ts +5 -61
- package/dist/schema/types.js +3 -6
- package/dist/sqlite/abstractSqliteQuerier.d.ts +1 -8
- package/dist/sqlite/localSqliteQuerierPool.d.ts +1 -7
- package/dist/sqlite/localSqliteQuerierPool.js +1 -7
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -7
- package/dist/sqlite/nodeSqliteQuerierPool.js +2 -7
- package/dist/sqlite/sqliteDialect.d.ts +5 -20
- package/dist/sqlite/sqliteDialect.js +29 -35
- package/dist/turso/tursoDialect.d.ts +4 -6
- package/dist/turso/tursoDialect.js +4 -6
- package/dist/turso/tursoLocalQuerierPool.d.ts +1 -7
- package/dist/turso/tursoLocalQuerierPool.js +1 -7
- package/dist/turso/tursoQuerierPool.d.ts +2 -6
- package/dist/turso/tursoQuerierPool.js +2 -6
- package/dist/turso/tursoSessionQuerier.d.ts +1 -7
- package/dist/turso/tursoSessionQuerier.js +1 -7
- package/dist/type/dialect.d.ts +42 -94
- package/dist/type/dialect.js +3 -13
- package/dist/type/entity.d.ts +163 -534
- package/dist/type/entity.js +26 -9
- package/dist/type/logger.d.ts +2 -14
- package/dist/type/migration.d.ts +9 -38
- package/dist/type/querier.d.ts +9 -28
- package/dist/type/querierPool.d.ts +4 -26
- package/dist/type/query.d.ts +19 -73
- package/dist/type/query.js +2 -7
- package/dist/type/queryAggregate.d.ts +18 -98
- package/dist/type/queryRaw.d.ts +1 -8
- package/dist/type/queryRaw.js +1 -8
- package/dist/type/queryWhere.d.ts +13 -61
- package/dist/type/universalQuerier.d.ts +18 -105
- package/dist/type/utility.d.ts +12 -24
- package/dist/type/vector.d.ts +8 -38
- package/dist/type/vector.js +1 -1
- package/dist/type/wire.d.ts +2 -5
- package/dist/util/dialect.util.d.ts +9 -27
- package/dist/util/dialect.util.js +10 -27
- package/dist/util/field.util.d.ts +2 -31
- package/dist/util/field.util.js +3 -43
- package/dist/util/fieldOption.util.d.ts +7 -15
- package/dist/util/fieldOption.util.js +1 -1
- package/dist/util/filters.util.d.ts +2 -5
- package/dist/util/filters.util.js +2 -5
- package/dist/util/logger.d.ts +2 -6
- package/dist/util/logger.js +2 -6
- package/dist/util/object.util.d.ts +2 -6
- package/dist/util/object.util.js +1 -5
- package/dist/util/raw.d.ts +3 -23
- package/dist/util/relationQuery.util.d.ts +3 -14
- package/dist/util/relationQuery.util.js +3 -14
- package/dist/util/rowKey.util.d.ts +2 -10
- package/dist/util/rowKey.util.js +2 -10
- package/dist/util/sql.util.d.ts +6 -37
- package/dist/util/sql.util.js +13 -73
- package/dist/util/sqlLiteral.d.ts +2 -13
- package/dist/util/sqlLiteral.js +8 -13
- package/dist/util/string.util.js +0 -2
- package/package.json +4 -4
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SqlQueryContext is an implementation of the QueryContext interface specifically for SQL-based dialects.
|
|
3
|
-
* It follows the "Accumulator" or "Builder" pattern to construct SQL queries and their corresponding parameters.
|
|
4
|
-
*
|
|
5
|
-
* This pattern solves the problem of building complex SQL strings while safely managing parameterized values,
|
|
6
|
-
* preventing SQL injection and handling dialect-specific parameter placeholders (e.g., '?' for MySQL, '$n' for PostgreSQL).
|
|
7
|
-
*/
|
|
1
|
+
/** A SQL statement being built: its text, and the values it binds, placeholders numbered by the dialect. */
|
|
8
2
|
export class SqlQueryContext {
|
|
9
3
|
dialect;
|
|
10
4
|
statement;
|
|
@@ -13,14 +7,8 @@ export class SqlQueryContext {
|
|
|
13
7
|
params;
|
|
14
8
|
tableAliases = new Set();
|
|
15
9
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* fragment context built via {@link AbstractSqlDialect.buildFragment}, so a bound value's
|
|
19
|
-
* placeholder is numbered correctly against the real query from the moment it's added, rather
|
|
20
|
-
* than needing to be reconciled after the fact.
|
|
21
|
-
* @param statement The context this one renders a fragment of, which owns the claimed aliases: a
|
|
22
|
-
* fragment is part of one statement, so its aliases have to be unique across the whole of it.
|
|
23
|
-
* @param inlineValues See {@link QueryContext.inlineValues}; a fragment takes its statement's.
|
|
10
|
+
* `params` and `statement` are a fragment's parent's, so a value numbers against the whole statement and
|
|
11
|
+
* an alias is unique across it; a fragment inlines values where its statement does.
|
|
24
12
|
*/
|
|
25
13
|
constructor(dialect, params = [], statement, inlineValues = false) {
|
|
26
14
|
this.dialect = dialect;
|
|
@@ -51,13 +39,7 @@ export class SqlQueryContext {
|
|
|
51
39
|
this.sqlChunks.push(this.dialect.addValue(this, value));
|
|
52
40
|
return this;
|
|
53
41
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Pushes values to the parameters list without appending placeholders to the SQL.
|
|
56
|
-
* This is useful when the placeholder is already present in the SQL string or handled elsewhere.
|
|
57
|
-
*
|
|
58
|
-
* @param values The values to be added to the parameters.
|
|
59
|
-
* @returns The current context instance for method chaining.
|
|
60
|
-
*/
|
|
42
|
+
/** Binds values whose placeholders the SQL already carries. */
|
|
61
43
|
pushValue(...values) {
|
|
62
44
|
this.params.push(...values.map((v) => this.dialect.normalizeValue(v)));
|
|
63
45
|
return this;
|
|
@@ -35,11 +35,8 @@ export type QuerySortOptions = {
|
|
|
35
35
|
readonly distinct?: boolean;
|
|
36
36
|
};
|
|
37
37
|
/**
|
|
38
|
-
* What the statement joins, from
|
|
39
|
-
*
|
|
40
|
-
* here, so the columns, the `ORDER BY` and the row lock cannot disagree about what is in the
|
|
41
|
-
* statement. `$sort` contributes to-one relations only; the rest is rejected where it is rendered.
|
|
42
|
-
* `claimAlias` names each join's table, parents first.
|
|
38
|
+
* What the statement joins, from `$populate` and from a `$sort` by a to-one relation's field, so the
|
|
39
|
+
* columns, the `ORDER BY` and the lock agree. `claimAlias` names each join's table, parents first.
|
|
43
40
|
*/
|
|
44
41
|
export declare function resolveQueryJoins<E>(meta: EntityMeta<E>, q: Query<E>, claimAlias?: (path: string) => string): QueryJoins;
|
|
45
42
|
/**
|
|
@@ -50,13 +47,7 @@ export declare function resolveQueryJoins<E>(meta: EntityMeta<E>, q: Query<E>, c
|
|
|
50
47
|
export declare function hasRequiredJoin<E>(meta: EntityMeta<E>, q: Query<E>): boolean;
|
|
51
48
|
/** Whether a statement aggregates a relation's rows: a to-many off its own row, or off a row it joins. */
|
|
52
49
|
export declare function aggregatesRelations<E>(meta: EntityMeta<E>, q: Query<E>): boolean;
|
|
53
|
-
/**
|
|
54
|
-
* The join an ordering may address at `path`, with the relation's own sort map, or why it may not.
|
|
55
|
-
* Every backend answers this the same way - a to-many has no single value to order by, a relation
|
|
56
|
-
* sort is a map of that relation's fields, and the path has to be joined - so it is answered once
|
|
57
|
-
* here rather than per dialect, where the three checks had already drifted apart twice. Only the
|
|
58
|
-
* remedy for an unjoined path is the dialect's business, which is what `unjoinable` says.
|
|
59
|
-
*/
|
|
50
|
+
/** The join a sort may address at `path` with the relation's own sort map, or why it may not; `unjoinable` is the dialect's remedy. */
|
|
60
51
|
export declare function resolveSortableJoin(relation: RelationMeta, path: string, value: unknown, joins: QueryJoins, unjoinable: string): {
|
|
61
52
|
readonly join: QueryJoin;
|
|
62
53
|
readonly sort: QuerySortMap<object>;
|
|
@@ -2,11 +2,8 @@ import { getMeta, relationOf } from '../entity/index.js';
|
|
|
2
2
|
import { getKeys, getRelationRequestSummary, isToManyRelation, parseRelationAtKey } from '../util/index.js';
|
|
3
3
|
export const NO_JOINS = new Map();
|
|
4
4
|
/**
|
|
5
|
-
* What the statement joins, from
|
|
6
|
-
*
|
|
7
|
-
* here, so the columns, the `ORDER BY` and the row lock cannot disagree about what is in the
|
|
8
|
-
* statement. `$sort` contributes to-one relations only; the rest is rejected where it is rendered.
|
|
9
|
-
* `claimAlias` names each join's table, parents first.
|
|
5
|
+
* What the statement joins, from `$populate` and from a `$sort` by a to-one relation's field, so the
|
|
6
|
+
* columns, the `ORDER BY` and the lock agree. `claimAlias` names each join's table, parents first.
|
|
10
7
|
*/
|
|
11
8
|
export function resolveQueryJoins(meta, q, claimAlias = (path) => path) {
|
|
12
9
|
if (!q.$populate && !q.$sort) {
|
|
@@ -91,13 +88,7 @@ function addSortJoins(joins, claimAlias, meta, sort, parent) {
|
|
|
91
88
|
addSortJoins(joins, claimAlias, join.meta, value, join);
|
|
92
89
|
}
|
|
93
90
|
}
|
|
94
|
-
/**
|
|
95
|
-
* The join an ordering may address at `path`, with the relation's own sort map, or why it may not.
|
|
96
|
-
* Every backend answers this the same way - a to-many has no single value to order by, a relation
|
|
97
|
-
* sort is a map of that relation's fields, and the path has to be joined - so it is answered once
|
|
98
|
-
* here rather than per dialect, where the three checks had already drifted apart twice. Only the
|
|
99
|
-
* remedy for an unjoined path is the dialect's business, which is what `unjoinable` says.
|
|
100
|
-
*/
|
|
91
|
+
/** The join a sort may address at `path` with the relation's own sort map, or why it may not; `unjoinable` is the dialect's remedy. */
|
|
101
92
|
export function resolveSortableJoin(relation, path, value, joins, unjoinable) {
|
|
102
93
|
if (isToManyRelation(relation)) {
|
|
103
94
|
throw new TypeError(`cannot $sort by '${path}': a parent has many of them, so there is no single value to order by. Sort the relation's own rows inside $populate instead.`);
|
|
@@ -16,17 +16,7 @@ export declare function resolveVectorCast(field: {
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function toSparsevecLiteral(values: readonly unknown[]): string;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* to the compiler, and invisible to any mocked test, because a mock returns the array the entity
|
|
22
|
-
* promises. It surfaces only as arithmetic quietly producing nonsense on real rows.
|
|
23
|
-
*
|
|
24
|
-
* Driven by `cast`, never by the shape of the text, so this is the exact mirror of the write side:
|
|
25
|
-
* a `sparsevec` column is read as `{1:1,3:2}/3` because that is what it was written as, and a dense
|
|
26
|
-
* one as `[1,2,3]`. Both return the dense array the field type promises, whichever width the column
|
|
27
|
-
* has. Sniffing the string instead would guess at a type the caller already knows.
|
|
28
|
-
*
|
|
29
|
-
* Returns `undefined` when the text does not match the column's own format, so a caller can keep the
|
|
30
|
-
* raw value rather than replace it with something invented.
|
|
19
|
+
* A vector column's text as the dense array its field promises (pgvector returns text), read by `cast`
|
|
20
|
+
* as it was written, `{1:1,3:2}/3` or `[1,2,3]`; `undefined` where the text matches neither.
|
|
31
21
|
*/
|
|
32
22
|
export declare function parseVectorLiteral(raw: string, cast: VectorCast): number[] | undefined;
|
|
@@ -24,18 +24,8 @@ export function toSparsevecLiteral(values) {
|
|
|
24
24
|
return `{${pairs}}/${values.length}`;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* to the compiler, and invisible to any mocked test, because a mock returns the array the entity
|
|
30
|
-
* promises. It surfaces only as arithmetic quietly producing nonsense on real rows.
|
|
31
|
-
*
|
|
32
|
-
* Driven by `cast`, never by the shape of the text, so this is the exact mirror of the write side:
|
|
33
|
-
* a `sparsevec` column is read as `{1:1,3:2}/3` because that is what it was written as, and a dense
|
|
34
|
-
* one as `[1,2,3]`. Both return the dense array the field type promises, whichever width the column
|
|
35
|
-
* has. Sniffing the string instead would guess at a type the caller already knows.
|
|
36
|
-
*
|
|
37
|
-
* Returns `undefined` when the text does not match the column's own format, so a caller can keep the
|
|
38
|
-
* raw value rather than replace it with something invented.
|
|
27
|
+
* A vector column's text as the dense array its field promises (pgvector returns text), read by `cast`
|
|
28
|
+
* as it was written, `{1:1,3:2}/3` or `[1,2,3]`; `undefined` where the text matches neither.
|
|
39
29
|
*/
|
|
40
30
|
export function parseVectorLiteral(raw, cast) {
|
|
41
31
|
const text = raw.trim();
|
|
@@ -63,13 +53,7 @@ function parseSparse(text) {
|
|
|
63
53
|
}
|
|
64
54
|
return dense;
|
|
65
55
|
}
|
|
66
|
-
/**
|
|
67
|
-
* `[1,0,2]`, whatever width the column has.
|
|
68
|
-
*
|
|
69
|
-
* A dense literal is valid JSON by construction, so parsing it as JSON is both stricter and cheaper
|
|
70
|
-
* than splitting: `[1,,2]` throws here, where `split(',').map(Number)` would have turned the hole
|
|
71
|
-
* into a 0.
|
|
72
|
-
*/
|
|
56
|
+
/** `[1,0,2]`, parsed as the JSON it is, which refuses a hole `split` would read as 0. */
|
|
73
57
|
function parseDense(text) {
|
|
74
58
|
if (!text.startsWith('[') || !text.endsWith(']'))
|
|
75
59
|
return undefined;
|
|
@@ -1,48 +1,23 @@
|
|
|
1
|
-
import type { EntityIndexMeta, EntityMeta, FieldOptions, Query, QueryContext, QueryVectorSearch, VectorDistance, VectorMetric } from '../type/index.js';
|
|
1
|
+
import type { EntityIndexMeta, EntityMeta, FieldOptions, Query, QueryContext, QueryVectorSearch, SqlDialectFeatures, VectorDistance, VectorMetric } from '../type/index.js';
|
|
2
2
|
import { AbstractDialect } from './abstractDialect.js';
|
|
3
3
|
import type { VectorCast } from './vectorCast.js';
|
|
4
4
|
/**
|
|
5
|
-
* Vector
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* A layer of its own because it is nearly self-contained - it needs only `escapeId` from the SQL
|
|
9
|
-
* dialect above it - unlike the JSON operators, which are woven into the generic comparison
|
|
10
|
-
* machinery (`neExpr`, `numericCast`, `formatIn`, ...) and belong with it.
|
|
11
|
-
*
|
|
12
|
-
* A dialect declares which metrics it has, and how it spells each, in {@link vectorMetrics}. Both
|
|
13
|
-
* shapes live in that one map - an operator (`"col" <=> $1`, Postgres/CockroachDB) or a function call
|
|
14
|
-
* (`VEC_DISTANCE_COSINE(col, ?)`, MariaDB/SQLite) - so {@link appendVectorSort} is written once and an
|
|
15
|
-
* engine with no vector search at all is simply the empty map.
|
|
5
|
+
* Vector search for the SQL dialects: the distance a `$sort` ranks by and projects, and the ANN tuning.
|
|
6
|
+
* Each dialect lists its metrics in {@link vectorMetrics}, an operator or a function; empty means no search.
|
|
16
7
|
*/
|
|
17
8
|
export declare abstract class VectorSqlDialect extends AbstractDialect {
|
|
18
9
|
readonly vectorExtension: string | undefined;
|
|
10
|
+
abstract readonly features: SqlDialectFeatures;
|
|
19
11
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* refuses instead of running a tuning that would silently not apply.
|
|
23
|
-
*/
|
|
24
|
-
readonly vectorTuningNeedsTransaction: boolean;
|
|
25
|
-
/**
|
|
26
|
-
* `SET`s that widen an ANN index's search for one query, run before it on the same connection.
|
|
27
|
-
*
|
|
28
|
-
* Keyed off `$sort` rather than a `$where` `$near`, because the ANN index is what ranks: pgvector
|
|
29
|
-
* reaches for HNSW on an `ORDER BY distance LIMIT`, while a bare distance predicate scans whatever
|
|
30
|
-
* the planner picks. Tuning a query that never touches the index would set a knob for nothing.
|
|
31
|
-
*
|
|
32
|
-
* Empty by default: SQLite, libSQL and Turso compute every distance, so there is no candidate list
|
|
33
|
-
* to widen, and a field with no ANN index has nothing to tune either.
|
|
12
|
+
* `SET`s widening an ANN index's search for one query, run before it on its connection. Keyed off `$sort`,
|
|
13
|
+
* since the index is what ranks. Empty where every distance is computed anyway.
|
|
34
14
|
*/
|
|
35
15
|
vectorTuningStatements<E>(_meta: EntityMeta<E>, _q: Query<E>): readonly string[];
|
|
36
16
|
/** The `$sort` key carrying a vector search, if the query ranks by one. */
|
|
37
17
|
protected vectorSortKey<E>(q: Query<E>): string | undefined;
|
|
38
18
|
/**
|
|
39
|
-
* The ANN index `$candidates`
|
|
40
|
-
*
|
|
41
|
-
* dialects that act on it cannot disagree about when tuning applies.
|
|
42
|
-
*
|
|
43
|
-
* Validates here rather than at each emitter because the number is spelled into the statement
|
|
44
|
-
* rather than bound: `SET LOCAL hnsw.ef_search = $1` is not a thing either engine accepts. `/http`
|
|
45
|
-
* casts client JSON straight to `Query`, so `'abc'` and `null` both reach this.
|
|
19
|
+
* The ANN index `$candidates` tunes for the query, or nothing to tune. Checked here, since the number is
|
|
20
|
+
* spelled into a `SET` rather than bound, and `/http` input is untyped.
|
|
46
21
|
*/
|
|
47
22
|
protected tunedVectorIndex<E>(meta: EntityMeta<E>, q: Query<E>): EntityIndexMeta | undefined;
|
|
48
23
|
/**
|
|
@@ -67,11 +42,6 @@ export declare abstract class VectorSqlDialect extends AbstractDialect {
|
|
|
67
42
|
* dialect needing a conversion around it (`$1::vector`, `VEC_FromText(?)`) declares it once.
|
|
68
43
|
*/
|
|
69
44
|
protected appendVectorValue(ctx: QueryContext, value: readonly unknown[], _field?: FieldOptions): void;
|
|
70
|
-
/**
|
|
71
|
-
* Whether this engine has pgvector's narrower vector types (`halfvec`, `sparsevec`) or only the one.
|
|
72
|
-
* Declared by the dialect that has them rather than looked up in a table keyed by dialect name.
|
|
73
|
-
*/
|
|
74
|
-
protected readonly hasNarrowVectorTypes: boolean;
|
|
75
45
|
/**
|
|
76
46
|
* The vector type this dialect actually has for a declared one, so the cast follows the column
|
|
77
47
|
* rather than naming a type the engine does not define.
|
|
@@ -3,35 +3,14 @@ import { findVectorIndex, findVectorSort } from '../util/dialect.util.js';
|
|
|
3
3
|
import { entityName } from '../util/object.util.js';
|
|
4
4
|
import { AbstractDialect } from './abstractDialect.js';
|
|
5
5
|
/**
|
|
6
|
-
* Vector
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* A layer of its own because it is nearly self-contained - it needs only `escapeId` from the SQL
|
|
10
|
-
* dialect above it - unlike the JSON operators, which are woven into the generic comparison
|
|
11
|
-
* machinery (`neExpr`, `numericCast`, `formatIn`, ...) and belong with it.
|
|
12
|
-
*
|
|
13
|
-
* A dialect declares which metrics it has, and how it spells each, in {@link vectorMetrics}. Both
|
|
14
|
-
* shapes live in that one map - an operator (`"col" <=> $1`, Postgres/CockroachDB) or a function call
|
|
15
|
-
* (`VEC_DISTANCE_COSINE(col, ?)`, MariaDB/SQLite) - so {@link appendVectorSort} is written once and an
|
|
16
|
-
* engine with no vector search at all is simply the empty map.
|
|
6
|
+
* Vector search for the SQL dialects: the distance a `$sort` ranks by and projects, and the ANN tuning.
|
|
7
|
+
* Each dialect lists its metrics in {@link vectorMetrics}, an operator or a function; empty means no search.
|
|
17
8
|
*/
|
|
18
9
|
export class VectorSqlDialect extends AbstractDialect {
|
|
19
10
|
vectorExtension = undefined;
|
|
20
11
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* refuses instead of running a tuning that would silently not apply.
|
|
24
|
-
*/
|
|
25
|
-
vectorTuningNeedsTransaction = false;
|
|
26
|
-
/**
|
|
27
|
-
* `SET`s that widen an ANN index's search for one query, run before it on the same connection.
|
|
28
|
-
*
|
|
29
|
-
* Keyed off `$sort` rather than a `$where` `$near`, because the ANN index is what ranks: pgvector
|
|
30
|
-
* reaches for HNSW on an `ORDER BY distance LIMIT`, while a bare distance predicate scans whatever
|
|
31
|
-
* the planner picks. Tuning a query that never touches the index would set a knob for nothing.
|
|
32
|
-
*
|
|
33
|
-
* Empty by default: SQLite, libSQL and Turso compute every distance, so there is no candidate list
|
|
34
|
-
* to widen, and a field with no ANN index has nothing to tune either.
|
|
12
|
+
* `SET`s widening an ANN index's search for one query, run before it on its connection. Keyed off `$sort`,
|
|
13
|
+
* since the index is what ranks. Empty where every distance is computed anyway.
|
|
35
14
|
*/
|
|
36
15
|
vectorTuningStatements(_meta, _q) {
|
|
37
16
|
return [];
|
|
@@ -41,13 +20,8 @@ export class VectorSqlDialect extends AbstractDialect {
|
|
|
41
20
|
return findVectorSort(q.$sort)?.key;
|
|
42
21
|
}
|
|
43
22
|
/**
|
|
44
|
-
* The ANN index `$candidates`
|
|
45
|
-
*
|
|
46
|
-
* dialects that act on it cannot disagree about when tuning applies.
|
|
47
|
-
*
|
|
48
|
-
* Validates here rather than at each emitter because the number is spelled into the statement
|
|
49
|
-
* rather than bound: `SET LOCAL hnsw.ef_search = $1` is not a thing either engine accepts. `/http`
|
|
50
|
-
* casts client JSON straight to `Query`, so `'abc'` and `null` both reach this.
|
|
23
|
+
* The ANN index `$candidates` tunes for the query, or nothing to tune. Checked here, since the number is
|
|
24
|
+
* spelled into a `SET` rather than bound, and `/http` input is untyped.
|
|
51
25
|
*/
|
|
52
26
|
tunedVectorIndex(meta, q) {
|
|
53
27
|
const candidates = q.$candidates;
|
|
@@ -83,17 +57,12 @@ export class VectorSqlDialect extends AbstractDialect {
|
|
|
83
57
|
appendVectorValue(ctx, value, _field) {
|
|
84
58
|
ctx.addValue(`[${value.join(',')}]`);
|
|
85
59
|
}
|
|
86
|
-
/**
|
|
87
|
-
* Whether this engine has pgvector's narrower vector types (`halfvec`, `sparsevec`) or only the one.
|
|
88
|
-
* Declared by the dialect that has them rather than looked up in a table keyed by dialect name.
|
|
89
|
-
*/
|
|
90
|
-
hasNarrowVectorTypes = false;
|
|
91
60
|
/**
|
|
92
61
|
* The vector type this dialect actually has for a declared one, so the cast follows the column
|
|
93
62
|
* rather than naming a type the engine does not define.
|
|
94
63
|
*/
|
|
95
64
|
supportedVectorType(cast) {
|
|
96
|
-
return this.
|
|
65
|
+
return this.features.narrowVectorTypes ? cast : 'vector';
|
|
97
66
|
}
|
|
98
67
|
/**
|
|
99
68
|
* The distance a vector `$sort` projects, which the projection names after `$project`. Delegates to
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { FieldOptions, HookEvent, RelationRegistration, Type } from '../../type/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* What the member decorators record for one class,
|
|
4
|
-
*
|
|
5
|
-
* decorator spec, so this object is the only channel between them and the class decorator that does.
|
|
6
|
-
*
|
|
7
|
-
* The writable counterpart of `EntityMembers`, which is what registration reads: this one is written
|
|
8
|
-
* into member by member, so every map is present and none of them is readonly.
|
|
3
|
+
* What the member decorators record for one class, until `@Entity()` or `defineEntity` drains it: the
|
|
4
|
+
* only channel from a member decorator to its class. The writable counterpart of `EntityMembers`.
|
|
9
5
|
*/
|
|
10
6
|
export type MemberRegistrations = {
|
|
11
7
|
readonly fields: Record<string, FieldOptions>;
|
|
@@ -13,13 +9,8 @@ export type MemberRegistrations = {
|
|
|
13
9
|
readonly hooks: Partial<Record<HookEvent, string[]>>;
|
|
14
10
|
};
|
|
15
11
|
/**
|
|
16
|
-
* The
|
|
17
|
-
*
|
|
18
|
-
* Deliberately holds **only** this class's members: inheritance is resolved later by walking the class
|
|
19
|
-
* prototype chain, not by reading through the metadata object's. tsc chains a subclass's metadata to its
|
|
20
|
-
* parent's and SWC does not, so anything built on that chain would work under one compiler and quietly
|
|
21
|
-
* lose inherited fields under the other. Keeping each bag to its own members also means a parent's map
|
|
22
|
-
* is never shared with its subclasses, and hooks cannot be registered twice.
|
|
12
|
+
* The class's own registrations, created on first use, never read through a parent's: inheritance walks
|
|
13
|
+
* the class chain, since not every compiler chains decorator metadata.
|
|
23
14
|
*/
|
|
24
15
|
export declare function memberRegistrations(metadata: DecoratorMetadata): MemberRegistrations;
|
|
25
16
|
/**
|
|
@@ -28,11 +19,7 @@ export declare function memberRegistrations(metadata: DecoratorMetadata): Member
|
|
|
28
19
|
*/
|
|
29
20
|
export declare function drainRegistrations(metadata: DecoratorMetadata | undefined): MemberRegistrations | undefined;
|
|
30
21
|
/**
|
|
31
|
-
* The registrations a class made for itself
|
|
32
|
-
*
|
|
33
|
-
* @remarks Only usable once the class is fully defined, which is why `@Entity()` reads
|
|
34
|
-
* `context.metadata` instead: TypeScript attaches `Symbol.metadata` to the class *after* its class
|
|
35
|
-
* decorators return. Ancestors are always fully defined by then, so this is how inherited members are
|
|
36
|
-
* collected.
|
|
22
|
+
* The registrations a class made for itself, readable once it is fully defined: `@Entity()` reads
|
|
23
|
+
* `context.metadata` instead, since the class gets `Symbol.metadata` after its decorators return.
|
|
37
24
|
*/
|
|
38
25
|
export declare function ownRegistrations(entity: Type<unknown>): MemberRegistrations | undefined;
|
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* without this every `context.metadata` is `undefined` and field registration is silently dropped
|
|
5
|
-
* rather than failing.
|
|
6
|
-
*
|
|
7
|
-
* `Symbol.for`, not `Symbol()`, so a duplicated copy of this module (HMR, federated bundles, ESM+CJS
|
|
8
|
-
* dual-loading) lands on the same symbol, and so it agrees with the key esbuild and SWC fall back to
|
|
9
|
-
* (`Symbol.metadata ?? Symbol.for('Symbol.metadata')`). Assigned through a widened alias because the
|
|
10
|
-
* lib declares the property `readonly`; when a runtime does define it, `??=` leaves it alone.
|
|
2
|
+
* Polyfills `Symbol.metadata`, without which TypeScript builds no `context.metadata` and every field is
|
|
3
|
+
* silently dropped. `Symbol.for`, the key esbuild and SWC fall back to, so duplicated modules agree.
|
|
11
4
|
*/
|
|
12
5
|
const symbolCtor = Symbol;
|
|
13
6
|
symbolCtor.metadata ??= Symbol.for('Symbol.metadata');
|
|
14
7
|
/** Where member registrations live on the per-class metadata object. */
|
|
15
8
|
const registrations = Symbol.for('uql-orm/entity/decoratorMembers');
|
|
16
9
|
/**
|
|
17
|
-
* The
|
|
18
|
-
*
|
|
19
|
-
* Deliberately holds **only** this class's members: inheritance is resolved later by walking the class
|
|
20
|
-
* prototype chain, not by reading through the metadata object's. tsc chains a subclass's metadata to its
|
|
21
|
-
* parent's and SWC does not, so anything built on that chain would work under one compiler and quietly
|
|
22
|
-
* lose inherited fields under the other. Keeping each bag to its own members also means a parent's map
|
|
23
|
-
* is never shared with its subclasses, and hooks cannot be registered twice.
|
|
10
|
+
* The class's own registrations, created on first use, never read through a parent's: inheritance walks
|
|
11
|
+
* the class chain, since not every compiler chains decorator metadata.
|
|
24
12
|
*/
|
|
25
13
|
export function memberRegistrations(metadata) {
|
|
26
14
|
if (!Object.hasOwn(metadata, registrations)) {
|
|
@@ -41,12 +29,8 @@ export function drainRegistrations(metadata) {
|
|
|
41
29
|
return own;
|
|
42
30
|
}
|
|
43
31
|
/**
|
|
44
|
-
* The registrations a class made for itself
|
|
45
|
-
*
|
|
46
|
-
* @remarks Only usable once the class is fully defined, which is why `@Entity()` reads
|
|
47
|
-
* `context.metadata` instead: TypeScript attaches `Symbol.metadata` to the class *after* its class
|
|
48
|
-
* decorators return. Ancestors are always fully defined by then, so this is how inherited members are
|
|
49
|
-
* collected.
|
|
32
|
+
* The registrations a class made for itself, readable once it is fully defined: `@Entity()` reads
|
|
33
|
+
* `context.metadata` instead, since the class gets `Symbol.metadata` after its decorators return.
|
|
50
34
|
*/
|
|
51
35
|
export function ownRegistrations(entity) {
|
|
52
36
|
const metadata = Object.getOwnPropertyDescriptor(entity, Symbol.metadata)?.value;
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import type { EntityIndexColumnInput, EntityIndexOptions, EntityOptions, FilterName, FilterOptions, RefMap, Type } from '../../type/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Marks a class as an entity and finalizes its metadata.
|
|
4
|
-
*
|
|
5
|
-
* @remarks Takes the registrations from `context.metadata` rather than from the class. Member
|
|
6
|
-
* decorators have already run by the time a class decorator does, but TypeScript defines
|
|
7
|
-
* `Symbol.metadata` on the class *after* the class decorators return, so reading `entity[Symbol.metadata]`
|
|
8
|
-
* here would find only what the base class left behind. `defineEntity` reads it off the class instead,
|
|
9
|
-
* which is correct for the imperative path because it runs later still.
|
|
3
|
+
* Marks a class as an entity and finalizes its metadata, draining `context.metadata`: the class gets
|
|
4
|
+
* `Symbol.metadata` only after its decorators return.
|
|
10
5
|
*/
|
|
11
6
|
export declare function Entity<E>(opts?: NoInfer<EntityOptions<E>>): (entity: Type<E>, context?: ClassDecoratorContext) => void;
|
|
12
7
|
/**
|
|
@@ -3,13 +3,8 @@ import { drainRegistrations } from './bag.js';
|
|
|
3
3
|
// The class-level decorators. Unlike the member ones they receive the class, so each is a direct call
|
|
4
4
|
// into the registry with no bag in between.
|
|
5
5
|
/**
|
|
6
|
-
* Marks a class as an entity and finalizes its metadata.
|
|
7
|
-
*
|
|
8
|
-
* @remarks Takes the registrations from `context.metadata` rather than from the class. Member
|
|
9
|
-
* decorators have already run by the time a class decorator does, but TypeScript defines
|
|
10
|
-
* `Symbol.metadata` on the class *after* the class decorators return, so reading `entity[Symbol.metadata]`
|
|
11
|
-
* here would find only what the base class left behind. `defineEntity` reads it off the class instead,
|
|
12
|
-
* which is correct for the imperative path because it runs later still.
|
|
6
|
+
* Marks a class as an entity and finalizes its metadata, draining `context.metadata`: the class gets
|
|
7
|
+
* `Symbol.metadata` only after its decorators return.
|
|
13
8
|
*/
|
|
14
9
|
export function Entity(opts) {
|
|
15
10
|
return (entity, context) => {
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import type { EntityGetter, FieldOptions, FieldType, HasCompositeKey, IdValue, NamedIdKey, RelationManyToManyOptions, RelationManyToOneOptions, RelationOneToManyOptions, RelationOneToOneOptions, TsTypeOf } from '../../type/index.js';
|
|
1
|
+
import type { EntityGetter, FieldOptions, FieldType, HasCompositeKey, IdValue, NamedIdKey, RejectKeys, RelationManyToManyOptions, RelationManyToOneOptions, RelationOneToManyOptions, RelationOneToOneOptions, TsTypeOf } from '../../type/index.js';
|
|
2
2
|
import type { RejectIncompatible } from '../../util/index.js';
|
|
3
3
|
/** A member decorator that also constrains the property it may be applied to, on a class `O`. */
|
|
4
4
|
type MemberDecorator<V, O = unknown> = (value: undefined, context: ClassFieldDecoratorContext<O, V>) => void;
|
|
5
|
-
/**
|
|
6
|
-
* Maps any option the type does not declare to `never`, turning a typo into a compile error.
|
|
7
|
-
*
|
|
8
|
-
* Needed because the decorators capture their options as a naked type parameter, and TypeScript
|
|
9
|
-
* skips excess-property checking on one of those: `@Field({ nulable: true })` compiled and was
|
|
10
|
-
* silently ignored. Resolves to `unknown` - an inert intersection member - when there are none.
|
|
11
|
-
*/
|
|
12
|
-
type RejectUnknown<O, Known> = [Exclude<keyof O, keyof Known>] extends [never] ? unknown : Record<Exclude<keyof O, keyof Known> & string, never>;
|
|
13
5
|
/**
|
|
14
6
|
* The property type a set of field options describes: the declared `type`, narrowed by `enum` to the
|
|
15
7
|
* values that type admits (so `enum: [2]` stays off a `String`), or else the referenced key's own type,
|
|
@@ -24,31 +16,20 @@ type DeclaredValue<O> = O extends {
|
|
|
24
16
|
} ? HasCompositeKey<E> extends true ? {
|
|
25
17
|
readonly __compositeKeyNeedsAColumnPerKey: true;
|
|
26
18
|
} : IdValue<E> : never;
|
|
27
|
-
/**
|
|
28
|
-
* The enum's members, or a named complaint when they widened.
|
|
29
|
-
*
|
|
30
|
-
* `['a', 'b']` without `as const` infers `string[]`, whose member type is the field's own type and
|
|
31
|
-
* so narrows nothing - the check would be silently off. Resolving to a type no property can hold
|
|
32
|
-
* makes that a compile error that says why, rather than a decoration.
|
|
33
|
-
*/
|
|
19
|
+
/** The enum's members, or a named complaint where they widened for lack of `as const`, which would check nothing. */
|
|
34
20
|
type EnumValue<Members, Declared> = Declared extends Members ? {
|
|
35
21
|
readonly __enumNeedsAsConst: true;
|
|
36
22
|
} : Members;
|
|
37
23
|
/**
|
|
38
|
-
* Declares a persisted field.
|
|
39
|
-
*
|
|
40
|
-
* `@Field({ type: String })` on a `number` property is a compile error rather than a silent TEXT column,
|
|
41
|
-
* which is what makes the now-mandatory `type` worth stating.
|
|
42
|
-
*
|
|
24
|
+
* Declares a persisted field, its `type` checked against the property's.
|
|
43
25
|
* @example `@Field({ type: String }) name?: string;`
|
|
44
|
-
* @example `@Field({ references: () => User }) userId?: string;`
|
|
45
|
-
* @example `@Field({ type: Number, computed: (line) => raw`${line.qty} * ${line.price}` }) total?: number;`
|
|
26
|
+
* @example `@Field({ references: () => User }) userId?: string;`
|
|
46
27
|
*/
|
|
47
28
|
export declare function Field<This, O extends FieldOptions<DeclaredValue<O>, This> & ({
|
|
48
29
|
type: FieldType;
|
|
49
30
|
} | {
|
|
50
31
|
references: EntityGetter;
|
|
51
|
-
}) &
|
|
32
|
+
}) & RejectKeys<Exclude<keyof O, keyof FieldOptions>> & RejectIncompatible<O>>(opts: O): MemberDecorator<DeclaredValue<O> | undefined, This>;
|
|
52
33
|
/**
|
|
53
34
|
* A key the type level cannot name, reported on each `@Id` that leaves it unnamed. Where no `idKey`
|
|
54
35
|
* brand and no conventional name applies, `IdKey` falls back to every field, and `IdValue`,
|
|
@@ -60,16 +41,12 @@ type KeyIsNamed<This> = [NamedIdKey<This>] extends [never] ? {
|
|
|
60
41
|
/** {@link MemberDecorator} that also constrains the class, which is where a key is named. */
|
|
61
42
|
type IdDecorator<V> = <This>(value: undefined, context: ClassFieldDecoratorContext<This, V> & KeyIsNamed<This>) => void;
|
|
62
43
|
/**
|
|
63
|
-
* Declares the primary key, checked
|
|
64
|
-
* a key not named `id`, `_id` or `uuid` has to be named by the `idKey` brand.
|
|
65
|
-
*
|
|
66
|
-
* @example `@Id({ type: Number }) id?: number;`
|
|
44
|
+
* Declares the primary key, checked like `@Field`; a key not named `id`, `_id` or `uuid` needs the `idKey` brand.
|
|
67
45
|
* @example `@Id({ type: 'uuid', onInsert: uuidv7 }) id?: string;`
|
|
68
|
-
* @example `[idKey]?: 'pk';` beside `@Id({ type: Number }) pk?: number;`
|
|
69
46
|
*/
|
|
70
47
|
export declare function Id<O extends FieldOptions<DeclaredValue<O>> & {
|
|
71
48
|
type: FieldType;
|
|
72
|
-
} &
|
|
49
|
+
} & RejectKeys<Exclude<keyof O, keyof FieldOptions>> & RejectIncompatible<O> & {
|
|
73
50
|
readonly nullable?: false;
|
|
74
51
|
}>(opts: O): IdDecorator<DeclaredValue<O> | undefined>;
|
|
75
52
|
/**
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { relationRegistration } from '../metadata/definition.js';
|
|
2
2
|
import { memberRegistrations } from './bag.js';
|
|
3
3
|
/**
|
|
4
|
-
* Declares a persisted field.
|
|
5
|
-
*
|
|
6
|
-
* `@Field({ type: String })` on a `number` property is a compile error rather than a silent TEXT column,
|
|
7
|
-
* which is what makes the now-mandatory `type` worth stating.
|
|
8
|
-
*
|
|
4
|
+
* Declares a persisted field, its `type` checked against the property's.
|
|
9
5
|
* @example `@Field({ type: String }) name?: string;`
|
|
10
|
-
* @example `@Field({ references: () => User }) userId?: string;`
|
|
11
|
-
* @example `@Field({ type: Number, computed: (line) => raw`${line.qty} * ${line.price}` }) total?: number;`
|
|
6
|
+
* @example `@Field({ references: () => User }) userId?: string;`
|
|
12
7
|
*/
|
|
13
8
|
export function Field(opts) {
|
|
14
9
|
return (_value, context) => {
|
|
@@ -16,12 +11,8 @@ export function Field(opts) {
|
|
|
16
11
|
};
|
|
17
12
|
}
|
|
18
13
|
/**
|
|
19
|
-
* Declares the primary key, checked
|
|
20
|
-
* a key not named `id`, `_id` or `uuid` has to be named by the `idKey` brand.
|
|
21
|
-
*
|
|
22
|
-
* @example `@Id({ type: Number }) id?: number;`
|
|
14
|
+
* Declares the primary key, checked like `@Field`; a key not named `id`, `_id` or `uuid` needs the `idKey` brand.
|
|
23
15
|
* @example `@Id({ type: 'uuid', onInsert: uuidv7 }) id?: string;`
|
|
24
|
-
* @example `[idKey]?: 'pk';` beside `@Id({ type: Number }) pk?: number;`
|
|
25
16
|
*/
|
|
26
17
|
export function Id(opts) {
|
|
27
18
|
return (_value, context) => {
|
|
@@ -39,25 +39,9 @@ export declare function soleIdOf<E>(meta: EntityMeta<E>, what: string): IdKey<E>
|
|
|
39
39
|
export declare function fieldOf<E>(meta: EntityMeta<E>, key: string): FieldMeta;
|
|
40
40
|
/** The relation `key` names, for a caller that took `key` from the metadata itself. */
|
|
41
41
|
export declare function relationOf<E>(meta: EntityMeta<E>, key: RelationKey<E>): RelationMeta;
|
|
42
|
-
/**
|
|
43
|
-
* Whether the caller named every column of the row's primary key, so {@link idOf} can name the row.
|
|
44
|
-
*
|
|
45
|
-
* `!= null` rather than falsiness: `0` and an empty string are ids a row can legitimately carry, and
|
|
46
|
-
* reading them as "no id" is how a write of that row turned into a second insert. Distinct from
|
|
47
|
-
* "does the row carry this column", which an insert asks of `undefined` alone because that is what
|
|
48
|
-
* decides whether the column appears in its `VALUES` list at all.
|
|
49
|
-
*/
|
|
42
|
+
/** Whether the row names every column of its primary key, `0` and `''` included. */
|
|
50
43
|
export declare function namesKey<E>(meta: EntityMeta<E>, row: EntityData<E>): boolean;
|
|
51
|
-
/**
|
|
52
|
-
* A row's primary key: the value itself for a single key, an object carrying every key for a
|
|
53
|
-
* composite - which is {@link WrittenId}, and reads as the {@link EntityId} a `$where` takes.
|
|
54
|
-
*
|
|
55
|
-
* What a settled write names its rows by, and what a write hands back. Naming a composite row by one
|
|
56
|
-
* of its columns would address every row agreeing on that one.
|
|
57
|
-
*
|
|
58
|
-
* `WrittenId` does not reduce for an unresolved `E`, so which branch this entity is in cannot be
|
|
59
|
-
* proven here, only checked - which is what `ids.length` does.
|
|
60
|
-
*/
|
|
44
|
+
/** A row's primary key: its value, or a map of every column on a composite, checked at run time. */
|
|
61
45
|
export declare function idOf<E>(meta: EntityMeta<E>, row: EntityData<E>): WrittenId<E>;
|
|
62
46
|
/**
|
|
63
47
|
* Forgets an entity, and reports whether there was one - for a registry that grows at runtime, where a
|