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.
- package/dist/browser/querier/httpQuerier.js +1 -8
- package/dist/browser/uql-browser.min.js.map +5 -5
- package/dist/bunSql/bunSql.util.d.ts +2 -6
- package/dist/bunSql/bunSql.util.js +2 -6
- package/dist/bunSql/bunSqlQuerier.d.ts +2 -5
- package/dist/bunSql/bunSqlQuerier.js +2 -5
- package/dist/cockroachdb/cockroachDialect.d.ts +4 -13
- package/dist/cockroachdb/cockroachDialect.js +4 -13
- package/dist/context/context.browser.js +2 -10
- package/dist/context/context.d.ts +4 -17
- package/dist/context/context.js +4 -17
- package/dist/dialect/abstractDialect.d.ts +4 -19
- package/dist/dialect/abstractDialect.js +2 -20
- package/dist/dialect/abstractSqlDialect.d.ts +47 -212
- package/dist/dialect/abstractSqlDialect.js +68 -222
- package/dist/dialect/aliases.d.ts +2 -12
- package/dist/dialect/aliases.js +4 -12
- package/dist/dialect/hydrateColumn.d.ts +2 -6
- package/dist/dialect/hydrateColumn.js +3 -13
- package/dist/dialect/jsonArrayElemMatchUtils.d.ts +1 -7
- package/dist/dialect/jsonArrayElemMatchUtils.js +1 -7
- package/dist/dialect/jsonSql.d.ts +6 -27
- package/dist/dialect/jsonSql.js +6 -27
- package/dist/dialect/mergeSqlDialect.d.ts +4 -22
- package/dist/dialect/mergeSqlDialect.js +4 -22
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +11 -37
- package/dist/dialect/mysqlLikeSqlDialect.js +35 -51
- package/dist/dialect/pgLikeSqlDialect.d.ts +8 -22
- package/dist/dialect/pgLikeSqlDialect.js +36 -39
- package/dist/dialect/queryContext.d.ts +4 -22
- package/dist/dialect/queryContext.js +4 -22
- package/dist/dialect/queryJoins.d.ts +3 -12
- package/dist/dialect/queryJoins.js +3 -12
- package/dist/dialect/vectorCast.d.ts +2 -12
- package/dist/dialect/vectorCast.js +3 -19
- package/dist/dialect/vectorSqlDialect.d.ts +8 -38
- package/dist/dialect/vectorSqlDialect.js +7 -38
- package/dist/entity/decorator/bag.d.ts +6 -19
- package/dist/entity/decorator/bag.js +6 -22
- package/dist/entity/decorator/entity.d.ts +5 -10
- package/dist/entity/decorator/entity.js +2 -7
- package/dist/entity/decorator/members.d.ts +10 -31
- package/dist/entity/decorator/members.js +3 -12
- package/dist/entity/metadata/definition.d.ts +5 -21
- package/dist/entity/metadata/definition.js +69 -91
- package/dist/http/handler.d.ts +2 -14
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/libsql/libsqlDialect.d.ts +1 -8
- package/dist/libsql/libsqlDialect.js +1 -8
- package/dist/maria/mariaDialect.d.ts +3 -5
- package/dist/maria/mariaDialect.js +5 -5
- package/dist/maria/mariadbQuerier.js +2 -2
- package/dist/maria/mariadbQuerierPool.js +1 -6
- package/dist/migrate/builder/migrationBuilder.js +3 -19
- package/dist/migrate/builder/splitSqlStatements.d.ts +1 -14
- package/dist/migrate/builder/splitSqlStatements.js +2 -22
- package/dist/migrate/builder/types.d.ts +2 -15
- package/dist/migrate/cli-config.js +2 -11
- package/dist/migrate/cli.js +2 -7
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -15
- package/dist/migrate/codegen/entityCodeGenerator.js +15 -44
- package/dist/migrate/codegen/fieldOptionsSource.d.ts +1 -8
- package/dist/migrate/codegen/fieldOptionsSource.js +3 -22
- package/dist/migrate/ddl/indexDdl.d.ts +2 -5
- package/dist/migrate/ddl/indexDdl.js +2 -5
- package/dist/migrate/ddl/pgIndexDdl.d.ts +3 -13
- package/dist/migrate/ddl/pgIndexDdl.js +3 -13
- package/dist/migrate/generator/definitionToNode.d.ts +2 -9
- package/dist/migrate/generator/definitionToNode.js +3 -17
- package/dist/migrate/generator/indexNodeToSchema.d.ts +2 -3
- package/dist/migrate/generator/indexNodeToSchema.js +2 -3
- package/dist/migrate/generator/mongoCommand.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.js +1 -8
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +6 -26
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +9 -41
- package/dist/migrate/introspection/baseSqlIntrospector.js +0 -1
- package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
- package/dist/migrate/introspection/mongoIntrospector.js +48 -46
- package/dist/migrate/introspection/mssqlIntrospector.d.ts +4 -4
- package/dist/migrate/introspection/mssqlIntrospector.js +18 -27
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +7 -2
- package/dist/migrate/introspection/mysqlIntrospector.js +16 -14
- package/dist/migrate/introspection/postgresIntrospector.d.ts +24 -9
- package/dist/migrate/introspection/postgresIntrospector.js +68 -59
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -1
- package/dist/migrate/introspection/sqliteIntrospector.js +8 -10
- package/dist/migrate/migrator.d.ts +9 -53
- package/dist/migrate/migrator.js +32 -65
- package/dist/migrate/schemaGenerator.d.ts +20 -66
- package/dist/migrate/schemaGenerator.js +32 -93
- package/dist/mongo/mongoDialect.d.ts +21 -53
- package/dist/mongo/mongoDialect.js +25 -70
- package/dist/mongo/mongodbQuerier.d.ts +5 -8
- package/dist/mongo/mongodbQuerier.js +31 -65
- package/dist/mssql/mssqlDialect.d.ts +8 -34
- package/dist/mssql/mssqlDialect.js +37 -51
- package/dist/mssql/mssqlQuerier.d.ts +37 -4
- package/dist/mssql/mssqlQuerier.js +2 -2
- package/dist/mssql/mssqlWireTypes.d.ts +2 -14
- package/dist/mssql/mssqlWireTypes.js +2 -14
- package/dist/nestjs/uqlModule.js +2 -7
- package/dist/pglite/pgliteQuerier.d.ts +1 -9
- package/dist/pglite/pgliteQuerierPool.d.ts +4 -26
- package/dist/pglite/pgliteQuerierPool.js +3 -18
- package/dist/postgres/abstractPgQuerierPool.d.ts +1 -8
- package/dist/postgres/abstractPgQuerierPool.js +1 -8
- package/dist/postgres/pgNumericTypes.d.ts +3 -26
- package/dist/postgres/pgNumericTypes.js +3 -26
- package/dist/postgres/postgresDialect.d.ts +4 -10
- package/dist/postgres/postgresDialect.js +4 -10
- package/dist/querier/abstractQuerier.d.ts +35 -103
- package/dist/querier/abstractQuerier.js +105 -201
- package/dist/querier/abstractSharedHandleQuerierPool.d.ts +3 -17
- package/dist/querier/abstractSharedHandleQuerierPool.js +3 -17
- package/dist/querier/abstractSqlQuerier.d.ts +15 -36
- package/dist/querier/abstractSqlQuerier.js +49 -131
- package/dist/schema/canonicalType.d.ts +3 -21
- package/dist/schema/canonicalType.js +22 -67
- package/dist/schema/dependencyGraph.d.ts +2 -8
- package/dist/schema/dependencyGraph.js +2 -32
- package/dist/schema/index.d.ts +1 -25
- package/dist/schema/index.js +0 -26
- package/dist/schema/indexColumns.d.ts +1 -8
- package/dist/schema/indexColumns.js +1 -8
- package/dist/schema/indexDifferences.d.ts +7 -40
- package/dist/schema/indexDifferences.js +6 -31
- package/dist/schema/schemaAST.d.ts +8 -175
- package/dist/schema/schemaAST.js +13 -365
- package/dist/schema/schemaASTBuilder.d.ts +2 -24
- package/dist/schema/schemaASTBuilder.js +6 -41
- package/dist/schema/schemaASTDiffer.d.ts +6 -46
- package/dist/schema/schemaASTDiffer.js +8 -56
- package/dist/schema/types.d.ts +5 -61
- package/dist/schema/types.js +3 -6
- package/dist/sqlite/abstractSqliteQuerier.d.ts +1 -8
- package/dist/sqlite/localSqliteQuerierPool.d.ts +1 -7
- package/dist/sqlite/localSqliteQuerierPool.js +1 -7
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -7
- package/dist/sqlite/nodeSqliteQuerierPool.js +2 -7
- package/dist/sqlite/sqliteDialect.d.ts +5 -20
- package/dist/sqlite/sqliteDialect.js +29 -35
- package/dist/turso/tursoDialect.d.ts +4 -6
- package/dist/turso/tursoDialect.js +4 -6
- package/dist/turso/tursoLocalQuerierPool.d.ts +1 -7
- package/dist/turso/tursoLocalQuerierPool.js +1 -7
- package/dist/turso/tursoQuerierPool.d.ts +2 -6
- package/dist/turso/tursoQuerierPool.js +2 -6
- package/dist/turso/tursoSessionQuerier.d.ts +1 -7
- package/dist/turso/tursoSessionQuerier.js +1 -7
- package/dist/type/dialect.d.ts +42 -94
- package/dist/type/dialect.js +3 -13
- package/dist/type/entity.d.ts +189 -551
- package/dist/type/entity.js +26 -9
- package/dist/type/logger.d.ts +2 -14
- package/dist/type/migration.d.ts +9 -38
- package/dist/type/querier.d.ts +9 -28
- package/dist/type/querierPool.d.ts +4 -26
- package/dist/type/query.d.ts +28 -78
- package/dist/type/query.js +2 -7
- package/dist/type/queryAggregate.d.ts +18 -98
- package/dist/type/queryRaw.d.ts +1 -8
- package/dist/type/queryRaw.js +1 -8
- package/dist/type/queryWhere.d.ts +13 -61
- package/dist/type/universalQuerier.d.ts +18 -105
- package/dist/type/utility.d.ts +12 -24
- package/dist/type/vector.d.ts +8 -38
- package/dist/type/vector.js +1 -1
- package/dist/type/wire.d.ts +2 -5
- package/dist/util/dialect.util.d.ts +9 -27
- package/dist/util/dialect.util.js +10 -27
- package/dist/util/field.util.d.ts +5 -37
- package/dist/util/field.util.js +7 -50
- package/dist/util/fieldOption.util.d.ts +7 -15
- package/dist/util/fieldOption.util.js +1 -1
- package/dist/util/filters.util.d.ts +2 -5
- package/dist/util/filters.util.js +2 -5
- package/dist/util/logger.d.ts +2 -6
- package/dist/util/logger.js +2 -6
- package/dist/util/object.util.d.ts +2 -6
- package/dist/util/object.util.js +1 -5
- package/dist/util/raw.d.ts +3 -23
- package/dist/util/relationQuery.util.d.ts +3 -14
- package/dist/util/relationQuery.util.js +3 -14
- package/dist/util/rowKey.util.d.ts +2 -10
- package/dist/util/rowKey.util.js +2 -10
- package/dist/util/sql.util.d.ts +6 -37
- package/dist/util/sql.util.js +13 -73
- package/dist/util/sqlLiteral.d.ts +2 -13
- package/dist/util/sqlLiteral.js +8 -13
- package/dist/util/string.util.js +0 -2
- package/package.json +4 -4
|
@@ -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,
|
|
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
|
-
|
|
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,
|
|
37
|
-
*
|
|
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
|
|
57
|
-
*
|
|
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
|
|
172
|
-
*
|
|
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
|
|
188
|
-
*
|
|
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
|
-
*
|
|
213
|
-
*
|
|
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
|
-
*
|
|
232
|
-
*
|
|
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
|
|
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
|
-
|
|
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<
|
|
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
|
-
|
|
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,
|
|
65
|
-
*
|
|
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
|
|
134
|
-
*
|
|
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
|
|
360
|
-
//
|
|
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
|
|
591
|
-
*
|
|
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
|
|
666
|
-
*
|
|
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
|
-
*
|
|
806
|
-
*
|
|
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
|
-
*
|
|
874
|
-
*
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
176
|
-
|
|
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
|
-
|
|
203
|
-
const
|
|
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(
|
|
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
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
return
|
|
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
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
|
52
|
-
*
|
|
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
|
|
139
|
-
* `'true'
|
|
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;
|