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