uql-orm 0.65.1 → 0.67.0
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 +5 -10
- package/dist/entity/decorator/entity.js +2 -7
- package/dist/entity/decorator/members.d.ts +10 -31
- package/dist/entity/decorator/members.js +3 -12
- package/dist/entity/metadata/definition.d.ts +5 -21
- package/dist/entity/metadata/definition.js +69 -91
- package/dist/http/handler.d.ts +2 -14
- package/dist/index.d.ts +3 -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 +20 -66
- package/dist/migrate/schemaGenerator.js +32 -93
- 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 +6 -41
- 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 +189 -551
- 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 +28 -78
- 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 +5 -37
- package/dist/util/field.util.js +7 -50
- 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
package/dist/type/entity.d.ts
CHANGED
|
@@ -4,89 +4,54 @@ import type { ColumnRef, QueryRaw } from './queryRaw.js';
|
|
|
4
4
|
import type { QueryWhere } from './queryWhere.js';
|
|
5
5
|
import type { Except, IsMany, Json, Scalar, Type, Unpacked } from './utility.js';
|
|
6
6
|
import type { VectorDistance, VectorIndexOptions, VectorIndexType } from './vector.js';
|
|
7
|
-
/**
|
|
8
|
-
* Allow to customize the name of the property that identifies an entity
|
|
9
|
-
*/
|
|
7
|
+
/** Brands the property an entity is identified by, where it is not `id`, `_id` or `uuid`. */
|
|
10
8
|
export declare const idKey: unique symbol;
|
|
11
|
-
/**
|
|
12
|
-
* The one filter name uql registers itself, from `@Field({ softDelete })`. Four ends have to agree on
|
|
13
|
-
* it and none would fail if they drifted: the field that registers it, the decorator that reserves
|
|
14
|
-
* the name against a user's own filter, the hard delete that switches it off, and the bypass check
|
|
15
|
-
* that lets it through on an entity which never declared one.
|
|
16
|
-
*/
|
|
9
|
+
/** The filter `@Field({ softDelete })` registers, a name reserved against an entity's own filters. */
|
|
17
10
|
export declare const SOFT_DELETE_FILTER = "softDelete";
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
*/
|
|
11
|
+
/** A filter name an entity may declare: any but {@link SOFT_DELETE_FILTER}, which a refusal names. */
|
|
12
|
+
export type FilterName<N extends string> = N extends typeof SOFT_DELETE_FILTER ? `'${N}' is reserved for the filter @Field({ softDelete }) registers` : N;
|
|
13
|
+
/** The key names of an entity. */
|
|
21
14
|
export type Key<E> = keyof E & string;
|
|
22
15
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* (without it, optional properties leak `undefined` into the union).
|
|
27
|
-
*
|
|
28
|
-
* `readonly Json[]` is its own arm because the brand sits on the element, so the `Json` arm cannot
|
|
29
|
-
* see it. What keeps a to-many relation out of that arm is the weak-type check: `Json<unknown>` is
|
|
30
|
-
* all-optional, which a class with named properties is not assignable to.
|
|
31
|
-
*
|
|
32
|
-
* The check is bracketed so `any` resolves once rather than matching both this and
|
|
33
|
-
* {@link RelationKey}: an unbracketed `any extends X` satisfies either branch. It reads
|
|
34
|
-
* `readonly Scalar[]`, which every mutable one satisfies too, so declaring a vector or a scalar
|
|
35
|
-
* array `readonly` does not push the field over into {@link RelationKey}.
|
|
16
|
+
* The field names of an entity: scalars, scalar arrays (a vector) and JSON, including a list of JSON
|
|
17
|
+
* documents, whose brand sits on the element. The check is bracketed so `any` lands on one side, and a
|
|
18
|
+
* class is kept off the `Json` arm by the weak-type check.
|
|
36
19
|
*/
|
|
37
20
|
export type FieldKey<E> = {
|
|
38
21
|
readonly [K in keyof E]-?: [NonNullable<E[K]>] extends [Scalar | readonly Scalar[] | Json | readonly Json[]] ? K : never;
|
|
39
22
|
}[Key<E>];
|
|
40
|
-
/**
|
|
41
|
-
* Infers the relation names of an entity: whatever is left once its fields and its methods are
|
|
42
|
-
* taken out. Stated as the complement rather than as {@link FieldKey}'s test negated, so the two
|
|
43
|
-
* cannot drift; methods are subtracted because one is not a `Scalar` and would otherwise read as a
|
|
44
|
-
* relation.
|
|
45
|
-
*/
|
|
23
|
+
/** The relation names of an entity: every key but its fields and its methods, so the two sets cannot drift. */
|
|
46
24
|
export type RelationKey<E> = Exclude<Key<E>, FieldKey<E> | MethodKey<E>>;
|
|
47
|
-
/**
|
|
48
|
-
* Whether `T` carries the `Json` brand. Checks for the `__json` marker key explicitly:
|
|
49
|
-
* a bare `extends Json<infer T>` is not discriminating in check position (primitives match it,
|
|
50
|
-
* inferring junk like `T = string`), while the marker key only exists on branded types.
|
|
51
|
-
*/
|
|
25
|
+
/** Whether `T` carries the `Json` brand, read off its marker key: a primitive matches `Json<infer P>` too. */
|
|
52
26
|
type IsJson<T> = '__json' extends keyof T ? true : false;
|
|
53
|
-
/**
|
|
54
|
-
type IsJsonColumn<T> = IsJson<T> extends true ? true : IsJson<NonNullable<Unpacked<T>>>;
|
|
55
|
-
/** The payload `P` of a branded `Json<P>`, or `never` for any non-JSON type. */
|
|
27
|
+
/** The payload `P` of a branded `Json<P>`, or `never` for any other type. */
|
|
56
28
|
type UnwrapJson<T> = IsJson<T> extends true ? (T extends Json<infer P> ? P : never) : never;
|
|
29
|
+
/** What a JSON column declared as `V` holds, `Json<P>` or `Json<P>[]` alike; `never` on any other column. */
|
|
30
|
+
type JsonPayload<V, T = NonNullable<V>> = IsJson<T> extends true ? UnwrapJson<T> : UnwrapJson<NonNullable<Unpacked<T>>>;
|
|
31
|
+
/** Whether `V` is what a JSON column holds. */
|
|
32
|
+
type IsJsonColumn<V> = [JsonPayload<V>] extends [never] ? false : true;
|
|
33
|
+
/** The JSON columns of `E`, which an index can address. */
|
|
34
|
+
type JsonColumnKey<E> = {
|
|
35
|
+
readonly [K in keyof E]-?: IsJsonColumn<E[K]> extends true ? K : never;
|
|
36
|
+
}[Key<E>];
|
|
57
37
|
/**
|
|
58
|
-
* The
|
|
59
|
-
* `
|
|
60
|
-
*/
|
|
61
|
-
type JsonElement<V> = NonNullable<Unpacked<NonNullable<V>>>;
|
|
62
|
-
/** The `Json` payload of a field value `V`; `never` when `V` is not a JSON field. */
|
|
63
|
-
type JsonPayload<V> = UnwrapJson<JsonElement<V>>;
|
|
64
|
-
/**
|
|
65
|
-
* The fields carrying the `Json` brand, `never` on an entity with none - which is most of them, and
|
|
66
|
-
* what makes {@link JsonFieldPaths} collapse to `never` without deriving a path for anything. Tests
|
|
67
|
-
* the brand rather than the payload, whose extra `Json<infer P>` inference is only worth doing once
|
|
68
|
-
* a field is known to be JSON.
|
|
38
|
+
* The JSON columns a dot-path reads into: all but one holding an array (`Json<string[]>`), which has
|
|
39
|
+
* no path. `never` on an entity with none, which is most of them.
|
|
69
40
|
*/
|
|
70
41
|
type JsonFieldKey<E> = {
|
|
71
|
-
readonly [K in
|
|
72
|
-
}[
|
|
42
|
+
readonly [K in JsonColumnKey<E>]: IsMany<JsonPayload<E[K]>> extends true ? never : K;
|
|
43
|
+
}[JsonColumnKey<E>];
|
|
73
44
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* leaves (they contribute no deeper path and self-prune through `` `${K}.${never}` ``), arrays
|
|
77
|
-
* contribute their element type's paths, and objects recurse per key up to 5 levels deep
|
|
78
|
-
* (deeper suffixes stay accepted via the `string` pattern at the cutoff).
|
|
45
|
+
* The dot-paths into a JSON payload: any suffix on an untyped one, none past a scalar, an array's
|
|
46
|
+
* element's, and an object's keys five levels deep, below which any suffix is accepted.
|
|
79
47
|
*/
|
|
80
48
|
type DeepJsonKeys<T, D extends unknown[] = []> = unknown extends T ? string : NonNullable<T> extends Scalar ? never : NonNullable<T> extends readonly (infer U)[] ? DeepJsonKeys<U, D> : D['length'] extends 5 ? string : {
|
|
81
49
|
[K in keyof NonNullable<T> & string]: K | `${K}.${DeepJsonKeys<NonNullable<T>[K], [...D, unknown]>}`;
|
|
82
50
|
}[keyof NonNullable<T> & string];
|
|
83
51
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* produces `'kind.public' | 'kind.theme' | 'kind.theme.color'`.
|
|
88
|
-
* For `items?: Json<{id: string}>[]`, produces `'items.id'`.
|
|
89
|
-
* An untyped `Json<unknown>` field yields the scoped pattern `` `${K}.${string}` ``.
|
|
52
|
+
* The dot-paths into an entity's JSON columns: `kind?: Json<{ theme: { color: string } }>` gives
|
|
53
|
+
* `'kind.theme' | 'kind.theme.color'`, `items?: Json<{ id: string }>[]` gives `'items.id'`, and an
|
|
54
|
+
* untyped `Json` gives `` `kind.${string}` ``.
|
|
90
55
|
*/
|
|
91
56
|
export type JsonFieldPaths<E> = {
|
|
92
57
|
readonly [K in JsonFieldKey<E>]: `${K & string}.${DeepJsonKeys<JsonPayload<E[K]>>}`;
|
|
@@ -96,41 +61,16 @@ export type JsonFieldPaths<E> = {
|
|
|
96
61
|
* `Record<string, unknown>` leaf). Arrays are stepped into via their element type.
|
|
97
62
|
*/
|
|
98
63
|
type PathValue<T, P extends string> = unknown extends T ? unknown : NonNullable<T> extends readonly (infer U)[] ? PathValue<NonNullable<U>, P> : P extends `${infer K}.${infer Rest}` ? K extends keyof NonNullable<T> ? PathValue<NonNullable<T>[K], Rest> : unknown : P extends keyof NonNullable<T> ? NonNullable<T>[P] : unknown;
|
|
99
|
-
/**
|
|
100
|
-
* The value type at a JSON dot-path `P` of entity `E`; `unknown` when unresolvable, which keeps
|
|
101
|
-
* untyped paths fully permissive in `$where`. Gated on {@link JsonFieldKey}, the same predicate
|
|
102
|
-
* {@link JsonFieldPaths} derives its keys from, so a path that is offered always resolves a value.
|
|
103
|
-
*/
|
|
64
|
+
/** The value at a JSON dot-path of `E`, `unknown` where it cannot be resolved, which keeps an untyped path permissive. */
|
|
104
65
|
export type JsonFieldPathValue<E, P extends string> = P extends `${infer F}.${infer Rest}` ? F extends JsonFieldKey<E> ? PathValue<JsonPayload<E[F]>, Rest> : unknown : unknown;
|
|
105
|
-
/**
|
|
106
|
-
* Extracts only the array-typed keys from `T`, mapping each to its element type via `Unpacked`.
|
|
107
|
-
* Used by `$push` and `$pull` to provide type-safe element targets.
|
|
108
|
-
*/
|
|
66
|
+
/** The array keys of `T`, each mapped to its element type: what `$push` and `$pull` address. */
|
|
109
67
|
export type JsonArrayFields<T> = {
|
|
110
68
|
[K in keyof T as IsMany<T[K]> extends true ? K & string : never]?: Unpacked<NonNullable<T[K]>>;
|
|
111
69
|
};
|
|
112
70
|
/**
|
|
113
|
-
*
|
|
114
|
-
* keys, `$
|
|
115
|
-
*
|
|
116
|
-
* `$set` is shallow: it assigns the given top-level keys and leaves the rest untouched (it is not
|
|
117
|
-
* an RFC 7396 recursive merge). `$pull` removes *every* element equal to the given value.
|
|
118
|
-
*
|
|
119
|
-
* Operators are applied `$pull` -> `$set` -> `$push` -> `$unset`, so any combination - including
|
|
120
|
-
* `$pull` and `$push` on the same key - yields the same result on every dialect.
|
|
121
|
-
*
|
|
122
|
-
* @example
|
|
123
|
-
* ```ts
|
|
124
|
-
* // set only - autocompletes keys from the JSON field's inner type
|
|
125
|
-
* querier.updateOneById(Company, id, { kind: { $set: { public: 1 } } });
|
|
126
|
-
* // unset only - autocompletes keys from the JSON field's inner type
|
|
127
|
-
* querier.updateOneById(Company, id, { kind: { $unset: ['private'] } });
|
|
128
|
-
* // append to / remove from an array - autocompletes array keys, value matches element type
|
|
129
|
-
* querier.updateOneById(Company, id, { kind: { $push: { tags: 'new-tag' } } });
|
|
130
|
-
* querier.updateOneById(Company, id, { kind: { $pull: { tags: 'stale-tag' } } });
|
|
131
|
-
* // combine
|
|
132
|
-
* querier.updateOneById(Company, id, { kind: { $set: { public: 1 }, $push: { tags: 'x' }, $unset: ['private'] } });
|
|
133
|
-
* ```
|
|
71
|
+
* A JSON field's update operators, applied `$pull`, `$set`, `$push`, `$unset` on every engine: `$set`
|
|
72
|
+
* assigns top-level keys (no deep merge), `$pull` removes every equal element. See the JSON guide.
|
|
73
|
+
* @example `{ kind: { $set: { public: 1 }, $push: { tags: 'x' }, $unset: ['private'] } }`
|
|
134
74
|
*/
|
|
135
75
|
export type JsonUpdateOp<T = unknown> = {
|
|
136
76
|
readonly $set?: Partial<T>;
|
|
@@ -139,53 +79,30 @@ export type JsonUpdateOp<T = unknown> = {
|
|
|
139
79
|
readonly $pull?: JsonArrayFields<T>;
|
|
140
80
|
};
|
|
141
81
|
/**
|
|
142
|
-
* The {@link JsonUpdateOp} a field
|
|
143
|
-
*
|
|
144
|
-
* `Json<infer T>` match that would otherwise offer `$set`/`$unset` on plain scalar fields.
|
|
145
|
-
* - `Json<T[]>` payloads. All four operators address object keys of the JSON document, so on an
|
|
146
|
-
* array column none is meaningful: PostgreSQL's `||` would concatenate arrays while
|
|
147
|
-
* `JSON_SET(arr, '$.k', v)` is a no-op on MySQL and SQLite. Replace the whole value instead.
|
|
148
|
-
* `Json<unknown>` stays permissive, since `unknown` is not an array.
|
|
82
|
+
* The {@link JsonUpdateOp} a field takes: `never` on a non-JSON field, and on a JSON array, whose
|
|
83
|
+
* operators would address keys it does not have (engines disagree on what that does).
|
|
149
84
|
*/
|
|
150
85
|
type JsonUpdateOpFor<V, T = UnwrapJson<NonNullable<V>>> = [T] extends [never] ? never : IsMany<T> extends true ? never : JsonUpdateOp<T>;
|
|
86
|
+
/** What an update takes beyond the value: `null` to clear an optional member, `raw` SQL, and JSON operators. */
|
|
87
|
+
type UpdateExtra<V> = (undefined extends V ? null : never) | QueryRaw | JsonUpdateOpFor<V>;
|
|
151
88
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* fields - the JSON operators.
|
|
155
|
-
*
|
|
156
|
-
* An optional property is a nullable column, and clearing one is what an update is for, so `null`
|
|
157
|
-
* belongs in the declared type rather than behind a cast.
|
|
158
|
-
*/
|
|
159
|
-
type UpdateFieldValue<V> = V | (undefined extends V ? null : never) | QueryRaw | JsonUpdateOpFor<V>;
|
|
160
|
-
/**
|
|
161
|
-
* An entity's fields and relations, each keeping its declared optionality: what the whole-record
|
|
162
|
-
* writes (`insertOne`, `saveOne`, `upsertOne`, and their `*Many`) persist.
|
|
163
|
-
*
|
|
164
|
-
* Not `E`: that *demands* back every method the class declares, so on an entity carrying a
|
|
165
|
-
* lifecycle hook - `@BeforeInsert() generateSlug()` - a plain `{ title: 'Hello' }` was rejected as
|
|
166
|
-
* "missing the following properties". Method-free entities were unaffected, which is why the other
|
|
167
|
-
* examples worked. No runtime filter can help; the call never gets that far. `Pick` because it
|
|
168
|
-
* stays indexable by `IdKey<E>`, which the write path needs.
|
|
169
|
-
*/
|
|
170
|
-
export type EntityData<E> = Pick<E, FieldKey<E> | RelationKey<E>>;
|
|
171
|
-
/**
|
|
172
|
-
* Payload type for update operations: {@link EntityData} made partial, and widened per field to
|
|
173
|
-
* accept `QueryRaw` or `JsonUpdateOp` (for JSON fields), which gives IDE autocomplete for
|
|
174
|
-
* `$set`/`$push`/`$pull` keys via `Json<infer T>`.
|
|
89
|
+
* What a whole-record write persists: the fields and relations with their declared optionality, a
|
|
90
|
+
* related row's alike, and no methods. Two mapped types, since asking each key costs a conditional.
|
|
175
91
|
*/
|
|
92
|
+
export type EntityData<E, F extends keyof E = FieldKey<E>, R extends keyof E = RelationKey<E>> = {
|
|
93
|
+
[P in F]: E[P];
|
|
94
|
+
} & {
|
|
95
|
+
[P in R]: E[P] | RelationData<E[P]>;
|
|
96
|
+
};
|
|
97
|
+
/** A relation's value as its rows' {@link EntityData}. */
|
|
98
|
+
type RelationData<V> = V extends readonly (infer T)[] ? EntityData<T>[] : V extends object ? EntityData<V> : never;
|
|
99
|
+
/** {@link EntityData} made partial, each member also taking its {@link UpdateExtra}. */
|
|
176
100
|
export type UpdatePayload<E, F extends keyof E = FieldKey<E>, R extends keyof E = RelationKey<E>> = {
|
|
177
|
-
[
|
|
101
|
+
[P in F]?: E[P] | UpdateExtra<E[P]>;
|
|
178
102
|
} & {
|
|
179
|
-
[
|
|
103
|
+
[P in R]?: E[P] | RelationData<E[P]> | UpdateExtra<E[P]>;
|
|
180
104
|
};
|
|
181
|
-
/**
|
|
182
|
-
* Infers the field values of an entity
|
|
183
|
-
*/
|
|
184
|
-
export type FieldValue<E> = E[FieldKey<E>];
|
|
185
|
-
/**
|
|
186
|
-
* The key's name where the entity states it: the `idKey` brand first, then the conventional names.
|
|
187
|
-
* `never` when nothing does, which is the case {@link IdKey} falls back on and `@Id` refuses.
|
|
188
|
-
*/
|
|
105
|
+
/** The key's name where the entity states it, by the `idKey` brand or a conventional name; `never` otherwise. */
|
|
189
106
|
export type NamedIdKey<E> = E extends {
|
|
190
107
|
[idKey]?: infer K;
|
|
191
108
|
} ? K & FieldKey<E> : E extends {
|
|
@@ -195,279 +112,143 @@ export type NamedIdKey<E> = E extends {
|
|
|
195
112
|
} ? 'id' & FieldKey<E> : E extends {
|
|
196
113
|
uuid?: unknown;
|
|
197
114
|
} ? 'uuid' & FieldKey<E> : never;
|
|
198
|
-
/**
|
|
199
|
-
* Infers the name of the key identifier on an entity
|
|
200
|
-
*/
|
|
115
|
+
/** The primary key's name, every field where the entity names none. `& string` for a generic `E`. */
|
|
201
116
|
export type IdKey<E> = ([NamedIdKey<E>] extends [never] ? FieldKey<E> : NamedIdKey<E>) & string;
|
|
202
|
-
/**
|
|
203
|
-
* Infers the value of the key identifier on an entity.
|
|
204
|
-
*
|
|
205
|
-
* A composite key is addressed by an object carrying every key, which is also the `$where` map it
|
|
206
|
-
* reduces to - so both spellings are one type. Completeness is checked at run time by
|
|
207
|
-
* `assertIdValue`: TypeScript cannot accumulate `@Id` across properties into the class type, so it
|
|
208
|
-
* cannot know how many keys there are.
|
|
209
|
-
*
|
|
210
|
-
* Nullable, because an entity declares its id optional - nothing has assigned one before the
|
|
211
|
-
* insert. That puts `undefined` inside every by-id method's parameter, where it would mean "no
|
|
212
|
-
* filter"; `assertIdValue` is what rejects it.
|
|
213
|
-
*/
|
|
117
|
+
/** The primary key's value, optional as the entity declares it: a by-id method refuses a nullish one at run time. */
|
|
214
118
|
export type IdValue<E> = E[IdKey<E>];
|
|
119
|
+
/** Whether `E`'s primary key spans several columns, which no single column can reference. */
|
|
120
|
+
export type HasCompositeKey<E> = true extends IsUnion<IdKey<E>> ? true : false;
|
|
215
121
|
/** Every column of a key, which is how a composite row is named and what a `$where` reduces to. */
|
|
216
122
|
type IdMap<E> = Partial<Pick<E, IdKey<E>>>;
|
|
217
123
|
/**
|
|
218
|
-
* How a row is addressed by its primary key: the value
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* A union rather than a choice between the two, because a caller holding one column's value has to
|
|
222
|
-
* reach the same parameter as one holding a map. {@link WrittenId} is where a shape is committed to.
|
|
223
|
-
*
|
|
224
|
-
* The keys stay optional, and completeness is checked at run time by `assertIdValue`: requiring them
|
|
225
|
-
* would refuse a `$where` map that names one row while it is still being built up.
|
|
124
|
+
* How a row is addressed by its primary key: the value, or a map carrying every key of a composite,
|
|
125
|
+
* which is also the `$where` it reduces to. Completeness is checked at run time.
|
|
226
126
|
*/
|
|
227
127
|
export type EntityId<E> = IdValue<E> | IdMap<E>;
|
|
228
128
|
/** Whether `T` is a union of more than one member, which for a key means the entity's is composite. */
|
|
229
129
|
type IsUnion<T, U = T> = T extends unknown ? ([U] extends [T] ? false : true) : never;
|
|
230
130
|
/**
|
|
231
|
-
* The id a write reports: the
|
|
232
|
-
*
|
|
233
|
-
* Exact where {@link EntityId} is a union, and that is the difference between them - a by-id method
|
|
234
|
-
* *accepts* either spelling, a write *commits* to one.
|
|
235
|
-
*
|
|
236
|
-
* Falls back to `EntityId` where {@link NamedIdKey} names nothing, because there `IdKey` is every
|
|
237
|
-
* field and a composite cannot be told from a single key: reporting a map for a scalar would be a
|
|
238
|
-
* lie. `@Id` refuses an unnamed key, so a decorated entity is always exact, and `defineEntity` is
|
|
239
|
-
* the path where this fallback is still reachable.
|
|
131
|
+
* The id a write reports: the value for a single key, the map for a composite. {@link EntityId} where
|
|
132
|
+
* the entity names no key, since a composite cannot then be told from a single one.
|
|
240
133
|
*/
|
|
241
134
|
export type WrittenId<E> = [NamedIdKey<E>] extends [never] ? EntityId<E> : IsUnion<IdKey<E>> extends true ? IdMap<E> : IdValue<E>;
|
|
242
|
-
/**
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
*/
|
|
253
|
-
export type
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
export type DateColumnType = 'date'
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
export type
|
|
262
|
-
/**
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* SQL vector column types
|
|
272
|
-
*/
|
|
273
|
-
export type VectorColumnType = 'vector' | 'halfvec' | 'sparsevec';
|
|
274
|
-
/**
|
|
275
|
-
* SQL column types supported by uql migrations
|
|
276
|
-
*/
|
|
277
|
-
export type ColumnType = NumericColumnType | StringColumnType | DateColumnType | JsonColumnType | BlobColumnType | BooleanColumnType | VectorColumnType;
|
|
278
|
-
/**
|
|
279
|
-
* Logical types for a field
|
|
280
|
-
*/
|
|
135
|
+
/** Every SQL column type a field may declare, by family: the unions below and `columnFamily` both read it. */
|
|
136
|
+
export declare const COLUMN_TYPES: {
|
|
137
|
+
readonly numeric: readonly ['int', 'integer', 'tinyint', 'smallint', 'bigint', 'float', 'float4', 'float8', 'double', 'double precision', 'decimal', 'numeric', 'real'];
|
|
138
|
+
readonly string: readonly ['char', 'varchar', 'text', 'uuid'];
|
|
139
|
+
readonly date: readonly ['date', 'time', 'datetime', 'timestamp', 'timestamptz'];
|
|
140
|
+
readonly json: readonly ['json', 'jsonb'];
|
|
141
|
+
readonly blob: readonly ['blob', 'bytea'];
|
|
142
|
+
readonly boolean: readonly ['bool', 'boolean'];
|
|
143
|
+
readonly vector: readonly ['vector', 'halfvec', 'sparsevec'];
|
|
144
|
+
};
|
|
145
|
+
/** The kind of column a field lands on, which decides whether an option means anything on it. */
|
|
146
|
+
export type ColumnFamily = keyof typeof COLUMN_TYPES;
|
|
147
|
+
type ColumnTypeOf<F extends ColumnFamily> = (typeof COLUMN_TYPES)[F][number];
|
|
148
|
+
export type NumericColumnType = ColumnTypeOf<'numeric'>;
|
|
149
|
+
export type StringColumnType = ColumnTypeOf<'string'>;
|
|
150
|
+
export type DateColumnType = ColumnTypeOf<'date'>;
|
|
151
|
+
export type JsonColumnType = ColumnTypeOf<'json'>;
|
|
152
|
+
export type BlobColumnType = ColumnTypeOf<'blob'>;
|
|
153
|
+
export type BooleanColumnType = ColumnTypeOf<'boolean'>;
|
|
154
|
+
export type VectorColumnType = ColumnTypeOf<'vector'>;
|
|
155
|
+
/** SQL column types supported by uql migrations. */
|
|
156
|
+
export type ColumnType = ColumnTypeOf<ColumnFamily>;
|
|
157
|
+
type ColumnTypeFamily<T> = {
|
|
158
|
+
[F in ColumnFamily]: T extends ColumnTypeOf<F> ? F : never;
|
|
159
|
+
}[ColumnFamily];
|
|
160
|
+
/** The family a declared `type` puts a column in, or every family where it names none. */
|
|
161
|
+
export type FamilyOf<T> = T extends ColumnType ? ColumnTypeFamily<T> : T extends NumberConstructor | BigIntConstructor ? 'numeric' : T extends StringConstructor ? 'string' : T extends DateConstructor ? 'date' : T extends BooleanConstructor ? 'boolean' : ColumnFamily;
|
|
162
|
+
/** What a field declares its `type` as: a constructor, or a column type. */
|
|
281
163
|
export type FieldType = StringConstructor | NumberConstructor | BooleanConstructor | DateConstructor | BigIntConstructor | ColumnType;
|
|
282
164
|
/**
|
|
283
|
-
* The {@link FieldType}
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* annotation is checked against the property's real TypeScript type, so `@Field({ type: String })` on
|
|
287
|
-
* a `number` no longer compiles into a silent TEXT column. `unknown` shapes fall through to the full
|
|
288
|
-
* {@link FieldType}, keeping genuinely untyped fields usable.
|
|
289
|
-
*
|
|
290
|
-
* JSON is matched on the `__json` brand rather than structurally, because {@link Json} intersects its
|
|
291
|
-
* payload (`Json<string>` really does extend `string`) and would otherwise land on the string arm.
|
|
292
|
-
* Both `Json<T>` and `Json<T>[]` have to be recognised, and the array check has to precede the scalar
|
|
293
|
-
* arms so a `number[]` vector is not read as a `number`.
|
|
165
|
+
* The {@link FieldType}s legal for a field declared as `V`, so `type: String` on a `number` does not
|
|
166
|
+
* compile. JSON is matched on its brand, which a `Json<string>` shares with `string`, and arrays before
|
|
167
|
+
* scalars, so a vector is not read as a `number`.
|
|
294
168
|
*/
|
|
295
169
|
export type TypeFor<V, T = NonNullable<V>> = IsJsonColumn<T> extends true ? JsonColumnType : T extends readonly number[] ? VectorColumnType : T extends string ? StringConstructor | StringColumnType : T extends number ? NumberConstructor | NumericColumnType : T extends bigint ? BigIntConstructor | NumericColumnType : T extends boolean ? BooleanConstructor | BooleanColumnType : T extends Date ? DateConstructor | DateColumnType : T extends Uint8Array ? BlobColumnType : FieldType;
|
|
296
|
-
/**
|
|
297
|
-
* A field as the registry holds it: what the user authored, plus what registration worked out.
|
|
298
|
-
*
|
|
299
|
-
* Separate from {@link FieldOptions} so neither of these can be written in a decorator. They used to
|
|
300
|
-
* live there behind an `@internal` tag and a "do not set this" note, which is a comment standing in
|
|
301
|
-
* for a type boundary.
|
|
302
|
-
*/
|
|
170
|
+
/** A field as the registry holds it: what was authored, plus what registration worked out, which no decorator can write. */
|
|
303
171
|
export type FieldMeta<V = TsTypeOf<FieldType>> = Except<FieldOptions<V>, 'computed'> & {
|
|
304
172
|
/** {@link FieldOptions.computed}, a callback resolved to the SQL it returns. */
|
|
305
173
|
readonly computed?: QueryRaw;
|
|
306
|
-
/**
|
|
307
|
-
* Set by `defineField` when the field gave `references` but no `type`, so schema generation resolves
|
|
308
|
-
* the column from the referenced primary key rather than from whatever ended up in `type`. That is
|
|
309
|
-
* what keeps a `uuid` primary key from becoming TEXT on every foreign key pointing at it.
|
|
310
|
-
*/
|
|
174
|
+
/** Whether the column type comes from the referenced key, where the field gave `references` but no `type`. */
|
|
311
175
|
readonly typeFromReference?: boolean;
|
|
312
|
-
/**
|
|
313
|
-
* Which key of the referenced entity this column points at, where that entity has more than one.
|
|
314
|
-
* Set by `fillOwningSide`; without it a composite target's columns would all take the first key's type.
|
|
315
|
-
*/
|
|
316
|
-
readonly referencedKey?: string;
|
|
317
176
|
};
|
|
318
|
-
/**
|
|
319
|
-
* Configurable options for a field, carrying `V`, the value the column holds: what a generator returns
|
|
320
|
-
* and what a default is has to be that value, checked the same way the declared `type` is. `Scalar` by
|
|
321
|
-
* default, for the places that handle a field without knowing which one it is.
|
|
322
|
-
*/
|
|
177
|
+
/** A field's options, checked against `V`, the value the column holds: every scalar where the field is unknown. */
|
|
323
178
|
export type FieldOptions<V = TsTypeOf<FieldType>, E = unknown> = {
|
|
324
179
|
readonly name?: string;
|
|
325
180
|
readonly isId?: true;
|
|
326
181
|
readonly type?: FieldType;
|
|
327
|
-
/**
|
|
328
|
-
* Dimensions for vector fields. Used in schema generation.
|
|
329
|
-
* @example `@Field({ type: 'vector', dimensions: 1536 })`
|
|
330
|
-
*/
|
|
182
|
+
/** A vector column's dimensions: `@Field({ type: 'vector', dimensions: 1536 })`. */
|
|
331
183
|
readonly dimensions?: number;
|
|
332
|
-
/**
|
|
333
|
-
* Default distance metric for vector similarity queries on this field.
|
|
334
|
-
* Queries can override via `$distance`. Defaults to `'cosine'` if omitted.
|
|
335
|
-
* @example `@Field({ type: 'vector', dimensions: 1536, distance: 'cosine' })`
|
|
336
|
-
*/
|
|
184
|
+
/** The metric a vector search on this field uses unless it names its own `$distance`; `'cosine'` by default. */
|
|
337
185
|
readonly distance?: VectorDistance;
|
|
338
|
-
/**
|
|
339
|
-
* Entity that this field references (for foreign keys).
|
|
340
|
-
*/
|
|
186
|
+
/** The entity this column is a foreign key to. */
|
|
341
187
|
readonly references?: EntityGetter;
|
|
342
188
|
/**
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* when this disagrees with a relation also declared on the same column (the relation wins).
|
|
346
|
-
* @example `@Field({ references: () => Company, onDelete: 'CASCADE' }) companyId?: string;`
|
|
189
|
+
* The foreign key's delete action, `@Field({ references: () => Company, onDelete: 'CASCADE' })`. A
|
|
190
|
+
* relation over the column wins, and is where the update action goes: `onUpdate` here is a value callback.
|
|
347
191
|
*/
|
|
348
192
|
readonly onDelete?: ForeignKeyAction;
|
|
349
193
|
/**
|
|
350
|
-
* The values the column accepts,
|
|
351
|
-
*
|
|
352
|
-
* Emitted as a column `CHECK (col IN (...))` on every SQL dialect rather than a native enum type:
|
|
353
|
-
* one code path, no separate schema object to order, and adding a value stays an ordinary column
|
|
354
|
-
* change instead of Postgres's irreversible `ALTER TYPE ... ADD VALUE`.
|
|
355
|
-
*
|
|
356
|
-
* Not constrained against the field's own type here: the decorator narrows the property to these
|
|
357
|
-
* values instead, which reports a mismatch where the mistake is rather than as an unrelated
|
|
358
|
-
* `never`. `as const` is what makes them literal, and so what makes any of it check.
|
|
359
|
-
*
|
|
360
|
-
* @example `@Field({ type: String, enum: ['draft', 'paid'] as const })`
|
|
194
|
+
* The values the column accepts, `enum: ['draft', 'paid'] as const`: a `CHECK (col IN (...))` on every
|
|
195
|
+
* SQL engine, and the property's type through the decorator, which is why they have to be `as const`.
|
|
361
196
|
*/
|
|
362
197
|
readonly enum?: EnumValues;
|
|
363
198
|
/**
|
|
364
|
-
* An expression the database computes,
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
* Unstored, it is spliced into each statement that reads the field, so nothing is persisted and any
|
|
368
|
-
* expression will do. With `stored`, it becomes a real column - `GENERATED ALWAYS AS (...) STORED` -
|
|
369
|
-
* which the engine keeps up to date, so it can be indexed and read like any other.
|
|
370
|
-
*
|
|
371
|
-
* @example `@Field({ type: String, computed: (user) => raw`${user.first} || ' ' || ${user.last}`, stored: true })`
|
|
199
|
+
* An expression the database computes, never written: spliced into each read, or with `stored` a
|
|
200
|
+
* generated column, `computed: (user) => raw`${user.first} || ' ' || ${user.last}``.
|
|
372
201
|
*/
|
|
373
202
|
readonly computed?: EntitySql<E>;
|
|
374
|
-
/**
|
|
375
|
-
* Whether {@link FieldOptions.computed} is a column the database keeps, rather than an expression
|
|
376
|
-
* spliced into each statement. The dial to flip after profiling: `$select`, `$where` and `$sort`
|
|
377
|
-
* read the field the same way either side of it, so no call site changes.
|
|
378
|
-
*/
|
|
203
|
+
/** Whether {@link FieldOptions.computed} is a generated column rather than spliced into each read; no query changes either way. */
|
|
379
204
|
readonly stored?: boolean;
|
|
380
205
|
readonly updatable?: boolean;
|
|
381
206
|
readonly eager?: boolean;
|
|
382
207
|
readonly onInsert?: OnFieldCallback<V>;
|
|
383
208
|
readonly onUpdate?: OnFieldCallback<V>;
|
|
384
209
|
/**
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
* filter it out (`<field> IS NULL`). An entity may have at most one soft-delete field.
|
|
388
|
-
*
|
|
389
|
-
* The value controls what is stamped on delete: `true` stamps the current timestamp
|
|
390
|
-
* (`new Date()`); any other `Scalar`/`QueryRaw` or `() => Scalar | QueryRaw` callback stamps
|
|
391
|
-
* that value (e.g. `() => Date.now()` for an epoch-millis column).
|
|
392
|
-
* @example `@Field({ softDelete: true }) deletedAt?: Date;`
|
|
393
|
-
* @example `@Field({ softDelete: () => Date.now() }) deletedAt?: number;`
|
|
210
|
+
* Makes a delete stamp this field instead of removing the row, and reads skip stamped rows. `true`
|
|
211
|
+
* stamps `new Date()`, anything else is the value or callback stamped, `softDelete: () => Date.now()`.
|
|
394
212
|
*/
|
|
395
213
|
readonly softDelete?: true | OnFieldCallback<V>;
|
|
396
|
-
/**
|
|
397
|
-
* SQL column type for migrations. If not specified, inferred from TypeScript type.
|
|
398
|
-
*/
|
|
214
|
+
/** The SQL type, where it differs from the one `type` implies: `type: String, columnType: 'decimal'`. */
|
|
399
215
|
readonly columnType?: ColumnType;
|
|
400
|
-
/**
|
|
401
|
-
* Field length (e.g. for varchar)
|
|
402
|
-
*/
|
|
216
|
+
/** A string column's length. */
|
|
403
217
|
readonly length?: number;
|
|
404
|
-
/**
|
|
405
|
-
* Field precision (e.g. for decimal)
|
|
406
|
-
*/
|
|
218
|
+
/** A decimal column's precision. */
|
|
407
219
|
readonly precision?: number;
|
|
408
|
-
/**
|
|
409
|
-
* Field scale (e.g. for decimal)
|
|
410
|
-
*/
|
|
220
|
+
/** A decimal column's scale. */
|
|
411
221
|
readonly scale?: number;
|
|
412
|
-
/**
|
|
413
|
-
* Whether the field is nullable
|
|
414
|
-
*/
|
|
415
222
|
readonly nullable?: boolean;
|
|
416
|
-
/**
|
|
417
|
-
* Whether the field is unique
|
|
418
|
-
*/
|
|
419
223
|
readonly unique?: boolean;
|
|
420
|
-
/**
|
|
421
|
-
* The column's DDL default, rendered into `CREATE TABLE` by `formatDefaultValue`.
|
|
422
|
-
*/
|
|
224
|
+
/** The column's DDL default. */
|
|
423
225
|
readonly defaultValue?: DdlDefault<V>;
|
|
424
|
-
/**
|
|
425
|
-
* Whether the column is auto-incrementing (for integer IDs).
|
|
426
|
-
*/
|
|
226
|
+
/** Whether the database generates the value; a numeric sole key does unless something else fills it. */
|
|
427
227
|
readonly autoIncrement?: boolean;
|
|
428
228
|
/**
|
|
429
229
|
* `true` for an index over the column, a string to name it. A foreign key column is indexed unless
|
|
430
230
|
* this is `false`.
|
|
431
231
|
*/
|
|
432
232
|
readonly index?: boolean | string;
|
|
433
|
-
/**
|
|
434
|
-
* Column comment/description for database documentation.
|
|
435
|
-
*/
|
|
233
|
+
/** The column's comment in the database. */
|
|
436
234
|
readonly comment?: string;
|
|
437
235
|
};
|
|
438
236
|
export type OnFieldCallback<V = TsTypeOf<FieldType>> = V | QueryRaw | (() => V | QueryRaw);
|
|
439
237
|
/**
|
|
440
|
-
* What a column may default to:
|
|
441
|
-
*
|
|
442
|
-
* that exception to every field is what let `@Field({ type: Number, defaultValue: 'hello' })` compile.
|
|
443
|
-
*
|
|
444
|
-
* The erased shape - `FieldOptions` with no field in mind - admits every column's default at once, or
|
|
445
|
-
* no `FieldOptions<V>` would be assignable to the one the registry and the dialects read.
|
|
238
|
+
* What a column may default to: its value, or on a JSON column the SQL literal it stores, `'{}'`. The
|
|
239
|
+
* erased `FieldOptions` takes both, so every field's options stay assignable to it.
|
|
446
240
|
*/
|
|
447
241
|
type DdlDefault<V, T = NonNullable<V>> = IsJsonColumn<T> extends true ? JsonDdlDefault : [TsTypeOf<FieldType>] extends [T] ? JsonDdlDefault | T : T;
|
|
448
242
|
/** What a JSON column, and the field-less `FieldOptions`, may default to. */
|
|
449
243
|
type JsonDdlDefault = Scalar | Record<string, unknown>;
|
|
450
244
|
/**
|
|
451
|
-
* The TypeScript
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
* Both directions are needed because they are consumed at opposite ends. `defineEntity` keys its bulk
|
|
455
|
-
* `fields` by property name, so the property's type is already known and {@link TypeFor} narrows the
|
|
456
|
-
* `type` allowed. A decorator has it the other way round: `@Field({ type: String })` is checked before
|
|
457
|
-
* the class exists, so the only way to reach the property is to state what `type: String` implies and
|
|
458
|
-
* let the decorator's context position compare it against the real field. Neither can be derived from
|
|
459
|
-
* the other by inference, so `entityOptions.test-d.ts` asserts they agree instead.
|
|
245
|
+
* The TypeScript type a declared `type` implies, the inverse of {@link TypeFor}: a decorator checks the
|
|
246
|
+
* property against it, `defineEntity` the other way round. `entityOptions.test-d.ts` keeps them agreeing.
|
|
460
247
|
*/
|
|
461
248
|
export type TsTypeOf<T> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BigIntConstructor ? bigint : T extends BooleanConstructor ? boolean : T extends DateConstructor ? Date : T extends StringColumnType ? string : T extends NumericColumnType ? number | bigint : T extends BooleanColumnType ? boolean : T extends DateColumnType ? Date : T extends JsonColumnType ? Json<unknown> | readonly Json<unknown>[] : T extends BlobColumnType ? Uint8Array : T extends VectorColumnType ? readonly number[] : unknown;
|
|
462
249
|
/**
|
|
463
|
-
* {@link FieldOptions} for a field declared as `V`,
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
* The second arm is load-bearing rather than a convenience: a foreign-key column may omit `type` so
|
|
467
|
-
* that schema generation resolves it from the referenced primary key instead, picking up that key's
|
|
468
|
-
* `columnType`, length and chained references. Forcing `type: Number` onto
|
|
469
|
-
* `@Field({ references: () => Company })` would silently downgrade a `uuid` key to TEXT on every
|
|
470
|
-
* column pointing at it.
|
|
250
|
+
* {@link FieldOptions} for a field declared as `V`, `type` checked by {@link TypeFor}. A foreign key may
|
|
251
|
+
* omit it, taking the referenced key's column type instead.
|
|
471
252
|
*/
|
|
472
253
|
export type FieldOptionsFor<V, E = unknown> = (FieldOptions<NonNullable<V>, E> & {
|
|
473
254
|
readonly type: TypeFor<V>;
|
|
@@ -475,15 +256,11 @@ export type FieldOptionsFor<V, E = unknown> = (FieldOptions<NonNullable<V>, E> &
|
|
|
475
256
|
readonly references: EntityGetter;
|
|
476
257
|
readonly type?: TypeFor<V>;
|
|
477
258
|
});
|
|
478
|
-
/**
|
|
479
|
-
* The entity a relation field points at: `Company` for both `company?: Company` and
|
|
480
|
-
* `companies?: Company[]`.
|
|
481
|
-
*/
|
|
259
|
+
/** The entity a relation points at: `Company` for `company?: Company` and `companies?: Company[]` alike. */
|
|
482
260
|
export type RelationTarget<V> = Extract<Unpacked<V>, object>;
|
|
483
261
|
/**
|
|
484
|
-
* {@link RelationOptions} for a relation
|
|
485
|
-
*
|
|
486
|
-
* conditional on `IsMany<V>`, which left a `mappedBy` callback untyped inside `defineEntity`.
|
|
262
|
+
* {@link RelationOptions} for a relation declared as `V`, keyed on the `cardinality` its shape allows: a
|
|
263
|
+
* key rather than a conditional, which is what types a `mappedBy` callback inside `defineEntity`.
|
|
487
264
|
*/
|
|
488
265
|
export type RelationOptionsFor<V, O = unknown> = {
|
|
489
266
|
readonly cardinality: IsMany<V> extends true ? '1m' | 'mm' : '11' | 'm1';
|
|
@@ -496,20 +273,13 @@ export type RelationOptionsFor<V, O = unknown> = {
|
|
|
496
273
|
} & RelationOneToManyOptions<RelationTarget<V>, O>) | ({
|
|
497
274
|
readonly cardinality: 'mm';
|
|
498
275
|
} & RelationManyToManyOptions<RelationTarget<V>, O>));
|
|
499
|
-
/**
|
|
500
|
-
* The method names of an entity, so hook registrations name a method that exists.
|
|
501
|
-
*/
|
|
276
|
+
/** The method names of an entity, which a hook registration names. */
|
|
502
277
|
export type MethodKey<E> = {
|
|
503
278
|
readonly [K in keyof E]-?: NonNullable<E[K]> extends (...args: never[]) => unknown ? K : never;
|
|
504
279
|
}[Key<E>];
|
|
505
280
|
/**
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
* A getter rather than the class itself because decorator expressions are evaluated while the class is
|
|
509
|
-
* being defined, before its binding is initialized, so naming the class directly is a `ReferenceError`
|
|
510
|
-
* for a self-reference and for whichever side of a circular import is evaluated first - the two shapes an
|
|
511
|
-
* entity graph almost always has. Nothing about the standard decorator spec changes that; it only removed
|
|
512
|
-
* the reflected `design:type` that used to make `entity` optional.
|
|
281
|
+
* An entity class read later, `() => Company`: a decorator runs before its class is bound, so a
|
|
282
|
+
* self-reference or a circular import would otherwise throw.
|
|
513
283
|
*/
|
|
514
284
|
export type EntityGetter<E = object> = () => Type<E>;
|
|
515
285
|
export type CascadeType = 'persist' | 'delete';
|
|
@@ -522,53 +292,43 @@ export type RelationOptions<E, O = unknown> = {
|
|
|
522
292
|
cardinality: RelationCardinality;
|
|
523
293
|
readonly cascade?: boolean | CascadeType;
|
|
524
294
|
/**
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
* (`@ManyToOne`, or a `@OneToOne` without `mappedBy`). `onDelete` falls back to the FK field's own
|
|
528
|
-
* `@Field({ onDelete })` when unset here; `onUpdate` has no such fallback since that key already means
|
|
529
|
-
* a value callback on `FieldOptions`.
|
|
295
|
+
* The foreign key's delete action, the database's alternative to `cascade`, read on the owning side;
|
|
296
|
+
* unset, the column's own `@Field({ onDelete })` applies.
|
|
530
297
|
*/
|
|
531
298
|
readonly onDelete?: ForeignKeyAction;
|
|
532
299
|
readonly onUpdate?: ForeignKeyAction;
|
|
533
300
|
/** The inverse side: the member of the target holding the foreign key or the owning relation, `(post) => post.author`. */
|
|
534
|
-
mappedBy?: (keys: KeyMap<E>) =>
|
|
535
|
-
/**
|
|
536
|
-
* The pivot entity of a many-to-many. Unconstrained by `E`: a pivot holds foreign keys to both
|
|
537
|
-
* sides and is not a relation value of the target, so nothing about it is derivable from `E`.
|
|
538
|
-
*/
|
|
301
|
+
mappedBy?: (keys: KeyMap<E>) => RelationKey<E> | ForeignKey<E, O>;
|
|
302
|
+
/** The junction entity of a many-to-many, holding a foreign key to each side. */
|
|
539
303
|
through?: EntityGetter;
|
|
540
304
|
/**
|
|
541
|
-
* The join columns:
|
|
542
|
-
*
|
|
543
|
-
* foreign: customer.code }]`. A `through` relation takes none: it joins by the junction's column
|
|
544
|
-
* referencing each side.
|
|
305
|
+
* The join columns: a to-one's foreign key, `(post) => post.authorId`, or pairs where no key fits,
|
|
306
|
+
* `(order, customer) => [{ local: order.customerCode, foreign: customer.code }]`. Not with `through`.
|
|
545
307
|
*/
|
|
546
|
-
references?: (local: KeyMap<O>, foreign: KeyMap<E>) =>
|
|
308
|
+
references?: (local: KeyMap<O>, foreign: KeyMap<E>) => ForeignKey<O, E> | readonly RelationReference<O, E>[];
|
|
547
309
|
};
|
|
548
|
-
/**
|
|
310
|
+
/** The one column of `O` that can be a foreign key to `E`: a field holding `E`'s key, which has to be a single one. */
|
|
311
|
+
type ForeignKey<O, E> = HasCompositeKey<E> extends true ? never : FieldKeyHolding<O, IdValue<E>>;
|
|
312
|
+
/** One pair of join columns, each a field read off its entity's key map, the local one holding the foreign's value. */
|
|
549
313
|
export type RelationReference<O, E> = {
|
|
550
|
-
readonly
|
|
551
|
-
|
|
552
|
-
|
|
314
|
+
readonly [F in keyof E]-?: {
|
|
315
|
+
readonly local: FieldKeyHolding<O, E[F]>;
|
|
316
|
+
readonly foreign: F;
|
|
317
|
+
};
|
|
318
|
+
}[FieldKey<E>];
|
|
319
|
+
/** The fields of `O` that can hold any value `V` takes. */
|
|
320
|
+
type FieldKeyHolding<O, V> = {
|
|
321
|
+
readonly [K in keyof O]-?: [NonNullable<V>] extends [NonNullable<O[K]>] ? K : never;
|
|
322
|
+
}[FieldKey<O>];
|
|
553
323
|
/** {@link RelationOptions.references} as pairs alone, for a to-many, which holds no foreign key of its own to name. */
|
|
554
324
|
type RelationReferencePairs<E, O> = (local: KeyMap<O>, foreign: KeyMap<E>) => readonly RelationReference<O, E>[];
|
|
555
|
-
/**
|
|
556
|
-
* A relation once `getMeta` has resolved it: `references` is filled in and `mappedBy` is the key its
|
|
557
|
-
* callback named. Consumers read this shape rather than {@link RelationOptions}, so they need no
|
|
558
|
-
* assertions - `fillRelations` establishes the invariant once, and throws where it cannot.
|
|
559
|
-
*
|
|
560
|
-
* `entity` and `through` stay {@link EntityGetter}s. Resolution could call them once and store the class,
|
|
561
|
-
* but only by keeping the authored relations in a second map: it settles them in place, reading them across
|
|
562
|
-
* entities not resolved yet, so the authored and the settled shape have to be one object. A phase-split
|
|
563
|
-
* metadata map costs more than the call parentheses it saves.
|
|
564
|
-
*/
|
|
325
|
+
/** A relation once `getMeta` resolved it: `references` settled into pairs and `mappedBy` a name. */
|
|
565
326
|
export type RelationMeta = Omit<RelationRegistration, 'references'> & {
|
|
566
327
|
references: RelationReferences;
|
|
567
328
|
};
|
|
568
329
|
/**
|
|
569
|
-
* A relation as the registry takes it
|
|
570
|
-
*
|
|
571
|
-
* names, until `getMeta` pairs it with the target's key, which registration may run before the target has.
|
|
330
|
+
* A relation as the registry takes it: `mappedBy` and `references` read down to names, `references` a
|
|
331
|
+
* single column until `getMeta` pairs it with the target's key.
|
|
572
332
|
*/
|
|
573
333
|
export type RelationRegistration = Omit<RelationOptions<object>, 'mappedBy' | 'references'> & {
|
|
574
334
|
mappedBy?: string;
|
|
@@ -581,38 +341,23 @@ type RelationOwnerJoin<E, O> = (Required<Pick<RelationOptions<E, O>, 'through'>>
|
|
|
581
341
|
readonly references: RelationReferencePairs<E, O>;
|
|
582
342
|
readonly through?: never;
|
|
583
343
|
};
|
|
584
|
-
|
|
585
|
-
type
|
|
344
|
+
/** The side holding the foreign key, which `references` names and the actions attach to. */
|
|
345
|
+
type RelationOptionsOwner<E, O> = Pick<RelationOptions<E, O>, 'entity' | 'cascade' | 'onDelete' | 'onUpdate'> & Required<Pick<RelationOptions<E, O>, 'references'>>;
|
|
346
|
+
type RelationOptionsInverseSide<E, O> = Pick<RelationOptions<E, O>, 'entity' | 'cascade'> & Required<Pick<RelationOptions<E, O>, 'mappedBy'>>;
|
|
586
347
|
type RelationOptionsThroughOwner<E, O> = Pick<RelationOptions<E, O>, 'entity' | 'cascade'> & RelationOwnerJoin<E, O>;
|
|
587
|
-
/**
|
|
588
|
-
* The key names of `E` as values, so a definition reads a member off it - `(post) => post.author` -
|
|
589
|
-
* and follows a rename. Homomorphic in `E`, which is what keeps that link, and `-?` so an optional
|
|
590
|
-
* member still names itself. At runtime one `Proxy` answering its own key serves every entity.
|
|
591
|
-
*/
|
|
348
|
+
/** The key names of `E` as values, so a definition reads a member off it, `(post) => post.author`, and follows a rename. */
|
|
592
349
|
export type KeyMap<E> = {
|
|
593
350
|
readonly [K in keyof E]-?: K;
|
|
594
351
|
};
|
|
595
|
-
/**
|
|
596
|
-
* The fields of `E` as {@link ColumnRef}s, for SQL that names them: `refs(User)` in a statement, the
|
|
597
|
-
* callback's parameter in a definition. Keyed over a type parameter constrained to `keyof E`, as
|
|
598
|
-
* {@link KeyMap} is over `keyof E`, which keeps each ref linked to its field for rename.
|
|
599
|
-
*/
|
|
352
|
+
/** The fields of `E` as {@link ColumnRef}s, for SQL that names them: `refs(User)`, or a definition's callback. */
|
|
600
353
|
export type RefMap<E, F extends keyof E = FieldKey<E>> = {
|
|
601
354
|
readonly [K in F]-?: ColumnRef<K & string>;
|
|
602
355
|
};
|
|
603
|
-
/**
|
|
604
|
-
* SQL a definition writes: `raw`, or a callback reading the entity's fields off its refs. The callback is
|
|
605
|
-
* declared as a method, bivariant in its refs, so one typed for its entity still fits where the entity is
|
|
606
|
-
* erased: the registry, which resolves it.
|
|
607
|
-
*/
|
|
356
|
+
/** SQL a definition writes: `raw`, or a callback reading the fields off its refs, bivariant so the registry can hold it. */
|
|
608
357
|
export type EntitySql<E> = QueryRaw | {
|
|
609
358
|
sql(refs: RefMap<E>): QueryRaw;
|
|
610
359
|
}['sql'];
|
|
611
|
-
/**
|
|
612
|
-
* A predicate DDL carries, over the entity's own fields: a relation, full-text search and a sub-query
|
|
613
|
-
* have nothing a `CHECK` or a partial index can hold. An intersection rather than `Except`, which would
|
|
614
|
-
* remap the keys and lose each one's link to its field.
|
|
615
|
-
*/
|
|
360
|
+
/** A predicate DDL can hold: the entity's own fields, without a relation, `$text` or a sub-query. */
|
|
616
361
|
export type EntityPredicate<E> = QueryWhere<E> & {
|
|
617
362
|
readonly [K in RelationKey<E>]?: never;
|
|
618
363
|
} & {
|
|
@@ -629,32 +374,19 @@ export type RelationReferences = {
|
|
|
629
374
|
readonly foreign: string;
|
|
630
375
|
}[];
|
|
631
376
|
export type RelationCardinality = '11' | 'm1' | '1m' | 'mm';
|
|
632
|
-
export type RelationOneToOneOptions<E, O = unknown> = RelationOptionsOwner<E, O> | RelationOptionsInverseSide<E>;
|
|
633
|
-
export type RelationOneToManyOptions<E, O = unknown> = RelationOptionsInverseSide<E> | RelationOptionsThroughOwner<E, O>;
|
|
377
|
+
export type RelationOneToOneOptions<E, O = unknown> = RelationOptionsOwner<E, O> | RelationOptionsInverseSide<E, O>;
|
|
378
|
+
export type RelationOneToManyOptions<E, O = unknown> = RelationOptionsInverseSide<E, O> | RelationOptionsThroughOwner<E, O>;
|
|
634
379
|
export type RelationManyToOneOptions<E, O = unknown> = RelationOptionsOwner<E, O>;
|
|
635
|
-
export type RelationManyToManyOptions<E, O = unknown> = RelationOptionsThroughOwner<E, O> | RelationOptionsInverseSide<E>;
|
|
636
|
-
/**
|
|
637
|
-
* Lifecycle hook event names.
|
|
638
|
-
*/
|
|
380
|
+
export type RelationManyToManyOptions<E, O = unknown> = RelationOptionsThroughOwner<E, O> | RelationOptionsInverseSide<E, O>;
|
|
381
|
+
/** The lifecycle events. An upsert has its own pair: which branch a row takes is the database's to decide. */
|
|
639
382
|
export type HookEvent = 'beforeInsert' | 'afterInsert' | 'beforeUpdate' | 'afterUpdate' | 'beforeUpsert' | 'afterUpsert' | 'beforeDelete' | 'afterDelete' | 'afterLoad';
|
|
640
|
-
/**
|
|
641
|
-
* A registered hook: the method name on the entity class to call.
|
|
642
|
-
*/
|
|
383
|
+
/** A registered hook: the entity's method to call. */
|
|
643
384
|
export type HookRegistration = {
|
|
644
385
|
readonly methodName: string;
|
|
645
386
|
};
|
|
646
387
|
/**
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
* euclidean (so a cosine query full-scans instead of using the index) and pgvector has no default
|
|
650
|
-
* operator class. MongoDB's `vectorSearch` is excluded - its generator emits no metric at all, so
|
|
651
|
-
* requiring one would demand a value that is dropped.
|
|
652
|
-
*
|
|
653
|
-
* The non-vector arm forbids `distance` (rather than just omitting it) because `VectorIndexOptions`
|
|
654
|
-
* - intersected in below by {@link EntityIndexMeta} - already declares `distance` as optional, for
|
|
655
|
-
* the sake of the migration/introspection schema types that reuse it without this discriminated
|
|
656
|
-
* `type`/`distance` pairing. Without the explicit `never` here, that optional `distance` would
|
|
657
|
-
* survive the intersection and silently typecheck `{ type: 'btree', distance: 'cosine' }`.
|
|
388
|
+
* An index type with the metric it needs: a vector index has to name one, since engines default to
|
|
389
|
+
* a different one than the queries use, and any other index names none.
|
|
658
390
|
*/
|
|
659
391
|
export type IndexTypeOptions = {
|
|
660
392
|
type: VectorIndexType;
|
|
@@ -663,22 +395,14 @@ export type IndexTypeOptions = {
|
|
|
663
395
|
type?: Exclude<IndexType, VectorIndexType>;
|
|
664
396
|
distance?: never;
|
|
665
397
|
};
|
|
666
|
-
/**
|
|
667
|
-
* One index entry as the migration builder takes it: a column name, `raw` for an expression, or an object
|
|
668
|
-
* when the entry needs more. An entity's entries are this too, which is what `normalizeIndexColumn` reads.
|
|
669
|
-
*/
|
|
398
|
+
/** One index entry as the migration builder takes it: a column name, `raw`, or an object when it needs more. */
|
|
670
399
|
export type IndexColumnInput = string | QueryRaw | EntityIndexColumn;
|
|
671
400
|
/**
|
|
672
|
-
* One entry of an entity's index, read off its refs: a column, `raw
|
|
673
|
-
* the entry needs more, a JSON entry's path checked against its column.
|
|
401
|
+
* One entry of an entity's index, read off its refs: a column, `raw`, or an object when it needs more.
|
|
674
402
|
* @example `@Index((post) => [post.tenantId, { column: post.createdAt, order: 'desc' }, raw`lower(${post.email})`])`
|
|
675
403
|
*/
|
|
676
404
|
export type EntityIndexColumnInput<E> = QueryRaw | IndexColumnOptions | IndexJsonColumnOptions<E>;
|
|
677
|
-
/**
|
|
678
|
-
* The JSON entries, one arm per JSON field, each `path` checked against the payload of the column its own
|
|
679
|
-
* entry names: a misspelled path still builds a valid index that no query matches. On a column that is
|
|
680
|
-
* the array (`Json<string[]>`), `jsonArray`'s path resolves to `never`, so it can only be omitted.
|
|
681
|
-
*/
|
|
405
|
+
/** A JSON entry, its `path` checked against its own column's payload: a misspelled one builds an index nothing uses. */
|
|
682
406
|
type IndexJsonColumnOptions<E> = {
|
|
683
407
|
[K in JsonColumnKey<E>]: IndexColumnPlainModifiers & {
|
|
684
408
|
readonly column: ColumnRef<K & string>;
|
|
@@ -690,37 +414,15 @@ type IndexJsonColumnOptions<E> = {
|
|
|
690
414
|
readonly jsonPath?: never;
|
|
691
415
|
});
|
|
692
416
|
}[JsonColumnKey<E>];
|
|
693
|
-
/**
|
|
694
|
-
* The JSON columns an index can address, which is a wider set than {@link JsonFieldKey}: that one
|
|
695
|
-
* unwraps arrays to find the brand, so a column that *is* an array (`Json<string[]>`) reads as a
|
|
696
|
-
* plain one - right for `$where`, which has no path into it, and wrong for `jsonArray`, whose whole
|
|
697
|
-
* subject is that column.
|
|
698
|
-
*/
|
|
699
|
-
type JsonColumnKey<E> = {
|
|
700
|
-
readonly [K in keyof E]-?: IsJsonColumn<NonNullable<E[K]>> extends true ? K : never;
|
|
701
|
-
}[Key<E>];
|
|
702
|
-
/** The payload a path is checked against: the column's own brand, or that of the documents it holds. */
|
|
703
|
-
type JsonColumnPayload<V> = IsJson<NonNullable<V>> extends true ? UnwrapJson<NonNullable<V>> : JsonPayload<V>;
|
|
704
|
-
/**
|
|
705
|
-
* A JSON modifier with its `path` narrowed to the ones that column's payload actually has. Everything
|
|
706
|
-
* else - and `path`'s own optionality, which `jsonArray` needs and `jsonPath` does not - is taken
|
|
707
|
-
* from the declared type rather than restated, so a property added to either cannot miss the checked
|
|
708
|
-
* form.
|
|
709
|
-
*/
|
|
417
|
+
/** A JSON modifier with its `path` narrowed to the column's payload, everything else taken from `T` as declared. */
|
|
710
418
|
type WithCheckedPath<T extends {
|
|
711
419
|
path?: string;
|
|
712
420
|
}, E, K extends Key<E>> = Except<T, 'path' & keyof T> & {
|
|
713
|
-
[P in keyof Pick<T, Extract<keyof T, 'path'>>]: DeepJsonKeys<
|
|
421
|
+
[P in keyof Pick<T, Extract<keyof T, 'path'>>]: DeepJsonKeys<JsonPayload<E[K]>>;
|
|
714
422
|
};
|
|
715
|
-
/**
|
|
716
|
-
* What an index entry can carry besides the thing being indexed. Shared with the normalized
|
|
717
|
-
* `IndexColumnSchema`, so the authored and internal shapes cannot drift apart.
|
|
718
|
-
*/
|
|
423
|
+
/** What an index entry carries besides its column, shared by the authored and the normalized entry. */
|
|
719
424
|
export type IndexColumnModifiers = {
|
|
720
|
-
/**
|
|
721
|
-
* Index only the first `n` characters. MySQL and MariaDB *require* this to index a `TEXT`/`BLOB`
|
|
722
|
-
* column at all ("used in key specification without a key length"); no other engine accepts it.
|
|
723
|
-
*/
|
|
425
|
+
/** Index only the first `n` characters, which the MySQL family requires on a `TEXT` or `BLOB` column. */
|
|
724
426
|
readonly length?: number;
|
|
725
427
|
/** Stored sort order, which lets `ORDER BY ... DESC` pagination use the index. */
|
|
726
428
|
readonly order?: 'asc' | 'desc';
|
|
@@ -734,18 +436,9 @@ export type IndexColumnModifiers = {
|
|
|
734
436
|
readonly jsonArray?: IndexJsonArray;
|
|
735
437
|
};
|
|
736
438
|
/**
|
|
737
|
-
* An index over
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
741
|
-
* `type` picks the reading the way an operand's own type does (`jsonCompareMode`): compared as a
|
|
742
|
-
* number, indexed as a number. Which engines have it is `IndexFeature`'s `jsonPath`.
|
|
743
|
-
*
|
|
744
|
-
* @example
|
|
745
|
-
* ```ts
|
|
746
|
-
* @Index((user) => [{ column: user.kind, jsonPath: { path: 'theme.color', type: String } }]) // 'kind.theme.color': 'red'
|
|
747
|
-
* @Index((user) => [{ column: user.kind, jsonPath: { path: 'rating', type: Number } }]) // 'kind.rating': { $gte: 4 }
|
|
748
|
-
* ```
|
|
439
|
+
* An index over a path inside a JSON column, spelled as the `$where` on it compiles, which is how the
|
|
440
|
+
* planner matches the two. `type` is how the queries compare it.
|
|
441
|
+
* @example `@Index((user) => [{ column: user.kind, jsonPath: { path: 'rating', type: Number } }])`
|
|
749
442
|
*/
|
|
750
443
|
export type IndexJsonPath = {
|
|
751
444
|
/** The path inside the column, spelled as a `$where` key spells it: `'theme.color'`. */
|
|
@@ -754,18 +447,9 @@ export type IndexJsonPath = {
|
|
|
754
447
|
readonly type: FieldType;
|
|
755
448
|
};
|
|
756
449
|
/**
|
|
757
|
-
* MySQL's multi-valued index
|
|
758
|
-
*
|
|
759
|
-
*
|
|
760
|
-
*
|
|
761
|
-
* MySQL is alone in having it - `IndexFeature`'s `jsonArray` - and an index asking for it elsewhere
|
|
762
|
-
* is refused rather than silently built.
|
|
763
|
-
*
|
|
764
|
-
* @example
|
|
765
|
-
* ```ts
|
|
766
|
-
* @Index((user) => [{ column: user.tags, jsonArray: { type: String, length: 64 } }]) // tags: { $all: [...] }
|
|
767
|
-
* @Index((user) => [{ column: user.kind, jsonArray: { path: 'ids', type: Number } }]) // 'kind.ids': { $all: [...] }
|
|
768
|
-
* ```
|
|
450
|
+
* MySQL's multi-valued index, one key per element of the JSON array at `path`, what `$all` and
|
|
451
|
+
* `$elemMatch` containment use; refused on any other engine.
|
|
452
|
+
* @example `@Index((user) => [{ column: user.tags, jsonArray: { type: String, length: 64 } }])`
|
|
769
453
|
*/
|
|
770
454
|
export type IndexJsonArray = {
|
|
771
455
|
/** The array's path inside the column, spelled as a `$where` key spells it; omit for the column. */
|
|
@@ -777,37 +461,25 @@ export type IndexJsonArray = {
|
|
|
777
461
|
};
|
|
778
462
|
/** The modifiers that do not name a JSON path, and so need no entity to be checked against. */
|
|
779
463
|
type IndexColumnPlainModifiers = Except<IndexColumnModifiers, 'jsonPath' | 'jsonArray'>;
|
|
780
|
-
/**
|
|
781
|
-
* An entity's entry with plain modifiers. `jsonPath` and `jsonArray` are `never` here, since a JSON entry
|
|
782
|
-
* would otherwise match this shape too, its path unchecked.
|
|
783
|
-
*/
|
|
464
|
+
/** An entity's entry with plain modifiers, never a JSON one, whose path would then go unchecked. */
|
|
784
465
|
type IndexColumnOptions = IndexColumnPlainModifiers & {
|
|
785
466
|
/** A column read off the refs, or `raw` for an expression. */
|
|
786
467
|
readonly column: QueryRaw;
|
|
787
468
|
readonly jsonPath?: never;
|
|
788
469
|
readonly jsonArray?: never;
|
|
789
470
|
};
|
|
790
|
-
/**
|
|
791
|
-
* One index entry, normalized: every authored shape reduces to this before any dialect or generator sees
|
|
792
|
-
* it, so rendering never re-parses the sugar.
|
|
793
|
-
*/
|
|
471
|
+
/** One index entry, normalized, as every dialect and generator reads it. */
|
|
794
472
|
export type IndexColumnSchema = IndexColumnModifiers & {
|
|
795
473
|
/** A column name, or raw SQL when {@link expression} is set. */
|
|
796
474
|
readonly column: string;
|
|
797
475
|
/** Whether {@link column} is an expression to emit as-is rather than an identifier to quote. */
|
|
798
476
|
readonly expression?: boolean;
|
|
799
477
|
};
|
|
800
|
-
/**
|
|
801
|
-
* One index entry as entity metadata keeps it: a member, or an expression left unrendered until the
|
|
802
|
-
* schema is built, where the dialect and the naming strategy resolve what it references. Rendered, it
|
|
803
|
-
* is an {@link IndexColumnSchema}.
|
|
804
|
-
*/
|
|
478
|
+
/** One index entry as metadata keeps it: a member, or an expression rendered when the schema is built. */
|
|
805
479
|
export type EntityIndexColumn = IndexColumnModifiers & {
|
|
806
480
|
readonly column: string | QueryRaw;
|
|
807
481
|
};
|
|
808
|
-
/**
|
|
809
|
-
* An index as stored in entity metadata: authored options with the columns normalized.
|
|
810
|
-
*/
|
|
482
|
+
/** An index as metadata keeps it. */
|
|
811
483
|
export type EntityIndexMeta<E = object> = {
|
|
812
484
|
/** The indexed columns, in order. */
|
|
813
485
|
columns: readonly EntityIndexColumn[];
|
|
@@ -817,10 +489,7 @@ export type EntityIndexMeta<E = object> = {
|
|
|
817
489
|
unique?: boolean;
|
|
818
490
|
/** Partial index predicate, compiled when the schema is built. */
|
|
819
491
|
where?: EntityWhereMeta<E>;
|
|
820
|
-
/**
|
|
821
|
-
* Extra columns stored in the index but not part of its key, so a query reading only these is
|
|
822
|
-
* answered from the index alone. Postgres-wire only (`INCLUDE`).
|
|
823
|
-
*/
|
|
492
|
+
/** Columns stored in the index beyond its key, so a query reading only these needs no row. Postgres-wire only. */
|
|
824
493
|
include?: readonly string[];
|
|
825
494
|
} & VectorIndexOptions & IndexTypeOptions;
|
|
826
495
|
export type EntityMeta<E> = {
|
|
@@ -831,13 +500,7 @@ export type EntityMeta<E> = {
|
|
|
831
500
|
derivedName?: boolean;
|
|
832
501
|
/** Set only when the entity named one; unset defers to the pool where it is used. See `AbstractDialect.resolveSchema`. */
|
|
833
502
|
schema?: string;
|
|
834
|
-
/**
|
|
835
|
-
* Every key of the primary key, in declaration order. One unless the entity declares a composite.
|
|
836
|
-
*
|
|
837
|
-
* The only stored form: a single `id` beside it could only ever be right for a single-key entity,
|
|
838
|
-
* so every reader had to know whether it was safe. Asking whether *this* field is part of the key
|
|
839
|
-
* is `fields[key].isId`, which is O(1) and the source this list is derived from.
|
|
840
|
-
*/
|
|
503
|
+
/** Every column of the primary key, in declaration order. */
|
|
841
504
|
ids: readonly IdKey<E>[];
|
|
842
505
|
softDelete?: FieldKey<E>;
|
|
843
506
|
/** Named, default-on `$where` filters applied to every query unless bypassed. */
|
|
@@ -858,20 +521,14 @@ export type EntityMeta<E> = {
|
|
|
858
521
|
checks?: EntityCheckMeta<E>[];
|
|
859
522
|
/** Lifecycle hooks registered via @BeforeInsert, @AfterUpdate, etc. */
|
|
860
523
|
hooks?: Partial<Record<HookEvent, HookRegistration[]>>;
|
|
861
|
-
/**
|
|
862
|
-
* Bumped by every `define*` call, so anything derived from this metadata can tell that it changed.
|
|
863
|
-
* A content type registered at runtime keeps adding to an entity that has already been read.
|
|
864
|
-
*/
|
|
524
|
+
/** Bumped by every `define*` call, so what is derived from the metadata can tell it changed. */
|
|
865
525
|
revision: number;
|
|
866
526
|
/** The revision `getMeta` last finalized, which is what makes finalizing idempotent and re-entrant. */
|
|
867
527
|
processedAt?: number;
|
|
868
528
|
};
|
|
869
529
|
/**
|
|
870
|
-
* A table
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
* @example `{ where: { balance: { $gte: 0 } } }`
|
|
874
|
-
* @example `{ where: (wallet) => raw`${wallet.spent} <= ${wallet.balance}` }`
|
|
530
|
+
* A table's `CHECK`, `{ where: { balance: { $gte: 0 } } }`, or SQL off the refs,
|
|
531
|
+
* `{ where: (wallet) => raw`${wallet.spent} <= ${wallet.balance}` }`.
|
|
875
532
|
*/
|
|
876
533
|
export type CheckOptions<E = unknown> = {
|
|
877
534
|
/** Derived from the table and the constraint's position when absent. */
|
|
@@ -883,11 +540,7 @@ export type EntityCheckMeta<E = object> = {
|
|
|
883
540
|
readonly name?: string;
|
|
884
541
|
readonly where: EntityWhereMeta<E>;
|
|
885
542
|
};
|
|
886
|
-
/**
|
|
887
|
-
* An entity's members as the registry takes them, keyed by plain strings - what a decorator bag, an
|
|
888
|
-
* {@link EntityOptions} and a decorator bag both reduce to before anything is registered: a member
|
|
889
|
-
* decorator has no class to key against, so by then the keys are plain strings either way.
|
|
890
|
-
*/
|
|
543
|
+
/** An entity's members as the registry takes them, keyed by name: what decorators and `defineEntity` both reduce to. */
|
|
891
544
|
export type EntityMembers = {
|
|
892
545
|
readonly fields?: Readonly<Record<string, FieldOptions | undefined>>;
|
|
893
546
|
readonly relations?: Readonly<Record<string, RelationRegistration | undefined>>;
|
|
@@ -897,36 +550,21 @@ export type EntityMembers = {
|
|
|
897
550
|
type EntityFieldOptions<E, F extends keyof E = FieldKey<E>> = {
|
|
898
551
|
readonly [K in F]?: FieldOptionsFor<E[K], E>;
|
|
899
552
|
};
|
|
900
|
-
/**
|
|
901
|
-
* An entity's relations as `defineEntity` takes them. Keyed over every member rather than `RelationKey<E>`:
|
|
902
|
-
* inside the generic call, only a map over `keyof E` gives a `mappedBy` callback its contextual type. A
|
|
903
|
-
* field named here still fails, on its options, since its value is no entity.
|
|
904
|
-
*/
|
|
553
|
+
/** An entity's relations as `defineEntity` takes them, keyed over every member: only that types a `mappedBy` callback. */
|
|
905
554
|
type EntityRelationOptions<E> = {
|
|
906
555
|
readonly [K in keyof E]?: RelationOptionsFor<E[K], E>;
|
|
907
556
|
};
|
|
908
|
-
/**
|
|
909
|
-
* Configurable options for an entity (`@Entity()` / `defineEntity`).
|
|
910
|
-
*
|
|
911
|
-
* Optional `fields`, `relations`, `indexes`, and `hooks` register metadata in one call for
|
|
912
|
-
* decorator-free setups. Omit them when using `@Field` / `@ManyToOne` / etc.
|
|
913
|
-
*/
|
|
557
|
+
/** An entity's options, `@Entity()` or `defineEntity`; the members too where no decorator declares them. */
|
|
914
558
|
export type EntityOptions<E = unknown> = {
|
|
915
559
|
readonly name?: string;
|
|
916
|
-
/**
|
|
917
|
-
* The base to inherit fields, relations, hooks and filters from, for a class that cannot extend one
|
|
918
|
-
* (minted at runtime, or its base chosen from data): the merge `class Child extends Base` does, with
|
|
919
|
-
* the class's real base nearer, so it wins. Checked against whatever properties the entity declares,
|
|
920
|
-
* which a class behind an index signature has none of. See the Inheritance guide.
|
|
921
|
-
*/
|
|
560
|
+
/** A base to inherit members from, for a class that cannot extend it; its real base, if any, wins. See the Inheritance guide. */
|
|
922
561
|
readonly extends?: string extends keyof E ? Type<object> : Type<Partial<E>>;
|
|
923
|
-
/**
|
|
924
|
-
* The schema (in MySQL terms, database) this table lives in, pinning it whichever pool reads it;
|
|
925
|
-
* unset follows the pool's own. Not in `name`: a dotted `name` is rejected.
|
|
926
|
-
*/
|
|
562
|
+
/** The schema (a MySQL database) the table lives in; unset follows the pool's. */
|
|
927
563
|
readonly schema?: string;
|
|
928
564
|
/** Named, default-on `$where` filters (soft-delete is auto-registered from `@Field({ softDelete })`). */
|
|
929
|
-
readonly filters?: Record<string, FilterOptions<E
|
|
565
|
+
readonly filters?: Record<string, FilterOptions<E>> & {
|
|
566
|
+
readonly [SOFT_DELETE_FILTER]?: never;
|
|
567
|
+
};
|
|
930
568
|
/** Scalar fields; use `isId: true` on exactly one field for the primary key. */
|
|
931
569
|
readonly fields?: EntityFieldOptions<E>;
|
|
932
570
|
readonly relations?: EntityRelationOptions<E>;
|