uql-orm 0.66.0 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +3 -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
@@ -1,11 +1,28 @@
1
- /**
2
- * Allow to customize the name of the property that identifies an entity
3
- */
1
+ /** Brands the property an entity is identified by, where it is not `id`, `_id` or `uuid`. */
4
2
  export const idKey = Symbol('idKey');
5
- /**
6
- * The one filter name uql registers itself, from `@Field({ softDelete })`. Four ends have to agree on
7
- * it and none would fail if they drifted: the field that registers it, the decorator that reserves
8
- * the name against a user's own filter, the hard delete that switches it off, and the bypass check
9
- * that lets it through on an entity which never declared one.
10
- */
3
+ /** The filter `@Field({ softDelete })` registers, a name reserved against an entity's own filters. */
11
4
  export const SOFT_DELETE_FILTER = 'softDelete';
5
+ /** Every SQL column type a field may declare, by family: the unions below and `columnFamily` both read it. */
6
+ export const COLUMN_TYPES = {
7
+ numeric: [
8
+ 'int',
9
+ 'integer',
10
+ 'tinyint',
11
+ 'smallint',
12
+ 'bigint',
13
+ 'float',
14
+ 'float4',
15
+ 'float8',
16
+ 'double',
17
+ 'double precision',
18
+ 'decimal',
19
+ 'numeric',
20
+ 'real',
21
+ ],
22
+ string: ['char', 'varchar', 'text', 'uuid'],
23
+ date: ['date', 'time', 'datetime', 'timestamp', 'timestamptz'],
24
+ json: ['json', 'jsonb'],
25
+ blob: ['blob', 'bytea'],
26
+ boolean: ['bool', 'boolean'],
27
+ vector: ['vector', 'halfvec', 'sparsevec'],
28
+ };
@@ -13,13 +13,7 @@ export interface Logger {
13
13
  * @param duration - The time it took to execute the query in milliseconds.
14
14
  */
15
15
  logQuery?(query: string, values?: unknown[], duration?: number): void;
16
- /**
17
- * Logs a slow query.
18
- * @param query - The SQL query string.
19
- * @param values - The parameters passed to the query (already redacted to `undefined`
20
- * upstream, per `ExtraOptions.logValues`, when values shouldn't be logged).
21
- * @param duration - The time it took to execute the query in milliseconds.
22
- */
16
+ /** Logs a query that took longer than the threshold, its values `undefined` unless `logValues` is on. */
23
17
  logSlowQuery?(query: string, values?: unknown[], duration?: number): void;
24
18
  /**
25
19
  * Logs a warning.
@@ -50,11 +44,5 @@ export interface Logger {
50
44
  * Function type for backward compatibility with simple loggers.
51
45
  */
52
46
  export type LoggerFunction = (message: unknown, ...args: unknown[]) => void;
53
- /**
54
- * Options for configuring ORM logging.
55
- * - boolean: true to enable all logs with DefaultLogger, false to disable.
56
- * - LogLevel[]: enable specific log levels with DefaultLogger.
57
- * - Logger: use a custom logger implementation.
58
- * - LoggerFunction: use a custom function (backward compatibility).
59
- */
47
+ /** How logging is configured: on or off, the levels to log, or a logger of your own. */
60
48
  export type LoggingOptions = boolean | LogLevel[] | Logger | LoggerFunction;
@@ -94,21 +94,11 @@ export interface MigrationResult {
94
94
  readonly success: boolean;
95
95
  readonly error?: Error;
96
96
  }
97
- /**
98
- * A column as a statement describes one: {@link ColumnNode} with the engine's type spelling in place
99
- * of the canonical one, and without the graph links.
100
- *
101
- * Derived so a field the node gains reaches every path that renders a column. Listed field by field,
102
- * this dropped `enum` and then `generatedAs`, and a column added to an existing table arrived without
103
- * the constraint or the expression the entity declared.
104
- */
97
+ /** A column as a statement renders one: a {@link ColumnNode} with the engine's type spelling and no graph links. */
105
98
  export interface ColumnSchema extends Omit<ColumnNode, 'type' | 'table' | 'referencedBy' | 'references'> {
106
99
  /**
107
- * The engine's own type spelling, as introspection read it (`tinyint(1)`, `DATETIME`, `VARCHAR`).
108
- * Deliberately not a {@link CanonicalType}: the diff has to compare what the engine would *store*,
109
- * and several canonical types share one storage type per engine - an entity `boolean` is `TINYINT(1)`
110
- * on MySQL and `INTEGER` on SQLite. Comparing canonical categories instead reports an alteration on
111
- * every sync for those columns. Use `sqlToCanonical` to interpret it.
100
+ * The engine's own type spelling, `TINYINT(1)`, compared as stored: canonical types would differ where
101
+ * the engine stores them alike. `sqlToCanonical` reads it.
112
102
  */
113
103
  readonly type: string;
114
104
  /** Bounds introspection reports beside the type, where the engine states them separately. */
@@ -193,11 +183,8 @@ export interface SchemaDiff {
193
183
  readonly schema?: string;
194
184
  readonly type: 'create' | 'alter' | 'drop';
195
185
  /**
196
- * The key the table has against the key the entity declares, set only when they differ.
197
- *
198
- * Compared by columns, never by name: the engine named the existing one, so requiring a derived
199
- * name to match would rewrite the primary key of every table on the first migration after
200
- * upgrading. `fromName` is what the database reported, and the only name a `DROP` can use.
186
+ * The table's key against the entity's, where their columns differ; `fromName` is the name the
187
+ * database reported, which is what a `DROP` needs.
201
188
  */
202
189
  readonly primaryKey?: {
203
190
  readonly from: string[];
@@ -259,13 +246,7 @@ export interface DropSchemaOptions {
259
246
  * Interface for generating DDL statements from entity metadata
260
247
  */
261
248
  export interface SchemaGenerator {
262
- /**
263
- * The whole schema for `entities`: every table, then the foreign keys between them.
264
- *
265
- * There is deliberately no per-entity counterpart. One entity means an AST holding one table, so every
266
- * cross-entity foreign key has nothing to resolve against and is dropped: all three call sites that
267
- * used to work that way emitted schemas with no referential integrity.
268
- */
249
+ /** The whole schema for `entities`, tables then the foreign keys between them, which need every entity at once. */
269
250
  generateCreateSchema(entities: readonly Type<object>[], options?: CreateSchemaOptions): string[];
270
251
  /**
271
252
  * Every `DROP TABLE` for `entities`, dependents first. The inverse of {@link generateCreateSchema},
@@ -307,21 +288,11 @@ export interface SchemaGenerator {
307
288
  */
308
289
  compileIndexPredicate(where: EntityWhereMeta<object>, entity: Type<object>, indexName: string): string;
309
290
  /**
310
- * Compare an entity with a database table node and return the differences.
311
- *
312
- * `desiredAst` is the entity side, from {@link buildAST}, and must span every entity a foreign key
313
- * on this table points at: a relation whose target is absent resolves to nothing, so the constraint
314
- * reads as missing from both sides, which is a match and no statement. Defaults to this entity
315
- * alone, which is right only where it has no relations.
291
+ * An entity's differences from its table. `desiredAst`, from {@link buildAST}, has to span every entity
292
+ * a foreign key here points at, or those keys read as matching.
316
293
  */
317
294
  diffSchema(entity: Type<object>, currentTable: TableNode | undefined, desiredAst?: SchemaAST): SchemaDiff | undefined;
318
- /**
319
- * The entity side as an AST, to hand to every {@link diffSchema} of one run - building it per
320
- * entity instead is quadratic in the number of entities.
321
- *
322
- * Optional because not every generator compares one: MongoDB has no foreign keys and diffs only
323
- * indexes, so it neither implements this nor reads the argument.
324
- */
295
+ /** The entities as one AST, built once per run for every {@link diffSchema}. Absent on MongoDB, which diffs only indexes. */
325
296
  buildAST?(entities: readonly Type<object>[]): SchemaAST;
326
297
  /**
327
298
  * The table's key: {@link resolveTableAlias} behind {@link resolveSchema}, which is how a
@@ -16,11 +16,8 @@ export type IsolationLevel = 'read uncommitted' | 'read committed' | 'repeatable
16
16
  */
17
17
  export type TransactionOptions = {
18
18
  /**
19
- * Applies to this transaction only.
20
- *
21
- * @remarks MySQL and MariaDB set it as a statement of its own ahead of `START TRANSACTION`, so a
22
- * `START TRANSACTION` that then fails leaves the level applied to whatever the pooled connection
23
- * runs next. Set it per transaction that needs it rather than relying on what a connection carries.
19
+ * Applies to this transaction only. The MySQL family sets it ahead of `START TRANSACTION`, where a
20
+ * failed start leaves it on the connection: set it per transaction that needs it.
24
21
  */
25
22
  readonly isolationLevel?: IsolationLevel;
26
23
  };
@@ -32,53 +29,37 @@ export type DialectName = SqlDialectName | 'mongodb';
32
29
  * what makes a typo'd query key report as itself rather than as a missing `$entity`.
33
30
  */
34
31
  export interface Querier extends UniversalQuerier {
35
- /**
36
- * Find one record. Supports both entity-as-argument and entity-as-field patterns.
37
- */
32
+ /** Find one record, the entity passed first or as the query's `$entity`. */
38
33
  findOne<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(q: QueryOneProjected<E, S, V, X, P, C> & {
39
34
  $entity: Type<E>;
40
35
  }, opts?: QueryOptions): Promise<QueryFindResult<E, S, V, X, P, C> | undefined>;
41
36
  findOne<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(entity: Type<E>, q: QueryOneProjected<E, S, V, X, P, C>, opts?: QueryOptions): Promise<QueryFindResult<E, S, V, X, P, C> | undefined>;
42
- /**
43
- * Find many records. Supports both entity-as-argument and entity-as-field patterns.
44
- */
37
+ /** Find many records, the entity passed first or as the query's `$entity`. */
45
38
  findMany<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(q: QueryProjected<E, S, V, X, P, C> & {
46
39
  $entity: Type<E>;
47
40
  }, opts?: QueryOptions): Promise<QueryFindResult<E, S, V, X, P, C>[]>;
48
41
  findMany<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(entity: Type<E>, q: QueryProjected<E, S, V, X, P, C>, opts?: QueryOptions): Promise<QueryFindResult<E, S, V, X, P, C>[]>;
49
- /**
50
- * Stream records as an async iterable, in both patterns, each with the relations and counts
51
- * `findMany` reads. Fires no lifecycle hooks.
52
- */
42
+ /** Stream records with the relations and counts `findMany` reads, the entity passed first or as `$entity`. No hooks fire. */
53
43
  findManyStream<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(q: QueryProjected<E, S, V, X, P, C> & {
54
44
  $entity: Type<E>;
55
45
  }, opts?: QueryOptions): AsyncIterable<QueryFindResult<E, S, V, X, P, C>>;
56
46
  findManyStream<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(entity: Type<E>, q: QueryProjected<E, S, V, X, P, C>, opts?: QueryOptions): AsyncIterable<QueryFindResult<E, S, V, X, P, C>>;
57
- /**
58
- * Find many records and count. Supports both patterns.
59
- */
47
+ /** Find many records and count every match, the entity passed first or as the query's `$entity`. */
60
48
  findManyAndCount<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(q: QueryProjected<E, S, V, X, P, C> & {
61
49
  $entity: Type<E>;
62
50
  }, opts?: QueryOptions): Promise<[QueryFindResult<E, S, V, X, P, C>[], number]>;
63
51
  findManyAndCount<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(entity: Type<E>, q: QueryProjected<E, S, V, X, P, C>, opts?: QueryOptions): Promise<[QueryFindResult<E, S, V, X, P, C>[], number]>;
64
- /**
65
- * Count records. Supports both patterns.
66
- */
52
+ /** Count records, the entity passed first or as the query's `$entity`. */
67
53
  count<E extends object>(q: QueryPage<E> & {
68
54
  $entity: Type<E>;
69
55
  }, opts?: QueryOptions): Promise<number>;
70
56
  count<E extends object>(entity: Type<E>, q?: QueryPage<E>, opts?: QueryOptions): Promise<number>;
71
- /**
72
- * Whether anything matches. Supports both patterns.
73
- */
57
+ /** Whether anything matches, the entity passed first or as the query's `$entity`. */
74
58
  exists<E extends object>(q: QueryFilter<E> & {
75
59
  $entity: Type<E>;
76
60
  }, opts?: QueryOptions): Promise<boolean>;
77
61
  exists<E extends object>(entity: Type<E>, q?: QueryFilter<E>, opts?: QueryOptions): Promise<boolean>;
78
- /**
79
- * Delete many records (soft-deletes when the entity has a soft-delete field, else removes them).
80
- * Supports both entity-as-argument and entity-as-field patterns.
81
- */
62
+ /** Delete many records, the entity passed first or as `$entity`; soft-deletes where the entity has a soft-delete field. */
82
63
  deleteMany<E extends object>(q: QuerySearch<E> & {
83
64
  $entity: Type<E>;
84
65
  }, opts?: QueryOptions): Promise<number>;
@@ -13,25 +13,9 @@ export interface PoolRunOptions {
13
13
  readonly context?: UqlContext;
14
14
  }
15
15
  /**
16
- * Querier pool. Read the dialect id via `pool.dialect.dialectName` (see {@link AbstractDialect.dialectName}); queriers expose the same on `querier.dialect`.
17
- *
18
- * A pool is a {@link UniversalQuerier} too, so a function that runs queries takes that type and the
19
- * caller passes its own querier or the pool. `pool.op(...)` is exactly
20
- * `pool.withQuerier((querier) => querier.op(...))`, so two pool calls are two units of work; when they
21
- * must commit together, that is `transaction`.
22
- *
23
- * Acquiring per call is also what makes `Promise.all([pool.findMany(A, {}), pool.count(B, {})])` run on
24
- * separate connections, while the same calls inside one `withQuerier`/`transaction` share a pinned
25
- * connection and serialize. Single-connection backends (better-sqlite3, Bun sqlite, D1) stay correct
26
- * but always serialize.
27
- *
28
- * An enclosing `withContext` scopes pool calls (`security` filters apply), which is why they take no
29
- * per-call `context` option (unlike `withQuerier`/`transaction`).
30
- *
31
- * Pool calls take the entity-as-argument form only; the `{ $entity }` form needs a querier.
32
- *
33
- * @typeParam Q - Querier implementation returned from the pool.
34
- * @typeParam D - Concrete dialect class held by the pool.
16
+ * A pool of queriers, and a {@link UniversalQuerier} itself: each call runs on a querier of its own, so
17
+ * two calls are two units of work (use `transaction` to join them) and run in parallel where the backend
18
+ * has more than one connection. An enclosing `withContext` scopes its calls. The `{ $entity }` form needs a querier.
35
19
  */
36
20
  export interface QuerierPool<Q extends Querier = Querier, D extends AbstractDialect = AbstractDialect> extends UniversalQuerier {
37
21
  /**
@@ -66,13 +50,7 @@ export interface QuerierPool<Q extends Querier = Querier, D extends AbstractDial
66
50
  */
67
51
  end(): Promise<void>;
68
52
  }
69
- /**
70
- * SQL pool surface: adds the raw-SQL executors of {@link SqlQuerier} (`all`/`run`), with the same
71
- * connection-per-call semantics as the {@link QuerierPool} read helpers (see that doc for the
72
- * parallelism model and its single-connection caveat).
73
- *
74
- * Raw `all`/`run` bypass query generation, so they are **not** scoped by `security` filters/context.
75
- */
53
+ /** A SQL pool, adding raw `all`/`run`, which no `security` filter scopes. */
76
54
  export interface SqlQuerierPool<Q extends SqlQuerier = SqlQuerier, D extends AbstractSqlDialect = AbstractSqlDialect> extends QuerierPool<Q, D>, Pick<SqlQuerier, 'all' | 'run'> {
77
55
  }
78
56
  /**
@@ -73,15 +73,8 @@ export type QueryPopulateRelationOptions<V> = IsMany<V> extends true ? RelationQ
73
73
  $required?: boolean;
74
74
  };
75
75
  /**
76
- * Ambient per-request context (e.g. `{ tenantId, userId, roles }`) resolved by parameterized
77
- * filters. Set with `withContext(ctx, cb)`. It's an `interface` (not a type alias) so you can type
78
- * your keys once via declaration merging and get them typed wherever context is read:
79
- *
80
- * ```ts
81
- * declare module 'uql-orm' {
82
- * interface UqlContext { tenantId: number; userId: string }
83
- * }
84
- * ```
76
+ * The per-request context parameterized filters read, set with `withContext(ctx, cb)`. An interface,
77
+ * so its keys can be typed once: `declare module 'uql-orm' { interface UqlContext { tenantId: number } }`.
85
78
  */
86
79
  export interface UqlContext {
87
80
  [key: string]: unknown;
@@ -140,16 +133,9 @@ export type QuerySortByCount = {
140
133
  $count: QuerySortDirection;
141
134
  };
142
135
  /**
143
- * sort by map - supports field keys, JSON dot-notation paths (restricted to real JSON fields,
144
- * like `QueryWhere`), relation sort via nested objects, and vector similarity search on
145
- * `number[]` fields. `Vector` is what confines a vector search to the level the statement ranks:
146
- * the queried entity. A relation of it is joined in one row at a time, so there is nothing to rank
147
- * there - the SQL dialects throw, and MongoDB would quietly drop it, so this is its only guard.
148
- *
149
- * One mapped type over the three key sets rather than three intersected. The sets are disjoint - a
150
- * JSON path is dotted, and a field key cannot also be a relation key - and an assignability check
151
- * against an intersection is repeated per constituent, which made this the single most expensive
152
- * type in the package to check.
136
+ * A sort by fields, JSON paths, a to-one relation's fields, a to-many's `$count`, or a vector distance,
137
+ * which `Vector` confines to the queried entity. One mapped type over the key sets: an intersection is
138
+ * checked once per member, which made this the costliest type to check.
153
139
  */
154
140
  export type QuerySortMap<E, Vector extends boolean = true, K extends keyof E = FieldKey<E> | RelationKey<E>> = {
155
141
  [P in K]?: P extends RelationKey<E> ? IsMany<E[P]> extends true ? QuerySortByCount : QuerySortMap<RelationTarget<E[P]>, false> : Vector extends true ? NonNullable<E[P]> extends readonly number[] ? QuerySortValue : QuerySortDirection : QuerySortDirection;
@@ -229,25 +215,13 @@ export type Query<E> = {
229
215
  */
230
216
  $distinct?: boolean;
231
217
  /**
232
- * take a row-level lock on the rows this query returns (`SELECT ... FOR UPDATE`). Needs an open
233
- * transaction: outside one the statement commits and drops the lock before the caller can act on
234
- * the rows, so it is rejected rather than emitted. Locks only the queried entity, never anything
235
- * reached through `$populate`. SQL only; MongoDB and the SQLite family reject it.
236
- *
237
- * Declared here rather than on {@link QuerySearch}, which `update`/`delete` take: that placement
238
- * is what keeps the clause off those statements at the type level.
218
+ * Lock the rows this query returns, `SELECT ... FOR UPDATE`, inside an open transaction: outside one
219
+ * it is refused, since the lock would drop before the rows are used. SQL only, and not the SQLite family.
239
220
  */
240
221
  $lock?: QueryLock;
241
222
  /**
242
- * how many candidates an approximate-nearest-neighbour index explores before ranking, for a vector
243
- * search. Higher trades speed for recall; the default is whatever the engine's own is, which is
244
- * tuned for speed. Ignored where the search is exact (SQLite, libSQL and Turso scan every row) and
245
- * where the field carries no ANN index, since there is nothing to widen.
246
- *
247
- * The units are the index's, not UQL's, so the number is not comparable across index types: it
248
- * becomes `hnsw.ef_search` or `ivfflat.probes` on Postgres, `mhnsw_ef_search` on MariaDB, and
249
- * `numCandidates` on MongoDB Atlas. On Postgres it needs an open transaction, since a `SET LOCAL`
250
- * outside one applies to nothing.
223
+ * How many candidates an ANN index explores before ranking a vector search, in that index's own units
224
+ * (`hnsw.ef_search`, `numCandidates`...); ignored where the search is exact. Postgres needs a transaction.
251
225
  */
252
226
  $candidates?: number;
253
227
  /**
@@ -264,13 +238,8 @@ export type Query<E> = {
264
238
  $limit?: number;
265
239
  };
266
240
  /**
267
- * `Query`'s clauses grouped by the shape of their value - what a parser reading one off the wire and
268
- * a validator checking a relation's own query both need, and what each used to enumerate for itself.
269
- * Declared beside the type they describe so the two cannot drift, and `satisfies` fails the build
270
- * rather than the runtime if a clause is ever renamed.
271
- *
272
- * `$lock` is only in {@link QUERY_STATEMENT_CLAUSES}: neither a wire query nor a relation's query
273
- * accepts it.
241
+ * `Query`'s clauses grouped by the shape of their value, for the wire parser and the relation query
242
+ * check alike; `satisfies` keeps them in step with `Query`.
274
243
  */
275
244
  export declare const QUERY_OBJECT_CLAUSES: readonly ["$select", "$populate", "$exclude", "$where", "$sort"];
276
245
  /**
@@ -305,16 +274,8 @@ export type QueryOne<E> = Except<Query<E>, '$limit'>;
305
274
  */
306
275
  export type QueryUnique<E> = Pick<QueryOne<E>, '$select' | '$exclude' | '$populate' | '$where'>;
307
276
  /**
308
- * The clauses that decide a row's shape, captured from the query as written: the field names
309
- * `$select` and `$exclude` list, the value those maps carry (a falsy one subtracts instead of
310
- * selecting, as it does at runtime, and a widened map is how a projection that is not statically
311
- * known announces itself), and the relation names `$populate` lists.
312
- *
313
- * Each is captured as a *key set* rather than as the map itself, which is what keeps the checks
314
- * intact: TypeScript skips excess-property checking on a naked type parameter, so a captured map
315
- * would take a typo'd key without a word, while a captured key set makes that typo fail its own
316
- * `FieldKey<E>` / `RelationKey<E>` constraint. Every other clause - `$where`, `$sort`, and each
317
- * populated relation's own query - stays the concrete {@link Query} it is today.
277
+ * The clauses that shape a row, captured as key sets rather than maps: a naked type parameter skips
278
+ * excess-property checks, while a key set fails its own constraint on a typo.
318
279
  * @internal
319
280
  */
320
281
  type QueryProjection<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P extends RelationKey<E>, C extends RelationKey<E>> = {
@@ -332,10 +293,8 @@ export type QueryProjected<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P
332
293
  */
333
294
  export type QueryOneProjected<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P extends RelationKey<E>, C extends RelationKey<E> = never> = QueryOne<E> & QueryProjection<E, S, V, X, P, C>;
334
295
  /**
335
- * The keys a query comes back with, mirroring what the runtime projects: the fields a positive
336
- * `$select` names, or every field minus what a falsy `$select` entry or a truthy `$exclude` entry
337
- * subtracts, plus the relations `$populate` asked for. A positive `$select` wins outright, which is
338
- * why `$exclude` is only read on the branch where there is none.
296
+ * The keys a query comes back with, as the runtime projects them: a positive `$select`'s, or every
297
+ * field minus what `$select` or `$exclude` subtracts, plus the populated relations.
339
298
  * @internal
340
299
  */
341
300
  type ProjectedKeys<E, S, V, X, P> = ([V] extends [false | 0] ? Exclude<FieldKey<E>, S> : [S] extends [never] ? Exclude<FieldKey<E>, X> : S) | P;
@@ -345,16 +304,9 @@ type ProjectedKeys<E, S, V, X, P> = ([V] extends [false | 0] ? Exclude<FieldKey<
345
304
  */
346
305
  type IsUniform<V> = [V] extends [true | 1] ? true : [V] extends [false | 0] ? true : false;
347
306
  /**
348
- * A row of a find result: the entity narrowed to the fields the query projected, plus the relations
349
- * it populated - reading anything the query left out is a compile error rather than a silent
350
- * `undefined`. Modifiers are preserved, so an optional field stays optional. Name a projected row
351
- * with it where a helper has to take one: `QueryFindResult<User, 'id' | 'name'>`.
352
- *
353
- * The entity itself when the query projects nothing, when it uses a raw-projection array (columns,
354
- * not fields), and when the projection is not uniform - a `Query<E>` built elsewhere, or a map
355
- * mixing selected and subtracted entries, whose positive keys inference cannot recover. Relations
356
- * keep their declared type: narrowing them means capturing their queries as maps, which costs those
357
- * queries their own checks.
307
+ * A find's row: the entity narrowed to what the query projected and populated, so reading anything
308
+ * else does not compile. The entity itself where the projection is raw, absent or not uniform.
309
+ * @example `QueryFindResult<User, 'id' | 'name'>`
358
310
  */
359
311
  export type QueryFindResult<E, S extends FieldKey<E> = never, V = true, X extends FieldKey<E> = never, P extends RelationKey<E> = never, C extends RelationKey<E> = never> = QueryProjectedRow<E, S, V, X, P, C> & CountedRelations<C>;
360
312
  /**
@@ -379,13 +331,7 @@ type PopulatedToMany<E, P> = Extract<P, ToManyRelationKey<E>>;
379
331
  export type QueryStringified = {
380
332
  [K in keyof Query<unknown>]?: string;
381
333
  };
382
- /**
383
- * What upserting one row reports, against the entity rather than the driver.
384
- *
385
- * `created` is here and not on {@link QueryUpsertManyResult} because it is only ever knowable for a
386
- * single statement: a batch's `affectedRows` is a weighted sum on the dialects that report one at
387
- * all, and a batch of mixed shapes is several statements.
388
- */
334
+ /** What upserting one row reports. `created` is only knowable for a single statement, so a batch has none. */
389
335
  export type QueryUpsertOneResult<E> = {
390
336
  readonly id?: WrittenId<E>;
391
337
  readonly changes?: number;
@@ -4,13 +4,8 @@
4
4
  */
5
5
  export const COUNT_RESULT_KEY = '_count';
6
6
  /**
7
- * `Query`'s clauses grouped by the shape of their value - what a parser reading one off the wire and
8
- * a validator checking a relation's own query both need, and what each used to enumerate for itself.
9
- * Declared beside the type they describe so the two cannot drift, and `satisfies` fails the build
10
- * rather than the runtime if a clause is ever renamed.
11
- *
12
- * `$lock` is only in {@link QUERY_STATEMENT_CLAUSES}: neither a wire query nor a relation's query
13
- * accepts it.
7
+ * `Query`'s clauses grouped by the shape of their value, for the wire parser and the relation query
8
+ * check alike; `satisfies` keeps them in step with `Query`.
14
9
  */
15
10
  export const QUERY_OBJECT_CLAUSES = [
16
11
  '$select',
@@ -1,21 +1,8 @@
1
1
  import type { FieldKey } from './entity.js';
2
2
  import type { QueryPager, QuerySelect, QuerySortDirection } from './query.js';
3
3
  import type { QueryWhere, QueryWhereFieldValue } from './queryWhere.js';
4
- /**
5
- * Maps the offending keys to `never`, turning an excess key into a compile error; resolves to
6
- * `unknown` (an inert intersection member) when there are none. Needed because `$group`/`$select` are
7
- * captured as whole maps, and TypeScript skips excess-property checking on a naked type parameter.
8
- * A find captures key sets instead, where an unknown key fails the capture's own constraint.
9
- * @internal
10
- */
11
- type Reject<K> = [K] extends [never] ? unknown : Record<K & string, never>;
12
- /**
13
- * The columns `$group` actually names: keys whose value is literally `true`, not `keyof G`.
14
- * Wherever `G` cannot be inferred - `$group` omitted, hoisted, or annotated - it *is* its own
15
- * constraint, whose every value is `true | undefined`, and keying off values yields `never` there
16
- * rather than every field of the entity.
17
- * @internal
18
- */
4
+ import type { RejectKeys } from './utility.js';
5
+ /** The columns `$group` names by a literal `true`, so an uninferred `$group`, its own constraint, names none. */
19
6
  type GroupedKeys<G> = {
20
7
  [K in keyof G]: G[K] extends true ? K : never;
21
8
  }[keyof G];
@@ -95,15 +82,8 @@ type TotallingOp = OpsOf<'$sum' | '$avg' | '$sumDistinct' | '$avgDistinct'>;
95
82
  */
96
83
  type QueryAggregateArgMap<E> = Record<'$count', QueryAggregateArg<E>> & Record<TotallingOp, QueryFieldRef<E, NumericFieldKey<E>>> & Record<Exclude<AggregateOp, '$count' | TotallingOp>, QueryFieldRef<E>>;
97
84
  /**
98
- * An aggregate function applied to a field. Exactly one operation per entry (a second op is a
99
- * compile error). Only `$count` accepts `'*'` (i.e. `COUNT(*)`); every other op requires a field.
100
- * DISTINCT variants are flat ops (`$countDistinct`/`$sumDistinct`/`$avgDistinct`) taking a field.
101
- *
102
- * @example { $count: '*' } -> COUNT(*)
103
- * @example { $countDistinct: { id: true } } -> COUNT(DISTINCT "id")
104
- * @example { $sum: { amount: true } } -> SUM("amount")
105
- * @example { $sumDistinct: { amount: true } } -> SUM(DISTINCT "amount")
106
- * @example { $avg: { age: true } } -> AVG("age")
85
+ * An aggregate over one field, exactly one op per entry: `{ $sum: { amount: true } }` is `SUM("amount")`,
86
+ * `{ $countDistinct: { id: true } }` is `COUNT(DISTINCT "id")`, and only `$count` takes `'*'`.
107
87
  */
108
88
  export type QueryAggregateFn<E> = ExactlyOne<QueryAggregateArgMap<E>>;
109
89
  /** A single-key `{ [op]: unknown }` shape for each op in `Ops`, matched to infer that op's result. */
@@ -114,44 +94,17 @@ type FnWithOp<Ops extends string> = {
114
94
  }[Ops];
115
95
  /** Ops that count rows. Alone among the ops they answer `0`, never NULL, over an empty group. */
116
96
  type CountingOp = OpsOf<'$count' | '$countDistinct'>;
117
- /**
118
- * Group-by columns: an object mapping entity field keys to `true`, exactly like {@link QuerySelect}.
119
- * Typed against the entity, so a typo'd column is a compile error. Compute aggregate columns with
120
- * {@link QueryAggMap} (the `$select` key), not here.
121
- *
122
- * @example
123
- * ```ts
124
- * { status: true } // -> GROUP BY "status"
125
- * ```
126
- */
97
+ /** The columns to group by, `{ status: true }`, typed against the entity like `$select`. */
127
98
  export type QueryGroupMap<E> = Readonly<QuerySelect<E, FieldKey<E>, true>>;
128
- /**
129
- * Computed aggregate columns: an object mapping your chosen output alias to an aggregate function.
130
- * Alias names are free (you are naming new columns); the aggregated field reference inside each
131
- * function is typed against the entity.
132
- *
133
- * @example
134
- * ```ts
135
- * { count: { $count: '*' }, avgAge: { $avg: { age: true } } }
136
- * // -> COUNT(*) AS "count", AVG("age") AS "avgAge"
137
- * ```
138
- */
99
+ /** Computed columns by the alias each is read back under: `{ count: { $count: '*' }, avgAge: { $avg: { age: true } } }`. */
139
100
  export type QueryAggMap<E> = {
140
101
  readonly [alias: string]: QueryAggregateFn<E>;
141
102
  };
142
103
  /** The entity type of an aggregated field reference `F`, or `unknown` if it is not a known field. */
143
104
  type FieldValueType<E, F> = F extends keyof E ? E[F] : unknown;
144
105
  /**
145
- * Resolves a single computed column's type from its aggregate function: `$count` is always
146
- * `number`; `$sum`/`$avg` total to a `number` or to `null`; `$min`/`$max` keep the aggregated
147
- * field's own type, likewise or `null`.
148
- *
149
- * Everything but `$count` is nullable: an aggregate over zero rows is NULL, and an ungrouped one
150
- * still returns a row, so a `$where` matching nothing hands back a row of NULLs.
151
- *
152
- * `$sum`/`$avg` are exact to 2^53: Postgres widens a sum over BIGINT to NUMERIC, and decoding that
153
- * text to satisfy this `number` drops the digits past that bound. Use `raw()` for a wider total.
154
- * @internal
106
+ * A computed column's type: a count is a `number`; every other aggregate is `null` over no rows, a
107
+ * total a `number` (exact to 2^53, `raw` beyond) and `$min`/`$max` the field's own type.
155
108
  */
156
109
  type QueryAggregateFnResult<E, Fn> = Fn extends FnWithOp<CountingOp> ? number : Fn extends FnWithOp<TotallingOp> ? number | null : Fn extends {
157
110
  readonly $min: infer F;
@@ -165,40 +118,17 @@ type QueryAggregateFnResult<E, Fn> = Fn extends FnWithOp<CountingOp> ? number :
165
118
  type Simplify<T> = {
166
119
  [K in keyof T]: T[K];
167
120
  } & {};
168
- /**
169
- * Infers the aggregated result row: grouped columns (`G`) keep their entity type; computed columns
170
- * (`A`) resolve from their aggregate function via {@link QueryAggregateFnResult}.
171
- *
172
- * Grouped columns come from {@link GroupedKeys}, not `keyof G`, so a `$group` the compiler could
173
- * not read contributes none rather than all of them.
174
- */
121
+ /** An aggregate's row: each grouped column with its entity type, each computed one with its aggregate's. */
175
122
  export type QueryAggregateResult<E, G, A> = Simplify<Pick<E, GroupedKeys<G> & FieldKey<E>> & {
176
123
  -readonly [K in keyof A]: QueryAggregateFnResult<E, A[K]>;
177
124
  }>;
178
- /**
179
- * Erased runtime shape of a HAVING clause (alias -> comparison), consumed by the dialect builders.
180
- * Values are `unknown` because the SQL is built generically; the typed, per-column value checking
181
- * lives in {@link QueryAggregate.$having}.
182
- *
183
- * @example { count: { $gt: 5 } } -> HAVING COUNT(*) > 5
184
- */
125
+ /** A `HAVING` as the dialects read it, erased; {@link QueryAggregate.$having} is where it is typed. `{ count: { $gt: 5 } }` */
185
126
  export type QueryHavingMap = {
186
127
  readonly [alias: string]: QueryWhereFieldValue<unknown> | undefined;
187
128
  };
188
129
  /**
189
- * Aggregate query - separate from `Query<E>` to keep return types honest.
190
- * Used exclusively with `querier.aggregate()`.
191
- *
192
- * @example
193
- * ```ts
194
- * querier.aggregate(User, {
195
- * $where: { deletedAt: { $isNull: true } },
196
- * $group: { status: true },
197
- * $select: { count: { $count: '*' }, avgAge: { $avg: { age: true } } },
198
- * $having: { count: { $gt: 5 } },
199
- * $sort: { count: -1 },
200
- * });
201
- * ```
130
+ * An aggregate query, apart from `Query` so its row type stays honest:
131
+ * `aggregate(User, { $group: { status: true }, $select: { n: { $count: '*' } }, $having: { n: { $gt: 5 } } })`.
202
132
  */
203
133
  export type QueryAggregate<E, G extends QueryGroupMap<E> = QueryGroupMap<E>, A extends QueryAggMap<E> = QueryAggMap<E>> = {
204
134
  /**
@@ -207,29 +137,19 @@ export type QueryAggregate<E, G extends QueryGroupMap<E> = QueryGroupMap<E>, A e
207
137
  readonly $where?: QueryWhere<E>;
208
138
  /**
209
139
  * Columns to group by - `{ status: true }`, typed against the entity like `$select`. A computed
210
- * aggregate wrongly placed here (it belongs in `$select`) is rejected via {@link Reject}, since
140
+ * aggregate wrongly placed here (it belongs in `$select`) is rejected via {@link RejectKeys}, since
211
141
  * `$group` is captured as a generic and a bare generic skips excess-property checking. The captured
212
142
  * map meets its schema, {@link QueryGroupMap}, so each key keeps its link to the entity property.
213
143
  */
214
- readonly $group?: G & QueryGroupMap<E> & Reject<Exclude<keyof G, FieldKey<E>>>;
144
+ readonly $group?: G & QueryGroupMap<E> & RejectKeys<Exclude<keyof G, FieldKey<E>>>;
215
145
  /**
216
- * Computed aggregate columns - `{ count: { $count: '*' }, avgAge: { $avg: { age: true } } }`. The
217
- * captured map meets its schema over the same aliases, as `$group` does, so field keys stay linked
218
- * (a `Record<keyof A, ...>` spelling of the same type breaks the inference of `A`).
219
- *
220
- * An alias repeating a `$group` column is rejected: both would be emitted under that one name,
221
- * leaving the driver to keep whichever it read last.
146
+ * The computed columns by alias, the captured map meeting its schema so field keys stay linked. An alias
147
+ * repeating a `$group` column is refused, since both would come back under one name.
222
148
  */
223
149
  readonly $select?: A & {
224
150
  readonly [K in keyof A]: QueryAggregateFn<E>;
225
- } & Reject<NamedKeys<A> & GroupedKeys<G>>;
226
- /**
227
- * Post-aggregation filtering, applied after grouping (SQL `HAVING`, MongoDB post-group `$match`).
228
- * Keyed by the result columns (grouped columns + computed aliases), and each value is typed to that
229
- * column's result type - a `$min`/`$max` over a `Date` field compares against a `Date`, a grouped
230
- * column against its own type - reusing {@link QueryAggregateResult}. A name that is neither is a
231
- * compile error.
232
- */
151
+ } & RejectKeys<NamedKeys<A> & GroupedKeys<G>>;
152
+ /** Filtering after grouping, by a result column, each value typed as that column is. */
233
153
  readonly $having?: {
234
154
  readonly [K in keyof QueryAggregateResult<E, G, A>]?: QueryWhereFieldValue<QueryAggregateResult<E, G, A>[K]>;
235
155
  };
@@ -33,14 +33,7 @@ export declare class QueryRaw {
33
33
  constructor(value: QueryRawFn, alias?: string);
34
34
  /** The same expression under an alias, for a `$select` projection. */
35
35
  as(alias: string): QueryRaw;
36
- /**
37
- * Emit this expression into `opts.ctx`. How a raw value becomes SQL is the raw value's own
38
- * business, which is what lets a `raw` tagged template resolve an interpolated fragment without
39
- * the dialect having to expose a method for it.
40
- *
41
- * The alias is not emitted here: it names a `$select` projection, which writes it after the term,
42
- * and anywhere else it would land mid-expression.
43
- */
36
+ /** Writes the expression into `opts.ctx`. The alias is the projection's to write, after the term. */
44
37
  render(opts: QueryRawRenderOptions): void;
45
38
  }
46
39
  /**