uql-orm 0.53.0 → 0.55.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/README.md +2 -2
- package/dist/browser/uql-browser.min.js.map +2 -2
- package/dist/bunSql/bunSql.util.d.ts +3 -14
- package/dist/bunSql/bunSql.util.js +33 -56
- package/dist/bunSql/bunSqlQuerier.d.ts +3 -6
- package/dist/bunSql/bunSqlQuerier.js +7 -13
- package/dist/bunSql/bunSqlQuerierPool.d.ts +10 -5
- package/dist/bunSql/bunSqlQuerierPool.js +25 -10
- package/dist/cockroachdb/cockroachDialect.d.ts +2 -5
- package/dist/cockroachdb/cockroachDialect.js +2 -5
- package/dist/cockroachdb/crdbQuerierPool.d.ts +1 -3
- package/dist/cockroachdb/crdbQuerierPool.js +0 -4
- package/dist/cockroachdb/index.d.ts +0 -1
- package/dist/cockroachdb/index.js +0 -1
- package/dist/d1/d1SqliteDialect.d.ts +5 -0
- package/dist/d1/d1SqliteDialect.js +7 -0
- package/dist/dialect/abstractSqlDialect.d.ts +15 -9
- package/dist/dialect/abstractSqlDialect.js +47 -54
- package/dist/dialect/hydrateColumn.js +2 -2
- package/dist/dialect/mergeSqlDialect.d.ts +2 -2
- package/dist/dialect/mergeSqlDialect.js +0 -4
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +0 -3
- package/dist/dialect/mysqlLikeSqlDialect.js +0 -3
- package/dist/dialect/pgLikeSqlDialect.d.ts +5 -0
- package/dist/dialect/pgLikeSqlDialect.js +12 -2
- package/dist/entity/decorator/members.d.ts +3 -10
- package/dist/entity/index.d.ts +1 -1
- package/dist/entity/index.js +1 -1
- package/dist/entity/metadata/definition.d.ts +3 -1
- package/dist/entity/metadata/definition.js +8 -4
- package/dist/libsql/index.d.ts +0 -1
- package/dist/libsql/index.js +0 -1
- package/dist/libsql/libsqlQuerierPool.d.ts +3 -5
- package/dist/libsql/libsqlQuerierPool.js +2 -5
- package/dist/maria/mariadbQuerier.d.ts +0 -3
- package/dist/maria/mariadbQuerier.js +6 -7
- package/dist/maria/mariadbQuerierPool.js +4 -7
- package/dist/migrate/builder/migrationBuilder.js +0 -4
- package/dist/migrate/ddl/index.d.ts +3 -3
- package/dist/migrate/ddl/index.js +3 -3
- package/dist/migrate/migrator.d.ts +3 -7
- package/dist/migrate/migrator.js +3 -7
- package/dist/migrate/schemaGenerator.d.ts +0 -13
- package/dist/migrate/schemaGenerator.js +0 -13
- package/dist/migrate/storage/databaseStorage.d.ts +2 -2
- package/dist/migrate/storage/databaseStorage.js +2 -2
- package/dist/mongo/index.d.ts +0 -1
- package/dist/mongo/index.js +0 -1
- package/dist/mongo/mongoDialect.d.ts +0 -1
- package/dist/mongo/mongoDialect.js +3 -14
- package/dist/mongo/mongodbQuerier.d.ts +3 -5
- package/dist/mongo/mongodbQuerier.js +23 -23
- package/dist/mongo/mongodbQuerierPool.d.ts +2 -2
- package/dist/mongo/mongodbQuerierPool.js +2 -2
- package/dist/mssql/mssqlDialect.d.ts +5 -5
- package/dist/mssql/mssqlDialect.js +11 -8
- package/dist/mssql/mssqlQuerier.d.ts +13 -6
- package/dist/mssql/mssqlQuerier.js +30 -75
- package/dist/mssql/mssqlQuerierPool.js +2 -0
- package/dist/mssql/mssqlWireTypes.d.ts +3 -4
- package/dist/mssql/mssqlWireTypes.js +5 -8
- package/dist/mysql/index.d.ts +0 -1
- package/dist/mysql/index.js +0 -1
- package/dist/mysql/mysql2Querier.d.ts +1 -4
- package/dist/mysql/mysql2Querier.js +0 -3
- package/dist/mysql/mysql2QuerierPool.d.ts +2 -2
- package/dist/mysql/mysql2QuerierPool.js +5 -3
- package/dist/neon/index.d.ts +0 -2
- package/dist/neon/index.js +0 -2
- package/dist/neon/neonQuerierPool.d.ts +2 -4
- package/dist/neon/neonQuerierPool.js +2 -6
- package/dist/pglite/index.d.ts +0 -1
- package/dist/pglite/index.js +0 -1
- package/dist/pglite/pgliteQuerier.d.ts +3 -3
- package/dist/pglite/pgliteQuerier.js +1 -1
- package/dist/pglite/pgliteQuerierPool.d.ts +7 -2
- package/dist/pglite/pgliteQuerierPool.js +16 -6
- package/dist/postgres/abstractPgQuerierPool.d.ts +8 -12
- package/dist/postgres/abstractPgQuerierPool.js +8 -6
- package/dist/postgres/index.d.ts +0 -1
- package/dist/postgres/index.js +0 -1
- package/dist/postgres/pgNumericTypes.d.ts +5 -5
- package/dist/postgres/pgNumericTypes.js +11 -7
- package/dist/postgres/pgQuerier.d.ts +22 -4
- package/dist/postgres/pgQuerier.js +29 -2
- package/dist/postgres/pgQuerierPool.d.ts +2 -4
- package/dist/postgres/pgQuerierPool.js +2 -6
- package/dist/postgres/postgresDialect.d.ts +5 -5
- package/dist/postgres/postgresDialect.js +5 -5
- package/dist/postgres/postgresWireDriverCapabilities.d.ts +2 -2
- package/dist/postgres/postgresWireDriverCapabilities.js +2 -2
- package/dist/querier/abstractPoolQuerier.d.ts +1 -1
- package/dist/querier/abstractPoolQuerier.js +1 -1
- package/dist/querier/abstractQuerier.d.ts +17 -22
- package/dist/querier/abstractQuerier.js +80 -57
- package/dist/querier/abstractSqlQuerier.d.ts +20 -13
- package/dist/querier/abstractSqlQuerier.js +96 -100
- package/dist/schema/schemaASTBuilder.js +7 -7
- package/dist/sqlite/hranaQuerier.d.ts +6 -8
- package/dist/sqlite/hranaQuerier.js +13 -30
- package/dist/sqlite/hranaQuerierPool.d.ts +3 -4
- package/dist/sqlite/hranaQuerierPool.js +2 -1
- package/dist/sqlite/localSqliteQuerierPool.d.ts +3 -3
- package/dist/sqlite/localSqliteQuerierPool.js +4 -2
- package/dist/sqlite/nodeSqliteAdapter.d.ts +0 -1
- package/dist/sqlite/nodeSqliteQuerierPool.js +0 -2
- package/dist/sqlite/sqlitePragmas.d.ts +12 -0
- package/dist/sqlite/sqlitePragmas.js +15 -0
- package/dist/sqlite/sqliteQuerierPool.d.ts +0 -5
- package/dist/sqlite/sqliteQuerierPool.js +2 -13
- package/dist/turso/index.d.ts +0 -1
- package/dist/turso/index.js +0 -1
- package/dist/turso/tursoLocalQuerier.d.ts +0 -1
- package/dist/turso/tursoLocalQuerierPool.js +2 -2
- package/dist/turso/tursoQuerierPool.d.ts +1 -3
- package/dist/turso/tursoQuerierPool.js +0 -4
- package/dist/type/dialect.d.ts +1 -1
- package/dist/type/entity.d.ts +6 -11
- package/dist/type/migration.d.ts +0 -3
- package/dist/type/query.d.ts +12 -12
- package/dist/type/query.js +0 -6
- package/dist/type/universalQuerier.d.ts +3 -3
- package/dist/util/dialect.util.d.ts +4 -3
- package/dist/util/dialect.util.js +2 -1
- package/dist/util/field.util.d.ts +4 -16
- package/dist/util/field.util.js +6 -19
- package/dist/util/fieldOption.util.d.ts +1 -4
- package/dist/util/fieldOption.util.js +0 -2
- package/dist/util/logger.d.ts +10 -11
- package/dist/util/logger.js +21 -11
- package/dist/util/raw.d.ts +3 -10
- package/dist/util/raw.js +3 -3
- package/dist/util/sql.util.js +2 -2
- package/dist/util/sqlLiteral.js +3 -8
- package/dist/util/string.util.js +2 -6
- package/dist/util/wideNumber.d.ts +14 -0
- package/dist/util/wideNumber.js +24 -0
- package/package.json +1 -1
- package/dist/cockroachdb/crdbQuerier.d.ts +0 -8
- package/dist/cockroachdb/crdbQuerier.js +0 -6
- package/dist/libsql/libsqlQuerier.d.ts +0 -10
- package/dist/libsql/libsqlQuerier.js +0 -10
- package/dist/mongo/mongodbNativeDialect.d.ts +0 -9
- package/dist/mongo/mongodbNativeDialect.js +0 -9
- package/dist/mysql/mysql2Dialect.d.ts +0 -9
- package/dist/mysql/mysql2Dialect.js +0 -9
- package/dist/neon/neonDialect.d.ts +0 -10
- package/dist/neon/neonDialect.js +0 -10
- package/dist/neon/neonQuerier.d.ts +0 -5
- package/dist/neon/neonQuerier.js +0 -3
- package/dist/pglite/pgliteDialect.d.ts +0 -14
- package/dist/pglite/pgliteDialect.js +0 -14
- package/dist/postgres/abstractPgQuerier.d.ts +0 -24
- package/dist/postgres/abstractPgQuerier.js +0 -32
- package/dist/postgres/pgDialect.d.ts +0 -10
- package/dist/postgres/pgDialect.js +0 -10
- package/dist/turso/tursoQuerier.d.ts +0 -10
- package/dist/turso/tursoQuerier.js +0 -10
|
@@ -10,10 +10,6 @@ import { derivedIndexName } from '../../util/sql.util.js';
|
|
|
10
10
|
import { createSchemaGenerator } from '../schemaGenerator.js';
|
|
11
11
|
import { splitSqlStatements } from './splitSqlStatements.js';
|
|
12
12
|
import { TableBuilder } from './tableBuilder.js';
|
|
13
|
-
/**
|
|
14
|
-
* Builder for altering a table.
|
|
15
|
-
* Delegates to parent builder for operation recording.
|
|
16
|
-
*/
|
|
17
13
|
/**
|
|
18
14
|
* One `createIndex` operation. Shared because the alter-table builder, the recorder and the
|
|
19
15
|
* executing builder all record the same thing, and an entry left unnormalized reaches the generator
|
|
@@ -7,9 +7,9 @@ export { MariaIndexDdl, MySqlIndexDdl, MysqlLikeIndexDdl } from './mysqlIndexDdl
|
|
|
7
7
|
export { CockroachIndexDdl, PgIndexDdl } from './pgIndexDdl.js';
|
|
8
8
|
export { TableDdl } from './tableDdl.js';
|
|
9
9
|
/**
|
|
10
|
-
* The index DDL a dialect gets, most specific first. `instanceof` rather than `dialectName`
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* The index DDL a dialect gets, most specific first. `instanceof` rather than the `dialectName`
|
|
11
|
+
* {@link tableDdlFor} reads, because each family's index DDL is typed to its dialect and the narrowing
|
|
12
|
+
* is what hands it one. Anything else gets the portable form, which is SQLite's.
|
|
13
13
|
*/
|
|
14
14
|
export declare function indexDdlFor(dialect: AbstractSqlDialect): IndexDdl;
|
|
15
15
|
/**
|
|
@@ -14,9 +14,9 @@ export { MariaIndexDdl, MySqlIndexDdl, MysqlLikeIndexDdl } from './mysqlIndexDdl
|
|
|
14
14
|
export { CockroachIndexDdl, PgIndexDdl } from './pgIndexDdl.js';
|
|
15
15
|
export { TableDdl } from './tableDdl.js';
|
|
16
16
|
/**
|
|
17
|
-
* The index DDL a dialect gets, most specific first. `instanceof` rather than `dialectName`
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* The index DDL a dialect gets, most specific first. `instanceof` rather than the `dialectName`
|
|
18
|
+
* {@link tableDdlFor} reads, because each family's index DDL is typed to its dialect and the narrowing
|
|
19
|
+
* is what hands it one. Anything else gets the portable form, which is SQLite's.
|
|
20
20
|
*/
|
|
21
21
|
export function indexDdlFor(dialect) {
|
|
22
22
|
if (dialect instanceof CockroachDialect) {
|
|
@@ -105,14 +105,10 @@ export declare class Migrator {
|
|
|
105
105
|
*/
|
|
106
106
|
private forceStatements;
|
|
107
107
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* The new-table case costs one existence check and creates with `IF NOT EXISTS`, so instances racing
|
|
112
|
-
* the same admin save settle instead of colliding. An existing table still pays for introspection,
|
|
113
|
-
* since a column diff needs the columns.
|
|
108
|
+
* The DDL for one entity: {@link planSync} narrowed to the table it names. A new table costs one
|
|
109
|
+
* existence check and is created with `IF NOT EXISTS`, so instances racing the same admin save
|
|
110
|
+
* settle instead of colliding; an existing one still pays for introspection, as a diff needs columns.
|
|
114
111
|
*/
|
|
115
|
-
/** The DDL for one entity: {@link planSync} narrowed to the table it names. */
|
|
116
112
|
private planEntity;
|
|
117
113
|
/** An alter diff as statements, narrowed to what the caller allows. */
|
|
118
114
|
private alterFromDiff;
|
package/dist/migrate/migrator.js
CHANGED
|
@@ -345,14 +345,10 @@ export class Migrator {
|
|
|
345
345
|
];
|
|
346
346
|
}
|
|
347
347
|
/**
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
* The new-table case costs one existence check and creates with `IF NOT EXISTS`, so instances racing
|
|
352
|
-
* the same admin save settle instead of colliding. An existing table still pays for introspection,
|
|
353
|
-
* since a column diff needs the columns.
|
|
348
|
+
* The DDL for one entity: {@link planSync} narrowed to the table it names. A new table costs one
|
|
349
|
+
* existence check and is created with `IF NOT EXISTS`, so instances racing the same admin save
|
|
350
|
+
* settle instead of colliding; an existing one still pays for introspection, as a diff needs columns.
|
|
354
351
|
*/
|
|
355
|
-
/** The DDL for one entity: {@link planSync} narrowed to the table it names. */
|
|
356
352
|
async planEntity(entity, options) {
|
|
357
353
|
const meta = getMeta(entity);
|
|
358
354
|
// Before anything reads `this.generator`, whose own failure names neither the entity nor the
|
|
@@ -25,9 +25,6 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
25
25
|
resolveColumnName(key: string, field: FieldOptions): string;
|
|
26
26
|
/** Escape an identifier (table name, column name, etc.) */
|
|
27
27
|
protected escapeId(identifier: string): string;
|
|
28
|
-
/**
|
|
29
|
-
* Primary key type for auto-increment integer IDs
|
|
30
|
-
*/
|
|
31
28
|
/**
|
|
32
29
|
* How an auto-increment key of `type` is spelled: the type as any other column renders it, plus what
|
|
33
30
|
* the engine appends to make it generated.
|
|
@@ -128,9 +125,6 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
128
125
|
name: string;
|
|
129
126
|
comment?: string;
|
|
130
127
|
}, schema?: string): string[];
|
|
131
|
-
/**
|
|
132
|
-
* Compare an entity with a database table node and return the differences.
|
|
133
|
-
*/
|
|
134
128
|
/**
|
|
135
129
|
* How this entity differs from the table the database reported, as the migrator's `SchemaDiff`.
|
|
136
130
|
*
|
|
@@ -139,13 +133,6 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
139
133
|
* table node first, and types are compared as the *engine* would store them - see `normalizeType`.
|
|
140
134
|
*/
|
|
141
135
|
diffSchema<E>(entity: Type<E>, currentTable: TableNode | undefined, desiredAst?: SchemaAST): SchemaDiff | undefined;
|
|
142
|
-
/**
|
|
143
|
-
* What the shared differ needs from a dialect: a type as this engine would actually store it.
|
|
144
|
-
*
|
|
145
|
-
* `boolean` is `TINYINT(1)` on MySQL and `INTEGER` on SQLite, so two canonical types that differ on
|
|
146
|
-
* paper can be one column in the database. Round-tripping through the engine's own spelling is what
|
|
147
|
-
* stops every such column reporting an alteration on every sync.
|
|
148
|
-
*/
|
|
149
136
|
/**
|
|
150
137
|
* Indexes the entity declares that the table does not already have, in any shape.
|
|
151
138
|
*
|
|
@@ -50,9 +50,6 @@ export class SqlSchemaGenerator {
|
|
|
50
50
|
escapeId(identifier) {
|
|
51
51
|
return this.dialect.escapeId(identifier);
|
|
52
52
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Primary key type for auto-increment integer IDs
|
|
55
|
-
*/
|
|
56
53
|
/**
|
|
57
54
|
* How an auto-increment key of `type` is spelled: the type as any other column renders it, plus what
|
|
58
55
|
* the engine appends to make it generated.
|
|
@@ -361,9 +358,6 @@ export class SqlSchemaGenerator {
|
|
|
361
358
|
const tableRef = this.dialect.escapeQualifiedId(tableName, schema);
|
|
362
359
|
return [`COMMENT ON COLUMN ${tableRef}.${this.escapeId(column.name)} IS ${this.dialect.escape(column.comment)};`];
|
|
363
360
|
}
|
|
364
|
-
/**
|
|
365
|
-
* Compare an entity with a database table node and return the differences.
|
|
366
|
-
*/
|
|
367
361
|
/**
|
|
368
362
|
* How this entity differs from the table the database reported, as the migrator's `SchemaDiff`.
|
|
369
363
|
*
|
|
@@ -447,13 +441,6 @@ export class SqlSchemaGenerator {
|
|
|
447
441
|
foreignKeysToAlter: foreignKeysToAlter.length ? foreignKeysToAlter : undefined,
|
|
448
442
|
};
|
|
449
443
|
}
|
|
450
|
-
/**
|
|
451
|
-
* What the shared differ needs from a dialect: a type as this engine would actually store it.
|
|
452
|
-
*
|
|
453
|
-
* `boolean` is `TINYINT(1)` on MySQL and `INTEGER` on SQLite, so two canonical types that differ on
|
|
454
|
-
* paper can be one column in the database. Round-tripping through the engine's own spelling is what
|
|
455
|
-
* stops every such column reporting an alteration on every sync.
|
|
456
|
-
*/
|
|
457
444
|
/**
|
|
458
445
|
* Indexes the entity declares that the table does not already have, in any shape.
|
|
459
446
|
*
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { MigrationStorage, QuerierPool, SqlQuerier } from '../../type/index.js';
|
|
2
|
+
/** Where executed migrations are recorded when the config does not name a table. */
|
|
3
|
+
export declare const DEFAULT_MIGRATIONS_TABLE = "uql_migrations";
|
|
2
4
|
/**
|
|
3
5
|
* Stores migration state in a database table.
|
|
4
6
|
* Uses the querier's dialect for escaping and placeholders.
|
|
5
7
|
*/
|
|
6
|
-
/** Where executed migrations are recorded when the config does not name a table. */
|
|
7
|
-
export declare const DEFAULT_MIGRATIONS_TABLE = "uql_migrations";
|
|
8
8
|
export declare class DatabaseMigrationStorage implements MigrationStorage {
|
|
9
9
|
private readonly pool;
|
|
10
10
|
private readonly tableName;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { withSqlQuerierForMigrations } from '../acquireQuerierForMigrations.js';
|
|
2
|
+
/** Where executed migrations are recorded when the config does not name a table. */
|
|
3
|
+
export const DEFAULT_MIGRATIONS_TABLE = 'uql_migrations';
|
|
2
4
|
/**
|
|
3
5
|
* Stores migration state in a database table.
|
|
4
6
|
* Uses the querier's dialect for escaping and placeholders.
|
|
5
7
|
*/
|
|
6
|
-
/** Where executed migrations are recorded when the config does not name a table. */
|
|
7
|
-
export const DEFAULT_MIGRATIONS_TABLE = 'uql_migrations';
|
|
8
8
|
export class DatabaseMigrationStorage {
|
|
9
9
|
pool;
|
|
10
10
|
tableName;
|
package/dist/mongo/index.d.ts
CHANGED
package/dist/mongo/index.js
CHANGED
|
@@ -20,7 +20,6 @@ export declare class MongoDialect extends AbstractDialect {
|
|
|
20
20
|
private static readonly ID_KEY;
|
|
21
21
|
/** Atlas rejects a `$vectorSearch` asking for more candidates than this. */
|
|
22
22
|
private static readonly MAX_NUM_CANDIDATES;
|
|
23
|
-
private static readonly AGGREGATE_OP_MAP;
|
|
24
23
|
/**
|
|
25
24
|
* MongoDB stores the primary key as `_id`; everything else resolves as usual. Projections, sorts,
|
|
26
25
|
* `$group` refs and `$where` keys all map through here, so no read path can address a property name
|
|
@@ -39,14 +39,6 @@ export class MongoDialect extends AbstractDialect {
|
|
|
39
39
|
static ID_KEY = '_id';
|
|
40
40
|
/** Atlas rejects a `$vectorSearch` asking for more candidates than this. */
|
|
41
41
|
static MAX_NUM_CANDIDATES = 10_000;
|
|
42
|
-
// Direct field aggregates → MongoDB accumulator. `$count` is handled separately (COUNT(*) vs
|
|
43
|
-
// COUNT(field) differ), so it is not listed here.
|
|
44
|
-
static AGGREGATE_OP_MAP = new Map([
|
|
45
|
-
['$sum', '$sum'],
|
|
46
|
-
['$avg', '$avg'],
|
|
47
|
-
['$min', '$min'],
|
|
48
|
-
['$max', '$max'],
|
|
49
|
-
]);
|
|
50
42
|
/**
|
|
51
43
|
* MongoDB stores the primary key as `_id`; everything else resolves as usual. Projections, sorts,
|
|
52
44
|
* `$group` refs and `$where` keys all map through here, so no read path can address a property name
|
|
@@ -511,7 +503,7 @@ export class MongoDialect extends AbstractDialect {
|
|
|
511
503
|
*/
|
|
512
504
|
aliasSort(sort) {
|
|
513
505
|
const normalized = {};
|
|
514
|
-
for (const [alias, dir] of Object.entries(sort
|
|
506
|
+
for (const [alias, dir] of Object.entries(sort)) {
|
|
515
507
|
normalized[alias] = sortDirection(dir);
|
|
516
508
|
}
|
|
517
509
|
return normalized;
|
|
@@ -999,11 +991,8 @@ export class MongoDialect extends AbstractDialect {
|
|
|
999
991
|
entry.fieldRef === '*' ? { $sum: 1 } : { $sum: { $cond: [{ $ne: [ref, null] }, 1, 0] } };
|
|
1000
992
|
}
|
|
1001
993
|
else {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
throw TypeError(`unsupported aggregate operator: ${entry.op}`);
|
|
1005
|
-
}
|
|
1006
|
-
groupAccumulators[entry.alias] = { [mongoOp]: ref };
|
|
994
|
+
// `$sum`, `$avg`, `$min` and `$max` are MongoDB accumulators of the same name.
|
|
995
|
+
groupAccumulators[entry.alias] = { [entry.op]: ref };
|
|
1007
996
|
}
|
|
1008
997
|
}
|
|
1009
998
|
return { groupId, groupAccumulators, distinctReducers };
|
|
@@ -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,
|
|
3
|
+
import type { EntityData, ExtraOptions, PrimaryKey, Query, QueryAggMap, QueryAggregate, QueryAggregateResult, QueryConflictPaths, QueryFilter, QueryGroupMap, QueryOptions, QuerySearch, TransactionOptions, Type, UpdatePayload } from '../type/index.js';
|
|
4
4
|
import { type ParentPartition } from '../util/index.js';
|
|
5
5
|
import type { MongoDialect } from './mongoDialect.js';
|
|
6
6
|
export declare class MongodbQuerier extends AbstractQuerier {
|
|
@@ -56,7 +56,7 @@ export declare class MongodbQuerier extends AbstractQuerier {
|
|
|
56
56
|
* the floor, and skipped the relation-sort rejection {@link MongoDialect.sort} raises.
|
|
57
57
|
*/
|
|
58
58
|
private settleIds;
|
|
59
|
-
internalInsertMany<E extends Document>(entity: Type<E>,
|
|
59
|
+
internalInsertMany<E extends Document>(entity: Type<E>, rows: EntityData<E>[]): Promise<void>;
|
|
60
60
|
internalUpdateMany<E extends Document>(entity: Type<E>, qm: QuerySearch<E>, payload: UpdatePayload<E>, opts?: QueryOptions): Promise<number>;
|
|
61
61
|
/**
|
|
62
62
|
* `_id` is immutable, so a key the payload names can only be written on the insert branch of an
|
|
@@ -65,18 +65,16 @@ export declare class MongodbQuerier extends AbstractQuerier {
|
|
|
65
65
|
private upsertUpdate;
|
|
66
66
|
private buildConflictFilter;
|
|
67
67
|
protected internalUpsertOne<E extends Document>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>): Promise<{
|
|
68
|
-
|
|
68
|
+
ids: (PrimaryKey | undefined)[];
|
|
69
69
|
changes: number;
|
|
70
70
|
created: boolean;
|
|
71
71
|
}>;
|
|
72
72
|
protected internalUpsertMany<E extends Document>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>[]): Promise<{
|
|
73
73
|
changes: number;
|
|
74
74
|
ids?: undefined;
|
|
75
|
-
firstId?: undefined;
|
|
76
75
|
} | {
|
|
77
76
|
changes: number;
|
|
78
77
|
ids: (PrimaryKey | undefined)[];
|
|
79
|
-
firstId: PrimaryKey | undefined;
|
|
80
78
|
}>;
|
|
81
79
|
protected internalDeleteMany<E extends Document>(entity: Type<E>, qm: QuerySearch<E>, opts?: QueryOptions): Promise<number>;
|
|
82
80
|
get hasOpenTransaction(): boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { COUNT_ALIAS } from '../dialect/aliases.js';
|
|
2
2
|
import { hasRequiredJoin } from '../dialect/queryJoins.js';
|
|
3
|
-
import { getMeta, idOf, soleIdOf } from '../entity/index.js';
|
|
3
|
+
import { fieldOf, getMeta, idOf, namesKey, soleIdOf } from '../entity/index.js';
|
|
4
4
|
import { AbstractQuerier, enrichError } from '../querier/index.js';
|
|
5
5
|
import { clone, getKeys, getRelationRequestSummary, getSoftDeleteValue, hasKeys, idOnlyQuery, isPagedQuery, populatesRelations, queryChildrenOf, throwNoPendingTransaction, throwPendingTransaction, withoutSoftDeleteFilter, } from '../util/index.js';
|
|
6
6
|
/**
|
|
@@ -259,22 +259,17 @@ export class MongodbQuerier extends AbstractQuerier {
|
|
|
259
259
|
// are named the same way every other driver names them.
|
|
260
260
|
return (this.dialect.normalizeIds(meta, founds) || []).map((found) => idOf(meta, found));
|
|
261
261
|
}
|
|
262
|
-
async internalInsertMany(entity,
|
|
262
|
+
async internalInsertMany(entity, rows) {
|
|
263
263
|
return this.timed('internalInsertMany', undefined, async () => {
|
|
264
|
-
if (!payloads?.length) {
|
|
265
|
-
return [];
|
|
266
|
-
}
|
|
267
|
-
payloads = clone(payloads);
|
|
268
264
|
const meta = getMeta(entity);
|
|
269
|
-
const persistables = this.dialect.getPersistables(meta,
|
|
265
|
+
const persistables = this.dialect.getPersistables(meta, rows, 'onInsert');
|
|
270
266
|
const { insertedIds } = await this.execute((session) => this.collection(entity).insertMany(persistables, { session }));
|
|
271
267
|
const ids = Object.values(insertedIds).map((id) => this.dialect.fromWireId(id));
|
|
272
268
|
const idKey = soleIdOf(meta, 'insert');
|
|
273
|
-
for (
|
|
274
|
-
|
|
269
|
+
for (let index = 0; index < rows.length; index++) {
|
|
270
|
+
rows[index][idKey] = ids[index];
|
|
275
271
|
}
|
|
276
|
-
await this.insertRelations(entity,
|
|
277
|
-
return ids;
|
|
272
|
+
await this.insertRelations(entity, rows);
|
|
278
273
|
});
|
|
279
274
|
}
|
|
280
275
|
async internalUpdateMany(entity, qm, payload, opts) {
|
|
@@ -332,10 +327,11 @@ export class MongodbQuerier extends AbstractQuerier {
|
|
|
332
327
|
includeResultMetadata: true,
|
|
333
328
|
session,
|
|
334
329
|
}));
|
|
335
|
-
|
|
330
|
+
// Read off the document as written, which carries its `_id` on either branch.
|
|
331
|
+
const id = this.dialect.fromWireId(res?.value?._id);
|
|
336
332
|
// `updatedExisting` is false when a new document was inserted (upserted).
|
|
337
333
|
const created = res?.lastErrorObject?.['updatedExisting'] === false;
|
|
338
|
-
return {
|
|
334
|
+
return { ids: [id], changes: id === undefined ? 0 : 1, created };
|
|
339
335
|
});
|
|
340
336
|
}
|
|
341
337
|
async internalUpsertMany(entity, conflictPaths, payload) {
|
|
@@ -343,8 +339,10 @@ export class MongodbQuerier extends AbstractQuerier {
|
|
|
343
339
|
if (!payload?.length) {
|
|
344
340
|
return { changes: 0 };
|
|
345
341
|
}
|
|
346
|
-
payload = clone(payload);
|
|
347
342
|
const meta = getMeta(entity);
|
|
343
|
+
// Asked before `getPersistable` fills an `onInsert` key into rows it may only update.
|
|
344
|
+
const unnamed = payload.map((row) => !namesKey(meta, row));
|
|
345
|
+
payload = clone(payload);
|
|
348
346
|
const operations = payload.map((item) => {
|
|
349
347
|
const persistable = this.dialect.getPersistable(meta, item, 'onInsert');
|
|
350
348
|
const filter = this.buildConflictFilter(entity, conflictPaths, item);
|
|
@@ -359,23 +357,24 @@ export class MongodbQuerier extends AbstractQuerier {
|
|
|
359
357
|
});
|
|
360
358
|
const res = await this.execute((session) => this.collection(entity).bulkWrite(operations, { session }));
|
|
361
359
|
const changes = (res.upsertedCount ?? 0) + (res.modifiedCount ?? 0);
|
|
362
|
-
// `upsertedIds` only
|
|
363
|
-
// updated document's `_id` is
|
|
364
|
-
|
|
365
|
-
const ids = payload.map((_, index) => {
|
|
360
|
+
// `upsertedIds` names only the documents inserted, keyed by operation index, so each lands on
|
|
361
|
+
// its own row; an updated document's `_id` is read back by the conflict fields instead.
|
|
362
|
+
const reported = payload.map((_, index) => {
|
|
366
363
|
const id = res.upsertedIds[index];
|
|
367
364
|
return id === undefined ? undefined : this.dialect.fromWireId(id);
|
|
368
365
|
});
|
|
369
|
-
|
|
366
|
+
const unplaced = reported.some((id, index) => id === undefined && unnamed[index]);
|
|
367
|
+
const found = unplaced ? await this.idsByConflict(entity, conflictPaths, payload) : [];
|
|
368
|
+
return { changes, ids: reported.map((id, index) => id ?? found[index]) };
|
|
370
369
|
});
|
|
371
370
|
}
|
|
372
371
|
async internalDeleteMany(entity, qm, opts = {}) {
|
|
373
372
|
return this.timed('internalDeleteMany', undefined, async () => {
|
|
374
373
|
const meta = getMeta(entity);
|
|
375
374
|
// Soft-delete (stamp) unless `hardDelete` is requested or the entity has no soft-delete field.
|
|
376
|
-
const
|
|
375
|
+
const softDelete = opts.hardDelete ? undefined : meta.softDelete;
|
|
377
376
|
// Hard delete targets matching rows regardless of soft-delete state (keeps other filters).
|
|
378
|
-
const findOpts =
|
|
377
|
+
const findOpts = softDelete ? opts : { ...opts, filters: withoutSoftDeleteFilter(opts.filters) };
|
|
379
378
|
// Delete has always resolved its ids first (it stamps or removes them by `_id`), so a relation
|
|
380
379
|
// condition needs nothing extra here - and passing the whole query is what makes its page apply.
|
|
381
380
|
const ids = await this.settleIds(entity, qm, findOpts);
|
|
@@ -383,10 +382,11 @@ export class MongodbQuerier extends AbstractQuerier {
|
|
|
383
382
|
return 0;
|
|
384
383
|
}
|
|
385
384
|
let changes;
|
|
386
|
-
if (
|
|
385
|
+
if (softDelete) {
|
|
386
|
+
const field = fieldOf(meta, softDelete);
|
|
387
387
|
// Stamp the mapped column: reads filter on it, so a `@Field({ name })` mismatch here would
|
|
388
388
|
// report a successful delete and leave the row visible.
|
|
389
|
-
const softDeleteColumn = this.dialect.resolveColumnName(
|
|
389
|
+
const softDeleteColumn = this.dialect.resolveColumnName(softDelete, field);
|
|
390
390
|
const updateResult = await this.execute((session) => this.collection(entity).updateMany({ _id: { $in: this.dialect.toWireId(ids) } }, { $set: { [softDeleteColumn]: getSoftDeleteValue(field) } }, {
|
|
391
391
|
session,
|
|
392
392
|
}));
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type MongoClientOptions } from 'mongodb';
|
|
2
2
|
import { AbstractQuerierPool } from '../querier/index.js';
|
|
3
3
|
import type { ExtraOptions } from '../type/index.js';
|
|
4
|
-
import {
|
|
4
|
+
import { MongoDialect } from './mongoDialect.js';
|
|
5
5
|
import { MongodbQuerier } from './mongodbQuerier.js';
|
|
6
|
-
export declare class MongodbQuerierPool extends AbstractQuerierPool<MongodbQuerier,
|
|
6
|
+
export declare class MongodbQuerierPool extends AbstractQuerierPool<MongodbQuerier, MongoDialect> {
|
|
7
7
|
private readonly client;
|
|
8
8
|
constructor(uri: string, opts?: MongoClientOptions, extra?: ExtraOptions);
|
|
9
9
|
getQuerier(): Promise<MongodbQuerier>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { MongoClient } from 'mongodb';
|
|
2
2
|
import { dialectOptionsFrom } from '../dialect/abstractDialect.js';
|
|
3
3
|
import { AbstractQuerierPool } from '../querier/index.js';
|
|
4
|
-
import {
|
|
4
|
+
import { MongoDialect } from './mongoDialect.js';
|
|
5
5
|
import { MongodbQuerier } from './mongodbQuerier.js';
|
|
6
6
|
export class MongodbQuerierPool extends AbstractQuerierPool {
|
|
7
7
|
client;
|
|
8
8
|
constructor(uri, opts, extra) {
|
|
9
|
-
super(new
|
|
9
|
+
super(new MongoDialect(dialectOptionsFrom(extra)), extra);
|
|
10
10
|
this.client = new MongoClient(uri, opts);
|
|
11
11
|
}
|
|
12
12
|
async getQuerier() {
|
|
@@ -18,18 +18,18 @@ export declare class MsSqlDialect extends MergeSqlDialect {
|
|
|
18
18
|
readonly commitTransactionCommand = "COMMIT TRANSACTION";
|
|
19
19
|
readonly rollbackTransactionCommand = "ROLLBACK TRANSACTION";
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* the transaction opens on, and would then stick to that connection for unrelated later queries.
|
|
24
|
-
* `MsSqlQuerier` reads the level back off this command and hands it to the driver.
|
|
21
|
+
* T-SQL has no inline form, so the level is set before the `BEGIN`. What a driver that sends these
|
|
22
|
+
* as statements would run; `MsSqlQuerier` opens its transactions through the driver instead.
|
|
25
23
|
*/
|
|
26
|
-
readonly isolationLevelStrategy = "
|
|
24
|
+
readonly isolationLevelStrategy = "set-before";
|
|
27
25
|
readonly dropIndexSyntax = "on-table";
|
|
28
26
|
readonly booleanLiteral = "integer";
|
|
29
27
|
/** [The hard server limit](https://github.com/yiisoft/yii2/issues/10371), not a driver preference. */
|
|
30
28
|
readonly maxBindValues = 2100;
|
|
31
29
|
/** `OUTPUT` has no trailing form: it sits between the column list and `VALUES`. */
|
|
32
30
|
readonly returningPosition = "after-target";
|
|
31
|
+
/** Microsoft documents no row order for a `MERGE ... OUTPUT`. */
|
|
32
|
+
readonly upsertReturningOrdered = false;
|
|
33
33
|
readonly insertIdSource: InsertIdSource;
|
|
34
34
|
/** Holds the update key lock across the insert; without it two concurrent upserts of one key race. */
|
|
35
35
|
protected readonly mergeTargetHint = " WITH (HOLDLOCK)";
|
|
@@ -52,18 +52,18 @@ export class MsSqlDialect extends MergeSqlDialect {
|
|
|
52
52
|
commitTransactionCommand = 'COMMIT TRANSACTION';
|
|
53
53
|
rollbackTransactionCommand = 'ROLLBACK TRANSACTION';
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* the transaction opens on, and would then stick to that connection for unrelated later queries.
|
|
58
|
-
* `MsSqlQuerier` reads the level back off this command and hands it to the driver.
|
|
55
|
+
* T-SQL has no inline form, so the level is set before the `BEGIN`. What a driver that sends these
|
|
56
|
+
* as statements would run; `MsSqlQuerier` opens its transactions through the driver instead.
|
|
59
57
|
*/
|
|
60
|
-
isolationLevelStrategy = '
|
|
58
|
+
isolationLevelStrategy = 'set-before';
|
|
61
59
|
dropIndexSyntax = 'on-table';
|
|
62
60
|
booleanLiteral = 'integer';
|
|
63
61
|
/** [The hard server limit](https://github.com/yiisoft/yii2/issues/10371), not a driver preference. */
|
|
64
62
|
maxBindValues = 2100;
|
|
65
63
|
/** `OUTPUT` has no trailing form: it sits between the column list and `VALUES`. */
|
|
66
64
|
returningPosition = 'after-target';
|
|
65
|
+
/** Microsoft documents no row order for a `MERGE ... OUTPUT`. */
|
|
66
|
+
upsertReturningOrdered = false;
|
|
67
67
|
insertIdSource = 'returning';
|
|
68
68
|
/** Holds the update key lock across the insert; without it two concurrent upserts of one key race. */
|
|
69
69
|
mergeTargetHint = ' WITH (HOLDLOCK)';
|
|
@@ -268,11 +268,14 @@ export class MsSqlDialect extends MergeSqlDialect {
|
|
|
268
268
|
return typeof value === 'boolean' ? `CAST(${placeholder} AS BIT)` : placeholder;
|
|
269
269
|
}
|
|
270
270
|
/**
|
|
271
|
-
* An object or array bound as JSON, which is the half both binders
|
|
272
|
-
* `undefined` for a scalar - where they diverge.
|
|
271
|
+
* An object or array bound as JSON, or a `raw()` rendered in place, which is the half both binders
|
|
272
|
+
* spell the same way; `undefined` for a scalar - where they diverge.
|
|
273
273
|
*/
|
|
274
274
|
#jsonCompound(ctx, value) {
|
|
275
|
-
if (value
|
|
275
|
+
if (value instanceof QueryRaw) {
|
|
276
|
+
return this.rawFragment(ctx, value);
|
|
277
|
+
}
|
|
278
|
+
if (value === null || typeof value !== 'object') {
|
|
276
279
|
return undefined;
|
|
277
280
|
}
|
|
278
281
|
ctx.pushValue(JSON.stringify(value));
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ConnectionPool } from 'mssql';
|
|
2
2
|
import { AbstractPoolQuerier } from '../querier/abstractPoolQuerier.js';
|
|
3
|
-
import type {
|
|
4
|
-
import type { MsSqlDialect } from './mssqlDialect.js';
|
|
3
|
+
import type { QueryUpdateResult, TransactionOptions } from '../type/index.js';
|
|
5
4
|
/**
|
|
6
5
|
* A connection is a `ConnectionPool` handle here rather than a checked-out socket: `mssql` owns its
|
|
7
6
|
* own pool and hands out `Request`s, so what UQL holds is the pool plus, once a transaction opens,
|
|
@@ -9,15 +8,23 @@ import type { MsSqlDialect } from './mssqlDialect.js';
|
|
|
9
8
|
*/
|
|
10
9
|
export declare class MsSqlQuerier extends AbstractPoolQuerier<ConnectionPool> {
|
|
11
10
|
#private;
|
|
12
|
-
constructor(connect: () => Promise<ConnectionPool>, dialect: MsSqlDialect, extra?: ExtraOptions);
|
|
13
11
|
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
14
12
|
internalRun(query: string, values?: unknown[]): Promise<QueryUpdateResult>;
|
|
15
13
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* The driver's own stream over the request, which pauses the request while the loop is behind, so
|
|
15
|
+
* rows arrive only as fast as they are read. A failure the driver reports through the promise alone
|
|
16
|
+
* would leave the loop waiting for rows, so it ends the stream instead.
|
|
19
17
|
*/
|
|
20
18
|
internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* `mssql` owns its pool and hands out a `Request` per call, so a `BEGIN TRANSACTION` sent as text
|
|
21
|
+
* would open one on a connection the next call may not be given. Its `Transaction` object is the
|
|
22
|
+
* only thing that pins them together, so the transaction is that object rather than statements, and
|
|
23
|
+
* the level goes to its `begin`: sent as a statement it would land on whichever connection served it.
|
|
24
|
+
*/
|
|
25
|
+
protected internalBegin(opts?: TransactionOptions): Promise<void>;
|
|
26
|
+
protected internalCommit(): Promise<void>;
|
|
27
|
+
protected internalRollback(): Promise<void>;
|
|
21
28
|
/** The pool owns the socket; releasing a querier only drops this one's claim on it. */
|
|
22
29
|
protected releaseConn(_conn: ConnectionPool, _discard: boolean): Promise<void>;
|
|
23
30
|
}
|