uql-orm 0.18.0 → 0.20.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 (149) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +3 -3
  3. package/dist/browser/querier/httpQuerier.d.ts +10 -10
  4. package/dist/browser/querier/httpQuerier.d.ts.map +1 -1
  5. package/dist/browser/querier/httpQuerier.js.map +1 -1
  6. package/dist/browser/type/clientQuerier.d.ts +9 -9
  7. package/dist/browser/type/clientQuerier.d.ts.map +1 -1
  8. package/dist/browser/uql-browser.min.js +2 -2
  9. package/dist/browser/uql-browser.min.js.map +4 -4
  10. package/dist/bunSql/bunSqlCockroachDialect.d.ts +1 -1
  11. package/dist/bunSql/bunSqlCockroachDialect.js +1 -1
  12. package/dist/dialect/abstractSqlDialect.d.ts +113 -51
  13. package/dist/dialect/abstractSqlDialect.d.ts.map +1 -1
  14. package/dist/dialect/abstractSqlDialect.js +186 -123
  15. package/dist/dialect/abstractSqlDialect.js.map +1 -1
  16. package/dist/dialect/jsonArrayElemMatchUtils.d.ts +5 -6
  17. package/dist/dialect/jsonArrayElemMatchUtils.d.ts.map +1 -1
  18. package/dist/dialect/jsonArrayElemMatchUtils.js +9 -19
  19. package/dist/dialect/jsonArrayElemMatchUtils.js.map +1 -1
  20. package/dist/dialect/jsonSql.d.ts +24 -0
  21. package/dist/dialect/jsonSql.d.ts.map +1 -0
  22. package/dist/dialect/jsonSql.js +37 -0
  23. package/dist/dialect/jsonSql.js.map +1 -0
  24. package/dist/dialect/mysqlLikeSqlDialect.d.ts +35 -3
  25. package/dist/dialect/mysqlLikeSqlDialect.d.ts.map +1 -1
  26. package/dist/dialect/mysqlLikeSqlDialect.js +64 -18
  27. package/dist/dialect/mysqlLikeSqlDialect.js.map +1 -1
  28. package/dist/dialect/pgLikeSqlDialect.d.ts +24 -5
  29. package/dist/dialect/pgLikeSqlDialect.d.ts.map +1 -1
  30. package/dist/dialect/pgLikeSqlDialect.js +50 -37
  31. package/dist/dialect/pgLikeSqlDialect.js.map +1 -1
  32. package/dist/dialect/vectorSqlDialect.d.ts +54 -0
  33. package/dist/dialect/vectorSqlDialect.d.ts.map +1 -0
  34. package/dist/dialect/vectorSqlDialect.js +73 -0
  35. package/dist/dialect/vectorSqlDialect.js.map +1 -0
  36. package/dist/entity/decorator/index-decorator.d.ts +6 -13
  37. package/dist/entity/decorator/index-decorator.d.ts.map +1 -1
  38. package/dist/entity/decorator/index-decorator.js.map +1 -1
  39. package/dist/maria/mariaDialect.d.ts +15 -3
  40. package/dist/maria/mariaDialect.d.ts.map +1 -1
  41. package/dist/maria/mariaDialect.js +25 -12
  42. package/dist/maria/mariaDialect.js.map +1 -1
  43. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -1
  44. package/dist/migrate/generator/mongoSchemaGenerator.d.ts.map +1 -1
  45. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +2 -1
  46. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts.map +1 -1
  47. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +5 -0
  48. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js.map +1 -1
  49. package/dist/migrate/introspection/baseSqlIntrospector.js +1 -1
  50. package/dist/migrate/introspection/baseSqlIntrospector.js.map +1 -1
  51. package/dist/migrate/introspection/mysqlIntrospector.d.ts +1 -3
  52. package/dist/migrate/introspection/mysqlIntrospector.d.ts.map +1 -1
  53. package/dist/migrate/introspection/mysqlIntrospector.js +0 -5
  54. package/dist/migrate/introspection/mysqlIntrospector.js.map +1 -1
  55. package/dist/migrate/introspection/postgresIntrospector.d.ts +1 -3
  56. package/dist/migrate/introspection/postgresIntrospector.d.ts.map +1 -1
  57. package/dist/migrate/introspection/postgresIntrospector.js +0 -5
  58. package/dist/migrate/introspection/postgresIntrospector.js.map +1 -1
  59. package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -3
  60. package/dist/migrate/introspection/sqliteIntrospector.d.ts.map +1 -1
  61. package/dist/migrate/introspection/sqliteIntrospector.js +0 -5
  62. package/dist/migrate/introspection/sqliteIntrospector.js.map +1 -1
  63. package/dist/migrate/schemaGenerator.js +1 -1
  64. package/dist/migrate/schemaGenerator.js.map +1 -1
  65. package/dist/mongo/mongoDialect.d.ts +29 -8
  66. package/dist/mongo/mongoDialect.d.ts.map +1 -1
  67. package/dist/mongo/mongoDialect.js +101 -12
  68. package/dist/mongo/mongoDialect.js.map +1 -1
  69. package/dist/mongo/mongodbQuerier.d.ts +2 -2
  70. package/dist/mongo/mongodbQuerier.d.ts.map +1 -1
  71. package/dist/mongo/mongodbQuerier.js +5 -4
  72. package/dist/mongo/mongodbQuerier.js.map +1 -1
  73. package/dist/postgres/postgresWireDriverCapabilities.d.ts +1 -1
  74. package/dist/postgres/postgresWireDriverCapabilities.js +1 -1
  75. package/dist/querier/abstractQuerier.d.ts +2 -2
  76. package/dist/querier/abstractQuerier.d.ts.map +1 -1
  77. package/dist/querier/abstractQuerier.js +6 -5
  78. package/dist/querier/abstractQuerier.js.map +1 -1
  79. package/dist/querier/abstractQuerierPool.d.ts +1 -1
  80. package/dist/querier/abstractQuerierPool.d.ts.map +1 -1
  81. package/dist/querier/abstractQuerierPool.js.map +1 -1
  82. package/dist/querier/abstractSqlQuerier.d.ts +2 -2
  83. package/dist/querier/abstractSqlQuerier.d.ts.map +1 -1
  84. package/dist/querier/abstractSqlQuerier.js.map +1 -1
  85. package/dist/querier/decorator/injectQuerier.d.ts +2 -2
  86. package/dist/querier/decorator/injectQuerier.d.ts.map +1 -1
  87. package/dist/querier/decorator/injectQuerier.js.map +1 -1
  88. package/dist/schema/schemaAST.d.ts.map +1 -1
  89. package/dist/schema/schemaAST.js +7 -19
  90. package/dist/schema/schemaAST.js.map +1 -1
  91. package/dist/schema/types.d.ts +1 -1
  92. package/dist/sqlite/sqliteDialect.d.ts +29 -8
  93. package/dist/sqlite/sqliteDialect.d.ts.map +1 -1
  94. package/dist/sqlite/sqliteDialect.js +59 -74
  95. package/dist/sqlite/sqliteDialect.js.map +1 -1
  96. package/dist/type/dialect.d.ts +192 -0
  97. package/dist/type/dialect.d.ts.map +1 -0
  98. package/dist/type/dialect.js +2 -0
  99. package/dist/type/dialect.js.map +1 -0
  100. package/dist/type/entity.d.ts +97 -45
  101. package/dist/type/entity.d.ts.map +1 -1
  102. package/dist/type/entity.js.map +1 -1
  103. package/dist/type/index.d.ts +5 -0
  104. package/dist/type/index.d.ts.map +1 -1
  105. package/dist/type/index.js +5 -0
  106. package/dist/type/index.js.map +1 -1
  107. package/dist/type/querier.d.ts +4 -3
  108. package/dist/type/querier.d.ts.map +1 -1
  109. package/dist/type/querier.js +1 -1
  110. package/dist/type/querier.js.map +1 -1
  111. package/dist/type/query.d.ts +19 -668
  112. package/dist/type/query.d.ts.map +1 -1
  113. package/dist/type/query.js +1 -51
  114. package/dist/type/query.js.map +1 -1
  115. package/dist/type/queryAggregate.d.ts +191 -0
  116. package/dist/type/queryAggregate.d.ts.map +1 -0
  117. package/dist/type/queryAggregate.js +39 -0
  118. package/dist/type/queryAggregate.js.map +1 -0
  119. package/dist/type/queryRaw.d.ts +35 -0
  120. package/dist/type/queryRaw.d.ts.map +1 -0
  121. package/dist/type/queryRaw.js +11 -0
  122. package/dist/type/queryRaw.js.map +1 -0
  123. package/dist/type/queryWhere.d.ts +271 -0
  124. package/dist/type/queryWhere.d.ts.map +1 -0
  125. package/dist/type/queryWhere.js +2 -0
  126. package/dist/type/queryWhere.js.map +1 -0
  127. package/dist/type/universalQuerier.d.ts +3 -2
  128. package/dist/type/universalQuerier.d.ts.map +1 -1
  129. package/dist/type/utility.d.ts +16 -2
  130. package/dist/type/utility.d.ts.map +1 -1
  131. package/dist/type/vector.d.ts +55 -0
  132. package/dist/type/vector.d.ts.map +1 -0
  133. package/dist/type/vector.js +2 -0
  134. package/dist/type/vector.js.map +1 -0
  135. package/dist/util/ansiSqlLiteral.d.ts +2 -0
  136. package/dist/util/ansiSqlLiteral.d.ts.map +1 -1
  137. package/dist/util/ansiSqlLiteral.js +5 -1
  138. package/dist/util/ansiSqlLiteral.js.map +1 -1
  139. package/dist/util/dialect.util.d.ts +14 -2
  140. package/dist/util/dialect.util.d.ts.map +1 -1
  141. package/dist/util/dialect.util.js +23 -0
  142. package/dist/util/dialect.util.js.map +1 -1
  143. package/dist/util/object.util.d.ts +12 -1
  144. package/dist/util/object.util.d.ts.map +1 -1
  145. package/dist/util/object.util.js +18 -0
  146. package/dist/util/object.util.js.map +1 -1
  147. package/dist/util/relationQuery.util.js +1 -1
  148. package/dist/util/relationQuery.util.js.map +1 -1
  149. package/package.json +2 -2
@@ -1,5 +1,8 @@
1
- import type { FieldKey, IdValue, JsonFieldPaths, RelationKey, UpdatePayload } from './entity.js';
2
- import type { BooleanLike, ExpandScalar, PrimaryKey, Scalar, Type, Unpacked } from './utility.js';
1
+ import type { FieldKey, JsonFieldPaths, RelationKey } from './entity.js';
2
+ import type { QueryRaw } from './queryRaw.js';
3
+ import type { QueryWhere } from './queryWhere.js';
4
+ import type { BooleanLike, PrimaryKey, Unpacked } from './utility.js';
5
+ import type { QueryVectorSearch } from './vector.js';
3
6
  export type QueryOptions = {
4
7
  /**
5
8
  * Toggle named entity filters for this query. `false` disables all filters;
@@ -37,13 +40,16 @@ export type QuerySelectOptions = {
37
40
  export type QuerySelect<E> = {
38
41
  [K in FieldKey<E>]?: BooleanLike;
39
42
  };
43
+ /**
44
+ * Accepted `$select` value: a field map, or raw SQL projections built with `raw()`
45
+ * (e.g. `[raw('*'), raw('LOG10(points)', 'score')]`). The raw form is SQL-only.
46
+ */
47
+ export type QuerySelectValue<E> = QuerySelect<E> | readonly QueryRaw[];
40
48
  /**
41
49
  * Fields to exclude from the query result - `{ name: true }` blacklists fields.
42
50
  * Mutually exclusive with positive field selections in `$select`.
43
51
  */
44
- export type QueryExclude<E> = {
45
- [K in FieldKey<E>]?: BooleanLike;
46
- };
52
+ export type QueryExclude<E> = QuerySelect<E>;
47
53
  /**
48
54
  * relation population map.
49
55
  */
@@ -62,216 +68,6 @@ export type QueryConflictPaths<E> = {
62
68
  export type QueryPopulateRelationOptions<E> = (E extends unknown[] ? Query<Unpacked<E>> : QueryUnique<Unpacked<E>>) & {
63
69
  $required?: boolean;
64
70
  };
65
- /**
66
- * options for full-text-search operator.
67
- */
68
- export type QueryTextSearchOptions<E> = {
69
- /**
70
- * text to search for.
71
- */
72
- $value: string;
73
- /**
74
- * list of fields to search on.
75
- */
76
- $fields?: FieldKey<E>[];
77
- };
78
- /**
79
- * comparison by fields.
80
- */
81
- export type QueryWhereFieldMap<E> = {
82
- [K in FieldKey<E>]?: QueryWhereFieldValue<E[K]>;
83
- };
84
- /**
85
- * Field comparison, JSONB dot-path access, and relation filtering - all fully typed.
86
- * Uses both a mapped type (IDE autocompletion) and a pattern index signature (EPC acceptance)
87
- * for dot-paths because TypeScript's excess property checking cannot resolve recursive
88
- * conditional types in mapped type key positions.
89
- */
90
- export type QueryWhereMap<E> = QueryWhereFieldMap<E> & QueryWhereRootOperator<E> & {
91
- [P in JsonFieldPaths<E>]?: QueryWhereFieldValue<unknown>;
92
- } & {
93
- [key: `${string}.${string}`]: QueryWhereFieldValue<unknown> | undefined;
94
- } & {
95
- [K in RelationKey<E>]?: QueryWhereMap<Unpacked<NonNullable<E[K]>>>;
96
- };
97
- export type QueryWhereRootOperator<E> = {
98
- /**
99
- * joins query clauses with a logical `AND`, returns records that match all the clauses.
100
- */
101
- $and?: QueryWhereArray<E>;
102
- /**
103
- * joins query clauses with a logical `OR`, returns records that match any of the clauses.
104
- */
105
- $or?: QueryWhereArray<E>;
106
- /**
107
- * joins query clauses with a logical `AND`, returns records that do not match all the clauses.
108
- * @see {@link QueryWhereFieldOperatorMap.$not} for per-field negation.
109
- */
110
- $not?: QueryWhereArray<E>;
111
- /**
112
- * joins query clauses with a logical `OR`, returns records that do not match any of the clauses.
113
- */
114
- $nor?: QueryWhereArray<E>;
115
- /**
116
- * whether the specified fields match against a full-text search of the given string.
117
- */
118
- $text?: QueryTextSearchOptions<E>;
119
- /**
120
- * whether the record exists in the given sub-query.
121
- */
122
- $exists?: QueryRaw;
123
- /**
124
- * whether the record does not exists in the given sub-query.
125
- */
126
- $nexists?: QueryRaw;
127
- };
128
- /**
129
- * Per-field negation operators. `Pick`'s constraint ties this back to
130
- * {@link QueryWhereRootOperator} so a rename there breaks this union at compile time.
131
- */
132
- export type QueryNegateOp = keyof Pick<QueryWhereRootOperator<unknown>, '$not' | '$nor'>;
133
- /**
134
- * Comparison operators accepted by `$size` for range queries: {@link QueryHavingOp} plus `$between`.
135
- * Strips `null` from picked operators since array size is always numeric.
136
- */
137
- export type QuerySizeComparisonOps = {
138
- [K in QueryHavingOp | '$between']?: NonNullable<QueryWhereFieldOperatorMap<number>[K]>;
139
- };
140
- export type QueryWhereFieldOperatorMap<T> = {
141
- /**
142
- * whether a value is equal to the given value.
143
- */
144
- $eq?: ExpandScalar<T> | null;
145
- /**
146
- * whether a value is not equal to the given value.
147
- */
148
- $ne?: ExpandScalar<T> | null;
149
- /**
150
- * negates the given comparison for a single field.
151
- * @see {@link QueryWhereRootOperator.$not} for root-level clause negation.
152
- */
153
- $not?: QueryWhereFieldValue<T>;
154
- /**
155
- * whether a value is less than the given value.
156
- */
157
- $lt?: ExpandScalar<T>;
158
- /**
159
- * whether a value is less than or equal to the given value.
160
- */
161
- $lte?: ExpandScalar<T>;
162
- /**
163
- * whether a value is greater than the given value.
164
- */
165
- $gt?: ExpandScalar<T>;
166
- /**
167
- * whether a value is greater than or equal to the given value.
168
- */
169
- $gte?: ExpandScalar<T>;
170
- /**
171
- * whether a value is between two values (inclusive). Shorthand for $gte + $lte.
172
- * @example { age: { $between: [18, 65] } }
173
- */
174
- $between?: [ExpandScalar<T>, ExpandScalar<T>];
175
- /**
176
- * whether a string begins with the given string (case sensitive).
177
- */
178
- $startsWith?: string;
179
- /**
180
- * whether a string begins with the given string (case insensitive).
181
- */
182
- $istartsWith?: string;
183
- /**
184
- * whether a string ends with the given string (case sensitive).
185
- */
186
- $endsWith?: string;
187
- /**
188
- * whether a string ends with the given string (case insensitive).
189
- */
190
- $iendsWith?: string;
191
- /**
192
- * whether a string is contained within the given string (case sensitive).
193
- */
194
- $includes?: string;
195
- /**
196
- * whether a string is contained within the given string (case insensitive).
197
- */
198
- $iincludes?: string;
199
- /**
200
- * whether a string fulfills the given pattern (case sensitive).
201
- */
202
- $like?: string;
203
- /**
204
- * whether a string fulfills the given pattern (case insensitive).
205
- */
206
- $ilike?: string;
207
- /**
208
- * whether a string matches the given regular expression.
209
- */
210
- $regex?: string;
211
- /**
212
- * whether a value matches any of the given values.
213
- */
214
- $in?: ExpandScalar<T>[];
215
- /**
216
- * whether a value does not match any of the given values.
217
- */
218
- $nin?: ExpandScalar<T>[];
219
- /**
220
- * whether a value is null.
221
- * @example { deletedAt: { $isNull: true } }
222
- */
223
- $isNull?: boolean;
224
- /**
225
- * whether a value is not null.
226
- * @example { email: { $isNotNull: true } }
227
- */
228
- $isNotNull?: boolean;
229
- /**
230
- * whether an array contains all the specified values.
231
- * @example { tags: { $all: ['typescript', 'orm'] } }
232
- */
233
- $all?: T extends (infer U)[] ? ExpandScalar<U>[] : unknown[];
234
- /**
235
- * whether an array has the specified length.
236
- * Accepts a number for exact match, or a comparison operator object for range queries.
237
- * @example { roles: { $size: 3 } }
238
- * @example { roles: { $size: { $gte: 2 } } }
239
- * @example { roles: { $size: { $gt: 0, $lte: 5 } } }
240
- */
241
- $size?: number | QuerySizeComparisonOps;
242
- /**
243
- * whether an array contains at least one element matching all specified conditions.
244
- * @example { addresses: { $elemMatch: { city: 'NYC', zip: '10001' } } }
245
- */
246
- $elemMatch?: T extends (infer U)[] ? Partial<U> : Record<string, QueryWhereFieldValue<unknown>>;
247
- };
248
- /**
249
- * Simple relational comparison operators. `Pick`'s constraint ties this back to
250
- * {@link QueryWhereFieldOperatorMap} so a rename there breaks this union at compile time.
251
- */
252
- export type QueryCompareOp = keyof Pick<QueryWhereFieldOperatorMap<unknown>, '$gt' | '$gte' | '$lt' | '$lte'>;
253
- /**
254
- * String pattern-matching operators. `Pick`'s constraint ties this back to
255
- * {@link QueryWhereFieldOperatorMap} so a rename there breaks this union at compile time.
256
- */
257
- export type QueryLikeOp = keyof Pick<QueryWhereFieldOperatorMap<unknown>, '$startsWith' | '$istartsWith' | '$endsWith' | '$iendsWith' | '$includes' | '$iincludes' | '$like' | '$ilike'>;
258
- /**
259
- * `HAVING` clause operators: {@link QueryCompareOp} plus `$eq`/`$ne`. `Pick`'s constraint ties the
260
- * latter back to {@link QueryWhereFieldOperatorMap} so a rename there breaks this union at compile time.
261
- */
262
- export type QueryHavingOp = QueryCompareOp | keyof Pick<QueryWhereFieldOperatorMap<number>, '$eq' | '$ne'>;
263
- /**
264
- * Value for a field comparison.
265
- */
266
- export type QueryWhereFieldValue<T> = T | T[] | QueryWhereFieldOperatorMap<T> | QueryRaw;
267
- /**
268
- * query filter array - used for `$and`, `$or`, `$not`, `$nor` operators.
269
- */
270
- export type QueryWhereArray<E> = (QueryWhereMap<E> | QueryRaw)[];
271
- /**
272
- * query filter.
273
- */
274
- export type QueryWhere<E> = IdValue<E> | IdValue<E>[] | QueryWhereMap<E> | QueryWhereArray<E> | QueryRaw;
275
71
  /**
276
72
  * Ambient per-request context (e.g. `{ tenantId, userId, roles }`) resolved by parameterized
277
73
  * filters. Set with `withContext(ctx, cb)`. It's an `interface` (not a type alias) so you can type
@@ -319,60 +115,19 @@ export type FilterMeta<E = unknown> = FilterOptions<E>;
319
115
  * direction for the sort.
320
116
  */
321
117
  export type QuerySortDirection = -1 | 1 | 'asc' | 'desc';
322
- /**
323
- * Distance metrics supported by vector similarity search.
324
- * - `cosine` - best for text/LLM embeddings (default)
325
- * - `l2` - Euclidean distance
326
- * - `inner` - inner (dot) product
327
- * - `l1` - Manhattan distance
328
- * - `hamming` - for binary vectors
329
- */
330
- export type VectorDistance = 'cosine' | 'l2' | 'inner' | 'l1' | 'hamming';
331
- /**
332
- * Vector similarity search options - used inside `$sort` on vector fields.
333
- *
334
- * @example
335
- * ```ts
336
- * querier.findMany(Article, {
337
- * $sort: { embedding: { $vector: queryVec } },
338
- * $limit: 10,
339
- * });
340
- * ```
341
- */
342
- export interface QueryVectorSearch {
343
- /** The query vector to compare against. */
344
- readonly $vector: readonly number[];
345
- /** Distance metric. Overrides entity-level default. Falls back to `'cosine'`. */
346
- readonly $distance?: VectorDistance;
347
- /** Project the computed distance as a named field in the result. */
348
- readonly $project?: string;
349
- }
350
118
  /**
351
119
  * Accepted value for a field in `$sort` - either a direction or a vector similarity search.
352
120
  */
353
121
  export type QuerySortValue = QuerySortDirection | QueryVectorSearch;
354
122
  /**
355
- * Augments an entity with the distance field projected by a vector-search `$sort.$project`. The
356
- * find methods return the plain entity, so annotate the result with this when you project a score:
357
- * ```ts
358
- * const results = (await querier.findMany(Article, {
359
- * $sort: { embedding: { $vector: queryVec, $project: 'similarity' } },
360
- * })) as WithDistance<Article, 'similarity'>[];
361
- * ```
362
- */
363
- export type WithDistance<E, K extends string = '_distance'> = E & Record<K, number>;
364
- /**
365
- * sort by map - supports field keys, JSON dot-notation paths, relation sort,
366
- * and vector similarity search.
367
- * Uses both a mapped type (IDE autocompletion) and a pattern index signature (EPC acceptance)
368
- * for dot-paths, matching the same approach used in `QueryWhereMap`.
123
+ * sort by map - supports field keys, JSON dot-notation paths (restricted to real JSON fields,
124
+ * like `QueryWhereMap`), relation sort via nested objects, and vector similarity search on
125
+ * `number[]` fields.
369
126
  */
370
127
  export type QuerySortMap<E> = {
371
- [K in FieldKey<E>]?: QuerySortValue;
128
+ [K in FieldKey<E>]?: NonNullable<E[K]> extends readonly number[] ? QuerySortValue : QuerySortDirection;
372
129
  } & {
373
130
  [P in JsonFieldPaths<E>]?: QuerySortDirection;
374
- } & {
375
- [key: `${string}.${string}`]: QuerySortDirection | undefined;
376
131
  } & {
377
132
  [K in RelationKey<E>]?: QuerySortMap<NonNullable<Unpacked<E[K]>>>;
378
133
  };
@@ -410,9 +165,11 @@ export type QuerySearch<E> = {
410
165
  */
411
166
  export type Query<E> = {
412
167
  /**
413
- * field selection - `{ name: true }` whitelists fields. Mutually exclusive with `$exclude`.
168
+ * field selection - `{ name: true }` whitelists fields, or raw SQL projections
169
+ * (`[raw('LOG10(points)', 'score')]`, SQL dialects only - MongoDB rejects the raw-array form).
170
+ * Mutually exclusive with `$exclude`.
414
171
  */
415
- $select?: QuerySelect<E>;
172
+ $select?: QuerySelectValue<E>;
416
173
  /**
417
174
  * relation population options.
418
175
  */
@@ -434,15 +191,6 @@ export type QueryOne<E> = Omit<Query<E>, '$limit'>;
434
191
  * options to get an unique record.
435
192
  */
436
193
  export type QueryUnique<E> = Pick<QueryOne<E>, '$select' | '$exclude' | '$populate' | '$where'>;
437
- /**
438
- * Maps the offending keys to `never`, turning an excess key into a compile error; resolves to
439
- * `unknown` (an inert intersection member) when there are none. Used by `aggregate`'s `$group`,
440
- * which is captured as a generic (a bare generic skips excess-property checking). The find methods
441
- * don't need this: they take concrete `Query<E>` params, so TypeScript's native excess-property
442
- * checking rejects stray keys directly.
443
- * @internal
444
- */
445
- type Reject<K> = [K] extends [never] ? unknown : Record<K & string, never>;
446
194
  /**
447
195
  * stringified query.
448
196
  */
@@ -473,401 +221,4 @@ export type QueryUpdateResult = {
473
221
  */
474
222
  created?: boolean;
475
223
  };
476
- /**
477
- * options for the `raw` function.
478
- */
479
- export type QueryRawFnOptions = {
480
- /**
481
- * the current dialect.
482
- */
483
- dialect?: QueryDialect;
484
- /**
485
- * the prefix.
486
- */
487
- prefix?: string;
488
- /**
489
- * the escaped prefix.
490
- */
491
- escapedPrefix?: string;
492
- /**
493
- * the query context.
494
- */
495
- ctx?: QueryContext;
496
- };
497
- /**
498
- * a `raw` function
499
- */
500
- export type QueryRawFn = (opts?: QueryRawFnOptions) => void | Scalar;
501
- export declare const RAW_VALUE: unique symbol;
502
- export declare const RAW_ALIAS: unique symbol;
503
- export declare class QueryRaw {
504
- readonly [RAW_VALUE]: Scalar | QueryRawFn;
505
- readonly [RAW_ALIAS]?: string;
506
- constructor(value: Scalar | QueryRawFn, alias?: string);
507
- }
508
- /**
509
- * comparison options.
510
- */
511
- export type QueryComparisonOptions = QueryOptions & {
512
- /**
513
- * use precedence for the comparison or not.
514
- */
515
- usePrecedence?: boolean;
516
- };
517
- /**
518
- * query filter options.
519
- */
520
- export type QueryWhereOptions = QueryComparisonOptions & {
521
- /**
522
- * clause to be used in the filter.
523
- */
524
- clause?: 'WHERE' | 'AND' | false;
525
- };
526
- export interface QueryContext {
527
- append(sql: string): this;
528
- addValue(value: unknown): this;
529
- pushValue(...values: unknown[]): this;
530
- readonly sql: string;
531
- readonly values: unknown[];
532
- }
533
- /**
534
- * Capabilities of the database driver (transport layer).
535
- */
536
- export interface DriverCapabilities {
537
- /**
538
- * Whether JSON bind parameters are cast via text first (`($n::text)::jsonb`).
539
- * Bun SQL PostgreSQL uses this for reliable jsonb merge/push; `pg` does not.
540
- */
541
- readonly explicitJsonCast: boolean;
542
- /**
543
- * Whether the driver natively supports JS arrays for the underlying database type.
544
- * `PgDialect` keeps this `true` for node-postgres; Bun SQL PostgreSQL uses `false` and
545
- * `toPgArray` string literals instead.
546
- */
547
- readonly nativeArrays: boolean;
548
- /** Whether the dialect natively supports the JSONB binary JSON type (Postgres/CockroachDB). */
549
- readonly supportsJsonb: boolean;
550
- }
551
- /**
552
- * How a dialect surfaces the IDs generated by an INSERT statement:
553
- * - `'returning'`: the statement itself returns one row per inserted record (`RETURNING`,
554
- * or MongoDB's `insertedIds`), so IDs are exact for every row.
555
- * - `'firstId'`: the driver header only exposes the first generated ID (MySQL `insertId`);
556
- * the remaining IDs are inferred by incrementing it.
557
- * - `'lastId'`: the driver header only exposes the last generated ID (SQLite `lastInsertRowid`);
558
- * the remaining IDs are inferred backwards from it.
559
- */
560
- export type InsertIdSource = 'returning' | 'firstId' | 'lastId';
561
- /**
562
- * Features of the database engine (SQL syntax layer).
563
- */
564
- export interface EngineFeatures {
565
- readonly ifNotExists: boolean;
566
- readonly indexIfNotExists: boolean;
567
- readonly dropTableCascade: boolean;
568
- readonly renameColumn: boolean;
569
- readonly foreignKeyAlter: boolean;
570
- /** Whether the dialect supports inline COMMENT on columns (MySQL/MariaDB). */
571
- readonly columnComment: boolean;
572
- /**
573
- * How vector indexes are emitted: inline in CREATE TABLE (MySQL/MariaDB), a standalone
574
- * `CREATE INDEX ... USING <type> (col opclass)` (Postgres/SQLite), or a standalone
575
- * `CREATE VECTOR INDEX (col opclass)` with no access-method keyword (CockroachDB's native type).
576
- */
577
- readonly vectorIndexStyle: 'inline' | 'create' | 'native';
578
- /** Whether the dialect requires/allows (n) length constraints on vector types. */
579
- readonly vectorSupportsLength: boolean;
580
- /** Whether the dialect natively supports the TIMESTAMPTZ alias/type. */
581
- readonly supportsTimestamptz: boolean;
582
- /** Whether the dialect defaults to TEXT for strings when no length is specified (e.g. Postgres). */
583
- readonly defaultStringAsText: boolean;
584
- }
585
- export interface DialectFeatures extends EngineFeatures, DriverCapabilities {
586
- }
587
- export interface QueryDialect {
588
- /**
589
- * The dialect features.
590
- */
591
- readonly features: DialectFeatures;
592
- /**
593
- * obtains the records matching the given search parameters.
594
- * @param ctx the query context
595
- * @param entity the target entity
596
- * @param q the criteria options
597
- * @param opts the query options
598
- */
599
- find<E>(ctx: QueryContext, entity: Type<E>, q: Query<E>, opts?: QueryOptions): void;
600
- /**
601
- * counts the number of records matching the given search parameters.
602
- * @param ctx the query context
603
- * @param entity the target entity
604
- * @param q the criteria options
605
- * @param opts the query options
606
- */
607
- count<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): void;
608
- /**
609
- * insert records.
610
- * @param ctx the query context
611
- * @param entity the target entity
612
- * @param payload the payload
613
- * @param opts the query options
614
- */
615
- insert<E>(ctx: QueryContext, entity: Type<E>, payload: E | E[], opts?: QueryOptions): void;
616
- /**
617
- * update records.
618
- * @param ctx the query context
619
- * @param entity the target entity
620
- * @param q the criteria options
621
- * @param payload
622
- * @param opts the query options
623
- */
624
- update<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, payload: UpdatePayload<E>, opts?: QueryOptions): void;
625
- /**
626
- * upsert records.
627
- * @param ctx the query context
628
- * @param entity the target entity
629
- * @param conflictPaths the conflict paths
630
- * @param payload
631
- */
632
- upsert<E>(ctx: QueryContext, entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: E | E[]): void;
633
- /**
634
- * delete records.
635
- * @param ctx the query context
636
- * @param entity the target entity
637
- * @param q the criteria options
638
- * @param opts the query options
639
- */
640
- delete<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): void;
641
- /**
642
- * escape an identifier.
643
- * @param val the value to be escaped
644
- * @param forbidQualified don't escape dots
645
- * @param addDot use a dot as suffix
646
- */
647
- escapeId(val: string, forbidQualified?: boolean, addDot?: boolean): string;
648
- /**
649
- * escape a value.
650
- * @param val the value to escape
651
- */
652
- escape(val: unknown): string;
653
- /**
654
- * add a value to the query.
655
- * @param values the values array
656
- * @param value the value to add
657
- */
658
- addValue(values: unknown[], value: unknown): string;
659
- /**
660
- * normalizes a value according to the dialect.
661
- * @param value the value to normalize
662
- */
663
- normalizeValue(value: unknown): unknown;
664
- /**
665
- * create a new query context.
666
- */
667
- createContext(): QueryContext;
668
- }
669
- /**
670
- * Supported SQL dialect identifiers.
671
- */
672
- export type SqlDialectName = 'postgres' | 'cockroachdb' | 'mysql' | 'mariadb' | 'sqlite';
673
- /**
674
- * Minimal dialect interface exposing escapeIdChar for SQL operations
675
- */
676
- export interface SqlQueryDialect extends QueryDialect {
677
- /**
678
- * The SQL dialect name (postgres, mysql, mariadb, sqlite).
679
- */
680
- readonly dialectName: SqlDialectName;
681
- /**
682
- * the escape character for identifiers.
683
- */
684
- readonly escapeIdChar: '"' | '`';
685
- /**
686
- * Build an aggregate query.
687
- */
688
- aggregate<E>(ctx: QueryContext, entity: Type<E>, q: QueryAggregate<E>, opts?: QueryOptions): void;
689
- /**
690
- * Get the placeholder for a parameter at the given index (1-based).
691
- * Default: '?' for MySQL/MariaDB/SQLite, '$n' for PostgreSQL.
692
- */
693
- placeholder(index: number): string;
694
- }
695
- declare const QUERY_AGGREGATE_OPS: readonly ['$count', '$sum', '$avg', '$min', '$max'];
696
- /**
697
- * Supported aggregate operations.
698
- */
699
- export type QueryAggregateOp = (typeof QUERY_AGGREGATE_OPS)[number];
700
- /**
701
- * Whether `op` is one of {@link QueryAggregateOp}'s known aggregate operators - validates operator
702
- * keys parsed from query data before trusting them as `QueryAggregateOp`.
703
- */
704
- export declare function isQueryAggregateOp(op: string): op is QueryAggregateOp;
705
- /**
706
- * DISTINCT-qualified aggregate ops, each mapped to the base op it applies to a field's distinct
707
- * values: `$countDistinct` → `COUNT(DISTINCT col)`, and likewise `$sumDistinct`/`$avgDistinct`. Flat
708
- * (not a nested `{ $distinct }` argument) so the op is self-documenting and greppable. `$min`/`$max`
709
- * are omitted: DISTINCT is a no-op for them.
710
- */
711
- declare const QUERY_AGGREGATE_DISTINCT_OP_BASE: {
712
- readonly $countDistinct: '$count';
713
- readonly $sumDistinct: '$sum';
714
- readonly $avgDistinct: '$avg';
715
- };
716
- /** DISTINCT-qualified aggregate operators (the keys of {@link QUERY_AGGREGATE_DISTINCT_OP_BASE}). */
717
- export type QueryAggregateDistinctOp = keyof typeof QUERY_AGGREGATE_DISTINCT_OP_BASE;
718
- /**
719
- * Resolve an aggregate op key into its base op and whether it is DISTINCT-qualified. A flat distinct
720
- * op resolves to its base op with `distinct: true`; a plain op to `distinct: false`. Throws otherwise
721
- * (`$min`/`$max` have no distinct variant).
722
- */
723
- export declare function resolveAggregateOp(key: string): {
724
- op: QueryAggregateOp;
725
- distinct: boolean;
726
- };
727
- /** The argument of an aggregate function: a field, or `'*'` (only meaningful for `COUNT(*)`). */
728
- export type QueryAggregateArg<E> = FieldKey<E> | '*';
729
- /** Ops whose argument must be a plain field: every op except `$count` (which also accepts `'*'`). */
730
- type QueryAggregateFieldOp = Exclude<QueryAggregateOp, '$count'> | QueryAggregateDistinctOp;
731
- /** Every aggregate op mapped to its accepted argument: `$count` takes a field or `'*'`, the rest a field. */
732
- type QueryAggregateArgMap<E> = Record<'$count', QueryAggregateArg<E>> & Record<QueryAggregateFieldOp, FieldKey<E>>;
733
- /** Exactly one key of `T`: the chosen op with its value; every other op key is forbidden (`never`). */
734
- type ExactlyOne<T> = {
735
- [K in keyof T]: Readonly<Record<K, T[K]>> & Partial<Readonly<Record<Exclude<keyof T, K>, never>>>;
736
- }[keyof T];
737
- /**
738
- * An aggregate function applied to a field. Exactly one operation per entry (a second op is a
739
- * compile error). Only `$count` accepts `'*'` (i.e. `COUNT(*)`); every other op requires a field.
740
- * DISTINCT variants are flat ops (`$countDistinct`/`$sumDistinct`/`$avgDistinct`) taking a field.
741
- *
742
- * @example { $count: '*' } → COUNT(*)
743
- * @example { $countDistinct: 'id' } → COUNT(DISTINCT "id")
744
- * @example { $sum: 'amount' } → SUM("amount")
745
- * @example { $sumDistinct: 'amount' } → SUM(DISTINCT "amount")
746
- * @example { $avg: 'age' } → AVG("age")
747
- */
748
- export type QueryAggregateFn<E> = ExactlyOne<QueryAggregateArgMap<E>>;
749
- /**
750
- * Aggregate ops whose grouped column always resolves to `number`, regardless of the aggregated
751
- * field's own type: the DISTINCT variants plus the base ops they map to (`$count`/`$sum`/`$avg`).
752
- */
753
- type QueryAggregateNumericOp = QueryAggregateDistinctOp | (typeof QUERY_AGGREGATE_DISTINCT_OP_BASE)[QueryAggregateDistinctOp];
754
- /** A single-key `{ [op]: unknown }` shape for each {@link QueryAggregateNumericOp}, matched to infer a `number` result. */
755
- type QueryAggregateNumericFn = {
756
- [K in QueryAggregateNumericOp]: {
757
- readonly [P in K]: unknown;
758
- };
759
- }[QueryAggregateNumericOp];
760
- /**
761
- * Group-by columns: an object mapping entity field keys to `true`, exactly like {@link QuerySelect}.
762
- * Typed against the entity, so a typo'd column is a compile error. Compute aggregate columns with
763
- * {@link QueryAggMap} (the `$agg` key), not here.
764
- *
765
- * @example
766
- * ```ts
767
- * { status: true } // → GROUP BY "status"
768
- * ```
769
- */
770
- export type QueryGroupMap<E> = {
771
- readonly [K in FieldKey<E>]?: true;
772
- };
773
- /**
774
- * Computed aggregate columns: an object mapping your chosen output alias to an aggregate function.
775
- * Alias names are free (you are naming new columns); the aggregated field reference inside each
776
- * function is typed against the entity.
777
- *
778
- * @example
779
- * ```ts
780
- * { count: { $count: '*' }, avgAge: { $avg: 'age' } }
781
- * // → COUNT(*) AS "count", AVG("age") AS "avgAge"
782
- * ```
783
- */
784
- export type QueryAggMap<E> = {
785
- readonly [alias: string]: QueryAggregateFn<E>;
786
- };
787
- /** The entity type of an aggregated field reference `F`, or `unknown` if it is not a known field. */
788
- type FieldValueType<E, F> = F extends keyof E ? E[F] : unknown;
789
- /**
790
- * Resolves a single computed column's type from its aggregate function: `$count`/`$sum`/`$avg` are
791
- * always `number`; `$min`/`$max` keep the aggregated field's own type.
792
- * @internal
793
- */
794
- type QueryAggregateFnResult<E, Fn> = Fn extends QueryAggregateNumericFn ? number : Fn extends {
795
- readonly $min: infer F;
796
- } ? FieldValueType<E, F> : Fn extends {
797
- readonly $max: infer F;
798
- } ? FieldValueType<E, F> : unknown;
799
- /**
800
- * Flattens an intersection into a single object literal for readable editor hovers.
801
- * @internal
802
- */
803
- type Simplify<T> = {
804
- [K in keyof T]: T[K];
805
- } & {};
806
- /**
807
- * Infers the aggregated result row: grouped columns (`G`) keep their entity type; computed columns
808
- * (`A`) resolve from their aggregate function via {@link QueryAggregateFnResult}.
809
- */
810
- export type QueryAggregateResult<E, G, A> = Simplify<{
811
- -readonly [K in keyof G & FieldKey<E>]: E[K];
812
- } & {
813
- -readonly [K in keyof A]: QueryAggregateFnResult<E, A[K]>;
814
- }>;
815
- /**
816
- * Erased runtime shape of a HAVING clause (alias → comparison), consumed by the dialect builders.
817
- * Values are `unknown` because the SQL is built generically; the typed, per-column value checking
818
- * lives in {@link QueryAggregate.$having}.
819
- *
820
- * @example { count: { $gt: 5 } } → HAVING COUNT(*) > 5
821
- */
822
- export type QueryHavingMap = {
823
- readonly [alias: string]: QueryWhereFieldValue<unknown> | undefined;
824
- };
825
- /**
826
- * Aggregate query - separate from `Query<E>` to keep return types honest.
827
- * Used exclusively with `querier.aggregate()`.
828
- *
829
- * @example
830
- * ```ts
831
- * querier.aggregate(User, {
832
- * $where: { deletedAt: { $isNull: true } },
833
- * $group: { status: true },
834
- * $agg: { count: { $count: '*' }, avgAge: { $avg: 'age' } },
835
- * $having: { count: { $gt: 5 } },
836
- * $sort: { count: -1 },
837
- * });
838
- * ```
839
- */
840
- export type QueryAggregate<E, G extends QueryGroupMap<E> = QueryGroupMap<E>, A extends QueryAggMap<E> = QueryAggMap<E>> = {
841
- /**
842
- * Row-level filtering, applied before grouping (SQL `WHERE`, MongoDB `$match`).
843
- */
844
- readonly $where?: QueryWhere<E>;
845
- /**
846
- * Columns to group by - `{ status: true }`, typed against the entity like `$select`. A computed
847
- * aggregate wrongly placed here (it belongs in `$agg`) is rejected via {@link Reject}, since
848
- * `$group` is captured as a generic and a bare generic skips excess-property checking.
849
- */
850
- readonly $group?: G & Reject<Exclude<keyof G, FieldKey<E>>>;
851
- /**
852
- * Computed aggregate columns - `{ count: { $count: '*' }, avgAge: { $avg: 'age' } }`.
853
- */
854
- readonly $agg?: A;
855
- /**
856
- * Post-aggregation filtering, applied after grouping (SQL `HAVING`, MongoDB post-group `$match`).
857
- * Keyed by the result columns (grouped columns + computed aliases), and each value is typed to that
858
- * column's result type - a `$min`/`$max` over a `Date` field compares against a `Date`, a grouped
859
- * column against its own type - reusing {@link QueryAggregateResult}. A name that is neither is a
860
- * compile error.
861
- */
862
- readonly $having?: {
863
- readonly [K in keyof QueryAggregateResult<E, G, A>]?: QueryWhereFieldValue<QueryAggregateResult<E, G, A>[K]>;
864
- };
865
- /**
866
- * Sort the aggregated results by a grouped column, a computed alias, or an entity field.
867
- */
868
- readonly $sort?: QuerySortMap<E> & {
869
- readonly [K in (keyof G & string) | (keyof A & string)]?: QuerySortDirection;
870
- };
871
- } & QueryPager;
872
- export {};
873
224
  //# sourceMappingURL=query.d.ts.map