uql-orm 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/browser/uql-browser.min.js.map +1 -1
  2. package/dist/bunSql/bunSql.util.d.ts +15 -15
  3. package/dist/bunSql/bunSql.util.js +22 -35
  4. package/dist/bunSql/bunSqlQuerier.d.ts +2 -2
  5. package/dist/bunSql/bunSqlQuerier.js +3 -3
  6. package/dist/bunSql/bunSqlQuerierPool.d.ts +1 -13
  7. package/dist/bunSql/bunSqlQuerierPool.js +3 -34
  8. package/dist/d1/d1Querier.d.ts +12 -4
  9. package/dist/d1/d1Querier.js +6 -11
  10. package/dist/d1/d1QuerierPool.d.ts +7 -3
  11. package/dist/d1/d1QuerierPool.js +5 -3
  12. package/dist/dialect/abstractSqlDialect.d.ts +12 -7
  13. package/dist/dialect/abstractSqlDialect.js +51 -50
  14. package/dist/dialect/mysqlLikeSqlDialect.js +1 -1
  15. package/dist/dialect/pgLikeSqlDialect.d.ts +1 -0
  16. package/dist/dialect/pgLikeSqlDialect.js +8 -7
  17. package/dist/dialect/queryContext.d.ts +5 -6
  18. package/dist/dialect/queryContext.js +8 -8
  19. package/dist/entity/decorator/entity.d.ts +6 -10
  20. package/dist/entity/decorator/entity.js +4 -8
  21. package/dist/entity/decorator/members.d.ts +3 -2
  22. package/dist/entity/decorator/members.js +1 -0
  23. package/dist/entity/metadata/definition.d.ts +2 -2
  24. package/dist/entity/metadata/definition.js +23 -26
  25. package/dist/libsql/libsqlDialect.d.ts +1 -1
  26. package/dist/libsql/libsqlDialect.js +1 -1
  27. package/dist/libsql/libsqlQuerierPool.d.ts +18 -9
  28. package/dist/libsql/libsqlQuerierPool.js +32 -20
  29. package/dist/migrate/builder/migrationBuilder.js +3 -5
  30. package/dist/migrate/builder/tableBuilder.js +2 -4
  31. package/dist/migrate/builder/types.d.ts +11 -3
  32. package/dist/migrate/codegen/index.d.ts +1 -1
  33. package/dist/migrate/codegen/index.js +1 -1
  34. package/dist/migrate/codegen/indexDecoratorSource.d.ts +1 -1
  35. package/dist/migrate/codegen/indexDecoratorSource.js +4 -6
  36. package/dist/migrate/codegen/migrationFile.d.ts +0 -4
  37. package/dist/migrate/codegen/migrationFile.js +0 -2
  38. package/dist/migrate/generator/definitionToNode.d.ts +8 -5
  39. package/dist/migrate/generator/definitionToNode.js +13 -4
  40. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +2 -0
  41. package/dist/migrate/generator/mongoSchemaGenerator.js +6 -1
  42. package/dist/migrate/schemaGenerator.d.ts +5 -3
  43. package/dist/migrate/schemaGenerator.js +9 -2
  44. package/dist/mongo/mongoDialect.js +1 -1
  45. package/dist/mssql/mssqlDialect.js +3 -5
  46. package/dist/querier/abstractSharedHandleQuerierPool.d.ts +5 -5
  47. package/dist/querier/abstractSharedHandleQuerierPool.js +5 -5
  48. package/dist/schema/schemaASTBuilder.d.ts +6 -1
  49. package/dist/schema/schemaASTBuilder.js +17 -16
  50. package/dist/sqlite/abstractSqliteQuerier.d.ts +11 -28
  51. package/dist/sqlite/abstractSqliteQuerier.js +14 -33
  52. package/dist/sqlite/bunSqliteAdapter.bun.d.ts +5 -4
  53. package/dist/sqlite/bunSqliteAdapter.bun.js +1 -1
  54. package/dist/sqlite/hranaQuerier.d.ts +6 -4
  55. package/dist/sqlite/hranaQuerier.js +4 -13
  56. package/dist/sqlite/index.d.ts +0 -1
  57. package/dist/sqlite/index.js +0 -1
  58. package/dist/sqlite/localSqliteQuerierPool.d.ts +14 -5
  59. package/dist/sqlite/nodeSqliteAdapter.d.ts +3 -4
  60. package/dist/sqlite/nodeSqliteAdapter.js +3 -6
  61. package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -3
  62. package/dist/sqlite/nodeSqliteQuerierPool.js +3 -1
  63. package/dist/sqlite/sqliteDialect.d.ts +1 -1
  64. package/dist/sqlite/sqliteDialect.js +1 -1
  65. package/dist/sqlite/sqlitePragmas.d.ts +2 -11
  66. package/dist/sqlite/sqlitePragmas.js +1 -1
  67. package/dist/sqlite/sqliteQuerier.d.ts +29 -10
  68. package/dist/sqlite/sqliteQuerier.js +26 -4
  69. package/dist/sqlite/sqliteQuerierPool.d.ts +7 -3
  70. package/dist/sqlite/sqliteQuerierPool.js +12 -8
  71. package/dist/turso/index.d.ts +1 -0
  72. package/dist/turso/index.js +1 -0
  73. package/dist/turso/local.d.ts +1 -1
  74. package/dist/turso/local.js +1 -1
  75. package/dist/turso/tursoDialect.d.ts +4 -9
  76. package/dist/turso/tursoDialect.js +4 -12
  77. package/dist/turso/tursoLocalDialect.d.ts +10 -0
  78. package/dist/turso/tursoLocalDialect.js +13 -0
  79. package/dist/turso/tursoLocalQuerierPool.d.ts +8 -13
  80. package/dist/turso/tursoLocalQuerierPool.js +6 -5
  81. package/dist/turso/tursoQuerierPool.d.ts +15 -30
  82. package/dist/turso/tursoQuerierPool.js +13 -23
  83. package/dist/turso/tursoSessionQuerier.d.ts +57 -0
  84. package/dist/turso/tursoSessionQuerier.js +50 -0
  85. package/dist/type/dialect.d.ts +15 -6
  86. package/dist/type/entity.d.ts +108 -73
  87. package/dist/type/migration.d.ts +9 -2
  88. package/dist/type/query.d.ts +3 -3
  89. package/dist/type/queryLock.d.ts +7 -7
  90. package/dist/type/queryLock.js +8 -6
  91. package/dist/type/queryRaw.d.ts +30 -30
  92. package/dist/type/queryRaw.js +14 -9
  93. package/dist/util/ddlExpression.util.d.ts +8 -13
  94. package/dist/util/ddlExpression.util.js +14 -23
  95. package/dist/util/dialect.util.d.ts +1 -1
  96. package/dist/util/dialect.util.js +3 -4
  97. package/dist/util/field.util.d.ts +1 -1
  98. package/dist/util/raw.d.ts +24 -17
  99. package/dist/util/raw.js +46 -17
  100. package/dist/util/wideNumber.d.ts +2 -2
  101. package/dist/util/wideNumber.js +2 -2
  102. package/package.json +2 -2
  103. package/dist/sqlite/hranaQuerierPool.d.ts +0 -20
  104. package/dist/sqlite/hranaQuerierPool.js +0 -26
  105. package/dist/turso/tursoLocalQuerier.d.ts +0 -24
  106. package/dist/turso/tursoLocalQuerier.js +0 -20
@@ -273,8 +273,7 @@ export class MsSqlDialect extends MergeSqlDialect {
273
273
  * scalar - which is why reading and writing need the two different binders here.
274
274
  */
275
275
  jsonScalarParam(ctx, value) {
276
- return (this.#jsonCompound(ctx, value) ??
277
- this.addValue(ctx.values, typeof value === 'boolean' ? JSON.stringify(value) : value));
276
+ return (this.#jsonCompound(ctx, value) ?? this.addValue(ctx, typeof value === 'boolean' ? JSON.stringify(value) : value));
278
277
  }
279
278
  /**
280
279
  * A value being *written* to a JSON path, which takes the type the driver sent: a `BIT` becomes a
@@ -286,7 +285,7 @@ export class MsSqlDialect extends MergeSqlDialect {
286
285
  if (compound) {
287
286
  return compound;
288
287
  }
289
- const placeholder = this.addValue(ctx.values, value);
288
+ const placeholder = this.addValue(ctx, value);
290
289
  return typeof value === 'boolean' ? `CAST(${placeholder} AS BIT)` : placeholder;
291
290
  }
292
291
  /**
@@ -300,8 +299,7 @@ export class MsSqlDialect extends MergeSqlDialect {
300
299
  if (value === null || typeof value !== 'object') {
301
300
  return undefined;
302
301
  }
303
- ctx.pushValue(JSON.stringify(value));
304
- return `JSON_QUERY(${this.placeholder(ctx.values.length)})`;
302
+ return `JSON_QUERY(${this.addValue(ctx, JSON.stringify(value))})`;
305
303
  }
306
304
  /** An exploded element compares as text here, so `$elemMatch` always expands per field. */
307
305
  jsonContainmentIsPartial = false;
@@ -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 an engine that gives one connection per database and keeps it open for the pool's
6
- * lifetime: every local SQLite driver, the embedded Turso engine, and PGlite.
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. That state is not *isolated*, which is the one way these differ from a real pool: there is a
10
- * single connection under every querier, so two of them cannot hold independent transactions, and a
11
- * unit of work that needs one needs its own pool and therefore its own database.
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 an engine that gives one connection per database and keeps it open for the pool's
4
- * lifetime: every local SQLite driver, the embedded Turso engine, and PGlite.
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. That state is not *isolated*, which is the one way these differ from a real pool: there is a
8
- * single connection under every querier, so two of them cannot hold independent transactions, and a
9
- * unit of work that needs one needs its own pool and therefore its own database.
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
@@ -6,7 +6,7 @@
6
6
  * - Database introspection results (TableSchema[])
7
7
  */
8
8
  import type { EntityGetter } from '../type/entity.js';
9
- import type { EntityMeta, FieldMeta, FieldOptions, Type } from '../type/index.js';
9
+ import type { EntityMeta, EntityWhereMeta, FieldMeta, FieldOptions, Type } from '../type/index.js';
10
10
  import type { NamingStrategy } from '../type/namingStrategy.js';
11
11
  import { SchemaAST } from './schemaAST.js';
12
12
  import { type CanonicalType, type ForeignKeyAction } from './types.js';
@@ -24,6 +24,11 @@ export interface BuildSchemaASTOptions {
24
24
  namingStrategy?: NamingStrategy;
25
25
  /** Default action for foreign key ON DELETE and ON UPDATE clauses */
26
26
  defaultForeignKeyAction?: ForeignKeyAction;
27
+ /**
28
+ * The text of SQL an entity declares - a check, a stored computed column, an index expression or
29
+ * predicate - which only a dialect can render. `buildEntityAST` supplies it from the generator.
30
+ */
31
+ compileDdl?: (sql: EntityWhereMeta<object>, entity: Type<object>) => string;
27
32
  }
28
33
  /**
29
34
  * 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 { ddlText } from '../util/ddlExpression.util.js';
9
+ import { 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';
@@ -30,6 +30,7 @@ export function buildSchemaAST(entities, options = {}) {
30
30
  resolveSchema: options.resolveSchema ?? ((m) => m.schema),
31
31
  resolveColumnName: options.resolveColumnName ?? ((k, f) => namingStrategy?.columnName(f.name ?? k) ?? f.name ?? k),
32
32
  defaultForeignKeyAction: options.defaultForeignKeyAction ?? DEFAULT_FOREIGN_KEY_ACTION,
33
+ compileDdl: options.compileDdl ?? refuseDdl,
33
34
  };
34
35
  for (const pass of [addTableFromEntity, addRelationshipsFromEntity, addIndexesFromEntity]) {
35
36
  for (const entity of entities) {
@@ -38,6 +39,10 @@ export function buildSchemaAST(entities, options = {}) {
38
39
  }
39
40
  return ctx.ast;
40
41
  }
42
+ /** The `compileDdl` of a build given no dialect, which has nothing to render an entity's SQL with. */
43
+ function refuseDdl() {
44
+ throw new TypeError('building the schema of an entity that declares SQL (a check, a stored computed column, an index expression or predicate) needs a dialect to render it: pass `compileDdl`, as `buildEntityAST` does');
45
+ }
41
46
  /**
42
47
  * Resolve the canonical type for a field, inheriting from the referenced
43
48
  * entity's primary key when the field is a foreign-key reference
@@ -78,7 +83,7 @@ function addTableFromEntity(ctx, meta) {
78
83
  const tableName = ctx.resolveTableName(meta);
79
84
  const table = createTableNode(tableName, ctx.resolveSchema(meta));
80
85
  const { columns, primaryKey } = table;
81
- table.checks?.push(...(meta.checks ?? []));
86
+ table.checks?.push(...(meta.checks ?? []).map(({ name, where }) => ({ name, expression: ctx.compileDdl(where, meta.entity) })));
82
87
  // Add columns from fields
83
88
  for (const [key, field] of definedEntries(meta.fields)) {
84
89
  // An inlined expression has no column; a stored one is a column like any other.
@@ -98,7 +103,7 @@ function addTableFromEntity(ctx, meta) {
98
103
  isPrimaryKey,
99
104
  isAutoIncrement: isAutoIncrement(field, isSoleKey),
100
105
  isUnique: field.unique ?? false,
101
- generatedAs: ddlText(field.computed, `the computed column '${columnName}'`),
106
+ generatedAs: field.computed && ctx.compileDdl(field.computed, meta.entity),
102
107
  comment: field.comment,
103
108
  enum: field.enum,
104
109
  table,
@@ -237,27 +242,23 @@ function resolveIncludeColumn(ctx, meta, column) {
237
242
  function addCompositeIndex(ctx, table, meta, idxMeta) {
238
243
  // An entry survives if it is an expression (nothing to resolve) or names a column that exists;
239
244
  // an index left with none is dropped, the same as one naming only unknown columns always was.
240
- const entries = idxMeta.columns
241
- .map((entry) => {
242
- if (entry.expression)
243
- return entry;
245
+ const resolved = idxMeta.columns.flatMap((entry) => {
246
+ if (typeof entry.column !== 'string')
247
+ return [entry];
244
248
  const field = meta.fields[entry.column];
245
249
  const column = field && ctx.resolveColumnName(entry.column, field);
246
- return column && table.columns.has(column) ? { ...entry, column } : undefined;
247
- })
248
- .filter((entry) => entry !== undefined);
249
- if (!entries.length)
250
+ return column && table.columns.has(column) ? [{ ...entry, column }] : [];
251
+ });
252
+ if (!resolved.length)
250
253
  return;
251
- // An index over expressions alone has no column names to build a default name from.
252
- const named = entries.map((entry, at) => (entry.expression ? `expr${at}` : entry.column));
253
254
  ctx.ast.addIndex({
254
- name: idxMeta.name ?? derivedIndexName(table.name, named),
255
+ name: idxMeta.name ?? derivedIndexName(table.name, indexNameParts(resolved)),
255
256
  table,
256
- entries,
257
+ entries: resolved.map((entry) => renderIndexColumn(entry, (sql) => ctx.compileDdl(sql, meta.entity))),
257
258
  include: idxMeta.include?.map((column) => resolveIncludeColumn(ctx, meta, column)),
258
259
  unique: idxMeta.unique ?? false,
259
260
  type: idxMeta.type,
260
- where: idxMeta.where,
261
+ where: idxMeta.where && ctx.compileDdl(idxMeta.where, meta.entity),
261
262
  distance: idxMeta.distance,
262
263
  m: idxMeta.m,
263
264
  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
- /** Header a SQLite driver returns for a statement without a `RETURNING` clause. */
12
- export type SqliteRunResult = {
13
- changes: number;
14
- lastInsertRowid: number | bigint;
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
- * A prepared statement from a driver with better-sqlite3 semantics. `better-sqlite3` and `bun:sqlite`
20
- * answer synchronously, `@tursodatabase/database` with promises, and {@link PreparedSqliteQuerier}
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
- /** Bound parameters reach a driver as `unknown[]` from the compiler; every driver types them narrowly. */
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 the SQLite drivers that expose prepared statements: `better-sqlite3`, `bun:sqlite`
15
- * (through `adaptBunSqlite`) and the embedded Turso engine. They differ only in whether preparing and
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 PreparedSqliteQuerier extends AbstractSqliteQuerier {
7
+ export class AbstractSqliteQuerier extends AbstractSqlQuerier {
20
8
  async internalAll(query, values) {
21
- const stmt = await this.prepare(query);
22
- return (await stmt.all(...toSqliteBindValues(values)));
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 stmt = await this.prepare(query);
32
- // `reader` is true for any statement with a RETURNING clause; `.run()` silently discards
33
- // returned rows, so those statements must go through `.all()` instead.
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, SqliteRunResult } from './abstractSqliteQuerier.js';
2
- import type { SqliteDatabase } from './sqliteQuerier.js';
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 SqliteDatabase}.
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): SqliteDatabase;
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 SqliteDatabase}.
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
- internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
48
- internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
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
- async internalAll(query, values) {
20
- const target = this.tx || this.client;
21
- const res = await target.execute({ sql: query, args: values });
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
  }
@@ -1,6 +1,5 @@
1
1
  export * from './abstractSqliteQuerier.js';
2
2
  export * from './hranaQuerier.js';
3
- export * from './hranaQuerierPool.js';
4
3
  export * from './nodeSqliteQuerierPool.js';
5
4
  export * from './sqliteDialect.js';
6
5
  export * from './sqliteQuerier.js';
@@ -1,6 +1,5 @@
1
1
  export * from './abstractSqliteQuerier.js';
2
2
  export * from './hranaQuerier.js';
3
- export * from './hranaQuerierPool.js';
4
3
  export * from './nodeSqliteQuerierPool.js';
5
4
  export * from './sqliteDialect.js';
6
5
  export * from './sqliteQuerier.js';
@@ -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 SqliteDatabase, SqliteQuerier } from './sqliteQuerier.js';
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<SqliteDatabase, SqliteQuerier, SqliteDialect> {
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<SqliteDatabase>;
26
- protected openDb(): Promise<SqliteDatabase>;
27
- protected buildQuerier(db: SqliteDatabase): SqliteQuerier;
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 { SqliteDatabase } from './sqliteQuerier.js';
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 SqliteDatabase}.
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): SqliteDatabase;
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 SqliteDatabase}.
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. `lastInsertRowid` keeps its `bigint` arm.
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<SqliteDatabase>;
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
- /** A function call takes 127 arguments before SQLite 3.48, as libSQL and Turso embed. */
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
- /** A function call takes 127 arguments before SQLite 3.48, as libSQL and Turso embed. */
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';
@@ -1,12 +1,3 @@
1
- import type { SqlitePreparedStatement } from './abstractSqliteQuerier.js';
2
- /**
3
- * How every local SQLite connection opens. WAL, so a reader does not wait on the writer, and
4
- * `foreign_keys`, which SQLite ships off per connection for backward compatibility: without it the
5
- * constraints uql's own DDL declares are decorative - a declared `onDelete: 'CASCADE'` silently does
6
- * nothing and a dangling reference is accepted.
7
- */
8
- export declare const SQLITE_PRAGMAS: readonly ['journal_mode = WAL', 'foreign_keys = ON'];
1
+ import type { SqliteDatabase } from './sqliteQuerier.js';
9
2
  /** Runs {@link SQLITE_PRAGMAS} through a driver's own statements, whether it answers now or later. */
10
- export declare function applySqlitePragmas(db: {
11
- prepare(sql: string): SqlitePreparedStatement | Promise<SqlitePreparedStatement>;
12
- }): Promise<void>;
3
+ export declare function applySqlitePragmas(db: Pick<SqliteDatabase, 'prepare'>): Promise<void>;
@@ -4,7 +4,7 @@
4
4
  * constraints uql's own DDL declares are decorative - a declared `onDelete: 'CASCADE'` silently does
5
5
  * nothing and a dangling reference is accepted.
6
6
  */
7
- export const SQLITE_PRAGMAS = ['journal_mode = WAL', 'foreign_keys = ON'];
7
+ const SQLITE_PRAGMAS = ['journal_mode = WAL', 'foreign_keys = ON'];
8
8
  /** Runs {@link SQLITE_PRAGMAS} through a driver's own statements, whether it answers now or later. */
9
9
  export async function applySqlitePragmas(db) {
10
10
  for (const pragma of SQLITE_PRAGMAS) {
@@ -1,20 +1,39 @@
1
- import type { ExtraOptions } from '../type/index.js';
2
- import { PreparedSqliteQuerier, type SqlitePreparedStatement } from './abstractSqliteQuerier.js';
1
+ import type { ExtraOptions, RawRow } from '../type/index.js';
2
+ import { AbstractSqliteQuerier, type SqliteBindValue } from './abstractSqliteQuerier.js';
3
3
  import type { SqliteDialect } from './sqliteDialect.js';
4
+ /** What uql reads of a driver's `run()`: the row count. An inserted id comes back through `RETURNING`. */
5
+ export type SqliteRunResult = {
6
+ changes: number;
7
+ };
8
+ /** A prepared statement with better-sqlite3 semantics, answering at once or with a promise. */
9
+ export type SqlitePreparedStatement = {
10
+ /** True for any statement returning rows, including one with a `RETURNING` clause. */
11
+ readonly reader: boolean;
12
+ all(...values: SqliteBindValue[]): unknown[] | Promise<unknown[]>;
13
+ run(...values: SqliteBindValue[]): SqliteRunResult | Promise<SqliteRunResult>;
14
+ iterate(...values: SqliteBindValue[]): Iterable<unknown> | AsyncIterable<unknown>;
15
+ };
4
16
  /**
5
- * Structural subset of a synchronous better-sqlite3-compatible driver, declared locally so this
6
- * querier carries no vendor type. A real `better-sqlite3` `Database` satisfies it directly;
7
- * `bun:sqlite` is adapted to it by {@link Sqlite3QuerierPool}.
17
+ * A SQLite driver that prepares statements. `better-sqlite3` and the embedded Turso engine satisfy it
18
+ * as they are, `bun:sqlite` and `node:sqlite` through their adapters.
8
19
  */
9
20
  export type SqliteDatabase = {
10
- prepare(sql: string): SqlitePreparedStatement;
11
- /** Installs a loadable extension (`sqlite-vec`, ...) into this connection. */
12
- loadExtension(path: string): void;
21
+ prepare(sql: string): SqlitePreparedStatement | Promise<SqlitePreparedStatement>;
13
22
  close(): unknown;
14
23
  };
15
- export declare class SqliteQuerier extends PreparedSqliteQuerier {
24
+ /**
25
+ * Querier for the SQLite drivers that prepare statements: `better-sqlite3`, `bun:sqlite`, `node:sqlite`
26
+ * and the embedded Turso engine. They differ only in whether preparing and stepping answer at once or
27
+ * with a promise, which `await` and `for await` absorb.
28
+ */
29
+ export declare class SqliteQuerier extends AbstractSqliteQuerier {
16
30
  readonly db: SqliteDatabase;
17
31
  readonly extra?: ExtraOptions | undefined;
18
32
  constructor(db: SqliteDatabase, dialect: SqliteDialect, extra?: ExtraOptions | undefined);
19
- protected prepare(query: string): SqlitePreparedStatement;
33
+ /** `reader` picks the call: `run()` would discard the rows of a statement that reads, RETURNING included. */
34
+ protected execute(query: string, values?: unknown[]): Promise<{
35
+ rows: RawRow[];
36
+ changes: number;
37
+ }>;
38
+ internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, unknown>;
20
39
  }