uql-orm 0.64.0 → 0.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/bunSql/bunSqlQuerier.d.ts +3 -10
  2. package/dist/bunSql/bunSqlQuerier.js +2 -16
  3. package/dist/bunSql/bunSqlQuerierPool.d.ts +0 -2
  4. package/dist/bunSql/bunSqlQuerierPool.js +14 -16
  5. package/dist/d1/d1Querier.d.ts +13 -34
  6. package/dist/d1/d1Querier.js +1 -1
  7. package/dist/d1/d1QuerierPool.d.ts +3 -3
  8. package/dist/dialect/abstractDialect.d.ts +4 -9
  9. package/dist/dialect/abstractDialect.js +4 -5
  10. package/dist/dialect/abstractSqlDialect.d.ts +2 -2
  11. package/dist/dialect/index.d.ts +0 -1
  12. package/dist/dialect/index.js +2 -3
  13. package/dist/dialect/mysqlLikeSqlDialect.js +0 -3
  14. package/dist/dialect/pgLikeSqlDialect.d.ts +9 -1
  15. package/dist/dialect/pgLikeSqlDialect.js +8 -5
  16. package/dist/dialect/queryContext.d.ts +3 -3
  17. package/dist/entity/metadata/definition.d.ts +6 -0
  18. package/dist/entity/metadata/definition.js +109 -76
  19. package/dist/migrate/cli.d.ts +1 -1
  20. package/dist/migrate/cli.js +20 -34
  21. package/dist/migrate/codegen/entityCodeGenerator.d.ts +5 -0
  22. package/dist/migrate/codegen/entityCodeGenerator.js +29 -7
  23. package/dist/migrate/codegen/indexDecoratorSource.js +1 -5
  24. package/dist/migrate/codegen/sourceLiteral.d.ts +2 -0
  25. package/dist/migrate/codegen/sourceLiteral.js +4 -0
  26. package/dist/migrate/index.d.ts +1 -1
  27. package/dist/migrate/index.js +1 -1
  28. package/dist/migrate/introspection/registry.d.ts +2 -2
  29. package/dist/migrate/introspection/registry.js +6 -11
  30. package/dist/migrate/migrationTarget.d.ts +6 -6
  31. package/dist/migrate/migrationTarget.js +18 -16
  32. package/dist/migrate/migrator.d.ts +3 -7
  33. package/dist/migrate/migrator.js +10 -31
  34. package/dist/migrate/schemaGenerator.d.ts +1 -3
  35. package/dist/migrate/schemaGenerator.js +0 -4
  36. package/dist/mongo/mongoDialect.d.ts +1 -1
  37. package/dist/mongo/mongoDialect.js +1 -4
  38. package/dist/mssql/mssqlDialect.js +0 -3
  39. package/dist/pglite/pgliteQuerier.d.ts +2 -6
  40. package/dist/pglite/pgliteQuerier.js +2 -9
  41. package/dist/postgres/index.d.ts +0 -1
  42. package/dist/postgres/index.js +0 -1
  43. package/dist/querier/abstractSharedHandleQuerierPool.d.ts +2 -5
  44. package/dist/querier/abstractSharedHandleQuerierPool.js +2 -5
  45. package/dist/querier/abstractSqlQuerier.d.ts +2 -3
  46. package/dist/querier/abstractSqlQuerier.js +8 -4
  47. package/dist/querier/cursorStream.d.ts +13 -0
  48. package/dist/{postgres/pgCursorStream.js → querier/cursorStream.js} +4 -13
  49. package/dist/schema/canonicalType.js +1 -1
  50. package/dist/schema/schemaASTBuilder.js +34 -40
  51. package/dist/sqlite/abstractSqliteQuerier.d.ts +7 -3
  52. package/dist/sqlite/abstractSqliteQuerier.js +18 -4
  53. package/dist/sqlite/hranaQuerier.d.ts +1 -1
  54. package/dist/sqlite/localSqliteQuerierPool.d.ts +7 -0
  55. package/dist/sqlite/localSqliteQuerierPool.js +19 -0
  56. package/dist/sqlite/nodeSqliteQuerierPool.js +2 -3
  57. package/dist/sqlite/sqliteDialect.js +0 -3
  58. package/dist/sqlite/sqliteQuerier.d.ts +8 -5
  59. package/dist/sqlite/sqliteQuerier.js +4 -13
  60. package/dist/sqlite/sqliteQuerierPool.js +4 -4
  61. package/dist/turso/tursoSessionQuerier.d.ts +2 -2
  62. package/dist/turso/tursoSessionQuerier.js +16 -18
  63. package/dist/type/dialect.d.ts +25 -35
  64. package/dist/type/entity.d.ts +26 -28
  65. package/dist/type/migratorDialect.d.ts +0 -9
  66. package/dist/type/migratorDialect.js +1 -16
  67. package/dist/type/querierPool.d.ts +0 -4
  68. package/dist/type/queryRaw.d.ts +2 -2
  69. package/dist/type/universalQuerier.d.ts +2 -2
  70. package/package.json +1 -3
  71. package/dist/postgres/pgCursorStream.d.ts +0 -20
  72. package/dist/postgres/postgresWireDriverCapabilities.d.ts +0 -21
  73. package/dist/postgres/postgresWireDriverCapabilities.js +0 -21
  74. package/dist/sqlite/bunSqliteAdapter.bun.d.ts +0 -27
  75. package/dist/sqlite/bunSqliteAdapter.bun.js +0 -25
  76. package/dist/sqlite/nodeSqliteAdapter.d.ts +0 -33
  77. package/dist/sqlite/nodeSqliteAdapter.js +0 -25
@@ -20,6 +20,13 @@ export type LocalSqliteDatabase = {
20
20
  loadExtension(path: string): void;
21
21
  close(): unknown;
22
22
  };
23
+ /**
24
+ * A `node:sqlite` or `bun:sqlite` handle as a {@link LocalSqliteDatabase}. Neither says whether a statement
25
+ * reads, so `reads` does: taken by `run()`, a RETURNING statement's rows would be lost, and its ids with them.
26
+ */
27
+ export declare function adaptSqlite<S extends Omit<SqlitePreparedStatement, 'reader'>>(db: Omit<LocalSqliteDatabase, 'prepare'> & {
28
+ prepare(sql: string): S;
29
+ }, reads: (stmt: S) => boolean): LocalSqliteDatabase;
23
30
  /**
24
31
  * Pool for a SQLite database opened in this process, whichever driver provides it. SQLite gives one
25
32
  * connection per file, so the shared-handle lifecycle is {@link AbstractSharedHandleQuerierPool}'s.
@@ -3,6 +3,25 @@ import { AbstractSharedHandleQuerierPool } from '../querier/abstractSharedHandle
3
3
  import { SqliteDialect } from './sqliteDialect.js';
4
4
  import { applySqlitePragmas } from './sqlitePragmas.js';
5
5
  import { SqliteQuerier } from './sqliteQuerier.js';
6
+ /**
7
+ * A `node:sqlite` or `bun:sqlite` handle as a {@link LocalSqliteDatabase}. Neither says whether a statement
8
+ * reads, so `reads` does: taken by `run()`, a RETURNING statement's rows would be lost, and its ids with them.
9
+ */
10
+ export function adaptSqlite(db, reads) {
11
+ return {
12
+ prepare: (sql) => {
13
+ const stmt = db.prepare(sql);
14
+ return {
15
+ reader: reads(stmt),
16
+ all: (...values) => stmt.all(...values),
17
+ run: (...values) => stmt.run(...values),
18
+ iterate: (...values) => stmt.iterate(...values),
19
+ };
20
+ },
21
+ loadExtension: (path) => db.loadExtension(path),
22
+ close: () => db.close(),
23
+ };
24
+ }
6
25
  /**
7
26
  * Pool for a SQLite database opened in this process, whichever driver provides it. SQLite gives one
8
27
  * connection per file, so the shared-handle lifecycle is {@link AbstractSharedHandleQuerierPool}'s.
@@ -1,5 +1,4 @@
1
- import { AbstractLocalSqliteQuerierPool, } from './localSqliteQuerierPool.js';
2
- import { adaptNodeSqlite } from './nodeSqliteAdapter.js';
1
+ import { AbstractLocalSqliteQuerierPool, adaptSqlite, } from './localSqliteQuerierPool.js';
3
2
  /**
4
3
  * Pool backed by Node's built-in `node:sqlite`, so SQLite works with **no dependency at all** rather
5
4
  * than requiring the `better-sqlite3` native build. Use {@link Sqlite3QuerierPool} instead when you
@@ -25,6 +24,6 @@ export class NodeSqliteQuerierPool extends AbstractLocalSqliteQuerierPool {
25
24
  // `node:sqlite` refuses `loadExtension` unless the database was opened with this on.
26
25
  ...(extensions?.length ? { allowExtension: true } : undefined),
27
26
  });
28
- return adaptNodeSqlite(nodeDb);
27
+ return adaptSqlite(nodeDb, (stmt) => stmt.columns().length > 0);
29
28
  }
30
29
  }
@@ -7,9 +7,6 @@ import { columnFamily, isIntegerColumn } from '../util/field.util.js';
7
7
  export class SqliteDialect extends AbstractSqlDialect {
8
8
  /** Default {@link DialectFeatures} for SQLite and SQLite-derived dialects. */
9
9
  featureDefaults = {
10
- explicitJsonCast: false,
11
- nativeArrays: false,
12
- supportsJsonb: false,
13
10
  ifNotExists: true,
14
11
  indexIfNotExists: true,
15
12
  schemas: false, // SQLite's namespaces are attached database files, not declared objects
@@ -1,9 +1,12 @@
1
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
- /** What uql reads of a driver's `run()`: the row count. An inserted id comes back through `RETURNING`. */
4
+ /**
5
+ * What uql reads of a driver's `run()`: the row count, which `node:sqlite` answers as a `bigint` once it
6
+ * reads integers as ones. An inserted id comes back through `RETURNING`.
7
+ */
5
8
  export type SqliteRunResult = {
6
- changes: number;
9
+ changes: number | bigint;
7
10
  };
8
11
  /** A prepared statement with better-sqlite3 semantics, answering at once or with a promise. */
9
12
  export type SqlitePreparedStatement = {
@@ -15,7 +18,7 @@ export type SqlitePreparedStatement = {
15
18
  };
16
19
  /**
17
20
  * 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.
21
+ * as they are, `bun:sqlite` and `node:sqlite` through `adaptSqlite`.
19
22
  */
20
23
  export type SqliteDatabase = {
21
24
  prepare(sql: string): SqlitePreparedStatement | Promise<SqlitePreparedStatement>;
@@ -31,9 +34,9 @@ export declare class SqliteQuerier extends AbstractSqliteQuerier {
31
34
  readonly extra?: ExtraOptions | undefined;
32
35
  constructor(db: SqliteDatabase, dialect: SqliteDialect, extra?: ExtraOptions | undefined);
33
36
  /** `reader` picks the call: `run()` would discard the rows of a statement that reads, RETURNING included. */
34
- protected execute(query: string, values?: unknown[]): Promise<{
37
+ protected execute(query: string, values: SqliteBindValue[]): Promise<{
35
38
  rows: RawRow[];
36
39
  changes: number;
37
40
  }>;
38
- internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, unknown>;
41
+ protected iterate(query: string, values: SqliteBindValue[]): Promise<AsyncIterable<RawRow> | Iterable<RawRow>>;
39
42
  }
@@ -1,4 +1,3 @@
1
- import { decodeBigInts } from '../util/wideNumber.js';
2
1
  import { AbstractSqliteQuerier } from './abstractSqliteQuerier.js';
3
2
  /**
4
3
  * Querier for the SQLite drivers that prepare statements: `better-sqlite3`, `bun:sqlite`, `node:sqlite`
@@ -16,20 +15,12 @@ export class SqliteQuerier extends AbstractSqliteQuerier {
16
15
  /** `reader` picks the call: `run()` would discard the rows of a statement that reads, RETURNING included. */
17
16
  async execute(query, values) {
18
17
  const stmt = await this.db.prepare(query);
19
- const bound = toBindValues(values);
20
18
  if (stmt.reader) {
21
- return { rows: (await stmt.all(...bound)), changes: 0 };
19
+ return { rows: (await stmt.all(...values)), changes: 0 };
22
20
  }
23
- return { rows: [], changes: (await stmt.run(...bound)).changes };
21
+ return { rows: [], changes: Number((await stmt.run(...values)).changes) };
24
22
  }
25
- async *internalStream(query, values) {
26
- const stmt = await this.db.prepare(query);
27
- for await (const row of stmt.iterate(...toBindValues(values))) {
28
- yield decodeBigInts(row);
29
- }
23
+ async iterate(query, values) {
24
+ return (await this.db.prepare(query)).iterate(...values);
30
25
  }
31
26
  }
32
- /** Bound parameters reach a driver as `unknown[]` from the compiler; every driver types them narrowly. */
33
- function toBindValues(values) {
34
- return (values ?? []);
35
- }
@@ -1,4 +1,4 @@
1
- import { AbstractLocalSqliteQuerierPool, } from './localSqliteQuerierPool.js';
1
+ import { AbstractLocalSqliteQuerierPool, adaptSqlite, } from './localSqliteQuerierPool.js';
2
2
  /**
3
3
  * Pool for `better-sqlite3`, or `bun:sqlite` when running under Bun - the same file, through whichever
4
4
  * driver the runtime provides.
@@ -18,11 +18,11 @@ export class Sqlite3QuerierPool extends AbstractLocalSqliteQuerierPool {
18
18
  const { extensions, ...driverOpts } = this.opts ?? {};
19
19
  if (typeof Bun !== 'undefined') {
20
20
  const { Database } = await import('bun:sqlite');
21
- const { adaptBunSqlite } = await import('./bunSqliteAdapter.bun.js');
22
21
  const bunOpts = { ...driverOpts, safeIntegers: true };
23
- return adaptBunSqlite(typeof this.filename === 'string'
22
+ const bunDb = typeof this.filename === 'string'
24
23
  ? new Database(this.filename, bunOpts)
25
- : Database.deserialize(this.filename, bunOpts));
24
+ : Database.deserialize(this.filename, bunOpts);
25
+ return adaptSqlite(bunDb, (stmt) => stmt.columnNames.length > 0);
26
26
  }
27
27
  const { default: BetterSqlite3 } = await import('better-sqlite3');
28
28
  return new BetterSqlite3(this.filename, driverOpts).defaultSafeIntegers(true);
@@ -47,11 +47,11 @@ export declare class TursoSessionQuerier extends AbstractSqliteQuerier {
47
47
  readonly session: TursoSession;
48
48
  readonly extra?: ExtraOptions | undefined;
49
49
  constructor(session: TursoSession, dialect: SqliteDialect, extra?: ExtraOptions | undefined);
50
- protected execute(query: string, values?: unknown[]): Promise<{
50
+ protected execute(query: string, values: SqliteBindValue[]): Promise<{
51
51
  rows: RawRow[];
52
52
  changes: number;
53
53
  }>;
54
54
  /** Row by row off the statement's cursor, as the server steps it, each decoded as `execute` decodes one. */
55
- internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, unknown>;
55
+ protected iterate(query: string, values: SqliteBindValue[]): Promise<AsyncGenerator<RawRow, void, unknown>>;
56
56
  internalRelease(): Promise<void>;
57
57
  }
@@ -1,5 +1,4 @@
1
1
  import { AbstractSqliteQuerier } from '../sqlite/abstractSqliteQuerier.js';
2
- import { decodeBigInts } from '../util/wideNumber.js';
3
2
  /**
4
3
  * Querier for Turso Cloud on a session of its own.
5
4
  *
@@ -16,25 +15,28 @@ export class TursoSessionQuerier extends AbstractSqliteQuerier {
16
15
  this.extra = extra;
17
16
  }
18
17
  async execute(query, values) {
19
- const { columns, rows, rowsAffected } = await this.session.execute(query, toBindValues(values), true);
18
+ const { columns, rows, rowsAffected } = await this.session.execute(query, values, true);
20
19
  return { rows: rows.map((row) => toRow(columns, row)), changes: rowsAffected };
21
20
  }
22
21
  /** Row by row off the statement's cursor, as the server steps it, each decoded as `execute` decodes one. */
23
- async *internalStream(query, values) {
22
+ async iterate(query, values) {
24
23
  const { DatabaseError, decodeValue } = await import('@tursodatabase/serverless');
25
- const { entries } = await this.session.executeRaw(query, toBindValues(values));
26
- let columns = [];
27
- for await (const entry of entries) {
28
- if (entry.type === 'step_error' || entry.type === 'error') {
29
- throw new DatabaseError(entry.error?.message ?? 'SQL execution failed', entry.error?.code);
30
- }
31
- if (entry.cols) {
32
- columns = entry.cols.map(({ name }) => name);
33
- }
34
- if (entry.row) {
35
- yield decodeBigInts(toRow(columns, entry.row.map((value) => decodeValue(value, true))));
24
+ const { entries } = await this.session.executeRaw(query, values);
25
+ async function* rows() {
26
+ let columns = [];
27
+ for await (const entry of entries) {
28
+ if (entry.type === 'step_error' || entry.type === 'error') {
29
+ throw new DatabaseError(entry.error?.message ?? 'SQL execution failed', entry.error?.code);
30
+ }
31
+ if (entry.cols) {
32
+ columns = entry.cols.map(({ name }) => name);
33
+ }
34
+ if (entry.row) {
35
+ yield toRow(columns, entry.row.map((value) => decodeValue(value, true)));
36
+ }
36
37
  }
37
38
  }
39
+ return rows();
38
40
  }
39
41
  async internalRelease() {
40
42
  await this.session.close();
@@ -44,7 +46,3 @@ export class TursoSessionQuerier extends AbstractSqliteQuerier {
44
46
  function toRow(columns, values) {
45
47
  return Object.fromEntries(columns.map((column, at) => [column, values[at]]));
46
48
  }
47
- /** Bound parameters reach a driver as `unknown[]` from the compiler; a session binds them as they are. */
48
- function toBindValues(values) {
49
- return (values ?? []);
50
- }
@@ -54,7 +54,8 @@ export type QueryContextOptions = {
54
54
  readonly inlineValues?: boolean;
55
55
  };
56
56
  /**
57
- * Capabilities of the database driver (transport layer).
57
+ * How a Postgres-wire driver binds a parameter, which is all its dialect's `driverCapabilities` option may
58
+ * change: what the engine has is the dialect's own to state.
58
59
  */
59
60
  export interface DriverCapabilities {
60
61
  /**
@@ -68,8 +69,6 @@ export interface DriverCapabilities {
68
69
  * `toPgArray` string literals instead.
69
70
  */
70
71
  readonly nativeArrays: boolean;
71
- /** Whether the dialect natively supports the JSONB binary JSON type (Postgres/CockroachDB). */
72
- readonly supportsJsonb: boolean;
73
72
  }
74
73
  /**
75
74
  * How a dialect surfaces the IDs generated by an INSERT statement:
@@ -77,14 +76,12 @@ export interface DriverCapabilities {
77
76
  * or MongoDB's `insertedIds`), so IDs are exact for every row.
78
77
  * - `'firstId'`: the driver header only exposes the first generated ID (MySQL `insertId`);
79
78
  * the remaining IDs are inferred by incrementing it.
80
- * - `'lastId'`: the driver header only exposes the last generated ID (SQLite `lastInsertRowid`);
81
- * the remaining IDs are inferred backwards from it.
82
79
  */
83
- export type InsertIdSource = 'returning' | 'firstId' | 'lastId';
80
+ export type InsertIdSource = 'returning' | 'firstId';
84
81
  /**
85
82
  * Features of the database engine (SQL syntax layer).
86
83
  */
87
- export interface EngineFeatures {
84
+ export interface DialectFeatures {
88
85
  readonly ifNotExists: boolean;
89
86
  readonly indexIfNotExists: boolean;
90
87
  /**
@@ -110,7 +107,7 @@ export interface EngineFeatures {
110
107
  * A boolean rather than a mode: SQLite would accept a `VIRTUAL` column here, but emitting one where
111
108
  * the entity said `stored` makes the same entity a stored column on a new database and a virtual one
112
109
  * on an old, which nothing diffs and no one can see. Refusal has one form; only what UQL *emits*
113
- * earns a mode, which is what makes {@link EngineFeatures.commentSyntax} three-way.
110
+ * earns a mode, which is what makes {@link DialectFeatures.commentSyntax} three-way.
114
111
  */
115
112
  readonly generatedColumnAdd: boolean;
116
113
  /**
@@ -145,19 +142,25 @@ export interface EngineFeatures {
145
142
  /** Whether the engine has unsigned integers, so `@Field({ unsigned: true })` reaches the column. */
146
143
  readonly supportsUnsigned: boolean;
147
144
  /**
148
- * Whether the engine has SQL-level cursors (`DECLARE`/`FETCH FORWARD`/`CLOSE`), which is how a
149
- * driver with no cursor API of its own still streams a result set instead of buffering it - see
150
- * `postgres/pgCursorStream.ts`. True across the Postgres wire family, whose spelling that helper
151
- * speaks; SQL Server and Oracle have cursors of their own but not this syntax.
152
- *
153
- * The node-`pg` family reports `true` and goes on using `pg-query-stream`: the flag says the engine
154
- * has cursors, not that the driver needs them.
145
+ * Whether the engine has `DECLARE`/`FETCH FORWARD`/`CLOSE` cursors, which a querier with no stream of
146
+ * its own pages a read through (`querier/cursorStream.ts`) instead of reading it whole. The engine's
147
+ * answer, not the driver's: node-`pg` streams on its own and keeps doing so.
155
148
  */
156
149
  readonly serverSideCursors: boolean;
157
150
  }
158
- export interface DialectFeatures extends EngineFeatures, DriverCapabilities {
159
- }
160
- export interface QueryDialect {
151
+ /**
152
+ * What a SQL statement is rendered through, as a `raw` callback and a query context see it:
153
+ * `AbstractSqlDialect` is the one implementation.
154
+ */
155
+ export interface SqlQueryDialect {
156
+ /**
157
+ * The SQL dialect name.
158
+ */
159
+ readonly dialectName: SqlDialectName;
160
+ /**
161
+ * the escape character for identifiers.
162
+ */
163
+ readonly escapeIdChar: '"' | '`';
161
164
  /**
162
165
  * The dialect features.
163
166
  */
@@ -242,23 +245,6 @@ export interface QueryDialect {
242
245
  * The column a field of `meta` is stored in, named the way this dialect names columns.
243
246
  */
244
247
  columnOf<E>(meta: EntityMeta<E>, key: string): string;
245
- }
246
- /**
247
- * Supported SQL dialect identifiers.
248
- */
249
- export type SqlDialectName = 'postgres' | 'cockroachdb' | 'mysql' | 'mariadb' | 'sqlite' | 'mssql';
250
- /**
251
- * Minimal dialect interface exposing escapeIdChar for SQL operations
252
- */
253
- export interface SqlQueryDialect extends QueryDialect {
254
- /**
255
- * The SQL dialect name (postgres, mysql, mariadb, sqlite, mssql).
256
- */
257
- readonly dialectName: SqlDialectName;
258
- /**
259
- * the escape character for identifiers.
260
- */
261
- readonly escapeIdChar: '"' | '`';
262
248
  /**
263
249
  * Build an aggregate query.
264
250
  */
@@ -269,6 +255,10 @@ export interface SqlQueryDialect extends QueryDialect {
269
255
  */
270
256
  placeholder(index: number): string;
271
257
  }
258
+ /**
259
+ * Supported SQL dialect identifiers.
260
+ */
261
+ export type SqlDialectName = 'postgres' | 'cockroachdb' | 'mysql' | 'mariadb' | 'sqlite' | 'mssql';
272
262
  /**
273
263
  * An index capability that some engines have and others reject outright. Verified live: expression
274
264
  * indexes exist everywhere but MariaDB 12.3 (which needs a generated column); prefix lengths are
@@ -481,23 +481,21 @@ export type FieldOptionsFor<V, E = unknown> = (FieldOptions<NonNullable<V>, E> &
481
481
  */
482
482
  export type RelationTarget<V> = Extract<Unpacked<V>, object>;
483
483
  /**
484
- * {@link RelationOptions} for a relation field declared as `V`, with `entity` required and pinned to
485
- * `V`'s own type, and the cardinality restricted to the ones that field shape can hold. Together those
486
- * reject `@ManyToOne({ entity: () => Other })` on a `Company` field, and any to-many cardinality on a
487
- * field that is not an array. A to-many additionally needs a {@link RelationJoin}.
488
- *
489
- * The join is required through the `cardinality` written rather than through `IsMany<V>`: a conditional
490
- * member of the intersection leaves a `mappedBy` callback without a contextual type inside a generic
491
- * call (`defineEntity`), where a union keyed on a property does not.
484
+ * {@link RelationOptions} for a relation field declared as `V`: what each cardinality's decorator takes,
485
+ * keyed on the `cardinality` written and restricted to the ones the field's shape holds. A key, not a
486
+ * conditional on `IsMany<V>`, which left a `mappedBy` callback untyped inside `defineEntity`.
492
487
  */
493
- export type RelationOptionsFor<V, O = unknown> = Omit<RelationOptions<RelationTarget<V>, O>, 'entity' | 'cardinality'> & {
494
- readonly entity: EntityGetter<RelationTarget<V>>;
488
+ export type RelationOptionsFor<V, O = unknown> = {
495
489
  readonly cardinality: IsMany<V> extends true ? '1m' | 'mm' : '11' | 'm1';
496
490
  } & (({
497
- readonly cardinality: '1m' | 'mm';
498
- } & RelationJoin<RelationTarget<V>, O>) | {
499
- readonly cardinality: '11' | 'm1';
500
- });
491
+ readonly cardinality: '11';
492
+ } & RelationOneToOneOptions<RelationTarget<V>, O>) | ({
493
+ readonly cardinality: 'm1';
494
+ } & RelationManyToOneOptions<RelationTarget<V>, O>) | ({
495
+ readonly cardinality: '1m';
496
+ } & RelationOneToManyOptions<RelationTarget<V>, O>) | ({
497
+ readonly cardinality: 'mm';
498
+ } & RelationManyToManyOptions<RelationTarget<V>, O>));
501
499
  /**
502
500
  * The method names of an entity, so hook registrations name a method that exists.
503
501
  */
@@ -540,17 +538,20 @@ export type RelationOptions<E, O = unknown> = {
540
538
  */
541
539
  through?: EntityGetter;
542
540
  /**
543
- * The join columns where no convention fits: each pairs a field of the declaring entity with one of
544
- * the target, `(order, customer) => [{ local: order.customerCode, foreign: customer.code }]`. A
545
- * `through` relation takes none: its junction's columns follow the convention.
541
+ * The join columns: the foreign key a to-one declares, `(post) => post.authorId`, which points at the
542
+ * target's primary key, or pairs where no key fits, `(order, customer) => [{ local: order.customerCode,
543
+ * foreign: customer.code }]`. A `through` relation takes none: it joins by the junction's column
544
+ * referencing each side.
546
545
  */
547
- references?: (local: KeyMap<O>, foreign: KeyMap<E>) => readonly RelationReference<O, E>[];
546
+ references?: (local: KeyMap<O>, foreign: KeyMap<E>) => FieldKey<O> | readonly RelationReference<O, E>[];
548
547
  };
549
548
  /** One pair of join columns, each a field read off its entity's key map. */
550
549
  export type RelationReference<O, E> = {
551
550
  readonly local: FieldKey<O>;
552
551
  readonly foreign: FieldKey<E>;
553
552
  };
553
+ /** {@link RelationOptions.references} as pairs alone, for a to-many, which holds no foreign key of its own to name. */
554
+ type RelationReferencePairs<E, O> = (local: KeyMap<O>, foreign: KeyMap<E>) => readonly RelationReference<O, E>[];
554
555
  /**
555
556
  * A relation once `getMeta` has resolved it: `references` is filled in and `mappedBy` is the key its
556
557
  * callback named. Consumers read this shape rather than {@link RelationOptions}, so they need no
@@ -562,28 +563,25 @@ export type RelationReference<O, E> = {
562
563
  * from "declared, but an inverse side too, so neither owns the foreign key" needs the unresolved shape
563
564
  * still there to find. A phase-split metadata map costs more than the call parentheses it saves.
564
565
  */
565
- export type RelationMeta = RelationRegistration & {
566
+ export type RelationMeta = Omit<RelationRegistration, 'references'> & {
566
567
  references: RelationReferences;
567
568
  };
568
569
  /**
569
570
  * A relation as the registry takes it, whichever entity it targets: `mappedBy` and `references` read
570
- * off their key maps down to the names they give, `references` unset until `getMeta` settles it.
571
+ * off their key maps down to the names they give. `references` stays unset, or the one column a to-one
572
+ * names, until `getMeta` pairs it with the target's key, which registration may run before the target has.
571
573
  */
572
574
  export type RelationRegistration = Omit<RelationOptions<object>, 'mappedBy' | 'references'> & {
573
575
  mappedBy?: string;
574
- references?: RelationReferences;
576
+ references?: RelationReferences | string;
575
577
  };
576
578
  /** How a to-many owner reaches its children: a junction entity or the join columns, never both. */
577
579
  type RelationOwnerJoin<E, O> = (Required<Pick<RelationOptions<E, O>, 'through'>> & {
578
580
  readonly references?: never;
579
- }) | (Required<Pick<RelationOptions<E, O>, 'references'>> & {
581
+ }) | {
582
+ readonly references: RelationReferencePairs<E, O>;
580
583
  readonly through?: never;
581
- });
582
- /**
583
- * Every way a to-many can say where its rows are. Required because nothing about the field implies it:
584
- * without one of the three, resolution has no columns to join on and throws.
585
- */
586
- type RelationJoin<E, O> = RelationOwnerJoin<E, O> | Required<Pick<RelationOptions<E>, 'mappedBy'>>;
584
+ };
587
585
  type RelationOptionsOwner<E, O> = Pick<RelationOptions<E, O>, 'entity' | 'references' | 'cascade' | 'onDelete' | 'onUpdate'>;
588
586
  type RelationOptionsInverseSide<E> = Pick<RelationOptions<E>, 'entity' | 'cascade'> & Required<Pick<RelationOptions<E>, 'mappedBy'>>;
589
587
  type RelationOptionsThroughOwner<E, O> = Pick<RelationOptions<E, O>, 'entity' | 'cascade'> & RelationOwnerJoin<E, O>;
@@ -1,13 +1,4 @@
1
1
  import type { AbstractSqlDialect } from '../dialect/abstractSqlDialect.js';
2
2
  import type { MongoDialect } from '../mongo/mongoDialect.js';
3
- import type { DialectName } from './querier.js';
4
3
  /** The dialects the migrator runs on, which `dialectName` tells apart: every SQL engine, and MongoDB. */
5
4
  export type MigratorDialect = AbstractSqlDialect | MongoDialect;
6
- declare const KNOWN_MIGRATOR_DIALECTS: readonly ["postgres", "cockroachdb", "mysql", "mariadb", "sqlite", "mssql", "mongodb"];
7
- export type KnownMigratorDialect = (typeof KNOWN_MIGRATOR_DIALECTS)[number];
8
- /**
9
- * Whether `d` is supported by built-in migrator introspection / schema generators.
10
- * Other `Dialect` values may still be valid on a pool but get no default generator.
11
- */
12
- export declare function isKnownMigratorDialect(d: DialectName): d is KnownMigratorDialect;
13
- export {};
@@ -1,16 +1 @@
1
- const KNOWN_MIGRATOR_DIALECTS = [
2
- 'postgres',
3
- 'cockroachdb',
4
- 'mysql',
5
- 'mariadb',
6
- 'sqlite',
7
- 'mssql',
8
- 'mongodb',
9
- ];
10
- /**
11
- * Whether `d` is supported by built-in migrator introspection / schema generators.
12
- * Other `Dialect` values may still be valid on a pool but get no default generator.
13
- */
14
- export function isKnownMigratorDialect(d) {
15
- return KNOWN_MIGRATOR_DIALECTS.includes(d);
16
- }
1
+ export {};
@@ -75,10 +75,6 @@ export interface QuerierPool<Q extends Querier = Querier, D extends AbstractDial
75
75
  */
76
76
  export interface SqlQuerierPool<Q extends SqlQuerier = SqlQuerier, D extends AbstractSqlDialect = AbstractSqlDialect> extends QuerierPool<Q, D>, Pick<SqlQuerier, 'all' | 'run'> {
77
77
  }
78
- /** Dialect class used by pool `P` (when `P` is a {@link QuerierPool}). */
79
- export type QuerierPoolDialect<P> = P extends QuerierPool<infer _Q, infer D> ? D : never;
80
- /** Querier type produced by pool `P`. */
81
- export type QuerierPoolQuerier<P> = P extends QuerierPool<infer Q, infer _D> ? Q : never;
82
78
  /**
83
79
  * Represents a high-compatibility SQL pool shim for Node.js integrations (e.g., express-session).
84
80
  */
@@ -1,9 +1,9 @@
1
- import type { QueryContext, QueryDialect } from './dialect.js';
1
+ import type { QueryContext, SqlQueryDialect } from './dialect.js';
2
2
  import type { Type } from './utility.js';
3
3
  /** What a `raw` callback receives. See {@link QueryRawFn}. */
4
4
  export type QueryRawRenderOptions = {
5
5
  /** The dialect rendering the SQL. */
6
- dialect: QueryDialect;
6
+ dialect: SqlQueryDialect;
7
7
  /** The alias of the table in scope, unescaped; empty where there is none. */
8
8
  prefix: string;
9
9
  /** {@link prefix} escaped, with its trailing dot. */
@@ -122,8 +122,8 @@ export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions>
122
122
  * dialect's bind-parameter limit) and return their IDs in payload order.
123
123
  *
124
124
  * Provided IDs and client-generated ones (`@Id({ onInsert })`) are always returned as-is.
125
- * Database-generated IDs are exact on `'returning'` dialects (Postgres, MariaDB, MongoDB);
126
- * on MySQL/SQLite they are inferred from the driver header, which is only reliable for
125
+ * Database-generated IDs are exact wherever the statement returns them, which is everywhere but
126
+ * MySQL: there they are inferred from the driver header, which is only reliable for
127
127
  * auto-increment keys in batches without explicit IDs - otherwise those entries are
128
128
  * `undefined` rather than potentially wrong values. A composite key is never one the statement
129
129
  * reports, so those rows are named as written, `onInsert` columns included.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "homepage": "https://uql-orm.dev",
4
4
  "description": "The JSON-native TypeScript ORM for Bun, Browsers, Edge, Deno, Node, Workers. Supports PostgreSQL, PGlite, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.",
5
5
  "license": "MIT",
6
- "version": "0.64.0",
6
+ "version": "0.65.0",
7
7
  "type": "module",
8
8
  "engines": {
9
9
  "node": ">=24"
@@ -23,13 +23,11 @@
23
23
  "./entity": "./dist/entity/index.js",
24
24
  "./querier": "./dist/querier/index.js",
25
25
  "./type": "./dist/type/index.js",
26
- "./type/migratorDialect": "./dist/type/migratorDialect.js",
27
26
  "./util": "./dist/util/index.js",
28
27
  "./namingStrategy": "./dist/namingStrategy/index.js",
29
28
  "./migrate": "./dist/migrate/index.js",
30
29
  "./mysql": "./dist/mysql/index.js",
31
30
  "./postgres": "./dist/postgres/index.js",
32
- "./postgres/wireCapabilities": "./dist/postgres/postgresWireDriverCapabilities.js",
33
31
  "./cockroachdb": "./dist/cockroachdb/index.js",
34
32
  "./maria": "./dist/maria/index.js",
35
33
  "./sqlite": "./dist/sqlite/index.js",
@@ -1,20 +0,0 @@
1
- /**
2
- * Runs one statement of the cursor protocol. `internalAll` for every caller so far: the cursor holds
3
- * a connection's session state, so it must be the querier's own connection, and it must not go
4
- * through `all()`, whose `serialize` is not re-entrant.
5
- */
6
- export type CursorExecutor<T> = (query: string, values?: unknown[]) => Promise<T[]>;
7
- /**
8
- * Stream a Postgres-wire result through a server-side cursor, for a driver whose client exposes none:
9
- * `bun:sql` (no cursor API at all, [oven-sh/bun#17181](https://github.com/oven-sh/bun/issues/17181))
10
- * and PGlite. `pg` has `pg-query-stream` and keeps using it.
11
- *
12
- * `DECLARE` is only legal inside a transaction, so one is opened here when the caller has none - and
13
- * then committed, or rolled back if the stream failed. That `BEGIN` goes straight to the connection
14
- * rather than through `beginTransaction`, so the querier's own transaction state stays untouched:
15
- * this one is the generator's, and ends with it.
16
- *
17
- * The cleanup lives in `finally` because a consumer that stops early (`break`, a `throw` downstream)
18
- * ends the generator there and nowhere else, and an abandoned cursor holds its transaction open.
19
- */
20
- export declare function streamViaCursor<T>(exec: CursorExecutor<T>, query: string, values?: unknown[], inTransaction?: boolean): AsyncIterable<T>;
@@ -1,21 +0,0 @@
1
- /**
2
- * Driver-shaped parameter handling for **Bun SQL** (and any client like it) on a Postgres-wire
3
- * dialect: arrays go as string literals (`nativeArrays: false`, {@link PgLikeSqlDialect}'s `toPgArray`
4
- * path) and a JSON bind is re-cast through text (`explicitJsonCast: true`). Both are measured, on a
5
- * live server: `bun:sql` binds neither `sql.array(...)` nor a plain JS array through `unsafe()`
6
- * (verified again on Bun 1.4.2), and without the text re-cast a `$set`/`$push` on a JSONB column
7
- * silently writes the wrong value or throws - on Postgres and, identically, on CockroachDB, which
8
- * `bun:sql` reaches through its own Postgres wire implementation.
9
- *
10
- * The pair is one constant because it is one driver's shape, and `BunSqlQuerierPool` hands it to
11
- * `PostgresDialect`/`CockroachDialect` as their `driverCapabilities` rather than subclassing either:
12
- * Bun changes how a parameter binds, never the SQL. `PgQuerierPool` uses neither, keeping the base
13
- * {@link PgLikeSqlDialect} defaults, since node-`pg` needs no fix.
14
- *
15
- * @remarks Optional import for custom pools. Neon uses its own serverless driver (not `bun:sql`),
16
- * so `NeonQuerierPool` is a separate, unverified case - do not assume it needs this without testing.
17
- */
18
- export declare const POSTGRES_WIRE_DRIVER_CAPABILITIES: {
19
- readonly nativeArrays: false;
20
- readonly explicitJsonCast: true;
21
- };
@@ -1,21 +0,0 @@
1
- /**
2
- * Driver-shaped parameter handling for **Bun SQL** (and any client like it) on a Postgres-wire
3
- * dialect: arrays go as string literals (`nativeArrays: false`, {@link PgLikeSqlDialect}'s `toPgArray`
4
- * path) and a JSON bind is re-cast through text (`explicitJsonCast: true`). Both are measured, on a
5
- * live server: `bun:sql` binds neither `sql.array(...)` nor a plain JS array through `unsafe()`
6
- * (verified again on Bun 1.4.2), and without the text re-cast a `$set`/`$push` on a JSONB column
7
- * silently writes the wrong value or throws - on Postgres and, identically, on CockroachDB, which
8
- * `bun:sql` reaches through its own Postgres wire implementation.
9
- *
10
- * The pair is one constant because it is one driver's shape, and `BunSqlQuerierPool` hands it to
11
- * `PostgresDialect`/`CockroachDialect` as their `driverCapabilities` rather than subclassing either:
12
- * Bun changes how a parameter binds, never the SQL. `PgQuerierPool` uses neither, keeping the base
13
- * {@link PgLikeSqlDialect} defaults, since node-`pg` needs no fix.
14
- *
15
- * @remarks Optional import for custom pools. Neon uses its own serverless driver (not `bun:sql`),
16
- * so `NeonQuerierPool` is a separate, unverified case - do not assume it needs this without testing.
17
- */
18
- export const POSTGRES_WIRE_DRIVER_CAPABILITIES = {
19
- nativeArrays: false,
20
- explicitJsonCast: true,
21
- };
@@ -1,27 +0,0 @@
1
- import type { SqliteBindValue } from './abstractSqliteQuerier.js';
2
- import type { LocalSqliteDatabase } from './localSqliteQuerierPool.js';
3
- import type { SqliteRunResult } from './sqliteQuerier.js';
4
- /** A `bun:sqlite` statement: better-sqlite3-shaped, except it reports columns instead of `reader`. */
5
- type BunStatement = {
6
- columnNames: string[];
7
- all(...values: SqliteBindValue[]): unknown[];
8
- run(...values: SqliteBindValue[]): SqliteRunResult;
9
- iterate(...values: SqliteBindValue[]): Iterable<unknown>;
10
- };
11
- type BunDatabase = {
12
- prepare(sql: string): BunStatement;
13
- loadExtension(path: string): void;
14
- close(): unknown;
15
- };
16
- /**
17
- * Presents a `bun:sqlite` handle as a {@link LocalSqliteDatabase}.
18
- *
19
- * @remarks Its statements expose no `reader`, so without deriving one every `RETURNING` statement
20
- * would take the `run()` path, which discards returned rows, and inserts would report no ids.
21
- * `columnNames` is non-empty for exactly the statements better-sqlite3 marks as readers.
22
- *
23
- * Lives in a `.bun.ts` file because it only ever executes under Bun: the Node coverage run cannot
24
- * reach it, and `sqliteQuerier.bun.test.ts` covers it under `test:bun` instead.
25
- */
26
- export declare function adaptBunSqlite(db: BunDatabase): LocalSqliteDatabase;
27
- export {};