uql-orm 0.62.0 → 0.64.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/bunSql.util.d.ts +15 -15
- package/dist/bunSql/bunSql.util.js +22 -35
- package/dist/bunSql/bunSqlQuerier.d.ts +2 -2
- package/dist/bunSql/bunSqlQuerier.js +3 -3
- package/dist/bunSql/bunSqlQuerierPool.d.ts +1 -13
- package/dist/bunSql/bunSqlQuerierPool.js +3 -34
- package/dist/d1/d1Querier.d.ts +12 -4
- package/dist/d1/d1Querier.js +6 -11
- package/dist/d1/d1QuerierPool.d.ts +7 -3
- package/dist/d1/d1QuerierPool.js +5 -3
- package/dist/entity/decorator/entity.d.ts +5 -9
- package/dist/entity/decorator/entity.js +3 -7
- package/dist/entity/metadata/definition.d.ts +2 -2
- package/dist/entity/metadata/definition.js +13 -22
- package/dist/libsql/libsqlDialect.d.ts +1 -1
- package/dist/libsql/libsqlDialect.js +1 -1
- package/dist/libsql/libsqlQuerierPool.d.ts +18 -9
- package/dist/libsql/libsqlQuerierPool.js +32 -20
- package/dist/migrate/builder/expressions.js +1 -15
- package/dist/migrate/builder/migrationBuilder.d.ts +6 -28
- package/dist/migrate/builder/migrationBuilder.js +9 -83
- package/dist/migrate/builder/types.d.ts +14 -24
- package/dist/migrate/cli.d.ts +1 -6
- package/dist/migrate/cli.js +3 -10
- package/dist/migrate/codegen/index.d.ts +1 -1
- package/dist/migrate/codegen/index.js +1 -1
- package/dist/migrate/codegen/indexDecoratorSource.d.ts +1 -1
- package/dist/migrate/codegen/indexDecoratorSource.js +4 -8
- package/dist/migrate/codegen/migrationFile.d.ts +9 -5
- package/dist/migrate/codegen/migrationFile.js +2 -3
- package/dist/migrate/ddl/indexDdl.d.ts +4 -2
- package/dist/migrate/ddl/indexDdl.js +16 -15
- package/dist/migrate/generator/mongoCommand.d.ts +9 -9
- package/dist/migrate/generator/mongoCommand.js +1 -1
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +21 -26
- package/dist/migrate/generator/mongoSchemaGenerator.js +103 -80
- package/dist/migrate/index.d.ts +1 -1
- package/dist/migrate/index.js +1 -1
- package/dist/migrate/indexPredicate.d.ts +8 -0
- package/dist/migrate/indexPredicate.js +52 -0
- package/dist/migrate/migrationTarget.d.ts +23 -0
- package/dist/migrate/migrationTarget.js +48 -0
- package/dist/migrate/migrator.d.ts +17 -45
- package/dist/migrate/migrator.js +80 -179
- package/dist/migrate/schemaGenerator.d.ts +12 -13
- package/dist/migrate/schemaGenerator.js +43 -9
- package/dist/mongo/mongoDialect.d.ts +6 -1
- package/dist/querier/abstractSharedHandleQuerierPool.d.ts +5 -5
- package/dist/querier/abstractSharedHandleQuerierPool.js +5 -5
- package/dist/schema/schemaASTBuilder.d.ts +2 -0
- package/dist/schema/schemaASTBuilder.js +9 -22
- package/dist/sqlite/abstractSqliteQuerier.d.ts +11 -28
- package/dist/sqlite/abstractSqliteQuerier.js +14 -33
- package/dist/sqlite/bunSqliteAdapter.bun.d.ts +5 -4
- package/dist/sqlite/bunSqliteAdapter.bun.js +1 -1
- package/dist/sqlite/hranaQuerier.d.ts +6 -4
- package/dist/sqlite/hranaQuerier.js +4 -13
- package/dist/sqlite/index.d.ts +0 -1
- package/dist/sqlite/index.js +0 -1
- package/dist/sqlite/localSqliteQuerierPool.d.ts +14 -5
- package/dist/sqlite/nodeSqliteAdapter.d.ts +3 -4
- package/dist/sqlite/nodeSqliteAdapter.js +3 -6
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -3
- package/dist/sqlite/nodeSqliteQuerierPool.js +3 -1
- package/dist/sqlite/sqliteDialect.d.ts +1 -1
- package/dist/sqlite/sqliteDialect.js +1 -1
- package/dist/sqlite/sqlitePragmas.d.ts +2 -11
- package/dist/sqlite/sqlitePragmas.js +1 -1
- package/dist/sqlite/sqliteQuerier.d.ts +29 -10
- package/dist/sqlite/sqliteQuerier.js +26 -4
- package/dist/sqlite/sqliteQuerierPool.d.ts +7 -3
- package/dist/sqlite/sqliteQuerierPool.js +12 -8
- package/dist/turso/index.d.ts +1 -0
- package/dist/turso/index.js +1 -0
- package/dist/turso/local.d.ts +1 -1
- package/dist/turso/local.js +1 -1
- package/dist/turso/tursoDialect.d.ts +4 -9
- package/dist/turso/tursoDialect.js +4 -12
- package/dist/turso/tursoLocalDialect.d.ts +10 -0
- package/dist/turso/tursoLocalDialect.js +13 -0
- package/dist/turso/tursoLocalQuerierPool.d.ts +8 -13
- package/dist/turso/tursoLocalQuerierPool.js +6 -5
- package/dist/turso/tursoQuerierPool.d.ts +15 -30
- package/dist/turso/tursoQuerierPool.js +13 -23
- package/dist/turso/tursoSessionQuerier.d.ts +57 -0
- package/dist/turso/tursoSessionQuerier.js +50 -0
- package/dist/type/entity.d.ts +37 -62
- package/dist/type/migration.d.ts +11 -40
- package/dist/type/queryRaw.d.ts +8 -0
- package/dist/type/queryRaw.js +11 -0
- package/dist/util/ddlExpression.util.d.ts +5 -3
- package/dist/util/ddlExpression.util.js +19 -12
- package/dist/util/raw.d.ts +6 -1
- package/dist/util/raw.js +11 -8
- package/dist/util/sqlLiteral.js +5 -3
- package/dist/util/wideNumber.d.ts +2 -2
- package/dist/util/wideNumber.js +2 -2
- package/package.json +2 -2
- package/dist/migrate/schemaGeneratorAsync.d.ts +0 -7
- package/dist/migrate/schemaGeneratorAsync.js +0 -12
- package/dist/sqlite/hranaQuerierPool.d.ts +0 -20
- package/dist/sqlite/hranaQuerierPool.js +0 -26
- package/dist/turso/tursoLocalQuerier.d.ts +0 -24
- package/dist/turso/tursoLocalQuerier.js +0 -20
|
@@ -6,10 +6,12 @@ import { diffRelationshipNodes, diffTable } from '../schema/schemaASTDiffer.js';
|
|
|
6
6
|
import { isAutoIncrement, qualifyName } from '../util/index.js';
|
|
7
7
|
import { derivedCheckName, derivedForeignKeyName, derivedPrimaryKeyName } from '../util/sql.util.js';
|
|
8
8
|
import { formatDefaultValue, SqlExpression } from './builder/expressions.js';
|
|
9
|
+
import { splitSqlStatements } from './builder/splitSqlStatements.js';
|
|
9
10
|
import { indexDdlFor, tableDdlFor } from './ddl/index.js';
|
|
10
11
|
import { sizedType } from './ddl/tableDdl.js';
|
|
11
12
|
import { columnForeignKey, columnIndex, fullColumnDefinitionToNode, renderIndexDefinition, tableDefinitionToNode, } from './generator/definitionToNode.js';
|
|
12
13
|
import { indexNodeToSchema } from './generator/indexNodeToSchema.js';
|
|
14
|
+
import { assertIndexPredicate } from './indexPredicate.js';
|
|
13
15
|
/**
|
|
14
16
|
* Unified SQL schema generator.
|
|
15
17
|
* Parameterized by dialect to handle Postgres, MySQL, MariaDB, and SQLite.
|
|
@@ -48,6 +50,10 @@ export class SqlSchemaGenerator {
|
|
|
48
50
|
compileDdl(sql, entity) {
|
|
49
51
|
return this.dialect.compileDdl(sql, entity);
|
|
50
52
|
}
|
|
53
|
+
compileIndexPredicate(where, entity, indexName) {
|
|
54
|
+
assertIndexPredicate(where, this.dialect.dialectName, indexName);
|
|
55
|
+
return this.dialect.compileDdl(where, entity);
|
|
56
|
+
}
|
|
51
57
|
/** Escape an identifier (table name, column name, etc.) */
|
|
52
58
|
escapeId(identifier) {
|
|
53
59
|
return this.dialect.escapeId(identifier);
|
|
@@ -577,13 +583,43 @@ export class SqlSchemaGenerator {
|
|
|
577
583
|
generateRenameTableSql(oldName, newName) {
|
|
578
584
|
return this.tableDdl.renameTable(oldName, newName);
|
|
579
585
|
}
|
|
586
|
+
/** `raw` is split, being the one SQL no generator wrote. */
|
|
587
|
+
generateOperation(operation) {
|
|
588
|
+
switch (operation.type) {
|
|
589
|
+
case 'createTable':
|
|
590
|
+
return this.generateCreateTableFromDefinition(operation.table);
|
|
591
|
+
case 'dropTable':
|
|
592
|
+
return [
|
|
593
|
+
this.generateDropTable(operation.tableName, { ifExists: operation.ifExists, cascade: operation.cascade }),
|
|
594
|
+
];
|
|
595
|
+
case 'renameTable':
|
|
596
|
+
return [this.generateRenameTableSql(operation.oldName, operation.newName)];
|
|
597
|
+
case 'addColumn':
|
|
598
|
+
return this.generateAddColumnSql(operation.tableName, operation.column);
|
|
599
|
+
case 'dropColumn':
|
|
600
|
+
return this.generateDropColumnSql(operation.tableName, operation.columnName);
|
|
601
|
+
case 'renameColumn':
|
|
602
|
+
return [this.generateRenameColumnSql(operation.tableName, operation.oldName, operation.newName)];
|
|
603
|
+
case 'alterColumn':
|
|
604
|
+
return this.generateAlterColumnSql(operation.tableName, operation.columnName, operation.changes);
|
|
605
|
+
case 'createIndex':
|
|
606
|
+
return [this.generateCreateIndexFromDefinition(operation.tableName, operation.index)];
|
|
607
|
+
case 'dropIndex':
|
|
608
|
+
return [this.generateDropIndex(operation.tableName, operation.indexName)];
|
|
609
|
+
case 'addForeignKey':
|
|
610
|
+
return [this.generateAddForeignKeySql(operation.tableName, operation.foreignKey)];
|
|
611
|
+
case 'dropForeignKey':
|
|
612
|
+
return [this.generateDropForeignKeySql(operation.tableName, operation.constraintName)];
|
|
613
|
+
case 'raw':
|
|
614
|
+
return splitSqlStatements(operation.sql);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
580
617
|
/**
|
|
581
618
|
* `ADD COLUMN`, plus the constraint and index the column declares.
|
|
582
619
|
*
|
|
583
620
|
* `CREATE TABLE` lifts a column's `references` and `index` onto the table it is building; this had
|
|
584
621
|
* no lift, so a hand-written `addColumn(...).references(...).index()` emitted the column alone and
|
|
585
|
-
* dropped both without a word.
|
|
586
|
-
* already returns, and `execute` splits them.
|
|
622
|
+
* dropped both without a word.
|
|
587
623
|
*/
|
|
588
624
|
generateAddColumnSql(tableName, column) {
|
|
589
625
|
this.assertColumnAddable(tableName, column);
|
|
@@ -598,14 +634,14 @@ export class SqlSchemaGenerator {
|
|
|
598
634
|
statements.push(this.generateCreateIndex(tableName, index));
|
|
599
635
|
}
|
|
600
636
|
statements.push(...this.generateColumnCommentStatement(tableName, column));
|
|
601
|
-
return statements
|
|
637
|
+
return statements;
|
|
602
638
|
}
|
|
603
639
|
generateAlterColumnSql(tableName, columnName, column) {
|
|
604
640
|
const node = fullColumnDefinitionToNode(column, tableName);
|
|
605
|
-
return this.generateAlterColumnStatements(tableName, { ...this.columnNodeToSchema(node), name: columnName }, this.generateColumnFromNode(node))
|
|
641
|
+
return this.generateAlterColumnStatements(tableName, { ...this.columnNodeToSchema(node), name: columnName }, this.generateColumnFromNode(node));
|
|
606
642
|
}
|
|
607
643
|
generateDropColumnSql(tableName, columnName) {
|
|
608
|
-
return this.tableDdl.dropColumn(tableName, columnName)
|
|
644
|
+
return this.tableDdl.dropColumn(tableName, columnName);
|
|
609
645
|
}
|
|
610
646
|
generateRenameColumnSql(tableName, oldName, newName) {
|
|
611
647
|
return this.tableDdl.renameColumn(tableName, oldName, newName);
|
|
@@ -726,13 +762,11 @@ export function buildEntityAST(generator, entities, defaultForeignKeyAction) {
|
|
|
726
762
|
resolveSchema: (meta) => generator.resolveSchema(meta),
|
|
727
763
|
resolveColumnName: (key, field) => generator.resolveColumnName(key, field),
|
|
728
764
|
compileDdl: (sql, entity) => generator.compileDdl(sql, entity),
|
|
765
|
+
compileIndexPredicate: (where, entity, indexName) => generator.compileIndexPredicate(where, entity, indexName),
|
|
729
766
|
defaultForeignKeyAction,
|
|
730
767
|
});
|
|
731
768
|
}
|
|
732
|
-
/**
|
|
733
|
-
* Synchronous factory for SQL schema generators only.
|
|
734
|
-
* For MongoDB, use `createSchemaGeneratorAsync` from `./schemaGeneratorAsync.js` so the optional `mongodb` peer is not loaded at import time.
|
|
735
|
-
*/
|
|
769
|
+
/** The SQL schema generator for `dialect`, `undefined` on MongoDB, whose generator needs its optional peer. */
|
|
736
770
|
export function createSchemaGenerator(dialect, defaultForeignKeyAction) {
|
|
737
771
|
return dialect.dialectName === 'mongodb' ? undefined : new SqlSchemaGenerator(dialect, defaultForeignKeyAction);
|
|
738
772
|
}
|
|
@@ -10,6 +10,11 @@ type MongoReadStages = {
|
|
|
10
10
|
/** Keys merged into the query's projection, when it has one: a vector search's score. */
|
|
11
11
|
readonly project?: Record<string, 1>;
|
|
12
12
|
};
|
|
13
|
+
/** Accumulator threaded through `$where` rendering: the relation lookups it needs, and their temp fields. */
|
|
14
|
+
type RelationLookups = {
|
|
15
|
+
readonly stages: MongoAggregationPipelineEntry<Document>[];
|
|
16
|
+
readonly temps: string[];
|
|
17
|
+
};
|
|
13
18
|
/** Default {@link DialectFeatures} for MongoDB; shared by {@link MongoDialect} and its schema generator. */
|
|
14
19
|
export declare const mongoDialectFeatures: DialectFeatures;
|
|
15
20
|
export declare class MongoDialect extends AbstractDialect {
|
|
@@ -46,7 +51,7 @@ export declare class MongoDialect extends AbstractDialect {
|
|
|
46
51
|
* recursion). Relation keys need `$lookup` stages, so they are only accepted when `lookups` is
|
|
47
52
|
* given - a plain `find`/`updateMany` filter has nowhere to put them.
|
|
48
53
|
*/
|
|
49
|
-
|
|
54
|
+
protected renderFilter<E extends Document>(entity: Type<E>, where?: QueryWhere<E>, lookups?: RelationLookups): Filter<E>;
|
|
50
55
|
/**
|
|
51
56
|
* Renders `$and`/`$or`/`$not`/`$nor` into `filter`. MongoDB has no root-level `$not`, so both
|
|
52
57
|
* negating operators become its `$nor`, which is exactly `NOT (a OR b)` - and by De Morgan that
|
|
@@ -2,13 +2,13 @@ import type { AbstractSqlDialect } from '../dialect/index.js';
|
|
|
2
2
|
import type { SqlQuerier } from '../type/index.js';
|
|
3
3
|
import { AbstractSqlQuerierPool } from './abstractSqlQuerierPool.js';
|
|
4
4
|
/**
|
|
5
|
-
* Base pool for
|
|
6
|
-
*
|
|
5
|
+
* Base pool for a handle opened once and kept for the pool's lifetime: the one connection every local
|
|
6
|
+
* SQLite driver, the embedded Turso engine and PGlite give per database, or libSQL's client.
|
|
7
7
|
*
|
|
8
8
|
* The handle is shared, but each acquisition gets its own querier, so transaction state stays per unit
|
|
9
|
-
* of work.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* of work. On a single connection that state is not *isolated*, which is the one way these differ from
|
|
10
|
+
* a real pool: two queriers cannot hold independent transactions, and a unit of work that needs one needs
|
|
11
|
+
* its own pool and therefore its own database. libSQL's client opens a session per transaction instead.
|
|
12
12
|
*
|
|
13
13
|
* What a second `BEGIN` then does is the engine's, not this class's: SQLite and the embedded Turso
|
|
14
14
|
* engine both refuse it ("cannot start a transaction within a transaction"), while PGlite accepts it
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { AbstractSqlQuerierPool } from './abstractSqlQuerierPool.js';
|
|
2
2
|
/**
|
|
3
|
-
* Base pool for
|
|
4
|
-
*
|
|
3
|
+
* Base pool for a handle opened once and kept for the pool's lifetime: the one connection every local
|
|
4
|
+
* SQLite driver, the embedded Turso engine and PGlite give per database, or libSQL's client.
|
|
5
5
|
*
|
|
6
6
|
* The handle is shared, but each acquisition gets its own querier, so transaction state stays per unit
|
|
7
|
-
* of work.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* of work. On a single connection that state is not *isolated*, which is the one way these differ from
|
|
8
|
+
* a real pool: two queriers cannot hold independent transactions, and a unit of work that needs one needs
|
|
9
|
+
* its own pool and therefore its own database. libSQL's client opens a session per transaction instead.
|
|
10
10
|
*
|
|
11
11
|
* What a second `BEGIN` then does is the engine's, not this class's: SQLite and the embedded Turso
|
|
12
12
|
* engine both refuse it ("cannot start a transaction within a transaction"), while PGlite accepts it
|
|
@@ -29,6 +29,8 @@ export interface BuildSchemaASTOptions {
|
|
|
29
29
|
* predicate - which only a dialect can render. `buildEntityAST` supplies it from the generator.
|
|
30
30
|
*/
|
|
31
31
|
compileDdl?: (sql: EntityWhereMeta<object>, entity: Type<object>) => string;
|
|
32
|
+
/** A partial index's predicate as the engine writes it, `compileDdl` where none is given. `buildEntityAST` supplies it. */
|
|
33
|
+
compileIndexPredicate?: (where: EntityWhereMeta<object>, entity: Type<object>, indexName: string) => string;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
36
|
* Build a SchemaAST from entity classes (decorated with `@Entity`, `@Field`, etc.).
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - Database introspection results (TableSchema[])
|
|
7
7
|
*/
|
|
8
8
|
import { getMeta, soleIdOf } from '../entity/metadata/definition.js';
|
|
9
|
-
import { indexNameParts, renderIndexColumn } from '../util/ddlExpression.util.js';
|
|
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';
|
|
12
12
|
import { isAutoIncrement } from '../util/field.util.js';
|
|
@@ -23,6 +23,7 @@ import { DEFAULT_FOREIGN_KEY_ACTION, } from './types.js';
|
|
|
23
23
|
*/
|
|
24
24
|
export function buildSchemaAST(entities, options = {}) {
|
|
25
25
|
const { namingStrategy } = options;
|
|
26
|
+
const compileDdl = options.compileDdl ?? refuseDdl;
|
|
26
27
|
const ctx = {
|
|
27
28
|
ast: new SchemaAST(),
|
|
28
29
|
resolveTableName: options.resolveTableName ??
|
|
@@ -30,7 +31,8 @@ export function buildSchemaAST(entities, options = {}) {
|
|
|
30
31
|
resolveSchema: options.resolveSchema ?? ((m) => m.schema),
|
|
31
32
|
resolveColumnName: options.resolveColumnName ?? ((k, f) => namingStrategy?.columnName(f.name ?? k) ?? f.name ?? k),
|
|
32
33
|
defaultForeignKeyAction: options.defaultForeignKeyAction ?? DEFAULT_FOREIGN_KEY_ACTION,
|
|
33
|
-
compileDdl
|
|
34
|
+
compileDdl,
|
|
35
|
+
compileIndexPredicate: options.compileIndexPredicate ?? compileDdl,
|
|
34
36
|
};
|
|
35
37
|
for (const pass of [addTableFromEntity, addRelationshipsFromEntity, addIndexesFromEntity]) {
|
|
36
38
|
for (const entity of entities) {
|
|
@@ -180,23 +182,7 @@ function addIndexesFromEntity(ctx, meta) {
|
|
|
180
182
|
const table = tableOf(ctx, meta);
|
|
181
183
|
if (!table)
|
|
182
184
|
return;
|
|
183
|
-
for (const
|
|
184
|
-
const field = meta.fields[key];
|
|
185
|
-
if (!field?.index)
|
|
186
|
-
continue;
|
|
187
|
-
const column = table.columns.get(ctx.resolveColumnName(key, field));
|
|
188
|
-
if (!column)
|
|
189
|
-
continue;
|
|
190
|
-
ctx.ast.addIndex({
|
|
191
|
-
name: typeof field.index === 'string' ? field.index : derivedIndexName(table.name, [column.name]),
|
|
192
|
-
table,
|
|
193
|
-
entries: [{ column: column.name }],
|
|
194
|
-
unique: field.unique ?? false,
|
|
195
|
-
source: 'entity',
|
|
196
|
-
syncStatus: 'entity_only',
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
for (const idxMeta of meta.indexes ?? []) {
|
|
185
|
+
for (const idxMeta of declaredIndexes(meta)) {
|
|
200
186
|
addCompositeIndex(ctx, table, meta, idxMeta);
|
|
201
187
|
}
|
|
202
188
|
addForeignKeyIndexes(ctx, meta, table);
|
|
@@ -235,7 +221,7 @@ function resolveIncludeColumn(ctx, meta, column) {
|
|
|
235
221
|
return field ? ctx.resolveColumnName(column, field) : column;
|
|
236
222
|
}
|
|
237
223
|
/**
|
|
238
|
-
* One
|
|
224
|
+
* One index the entity declares. Its entries keep the authored form (expression, prefix length, order) with
|
|
239
225
|
* names resolved, so the generator renders exactly what was declared; `columns` is the resolvable
|
|
240
226
|
* subset, which is what diffing and introspection compare.
|
|
241
227
|
*/
|
|
@@ -251,14 +237,15 @@ function addCompositeIndex(ctx, table, meta, idxMeta) {
|
|
|
251
237
|
});
|
|
252
238
|
if (!resolved.length)
|
|
253
239
|
return;
|
|
240
|
+
const name = idxMeta.name ?? derivedIndexName(table.name, indexNameParts(resolved));
|
|
254
241
|
ctx.ast.addIndex({
|
|
255
|
-
name
|
|
242
|
+
name,
|
|
256
243
|
table,
|
|
257
244
|
entries: resolved.map((entry) => renderIndexColumn(entry, (sql) => ctx.compileDdl(sql, meta.entity))),
|
|
258
245
|
include: idxMeta.include?.map((column) => resolveIncludeColumn(ctx, meta, column)),
|
|
259
246
|
unique: idxMeta.unique ?? false,
|
|
260
247
|
type: idxMeta.type,
|
|
261
|
-
where: idxMeta.where && ctx.
|
|
248
|
+
where: idxMeta.where && ctx.compileIndexPredicate(idxMeta.where, meta.entity, name),
|
|
262
249
|
distance: idxMeta.distance,
|
|
263
250
|
m: idxMeta.m,
|
|
264
251
|
efConstruction: idxMeta.efConstruction,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AbstractSqlQuerier } from '../querier/index.js';
|
|
2
|
+
import type { RawRow } from '../type/index.js';
|
|
2
3
|
/**
|
|
3
4
|
* Values every SQLite driver accepts as a bound parameter.
|
|
4
5
|
*
|
|
@@ -8,41 +9,23 @@ import { AbstractSqlQuerier } from '../querier/index.js';
|
|
|
8
9
|
* driver as one; leaving `boolean` here only invited a runtime throw that is now a compile error.
|
|
9
10
|
*/
|
|
10
11
|
export type SqliteBindValue = null | string | number | bigint | Uint8Array;
|
|
11
|
-
/**
|
|
12
|
-
export type
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/** What a statement came back with on a SQLite driver: the rows it read, and how many rows it changed. */
|
|
13
|
+
export type SqliteExecution = {
|
|
14
|
+
readonly rows: RawRow[];
|
|
15
|
+
readonly changes: number;
|
|
15
16
|
};
|
|
16
|
-
/** Bound parameters reach a driver as `unknown[]` from the compiler; every driver types them narrowly. */
|
|
17
|
-
export declare function toSqliteBindValues(values?: unknown[]): SqliteBindValue[];
|
|
18
17
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* awaits either.
|
|
18
|
+
* Querier for every SQLite driver. Each supplies one hook, {@link execute}; what they share - the
|
|
19
|
+
* wide-integer decode, and a RETURNING statement counted by its rows - is written once here.
|
|
22
20
|
*/
|
|
23
|
-
export type SqlitePreparedStatement = {
|
|
24
|
-
/** True for any statement returning rows, including one with a `RETURNING` clause. */
|
|
25
|
-
readonly reader: boolean;
|
|
26
|
-
all(...values: SqliteBindValue[]): unknown[] | Promise<unknown[]>;
|
|
27
|
-
run(...values: SqliteBindValue[]): SqliteRunResult | Promise<SqliteRunResult>;
|
|
28
|
-
iterate(...values: SqliteBindValue[]): Iterable<unknown> | AsyncIterable<unknown>;
|
|
29
|
-
};
|
|
30
21
|
export declare abstract class AbstractSqliteQuerier extends AbstractSqlQuerier {
|
|
22
|
+
/** Runs one statement, answering its rows as the driver read them. */
|
|
23
|
+
protected abstract execute(query: string, values?: unknown[]): Promise<SqliteExecution>;
|
|
24
|
+
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
25
|
+
internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
|
|
31
26
|
/**
|
|
32
27
|
* SQLite drivers hold a single shared handle rather than a connection from a pool, so releasing
|
|
33
28
|
* a querier returns nothing at all. Drivers owning a closable per-querier connection override this.
|
|
34
29
|
*/
|
|
35
30
|
internalRelease(): Promise<void>;
|
|
36
31
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Querier for the SQLite drivers that expose prepared statements: `better-sqlite3`, `bun:sqlite`
|
|
39
|
-
* (through `adaptBunSqlite`) and the embedded Turso engine. They differ only in whether preparing and
|
|
40
|
-
* stepping are synchronous, which `await` and `for await` absorb, so the read/write/stream logic -
|
|
41
|
-
* including the `reader` rule below, whose loss silently drops inserted ids - is written once.
|
|
42
|
-
*/
|
|
43
|
-
export declare abstract class PreparedSqliteQuerier extends AbstractSqliteQuerier {
|
|
44
|
-
protected abstract prepare(query: string): SqlitePreparedStatement | Promise<SqlitePreparedStatement>;
|
|
45
|
-
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
46
|
-
internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, unknown>;
|
|
47
|
-
internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
|
|
48
|
-
}
|
|
@@ -1,41 +1,22 @@
|
|
|
1
1
|
import { AbstractSqlQuerier } from '../querier/index.js';
|
|
2
|
-
|
|
3
|
-
export function toSqliteBindValues(values) {
|
|
4
|
-
return (values || []);
|
|
5
|
-
}
|
|
6
|
-
export class AbstractSqliteQuerier extends AbstractSqlQuerier {
|
|
7
|
-
/**
|
|
8
|
-
* SQLite drivers hold a single shared handle rather than a connection from a pool, so releasing
|
|
9
|
-
* a querier returns nothing at all. Drivers owning a closable per-querier connection override this.
|
|
10
|
-
*/
|
|
11
|
-
async internalRelease() { }
|
|
12
|
-
}
|
|
2
|
+
import { decodeBigInts } from '../util/wideNumber.js';
|
|
13
3
|
/**
|
|
14
|
-
* Querier for
|
|
15
|
-
*
|
|
16
|
-
* stepping are synchronous, which `await` and `for await` absorb, so the read/write/stream logic -
|
|
17
|
-
* including the `reader` rule below, whose loss silently drops inserted ids - is written once.
|
|
4
|
+
* Querier for every SQLite driver. Each supplies one hook, {@link execute}; what they share - the
|
|
5
|
+
* wide-integer decode, and a RETURNING statement counted by its rows - is written once here.
|
|
18
6
|
*/
|
|
19
|
-
export class
|
|
7
|
+
export class AbstractSqliteQuerier extends AbstractSqlQuerier {
|
|
20
8
|
async internalAll(query, values) {
|
|
21
|
-
const
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
async *internalStream(query, values) {
|
|
25
|
-
const stmt = await this.prepare(query);
|
|
26
|
-
for await (const row of stmt.iterate(...toSqliteBindValues(values))) {
|
|
27
|
-
yield row;
|
|
28
|
-
}
|
|
9
|
+
const { rows } = await this.execute(query, values);
|
|
10
|
+
return rows.map(decodeBigInts);
|
|
29
11
|
}
|
|
30
12
|
async internalRun(query, values) {
|
|
31
|
-
const
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
if (stmt.reader) {
|
|
35
|
-
const rows = (await stmt.all(...toSqliteBindValues(values)));
|
|
36
|
-
return this.buildUpdateResult({ rows });
|
|
37
|
-
}
|
|
38
|
-
const { changes, lastInsertRowid } = await stmt.run(...toSqliteBindValues(values));
|
|
39
|
-
return this.buildUpdateResult({ changes, id: lastInsertRowid });
|
|
13
|
+
const { rows, changes } = await this.execute(query, values);
|
|
14
|
+
// A driver's own count is unreliable for a RETURNING statement (Hrana answers 0), so its rows answer.
|
|
15
|
+
return this.buildUpdateResult({ rows: rows.map(decodeBigInts), changes: rows.length || changes });
|
|
40
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* SQLite drivers hold a single shared handle rather than a connection from a pool, so releasing
|
|
19
|
+
* a querier returns nothing at all. Drivers owning a closable per-querier connection override this.
|
|
20
|
+
*/
|
|
21
|
+
async internalRelease() { }
|
|
41
22
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { SqliteBindValue
|
|
2
|
-
import type {
|
|
1
|
+
import type { SqliteBindValue } from './abstractSqliteQuerier.js';
|
|
2
|
+
import type { LocalSqliteDatabase } from './localSqliteQuerierPool.js';
|
|
3
|
+
import type { SqliteRunResult } from './sqliteQuerier.js';
|
|
3
4
|
/** A `bun:sqlite` statement: better-sqlite3-shaped, except it reports columns instead of `reader`. */
|
|
4
5
|
type BunStatement = {
|
|
5
6
|
columnNames: string[];
|
|
@@ -13,7 +14,7 @@ type BunDatabase = {
|
|
|
13
14
|
close(): unknown;
|
|
14
15
|
};
|
|
15
16
|
/**
|
|
16
|
-
* Presents a `bun:sqlite` handle as a {@link
|
|
17
|
+
* Presents a `bun:sqlite` handle as a {@link LocalSqliteDatabase}.
|
|
17
18
|
*
|
|
18
19
|
* @remarks Its statements expose no `reader`, so without deriving one every `RETURNING` statement
|
|
19
20
|
* would take the `run()` path, which discards returned rows, and inserts would report no ids.
|
|
@@ -22,5 +23,5 @@ type BunDatabase = {
|
|
|
22
23
|
* Lives in a `.bun.ts` file because it only ever executes under Bun: the Node coverage run cannot
|
|
23
24
|
* reach it, and `sqliteQuerier.bun.test.ts` covers it under `test:bun` instead.
|
|
24
25
|
*/
|
|
25
|
-
export declare function adaptBunSqlite(db: BunDatabase):
|
|
26
|
+
export declare function adaptBunSqlite(db: BunDatabase): LocalSqliteDatabase;
|
|
26
27
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Presents a `bun:sqlite` handle as a {@link
|
|
2
|
+
* Presents a `bun:sqlite` handle as a {@link LocalSqliteDatabase}.
|
|
3
3
|
*
|
|
4
4
|
* @remarks Its statements expose no `reader`, so without deriving one every `RETURNING` statement
|
|
5
5
|
* would take the `run()` path, which discards returned rows, and inserts would report no ids.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExtraOptions } from '../type/index.js';
|
|
1
|
+
import type { ExtraOptions, RawRow } from '../type/index.js';
|
|
2
2
|
import { AbstractSqliteQuerier, type SqliteBindValue } from './abstractSqliteQuerier.js';
|
|
3
3
|
import type { SqliteDialect } from './sqliteDialect.js';
|
|
4
4
|
/**
|
|
@@ -11,7 +11,6 @@ export type HranaInValue = SqliteBindValue | ArrayBuffer | Date;
|
|
|
11
11
|
export type HranaResultSet = {
|
|
12
12
|
rows: unknown[];
|
|
13
13
|
rowsAffected: number;
|
|
14
|
-
lastInsertRowid?: bigint;
|
|
15
14
|
};
|
|
16
15
|
export type HranaExecutor = {
|
|
17
16
|
execute(stmt: {
|
|
@@ -44,8 +43,11 @@ export declare class HranaQuerier extends AbstractSqliteQuerier {
|
|
|
44
43
|
private tx?;
|
|
45
44
|
private readonly closeClientOnRelease;
|
|
46
45
|
constructor(client: HranaClient, dialect: SqliteDialect, extra?: ExtraOptions | undefined, connection?: HranaQuerierConnectionOptions);
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
/** Runs on the open transaction's handle when there is one. */
|
|
47
|
+
protected execute(query: string, values?: unknown[]): Promise<{
|
|
48
|
+
rows: RawRow[];
|
|
49
|
+
changes: number;
|
|
50
|
+
}>;
|
|
49
51
|
protected internalBegin(): Promise<void>;
|
|
50
52
|
/**
|
|
51
53
|
* Both drop the handle before the call, not after: one that outlived a failed commit would carry
|
|
@@ -16,18 +16,10 @@ export class HranaQuerier extends AbstractSqliteQuerier {
|
|
|
16
16
|
this.extra = extra;
|
|
17
17
|
this.closeClientOnRelease = connection?.closeClientOnRelease ?? false;
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const res = await
|
|
22
|
-
return res.rows;
|
|
23
|
-
}
|
|
24
|
-
async internalRun(query, values) {
|
|
25
|
-
const target = this.tx || this.client;
|
|
26
|
-
const res = await target.execute({ sql: query, args: values });
|
|
27
|
-
const rows = res.rows;
|
|
28
|
-
// `rowsAffected` is unreliably 0 whenever the statement has a RETURNING clause, so prefer
|
|
29
|
-
// the actual row count when rows were returned.
|
|
30
|
-
return this.buildUpdateResult({ rows, changes: rows.length || res.rowsAffected, id: res.lastInsertRowid });
|
|
19
|
+
/** Runs on the open transaction's handle when there is one. */
|
|
20
|
+
async execute(query, values) {
|
|
21
|
+
const res = await (this.tx ?? this.client).execute({ sql: query, args: values });
|
|
22
|
+
return { rows: res.rows, changes: res.rowsAffected };
|
|
31
23
|
}
|
|
32
24
|
async internalBegin() {
|
|
33
25
|
this.tx = await this.client.transaction('write');
|
|
@@ -47,7 +39,6 @@ export class HranaQuerier extends AbstractSqliteQuerier {
|
|
|
47
39
|
await tx?.rollback();
|
|
48
40
|
}
|
|
49
41
|
async internalRelease() {
|
|
50
|
-
await super.internalRelease();
|
|
51
42
|
if (this.closeClientOnRelease) {
|
|
52
43
|
this.client.close();
|
|
53
44
|
}
|
package/dist/sqlite/index.d.ts
CHANGED
package/dist/sqlite/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AbstractSharedHandleQuerierPool } from '../querier/abstractSharedHandleQuerierPool.js';
|
|
2
2
|
import type { ExtraOptions } from '../type/index.js';
|
|
3
3
|
import { SqliteDialect } from './sqliteDialect.js';
|
|
4
|
-
import { type
|
|
4
|
+
import { type SqlitePreparedStatement, SqliteQuerier } from './sqliteQuerier.js';
|
|
5
5
|
/** What every local SQLite pool accepts on top of its driver's own options. */
|
|
6
6
|
export type LocalSqlitePoolOptions = {
|
|
7
7
|
/**
|
|
@@ -11,6 +11,15 @@ export type LocalSqlitePoolOptions = {
|
|
|
11
11
|
*/
|
|
12
12
|
extensions?: readonly string[];
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* A database opened in this process by a driver that answers at once, and installs loadable extensions
|
|
16
|
+
* (`sqlite-vec`, ...) into its connection.
|
|
17
|
+
*/
|
|
18
|
+
export type LocalSqliteDatabase = {
|
|
19
|
+
prepare(sql: string): SqlitePreparedStatement;
|
|
20
|
+
loadExtension(path: string): void;
|
|
21
|
+
close(): unknown;
|
|
22
|
+
};
|
|
14
23
|
/**
|
|
15
24
|
* Pool for a SQLite database opened in this process, whichever driver provides it. SQLite gives one
|
|
16
25
|
* connection per file, so the shared-handle lifecycle is {@link AbstractSharedHandleQuerierPool}'s.
|
|
@@ -18,11 +27,11 @@ export type LocalSqlitePoolOptions = {
|
|
|
18
27
|
* Subclasses supply only {@link createDb}: configuring the connection on the way up - the pragmas,
|
|
19
28
|
* then the extensions - is the same for `better-sqlite3`, `bun:sqlite` and `node:sqlite`.
|
|
20
29
|
*/
|
|
21
|
-
export declare abstract class AbstractLocalSqliteQuerierPool<O extends LocalSqlitePoolOptions> extends AbstractSharedHandleQuerierPool<
|
|
30
|
+
export declare abstract class AbstractLocalSqliteQuerierPool<O extends LocalSqlitePoolOptions> extends AbstractSharedHandleQuerierPool<LocalSqliteDatabase, SqliteQuerier, SqliteDialect> {
|
|
22
31
|
readonly opts?: O | undefined;
|
|
23
32
|
constructor(opts?: O | undefined, extra?: ExtraOptions);
|
|
24
33
|
/** Opens the driver's database, and nothing more: the caller configures it. */
|
|
25
|
-
protected abstract createDb(): Promise<
|
|
26
|
-
protected openDb(): Promise<
|
|
27
|
-
protected buildQuerier(db:
|
|
34
|
+
protected abstract createDb(): Promise<LocalSqliteDatabase>;
|
|
35
|
+
protected openDb(): Promise<LocalSqliteDatabase>;
|
|
36
|
+
protected buildQuerier(db: LocalSqliteDatabase): SqliteQuerier;
|
|
28
37
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SqliteBindValue } from './abstractSqliteQuerier.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { LocalSqliteDatabase } from './localSqliteQuerierPool.js';
|
|
3
3
|
/**
|
|
4
4
|
* A `node:sqlite` statement: better-sqlite3-shaped, except it describes columns instead of reporting
|
|
5
5
|
* `reader`, and types `changes` as possibly `bigint` where better-sqlite3 always answers a `number`.
|
|
@@ -9,7 +9,6 @@ type NodeSqliteStatement = {
|
|
|
9
9
|
all(...values: SqliteBindValue[]): unknown[];
|
|
10
10
|
run(...values: SqliteBindValue[]): {
|
|
11
11
|
changes: number | bigint;
|
|
12
|
-
lastInsertRowid: number | bigint;
|
|
13
12
|
};
|
|
14
13
|
iterate(...values: SqliteBindValue[]): Iterable<unknown>;
|
|
15
14
|
};
|
|
@@ -23,12 +22,12 @@ export type NodeSqliteDatabase = {
|
|
|
23
22
|
close(): void;
|
|
24
23
|
};
|
|
25
24
|
/**
|
|
26
|
-
* Presents a `node:sqlite` handle as a {@link
|
|
25
|
+
* Presents a `node:sqlite` handle as a {@link LocalSqliteDatabase}.
|
|
27
26
|
*
|
|
28
27
|
* @remarks Its statements expose no `reader`, so without deriving one every `RETURNING` statement
|
|
29
28
|
* would take the `run()` path, which discards returned rows, and inserts would report no ids.
|
|
30
29
|
* `columns()` is non-empty for exactly the statements better-sqlite3 marks as readers, including
|
|
31
30
|
* `INSERT ... RETURNING` and `DELETE ... RETURNING`.
|
|
32
31
|
*/
|
|
33
|
-
export declare function adaptNodeSqlite(db: NodeSqliteDatabase):
|
|
32
|
+
export declare function adaptNodeSqlite(db: NodeSqliteDatabase): LocalSqliteDatabase;
|
|
34
33
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Presents a `node:sqlite` handle as a {@link
|
|
2
|
+
* Presents a `node:sqlite` handle as a {@link LocalSqliteDatabase}.
|
|
3
3
|
*
|
|
4
4
|
* @remarks Its statements expose no `reader`, so without deriving one every `RETURNING` statement
|
|
5
5
|
* would take the `run()` path, which discards returned rows, and inserts would report no ids.
|
|
@@ -14,11 +14,8 @@ export function adaptNodeSqlite(db) {
|
|
|
14
14
|
reader: stmt.columns().length > 0,
|
|
15
15
|
all: (...values) => stmt.all(...values),
|
|
16
16
|
// `changes` is narrowed to `number` to match every other driver; a row count cannot exceed
|
|
17
|
-
// the safe-integer range, so nothing is lost.
|
|
18
|
-
run: (...values) => {
|
|
19
|
-
const { changes, lastInsertRowid } = stmt.run(...values);
|
|
20
|
-
return { changes: Number(changes), lastInsertRowid };
|
|
21
|
-
},
|
|
17
|
+
// the safe-integer range, so nothing is lost.
|
|
18
|
+
run: (...values) => ({ changes: Number(stmt.run(...values).changes) }),
|
|
22
19
|
iterate: (...values) => stmt.iterate(...values),
|
|
23
20
|
};
|
|
24
21
|
},
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ExtraOptions } from '../type/index.js';
|
|
2
|
-
import { AbstractLocalSqliteQuerierPool, type LocalSqlitePoolOptions } from './localSqliteQuerierPool.js';
|
|
3
|
-
import type { SqliteDatabase } from './sqliteQuerier.js';
|
|
2
|
+
import { AbstractLocalSqliteQuerierPool, type LocalSqliteDatabase, type LocalSqlitePoolOptions } from './localSqliteQuerierPool.js';
|
|
4
3
|
/**
|
|
5
4
|
* The `DatabaseSync` options worth surfacing, plus the loadable extensions to install. Declared here
|
|
6
5
|
* rather than imported from `node:sqlite` so this module needs no ambient Node types; unknown keys
|
|
@@ -24,5 +23,5 @@ export type NodeSqlitePoolOptions = LocalSqlitePoolOptions & {
|
|
|
24
23
|
export declare class NodeSqliteQuerierPool extends AbstractLocalSqliteQuerierPool<NodeSqlitePoolOptions> {
|
|
25
24
|
readonly filename: string;
|
|
26
25
|
constructor(filename?: string, opts?: NodeSqlitePoolOptions, extra?: ExtraOptions);
|
|
27
|
-
protected createDb(): Promise<
|
|
26
|
+
protected createDb(): Promise<LocalSqliteDatabase>;
|
|
28
27
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AbstractLocalSqliteQuerierPool } from './localSqliteQuerierPool.js';
|
|
1
|
+
import { AbstractLocalSqliteQuerierPool, } from './localSqliteQuerierPool.js';
|
|
2
2
|
import { adaptNodeSqlite } from './nodeSqliteAdapter.js';
|
|
3
3
|
/**
|
|
4
4
|
* Pool backed by Node's built-in `node:sqlite`, so SQLite works with **no dependency at all** rather
|
|
@@ -20,6 +20,8 @@ export class NodeSqliteQuerierPool extends AbstractLocalSqliteQuerierPool {
|
|
|
20
20
|
const { extensions, ...driverOpts } = this.opts ?? {};
|
|
21
21
|
const nodeDb = new DatabaseSync(this.filename, {
|
|
22
22
|
...driverOpts,
|
|
23
|
+
// Integers as `bigint`, which the querier decodes exactly past 2^53.
|
|
24
|
+
readBigInts: true,
|
|
23
25
|
// `node:sqlite` refuses `loadExtension` unless the database was opened with this on.
|
|
24
26
|
...(extensions?.length ? { allowExtension: true } : undefined),
|
|
25
27
|
});
|
|
@@ -16,7 +16,7 @@ export declare class SqliteDialect extends AbstractSqlDialect {
|
|
|
16
16
|
/** SQLite locks the whole database, not rows, so `$lock` has nothing to map onto. */
|
|
17
17
|
readonly supportsRowLocks = false;
|
|
18
18
|
readonly booleanLiteral = "integer";
|
|
19
|
-
/**
|
|
19
|
+
/** SQLite's own cap on a function call before 3.48, which libSQL and `bun:sqlite`'s build still have. */
|
|
20
20
|
readonly maxFunctionArgs: number;
|
|
21
21
|
readonly insertIdSource = "returning";
|
|
22
22
|
/**
|
|
@@ -39,7 +39,7 @@ export class SqliteDialect extends AbstractSqlDialect {
|
|
|
39
39
|
/** SQLite locks the whole database, not rows, so `$lock` has nothing to map onto. */
|
|
40
40
|
supportsRowLocks = false;
|
|
41
41
|
booleanLiteral = 'integer';
|
|
42
|
-
/**
|
|
42
|
+
/** SQLite's own cap on a function call before 3.48, which libSQL and `bun:sqlite`'s build still have. */
|
|
43
43
|
maxFunctionArgs = 127;
|
|
44
44
|
// SQLite supports `RETURNING` (including on `INSERT ... ON CONFLICT`), so IDs are exact per row.
|
|
45
45
|
insertIdSource = 'returning';
|