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.
Files changed (193) hide show
  1. package/dist/browser/querier/httpQuerier.js +1 -8
  2. package/dist/browser/uql-browser.min.js.map +5 -5
  3. package/dist/bunSql/bunSql.util.d.ts +2 -6
  4. package/dist/bunSql/bunSql.util.js +2 -6
  5. package/dist/bunSql/bunSqlQuerier.d.ts +2 -5
  6. package/dist/bunSql/bunSqlQuerier.js +2 -5
  7. package/dist/cockroachdb/cockroachDialect.d.ts +4 -13
  8. package/dist/cockroachdb/cockroachDialect.js +4 -13
  9. package/dist/context/context.browser.js +2 -10
  10. package/dist/context/context.d.ts +4 -17
  11. package/dist/context/context.js +4 -17
  12. package/dist/dialect/abstractDialect.d.ts +4 -19
  13. package/dist/dialect/abstractDialect.js +2 -20
  14. package/dist/dialect/abstractSqlDialect.d.ts +47 -212
  15. package/dist/dialect/abstractSqlDialect.js +68 -222
  16. package/dist/dialect/aliases.d.ts +2 -12
  17. package/dist/dialect/aliases.js +4 -12
  18. package/dist/dialect/hydrateColumn.d.ts +2 -6
  19. package/dist/dialect/hydrateColumn.js +3 -13
  20. package/dist/dialect/jsonArrayElemMatchUtils.d.ts +1 -7
  21. package/dist/dialect/jsonArrayElemMatchUtils.js +1 -7
  22. package/dist/dialect/jsonSql.d.ts +6 -27
  23. package/dist/dialect/jsonSql.js +6 -27
  24. package/dist/dialect/mergeSqlDialect.d.ts +4 -22
  25. package/dist/dialect/mergeSqlDialect.js +4 -22
  26. package/dist/dialect/mysqlLikeSqlDialect.d.ts +11 -37
  27. package/dist/dialect/mysqlLikeSqlDialect.js +35 -51
  28. package/dist/dialect/pgLikeSqlDialect.d.ts +8 -22
  29. package/dist/dialect/pgLikeSqlDialect.js +36 -39
  30. package/dist/dialect/queryContext.d.ts +4 -22
  31. package/dist/dialect/queryContext.js +4 -22
  32. package/dist/dialect/queryJoins.d.ts +3 -12
  33. package/dist/dialect/queryJoins.js +3 -12
  34. package/dist/dialect/vectorCast.d.ts +2 -12
  35. package/dist/dialect/vectorCast.js +3 -19
  36. package/dist/dialect/vectorSqlDialect.d.ts +8 -38
  37. package/dist/dialect/vectorSqlDialect.js +7 -38
  38. package/dist/entity/decorator/bag.d.ts +6 -19
  39. package/dist/entity/decorator/bag.js +6 -22
  40. package/dist/entity/decorator/entity.d.ts +2 -7
  41. package/dist/entity/decorator/entity.js +2 -7
  42. package/dist/entity/decorator/members.d.ts +7 -30
  43. package/dist/entity/decorator/members.js +3 -12
  44. package/dist/entity/metadata/definition.d.ts +2 -18
  45. package/dist/entity/metadata/definition.js +6 -28
  46. package/dist/http/handler.d.ts +2 -14
  47. package/dist/index.d.ts +4 -1
  48. package/dist/index.js +3 -1
  49. package/dist/libsql/libsqlDialect.d.ts +1 -8
  50. package/dist/libsql/libsqlDialect.js +1 -8
  51. package/dist/maria/mariaDialect.d.ts +3 -5
  52. package/dist/maria/mariaDialect.js +5 -5
  53. package/dist/maria/mariadbQuerier.js +2 -2
  54. package/dist/maria/mariadbQuerierPool.js +1 -6
  55. package/dist/migrate/builder/migrationBuilder.js +3 -19
  56. package/dist/migrate/builder/splitSqlStatements.d.ts +1 -14
  57. package/dist/migrate/builder/splitSqlStatements.js +2 -22
  58. package/dist/migrate/builder/types.d.ts +2 -15
  59. package/dist/migrate/cli-config.js +2 -11
  60. package/dist/migrate/cli.js +2 -7
  61. package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -15
  62. package/dist/migrate/codegen/entityCodeGenerator.js +15 -44
  63. package/dist/migrate/codegen/fieldOptionsSource.d.ts +1 -8
  64. package/dist/migrate/codegen/fieldOptionsSource.js +3 -22
  65. package/dist/migrate/ddl/indexDdl.d.ts +2 -5
  66. package/dist/migrate/ddl/indexDdl.js +2 -5
  67. package/dist/migrate/ddl/pgIndexDdl.d.ts +3 -13
  68. package/dist/migrate/ddl/pgIndexDdl.js +3 -13
  69. package/dist/migrate/generator/definitionToNode.d.ts +2 -9
  70. package/dist/migrate/generator/definitionToNode.js +3 -17
  71. package/dist/migrate/generator/indexNodeToSchema.d.ts +2 -3
  72. package/dist/migrate/generator/indexNodeToSchema.js +2 -3
  73. package/dist/migrate/generator/mongoCommand.d.ts +1 -8
  74. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -8
  75. package/dist/migrate/generator/mongoSchemaGenerator.js +1 -8
  76. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +6 -26
  77. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +9 -41
  78. package/dist/migrate/introspection/baseSqlIntrospector.js +0 -1
  79. package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
  80. package/dist/migrate/introspection/mongoIntrospector.js +48 -46
  81. package/dist/migrate/introspection/mssqlIntrospector.d.ts +4 -4
  82. package/dist/migrate/introspection/mssqlIntrospector.js +18 -27
  83. package/dist/migrate/introspection/mysqlIntrospector.d.ts +7 -2
  84. package/dist/migrate/introspection/mysqlIntrospector.js +16 -14
  85. package/dist/migrate/introspection/postgresIntrospector.d.ts +24 -9
  86. package/dist/migrate/introspection/postgresIntrospector.js +68 -59
  87. package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -1
  88. package/dist/migrate/introspection/sqliteIntrospector.js +8 -10
  89. package/dist/migrate/migrator.d.ts +9 -53
  90. package/dist/migrate/migrator.js +32 -65
  91. package/dist/migrate/schemaGenerator.d.ts +16 -66
  92. package/dist/migrate/schemaGenerator.js +21 -74
  93. package/dist/mongo/mongoDialect.d.ts +21 -53
  94. package/dist/mongo/mongoDialect.js +25 -70
  95. package/dist/mongo/mongodbQuerier.d.ts +5 -8
  96. package/dist/mongo/mongodbQuerier.js +31 -65
  97. package/dist/mssql/mssqlDialect.d.ts +8 -34
  98. package/dist/mssql/mssqlDialect.js +37 -51
  99. package/dist/mssql/mssqlQuerier.d.ts +37 -4
  100. package/dist/mssql/mssqlQuerier.js +2 -2
  101. package/dist/mssql/mssqlWireTypes.d.ts +2 -14
  102. package/dist/mssql/mssqlWireTypes.js +2 -14
  103. package/dist/nestjs/uqlModule.js +2 -7
  104. package/dist/pglite/pgliteQuerier.d.ts +1 -9
  105. package/dist/pglite/pgliteQuerierPool.d.ts +4 -26
  106. package/dist/pglite/pgliteQuerierPool.js +3 -18
  107. package/dist/postgres/abstractPgQuerierPool.d.ts +1 -8
  108. package/dist/postgres/abstractPgQuerierPool.js +1 -8
  109. package/dist/postgres/pgNumericTypes.d.ts +3 -26
  110. package/dist/postgres/pgNumericTypes.js +3 -26
  111. package/dist/postgres/postgresDialect.d.ts +4 -10
  112. package/dist/postgres/postgresDialect.js +4 -10
  113. package/dist/querier/abstractQuerier.d.ts +35 -103
  114. package/dist/querier/abstractQuerier.js +105 -201
  115. package/dist/querier/abstractSharedHandleQuerierPool.d.ts +3 -17
  116. package/dist/querier/abstractSharedHandleQuerierPool.js +3 -17
  117. package/dist/querier/abstractSqlQuerier.d.ts +15 -36
  118. package/dist/querier/abstractSqlQuerier.js +49 -131
  119. package/dist/schema/canonicalType.d.ts +3 -21
  120. package/dist/schema/canonicalType.js +22 -67
  121. package/dist/schema/dependencyGraph.d.ts +2 -8
  122. package/dist/schema/dependencyGraph.js +2 -32
  123. package/dist/schema/index.d.ts +1 -25
  124. package/dist/schema/index.js +0 -26
  125. package/dist/schema/indexColumns.d.ts +1 -8
  126. package/dist/schema/indexColumns.js +1 -8
  127. package/dist/schema/indexDifferences.d.ts +7 -40
  128. package/dist/schema/indexDifferences.js +6 -31
  129. package/dist/schema/schemaAST.d.ts +8 -175
  130. package/dist/schema/schemaAST.js +13 -365
  131. package/dist/schema/schemaASTBuilder.d.ts +2 -24
  132. package/dist/schema/schemaASTBuilder.js +2 -30
  133. package/dist/schema/schemaASTDiffer.d.ts +6 -46
  134. package/dist/schema/schemaASTDiffer.js +8 -56
  135. package/dist/schema/types.d.ts +5 -61
  136. package/dist/schema/types.js +3 -6
  137. package/dist/sqlite/abstractSqliteQuerier.d.ts +1 -8
  138. package/dist/sqlite/localSqliteQuerierPool.d.ts +1 -7
  139. package/dist/sqlite/localSqliteQuerierPool.js +1 -7
  140. package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -7
  141. package/dist/sqlite/nodeSqliteQuerierPool.js +2 -7
  142. package/dist/sqlite/sqliteDialect.d.ts +5 -20
  143. package/dist/sqlite/sqliteDialect.js +29 -35
  144. package/dist/turso/tursoDialect.d.ts +4 -6
  145. package/dist/turso/tursoDialect.js +4 -6
  146. package/dist/turso/tursoLocalQuerierPool.d.ts +1 -7
  147. package/dist/turso/tursoLocalQuerierPool.js +1 -7
  148. package/dist/turso/tursoQuerierPool.d.ts +2 -6
  149. package/dist/turso/tursoQuerierPool.js +2 -6
  150. package/dist/turso/tursoSessionQuerier.d.ts +1 -7
  151. package/dist/turso/tursoSessionQuerier.js +1 -7
  152. package/dist/type/dialect.d.ts +42 -94
  153. package/dist/type/dialect.js +3 -13
  154. package/dist/type/entity.d.ts +163 -534
  155. package/dist/type/entity.js +26 -9
  156. package/dist/type/logger.d.ts +2 -14
  157. package/dist/type/migration.d.ts +9 -38
  158. package/dist/type/querier.d.ts +9 -28
  159. package/dist/type/querierPool.d.ts +4 -26
  160. package/dist/type/query.d.ts +19 -73
  161. package/dist/type/query.js +2 -7
  162. package/dist/type/queryAggregate.d.ts +18 -98
  163. package/dist/type/queryRaw.d.ts +1 -8
  164. package/dist/type/queryRaw.js +1 -8
  165. package/dist/type/queryWhere.d.ts +13 -61
  166. package/dist/type/universalQuerier.d.ts +18 -105
  167. package/dist/type/utility.d.ts +12 -24
  168. package/dist/type/vector.d.ts +8 -38
  169. package/dist/type/vector.js +1 -1
  170. package/dist/type/wire.d.ts +2 -5
  171. package/dist/util/dialect.util.d.ts +9 -27
  172. package/dist/util/dialect.util.js +10 -27
  173. package/dist/util/field.util.d.ts +2 -31
  174. package/dist/util/field.util.js +3 -43
  175. package/dist/util/fieldOption.util.d.ts +7 -15
  176. package/dist/util/fieldOption.util.js +1 -1
  177. package/dist/util/filters.util.d.ts +2 -5
  178. package/dist/util/filters.util.js +2 -5
  179. package/dist/util/logger.d.ts +2 -6
  180. package/dist/util/logger.js +2 -6
  181. package/dist/util/object.util.d.ts +2 -6
  182. package/dist/util/object.util.js +1 -5
  183. package/dist/util/raw.d.ts +3 -23
  184. package/dist/util/relationQuery.util.d.ts +3 -14
  185. package/dist/util/relationQuery.util.js +3 -14
  186. package/dist/util/rowKey.util.d.ts +2 -10
  187. package/dist/util/rowKey.util.js +2 -10
  188. package/dist/util/sql.util.d.ts +6 -37
  189. package/dist/util/sql.util.js +13 -73
  190. package/dist/util/sqlLiteral.d.ts +2 -13
  191. package/dist/util/sqlLiteral.js +8 -13
  192. package/dist/util/string.util.js +0 -2
  193. package/package.json +4 -4
@@ -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
- * Infers the field names of an entity.
26
- * Includes scalar fields, JSON fields, scalar arrays (e.g. vector `number[]`) and arrays of JSON.
27
- * The `-?` modifier strips optionality so the indexed access yields clean key unions
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
- /** Whether `T` is what a JSON column holds: the branded payload, or an array of them. */
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 one branded value a field value `V` holds: `Json<T>` for both `Json<T>` and `Json<T>[]`, via
61
- * `Unpacked`, a no-op for the non-array case.
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 keyof E]-?: IsJson<JsonElement<E[K]>> extends true ? K : never;
74
- }[Key<E>];
42
+ readonly [K in JsonColumnKey<E>]: IsMany<JsonPayload<E[K]>> extends true ? never : K;
43
+ }[JsonColumnKey<E>];
75
44
  /**
76
- * Recursively derives dot-notation key paths from a JSON payload type. Handles every shape at
77
- * entry: an untyped (`unknown`) payload accepts any suffix via a `string` pattern, scalars are
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
- * Extracts dot-notation paths from `Json<T>` values, handling both scalar JSON
87
- * and arrays of JSON (`Json<{foo: string}>[]`, a column holding a list of documents).
88
- * For `kind?: Json<{ public: number; theme: { color: string } }>`,
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
- * Operator shape accepted by JSON/JSONB fields in update payloads: `$set`/`$unset` target object
116
- * keys, `$push`/`$pull` target array elements. All four are type-safe with IDE autocomplete.
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 accepts, or `never` where the operators do not apply:
145
- * - Non-JSON fields. {@link UnwrapJson}'s {@link IsJson} guard avoids the non-discriminating bare
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
- * Accepted value for a single field in an update payload: the value itself, `null` where the column
155
- * is nullable, `QueryRaw` for a raw SQL expression (e.g. ``raw`NOW()` ``), and - for JSON object
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
- [K in F]?: UpdateFieldValue<E[K]>;
101
+ [P in F]?: E[P] | UpdateExtra<E[P]>;
180
102
  } & {
181
- [K in R]?: E[K];
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 for a single key, an object carrying every
223
- * key for a composite - which is also the `$where` map it reduces to, so both spellings are one type.
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 column's value for a single key, the key map for a composite.
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
- * Infers the values of the relations on an entity
248
- */
249
- export type RelationValue<E> = E[RelationKey<E>];
250
- /**
251
- * SQL numeric column types
252
- */
253
- export type NumericColumnType = 'int' | 'integer' | 'tinyint' | 'smallint' | 'bigint' | 'float' | 'float4' | 'float8' | 'double' | 'double precision' | 'decimal' | 'numeric' | 'real';
254
- /**
255
- * SQL string column types
256
- */
257
- export type StringColumnType = 'char' | 'varchar' | 'text' | 'uuid';
258
- /**
259
- * SQL date/time column types
260
- */
261
- export type DateColumnType = 'date' | 'time' | 'datetime' | 'timestamp' | 'timestamptz';
262
- /**
263
- * SQL JSON column types
264
- */
265
- export type JsonColumnType = 'json' | 'jsonb';
266
- /**
267
- * SQL binary/blob column types
268
- */
269
- export type BlobColumnType = 'blob' | 'bytea';
270
- /**
271
- * SQL boolean column types
272
- */
273
- export type BooleanColumnType = 'bool' | 'boolean';
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} values legal for a field declared as `V`.
288
- *
289
- * This is what makes an explicit `type` an improvement over the reflected one it replaces: the
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
- * Referential action for the generated foreign key. Delete side only: `onUpdate` below already means
343
- * a value callback. Reach for `@ManyToOne({ onDelete, onUpdate })` when the update side matters too, or
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, enforced by the database as well as by TypeScript.
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, rather than a value the caller writes. Never part of an
364
- * insert or update either way.
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
- * Marks this field as the soft-delete field. Its presence makes the entity "soft deletable":
385
- * a `delete` becomes an `UPDATE` that stamps this field instead of removing the row, and reads
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: the value it holds, except on a JSON column, which defaults with the
440
- * SQL literal it stores (`defaultValue: '{}'`) whatever the property's TypeScript type is. Opening
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 types a field may be declared as, given the `type` it registers: the inverse of
451
- * {@link TypeFor}.
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`, with `type` required and checked by
463
- * {@link TypeFor}.
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 field declared as `V`: what each cardinality's decorator takes,
484
- * keyed on the `cardinality` written and restricted to the ones the field's shape holds. A key, not a
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
- * A deferred reference to an entity class, e.g. `() => Company`.
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
- * Referential actions for the generated foreign key, letting the database cascade instead of the ORM's
525
- * `cascade` (pick one; declaring both leaves the FK nothing to do). Read from the owning side
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: the foreign key a to-one declares, `(post) => post.authorId`, which points at the
541
- * target's primary key, or pairs where no key fits, `(order, customer) => [{ local: order.customerCode,
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, whichever entity it targets: `mappedBy` and `references` read
577
- * off their key maps down to the names they give. `references` stays unset, or the one column a to-one
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
- * Index type paired with the metric it needs. `distance` is required for {@link VectorIndexType}
655
- * because omitting it changes the DDL semantics silently: MariaDB's `DISTANCE=` defaults to
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` for an expression, or an object when
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<JsonColumnPayload<E[K]>>;
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 one path inside a JSON column, compiled by the same code a `$where` on that path is:
745
- * an expression index is matched by its own text, so an index spelled even slightly differently is
746
- * one the planner never reaches for.
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: one key per *element* of the JSON array at `path` (the column itself
765
- * when there is none), which is the only index `$all`/`$elemMatch` containment can use. `type` is
766
- * the element's, and a string or binary one needs a `length`, since the cast is what sizes the key.
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-level `CHECK`: a predicate over the entity's fields, or SQL reading them off refs. A value in
878
- * either is written as its literal, since DDL has no placeholder to bind one into.
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>> & {