uql-orm 0.64.0 → 0.65.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/bunSql/bunSqlQuerier.d.ts +3 -10
- package/dist/bunSql/bunSqlQuerier.js +2 -16
- package/dist/bunSql/bunSqlQuerierPool.d.ts +0 -2
- package/dist/bunSql/bunSqlQuerierPool.js +14 -16
- package/dist/d1/d1Querier.d.ts +13 -34
- package/dist/d1/d1Querier.js +1 -1
- package/dist/d1/d1QuerierPool.d.ts +3 -3
- package/dist/dialect/abstractDialect.d.ts +4 -9
- package/dist/dialect/abstractDialect.js +4 -5
- package/dist/dialect/abstractSqlDialect.d.ts +2 -2
- package/dist/dialect/index.d.ts +0 -1
- package/dist/dialect/index.js +2 -3
- package/dist/dialect/mysqlLikeSqlDialect.js +0 -3
- package/dist/dialect/pgLikeSqlDialect.d.ts +9 -1
- package/dist/dialect/pgLikeSqlDialect.js +8 -5
- package/dist/dialect/queryContext.d.ts +3 -3
- package/dist/entity/metadata/definition.d.ts +6 -0
- package/dist/entity/metadata/definition.js +109 -76
- package/dist/migrate/cli.d.ts +1 -1
- package/dist/migrate/cli.js +20 -34
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +5 -0
- package/dist/migrate/codegen/entityCodeGenerator.js +29 -7
- package/dist/migrate/codegen/indexDecoratorSource.js +1 -5
- package/dist/migrate/codegen/sourceLiteral.d.ts +2 -0
- package/dist/migrate/codegen/sourceLiteral.js +4 -0
- package/dist/migrate/index.d.ts +1 -1
- package/dist/migrate/index.js +1 -1
- package/dist/migrate/introspection/registry.d.ts +2 -2
- package/dist/migrate/introspection/registry.js +6 -11
- package/dist/migrate/migrationTarget.d.ts +6 -6
- package/dist/migrate/migrationTarget.js +18 -16
- package/dist/migrate/migrator.d.ts +3 -7
- package/dist/migrate/migrator.js +10 -31
- package/dist/migrate/schemaGenerator.d.ts +1 -3
- package/dist/migrate/schemaGenerator.js +0 -4
- package/dist/mongo/mongoDialect.d.ts +1 -1
- package/dist/mongo/mongoDialect.js +1 -4
- package/dist/mssql/mssqlDialect.js +0 -3
- package/dist/pglite/pgliteQuerier.d.ts +2 -6
- package/dist/pglite/pgliteQuerier.js +2 -9
- package/dist/postgres/index.d.ts +0 -1
- package/dist/postgres/index.js +0 -1
- package/dist/querier/abstractSharedHandleQuerierPool.d.ts +2 -5
- package/dist/querier/abstractSharedHandleQuerierPool.js +2 -5
- package/dist/querier/abstractSqlQuerier.d.ts +2 -3
- package/dist/querier/abstractSqlQuerier.js +8 -4
- package/dist/querier/cursorStream.d.ts +13 -0
- package/dist/{postgres/pgCursorStream.js → querier/cursorStream.js} +4 -13
- package/dist/schema/canonicalType.js +1 -1
- package/dist/schema/schemaASTBuilder.js +34 -40
- package/dist/sqlite/abstractSqliteQuerier.d.ts +7 -3
- package/dist/sqlite/abstractSqliteQuerier.js +18 -4
- package/dist/sqlite/hranaQuerier.d.ts +1 -1
- package/dist/sqlite/localSqliteQuerierPool.d.ts +7 -0
- package/dist/sqlite/localSqliteQuerierPool.js +19 -0
- package/dist/sqlite/nodeSqliteQuerierPool.js +2 -3
- package/dist/sqlite/sqliteDialect.js +0 -3
- package/dist/sqlite/sqliteQuerier.d.ts +8 -5
- package/dist/sqlite/sqliteQuerier.js +4 -13
- package/dist/sqlite/sqliteQuerierPool.js +4 -4
- package/dist/turso/tursoSessionQuerier.d.ts +2 -2
- package/dist/turso/tursoSessionQuerier.js +16 -18
- package/dist/type/dialect.d.ts +25 -35
- package/dist/type/entity.d.ts +26 -28
- package/dist/type/migratorDialect.d.ts +0 -9
- package/dist/type/migratorDialect.js +1 -16
- package/dist/type/querierPool.d.ts +0 -4
- package/dist/type/queryRaw.d.ts +2 -2
- package/dist/type/universalQuerier.d.ts +2 -2
- package/package.json +1 -3
- package/dist/postgres/pgCursorStream.d.ts +0 -20
- package/dist/postgres/postgresWireDriverCapabilities.d.ts +0 -21
- package/dist/postgres/postgresWireDriverCapabilities.js +0 -21
- package/dist/sqlite/bunSqliteAdapter.bun.d.ts +0 -27
- package/dist/sqlite/bunSqliteAdapter.bun.js +0 -25
- package/dist/sqlite/nodeSqliteAdapter.d.ts +0 -33
- package/dist/sqlite/nodeSqliteAdapter.js +0 -25
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isMongoQuerier, isSqlQuerier, } from '../type/index.js';
|
|
2
2
|
import { withMongoQuerierForMigrations, withSqlQuerierForMigrations } from './acquireQuerierForMigrations.js';
|
|
3
3
|
import { MigrationBuilder } from './builder/migrationBuilder.js';
|
|
4
4
|
import { migrationSource } from './codegen/migrationFile.js';
|
|
5
5
|
import { runMongoCommand } from './generator/mongoCommand.js';
|
|
6
|
-
import {
|
|
6
|
+
import { SqlSchemaGenerator } from './schemaGenerator.js';
|
|
7
7
|
import { DatabaseMigrationStorage } from './storage/databaseStorage.js';
|
|
8
8
|
import { MongoMigrationStorage } from './storage/mongoStorage.js';
|
|
9
9
|
const sqlSession = (querier) => ({
|
|
@@ -21,20 +21,22 @@ async function mongoSchemaGenerator(namingStrategy, defaultForeignKeyAction) {
|
|
|
21
21
|
const { MongoSchemaGenerator } = await import('./generator/mongoSchemaGenerator.js');
|
|
22
22
|
return new MongoSchemaGenerator(namingStrategy, defaultForeignKeyAction);
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
export function migrationTargetFor(pool, defaultForeignKeyAction) {
|
|
25
|
+
const { dialect } = pool;
|
|
26
|
+
if (dialect.dialectName === 'mongodb') {
|
|
27
|
+
return {
|
|
28
|
+
source: migrationSource.MongoQuerier,
|
|
29
|
+
storage: (tableName) => new MongoMigrationStorage(pool, { tableName }),
|
|
30
|
+
generator: () => mongoSchemaGenerator(dialect.namingStrategy, defaultForeignKeyAction),
|
|
31
|
+
withSession: (task) => withMongoQuerierForMigrations(pool, 'Migrator', (querier) => task(mongoSession(querier))),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
source: migrationSource.SqlQuerier,
|
|
36
|
+
storage: (tableName) => new DatabaseMigrationStorage(pool, { tableName }),
|
|
37
|
+
generator: async () => new SqlSchemaGenerator(dialect, defaultForeignKeyAction),
|
|
38
|
+
withSession: (task) => withSqlQuerierForMigrations(pool, 'Migrator', (querier) => task(sqlSession(querier))),
|
|
39
|
+
};
|
|
38
40
|
}
|
|
39
41
|
/** A builder running each operation on `querier`, as SQL or as MongoDB driver commands. */
|
|
40
42
|
export async function migrationBuilderFor(querier) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LoggingOptions, Migration, MigrationDefinition, MigrationResult, MigrationStorage, MigratorDialect, MigratorOptions, Querier, QuerierPool, SchemaDiff, SchemaGenerator, SchemaIntrospector, SqlQuerier, SyncOptions, Type } from '../type/index.js';
|
|
2
2
|
import { LoggerWrapper } from '../util/index.js';
|
|
3
3
|
import type { IMigrationBuilder } from './builder/types.js';
|
|
4
4
|
/**
|
|
@@ -13,17 +13,13 @@ export declare class Migrator {
|
|
|
13
13
|
set logger(value: LoggingOptions);
|
|
14
14
|
private readonly _entities?;
|
|
15
15
|
get entities(): Type<object>[];
|
|
16
|
-
readonly dialectName: DialectName;
|
|
17
16
|
/** The generator given, or this dialect's once {@link getSchemaGenerator} has loaded it. */
|
|
18
17
|
schemaGenerator?: SchemaGenerator;
|
|
19
|
-
schemaIntrospector
|
|
20
|
-
private readonly defaultForeignKeyAction?;
|
|
18
|
+
schemaIntrospector: SchemaIntrospector;
|
|
21
19
|
private readonly target;
|
|
22
20
|
constructor(pool: QuerierPool<Querier, MigratorDialect>, options?: MigratorOptions);
|
|
23
21
|
/** The schema generator, loaded on first use: MongoDB's needs its optional peer. */
|
|
24
22
|
getSchemaGenerator(): Promise<SchemaGenerator>;
|
|
25
|
-
/** `schema` reads one namespace instead of the connection's own; see {@link BaseSqlIntrospector.schema}. */
|
|
26
|
-
protected createIntrospector(schema?: string): SchemaIntrospector | undefined;
|
|
27
23
|
/**
|
|
28
24
|
* Get all discovered migrations from the migrations directory
|
|
29
25
|
*/
|
|
@@ -112,7 +108,7 @@ export declare class Migrator {
|
|
|
112
108
|
/** The configured entities, with `entity` among them however the migrator was built. */
|
|
113
109
|
private entitiesWith;
|
|
114
110
|
/** The introspector for a claimed schema, which is the connection's own where none is claimed. */
|
|
115
|
-
private
|
|
111
|
+
private schemaIntrospectorFor;
|
|
116
112
|
/**
|
|
117
113
|
* The DDL {@link sync} would run, without running it. Separate so `--dry-run` shows the real
|
|
118
114
|
* statements rather than a summary of a second, differently-computed diff.
|
package/dist/migrate/migrator.js
CHANGED
|
@@ -25,36 +25,25 @@ export class Migrator {
|
|
|
25
25
|
get entities() {
|
|
26
26
|
return this._entities ?? getEntities();
|
|
27
27
|
}
|
|
28
|
-
dialectName;
|
|
29
28
|
/** The generator given, or this dialect's once {@link getSchemaGenerator} has loaded it. */
|
|
30
29
|
schemaGenerator;
|
|
31
30
|
schemaIntrospector;
|
|
32
|
-
defaultForeignKeyAction;
|
|
33
31
|
target;
|
|
34
32
|
constructor(pool, options = {}) {
|
|
35
33
|
this.pool = pool;
|
|
36
|
-
this.
|
|
37
|
-
this.
|
|
38
|
-
this.defaultForeignKeyAction = options.defaultForeignKeyAction;
|
|
39
|
-
this.storage = options.storage ?? this.target.storage(pool, options.tableName);
|
|
34
|
+
this.target = migrationTargetFor(pool, options.defaultForeignKeyAction);
|
|
35
|
+
this.storage = options.storage ?? this.target.storage(options.tableName);
|
|
40
36
|
this.migrationsPath = options.migrationsPath ?? './migrations';
|
|
41
37
|
this._logger = new LoggerWrapper(options.logger, { logValues: options.logValues, slowQuery: options.slowQuery });
|
|
42
38
|
this._entities = options.entities;
|
|
43
|
-
this.schemaIntrospector =
|
|
39
|
+
this.schemaIntrospector = introspectorFor(pool);
|
|
44
40
|
this.schemaGenerator = options.schemaGenerator;
|
|
45
41
|
}
|
|
46
42
|
/** The schema generator, loaded on first use: MongoDB's needs its optional peer. */
|
|
47
43
|
async getSchemaGenerator() {
|
|
48
|
-
this.schemaGenerator ??= await this.target.generator(
|
|
49
|
-
if (!this.schemaGenerator) {
|
|
50
|
-
throw new TypeError(`No schema generator for dialect '${this.dialectName}'`);
|
|
51
|
-
}
|
|
44
|
+
this.schemaGenerator ??= await this.target.generator();
|
|
52
45
|
return this.schemaGenerator;
|
|
53
46
|
}
|
|
54
|
-
/** `schema` reads one namespace instead of the connection's own; see {@link BaseSqlIntrospector.schema}. */
|
|
55
|
-
createIntrospector(schema) {
|
|
56
|
-
return introspectorFor(this.dialectName, this.pool, schema);
|
|
57
|
-
}
|
|
58
47
|
/**
|
|
59
48
|
* Get all discovered migrations from the migrations directory
|
|
60
49
|
*/
|
|
@@ -133,7 +122,7 @@ export class Migrator {
|
|
|
133
122
|
*/
|
|
134
123
|
async runMigration(migration, direction) {
|
|
135
124
|
const startTime = Date.now();
|
|
136
|
-
return this.target.withSession(
|
|
125
|
+
return this.target.withSession(async ({ querier, transaction }) => {
|
|
137
126
|
try {
|
|
138
127
|
this.logger.logMigration(`${direction === 'up' ? 'Running' : 'Reverting'} migration: ${migration.name}`);
|
|
139
128
|
await transaction(async () => {
|
|
@@ -222,9 +211,6 @@ export class Migrator {
|
|
|
222
211
|
*/
|
|
223
212
|
async getDiffs() {
|
|
224
213
|
const generator = await this.getSchemaGenerator();
|
|
225
|
-
if (!this.schemaIntrospector) {
|
|
226
|
-
throw new TypeError(`No introspector for dialect '${this.dialectName}'`);
|
|
227
|
-
}
|
|
228
214
|
const ast = await this.introspectClaimedSchemas();
|
|
229
215
|
// Both sides built once: the database's above, the entities' here. Left to `diffSchema`, each
|
|
230
216
|
// entity would rebuild the whole AST, which is quadratic in the number of entities. Absent on a
|
|
@@ -247,11 +233,7 @@ export class Migrator {
|
|
|
247
233
|
const claimed = new Set(this.entities.map((entity) => this.pool.dialect.resolveSchema(getMeta(entity))));
|
|
248
234
|
const merged = new SchemaAST();
|
|
249
235
|
for (const schema of claimed) {
|
|
250
|
-
const
|
|
251
|
-
if (!introspector) {
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
for (const table of (await introspectSchema(introspector)).getTables()) {
|
|
236
|
+
for (const table of (await introspectSchema(this.schemaIntrospectorFor(schema))).getTables()) {
|
|
255
237
|
merged.addTable(table);
|
|
256
238
|
}
|
|
257
239
|
}
|
|
@@ -294,10 +276,7 @@ export class Migrator {
|
|
|
294
276
|
*/
|
|
295
277
|
async planEntity(generator, entity, options) {
|
|
296
278
|
const meta = getMeta(entity);
|
|
297
|
-
const introspector = this.
|
|
298
|
-
if (!introspector) {
|
|
299
|
-
throw new TypeError(`No introspector for '${meta.entity.name}' on '${this.dialectName}'`);
|
|
300
|
-
}
|
|
279
|
+
const introspector = this.schemaIntrospectorFor(this.pool.dialect.resolveSchema(meta));
|
|
301
280
|
const tableName = generator.resolveTableName(meta);
|
|
302
281
|
return (await introspector.tableExists(tableName))
|
|
303
282
|
? this.alterFromEntity(generator, entity, (await introspectSchema(introspector)).getTable(tableName), options)
|
|
@@ -319,8 +298,8 @@ export class Migrator {
|
|
|
319
298
|
return entities.includes(entity) ? entities : [...entities, entity];
|
|
320
299
|
}
|
|
321
300
|
/** The introspector for a claimed schema, which is the connection's own where none is claimed. */
|
|
322
|
-
|
|
323
|
-
return schema === undefined ? this.schemaIntrospector : this.
|
|
301
|
+
schemaIntrospectorFor(schema) {
|
|
302
|
+
return schema === undefined ? this.schemaIntrospector : introspectorFor(this.pool, schema);
|
|
324
303
|
}
|
|
325
304
|
/**
|
|
326
305
|
* The DDL {@link sync} would run, without running it. Separate so `--dry-run` shows the real
|
|
@@ -399,7 +378,7 @@ export class Migrator {
|
|
|
399
378
|
}
|
|
400
379
|
/** Runs the statements a generator wrote, in one transaction where the engine takes DDL in one. */
|
|
401
380
|
async executeSyncStatements(statements, options) {
|
|
402
|
-
await this.target.withSession(
|
|
381
|
+
await this.target.withSession(({ run, transaction }) => transaction(async () => {
|
|
403
382
|
for (const statement of statements) {
|
|
404
383
|
if (options.logging)
|
|
405
384
|
this.logger.logSchema(`Executing: ${statement}`);
|
|
@@ -2,7 +2,7 @@ import type { AbstractSqlDialect } from '../dialect/index.js';
|
|
|
2
2
|
import type { SchemaAST } from '../schema/schemaAST.js';
|
|
3
3
|
import { type DiffOptions } from '../schema/schemaASTDiffer.js';
|
|
4
4
|
import type { CanonicalType, ColumnNode, ForeignKeyAction, IndexNode, TableNode } from '../schema/types.js';
|
|
5
|
-
import type { ColumnSchema, CreateSchemaOptions, DialectFeatures, DropSchemaOptions, EntityMeta, EntityWhereMeta, FieldMeta, FieldOptions, ForeignKeySchema, IndexSchema,
|
|
5
|
+
import type { ColumnSchema, CreateSchemaOptions, DialectFeatures, DropSchemaOptions, EntityMeta, EntityWhereMeta, FieldMeta, FieldOptions, ForeignKeySchema, IndexSchema, NamingStrategy, SchemaDiff, SchemaGenerator, Type } from '../type/index.js';
|
|
6
6
|
import type { AnyMigrationOperation, FullColumnDefinition, IndexDefinition, TableDefinition } from './builder/types.js';
|
|
7
7
|
import { type IndexDdl, type TableDdl } from './ddl/index.js';
|
|
8
8
|
/**
|
|
@@ -222,5 +222,3 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
|
|
|
222
222
|
* table of a project using a naming strategy as both missing and unexpected.
|
|
223
223
|
*/
|
|
224
224
|
export declare function buildEntityAST(generator: Pick<SchemaGenerator, 'resolveTableAlias' | 'resolveSchema' | 'resolveColumnName' | 'compileDdl' | 'compileIndexPredicate'>, entities: readonly Type<object>[], defaultForeignKeyAction?: ForeignKeyAction): SchemaAST;
|
|
225
|
-
/** The SQL schema generator for `dialect`, `undefined` on MongoDB, whose generator needs its optional peer. */
|
|
226
|
-
export declare function createSchemaGenerator(dialect: MigratorDialect, defaultForeignKeyAction?: ForeignKeyAction): SqlSchemaGenerator | undefined;
|
|
@@ -766,7 +766,3 @@ export function buildEntityAST(generator, entities, defaultForeignKeyAction) {
|
|
|
766
766
|
defaultForeignKeyAction,
|
|
767
767
|
});
|
|
768
768
|
}
|
|
769
|
-
/** The SQL schema generator for `dialect`, `undefined` on MongoDB, whose generator needs its optional peer. */
|
|
770
|
-
export function createSchemaGenerator(dialect, defaultForeignKeyAction) {
|
|
771
|
-
return dialect.dialectName === 'mongodb' ? undefined : new SqlSchemaGenerator(dialect, defaultForeignKeyAction);
|
|
772
|
-
}
|
|
@@ -15,7 +15,7 @@ type RelationLookups = {
|
|
|
15
15
|
readonly stages: MongoAggregationPipelineEntry<Document>[];
|
|
16
16
|
readonly temps: string[];
|
|
17
17
|
};
|
|
18
|
-
/** Default {@link DialectFeatures} for MongoDB
|
|
18
|
+
/** Default {@link DialectFeatures} for MongoDB. */
|
|
19
19
|
export declare const mongoDialectFeatures: DialectFeatures;
|
|
20
20
|
export declare class MongoDialect extends AbstractDialect {
|
|
21
21
|
#private;
|
|
@@ -6,11 +6,8 @@ import { assertSoleId, fieldOf, getMeta, relationOf, soleIdOf } from '../entity/
|
|
|
6
6
|
import { COUNT_RESULT_KEY } from '../type/query.js';
|
|
7
7
|
import { QueryRaw } from '../type/queryRaw.js';
|
|
8
8
|
import { asSelectMap, assertAggregateColumns, assertNonNegativeInteger, columnFamily, countedRelations, entityName, fillOnFields, filterFieldKeys, findVectorIndex, findVectorSort, getKeys, getRelationRequestSummary, hasKeys, isJsonUpdateOp, isOperatorMap, isOperatorObject, isVectorSearch, normalizeScalarFieldSelection, parentJoins, parseGroupMap, parseRelationAtKey, parseRelationSize, parseSortByCount, someKey, targetKeyColumns, } from '../util/index.js';
|
|
9
|
-
/** Default {@link DialectFeatures} for MongoDB
|
|
9
|
+
/** Default {@link DialectFeatures} for MongoDB. */
|
|
10
10
|
export const mongoDialectFeatures = {
|
|
11
|
-
explicitJsonCast: false,
|
|
12
|
-
nativeArrays: false,
|
|
13
|
-
supportsJsonb: false,
|
|
14
11
|
ifNotExists: false,
|
|
15
12
|
indexIfNotExists: false,
|
|
16
13
|
schemas: false, // the connection picks the database, and a collection name takes no dot
|
|
@@ -20,9 +20,6 @@ import { escapeSingleQuotes } from '../util/sqlLiteral.js';
|
|
|
20
20
|
*/
|
|
21
21
|
export class MsSqlDialect extends MergeSqlDialect {
|
|
22
22
|
featureDefaults = {
|
|
23
|
-
explicitJsonCast: false,
|
|
24
|
-
nativeArrays: false,
|
|
25
|
-
supportsJsonb: false,
|
|
26
23
|
// Neither object takes an `IF NOT EXISTS`; both need a `sys` catalogue lookup around them, which
|
|
27
24
|
// the generator does not emit.
|
|
28
25
|
ifNotExists: false,
|
|
@@ -20,10 +20,8 @@ export type PgliteDatabase = {
|
|
|
20
20
|
/**
|
|
21
21
|
* Querier for PGlite, Postgres compiled to WASM and run in this process.
|
|
22
22
|
*
|
|
23
|
-
* @remarks Extends {@link AbstractSqlQuerier} rather than `PgQuerier`, whose `
|
|
24
|
-
*
|
|
25
|
-
* streaming pages the rows in SQL instead. `BEGIN`/`COMMIT` are plain statements on the single
|
|
26
|
-
* connection, leaving transactions to the base class.
|
|
23
|
+
* @remarks Extends {@link AbstractSqlQuerier} rather than `PgQuerier`, whose stream needs `pg-query-stream`,
|
|
24
|
+
* which PGlite's client cannot run. `BEGIN`/`COMMIT` are plain statements on the single connection.
|
|
27
25
|
*/
|
|
28
26
|
export declare class PgliteQuerier extends AbstractSqlQuerier {
|
|
29
27
|
readonly db: PgliteDatabase;
|
|
@@ -31,8 +29,6 @@ export declare class PgliteQuerier extends AbstractSqlQuerier {
|
|
|
31
29
|
constructor(db: PgliteDatabase, dialect: PostgresDialect, extra?: ExtraOptions | undefined);
|
|
32
30
|
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
33
31
|
internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
|
|
34
|
-
/** Postgres compiled to WASM is still Postgres: `DECLARE`/`FETCH` streams what the client cannot. */
|
|
35
|
-
protected internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, any>;
|
|
36
32
|
/** The handle belongs to the pool, which hands out one querier per unit of work over it. */
|
|
37
33
|
internalRelease(): Promise<void>;
|
|
38
34
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { streamViaCursor } from '../postgres/pgCursorStream.js';
|
|
2
1
|
import { AbstractSqlQuerier } from '../querier/index.js';
|
|
3
2
|
/**
|
|
4
3
|
* Querier for PGlite, Postgres compiled to WASM and run in this process.
|
|
5
4
|
*
|
|
6
|
-
* @remarks Extends {@link AbstractSqlQuerier} rather than `PgQuerier`, whose `
|
|
7
|
-
*
|
|
8
|
-
* streaming pages the rows in SQL instead. `BEGIN`/`COMMIT` are plain statements on the single
|
|
9
|
-
* connection, leaving transactions to the base class.
|
|
5
|
+
* @remarks Extends {@link AbstractSqlQuerier} rather than `PgQuerier`, whose stream needs `pg-query-stream`,
|
|
6
|
+
* which PGlite's client cannot run. `BEGIN`/`COMMIT` are plain statements on the single connection.
|
|
10
7
|
*/
|
|
11
8
|
export class PgliteQuerier extends AbstractSqlQuerier {
|
|
12
9
|
db;
|
|
@@ -26,10 +23,6 @@ export class PgliteQuerier extends AbstractSqlQuerier {
|
|
|
26
23
|
// where the latter also counts a `SELECT`'s rows and is absent altogether from a DDL tag.
|
|
27
24
|
return this.buildUpdateResult({ rows: res.rows, changes: res.affectedRows ?? 0 });
|
|
28
25
|
}
|
|
29
|
-
/** Postgres compiled to WASM is still Postgres: `DECLARE`/`FETCH` streams what the client cannot. */
|
|
30
|
-
async *internalStream(query, values) {
|
|
31
|
-
yield* streamViaCursor((sql, params) => this.internalAll(sql, params), query, values, this.hasOpenTransaction);
|
|
32
|
-
}
|
|
33
26
|
/** The handle belongs to the pool, which hands out one querier per unit of work over it. */
|
|
34
27
|
async internalRelease() { }
|
|
35
28
|
}
|
package/dist/postgres/index.d.ts
CHANGED
package/dist/postgres/index.js
CHANGED
|
@@ -15,13 +15,10 @@ import { AbstractSqlQuerierPool } from './abstractSqlQuerierPool.js';
|
|
|
15
15
|
* into the transaction already open - see {@link PgliteQuerierPool}, which is why that one is worth
|
|
16
16
|
* saying out loud.
|
|
17
17
|
*
|
|
18
|
-
* Subclasses supply only how to open the handle and how to wrap it
|
|
19
|
-
* takes `buildQuerier` alone. The lazy open and the close were written out once per pool before, along
|
|
20
|
-
* with three partial copies of the paragraph above.
|
|
18
|
+
* Subclasses supply only how to open the handle and how to wrap it.
|
|
21
19
|
*
|
|
22
20
|
* @remarks Deliberately not re-exported from `querier/index.ts`, which the root entry point re-exports:
|
|
23
|
-
* only the
|
|
24
|
-
* is imported.
|
|
21
|
+
* only the driver entries that open a single handle need this, and each imports it by path.
|
|
25
22
|
*/
|
|
26
23
|
export declare abstract class AbstractSharedHandleQuerierPool<DB extends {
|
|
27
24
|
close(): unknown;
|
|
@@ -13,13 +13,10 @@ import { AbstractSqlQuerierPool } from './abstractSqlQuerierPool.js';
|
|
|
13
13
|
* into the transaction already open - see {@link PgliteQuerierPool}, which is why that one is worth
|
|
14
14
|
* saying out loud.
|
|
15
15
|
*
|
|
16
|
-
* Subclasses supply only how to open the handle and how to wrap it
|
|
17
|
-
* takes `buildQuerier` alone. The lazy open and the close were written out once per pool before, along
|
|
18
|
-
* with three partial copies of the paragraph above.
|
|
16
|
+
* Subclasses supply only how to open the handle and how to wrap it.
|
|
19
17
|
*
|
|
20
18
|
* @remarks Deliberately not re-exported from `querier/index.ts`, which the root entry point re-exports:
|
|
21
|
-
* only the
|
|
22
|
-
* is imported.
|
|
19
|
+
* only the driver entries that open a single handle need this, and each imports it by path.
|
|
23
20
|
*/
|
|
24
21
|
export class AbstractSharedHandleQuerierPool extends AbstractSqlQuerierPool {
|
|
25
22
|
/**
|
|
@@ -80,9 +80,8 @@ export declare abstract class AbstractSqlQuerier extends AbstractQuerier impleme
|
|
|
80
80
|
private hydrateRows;
|
|
81
81
|
protected internalFindManyStream<E extends object>(entity: Type<E>, q: Query<E>, opts?: QueryOptions): AsyncGenerator<Awaited<E>, void, unknown>;
|
|
82
82
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* Drivers with native cursor/streaming APIs (SQLite, Pg) should override this.
|
|
83
|
+
* A read's rows one at a time: paged through a server-side cursor where the engine has one, read whole
|
|
84
|
+
* where it has none. A driver that streams on its own overrides this.
|
|
86
85
|
*/
|
|
87
86
|
protected internalStream<T>(query: string, values?: unknown[]): AsyncIterable<T>;
|
|
88
87
|
/**
|
|
@@ -4,6 +4,7 @@ import { getMeta, idOf, namesKey } from '../entity/index.js';
|
|
|
4
4
|
import { COUNT_RESULT_KEY } from '../type/index.js';
|
|
5
5
|
import { buildUpdateResult, cascadesOnDelete, clone, getInsertFieldKeys, insertShapeOf, idOnlyQuery, isAutoIncrement, isPagedQuery, isRecord, obtainAttrsPaths, throwNoPendingTransaction, throwPendingTransaction, unflatObject, unflatObjects, whereIds, withoutSoftDeleteFilter, } from '../util/index.js';
|
|
6
6
|
import { AbstractQuerier } from './abstractQuerier.js';
|
|
7
|
+
import { streamViaCursor } from './cursorStream.js';
|
|
7
8
|
import { enrichError } from './queryError.js';
|
|
8
9
|
/**
|
|
9
10
|
* Row indexes grouped by whether the caller supplied the key, payload order kept within each group.
|
|
@@ -240,12 +241,15 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
240
241
|
}
|
|
241
242
|
}
|
|
242
243
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* Drivers with native cursor/streaming APIs (SQLite, Pg) should override this.
|
|
244
|
+
* A read's rows one at a time: paged through a server-side cursor where the engine has one, read whole
|
|
245
|
+
* where it has none. A driver that streams on its own overrides this.
|
|
246
246
|
*/
|
|
247
247
|
async *internalStream(query, values) {
|
|
248
|
-
|
|
248
|
+
if (!this.dialect.features.serverSideCursors) {
|
|
249
|
+
yield* await this.internalAll(query, values);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
yield* streamViaCursor((sql, params) => this.internalAll(sql, params), query, values, this.hasOpenTransaction);
|
|
249
253
|
}
|
|
250
254
|
/**
|
|
251
255
|
* Turn what a driver returned back into the types the entity declares, for every row and everything
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs one statement of the cursor protocol on the querier's own connection, which holds the cursor, and
|
|
3
|
+
* not through `all()`, whose `serialize` is not re-entrant.
|
|
4
|
+
*/
|
|
5
|
+
type CursorExecutor<T> = (query: string, values?: unknown[]) => Promise<T[]>;
|
|
6
|
+
/**
|
|
7
|
+
* Streams a Postgres-wire read through a server-side cursor. `DECLARE` needs a transaction, so one is
|
|
8
|
+
* opened on the connection itself when the caller has none, leaving the querier's state untouched.
|
|
9
|
+
* Cleanup sits in `finally`, which a consumer that stops early still reaches, and is best-effort once
|
|
10
|
+
* the read failed, so the read's error stays the one thrown.
|
|
11
|
+
*/
|
|
12
|
+
export declare function streamViaCursor<T>(exec: CursorExecutor<T>, query: string, values?: unknown[], inTransaction?: boolean): AsyncIterable<T>;
|
|
13
|
+
export {};
|
|
@@ -4,17 +4,10 @@ const CURSOR_ALIAS = '_uql_cursor';
|
|
|
4
4
|
const FETCH_SIZE = 100;
|
|
5
5
|
let cursorSeq = 0;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `DECLARE` is only legal inside a transaction, so one is opened here when the caller has none - and
|
|
12
|
-
* then committed, or rolled back if the stream failed. That `BEGIN` goes straight to the connection
|
|
13
|
-
* rather than through `beginTransaction`, so the querier's own transaction state stays untouched:
|
|
14
|
-
* this one is the generator's, and ends with it.
|
|
15
|
-
*
|
|
16
|
-
* The cleanup lives in `finally` because a consumer that stops early (`break`, a `throw` downstream)
|
|
17
|
-
* ends the generator there and nowhere else, and an abandoned cursor holds its transaction open.
|
|
7
|
+
* Streams a Postgres-wire read through a server-side cursor. `DECLARE` needs a transaction, so one is
|
|
8
|
+
* opened on the connection itself when the caller has none, leaving the querier's state untouched.
|
|
9
|
+
* Cleanup sits in `finally`, which a consumer that stops early still reaches, and is best-effort once
|
|
10
|
+
* the read failed, so the read's error stays the one thrown.
|
|
18
11
|
*/
|
|
19
12
|
export async function* streamViaCursor(exec, query, values, inTransaction = false) {
|
|
20
13
|
const cursor = `${CURSOR_ALIAS}_${++cursorSeq}`;
|
|
@@ -38,8 +31,6 @@ export async function* streamViaCursor(exec, query, values, inTransaction = fals
|
|
|
38
31
|
throw err;
|
|
39
32
|
}
|
|
40
33
|
finally {
|
|
41
|
-
// Best-effort once the stream has failed: an error raised here would replace the one that brought
|
|
42
|
-
// us here, which is the one worth reporting, and the rollback discards the cursor either way.
|
|
43
34
|
const end = failed ? (sql) => exec(sql).catch(() => []) : exec;
|
|
44
35
|
await end(`CLOSE ${cursor}`);
|
|
45
36
|
if (ownsTransaction) {
|
|
@@ -338,7 +338,7 @@ export function canonicalToSql(type, dialect) {
|
|
|
338
338
|
}
|
|
339
339
|
return type.unsigned && features.supportsUnsigned ? `${sqlType} UNSIGNED` : sqlType;
|
|
340
340
|
}
|
|
341
|
-
/** See {@link
|
|
341
|
+
/** See {@link DialectFeatures.stringSizing} for what each mode means. */
|
|
342
342
|
function formatStringSqlType(type, base, sizing) {
|
|
343
343
|
if (sizing === 'text') {
|
|
344
344
|
return base;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - Entity metadata (decorator-based entities)
|
|
6
6
|
* - Database introspection results (TableSchema[])
|
|
7
7
|
*/
|
|
8
|
-
import { getMeta, soleIdOf } from '../entity/metadata/definition.js';
|
|
8
|
+
import { foreignKeysOf, getMeta, soleIdOf } from '../entity/metadata/definition.js';
|
|
9
9
|
import { declaredIndexes, indexNameParts, renderIndexColumn } from '../util/ddlExpression.util.js';
|
|
10
10
|
import { isInlinedExpression } from '../util/field.util.js';
|
|
11
11
|
import { isSoleIdField } from '../util/field.util.js';
|
|
@@ -124,54 +124,48 @@ function tableOf(ctx, meta) {
|
|
|
124
124
|
return ctx.ast.getTable(qualifyName(ctx.resolveTableName(meta), ctx.resolveSchema(meta)));
|
|
125
125
|
}
|
|
126
126
|
/**
|
|
127
|
-
* Add
|
|
127
|
+
* Add a relationship for each foreign key the entity holds, whether a relation declares it or a bare
|
|
128
|
+
* `@Field({ references })` does.
|
|
128
129
|
*/
|
|
129
130
|
function addRelationshipsFromEntity(ctx, meta) {
|
|
130
131
|
const table = tableOf(ctx, meta);
|
|
131
132
|
if (!table)
|
|
132
133
|
return;
|
|
133
|
-
for (const
|
|
134
|
-
const relatedMeta = getMeta(
|
|
134
|
+
for (const foreignKey of foreignKeysOf(meta)) {
|
|
135
|
+
const relatedMeta = getMeta(foreignKey.entity());
|
|
135
136
|
const relatedTable = tableOf(ctx, relatedMeta);
|
|
136
137
|
if (!relatedTable)
|
|
137
138
|
continue;
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const localColumn = localField && table.columns.get(ctx.resolveColumnName(localProp, localField));
|
|
152
|
-
const foreignColumn = foreignField && relatedTable.columns.get(ctx.resolveColumnName(foreignProp, foreignField));
|
|
153
|
-
if (!localColumn || !foreignColumn)
|
|
154
|
-
break;
|
|
155
|
-
localColumns.push(localColumn);
|
|
156
|
-
foreignColumns.push(foreignColumn);
|
|
157
|
-
}
|
|
158
|
-
// A pair that cannot be resolved drops the whole constraint: half of one enforces a rule
|
|
159
|
-
// nobody declared, over a subset of the key.
|
|
160
|
-
if (localColumns.length !== relation.references.length)
|
|
161
|
-
continue;
|
|
162
|
-
ctx.ast.addRelationship({
|
|
163
|
-
name: derivedForeignKeyName(table.name, localColumns.map((column) => column.name)),
|
|
164
|
-
type: relation.cardinality === 'm1' ? 'ManyToOne' : 'OneToOne',
|
|
165
|
-
from: { table, columns: localColumns },
|
|
166
|
-
to: { table: relatedTable, columns: foreignColumns },
|
|
167
|
-
// Falls back to the FK column's own `onDelete`, which is what makes a bare `@Field({
|
|
168
|
-
// references, onDelete })` work with no relation declared at all.
|
|
169
|
-
onDelete: relation.onDelete ?? meta.fields[relation.references[0].local]?.onDelete ?? ctx.defaultForeignKeyAction,
|
|
170
|
-
onUpdate: relation.onUpdate ?? ctx.defaultForeignKeyAction,
|
|
171
|
-
confidence: 1.0,
|
|
172
|
-
inferredFrom: 'entity_decorator',
|
|
173
|
-
});
|
|
139
|
+
// Every pair, not just the first: a composite key is one constraint over all its columns, and
|
|
140
|
+
// the engine requires the referenced columns to match a unique constraint as a whole.
|
|
141
|
+
const localColumns = [];
|
|
142
|
+
const foreignColumns = [];
|
|
143
|
+
for (const { local: localProp, foreign: foreignProp } of foreignKey.references) {
|
|
144
|
+
const localField = meta.fields[localProp];
|
|
145
|
+
const foreignField = relatedMeta.fields[foreignProp];
|
|
146
|
+
const localColumn = localField && table.columns.get(ctx.resolveColumnName(localProp, localField));
|
|
147
|
+
const foreignColumn = foreignField && relatedTable.columns.get(ctx.resolveColumnName(foreignProp, foreignField));
|
|
148
|
+
if (!localColumn || !foreignColumn)
|
|
149
|
+
break;
|
|
150
|
+
localColumns.push(localColumn);
|
|
151
|
+
foreignColumns.push(foreignColumn);
|
|
174
152
|
}
|
|
153
|
+
// A pair that cannot be resolved drops the whole constraint: half of one enforces a rule
|
|
154
|
+
// nobody declared, over a subset of the key.
|
|
155
|
+
if (localColumns.length !== foreignKey.references.length)
|
|
156
|
+
continue;
|
|
157
|
+
ctx.ast.addRelationship({
|
|
158
|
+
name: derivedForeignKeyName(table.name, localColumns.map((column) => column.name)),
|
|
159
|
+
type: foreignKey.cardinality === 'm1' ? 'ManyToOne' : 'OneToOne',
|
|
160
|
+
from: { table, columns: localColumns },
|
|
161
|
+
to: { table: relatedTable, columns: foreignColumns },
|
|
162
|
+
// Falls back to the FK column's own `onDelete`, which is what makes a bare `@Field({
|
|
163
|
+
// references, onDelete })` work with no relation declared at all.
|
|
164
|
+
onDelete: foreignKey.onDelete ?? meta.fields[foreignKey.references[0].local]?.onDelete ?? ctx.defaultForeignKeyAction,
|
|
165
|
+
onUpdate: foreignKey.onUpdate ?? ctx.defaultForeignKeyAction,
|
|
166
|
+
confidence: 1.0,
|
|
167
|
+
inferredFrom: 'entity_decorator',
|
|
168
|
+
});
|
|
175
169
|
}
|
|
176
170
|
}
|
|
177
171
|
/**
|
|
@@ -15,14 +15,18 @@ export type SqliteExecution = {
|
|
|
15
15
|
readonly changes: number;
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
|
-
* Querier for every SQLite driver. Each supplies
|
|
19
|
-
*
|
|
18
|
+
* Querier for every SQLite driver. Each supplies {@link execute}, and {@link iterate} where it steps a
|
|
19
|
+
* statement row by row; what they share - the values bound as SQLite takes them, the wide-integer
|
|
20
|
+
* decode, and a RETURNING statement counted by its rows - is written once here.
|
|
20
21
|
*/
|
|
21
22
|
export declare abstract class AbstractSqliteQuerier extends AbstractSqlQuerier {
|
|
22
23
|
/** Runs one statement, answering its rows as the driver read them. */
|
|
23
|
-
protected abstract execute(query: string, values
|
|
24
|
+
protected abstract execute(query: string, values: SqliteBindValue[]): Promise<SqliteExecution>;
|
|
25
|
+
/** A statement's rows as the driver answers them: read whole, unless it steps them one at a time. */
|
|
26
|
+
protected iterate(query: string, values: SqliteBindValue[]): Promise<Iterable<RawRow> | AsyncIterable<RawRow>>;
|
|
24
27
|
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
25
28
|
internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
|
|
29
|
+
internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, unknown>;
|
|
26
30
|
/**
|
|
27
31
|
* SQLite drivers hold a single shared handle rather than a connection from a pool, so releasing
|
|
28
32
|
* a querier returns nothing at all. Drivers owning a closable per-querier connection override this.
|
|
@@ -1,22 +1,36 @@
|
|
|
1
1
|
import { AbstractSqlQuerier } from '../querier/index.js';
|
|
2
2
|
import { decodeBigInts } from '../util/wideNumber.js';
|
|
3
3
|
/**
|
|
4
|
-
* Querier for every SQLite driver. Each supplies
|
|
5
|
-
*
|
|
4
|
+
* Querier for every SQLite driver. Each supplies {@link execute}, and {@link iterate} where it steps a
|
|
5
|
+
* statement row by row; what they share - the values bound as SQLite takes them, the wide-integer
|
|
6
|
+
* decode, and a RETURNING statement counted by its rows - is written once here.
|
|
6
7
|
*/
|
|
7
8
|
export class AbstractSqliteQuerier extends AbstractSqlQuerier {
|
|
9
|
+
/** A statement's rows as the driver answers them: read whole, unless it steps them one at a time. */
|
|
10
|
+
async iterate(query, values) {
|
|
11
|
+
return (await this.execute(query, values)).rows;
|
|
12
|
+
}
|
|
8
13
|
async internalAll(query, values) {
|
|
9
|
-
const { rows } = await this.execute(query, values);
|
|
14
|
+
const { rows } = await this.execute(query, toBindValues(values));
|
|
10
15
|
return rows.map(decodeBigInts);
|
|
11
16
|
}
|
|
12
17
|
async internalRun(query, values) {
|
|
13
|
-
const { rows, changes } = await this.execute(query, values);
|
|
18
|
+
const { rows, changes } = await this.execute(query, toBindValues(values));
|
|
14
19
|
// A driver's own count is unreliable for a RETURNING statement (Hrana answers 0), so its rows answer.
|
|
15
20
|
return this.buildUpdateResult({ rows: rows.map(decodeBigInts), changes: rows.length || changes });
|
|
16
21
|
}
|
|
22
|
+
async *internalStream(query, values) {
|
|
23
|
+
for await (const row of await this.iterate(query, toBindValues(values))) {
|
|
24
|
+
yield decodeBigInts(row);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
17
27
|
/**
|
|
18
28
|
* SQLite drivers hold a single shared handle rather than a connection from a pool, so releasing
|
|
19
29
|
* a querier returns nothing at all. Drivers owning a closable per-querier connection override this.
|
|
20
30
|
*/
|
|
21
31
|
async internalRelease() { }
|
|
22
32
|
}
|
|
33
|
+
/** The compiler hands values over untyped, which the dialect has already normalized to what SQLite binds. */
|
|
34
|
+
function toBindValues(values = []) {
|
|
35
|
+
return values;
|
|
36
|
+
}
|
|
@@ -44,7 +44,7 @@ export declare class HranaQuerier extends AbstractSqliteQuerier {
|
|
|
44
44
|
private readonly closeClientOnRelease;
|
|
45
45
|
constructor(client: HranaClient, dialect: SqliteDialect, extra?: ExtraOptions | undefined, connection?: HranaQuerierConnectionOptions);
|
|
46
46
|
/** Runs on the open transaction's handle when there is one. */
|
|
47
|
-
protected execute(query: string, values
|
|
47
|
+
protected execute(query: string, values: SqliteBindValue[]): Promise<{
|
|
48
48
|
rows: RawRow[];
|
|
49
49
|
changes: number;
|
|
50
50
|
}>;
|