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.
Files changed (104) hide show
  1. package/dist/bunSql/bunSql.util.d.ts +15 -15
  2. package/dist/bunSql/bunSql.util.js +22 -35
  3. package/dist/bunSql/bunSqlQuerier.d.ts +2 -2
  4. package/dist/bunSql/bunSqlQuerier.js +3 -3
  5. package/dist/bunSql/bunSqlQuerierPool.d.ts +1 -13
  6. package/dist/bunSql/bunSqlQuerierPool.js +3 -34
  7. package/dist/d1/d1Querier.d.ts +12 -4
  8. package/dist/d1/d1Querier.js +6 -11
  9. package/dist/d1/d1QuerierPool.d.ts +7 -3
  10. package/dist/d1/d1QuerierPool.js +5 -3
  11. package/dist/entity/decorator/entity.d.ts +5 -9
  12. package/dist/entity/decorator/entity.js +3 -7
  13. package/dist/entity/metadata/definition.d.ts +2 -2
  14. package/dist/entity/metadata/definition.js +13 -22
  15. package/dist/libsql/libsqlDialect.d.ts +1 -1
  16. package/dist/libsql/libsqlDialect.js +1 -1
  17. package/dist/libsql/libsqlQuerierPool.d.ts +18 -9
  18. package/dist/libsql/libsqlQuerierPool.js +32 -20
  19. package/dist/migrate/builder/expressions.js +1 -15
  20. package/dist/migrate/builder/migrationBuilder.d.ts +6 -28
  21. package/dist/migrate/builder/migrationBuilder.js +9 -83
  22. package/dist/migrate/builder/types.d.ts +14 -24
  23. package/dist/migrate/cli.d.ts +1 -6
  24. package/dist/migrate/cli.js +3 -10
  25. package/dist/migrate/codegen/index.d.ts +1 -1
  26. package/dist/migrate/codegen/index.js +1 -1
  27. package/dist/migrate/codegen/indexDecoratorSource.d.ts +1 -1
  28. package/dist/migrate/codegen/indexDecoratorSource.js +4 -8
  29. package/dist/migrate/codegen/migrationFile.d.ts +9 -5
  30. package/dist/migrate/codegen/migrationFile.js +2 -3
  31. package/dist/migrate/ddl/indexDdl.d.ts +4 -2
  32. package/dist/migrate/ddl/indexDdl.js +16 -15
  33. package/dist/migrate/generator/mongoCommand.d.ts +9 -9
  34. package/dist/migrate/generator/mongoCommand.js +1 -1
  35. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +21 -26
  36. package/dist/migrate/generator/mongoSchemaGenerator.js +103 -80
  37. package/dist/migrate/index.d.ts +1 -1
  38. package/dist/migrate/index.js +1 -1
  39. package/dist/migrate/indexPredicate.d.ts +8 -0
  40. package/dist/migrate/indexPredicate.js +52 -0
  41. package/dist/migrate/migrationTarget.d.ts +23 -0
  42. package/dist/migrate/migrationTarget.js +48 -0
  43. package/dist/migrate/migrator.d.ts +17 -45
  44. package/dist/migrate/migrator.js +80 -179
  45. package/dist/migrate/schemaGenerator.d.ts +12 -13
  46. package/dist/migrate/schemaGenerator.js +43 -9
  47. package/dist/mongo/mongoDialect.d.ts +6 -1
  48. package/dist/querier/abstractSharedHandleQuerierPool.d.ts +5 -5
  49. package/dist/querier/abstractSharedHandleQuerierPool.js +5 -5
  50. package/dist/schema/schemaASTBuilder.d.ts +2 -0
  51. package/dist/schema/schemaASTBuilder.js +9 -22
  52. package/dist/sqlite/abstractSqliteQuerier.d.ts +11 -28
  53. package/dist/sqlite/abstractSqliteQuerier.js +14 -33
  54. package/dist/sqlite/bunSqliteAdapter.bun.d.ts +5 -4
  55. package/dist/sqlite/bunSqliteAdapter.bun.js +1 -1
  56. package/dist/sqlite/hranaQuerier.d.ts +6 -4
  57. package/dist/sqlite/hranaQuerier.js +4 -13
  58. package/dist/sqlite/index.d.ts +0 -1
  59. package/dist/sqlite/index.js +0 -1
  60. package/dist/sqlite/localSqliteQuerierPool.d.ts +14 -5
  61. package/dist/sqlite/nodeSqliteAdapter.d.ts +3 -4
  62. package/dist/sqlite/nodeSqliteAdapter.js +3 -6
  63. package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -3
  64. package/dist/sqlite/nodeSqliteQuerierPool.js +3 -1
  65. package/dist/sqlite/sqliteDialect.d.ts +1 -1
  66. package/dist/sqlite/sqliteDialect.js +1 -1
  67. package/dist/sqlite/sqlitePragmas.d.ts +2 -11
  68. package/dist/sqlite/sqlitePragmas.js +1 -1
  69. package/dist/sqlite/sqliteQuerier.d.ts +29 -10
  70. package/dist/sqlite/sqliteQuerier.js +26 -4
  71. package/dist/sqlite/sqliteQuerierPool.d.ts +7 -3
  72. package/dist/sqlite/sqliteQuerierPool.js +12 -8
  73. package/dist/turso/index.d.ts +1 -0
  74. package/dist/turso/index.js +1 -0
  75. package/dist/turso/local.d.ts +1 -1
  76. package/dist/turso/local.js +1 -1
  77. package/dist/turso/tursoDialect.d.ts +4 -9
  78. package/dist/turso/tursoDialect.js +4 -12
  79. package/dist/turso/tursoLocalDialect.d.ts +10 -0
  80. package/dist/turso/tursoLocalDialect.js +13 -0
  81. package/dist/turso/tursoLocalQuerierPool.d.ts +8 -13
  82. package/dist/turso/tursoLocalQuerierPool.js +6 -5
  83. package/dist/turso/tursoQuerierPool.d.ts +15 -30
  84. package/dist/turso/tursoQuerierPool.js +13 -23
  85. package/dist/turso/tursoSessionQuerier.d.ts +57 -0
  86. package/dist/turso/tursoSessionQuerier.js +50 -0
  87. package/dist/type/entity.d.ts +37 -62
  88. package/dist/type/migration.d.ts +11 -40
  89. package/dist/type/queryRaw.d.ts +8 -0
  90. package/dist/type/queryRaw.js +11 -0
  91. package/dist/util/ddlExpression.util.d.ts +5 -3
  92. package/dist/util/ddlExpression.util.js +19 -12
  93. package/dist/util/raw.d.ts +6 -1
  94. package/dist/util/raw.js +11 -8
  95. package/dist/util/sqlLiteral.js +5 -3
  96. package/dist/util/wideNumber.d.ts +2 -2
  97. package/dist/util/wideNumber.js +2 -2
  98. package/package.json +2 -2
  99. package/dist/migrate/schemaGeneratorAsync.d.ts +0 -7
  100. package/dist/migrate/schemaGeneratorAsync.js +0 -12
  101. package/dist/sqlite/hranaQuerierPool.d.ts +0 -20
  102. package/dist/sqlite/hranaQuerierPool.js +0 -26
  103. package/dist/turso/tursoLocalQuerier.d.ts +0 -24
  104. package/dist/turso/tursoLocalQuerier.js +0 -20
@@ -1,14 +1,13 @@
1
1
  import type { SQL } from 'bun';
2
2
  import type { PrimaryKey, RawRow } from '../type/index.js';
3
- export type BunSqlResult<T = RawRow> = T[] & {
3
+ /** The header a `bun:sql` result carries next to its rows. */
4
+ export type BunSqlHeader = {
4
5
  count?: number;
5
- affectedRows?: number;
6
+ affectedRows?: number | null;
6
7
  lastInsertRowid?: PrimaryKey;
7
8
  };
8
- /**
9
- * The connection a {@link BunSqlQuerier} holds. `ReservedSQL` satisfies it as it is; the SQLite
10
- * adapter, which has no reservation, is given the pool's own handle with an inert `release`.
11
- */
9
+ export type BunSqlResult<T = RawRow> = T[] & BunSqlHeader;
10
+ /** The connection a {@link BunSqlQuerier} holds: what a `ReservedSQL` exposes of itself. */
12
11
  export type BunSqlConn = Pick<SQL, 'unsafe'> & {
13
12
  release(): void;
14
13
  };
@@ -17,24 +16,25 @@ export type BunSqlConn = Pick<SQL, 'unsafe'> & {
17
16
  * engine uql supports reaches it through a dedicated pool, and keeping this one total means Bun
18
17
  * gaining an adapter is a compile error here until the dialect is named.
19
18
  */
20
- export type BunSqlDialectName = 'postgres' | 'cockroachdb' | 'mysql' | 'mariadb' | 'sqlite';
19
+ export type BunSqlDialectName = 'postgres' | 'cockroachdb' | 'mysql' | 'mariadb';
21
20
  /**
22
- * Rows a statement read or wrote, from whichever field this adapter fills: Postgres, CockroachDB and
23
- * SQLite report `count` and leave `affectedRows` null, MySQL and MariaDB the other way around - and
24
- * `count` is 0 on a MySQL write, so the two are read in that order rather than coalesced.
21
+ * Rows a statement read or wrote, from whichever field this adapter fills: Postgres and CockroachDB
22
+ * report `count` and leave `affectedRows` null, MySQL and MariaDB the other way around - and `count`
23
+ * is 0 on a MySQL write, so the two are read in that order rather than coalesced.
25
24
  *
26
25
  * `undefined` when the header carries neither, which leaves the returned rows to answer for it -
27
26
  * `buildUpdateResult` already falls back to their count, and it is the only one that should.
28
27
  */
29
28
  export declare function getAffectedRows(res: BunSqlResult): number | undefined;
30
29
  /**
31
- * Normalizes SQL.Options into a structure that Bun's SQL engine expects for a given dialect.
32
- * Crucially handles 'filename' mapping for SQLite and alias resolution for Cockroach/MariaDB.
30
+ * Normalizes `SQL.Options` into what Bun's SQL engine expects for a given dialect: the adapter a
31
+ * CockroachDB URL dials, and every BIGINT read as a `bigint` whatever the config asks, for
32
+ * `decodeBigInts` to decode exactly.
33
33
  */
34
- export declare function normalizeBunOpts(config: SQL.Options, dialectName: BunSqlDialectName): SQL.Options;
34
+ export declare function normalizeBunOpts(config: SQL.Options, dialectName: BunSqlDialectName): SQL.PostgresOrMySQLOptions;
35
35
  /**
36
- * The engine a Bun `SQL.Options` points at: a SQLite file or `:memory:`, then the URL's scheme, then
37
- * the `adapter` Bun itself would read, and Postgres last - which is Bun's own fallback.
36
+ * The engine a Bun `SQL.Options` points at: the URL's scheme - a SQLite file or `:memory:` counting as
37
+ * `sqlite` - then the `adapter` Bun itself would read, and Postgres last, which is Bun's own fallback.
38
38
  */
39
39
  export declare function inferDialectName(config: SQL.Options): BunSqlDialectName;
40
40
  /** The id a MySQL-family insert reports, by the same wide-integer rule as every other BIGINT. */
@@ -1,8 +1,8 @@
1
1
  import { decodeWideNumber } from '../util/wideNumber.js';
2
2
  /**
3
- * Rows a statement read or wrote, from whichever field this adapter fills: Postgres, CockroachDB and
4
- * SQLite report `count` and leave `affectedRows` null, MySQL and MariaDB the other way around - and
5
- * `count` is 0 on a MySQL write, so the two are read in that order rather than coalesced.
3
+ * Rows a statement read or wrote, from whichever field this adapter fills: Postgres and CockroachDB
4
+ * report `count` and leave `affectedRows` null, MySQL and MariaDB the other way around - and `count`
5
+ * is 0 on a MySQL write, so the two are read in that order rather than coalesced.
6
6
  *
7
7
  * `undefined` when the header carries neither, which leaves the returned rows to answer for it -
8
8
  * `buildUpdateResult` already falls back to their count, and it is the only one that should.
@@ -11,21 +11,13 @@ export function getAffectedRows(res) {
11
11
  return res.affectedRows || res.count || undefined;
12
12
  }
13
13
  /**
14
- * Normalizes SQL.Options into a structure that Bun's SQL engine expects for a given dialect.
15
- * Crucially handles 'filename' mapping for SQLite and alias resolution for Cockroach/MariaDB.
14
+ * Normalizes `SQL.Options` into what Bun's SQL engine expects for a given dialect: the adapter a
15
+ * CockroachDB URL dials, and every BIGINT read as a `bigint` whatever the config asks, for
16
+ * `decodeBigInts` to decode exactly.
16
17
  */
17
18
  export function normalizeBunOpts(config, dialectName) {
18
- if (dialectName === 'sqlite') {
19
- const rawFilename = ('filename' in config ? config.filename : null) || ('url' in config ? config.url : null) || ':memory:';
20
- return {
21
- ...config,
22
- adapter: 'sqlite',
23
- filename: rawFilename.toString(),
24
- };
25
- }
26
19
  const adapter = dialectName === 'cockroachdb' ? 'postgres' : dialectName;
27
- // BIGINT as a `bigint`, so a wide one reaches uql exact for `decodeBigInts` to decode.
28
- const opts = { bigint: true, ...config, adapter };
20
+ const opts = { ...config, adapter, bigint: true };
29
21
  if (!opts.url) {
30
22
  return opts;
31
23
  }
@@ -41,30 +33,24 @@ export function normalizeBunOpts(config, dialectName) {
41
33
  return opts;
42
34
  }
43
35
  /**
44
- * The engine a Bun `SQL.Options` points at: a SQLite file or `:memory:`, then the URL's scheme, then
45
- * the `adapter` Bun itself would read, and Postgres last - which is Bun's own fallback.
36
+ * The engine a Bun `SQL.Options` points at: the URL's scheme - a SQLite file or `:memory:` counting as
37
+ * `sqlite` - then the `adapter` Bun itself would read, and Postgres last, which is Bun's own fallback.
46
38
  */
47
39
  export function inferDialectName(config) {
48
- if ('filename' in config && config.filename) {
49
- return 'sqlite';
50
- }
51
40
  const url = 'url' in config ? config.url?.toString() : undefined;
52
- if (url) {
53
- if (url === ':memory:' || url.endsWith('.db') || url.endsWith('.sqlite')) {
54
- return 'sqlite';
55
- }
56
- const scheme = url.split(':')[0];
57
- const elsewhere = ELSEWHERE.get(scheme);
41
+ const file = ('filename' in config && !!config.filename) || url === ':memory:' || /\.(db|sqlite)$/.test(url ?? '');
42
+ // Every Bun adapter name is a scheme here too, so the same two tables answer both.
43
+ for (const name of [file ? 'sqlite' : url?.split(':')[0], config.adapter]) {
44
+ const elsewhere = name && ELSEWHERE.get(name);
58
45
  if (elsewhere) {
59
- throw new TypeError(`Bun SQL has no ${elsewhere} driver; use the dedicated uql-orm/${elsewhere} pool`);
46
+ throw new TypeError(`uql-orm/bunSql does not drive ${elsewhere}; use the dedicated uql-orm/${elsewhere} pool`);
60
47
  }
61
- const dialect = SCHEMES.get(scheme);
48
+ const dialect = name && SCHEMES.get(name);
62
49
  if (dialect) {
63
50
  return dialect;
64
51
  }
65
52
  }
66
- // Every Bun adapter name is a scheme here too, so the one table answers both questions.
67
- return (config.adapter && SCHEMES.get(config.adapter)) || 'postgres';
53
+ return 'postgres';
68
54
  }
69
55
  /** A `Map` rather than an object literal, whose inherited keys would answer for a `constructor://` URL. */
70
56
  const SCHEMES = new Map([
@@ -73,18 +59,19 @@ const SCHEMES = new Map([
73
59
  ['mysql', 'mysql'],
74
60
  ['mysql2', 'mysql'],
75
61
  ['mariadb', 'mariadb'],
76
- ['sqlite', 'sqlite'],
77
- ['sqlite3', 'sqlite'],
78
62
  ['cockroachdb', 'cockroachdb'],
79
63
  ]);
80
64
  /**
81
- * Engines uql drives elsewhere but Bun cannot dial. Named rather than left out: Bun's `SQL` falls
82
- * back to Postgres for any scheme it does not know, so an unlisted `mssql://` would have connected
83
- * as Postgres and failed on the first statement instead of on the pool.
65
+ * Engines uql drives through another pool. Named rather than left out: Bun's `SQL` falls back to
66
+ * Postgres for any scheme it does not know, so an unlisted `mssql://` would have connected as Postgres
67
+ * and failed on the first statement instead of on the pool. SQLite runs on `Sqlite3QuerierPool`, which
68
+ * uses `bun:sqlite` under Bun.
84
69
  */
85
70
  const ELSEWHERE = new Map([
86
71
  ['mssql', 'mssql'],
87
72
  ['sqlserver', 'mssql'],
73
+ ['sqlite', 'sqlite'],
74
+ ['sqlite3', 'sqlite'],
88
75
  ]);
89
76
  /** The id a MySQL-family insert reports, by the same wide-integer rule as every other BIGINT. */
90
77
  export function getInsertId(res) {
@@ -1,7 +1,7 @@
1
1
  import { AbstractPoolQuerier } from '../querier/abstractPoolQuerier.js';
2
2
  import { type BunSqlConn } from './bunSql.util.js';
3
3
  /**
4
- * Querier for `bun:sql`, Bun's built-in driver for Postgres, MySQL, MariaDB, CockroachDB and SQLite.
4
+ * Querier for `bun:sql`, Bun's built-in driver for Postgres, MySQL, MariaDB and CockroachDB.
5
5
  *
6
6
  * @remarks Exposes no `SQL` of its own: the pool's would run a statement on any connection, outside
7
7
  * the transaction this one's reserved connection holds. Raw access is `pool.sql`.
@@ -14,7 +14,7 @@ export declare class BunSqlQuerier extends AbstractPoolQuerier<BunSqlConn> {
14
14
  *
15
15
  * Bun's `SQL.Query` is a `Promise` with no cursor or async-iterator API
16
16
  * ([oven-sh/bun#17181](https://github.com/oven-sh/bun/issues/17181)), so the rows have to be paged
17
- * in SQL instead - which the Postgres wire family can do and MySQL and SQLite cannot.
17
+ * in SQL instead - which the Postgres wire family can do and MySQL cannot.
18
18
  */
19
19
  protected internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, any>;
20
20
  private execute;
@@ -3,7 +3,7 @@ import { AbstractPoolQuerier } from '../querier/abstractPoolQuerier.js';
3
3
  import { decodeBigInts } from '../util/wideNumber.js';
4
4
  import { getAffectedRows, getInsertId } from './bunSql.util.js';
5
5
  /**
6
- * Querier for `bun:sql`, Bun's built-in driver for Postgres, MySQL, MariaDB, CockroachDB and SQLite.
6
+ * Querier for `bun:sql`, Bun's built-in driver for Postgres, MySQL, MariaDB and CockroachDB.
7
7
  *
8
8
  * @remarks Exposes no `SQL` of its own: the pool's would run a statement on any connection, outside
9
9
  * the transaction this one's reserved connection holds. Raw access is `pool.sql`.
@@ -18,7 +18,7 @@ export class BunSqlQuerier extends AbstractPoolQuerier {
18
18
  rows: Array.from(res, decodeBigInts),
19
19
  changes: getAffectedRows(res),
20
20
  id: getInsertId(res),
21
- upsertStatus: res.affectedRows,
21
+ upsertStatus: res.affectedRows ?? undefined,
22
22
  });
23
23
  }
24
24
  /**
@@ -26,7 +26,7 @@ export class BunSqlQuerier extends AbstractPoolQuerier {
26
26
  *
27
27
  * Bun's `SQL.Query` is a `Promise` with no cursor or async-iterator API
28
28
  * ([oven-sh/bun#17181](https://github.com/oven-sh/bun/issues/17181)), so the rows have to be paged
29
- * in SQL instead - which the Postgres wire family can do and MySQL and SQLite cannot.
29
+ * in SQL instead - which the Postgres wire family can do and MySQL cannot.
30
30
  */
31
31
  async *internalStream(query, values) {
32
32
  if (!this.dialect.features.serverSideCursors) {
@@ -8,12 +8,7 @@ export declare class BunSqlQuerierPool extends AbstractSqlQuerierPool<BunSqlQuer
8
8
  readonly config: SQL.Options;
9
9
  readonly sql: SQL;
10
10
  readonly sqlDialectName: BunSqlDialectName;
11
- private sqliteConfigured?;
12
- /**
13
- * @param config Bun's own `SQL.Options`, from which the engine is inferred. SQLite through here is
14
- * deprecated: `Sqlite3QuerierPool` (`uql-orm/sqlite`) runs on `bun:sqlite` under Bun, and streams,
15
- * loads extensions and prepares statements, none of which `bun:sql`'s SQLite adapter can.
16
- */
11
+ /** @param config Bun's own `SQL.Options`, from which the engine is inferred. */
17
12
  constructor(config: SQL.Options, extra?: ExtraOptions);
18
13
  /**
19
14
  * Provides a pg-compatible interface for libraries like connect-pg-simple.
@@ -21,12 +16,5 @@ export declare class BunSqlQuerierPool extends AbstractSqlQuerierPool<BunSqlQuer
21
16
  */
22
17
  get pool(): SqlPoolCompat;
23
18
  getQuerier(): Promise<BunSqlQuerier>;
24
- /**
25
- * Bun's SQLite adapter does not support connection reservation (it's unpooled), so the pool hands out
26
- * its one handle, configured like every other local SQLite connection on the first acquisition, and
27
- * a `release` that does nothing: the handle is the pool's, and outlives every querier over it.
28
- */
29
- private acquire;
30
- private configureSqlite;
31
19
  end(): Promise<void>;
32
20
  }
@@ -6,8 +6,6 @@ import { MySqlDialect } from '../mysql/mysqlDialect.js';
6
6
  import { PostgresDialect } from '../postgres/postgresDialect.js';
7
7
  import { POSTGRES_WIRE_DRIVER_CAPABILITIES } from '../postgres/postgresWireDriverCapabilities.js';
8
8
  import { AbstractSqlQuerierPool } from '../querier/index.js';
9
- import { SqliteDialect } from '../sqlite/sqliteDialect.js';
10
- import { SQLITE_PRAGMAS } from '../sqlite/sqlitePragmas.js';
11
9
  import { decodeBigInts } from '../util/wideNumber.js';
12
10
  import { getAffectedRows, inferDialectName, normalizeBunOpts, } from './bunSql.util.js';
13
11
  import { BunSqlQuerier } from './bunSqlQuerier.js';
@@ -24,30 +22,19 @@ const DialectMap = {
24
22
  cockroachdb: [CockroachDialect, POSTGRES_WIRE_DRIVER_CAPABILITIES],
25
23
  mysql: [MySqlDialect],
26
24
  mariadb: [MariaDialect],
27
- sqlite: [SqliteDialect],
28
25
  };
29
- const SQLITE_DEPRECATION = 'SQLite through uql-orm/bunSql is deprecated; use Sqlite3QuerierPool from uql-orm/sqlite, which runs on bun:sqlite under Bun';
30
26
  export class BunSqlQuerierPool extends AbstractSqlQuerierPool {
31
27
  config;
32
28
  sql;
33
29
  sqlDialectName;
34
- sqliteConfigured;
35
- /**
36
- * @param config Bun's own `SQL.Options`, from which the engine is inferred. SQLite through here is
37
- * deprecated: `Sqlite3QuerierPool` (`uql-orm/sqlite`) runs on `bun:sqlite` under Bun, and streams,
38
- * loads extensions and prepares statements, none of which `bun:sql`'s SQLite adapter can.
39
- */
30
+ /** @param config Bun's own `SQL.Options`, from which the engine is inferred. */
40
31
  constructor(config, extra) {
41
32
  const dialectName = inferDialectName(config);
42
33
  const [Dialect, driverCapabilities] = DialectMap[dialectName];
43
34
  super(new Dialect({ ...dialectOptionsFrom(extra), driverCapabilities }), extra);
44
35
  this.config = config;
45
36
  this.sqlDialectName = dialectName;
46
- if (dialectName === 'sqlite') {
47
- process.emitWarning(SQLITE_DEPRECATION, { type: 'DeprecationWarning', code: 'UQL_BUNSQL_SQLITE' });
48
- }
49
- const opts = normalizeBunOpts(config, dialectName);
50
- this.sql = new SQL(opts);
37
+ this.sql = new SQL(normalizeBunOpts(config, dialectName));
51
38
  }
52
39
  /**
53
40
  * Provides a pg-compatible interface for libraries like connect-pg-simple.
@@ -65,25 +52,7 @@ export class BunSqlQuerierPool extends AbstractSqlQuerierPool {
65
52
  };
66
53
  }
67
54
  async getQuerier() {
68
- return new BunSqlQuerier(() => this.acquire(), this.dialect, this.extra);
69
- }
70
- /**
71
- * Bun's SQLite adapter does not support connection reservation (it's unpooled), so the pool hands out
72
- * its one handle, configured like every other local SQLite connection on the first acquisition, and
73
- * a `release` that does nothing: the handle is the pool's, and outlives every querier over it.
74
- */
75
- async acquire() {
76
- if (this.sqlDialectName !== 'sqlite') {
77
- return this.sql.reserve();
78
- }
79
- this.sqliteConfigured ??= this.configureSqlite();
80
- await this.sqliteConfigured;
81
- return { unsafe: this.sql.unsafe.bind(this.sql), release: () => { } };
82
- }
83
- async configureSqlite() {
84
- for (const pragma of SQLITE_PRAGMAS) {
85
- await this.sql.unsafe(`PRAGMA ${pragma}`);
86
- }
55
+ return new BunSqlQuerier(() => this.sql.reserve(), this.dialect, this.extra);
87
56
  }
88
57
  async end() {
89
58
  await this.sql.close();
@@ -1,6 +1,6 @@
1
1
  import { AbstractSqliteQuerier } from '../sqlite/abstractSqliteQuerier.js';
2
2
  import type { SqliteDialect } from '../sqlite/sqliteDialect.js';
3
- import type { ExtraOptions } from '../type/index.js';
3
+ import type { ExtraOptions, RawRow } from '../type/index.js';
4
4
  export interface D1Meta {
5
5
  duration?: number;
6
6
  size_after?: number;
@@ -25,6 +25,7 @@ export interface D1ExecResult {
25
25
  export interface D1PreparedStatement {
26
26
  bind(...values: unknown[]): D1PreparedStatement;
27
27
  first<T = unknown>(colName?: string): Promise<T | null>;
28
+ /** Documented by D1 as an alias of {@link all}: both answer the rows and `meta.changes`. */
28
29
  run<T = unknown>(): Promise<D1Result<T>>;
29
30
  all<T = unknown>(): Promise<D1Result<T>>;
30
31
  raw<T = unknown>(): Promise<T[]>;
@@ -35,12 +36,19 @@ export interface D1Database {
35
36
  batch<T = unknown>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;
36
37
  exec(query: string): Promise<D1ExecResult>;
37
38
  }
38
- /** The only part of a D1 binding the querier uses; a full {@link D1Database} satisfies it. */
39
+ /**
40
+ * The only part of a D1 binding the querier uses: what a {@link D1Database} and a session from
41
+ * `withSession()`, which a read-replicated database is read through, both have.
42
+ */
39
43
  export type D1Preparer = Pick<D1Database, 'prepare'>;
40
44
  export declare class D1Querier extends AbstractSqliteQuerier {
41
45
  readonly db: D1Preparer;
42
46
  readonly extra?: ExtraOptions | undefined;
43
47
  constructor(db: D1Preparer, dialect: SqliteDialect, extra?: ExtraOptions | undefined);
44
- internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
45
- internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
48
+ protected execute(query: string, values?: unknown[]): Promise<{
49
+ rows: RawRow[];
50
+ changes: number;
51
+ }>;
52
+ /** D1 answers `BEGIN` with `D1_ERROR: not authorized`: a single statement is its only atomic unit. */
53
+ protected internalBegin(): Promise<void>;
46
54
  }
@@ -7,18 +7,13 @@ export class D1Querier extends AbstractSqliteQuerier {
7
7
  this.db = db;
8
8
  this.extra = extra;
9
9
  }
10
- async internalAll(query, values) {
10
+ async execute(query, values) {
11
11
  const stmt = this.db.prepare(query);
12
- const bound = values?.length ? stmt.bind(...values) : stmt;
13
- const res = await bound.all();
14
- return res.results;
12
+ const { results, meta } = await (values?.length ? stmt.bind(...values) : stmt).all();
13
+ return { rows: results, changes: meta.changes ?? 0 };
15
14
  }
16
- async internalRun(query, values) {
17
- const stmt = this.db.prepare(query);
18
- const bound = values?.length ? stmt.bind(...values) : stmt;
19
- const res = await bound.run();
20
- const rows = res.results;
21
- const changes = rows.length || res.meta?.changes || 0;
22
- return this.buildUpdateResult({ rows, changes, id: res.meta?.last_row_id });
15
+ /** D1 answers `BEGIN` with `D1_ERROR: not authorized`: a single statement is its only atomic unit. */
16
+ async internalBegin() {
17
+ throw new TypeError('Cloudflare D1 has no transactions: write the changes as one statement, or idempotently');
23
18
  }
24
19
  }
@@ -1,10 +1,14 @@
1
1
  import { AbstractSqlQuerierPool } from '../querier/index.js';
2
2
  import type { ExtraOptions } from '../type/index.js';
3
- import { type D1Database, D1Querier } from './d1Querier.js';
3
+ import { type D1Preparer, D1Querier } from './d1Querier.js';
4
4
  import { D1SqliteDialect } from './d1SqliteDialect.js';
5
+ /**
6
+ * Pool for Cloudflare D1. It holds nothing: every querier runs on what it was given, `env.DB` or a
7
+ * session from `env.DB.withSession()`, the way a read-replicated database is read consistently.
8
+ */
5
9
  export declare class D1QuerierPool extends AbstractSqlQuerierPool<D1Querier, D1SqliteDialect> {
6
- readonly db: D1Database;
7
- constructor(db: D1Database, extra?: ExtraOptions);
10
+ readonly db: D1Preparer;
11
+ constructor(db: D1Preparer, extra?: ExtraOptions);
8
12
  getQuerier(): Promise<D1Querier>;
9
13
  end(): Promise<void>;
10
14
  }
@@ -2,6 +2,10 @@ import { dialectOptionsFrom } from '../dialect/abstractDialect.js';
2
2
  import { AbstractSqlQuerierPool } from '../querier/index.js';
3
3
  import { D1Querier } from './d1Querier.js';
4
4
  import { D1SqliteDialect } from './d1SqliteDialect.js';
5
+ /**
6
+ * Pool for Cloudflare D1. It holds nothing: every querier runs on what it was given, `env.DB` or a
7
+ * session from `env.DB.withSession()`, the way a read-replicated database is read consistently.
8
+ */
5
9
  export class D1QuerierPool extends AbstractSqlQuerierPool {
6
10
  db;
7
11
  constructor(db, extra) {
@@ -11,7 +15,5 @@ export class D1QuerierPool extends AbstractSqlQuerierPool {
11
15
  async getQuerier() {
12
16
  return new D1Querier(this.db, this.dialect, this.extra);
13
17
  }
14
- async end() {
15
- // no-op for D1 bindings
16
- }
18
+ async end() { }
17
19
  }
@@ -1,4 +1,4 @@
1
- import type { EntityIndexOptions, EntityOptions, FieldKey, FilterOptions, IndexColumnInput, KeyMap, Type } from '../../type/index.js';
1
+ import type { EntityIndexColumnInput, EntityIndexOptions, EntityOptions, FilterOptions, RefMap, Type } from '../../type/index.js';
2
2
  /**
3
3
  * Marks a class as an entity and finalizes its metadata.
4
4
  *
@@ -16,12 +16,8 @@ export declare function Entity<E>(opts?: EntityOptions<E>): (entity: Type<E>, co
16
16
  */
17
17
  export declare function Filter<E>(name: string, opts: FilterOptions<E>): (entity: Type<E>) => void;
18
18
  /**
19
- * Declares a composite index, its columns read off the key map. Stacks, so several may sit above one
20
- * class. `E` is inferred from the class the returned decorator is applied to, which is what types the
21
- * key map: `@Index((user) => [user.nope])` does not compile, and a rename reaches every column.
22
- *
23
- * @example `@Index((user) => [user.lastName, user.firstName], { name: 'users_fullname_idx' })`
24
- * @example `@Index((user) => [user.email], { unique: true })`
25
- * @example `@Index((user) => [user.email], { unique: true, where: { deletedAt: null } })`
19
+ * Declares a composite index, its columns read off the entity's refs, so `@Index((user) => [user.nope])`
20
+ * does not compile and a rename reaches every column. Stacks, so several may sit above one class.
21
+ * @example `@Index((user) => [user.lastName, raw`lower(${user.email})`], { unique: true })`
26
22
  */
27
- export declare function Index<E>(columns: (keys: KeyMap<E>) => readonly IndexColumnInput<FieldKey<E>, E>[], options?: EntityIndexOptions<E>): (entity: Type<E>) => void;
23
+ export declare function Index<E>(columns: (refs: RefMap<E>) => readonly EntityIndexColumnInput<E>[], options?: EntityIndexOptions<E>): (entity: Type<E>) => void;
@@ -28,13 +28,9 @@ export function Filter(name, opts) {
28
28
  };
29
29
  }
30
30
  /**
31
- * Declares a composite index, its columns read off the key map. Stacks, so several may sit above one
32
- * class. `E` is inferred from the class the returned decorator is applied to, which is what types the
33
- * key map: `@Index((user) => [user.nope])` does not compile, and a rename reaches every column.
34
- *
35
- * @example `@Index((user) => [user.lastName, user.firstName], { name: 'users_fullname_idx' })`
36
- * @example `@Index((user) => [user.email], { unique: true })`
37
- * @example `@Index((user) => [user.email], { unique: true, where: { deletedAt: null } })`
31
+ * Declares a composite index, its columns read off the entity's refs, so `@Index((user) => [user.nope])`
32
+ * does not compile and a rename reaches every column. Stacks, so several may sit above one class.
33
+ * @example `@Index((user) => [user.lastName, raw`lower(${user.email})`], { unique: true })`
38
34
  */
39
35
  export function Index(columns, options = {}) {
40
36
  return (entity) => {
@@ -11,8 +11,8 @@ export declare function defineRelation<E, T extends object>(entity: Type<E>, key
11
11
  export declare function relationRegistration<T extends object, O>({ mappedBy, references, ...opts }: RelationOptions<T, O>): RelationRegistration;
12
12
  export declare function defineHook<E>(entity: Type<E>, methodName: string, event: HookEvent): EntityMeta<E>;
13
13
  /**
14
- * Declares a composite index, its columns read off the key map. `unique` and the authored column sugar
15
- * are normalized here, which is what lets the dialects render one shape instead of re-parsing it.
14
+ * Declares a composite index, its columns read off the entity's refs. `unique` and the authored column
15
+ * sugar are normalized here, which is what lets the dialects render one shape instead of re-parsing it.
16
16
  */
17
17
  export declare function defineIndex<E>(entity: Type<E>, index: EntityIndexInput<E>): EntityMeta<E>;
18
18
  export declare function defineFilter<E>(entity: Type<E>, name: string, opts: FilterOptions<E>): EntityMeta<E>;
@@ -1,6 +1,6 @@
1
1
  import { SOFT_DELETE_FILTER } from '../../type/index.js';
2
2
  import { isInlinedExpression } from '../../util/field.util.js';
3
- import { entityName, entitySql, entityWhere, fieldOptionConflict, getKeys, hasKeys, isToManyRelation, lowerFirst, normalizeIndexColumn, upperFirst, definedEntries, } from '../../util/index.js';
3
+ import { entityName, entitySql, entityWhere, fieldOptionConflict, getKeys, hasKeys, isToManyRelation, lowerFirst, memberRefs, normalizeIndexColumn, upperFirst, definedEntries, } from '../../util/index.js';
4
4
  import { ownRegistrations } from '../decorator/bag.js';
5
5
  /**
6
6
  * A map held on `globalThis` through the global symbol registry, so a single one survives multiple
@@ -56,8 +56,8 @@ export function defineRelation(entity, key, opts) {
56
56
  export function relationRegistration({ mappedBy, references, ...opts }) {
57
57
  return {
58
58
  ...opts,
59
- ...(mappedBy ? { mappedBy: mappedBy(keyMap()) } : {}),
60
- ...(references ? { references: [...references(keyMap(), keyMap())] } : {}),
59
+ ...(mappedBy && { mappedBy: mappedBy(keyMap()) }),
60
+ ...(references && { references: [...references(keyMap(), keyMap())] }),
61
61
  };
62
62
  }
63
63
  /** Every entity's key map: a callback only reads one property off it, and that property is its own key. */
@@ -83,26 +83,22 @@ function addRelation(entity, key, registration) {
83
83
  }
84
84
  export function defineHook(entity, methodName, event) {
85
85
  const meta = ensureWritableMeta(entity);
86
- if (!meta.hooks)
87
- meta.hooks = {};
88
- if (!meta.hooks[event])
89
- meta.hooks[event] = [];
90
- meta.hooks[event].push({ methodName });
86
+ ((meta.hooks ??= {})[event] ??= []).push({ methodName });
91
87
  return meta;
92
88
  }
93
89
  /**
94
- * Declares a composite index, its columns read off the key map. `unique` and the authored column sugar
95
- * are normalized here, which is what lets the dialects render one shape instead of re-parsing it.
90
+ * Declares a composite index, its columns read off the entity's refs. `unique` and the authored column
91
+ * sugar are normalized here, which is what lets the dialects render one shape instead of re-parsing it.
96
92
  */
97
93
  export function defineIndex(entity, index) {
98
94
  const meta = ensureWritableMeta(entity);
99
- const keys = keyMap();
95
+ const refs = memberRefs();
100
96
  (meta.indexes ??= []).push({
101
97
  ...index,
102
98
  unique: index.unique ?? false,
103
99
  where: index.where && entityWhere(index.where),
104
- columns: index.columns(keys).map(normalizeIndexColumn),
105
- include: index.include?.(keys),
100
+ columns: index.columns(refs).map(normalizeIndexColumn),
101
+ include: index.include?.(refs).map((ref) => ref.key),
106
102
  });
107
103
  return meta;
108
104
  }
@@ -114,9 +110,7 @@ export function defineFilter(entity, name, opts) {
114
110
  if (opts.security && opts.onMissing === 'skip') {
115
111
  throw TypeError(`'${entity.name}' security filter '${name}' cannot use onMissing: 'skip' (it must fail closed)`);
116
112
  }
117
- if (!meta.filters)
118
- meta.filters = {};
119
- meta.filters[name] = opts;
113
+ (meta.filters ??= {})[name] = opts;
120
114
  return meta;
121
115
  }
122
116
  /**
@@ -208,9 +202,7 @@ export function defineEntity(entity, opts = {}) {
208
202
  }
209
203
  if (softDeleteKeys.length) {
210
204
  meta.softDelete = softDeleteKeys[0];
211
- if (!meta.filters)
212
- meta.filters = {};
213
- meta.filters[SOFT_DELETE_FILTER] = { where: { [meta.softDelete]: null }, default: true };
205
+ (meta.filters ??= {})[SOFT_DELETE_FILTER] = { where: { [meta.softDelete]: null }, default: true };
214
206
  }
215
207
  const ids = getIdKeys(meta);
216
208
  if (!ids.length) {
@@ -506,10 +498,9 @@ function extendMeta(target, source) {
506
498
  }
507
499
  // Merge hooks from parent entity (parent hooks execute first)
508
500
  if (source.hooks) {
509
- if (!target.hooks)
510
- target.hooks = {};
501
+ const hooks = (target.hooks ??= {});
511
502
  for (const [event, sourceList] of definedEntries(source.hooks)) {
512
- target.hooks[event] = [...sourceList, ...(target.hooks[event] ?? [])];
503
+ hooks[event] = [...sourceList, ...(hooks[event] ?? [])];
513
504
  }
514
505
  }
515
506
  }
@@ -12,7 +12,7 @@ export declare class LibsqlDialect extends SqliteDialect {
12
12
  * functions this dialect would otherwise inherit are never present.
13
13
  *
14
14
  * @remarks `inner` and `l1` are left out: `vector_distance_dot` only exists in the newer Rust
15
- * engine (see `TursoDialect`) and no libSQL build has an L1 metric. Both raise the same
15
+ * engine (see `TursoLocalDialect`) and no libSQL build has an L1 metric. Both raise the same
16
16
  * "does not support vector distance metric" error as any other unsupported metric.
17
17
  */
18
18
  readonly vectorMetrics: ReadonlyMap<VectorDistance, VectorMetric>;
@@ -11,7 +11,7 @@ export class LibsqlDialect extends SqliteDialect {
11
11
  * functions this dialect would otherwise inherit are never present.
12
12
  *
13
13
  * @remarks `inner` and `l1` are left out: `vector_distance_dot` only exists in the newer Rust
14
- * engine (see `TursoDialect`) and no libSQL build has an L1 metric. Both raise the same
14
+ * engine (see `TursoLocalDialect`) and no libSQL build has an L1 metric. Both raise the same
15
15
  * "does not support vector distance metric" error as any other unsupported metric.
16
16
  */
17
17
  vectorMetrics = new Map([
@@ -1,19 +1,28 @@
1
1
  import type { Config } from '@libsql/client';
2
+ import { AbstractSharedHandleQuerierPool } from '../querier/abstractSharedHandleQuerierPool.js';
2
3
  import { type HranaClient, HranaQuerier } from '../sqlite/hranaQuerier.js';
3
- import { AbstractHranaQuerierPool } from '../sqlite/hranaQuerierPool.js';
4
4
  import type { ExtraOptions } from '../type/index.js';
5
5
  import { LibsqlDialect } from './libsqlDialect.js';
6
- /** Embedded replica: local `file:` DB + `syncUrl` remote - DDL should run on the remote (sqld). */
7
- export declare function libsqlUseRemoteForMigrations(config: Pick<Config, 'url' | 'syncUrl'>): boolean;
8
- export declare class LibsqlQuerierPool extends AbstractHranaQuerierPool<LibsqlDialect> {
6
+ /**
7
+ * Pool for libSQL. One client serves every querier, since Hrana keeps no per-connection state: a
8
+ * transaction takes its own session handle. The pool builds that client from `@libsql/client`'s
9
+ * `Config`, or shares one the caller built (`@libsql/client/web`, `@libsql/client-wasm`), which stays
10
+ * theirs to close.
11
+ */
12
+ export declare class LibsqlQuerierPool extends AbstractSharedHandleQuerierPool<HranaClient, HranaQuerier, LibsqlDialect> {
9
13
  private readonly conf;
10
- constructor(conf: Config, extra?: ExtraOptions);
11
- protected openClient(): Promise<HranaClient>;
14
+ constructor(conf: Config | HranaClient, extra?: ExtraOptions);
15
+ protected openDb(): Promise<HranaClient>;
16
+ protected buildQuerier(client: HranaClient): HranaQuerier;
17
+ end(): Promise<void>;
12
18
  /**
13
- * For embedded replicas (`file:` + `syncUrl`), returns a querier connected to `syncUrl` so migrations hit sqld.
14
- * Otherwise same as `getQuerier`. The migrator calls this for `up`/`down`, `syncForce`, and `autoSync` DDL.
19
+ * For an embedded replica - a `file:` url with a `syncUrl` - a querier on the sync url, so migrations
20
+ * reach sqld, its client closing with it. Anything else migrates like any other querier.
15
21
  */
16
22
  getMigrationQuerier(): Promise<HranaQuerier>;
17
- /** Imported on use, so `uql-orm/libsql` loads without the optional `@libsql/client` peer installed. */
23
+ /**
24
+ * Imported on use, so `uql-orm/libsql` loads without the optional `@libsql/client` peer installed.
25
+ * Integers read as `bigint` whatever the config asks, so the querier decodes one past 2^53 exactly.
26
+ */
18
27
  private createClient;
19
28
  }