uql-orm 0.54.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/browser/uql-browser.min.js.map +1 -1
- package/dist/bunSql/bunSql.util.d.ts +3 -14
- package/dist/bunSql/bunSql.util.js +33 -56
- package/dist/bunSql/bunSqlQuerier.d.ts +3 -6
- package/dist/bunSql/bunSqlQuerier.js +7 -13
- package/dist/bunSql/bunSqlQuerierPool.d.ts +10 -5
- package/dist/bunSql/bunSqlQuerierPool.js +25 -10
- package/dist/cockroachdb/crdbQuerierPool.d.ts +1 -3
- package/dist/cockroachdb/crdbQuerierPool.js +0 -4
- package/dist/cockroachdb/index.d.ts +0 -1
- package/dist/cockroachdb/index.js +0 -1
- package/dist/d1/d1SqliteDialect.d.ts +5 -0
- package/dist/d1/d1SqliteDialect.js +7 -0
- package/dist/dialect/abstractSqlDialect.d.ts +9 -9
- package/dist/dialect/abstractSqlDialect.js +38 -51
- package/dist/dialect/hydrateColumn.js +2 -2
- package/dist/dialect/mergeSqlDialect.d.ts +2 -2
- package/dist/dialect/mergeSqlDialect.js +0 -4
- package/dist/dialect/pgLikeSqlDialect.d.ts +5 -0
- package/dist/dialect/pgLikeSqlDialect.js +12 -2
- package/dist/entity/index.d.ts +1 -1
- package/dist/entity/index.js +1 -1
- package/dist/entity/metadata/definition.d.ts +3 -1
- package/dist/entity/metadata/definition.js +8 -0
- package/dist/libsql/index.d.ts +0 -1
- package/dist/libsql/index.js +0 -1
- package/dist/libsql/libsqlQuerierPool.d.ts +3 -5
- package/dist/libsql/libsqlQuerierPool.js +2 -5
- package/dist/maria/mariadbQuerier.d.ts +0 -3
- package/dist/maria/mariadbQuerier.js +6 -7
- package/dist/maria/mariadbQuerierPool.js +4 -7
- package/dist/migrate/ddl/index.d.ts +3 -3
- package/dist/migrate/ddl/index.js +3 -3
- package/dist/mongo/index.d.ts +0 -1
- package/dist/mongo/index.js +0 -1
- package/dist/mongo/mongoDialect.d.ts +0 -1
- package/dist/mongo/mongoDialect.js +3 -14
- package/dist/mongo/mongodbQuerier.js +6 -5
- package/dist/mongo/mongodbQuerierPool.d.ts +2 -2
- package/dist/mongo/mongodbQuerierPool.js +2 -2
- package/dist/mssql/mssqlDialect.d.ts +3 -5
- package/dist/mssql/mssqlDialect.js +9 -8
- package/dist/mssql/mssqlQuerier.d.ts +13 -6
- package/dist/mssql/mssqlQuerier.js +30 -75
- package/dist/mssql/mssqlQuerierPool.js +2 -0
- package/dist/mssql/mssqlWireTypes.d.ts +3 -4
- package/dist/mssql/mssqlWireTypes.js +5 -8
- package/dist/mysql/index.d.ts +0 -1
- package/dist/mysql/index.js +0 -1
- package/dist/mysql/mysql2Querier.d.ts +1 -4
- package/dist/mysql/mysql2Querier.js +0 -3
- package/dist/mysql/mysql2QuerierPool.d.ts +2 -2
- package/dist/mysql/mysql2QuerierPool.js +5 -3
- package/dist/neon/index.d.ts +0 -2
- package/dist/neon/index.js +0 -2
- package/dist/neon/neonQuerierPool.d.ts +2 -4
- package/dist/neon/neonQuerierPool.js +2 -6
- package/dist/pglite/index.d.ts +0 -1
- package/dist/pglite/index.js +0 -1
- package/dist/pglite/pgliteQuerier.d.ts +3 -3
- package/dist/pglite/pgliteQuerier.js +1 -1
- package/dist/pglite/pgliteQuerierPool.d.ts +7 -2
- package/dist/pglite/pgliteQuerierPool.js +16 -6
- package/dist/postgres/abstractPgQuerierPool.d.ts +8 -12
- package/dist/postgres/abstractPgQuerierPool.js +8 -6
- package/dist/postgres/index.d.ts +0 -1
- package/dist/postgres/index.js +0 -1
- package/dist/postgres/pgNumericTypes.d.ts +5 -5
- package/dist/postgres/pgNumericTypes.js +11 -7
- package/dist/postgres/pgQuerier.d.ts +22 -4
- package/dist/postgres/pgQuerier.js +29 -2
- package/dist/postgres/pgQuerierPool.d.ts +2 -4
- package/dist/postgres/pgQuerierPool.js +2 -6
- package/dist/postgres/postgresDialect.d.ts +5 -5
- package/dist/postgres/postgresDialect.js +5 -5
- package/dist/postgres/postgresWireDriverCapabilities.d.ts +2 -2
- package/dist/postgres/postgresWireDriverCapabilities.js +2 -2
- package/dist/querier/abstractPoolQuerier.d.ts +1 -1
- package/dist/querier/abstractPoolQuerier.js +1 -1
- package/dist/querier/abstractSqlQuerier.d.ts +11 -4
- package/dist/querier/abstractSqlQuerier.js +28 -16
- package/dist/sqlite/hranaQuerier.d.ts +6 -8
- package/dist/sqlite/hranaQuerier.js +13 -30
- package/dist/sqlite/hranaQuerierPool.d.ts +3 -4
- package/dist/sqlite/hranaQuerierPool.js +2 -1
- package/dist/sqlite/localSqliteQuerierPool.d.ts +3 -3
- package/dist/sqlite/localSqliteQuerierPool.js +4 -2
- package/dist/sqlite/nodeSqliteAdapter.d.ts +0 -1
- package/dist/sqlite/nodeSqliteQuerierPool.js +0 -2
- package/dist/sqlite/sqlitePragmas.d.ts +12 -0
- package/dist/sqlite/sqlitePragmas.js +15 -0
- package/dist/sqlite/sqliteQuerierPool.d.ts +0 -5
- package/dist/sqlite/sqliteQuerierPool.js +2 -13
- package/dist/turso/index.d.ts +0 -1
- package/dist/turso/index.js +0 -1
- package/dist/turso/tursoLocalQuerier.d.ts +0 -1
- package/dist/turso/tursoLocalQuerierPool.js +2 -2
- package/dist/turso/tursoQuerierPool.d.ts +1 -3
- package/dist/turso/tursoQuerierPool.js +0 -4
- package/dist/type/dialect.d.ts +1 -1
- package/dist/util/dialect.util.d.ts +1 -1
- package/dist/util/dialect.util.js +1 -1
- package/dist/util/logger.d.ts +7 -8
- package/dist/util/logger.js +18 -11
- package/dist/util/raw.js +3 -3
- package/dist/util/sqlLiteral.js +3 -8
- package/dist/util/string.util.js +2 -6
- package/dist/util/wideNumber.d.ts +14 -0
- package/dist/util/wideNumber.js +24 -0
- package/package.json +1 -1
- package/dist/cockroachdb/crdbQuerier.d.ts +0 -8
- package/dist/cockroachdb/crdbQuerier.js +0 -6
- package/dist/libsql/libsqlQuerier.d.ts +0 -10
- package/dist/libsql/libsqlQuerier.js +0 -10
- package/dist/mongo/mongodbNativeDialect.d.ts +0 -9
- package/dist/mongo/mongodbNativeDialect.js +0 -9
- package/dist/mysql/mysql2Dialect.d.ts +0 -9
- package/dist/mysql/mysql2Dialect.js +0 -9
- package/dist/neon/neonDialect.d.ts +0 -10
- package/dist/neon/neonDialect.js +0 -10
- package/dist/neon/neonQuerier.d.ts +0 -5
- package/dist/neon/neonQuerier.js +0 -3
- package/dist/pglite/pgliteDialect.d.ts +0 -14
- package/dist/pglite/pgliteDialect.js +0 -14
- package/dist/postgres/abstractPgQuerier.d.ts +0 -24
- package/dist/postgres/abstractPgQuerier.js +0 -32
- package/dist/postgres/pgDialect.d.ts +0 -10
- package/dist/postgres/pgDialect.js +0 -10
- package/dist/turso/tursoQuerier.d.ts +0 -10
- package/dist/turso/tursoQuerier.js +0 -10
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { decodeWideNumber } from '../util/wideNumber.js';
|
|
1
2
|
/**
|
|
2
|
-
* Decode `INT8` and `FLOAT8
|
|
3
|
+
* Decode `INT8` and `FLOAT8`, leaving every other type to the driver: an INT8 by `decodeWideNumber` - a
|
|
4
|
+
* number where one is exact, its exact text past 2^53 - and a FLOAT8 as the float64 it already is.
|
|
3
5
|
*
|
|
4
6
|
* uql owes this to the caller because uql picks the column: `type: Number` maps to BIGINT (see
|
|
5
7
|
* `schema/canonicalType.ts`), so without it a field declared `number` read back as `'9'` - including
|
|
@@ -21,15 +23,17 @@
|
|
|
21
23
|
* `types.setTypeParser` calls in `neon/neonQuerier.test.ts` - and both made the suite pass on
|
|
22
24
|
* behaviour the library never shipped. Do not reintroduce one.
|
|
23
25
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* keeps the column DECIMAL while leaving the value as the exact text the driver returned.
|
|
26
|
+
* A caller's own `types` in the pool options are spread after this one and therefore win. For a
|
|
27
|
+
* decimal, the lighter escape hatch is the declaration itself: `@Field({ type: String, columnType:
|
|
28
|
+
* 'decimal' })` keeps the column DECIMAL while leaving the value as the exact text the driver returned.
|
|
28
29
|
*/
|
|
29
30
|
export function numericTypes(types) {
|
|
30
31
|
// Text only: in binary mode an INT8 arrives as an 8-byte Buffer, and `Number(buffer)` is `NaN`.
|
|
31
|
-
const
|
|
32
|
+
const decoders = new Map([
|
|
33
|
+
[types.builtins['INT8'], decodeWideNumber],
|
|
34
|
+
[types.builtins['FLOAT8'], Number],
|
|
35
|
+
]);
|
|
32
36
|
return {
|
|
33
|
-
getTypeParser: (oid, format) => format === 'text' &&
|
|
37
|
+
getTypeParser: (oid, format) => (format === 'text' && decoders.get(oid)) || types.getTypeParser(oid, format),
|
|
34
38
|
};
|
|
35
39
|
}
|
|
@@ -1,5 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { AbstractPoolQuerier } from '../querier/abstractPoolQuerier.js';
|
|
2
|
+
import type { RawRow } from '../type/index.js';
|
|
3
|
+
export interface PgAnyClient {
|
|
4
|
+
query(text: string, values?: unknown[]): Promise<{
|
|
5
|
+
rows: RawRow[];
|
|
6
|
+
rowCount: number | null;
|
|
7
|
+
}>;
|
|
8
|
+
query(stream: object): AsyncIterable<RawRow> & {
|
|
9
|
+
destroy(): void;
|
|
10
|
+
};
|
|
11
|
+
/** Any truthy argument makes `pg-pool` evict the client instead of returning it to the idle list. */
|
|
12
|
+
release(discard?: boolean): void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Querier for every client with node-postgres' API: `pg` itself, for Postgres and CockroachDB, and
|
|
16
|
+
* Neon's serverless driver. Generic over the client alone - the dialect is whichever the pool built.
|
|
17
|
+
*/
|
|
18
|
+
export declare class PgQuerier<C extends PgAnyClient = PgAnyClient> extends AbstractPoolQuerier<C> {
|
|
19
|
+
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
20
|
+
internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
|
|
21
|
+
internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, unknown>;
|
|
22
|
+
protected releaseConn(conn: C, discard: boolean): Promise<void>;
|
|
5
23
|
}
|
|
@@ -1,3 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { AbstractPoolQuerier } from '../querier/abstractPoolQuerier.js';
|
|
2
|
+
/**
|
|
3
|
+
* Querier for every client with node-postgres' API: `pg` itself, for Postgres and CockroachDB, and
|
|
4
|
+
* Neon's serverless driver. Generic over the client alone - the dialect is whichever the pool built.
|
|
5
|
+
*/
|
|
6
|
+
export class PgQuerier extends AbstractPoolQuerier {
|
|
7
|
+
async internalAll(query, values) {
|
|
8
|
+
const res = await this.getConn().query(query, values);
|
|
9
|
+
return res.rows;
|
|
10
|
+
}
|
|
11
|
+
async internalRun(query, values) {
|
|
12
|
+
const res = await this.getConn().query(query, values);
|
|
13
|
+
return this.buildUpdateResult({ rows: res.rows, changes: res.rowCount ?? 0 });
|
|
14
|
+
}
|
|
15
|
+
async *internalStream(query, values) {
|
|
16
|
+
const { default: QueryStream } = await import('pg-query-stream');
|
|
17
|
+
const stream = this.getConn().query(new QueryStream(query, values));
|
|
18
|
+
try {
|
|
19
|
+
for await (const row of stream) {
|
|
20
|
+
yield row;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
stream.destroy();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async releaseConn(conn, discard) {
|
|
28
|
+
await conn.release(discard);
|
|
29
|
+
}
|
|
3
30
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Pool, type PoolClient, type PoolConfig } from 'pg';
|
|
2
2
|
import type { ExtraOptions } from '../type/index.js';
|
|
3
3
|
import { AbstractPgQuerierPool } from './abstractPgQuerierPool.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export declare class PgQuerierPool extends AbstractPgQuerierPool<PoolClient, PgQuerier, PgDialect> {
|
|
4
|
+
import { PostgresDialect } from './postgresDialect.js';
|
|
5
|
+
export declare class PgQuerierPool extends AbstractPgQuerierPool<PoolClient, PostgresDialect> {
|
|
7
6
|
readonly pool: Pool;
|
|
8
7
|
constructor(opts: PoolConfig, extra?: ExtraOptions);
|
|
9
|
-
protected buildQuerier(connect: () => Promise<PoolClient>): PgQuerier;
|
|
10
8
|
}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { Pool, types } from 'pg';
|
|
2
2
|
import { dialectOptionsFrom } from '../dialect/abstractDialect.js';
|
|
3
3
|
import { AbstractPgQuerierPool } from './abstractPgQuerierPool.js';
|
|
4
|
-
import { PgDialect } from './pgDialect.js';
|
|
5
4
|
import { numericTypes } from './pgNumericTypes.js';
|
|
6
|
-
import {
|
|
5
|
+
import { PostgresDialect } from './postgresDialect.js';
|
|
7
6
|
export class PgQuerierPool extends AbstractPgQuerierPool {
|
|
8
7
|
constructor(opts, extra) {
|
|
9
8
|
// keepAlive reduces (but can't eliminate) idle connections being silently
|
|
10
9
|
// dropped by NATs/firewalls on long-lived remote connections.
|
|
11
|
-
super(new
|
|
12
|
-
}
|
|
13
|
-
buildQuerier(connect) {
|
|
14
|
-
return new PgQuerier(connect, this.dialect, this.extra);
|
|
10
|
+
super(new PostgresDialect(dialectOptionsFrom(extra)), new Pool({ keepAlive: true, types: numericTypes(types), ...opts }), extra);
|
|
15
11
|
}
|
|
16
12
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { PgLikeSqlDialect } from '../dialect/pgLikeSqlDialect.js';
|
|
2
2
|
import type { QueryConflictPaths, QueryContext, SqlDialectName, Type } from '../type/index.js';
|
|
3
3
|
/**
|
|
4
|
-
* PostgreSQL dialect
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* upsert `created` detection.
|
|
4
|
+
* PostgreSQL dialect, the same class under every Postgres driver - `pg`, Neon, PGlite, `bun:sql` -
|
|
5
|
+
* where a driver that binds differently passes `driverCapabilities` rather than subclassing it.
|
|
6
|
+
* Shared Postgres-wire AST/quoting/JSONB/full-text-search/vector-search logic (including BIGINT
|
|
7
|
+
* IDENTITY PKs) lives in {@link PgLikeSqlDialect}; this class adds what's Postgres-only: the `vector`
|
|
8
|
+
* extension requirement, pgvector's index syntax, and `xmax`-based upsert `created` detection.
|
|
9
9
|
*/
|
|
10
10
|
export declare class PostgresDialect extends PgLikeSqlDialect {
|
|
11
11
|
readonly dialectName: SqlDialectName;
|
|
@@ -2,11 +2,11 @@ import { COUNT_ALIAS } from '../dialect/aliases.js';
|
|
|
2
2
|
import { PgLikeSqlDialect } from '../dialect/pgLikeSqlDialect.js';
|
|
3
3
|
import { getMeta } from '../entity/index.js';
|
|
4
4
|
/**
|
|
5
|
-
* PostgreSQL dialect
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* upsert `created` detection.
|
|
5
|
+
* PostgreSQL dialect, the same class under every Postgres driver - `pg`, Neon, PGlite, `bun:sql` -
|
|
6
|
+
* where a driver that binds differently passes `driverCapabilities` rather than subclassing it.
|
|
7
|
+
* Shared Postgres-wire AST/quoting/JSONB/full-text-search/vector-search logic (including BIGINT
|
|
8
|
+
* IDENTITY PKs) lives in {@link PgLikeSqlDialect}; this class adds what's Postgres-only: the `vector`
|
|
9
|
+
* extension requirement, pgvector's index syntax, and `xmax`-based upsert `created` detection.
|
|
10
10
|
*/
|
|
11
11
|
export class PostgresDialect extends PgLikeSqlDialect {
|
|
12
12
|
dialectName = 'postgres';
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* The pair is one constant because it is one driver's shape, and `BunSqlQuerierPool` hands it to
|
|
11
11
|
* `PostgresDialect`/`CockroachDialect` as their `driverCapabilities` rather than subclassing either:
|
|
12
|
-
* Bun changes how a parameter binds, never the SQL. `
|
|
12
|
+
* Bun changes how a parameter binds, never the SQL. `PgQuerierPool` uses neither, keeping the base
|
|
13
13
|
* {@link PgLikeSqlDialect} defaults, since node-`pg` needs no fix.
|
|
14
14
|
*
|
|
15
15
|
* @remarks Optional import for custom pools. Neon uses its own serverless driver (not `bun:sql`),
|
|
16
|
-
* so `
|
|
16
|
+
* so `NeonQuerierPool` is a separate, unverified case - do not assume it needs this without testing.
|
|
17
17
|
*/
|
|
18
18
|
export declare const POSTGRES_WIRE_DRIVER_CAPABILITIES: {
|
|
19
19
|
readonly nativeArrays: false;
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* The pair is one constant because it is one driver's shape, and `BunSqlQuerierPool` hands it to
|
|
11
11
|
* `PostgresDialect`/`CockroachDialect` as their `driverCapabilities` rather than subclassing either:
|
|
12
|
-
* Bun changes how a parameter binds, never the SQL. `
|
|
12
|
+
* Bun changes how a parameter binds, never the SQL. `PgQuerierPool` uses neither, keeping the base
|
|
13
13
|
* {@link PgLikeSqlDialect} defaults, since node-`pg` needs no fix.
|
|
14
14
|
*
|
|
15
15
|
* @remarks Optional import for custom pools. Neon uses its own serverless driver (not `bun:sql`),
|
|
16
|
-
* so `
|
|
16
|
+
* so `NeonQuerierPool` is a separate, unverified case - do not assume it needs this without testing.
|
|
17
17
|
*/
|
|
18
18
|
export const POSTGRES_WIRE_DRIVER_CAPABILITIES = {
|
|
19
19
|
nativeArrays: false,
|
|
@@ -6,7 +6,7 @@ export declare abstract class AbstractPoolQuerier<C> extends AbstractSqlQuerier
|
|
|
6
6
|
readonly extra?: ExtraOptions | undefined;
|
|
7
7
|
protected conn: C | undefined;
|
|
8
8
|
protected getConn(): C;
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(connect: () => Promise<C>, dialect: AbstractSqlDialect, extra?: ExtraOptions | undefined);
|
|
10
10
|
protected lazyConnect(): Promise<void>;
|
|
11
11
|
internalRelease(discard: boolean): Promise<void>;
|
|
12
12
|
protected abstract releaseConn(conn: C, discard: boolean): Promise<void>;
|
|
@@ -8,7 +8,7 @@ export class AbstractPoolQuerier extends AbstractSqlQuerier {
|
|
|
8
8
|
throw new TypeError('pool querier not connected');
|
|
9
9
|
return this.conn;
|
|
10
10
|
}
|
|
11
|
-
constructor(
|
|
11
|
+
constructor(connect, dialect, extra) {
|
|
12
12
|
super(dialect, extra);
|
|
13
13
|
this.connect = connect;
|
|
14
14
|
this.extra = extra;
|
|
@@ -129,14 +129,21 @@ export declare abstract class AbstractSqlQuerier extends AbstractQuerier impleme
|
|
|
129
129
|
protected internalDeleteMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): Promise<number>;
|
|
130
130
|
get hasOpenTransaction(): boolean;
|
|
131
131
|
beginTransaction(opts?: TransactionOptions): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Only an end that succeeded ends the transaction. A `COMMIT` that fails can leave it open (SQLite
|
|
134
|
+
* answers `SQLITE_BUSY` and keeps it), so the flag has to stay set for the `catch` in
|
|
135
|
+
* {@link AbstractQuerier.transaction} or {@link AbstractQuerier.release} to roll it back.
|
|
136
|
+
*/
|
|
132
137
|
commitTransaction(): Promise<void>;
|
|
133
138
|
rollbackTransaction(): Promise<void>;
|
|
134
139
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
140
|
+
* How this driver opens, commits and rolls back: the dialect's statements, unless its transactions
|
|
141
|
+
* are objects rather than statements - Hrana's session handle, `mssql`'s `Transaction` - in which
|
|
142
|
+
* case it overrides all three. The bookkeeping around them stays above, written once.
|
|
138
143
|
*/
|
|
139
|
-
|
|
144
|
+
protected internalBegin(opts?: TransactionOptions): Promise<void>;
|
|
145
|
+
protected internalCommit(): Promise<void>;
|
|
146
|
+
protected internalRollback(): Promise<void>;
|
|
140
147
|
/** Transaction statements skip `timed()`, so they attach their own query context to a failure. */
|
|
141
148
|
private runTransactionCommand;
|
|
142
149
|
}
|
|
@@ -241,18 +241,19 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
241
241
|
// The one path that does not go through `all`/`run`, so it connects on its own: streaming first on
|
|
242
242
|
// a freshly acquired querier used to reach `getConn()` with nothing acquired.
|
|
243
243
|
await this.lazyConnect();
|
|
244
|
+
// No `normalizeValues` here, unlike `all`/`run`: those also take raw SQL, while every value a
|
|
245
|
+
// context holds was normalized as it was bound.
|
|
244
246
|
const ctx = this.dialect.createContext();
|
|
245
247
|
this.dialect.find(ctx, entity, q, opts);
|
|
246
|
-
const normalizedParams = this.dialect.normalizeValues(ctx.values);
|
|
247
248
|
let attrsPaths;
|
|
248
249
|
try {
|
|
249
|
-
for await (const row of this.internalStream(ctx.sql,
|
|
250
|
+
for await (const row of this.internalStream(ctx.sql, ctx.values)) {
|
|
250
251
|
attrsPaths ??= obtainAttrsPaths(row);
|
|
251
252
|
yield this.hydrateFields(entity, unflatObject(row, attrsPaths));
|
|
252
253
|
}
|
|
253
254
|
}
|
|
254
255
|
catch (err) {
|
|
255
|
-
throw enrichError(err, this.logger, ctx.sql,
|
|
256
|
+
throw enrichError(err, this.logger, ctx.sql, ctx.values);
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
/**
|
|
@@ -261,8 +262,7 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
261
262
|
* Drivers with native cursor/streaming APIs (SQLite, Pg) should override this.
|
|
262
263
|
*/
|
|
263
264
|
async *internalStream(query, values) {
|
|
264
|
-
|
|
265
|
-
yield* rows;
|
|
265
|
+
yield* await this.internalAll(query, values);
|
|
266
266
|
}
|
|
267
267
|
/**
|
|
268
268
|
* Turn what a driver returned back into the types the entity declares, for the row and everything
|
|
@@ -504,35 +504,47 @@ export class AbstractSqlQuerier extends AbstractQuerier {
|
|
|
504
504
|
throwPendingTransaction();
|
|
505
505
|
}
|
|
506
506
|
await this.lazyConnect();
|
|
507
|
-
|
|
508
|
-
await this.runTransactionCommand(sql);
|
|
509
|
-
}
|
|
507
|
+
await this.internalBegin(opts);
|
|
510
508
|
this.hasPendingTransaction = true;
|
|
511
509
|
});
|
|
512
510
|
}
|
|
511
|
+
/**
|
|
512
|
+
* Only an end that succeeded ends the transaction. A `COMMIT` that fails can leave it open (SQLite
|
|
513
|
+
* answers `SQLITE_BUSY` and keeps it), so the flag has to stay set for the `catch` in
|
|
514
|
+
* {@link AbstractQuerier.transaction} or {@link AbstractQuerier.release} to roll it back.
|
|
515
|
+
*/
|
|
513
516
|
async commitTransaction() {
|
|
514
517
|
return this.serialize(async () => {
|
|
515
518
|
if (!this.hasPendingTransaction) {
|
|
516
519
|
throwNoPendingTransaction();
|
|
517
520
|
}
|
|
518
|
-
await this.
|
|
521
|
+
await this.internalCommit();
|
|
522
|
+
this.hasPendingTransaction = false;
|
|
519
523
|
});
|
|
520
524
|
}
|
|
521
525
|
async rollbackTransaction() {
|
|
522
526
|
return this.serialize(async () => {
|
|
523
527
|
if (this.hasPendingTransaction) {
|
|
524
|
-
await this.
|
|
528
|
+
await this.internalRollback();
|
|
529
|
+
this.hasPendingTransaction = false;
|
|
525
530
|
}
|
|
526
531
|
});
|
|
527
532
|
}
|
|
528
533
|
/**
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
534
|
+
* How this driver opens, commits and rolls back: the dialect's statements, unless its transactions
|
|
535
|
+
* are objects rather than statements - Hrana's session handle, `mssql`'s `Transaction` - in which
|
|
536
|
+
* case it overrides all three. The bookkeeping around them stays above, written once.
|
|
532
537
|
*/
|
|
533
|
-
async
|
|
534
|
-
|
|
535
|
-
|
|
538
|
+
async internalBegin(opts) {
|
|
539
|
+
for (const sql of this.dialect.getBeginTransactionStatements(opts?.isolationLevel)) {
|
|
540
|
+
await this.runTransactionCommand(sql);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
internalCommit() {
|
|
544
|
+
return this.runTransactionCommand(this.dialect.commitTransactionCommand);
|
|
545
|
+
}
|
|
546
|
+
internalRollback() {
|
|
547
|
+
return this.runTransactionCommand(this.dialect.rollbackTransactionCommand);
|
|
536
548
|
}
|
|
537
549
|
/** Transaction statements skip `timed()`, so they attach their own query context to a failure. */
|
|
538
550
|
async runTransactionCommand(sql) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExtraOptions
|
|
1
|
+
import type { ExtraOptions } from '../type/index.js';
|
|
2
2
|
import { AbstractSqliteQuerier, type SqliteBindValue } from './abstractSqliteQuerier.js';
|
|
3
3
|
import type { SqliteDialect } from './sqliteDialect.js';
|
|
4
4
|
/**
|
|
@@ -46,14 +46,12 @@ export declare class HranaQuerier extends AbstractSqliteQuerier {
|
|
|
46
46
|
constructor(client: HranaClient, dialect: SqliteDialect, extra?: ExtraOptions | undefined, connection?: HranaQuerierConnectionOptions);
|
|
47
47
|
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
48
48
|
internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
|
|
49
|
-
|
|
50
|
-
beginTransaction(_opts?: TransactionOptions): Promise<void>;
|
|
49
|
+
protected internalBegin(): Promise<void>;
|
|
51
50
|
/**
|
|
52
|
-
* Both drop the handle before the call, not after: one that outlived a failed commit
|
|
53
|
-
*
|
|
54
|
-
* there is nothing open.
|
|
51
|
+
* Both drop the handle before the call, not after: one that outlived a failed commit would carry
|
|
52
|
+
* every later statement into a transaction the server may already have ended.
|
|
55
53
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
protected internalCommit(): Promise<void>;
|
|
55
|
+
protected internalRollback(): Promise<void>;
|
|
58
56
|
internalRelease(): Promise<void>;
|
|
59
57
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { throwNoPendingTransaction, throwPendingTransaction } from '../util/index.js';
|
|
2
1
|
import { AbstractSqliteQuerier } from './abstractSqliteQuerier.js';
|
|
3
2
|
/**
|
|
4
3
|
* Querier for SQLite databases reached through a Hrana client.
|
|
@@ -30,38 +29,22 @@ export class HranaQuerier extends AbstractSqliteQuerier {
|
|
|
30
29
|
// the actual row count when rows were returned.
|
|
31
30
|
return this.buildUpdateResult({ rows, changes: rows.length || res.rowsAffected, id: res.lastInsertRowid });
|
|
32
31
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
async beginTransaction(_opts) {
|
|
37
|
-
return this.serialize(async () => {
|
|
38
|
-
if (this.tx) {
|
|
39
|
-
throwPendingTransaction();
|
|
40
|
-
}
|
|
41
|
-
this.tx = await this.client.transaction('write');
|
|
42
|
-
});
|
|
32
|
+
async internalBegin() {
|
|
33
|
+
this.tx = await this.client.transaction('write');
|
|
43
34
|
}
|
|
44
35
|
/**
|
|
45
|
-
* Both drop the handle before the call, not after: one that outlived a failed commit
|
|
46
|
-
*
|
|
47
|
-
* there is nothing open.
|
|
36
|
+
* Both drop the handle before the call, not after: one that outlived a failed commit would carry
|
|
37
|
+
* every later statement into a transaction the server may already have ended.
|
|
48
38
|
*/
|
|
49
|
-
async
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
async rollbackTransaction() {
|
|
60
|
-
return this.serialize(async () => {
|
|
61
|
-
const tx = this.tx;
|
|
62
|
-
this.tx = undefined;
|
|
63
|
-
await tx?.rollback();
|
|
64
|
-
});
|
|
39
|
+
async internalCommit() {
|
|
40
|
+
const tx = this.tx;
|
|
41
|
+
this.tx = undefined;
|
|
42
|
+
await tx?.commit();
|
|
43
|
+
}
|
|
44
|
+
async internalRollback() {
|
|
45
|
+
const tx = this.tx;
|
|
46
|
+
this.tx = undefined;
|
|
47
|
+
await tx?.rollback();
|
|
65
48
|
}
|
|
66
49
|
async internalRelease() {
|
|
67
50
|
await super.internalRelease();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AbstractSqlQuerierPool } from '../querier/index.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type HranaClient, HranaQuerier } from './hranaQuerier.js';
|
|
3
3
|
import type { SqliteDialect } from './sqliteDialect.js';
|
|
4
4
|
/**
|
|
5
5
|
* Pool for SQLite databases reached over the Hrana wire protocol (`@libsql/client`,
|
|
@@ -10,12 +10,11 @@ import type { SqliteDialect } from './sqliteDialect.js';
|
|
|
10
10
|
* constructor, so building a pool never throws when the optional driver peer is absent, which is what
|
|
11
11
|
* lets a Workers bundle construct one at module scope.
|
|
12
12
|
*/
|
|
13
|
-
export declare abstract class AbstractHranaQuerierPool<
|
|
13
|
+
export declare abstract class AbstractHranaQuerierPool<D extends SqliteDialect> extends AbstractSqlQuerierPool<HranaQuerier, D> {
|
|
14
14
|
private client?;
|
|
15
15
|
/** False when the caller injected their own client, in which case they own its lifecycle. */
|
|
16
16
|
protected readonly ownsClient: boolean;
|
|
17
17
|
protected abstract openClient(): Promise<HranaClient>;
|
|
18
|
-
|
|
19
|
-
getQuerier(): Promise<Q>;
|
|
18
|
+
getQuerier(): Promise<HranaQuerier>;
|
|
20
19
|
end(): Promise<void>;
|
|
21
20
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AbstractSqlQuerierPool } from '../querier/index.js';
|
|
2
|
+
import { HranaQuerier } from './hranaQuerier.js';
|
|
2
3
|
/**
|
|
3
4
|
* Pool for SQLite databases reached over the Hrana wire protocol (`@libsql/client`,
|
|
4
5
|
* `@tursodatabase/serverless/compat`).
|
|
@@ -14,7 +15,7 @@ export class AbstractHranaQuerierPool extends AbstractSqlQuerierPool {
|
|
|
14
15
|
ownsClient = true;
|
|
15
16
|
async getQuerier() {
|
|
16
17
|
this.client ??= await this.openClient();
|
|
17
|
-
return this.
|
|
18
|
+
return new HranaQuerier(this.client, this.dialect, this.extra);
|
|
18
19
|
}
|
|
19
20
|
async end() {
|
|
20
21
|
if (this.ownsClient) {
|
|
@@ -15,13 +15,13 @@ export type LocalSqlitePoolOptions = {
|
|
|
15
15
|
* Pool for a SQLite database opened in this process, whichever driver provides it. SQLite gives one
|
|
16
16
|
* connection per file, so the shared-handle lifecycle is {@link AbstractSharedHandleQuerierPool}'s.
|
|
17
17
|
*
|
|
18
|
-
* Subclasses supply only {@link createDb}:
|
|
19
|
-
* `better-sqlite3`, `bun:sqlite` and `node:sqlite
|
|
18
|
+
* Subclasses supply only {@link createDb}: configuring the connection on the way up - the pragmas,
|
|
19
|
+
* then the extensions - is the same for `better-sqlite3`, `bun:sqlite` and `node:sqlite`.
|
|
20
20
|
*/
|
|
21
21
|
export declare abstract class AbstractLocalSqliteQuerierPool<O extends LocalSqlitePoolOptions> extends AbstractSharedHandleQuerierPool<SqliteDatabase, SqliteQuerier, SqliteDialect> {
|
|
22
22
|
readonly opts?: O | undefined;
|
|
23
23
|
constructor(opts?: O | undefined, extra?: ExtraOptions);
|
|
24
|
-
/** Opens the driver's database
|
|
24
|
+
/** Opens the driver's database, and nothing more: the caller configures it. */
|
|
25
25
|
protected abstract createDb(): Promise<SqliteDatabase>;
|
|
26
26
|
protected openDb(): Promise<SqliteDatabase>;
|
|
27
27
|
protected buildQuerier(db: SqliteDatabase): SqliteQuerier;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { dialectOptionsFrom } from '../dialect/abstractDialect.js';
|
|
2
2
|
import { AbstractSharedHandleQuerierPool } from '../querier/abstractSharedHandleQuerierPool.js';
|
|
3
3
|
import { SqliteDialect } from './sqliteDialect.js';
|
|
4
|
+
import { applySqlitePragmas } from './sqlitePragmas.js';
|
|
4
5
|
import { SqliteQuerier } from './sqliteQuerier.js';
|
|
5
6
|
/**
|
|
6
7
|
* Pool for a SQLite database opened in this process, whichever driver provides it. SQLite gives one
|
|
7
8
|
* connection per file, so the shared-handle lifecycle is {@link AbstractSharedHandleQuerierPool}'s.
|
|
8
9
|
*
|
|
9
|
-
* Subclasses supply only {@link createDb}:
|
|
10
|
-
* `better-sqlite3`, `bun:sqlite` and `node:sqlite
|
|
10
|
+
* Subclasses supply only {@link createDb}: configuring the connection on the way up - the pragmas,
|
|
11
|
+
* then the extensions - is the same for `better-sqlite3`, `bun:sqlite` and `node:sqlite`.
|
|
11
12
|
*/
|
|
12
13
|
export class AbstractLocalSqliteQuerierPool extends AbstractSharedHandleQuerierPool {
|
|
13
14
|
opts;
|
|
@@ -17,6 +18,7 @@ export class AbstractLocalSqliteQuerierPool extends AbstractSharedHandleQuerierP
|
|
|
17
18
|
}
|
|
18
19
|
async openDb() {
|
|
19
20
|
const db = await this.createDb();
|
|
21
|
+
await applySqlitePragmas(db);
|
|
20
22
|
for (const extension of this.opts?.extensions ?? []) {
|
|
21
23
|
db.loadExtension(extension);
|
|
22
24
|
}
|
|
@@ -23,8 +23,6 @@ export class NodeSqliteQuerierPool extends AbstractLocalSqliteQuerierPool {
|
|
|
23
23
|
// `node:sqlite` refuses `loadExtension` unless the database was opened with this on.
|
|
24
24
|
...(extensions?.length ? { allowExtension: true } : undefined),
|
|
25
25
|
});
|
|
26
|
-
nodeDb.exec('PRAGMA journal_mode = WAL');
|
|
27
|
-
nodeDb.exec('PRAGMA foreign_keys = ON');
|
|
28
26
|
return adaptNodeSqlite(nodeDb);
|
|
29
27
|
}
|
|
30
28
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
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'];
|
|
9
|
+
/** 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>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How every local SQLite connection opens. WAL, so a reader does not wait on the writer, and
|
|
3
|
+
* `foreign_keys`, which SQLite ships off per connection for backward compatibility: without it the
|
|
4
|
+
* constraints uql's own DDL declares are decorative - a declared `onDelete: 'CASCADE'` silently does
|
|
5
|
+
* nothing and a dangling reference is accepted.
|
|
6
|
+
*/
|
|
7
|
+
export const SQLITE_PRAGMAS = ['journal_mode = WAL', 'foreign_keys = ON'];
|
|
8
|
+
/** Runs {@link SQLITE_PRAGMAS} through a driver's own statements, whether it answers now or later. */
|
|
9
|
+
export async function applySqlitePragmas(db) {
|
|
10
|
+
for (const pragma of SQLITE_PRAGMAS) {
|
|
11
|
+
const stmt = await db.prepare(`PRAGMA ${pragma}`);
|
|
12
|
+
// `journal_mode` answers with a row and `foreign_keys` with none; `reader` picks the call for each.
|
|
13
|
+
await (stmt.reader ? stmt.all() : stmt.run());
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -11,10 +11,5 @@ export type Sqlite3PoolOptions = Options & LocalSqlitePoolOptions;
|
|
|
11
11
|
export declare class Sqlite3QuerierPool extends AbstractLocalSqliteQuerierPool<Sqlite3PoolOptions> {
|
|
12
12
|
readonly filename: string | Buffer;
|
|
13
13
|
constructor(filename?: string | Buffer, opts?: Sqlite3PoolOptions, extra?: ExtraOptions);
|
|
14
|
-
/**
|
|
15
|
-
* SQLite ships with foreign keys unenforced, per connection, for backward compatibility. UQL emits the
|
|
16
|
-
* constraints in its DDL, so leaving them off means a declared `onDelete: 'CASCADE'` silently does
|
|
17
|
-
* nothing and a dangling reference is accepted. Enabled here on every driver, as TypeORM also does.
|
|
18
|
-
*/
|
|
19
14
|
protected createDb(): Promise<SqliteDatabase>;
|
|
20
15
|
}
|
|
@@ -10,11 +10,6 @@ export class Sqlite3QuerierPool extends AbstractLocalSqliteQuerierPool {
|
|
|
10
10
|
super(opts, extra);
|
|
11
11
|
this.filename = filename;
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
14
|
-
* SQLite ships with foreign keys unenforced, per connection, for backward compatibility. UQL emits the
|
|
15
|
-
* constraints in its DDL, so leaving them off means a declared `onDelete: 'CASCADE'` silently does
|
|
16
|
-
* nothing and a dangling reference is accepted. Enabled here on every driver, as TypeORM also does.
|
|
17
|
-
*/
|
|
18
13
|
async createDb() {
|
|
19
14
|
// `bun:sqlite` rejects option keys it does not know, and rejects an options object carrying no
|
|
20
15
|
// open flags, so `extensions` is stripped out and what remains of it collapses back to nothing.
|
|
@@ -23,15 +18,9 @@ export class Sqlite3QuerierPool extends AbstractLocalSqliteQuerierPool {
|
|
|
23
18
|
if (typeof Bun !== 'undefined') {
|
|
24
19
|
const { Database: BunDatabase } = await import('bun:sqlite');
|
|
25
20
|
const { adaptBunSqlite } = await import('./bunSqliteAdapter.bun.js');
|
|
26
|
-
|
|
27
|
-
bunDb.run('PRAGMA journal_mode = WAL');
|
|
28
|
-
bunDb.run('PRAGMA foreign_keys = ON');
|
|
29
|
-
return adaptBunSqlite(bunDb);
|
|
21
|
+
return adaptBunSqlite(new BunDatabase(this.filename, opts));
|
|
30
22
|
}
|
|
31
23
|
const { default: BetterSqlite3 } = await import('better-sqlite3');
|
|
32
|
-
|
|
33
|
-
db.pragma('journal_mode = WAL');
|
|
34
|
-
db.pragma('foreign_keys = ON');
|
|
35
|
-
return db;
|
|
24
|
+
return new BetterSqlite3(this.filename, opts);
|
|
36
25
|
}
|
|
37
26
|
}
|
package/dist/turso/index.d.ts
CHANGED
package/dist/turso/index.js
CHANGED