uql-orm 0.65.1 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +5 -10
  41. package/dist/entity/decorator/entity.js +2 -7
  42. package/dist/entity/decorator/members.d.ts +10 -31
  43. package/dist/entity/decorator/members.js +3 -12
  44. package/dist/entity/metadata/definition.d.ts +5 -21
  45. package/dist/entity/metadata/definition.js +69 -91
  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 +20 -66
  92. package/dist/migrate/schemaGenerator.js +32 -93
  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 +6 -41
  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 +189 -551
  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 +28 -78
  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 +5 -37
  174. package/dist/util/field.util.js +7 -50
  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,6 +1,6 @@
1
1
  import { type Document, type Filter, type Sort, type UpdateFilter } from 'mongodb';
2
2
  import { AbstractDialect } from '../dialect/abstractDialect.js';
3
- import type { DialectFeatures, EntityData, EntityMeta, FieldValue, Query, QueryAggMap, QueryAggregate, QueryExclude, QueryGroupMap, QueryOptions, QueryPopulate, QuerySelectValue, QuerySortMap, QueryVectorSearch, QueryWhere, Type } from '../type/index.js';
3
+ import type { DialectFeatures, EntityData, EntityMeta, Query, QueryAggMap, QueryAggregate, QueryExclude, QueryGroupMap, QueryOptions, QueryPager, QueryPopulate, QuerySelectValue, QuerySortMap, QueryVectorSearch, QueryWhere, Type } from '../type/index.js';
4
4
  import { type CallbackKey } from '../util/index.js';
5
5
  /** What a read pipeline contributes to {@link MongoDialect.readStages} beyond the query itself. */
6
6
  type MongoReadStages = {
@@ -19,7 +19,7 @@ type RelationLookups = {
19
19
  export declare const mongoDialectFeatures: DialectFeatures;
20
20
  export declare class MongoDialect extends AbstractDialect {
21
21
  #private;
22
- protected readonly featureDefaults: DialectFeatures;
22
+ readonly features: DialectFeatures;
23
23
  readonly dialectName = "mongodb";
24
24
  readonly insertIdSource = "returning";
25
25
  private static readonly ID_KEY;
@@ -33,11 +33,8 @@ export declare class MongoDialect extends AbstractDialect {
33
33
  columnOf<E>(meta: EntityMeta<E>, key: string): string;
34
34
  where<E extends Document>(entity: Type<E>, where?: QueryWhere<E>, opts?: QueryOptions): Filter<E>;
35
35
  /**
36
- * A `$where` that may constrain relations, split into the `$lookup` stages it needs and the `$match`
37
- * filter that consumes them. Each relation condition becomes one correlated lookup into a temporary
38
- * field plus an ordinary condition on that field, so the caller's boolean structure survives intact
39
- * (a relation inside `$or` still means what it says) and nothing depends on materializing ids.
40
- * `unset` names the temporary fields, which the caller drops once the match is done.
36
+ * A `$where` that may constrain relations, as the `$lookup` stages it needs and the `$match` reading
37
+ * them: each condition a lookup into a temporary field (`unset` names them), so `$or` keeps its meaning.
41
38
  */
42
39
  whereWithRelations<E extends Document>(entity: Type<E>, where?: QueryWhere<E>, opts?: QueryOptions): {
43
40
  readonly stages: MongoAggregationPipelineEntry<Document>[];
@@ -53,13 +50,8 @@ export declare class MongoDialect extends AbstractDialect {
53
50
  */
54
51
  protected renderFilter<E extends Document>(entity: Type<E>, where?: QueryWhere<E>, lookups?: RelationLookups): Filter<E>;
55
52
  /**
56
- * Renders `$and`/`$or`/`$not`/`$nor` into `filter`. MongoDB has no root-level `$not`, so both
57
- * negating operators become its `$nor`, which is exactly `NOT (a OR b)` - and by De Morgan that
58
- * makes a `$nor` list its clauses directly while a `$not` wraps them in one `$and` first.
59
- *
60
- * Clauses that render to nothing are dropped and an empty operator emits no key at all: MongoDB
61
- * rejects an empty `$and`/`$or`/`$nor` outright, where the SQL dialects contribute no term.
62
- * Negations accumulate into the one `$nor`, since `NOT a AND NOT b` is `$nor: [a, b]`.
53
+ * Renders `$and`/`$or`/`$not`/`$nor` into `filter`, both negations as MongoDB's `$nor` (a `$not`'s clauses
54
+ * wrapped in one `$and`), dropping empty clauses, since MongoDB refuses an empty operator.
63
55
  */
64
56
  private appendLogicalOperator;
65
57
  /**
@@ -103,9 +95,6 @@ export declare class MongoDialect extends AbstractDialect {
103
95
  * apply to JSON paths.
104
96
  */
105
97
  private assertKnownPathRoot;
106
- protected mapTableNameRow(row: {
107
- table_name: string;
108
- }): string;
109
98
  /** String operators -> { pattern: (v) => regex, caseInsensitive } */
110
99
  private static readonly REGEX_OP_MAP;
111
100
  /** MongoDB native operators - pass through as-is. */
@@ -167,13 +156,11 @@ export declare class MongoDialect extends AbstractDialect {
167
156
  */
168
157
  private pathOf;
169
158
  aggregationPipeline<E extends Document>(entity: Type<E>, q: Query<E>, opts?: QueryOptions): MongoAggregationPipelineEntry<E>[];
159
+ /** The `$skip`/`$limit` stages of a page, each checked: `/http` hands a page over untyped. */
160
+ pagerStages(q: QueryPager): MongoAggregationPipelineEntry<Document>[];
170
161
  /**
171
- * What a read runs after its entry stage, in the one order that works: the lookups its relations
172
- * need, the ordering and paging that may read them, and the projection last of all - it names the
173
- * fields the lookups add, and no stage after it could read what it dropped.
174
- *
175
- * Shared by the plain pipeline and the `$vectorSearch` one, which each used to spell the order out
176
- * for themselves and each got a different part of it wrong.
162
+ * What a read runs after its entry stage, in the one order that works: the lookups, then the sort and
163
+ * page that may read them, then the projection. Shared with the `$vectorSearch` pipeline.
177
164
  */
178
165
  readStages<E extends Document>(entity: Type<E>, q: Query<E>, extra?: MongoReadStages): MongoAggregationPipelineEntry<Document>[];
179
166
  /**
@@ -184,10 +171,8 @@ export declare class MongoDialect extends AbstractDialect {
184
171
  */
185
172
  private distinctStages;
186
173
  /**
187
- * The scalar projection a narrowing query asks for, widened by what the pipeline itself produced:
188
- * each populated relation and the tallies. It goes last, after the lookups have read the join keys -
189
- * projecting any earlier is what used to leave `$populate` empty, and is why the pipeline emitted no
190
- * projection at all and returned every column.
174
+ * The projection a narrowing query asks for, widened by what the pipeline produced (each populated
175
+ * relation and the tallies); last, once the lookups have read the join keys.
191
176
  */
192
177
  pipelineProjection<E extends Document>(entity: Type<E>, q: Query<E>): Record<string, 0 | 1> | undefined;
193
178
  /**
@@ -209,11 +194,8 @@ export declare class MongoDialect extends AbstractDialect {
209
194
  /** `doc` is the wire shape - `_id`, stored names, `ObjectId`s - and what comes back is the code's. */
210
195
  normalizeId<E extends Document>(meta: EntityMeta<E>, doc: Document | undefined): E | undefined;
211
196
  /**
212
- * The seam into the driver: a key, or a reference to one, as MongoDB stores it. A 24-hex string
213
- * becomes an `ObjectId`, so a write agrees with the filter that will later look for it; anything
214
- * else - a UUID, a number, an `ObjectId` already - is stored as given, which is how those keys keep
215
- * their value. Strictly 24-hex: the driver also accepts any 12-byte string, and coercing one of
216
- * those turned an ordinary short key into a foreign `ObjectId`. Arrays convert element-wise.
197
+ * A key as MongoDB stores it: a 24-hex string as an `ObjectId`, so a write matches the filter looking for
198
+ * it, and anything else as given. Only 24-hex, not any 12-byte string. Arrays convert element-wise.
217
199
  */
218
200
  toWireId(value: unknown): unknown;
219
201
  /** The seam out of the driver: an `ObjectId` becomes its hex string, the type the code declares. */
@@ -228,26 +210,11 @@ export declare class MongoDialect extends AbstractDialect {
228
210
  */
229
211
  getUpdateFilter<E extends Document>(persistable: Partial<E>): UpdateFilter<E> | Document[];
230
212
  /**
231
- * MongoDB rejects two operators targeting one path in a single update document, so any path shared
232
- * across operator groups is expressed as one aggregation-pipeline update instead.
233
- *
234
- * Each path's expression is composed in the same order stated on {@link JsonUpdateOp} (`$pull` ->
235
- * `$set` -> `$push` -> `$unset`), so every combination yields the identical result: a `$pull`
236
- * filters the stored array, a `$set` on the same path then replaces it outright, and a `$push`
237
- * appends to whatever those produced. `$unset` is a later stage, so it wins over a `$set` on the
238
- * same path - again matching SQL, where it is the outermost wrapper. Values are wrapped in
239
- * `$literal` so a string starting with `$` stays data rather than becoming a field reference.
213
+ * A JSON update as one pipeline, since MongoDB refuses two operators on one path: each path composed as
214
+ * `$pull`, `$set`, `$push`, then `$unset`, as SQL does, with values as `$literal` so `$x` stays data.
240
215
  */
241
216
  private getUpdatePipeline;
242
- /**
243
- * Refuses a key the caller left to MongoDB that MongoDB cannot mint one of.
244
- *
245
- * The only key a server generates is an `ObjectId`, which {@link fromWireId} hands back as its hex
246
- * string - so a key declared `String` is satisfiable and one declared `Number` is not. Answering a
247
- * numeric declaration with a string is the lie this exists to refuse: the field says `number`, the
248
- * value is not one, and every consumer that indexes or compares by it is quietly wrong. Prisma
249
- * refuses the same shape at its schema, and this is the first moment uql can.
250
- */
217
+ /** Refuses a key left to MongoDB that it cannot mint: only an `ObjectId`, read back as a string, so not a `Number`. */
251
218
  private assertMintableKey;
252
219
  getPersistables<E extends Document>(meta: EntityMeta<E>, payload: EntityData<E> | EntityData<E>[], callbackKey: CallbackKey): Partial<E>[];
253
220
  /**
@@ -273,7 +240,7 @@ export declare class MongoDialect extends AbstractDialect {
273
240
  buildVectorSearchStage<E extends Document>(entity: Type<E>, key: string, search: QueryVectorSearch, where: QueryWhere<E> | undefined, limit: number, opts?: QueryOptions, candidates?: number): Record<string, unknown>;
274
241
  }
275
242
  export type MongoAggregationPipelineEntry<E extends Document> = {
276
- $lookup?: MongoAggregationLookup<E>;
243
+ $lookup?: MongoAggregationLookup;
277
244
  $match?: Filter<E> | Record<string, unknown>;
278
245
  $sort?: Sort;
279
246
  $unwind?: MongoAggregationUnwind;
@@ -289,11 +256,12 @@ export type MongoAggregationPipelineEntry<E extends Document> = {
289
256
  $skip?: number;
290
257
  $limit?: number;
291
258
  };
292
- type MongoAggregationLookup<E extends Document> = {
259
+ /** A `$lookup`, whose pipeline runs over the collection it reads. */
260
+ type MongoAggregationLookup = {
293
261
  readonly from?: string;
294
262
  readonly foreignField?: string;
295
263
  readonly localField?: string;
296
- readonly pipeline?: MongoAggregationPipelineEntry<FieldValue<E>>[];
264
+ readonly pipeline?: MongoAggregationPipelineEntry<Document>[];
297
265
  /** A relation key when populating, a temporary field when a relation condition is being tested. */
298
266
  readonly as?: string;
299
267
  };
@@ -30,7 +30,7 @@ function declaredTypeName(type) {
30
30
  return typeof type === 'function' ? type.name : String(type);
31
31
  }
32
32
  export class MongoDialect extends AbstractDialect {
33
- featureDefaults = mongoDialectFeatures;
33
+ features = mongoDialectFeatures;
34
34
  dialectName = 'mongodb';
35
35
  // The MongoDB driver reports the exact `_id` of every inserted document (`insertedIds`).
36
36
  insertIdSource = 'returning';
@@ -61,11 +61,8 @@ export class MongoDialect extends AbstractDialect {
61
61
  return this.renderFilter(entity, this.scopedWhere(meta, where, opts));
62
62
  }
63
63
  /**
64
- * A `$where` that may constrain relations, split into the `$lookup` stages it needs and the `$match`
65
- * filter that consumes them. Each relation condition becomes one correlated lookup into a temporary
66
- * field plus an ordinary condition on that field, so the caller's boolean structure survives intact
67
- * (a relation inside `$or` still means what it says) and nothing depends on materializing ids.
68
- * `unset` names the temporary fields, which the caller drops once the match is done.
64
+ * A `$where` that may constrain relations, as the `$lookup` stages it needs and the `$match` reading
65
+ * them: each condition a lookup into a temporary field (`unset` names them), so `$or` keeps its meaning.
69
66
  */
70
67
  whereWithRelations(entity, where = {}, opts = {}) {
71
68
  const meta = getMeta(entity);
@@ -130,13 +127,8 @@ export class MongoDialect extends AbstractDialect {
130
127
  return filter;
131
128
  }
132
129
  /**
133
- * Renders `$and`/`$or`/`$not`/`$nor` into `filter`. MongoDB has no root-level `$not`, so both
134
- * negating operators become its `$nor`, which is exactly `NOT (a OR b)` - and by De Morgan that
135
- * makes a `$nor` list its clauses directly while a `$not` wraps them in one `$and` first.
136
- *
137
- * Clauses that render to nothing are dropped and an empty operator emits no key at all: MongoDB
138
- * rejects an empty `$and`/`$or`/`$nor` outright, where the SQL dialects contribute no term.
139
- * Negations accumulate into the one `$nor`, since `NOT a AND NOT b` is `$nor: [a, b]`.
130
+ * Renders `$and`/`$or`/`$not`/`$nor` into `filter`, both negations as MongoDB's `$nor` (a `$not`'s clauses
131
+ * wrapped in one `$and`), dropping empty clauses, since MongoDB refuses an empty operator.
140
132
  */
141
133
  appendLogicalOperator(filter, entity, key, val, lookups) {
142
134
  const { join, negate } = MongoDialect.GROUP_OPS[key];
@@ -282,9 +274,6 @@ export class MongoDialect extends AbstractDialect {
282
274
  }
283
275
  throw new TypeError(`path ${key} does not exist in ${entityName(meta)}`);
284
276
  }
285
- mapTableNameRow(row) {
286
- return row.table_name;
287
- }
288
277
  /** String operators -> { pattern: (v) => regex, caseInsensitive } */
289
278
  static REGEX_OP_MAP = new Map([
290
279
  ['$startsWith', { wrap: (v) => `^${v}`, ci: false }],
@@ -352,17 +341,9 @@ export class MongoDialect extends AbstractDialect {
352
341
  case '$isNotNull':
353
342
  result[val ? '$ne' : '$eq'] = null;
354
343
  break;
355
- case '$text':
356
- result['$text'] = { $search: val };
357
- break;
358
344
  case '$near':
359
- // Atlas has no distance operator. The only threshold it offers is a `$match` on
360
- // `{$meta:'vectorSearchScore'}`, which is a *similarity* on a scale set by the index's own
361
- // `similarity` - and that lives in the Atlas index definition, which UQL neither emits nor
362
- // reads (the same reason `$distance` is index-defined for `$text` above). Converting a
363
- // distance to that scale would mean guessing which metric produced the score, and guessing
364
- // wrong filters the wrong rows silently. So this refuses, the way an unsupported
365
- // `DISTANCE=` does rather than defaulting.
345
+ // Atlas offers only a similarity threshold, on the index's own scale, which UQL neither emits nor
346
+ // reads: converting a distance would mean guessing the metric, so this refuses.
366
347
  throw new TypeError('$near is not supported on MongoDB: Atlas scores by index-defined similarity, not distance. ' +
367
348
  "Project the score with $sort's $project and filter on it instead.");
368
349
  default:
@@ -579,20 +560,20 @@ export class MongoDialect extends AbstractDialect {
579
560
  ...(unset.length ? [{ $unset: unset }] : []),
580
561
  ...this.readStages(entity, q, {
581
562
  sort: this.sort(entity, q.$sort, q.$populate),
582
- pager: [
583
- ...(q.$skip === undefined ? [] : [{ $skip: assertNonNegativeInteger(q.$skip, '$skip') }]),
584
- ...(q.$limit === undefined ? [] : [{ $limit: assertNonNegativeInteger(q.$limit, '$limit') }]),
585
- ],
563
+ pager: this.pagerStages(q),
586
564
  }),
587
565
  ];
588
566
  }
567
+ /** The `$skip`/`$limit` stages of a page, each checked: `/http` hands a page over untyped. */
568
+ pagerStages(q) {
569
+ return [
570
+ ...(q.$skip === undefined ? [] : [{ $skip: assertNonNegativeInteger(q.$skip, '$skip') }]),
571
+ ...(q.$limit === undefined ? [] : [{ $limit: assertNonNegativeInteger(q.$limit, '$limit') }]),
572
+ ];
573
+ }
589
574
  /**
590
- * What a read runs after its entry stage, in the one order that works: the lookups its relations
591
- * need, the ordering and paging that may read them, and the projection last of all - it names the
592
- * fields the lookups add, and no stage after it could read what it dropped.
593
- *
594
- * Shared by the plain pipeline and the `$vectorSearch` one, which each used to spell the order out
595
- * for themselves and each got a different part of it wrong.
575
+ * What a read runs after its entry stage, in the one order that works: the lookups, then the sort and
576
+ * page that may read them, then the projection. Shared with the `$vectorSearch` pipeline.
596
577
  */
597
578
  readStages(entity, q, extra = {}) {
598
579
  const meta = getMeta(entity);
@@ -662,10 +643,8 @@ export class MongoDialect extends AbstractDialect {
662
643
  return [{ $group: { _id: groupId } }, { $replaceRoot: { newRoot: '$_id' } }];
663
644
  }
664
645
  /**
665
- * The scalar projection a narrowing query asks for, widened by what the pipeline itself produced:
666
- * each populated relation and the tallies. It goes last, after the lookups have read the join keys -
667
- * projecting any earlier is what used to leave `$populate` empty, and is why the pipeline emitted no
668
- * projection at all and returned every column.
646
+ * The projection a narrowing query asks for, widened by what the pipeline produced (each populated
647
+ * relation and the tallies); last, once the lookups have read the join keys.
669
648
  */
670
649
  pipelineProjection(entity, q) {
671
650
  if (!q.$select && !q.$exclude) {
@@ -802,11 +781,8 @@ export class MongoDialect extends AbstractDialect {
802
781
  return res;
803
782
  }
804
783
  /**
805
- * The seam into the driver: a key, or a reference to one, as MongoDB stores it. A 24-hex string
806
- * becomes an `ObjectId`, so a write agrees with the filter that will later look for it; anything
807
- * else - a UUID, a number, an `ObjectId` already - is stored as given, which is how those keys keep
808
- * their value. Strictly 24-hex: the driver also accepts any 12-byte string, and coercing one of
809
- * those turned an ordinary short key into a foreign `ObjectId`. Arrays convert element-wise.
784
+ * A key as MongoDB stores it: a 24-hex string as an `ObjectId`, so a write matches the filter looking for
785
+ * it, and anything else as given. Only 24-hex, not any 12-byte string. Arrays convert element-wise.
810
786
  */
811
787
  toWireId(value) {
812
788
  if (Array.isArray(value)) {
@@ -870,15 +846,8 @@ export class MongoDialect extends AbstractDialect {
870
846
  };
871
847
  }
872
848
  /**
873
- * MongoDB rejects two operators targeting one path in a single update document, so any path shared
874
- * across operator groups is expressed as one aggregation-pipeline update instead.
875
- *
876
- * Each path's expression is composed in the same order stated on {@link JsonUpdateOp} (`$pull` ->
877
- * `$set` -> `$push` -> `$unset`), so every combination yields the identical result: a `$pull`
878
- * filters the stored array, a `$set` on the same path then replaces it outright, and a `$push`
879
- * appends to whatever those produced. `$unset` is a later stage, so it wins over a `$set` on the
880
- * same path - again matching SQL, where it is the outermost wrapper. Values are wrapped in
881
- * `$literal` so a string starting with `$` stays data rather than becoming a field reference.
849
+ * A JSON update as one pipeline, since MongoDB refuses two operators on one path: each path composed as
850
+ * `$pull`, `$set`, `$push`, then `$unset`, as SQL does, with values as `$literal` so `$x` stays data.
882
851
  */
883
852
  getUpdatePipeline({ set, push, pull, unset }, exprPaths) {
884
853
  const assignments = {};
@@ -899,15 +868,7 @@ export class MongoDialect extends AbstractDialect {
899
868
  }
900
869
  return [{ $set: assignments }, ...(unset.size > 0 ? [{ $unset: [...unset] }] : [])];
901
870
  }
902
- /**
903
- * Refuses a key the caller left to MongoDB that MongoDB cannot mint one of.
904
- *
905
- * The only key a server generates is an `ObjectId`, which {@link fromWireId} hands back as its hex
906
- * string - so a key declared `String` is satisfiable and one declared `Number` is not. Answering a
907
- * numeric declaration with a string is the lie this exists to refuse: the field says `number`, the
908
- * value is not one, and every consumer that indexes or compares by it is quietly wrong. Prisma
909
- * refuses the same shape at its schema, and this is the first moment uql can.
910
- */
871
+ /** Refuses a key left to MongoDB that it cannot mint: only an `ObjectId`, read back as a string, so not a `Number`. */
911
872
  assertMintableKey(meta, field) {
912
873
  if (columnFamily(field.type) === 'string') {
913
874
  return;
@@ -989,13 +950,7 @@ export class MongoDialect extends AbstractDialect {
989
950
  pipeline.push({ $sort: sort });
990
951
  }
991
952
  }
992
- // $skip and $limit stages
993
- if (q.$skip !== undefined) {
994
- pipeline.push({ $skip: assertNonNegativeInteger(q.$skip, '$skip') });
995
- }
996
- if (q.$limit !== undefined) {
997
- pipeline.push({ $limit: assertNonNegativeInteger(q.$limit, '$limit') });
998
- }
953
+ pipeline.push(...this.pagerStages(q));
999
954
  return pipeline;
1000
955
  }
1001
956
  /**
@@ -1,6 +1,6 @@
1
1
  import type { Document, MongoClient } from 'mongodb';
2
2
  import { AbstractQuerier } from '../querier/index.js';
3
- import type { EntityData, ExtraOptions, PrimaryKey, Query, QueryAggMap, QueryAggregate, QueryAggregateResult, QueryConflictPaths, QueryFilter, QueryGroupMap, QueryOptions, QuerySearch, TransactionOptions, Type, UpdatePayload } from '../type/index.js';
3
+ import type { EntityData, ExtraOptions, PrimaryKey, Query, QueryAggMap, QueryAggregate, QueryAggregateResult, QueryConflictPaths, QueryPage, QueryGroupMap, QueryOptions, QuerySearch, TransactionOptions, Type, UpdatePayload } from '../type/index.js';
4
4
  import type { MongoDialect } from './mongoDialect.js';
5
5
  export declare class MongodbQuerier extends AbstractQuerier {
6
6
  readonly dialect: MongoDialect;
@@ -37,18 +37,15 @@ export declare class MongodbQuerier extends AbstractQuerier {
37
37
  * other query counts through {@link internalCount}, which needs no pipeline of its own.
38
38
  */
39
39
  protected internalFindManyAndCount<E extends Document>(entity: Type<E>, q: Query<E>, opts?: QueryOptions): Promise<[E[], number]>;
40
- protected internalCount<E extends Document>(entity: Type<E>, qm?: QueryFilter<E>, opts?: QueryOptions): Promise<number>;
40
+ /** The pipeline `countDocuments` runs, spelled out so a relation condition gets its lookups and a page its stages. */
41
+ protected internalCount<E extends Document>(entity: Type<E>, q: QueryPage<E>, opts?: QueryOptions): Promise<number>;
41
42
  /**
42
43
  * The collection's metadata count, which the driver exposes as its own call and which takes no
43
44
  * filter - the reason {@link UniversalQuerier.estimatedCount} takes none either.
44
45
  */
45
46
  estimatedCount<E extends Document>(entity: Type<E>): Promise<number>;
46
- /**
47
- * The ids matching `q`, in `q`'s own order and page, so a write can name the rows it settled on.
48
- * Built from the read pipeline rather than stages assembled here: that dropped `$sort`/`$limit` on
49
- * the floor, and skipped the relation-sort rejection {@link MongoDialect.sort} raises.
50
- */
51
- private settleIds;
47
+ /** A `find` filter cannot host the `$lookup` a relation condition needs, so such a write names its rows by id. */
48
+ protected settlesWrite<E extends Document>(entity: Type<E>, q: QuerySearch<E>): boolean;
52
49
  internalInsertMany<E extends Document>(entity: Type<E>, rows: EntityData<E>[]): Promise<void>;
53
50
  internalUpdateMany<E extends Document>(entity: Type<E>, qm: QuerySearch<E>, payload: UpdatePayload<E>, opts?: QueryOptions): Promise<number>;
54
51
  /**
@@ -1,8 +1,8 @@
1
1
  import { COUNT_ALIAS } from '../dialect/aliases.js';
2
2
  import { hasRequiredJoin } from '../dialect/queryJoins.js';
3
- import { fieldOf, getMeta, idOf, namesKey, soleIdOf } from '../entity/index.js';
3
+ import { fieldOf, getMeta, namesKey, soleIdOf } from '../entity/index.js';
4
4
  import { AbstractQuerier, enrichError } from '../querier/index.js';
5
- import { clone, getKeys, getSoftDeleteValue, hasKeys, idOnlyQuery, isPagedQuery, populatesRelations, throwNoPendingTransaction, throwPendingTransaction, withoutSoftDeleteFilter, } from '../util/index.js';
5
+ import { clone, getKeys, getSoftDeleteValue, hasKeys, populatesRelations, throwNoPendingTransaction, throwPendingTransaction, withoutSoftDeleteFilter, } from '../util/index.js';
6
6
  /**
7
7
  * `$limit: 0` asks for no rows, the way it does on every SQL dialect - but MongoDB reads `limit(0)`
8
8
  * as *unlimited*, so a read that passed it straight to the driver came back with the whole
@@ -147,21 +147,16 @@ export class MongodbQuerier extends AbstractQuerier {
147
147
  ]);
148
148
  return [founds, counted[0]?.[COUNT_ALIAS] ?? 0];
149
149
  }
150
- async internalCount(entity, qm = {}, opts) {
150
+ /** The pipeline `countDocuments` runs, spelled out so a relation condition gets its lookups and a page its stages. */
151
+ async internalCount(entity, q, opts) {
152
+ if (asksForNoRows(q)) {
153
+ return 0;
154
+ }
151
155
  return this.timed('internalCount', undefined, async () => {
152
- if (this.dialect.constrainsRelations(entity, qm.$where)) {
153
- const { stages, filter } = this.dialect.whereWithRelations(entity, qm.$where, opts);
154
- const [counted] = await this.execute((session) => this.collection(entity)
155
- .aggregate([...stages, { $match: filter }, { $count: COUNT_ALIAS }], {
156
- session,
157
- })
158
- .toArray());
159
- return counted?.[COUNT_ALIAS] ?? 0;
160
- }
161
- const filter = this.dialect.where(entity, qm.$where, opts);
162
- return this.execute((session) => this.collection(entity).countDocuments(filter, {
163
- session,
164
- }));
156
+ const { stages, filter } = this.dialect.whereWithRelations(entity, q.$where, opts);
157
+ const pipeline = [...stages, { $match: filter }, ...this.dialect.pagerStages(q), { $count: COUNT_ALIAS }];
158
+ const [counted] = await this.execute((session) => this.collection(entity).aggregate(pipeline, { session }).toArray());
159
+ return counted?.[COUNT_ALIAS] ?? 0;
165
160
  });
166
161
  }
167
162
  /**
@@ -171,18 +166,9 @@ export class MongodbQuerier extends AbstractQuerier {
171
166
  async estimatedCount(entity) {
172
167
  return this.timed('estimatedCount', undefined, async () => this.execute((session) => this.collection(entity).estimatedDocumentCount({ session })));
173
168
  }
174
- /**
175
- * The ids matching `q`, in `q`'s own order and page, so a write can name the rows it settled on.
176
- * Built from the read pipeline rather than stages assembled here: that dropped `$sort`/`$limit` on
177
- * the floor, and skipped the relation-sort rejection {@link MongoDialect.sort} raises.
178
- */
179
- async settleIds(entity, q, opts) {
180
- const meta = getMeta(entity);
181
- const pipeline = this.dialect.aggregationPipeline(entity, idOnlyQuery(meta, q), opts);
182
- const founds = await this.execute((session) => this.collection(entity).aggregate(pipeline, { session }).toArray());
183
- // `normalizeIds` has already spread a compound `_id` back into its columns, so the settled rows
184
- // are named the same way every other driver names them.
185
- return this.dialect.normalizeIds(meta, founds).map((found) => idOf(meta, found));
169
+ /** A `find` filter cannot host the `$lookup` a relation condition needs, so such a write names its rows by id. */
170
+ settlesWrite(entity, q) {
171
+ return super.settlesWrite(entity, q) || this.dialect.constrainsRelations(entity, q.$where);
186
172
  }
187
173
  async internalInsertMany(entity, rows) {
188
174
  return this.timed('internalInsertMany', undefined, async () => {
@@ -199,21 +185,11 @@ export class MongodbQuerier extends AbstractQuerier {
199
185
  }
200
186
  async internalUpdateMany(entity, qm, payload, opts) {
201
187
  return this.timed('internalUpdateMany', undefined, async () => {
202
- payload = clone(payload);
203
- const meta = getMeta(entity);
204
- const persistable = this.dialect.getPersistable(meta, payload, 'onUpdate');
205
- // Settled to ids first in two cases: an `updateMany` filter cannot host a `$lookup`, so a
206
- // relation condition has nowhere to go, and MongoDB takes no page on a write, so a paged one
207
- // has to name the rows it picked rather than touching every match.
208
- const where = this.dialect.constrainsRelations(entity, qm.$where) || isPagedQuery(qm)
209
- ? { _id: { $in: this.dialect.toWireId(await this.settleIds(entity, qm, opts)) } }
210
- : this.dialect.where(entity, qm.$where, opts);
188
+ const persistable = this.dialect.getPersistable(getMeta(entity), payload, 'onUpdate');
189
+ const filter = this.dialect.where(entity, qm.$where, opts);
211
190
  // Maps JSON operators ($set/$unset/$push/$pull) onto their native MongoDB equivalents.
212
191
  const update = this.dialect.getUpdateFilter(persistable);
213
- const { matchedCount } = await this.execute((session) => this.collection(entity).updateMany(where, update, {
214
- session,
215
- }));
216
- await this.updateRelations(entity, qm, payload, opts);
192
+ const { matchedCount } = await this.execute((session) => this.collection(entity).updateMany(filter, update, { session }));
217
193
  return matchedCount;
218
194
  });
219
195
  }
@@ -298,31 +274,21 @@ export class MongodbQuerier extends AbstractQuerier {
298
274
  const meta = getMeta(entity);
299
275
  // Soft-delete (stamp) unless `hardDelete` is requested or the entity has no soft-delete field.
300
276
  const softDelete = opts.hardDelete ? undefined : meta.softDelete;
301
- // Hard delete targets matching rows regardless of soft-delete state (keeps other filters).
302
- const findOpts = softDelete ? opts : { ...opts, filters: withoutSoftDeleteFilter(opts.filters) };
303
- // Delete has always resolved its ids first (it stamps or removes them by `_id`), so a relation
304
- // condition needs nothing extra here - and passing the whole query is what makes its page apply.
305
- const ids = await this.settleIds(entity, qm, findOpts);
306
- if (!ids.length) {
307
- return 0;
277
+ if (!softDelete) {
278
+ const filter = this.dialect.where(entity, qm.$where, {
279
+ ...opts,
280
+ filters: withoutSoftDeleteFilter(opts.filters),
281
+ });
282
+ const { deletedCount } = await this.execute((session) => this.collection(entity).deleteMany(filter, { session }));
283
+ return deletedCount;
308
284
  }
309
- let changes;
310
- if (softDelete) {
311
- const field = fieldOf(meta, softDelete);
312
- // Stamp the mapped column: reads filter on it, so a `@Field({ name })` mismatch here would
313
- // report a successful delete and leave the row visible.
314
- const softDeleteColumn = this.dialect.resolveColumnName(softDelete, field);
315
- const updateResult = await this.execute((session) => this.collection(entity).updateMany({ _id: { $in: this.dialect.toWireId(ids) } }, { $set: { [softDeleteColumn]: getSoftDeleteValue(field) } }, {
316
- session,
317
- }));
318
- changes = updateResult.matchedCount;
319
- }
320
- else {
321
- const deleteResult = await this.execute((session) => this.collection(entity).deleteMany({ _id: { $in: this.dialect.toWireId(ids) } }, { session }));
322
- changes = deleteResult.deletedCount;
323
- }
324
- await this.deleteRelations(entity, ids, opts);
325
- return changes;
285
+ const field = fieldOf(meta, softDelete);
286
+ // The mapped column, which reads filter on: a `@Field({ name })` mismatch would leave the row visible.
287
+ const column = this.dialect.resolveColumnName(softDelete, field);
288
+ const update = { $set: { [column]: getSoftDeleteValue(field) } };
289
+ const filter = this.dialect.where(entity, qm.$where, opts);
290
+ const { matchedCount } = await this.execute((session) => this.collection(entity).updateMany(filter, update, { session }));
291
+ return matchedCount;
326
292
  });
327
293
  }
328
294
  get hasOpenTransaction() {
@@ -1,17 +1,10 @@
1
1
  import { type RelationRows } from '../dialect/abstractSqlDialect.js';
2
2
  import { MergeSqlDialect } from '../dialect/mergeSqlDialect.js';
3
- import type { DialectFeatures, EntityMeta, FieldOptions, InsertIdSource, Query, QueryContext, QueryOptions, QueryPager, QuerySizeComparisonOps, Type, VectorDistance, VectorMetric } from '../type/index.js';
4
- /**
5
- * Microsoft SQL Server 2017 and up - the floor `STRING_AGG` sets, every other construct here being
6
- * 2016 or older.
7
- *
8
- * Identifiers are `"`-quoted rather than bracketed: `escapeIdChar` is one character that doubles to
9
- * escape itself, `"` is the ANSI spelling, and `tedious` enables `QUOTED_IDENTIFIER` by default.
10
- * Brackets would buy nothing and cost the shared dialect spec, which reads that one character.
11
- */
3
+ import type { EntityMeta, FieldOptions, InsertIdSource, Query, QueryContext, QueryOptions, QueryPager, QuerySizeComparisonOps, SqlDialectFeatures, Type, VectorDistance, VectorMetric } from '../type/index.js';
4
+ /** Microsoft SQL Server 2017 and up. Identifiers are `"`-quoted, the ANSI spelling `tedious` enables. */
12
5
  export declare class MsSqlDialect extends MergeSqlDialect {
13
6
  #private;
14
- protected readonly featureDefaults: DialectFeatures;
7
+ readonly features: SqlDialectFeatures;
15
8
  readonly dialectName = "mssql";
16
9
  readonly autoIncrementSuffix = "IDENTITY(1,1)";
17
10
  readonly tableOptions = "";
@@ -29,8 +22,6 @@ export declare class MsSqlDialect extends MergeSqlDialect {
29
22
  readonly maxBindValues = 2100;
30
23
  /** `OUTPUT` has no trailing form: it sits between the column list and `VALUES`. */
31
24
  readonly returningPosition = "after-target";
32
- /** Microsoft documents no row order for a `MERGE ... OUTPUT`. */
33
- readonly upsertReturningOrdered = false;
34
25
  readonly insertIdSource: InsertIdSource;
35
26
  /** Holds the update key lock across the insert; without it two concurrent upserts of one key race. */
36
27
  protected readonly mergeTargetHint = " WITH (HOLDLOCK)";
@@ -48,23 +39,13 @@ export declare class MsSqlDialect extends MergeSqlDialect {
48
39
  $distinct?: boolean;
49
40
  }, sorted?: boolean): void;
50
41
  /**
51
- * `SET IDENTITY_INSERT` around the insert, where the payload states a key the engine would
52
- * otherwise generate: writing one is refused outright ("cannot insert explicit value for identity
53
- * column ... when IDENTITY_INSERT is set to OFF") rather than ignored.
54
- *
55
- * Emitted only for that case, because the setting is per-session and only one table may hold it at
56
- * a time, so it is turned back off in the same batch it was turned on.
42
+ * `SET IDENTITY_INSERT` around an insert that states a key the engine would generate, which it otherwise
43
+ * refuses; turned off in the same batch, since one table per session may hold it.
57
44
  */
58
45
  insert<E>(ctx: QueryContext, entity: Type<E>, payload: E | E[], opts?: QueryOptions): void;
59
46
  /** The table to toggle, or nothing when no record writes a key the engine would have generated. */
60
47
  private identityInsertTarget;
61
- /**
62
- * A `DECIMAL` read back as the exact text it was written as, where the entity declared the field a
63
- * `String`. `tedious` decodes the type to a JS number before anything here can see it, so the
64
- * digits past 2^53 are gone at the wire unless the column is converted before it crosses - the same
65
- * reason MariaDB reads a vector column through `VEC_ToText`. 41 characters covers `DECIMAL(38, s)`
66
- * with room for the sign and the point.
67
- */
48
+ /** A `DECIMAL` declared `String`, converted before it crosses the wire, where `tedious` would round it. */
68
49
  protected selectFieldExpr(escapedColumn: string, field: FieldOptions): string;
69
50
  /**
70
51
  * The rows read as they are, `FOR JSON PATH` making the array. It nests a dotted key and leaves a
@@ -135,13 +116,8 @@ export declare class MsSqlDialect extends MergeSqlDialect {
135
116
  */
136
117
  protected getJsonPathJsonbExpr(escapedColumn: string, jsonPathStr: string): string;
137
118
  /**
138
- * A value being *compared* against a JSON path, which reads back as the text `JSON_VALUE` yields:
139
- * `'true'` for a boolean, `'12'` for a number. So only a boolean needs re-spelling; a number or a
140
- * string already binds as the text it will be compared with.
141
- *
142
- * There is no "parse this text as JSON" cast to bind through the way `CAST(? AS JSON)` and
143
- * `json(?)` serve the other families - `JSON_QUERY` marks text as JSON but answers NULL for a
144
- * scalar - which is why reading and writing need the two different binders here.
119
+ * A value compared against a JSON path, which reads back as text, so only a boolean needs spelling as
120
+ * `'true'`; SQL Server has no cast that parses text as JSON.
145
121
  */
146
122
  protected jsonScalarParam(ctx: QueryContext, value: unknown): string;
147
123
  /**
@@ -150,8 +126,6 @@ export declare class MsSqlDialect extends MergeSqlDialect {
150
126
  * flattened a boolean to 1/0 for this engine's columns, so the cast is what restores it.
151
127
  */
152
128
  protected jsonWriteParam(ctx: QueryContext, value: unknown): string;
153
- /** An exploded element compares as text here, so `$elemMatch` always expands per field. */
154
- protected readonly jsonContainmentIsPartial = false;
155
129
  protected jsonElemFrom(jsonField: string, _fields: readonly string[], alias: string): string;
156
130
  /** `JSON_VALUE`'s 4000-character bound applies to an element's field, unlike a whole column. */
157
131
  protected jsonElemRef(alias: string, field?: string): string;