uql-orm 0.53.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 +2 -2
- 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/cockroachDialect.d.ts +2 -5
- package/dist/cockroachdb/cockroachDialect.js +2 -5
- 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 +15 -9
- package/dist/dialect/abstractSqlDialect.js +47 -54
- 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/mysqlLikeSqlDialect.d.ts +0 -3
- package/dist/dialect/mysqlLikeSqlDialect.js +0 -3
- package/dist/dialect/pgLikeSqlDialect.d.ts +5 -0
- package/dist/dialect/pgLikeSqlDialect.js +12 -2
- package/dist/entity/decorator/members.d.ts +3 -10
- 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 -4
- 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/builder/migrationBuilder.js +0 -4
- package/dist/migrate/ddl/index.d.ts +3 -3
- package/dist/migrate/ddl/index.js +3 -3
- package/dist/migrate/migrator.d.ts +3 -7
- package/dist/migrate/migrator.js +3 -7
- package/dist/migrate/schemaGenerator.d.ts +0 -13
- package/dist/migrate/schemaGenerator.js +0 -13
- package/dist/migrate/storage/databaseStorage.d.ts +2 -2
- package/dist/migrate/storage/databaseStorage.js +2 -2
- 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.d.ts +3 -5
- package/dist/mongo/mongodbQuerier.js +23 -23
- package/dist/mongo/mongodbQuerierPool.d.ts +2 -2
- package/dist/mongo/mongodbQuerierPool.js +2 -2
- package/dist/mssql/mssqlDialect.d.ts +5 -5
- package/dist/mssql/mssqlDialect.js +11 -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/abstractQuerier.d.ts +17 -22
- package/dist/querier/abstractQuerier.js +80 -57
- package/dist/querier/abstractSqlQuerier.d.ts +20 -13
- package/dist/querier/abstractSqlQuerier.js +96 -100
- package/dist/schema/schemaASTBuilder.js +7 -7
- 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/type/entity.d.ts +6 -11
- package/dist/type/migration.d.ts +0 -3
- package/dist/type/query.d.ts +12 -12
- package/dist/type/query.js +0 -6
- package/dist/type/universalQuerier.d.ts +3 -3
- package/dist/util/dialect.util.d.ts +4 -3
- package/dist/util/dialect.util.js +2 -1
- package/dist/util/field.util.d.ts +4 -16
- package/dist/util/field.util.js +6 -19
- package/dist/util/fieldOption.util.d.ts +1 -4
- package/dist/util/fieldOption.util.js +0 -2
- package/dist/util/logger.d.ts +10 -11
- package/dist/util/logger.js +21 -11
- package/dist/util/raw.d.ts +3 -10
- package/dist/util/raw.js +3 -3
- package/dist/util/sql.util.js +2 -2
- 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
|
@@ -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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { dialectOptionsFrom } from '../dialect/abstractDialect.js';
|
|
2
2
|
import { AbstractSharedHandleQuerierPool } from '../querier/abstractSharedHandleQuerierPool.js';
|
|
3
|
+
import { applySqlitePragmas } from '../sqlite/sqlitePragmas.js';
|
|
3
4
|
import { TursoDialect } from './tursoDialect.js';
|
|
4
5
|
import { TursoLocalQuerier } from './tursoLocalQuerier.js';
|
|
5
6
|
/**
|
|
@@ -21,8 +22,7 @@ export class TursoLocalQuerierPool extends AbstractSharedHandleQuerierPool {
|
|
|
21
22
|
const { connect } = await import('@tursodatabase/database');
|
|
22
23
|
// Annotated rather than cast, so the structural contract is checked against the real driver.
|
|
23
24
|
const db = await connect(this.filename, this.opts);
|
|
24
|
-
await db
|
|
25
|
-
await db.pragma('foreign_keys = ON');
|
|
25
|
+
await applySqlitePragmas(db);
|
|
26
26
|
return db;
|
|
27
27
|
}
|
|
28
28
|
buildQuerier(db) {
|
|
@@ -2,7 +2,6 @@ import type { HranaClient } from '../sqlite/hranaQuerier.js';
|
|
|
2
2
|
import { AbstractHranaQuerierPool } from '../sqlite/hranaQuerierPool.js';
|
|
3
3
|
import type { ExtraOptions } from '../type/index.js';
|
|
4
4
|
import { TursoDialect } from './tursoDialect.js';
|
|
5
|
-
import { TursoQuerier } from './tursoQuerier.js';
|
|
6
5
|
/**
|
|
7
6
|
* Connection settings for Turso Cloud, mirroring `@tursodatabase/serverless`.
|
|
8
7
|
*
|
|
@@ -26,7 +25,7 @@ export type TursoConfig = {
|
|
|
26
25
|
* because over plain HTTP consecutive requests need not share a connection. Compat's session-backed
|
|
27
26
|
* transaction handle is the piece that makes it work.
|
|
28
27
|
*/
|
|
29
|
-
export declare class TursoQuerierPool extends AbstractHranaQuerierPool<
|
|
28
|
+
export declare class TursoQuerierPool extends AbstractHranaQuerierPool<TursoDialect> {
|
|
30
29
|
protected readonly ownsClient: boolean;
|
|
31
30
|
private readonly conf;
|
|
32
31
|
/**
|
|
@@ -35,5 +34,4 @@ export declare class TursoQuerierPool extends AbstractHranaQuerierPool<TursoQuer
|
|
|
35
34
|
*/
|
|
36
35
|
constructor(conf: TursoConfig | HranaClient, extra?: ExtraOptions);
|
|
37
36
|
protected openClient(): Promise<HranaClient>;
|
|
38
|
-
protected buildQuerier(client: HranaClient): TursoQuerier;
|
|
39
37
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { dialectOptionsFrom } from '../dialect/abstractDialect.js';
|
|
2
2
|
import { AbstractHranaQuerierPool } from '../sqlite/hranaQuerierPool.js';
|
|
3
3
|
import { TursoDialect } from './tursoDialect.js';
|
|
4
|
-
import { TursoQuerier } from './tursoQuerier.js';
|
|
5
4
|
function isClient(conf) {
|
|
6
5
|
return typeof conf.execute === 'function';
|
|
7
6
|
}
|
|
@@ -33,7 +32,4 @@ export class TursoQuerierPool extends AbstractHranaQuerierPool {
|
|
|
33
32
|
const { createClient } = await import('@tursodatabase/serverless/compat');
|
|
34
33
|
return createClient(this.conf);
|
|
35
34
|
}
|
|
36
|
-
buildQuerier(client) {
|
|
37
|
-
return new TursoQuerier(client, this.dialect, this.extra);
|
|
38
|
-
}
|
|
39
35
|
}
|
package/dist/type/dialect.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export interface DriverCapabilities {
|
|
|
59
59
|
readonly explicitJsonCast: boolean;
|
|
60
60
|
/**
|
|
61
61
|
* Whether the driver natively supports JS arrays for the underlying database type.
|
|
62
|
-
* `
|
|
62
|
+
* `PgQuerierPool` keeps this `true` for node-postgres; `BunSqlQuerierPool` sets `false` and binds
|
|
63
63
|
* `toPgArray` string literals instead.
|
|
64
64
|
*/
|
|
65
65
|
readonly nativeArrays: boolean;
|
package/dist/type/entity.d.ts
CHANGED
|
@@ -359,11 +359,6 @@ export type FieldOptions<V = TsTypeOf<FieldType>> = {
|
|
|
359
359
|
* @example `@Field({ type: String, enum: ['draft', 'paid'] as const })`
|
|
360
360
|
*/
|
|
361
361
|
readonly enum?: EnumValues;
|
|
362
|
-
/**
|
|
363
|
-
* @deprecated Renamed to {@link FieldOptions.computed}, which also takes `stored`. `npx uql-codemod`
|
|
364
|
-
* rewrites it. Giving both throws.
|
|
365
|
-
*/
|
|
366
|
-
readonly virtual?: QueryRaw;
|
|
367
362
|
/**
|
|
368
363
|
* An expression the database computes, rather than a value the caller writes. Never part of an
|
|
369
364
|
* insert or update either way.
|
|
@@ -818,12 +813,6 @@ export type EntityMeta<E> = {
|
|
|
818
813
|
/** The revision `getMeta` last finalized, which is what makes finalizing idempotent and re-entrant. */
|
|
819
814
|
processedAt?: number;
|
|
820
815
|
};
|
|
821
|
-
/**
|
|
822
|
-
* Configurable options for an entity (`@Entity()` / `defineEntity`).
|
|
823
|
-
*
|
|
824
|
-
* Optional `fields`, `relations`, `indexes`, and `hooks` register metadata in one call for
|
|
825
|
-
* decorator-free setups. Omit them when using `@Field` / `@ManyToOne` / etc.
|
|
826
|
-
*/
|
|
827
816
|
/**
|
|
828
817
|
* A table-level `CHECK`. The expression is `raw` with no interpolation, like an index expression:
|
|
829
818
|
* this is DDL, so there is no placeholder a bound value could go into.
|
|
@@ -843,6 +832,12 @@ export type EntityMembers = {
|
|
|
843
832
|
readonly relations?: Readonly<Record<string, RelationOptions | undefined>>;
|
|
844
833
|
readonly hooks?: Readonly<Partial<Record<HookEvent, readonly string[]>>>;
|
|
845
834
|
};
|
|
835
|
+
/**
|
|
836
|
+
* Configurable options for an entity (`@Entity()` / `defineEntity`).
|
|
837
|
+
*
|
|
838
|
+
* Optional `fields`, `relations`, `indexes`, and `hooks` register metadata in one call for
|
|
839
|
+
* decorator-free setups. Omit them when using `@Field` / `@ManyToOne` / etc.
|
|
840
|
+
*/
|
|
846
841
|
export type EntityOptions<E = unknown> = {
|
|
847
842
|
readonly name?: string;
|
|
848
843
|
/**
|
package/dist/type/migration.d.ts
CHANGED
|
@@ -372,9 +372,6 @@ export interface SchemaIntrospector {
|
|
|
372
372
|
* the database side never reports it, and no migration can close the gap.
|
|
373
373
|
*/
|
|
374
374
|
readonly indexFacets: ReadonlySet<IndexFacet>;
|
|
375
|
-
/**
|
|
376
|
-
* Introspect entire database schema and return SchemaAST.
|
|
377
|
-
*/
|
|
378
375
|
/** The whole database, or just the tables named. Names nothing matches are left out. */
|
|
379
376
|
introspect(tables?: readonly string[]): Promise<SchemaAST>;
|
|
380
377
|
/**
|
package/dist/type/query.d.ts
CHANGED
|
@@ -59,17 +59,17 @@ export type QueryExclude<E> = QuerySelect<E>;
|
|
|
59
59
|
export type QueryPopulate<E> = {
|
|
60
60
|
[K in RelationKey<E>]?: BooleanLike | QueryPopulateRelationOptions<E[K]>;
|
|
61
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* The key a read carries its relation tallies under. One spelling for the type and the runtime that
|
|
64
|
+
* fills it: they sit in different modules, so a drift would type-check and answer `undefined`.
|
|
65
|
+
*/
|
|
66
|
+
export declare const COUNT_RESULT_KEY = "_count";
|
|
62
67
|
/**
|
|
63
68
|
* How many rows each named relation holds per parent, `true` for all of them or a filter to narrow
|
|
64
69
|
* which ones count. One statement per relation named here, batched over every parent at once, so it
|
|
65
70
|
* stays flat however many rows the read returned. Comes back under `_count`, which keeps it clear of
|
|
66
71
|
* a relation of the same name that `$populate` filled with rows.
|
|
67
72
|
*/
|
|
68
|
-
/**
|
|
69
|
-
* The key a read carries its relation tallies under. One spelling for the type and the runtime that
|
|
70
|
-
* fills it: they sit in different modules, so a drift would type-check and answer `undefined`.
|
|
71
|
-
*/
|
|
72
|
-
export declare const COUNT_RESULT_KEY = "_count";
|
|
73
73
|
export type QueryCount<E> = {
|
|
74
74
|
[K in ToManyRelationKey<E>]?: BooleanLike | QueryFilter<RelationTarget<E[K]>>;
|
|
75
75
|
};
|
|
@@ -141,6 +141,13 @@ type ToOneRelationKey<E> = {
|
|
|
141
141
|
}[RelationKey<E>];
|
|
142
142
|
/** The relation names a parent holds many rows of, which a populated query fills with a list. */
|
|
143
143
|
type ToManyRelationKey<E> = Exclude<RelationKey<E>, ToOneRelationKey<E>>;
|
|
144
|
+
/**
|
|
145
|
+
* Ordering parents by how many rows a to-many relation holds - "the ten users with the most posts".
|
|
146
|
+
* The tally is computed per parent as a correlated count, never by loading the rows.
|
|
147
|
+
*/
|
|
148
|
+
export type QuerySortByCount = {
|
|
149
|
+
$count: QuerySortDirection;
|
|
150
|
+
};
|
|
144
151
|
/**
|
|
145
152
|
* sort by map - supports field keys, JSON dot-notation paths (restricted to real JSON fields,
|
|
146
153
|
* like `QueryWhere`), relation sort via nested objects, and vector similarity search on
|
|
@@ -153,13 +160,6 @@ type ToManyRelationKey<E> = Exclude<RelationKey<E>, ToOneRelationKey<E>>;
|
|
|
153
160
|
* against an intersection is repeated per constituent, which made this the single most expensive
|
|
154
161
|
* type in the package to check.
|
|
155
162
|
*/
|
|
156
|
-
/**
|
|
157
|
-
* Ordering parents by how many rows a to-many relation holds - "the ten users with the most posts".
|
|
158
|
-
* The tally is computed per parent as a correlated count, never by loading the rows.
|
|
159
|
-
*/
|
|
160
|
-
export type QuerySortByCount = {
|
|
161
|
-
$count: QuerySortDirection;
|
|
162
|
-
};
|
|
163
163
|
export type QuerySortMap<E, Vector extends boolean = true> = {
|
|
164
164
|
[K in FieldKey<E> | JsonFieldPaths<E> | RelationKey<E>]?: K extends RelationKey<E> ? IsMany<E[K]> extends true ? QuerySortByCount : QuerySortMap<RelationTarget<E[K]>, false> : K extends FieldKey<E> ? Vector extends true ? NonNullable<E[K]> extends readonly number[] ? QuerySortValue : QuerySortDirection : QuerySortDirection : QuerySortDirection;
|
|
165
165
|
};
|
package/dist/type/query.js
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* How many rows each named relation holds per parent, `true` for all of them or a filter to narrow
|
|
3
|
-
* which ones count. One statement per relation named here, batched over every parent at once, so it
|
|
4
|
-
* stays flat however many rows the read returned. Comes back under `_count`, which keeps it clear of
|
|
5
|
-
* a relation of the same name that `$populate` filled with rows.
|
|
6
|
-
*/
|
|
7
1
|
/**
|
|
8
2
|
* The key a read carries its relation tallies under. One spelling for the type and the runtime that
|
|
9
3
|
* fills it: they sit in different modules, so a drift would type-check and answer `undefined`.
|
|
@@ -126,7 +126,7 @@ export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions>
|
|
|
126
126
|
* on MySQL/SQLite 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
|
-
* reports, so those rows are named
|
|
129
|
+
* reports, so those rows are named as written, `onInsert` columns included.
|
|
130
130
|
* @param entity the entity to persist on
|
|
131
131
|
* @param payload the data to be persisted
|
|
132
132
|
* @return the IDs
|
|
@@ -137,7 +137,7 @@ export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions>
|
|
|
137
137
|
* @param entity the entity to persist on
|
|
138
138
|
* @param conflictPaths the keys to use for the unique search
|
|
139
139
|
* @param payload the data to be persisted
|
|
140
|
-
* @return
|
|
140
|
+
* @return the id and whether it was created; see {@link QueryUpsertOneResult}
|
|
141
141
|
*/
|
|
142
142
|
upsertOne<E extends object>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>): Promise<QueryUpsertOneResult<E>>;
|
|
143
143
|
/**
|
|
@@ -145,7 +145,7 @@ export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions>
|
|
|
145
145
|
* @param entity the entity to persist on
|
|
146
146
|
* @param conflictPaths the keys to use for the unique search
|
|
147
147
|
* @param payload the data to be persisted
|
|
148
|
-
* @return
|
|
148
|
+
* @return the ids, in payload order; see {@link QueryUpsertManyResult}
|
|
149
149
|
*/
|
|
150
150
|
upsertMany<E extends object>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>[]): Promise<QueryUpsertManyResult<E>>;
|
|
151
151
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CascadeType, type EntityData, type EntityId, type EntityIndexMeta, type EntityMeta, type FieldKey, type FieldOptions, type JsonUpdateOp, type OnFieldCallback, type Query, type QueryAggMap, type QueryAggregateOp, type QueryExclude, type QueryGroupMap, type QueryOptions, QueryRaw, type QuerySearch, type QuerySelect, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryVectorSearch, type QueryWhere, type RelationKey } from '../type/index.js';
|
|
1
|
+
import { type CascadeType, type EntityData, type EntityId, type EntityIndexMeta, type EntityMeta, type FieldKey, type FieldOptions, type JsonUpdateOp, type OnFieldCallback, type Query, type QueryAggMap, type QueryAggregateOp, type QueryExclude, type QueryGroupMap, type QueryOptions, QueryRaw, type QuerySearch, type QuerySelect, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryVectorSearch, type QueryWhere, type RelationKey, type UpdatePayload } from '../type/index.js';
|
|
2
2
|
export type CallbackKey = keyof Pick<FieldOptions, 'onInsert' | 'onUpdate'>;
|
|
3
3
|
export declare function filterFieldKeys<E>(meta: EntityMeta<E>, payload: EntityData<E>, callbackKey: CallbackKey): FieldKey<E>[];
|
|
4
4
|
/** Appends `record`'s not-yet-`seen` insertable keys (real, caller-written, defined value) to `keys`. */
|
|
@@ -35,7 +35,8 @@ export declare function getSoftDeleteValue(field: FieldOptions): string | number
|
|
|
35
35
|
}[] | readonly number[] | Uint8Array<ArrayBufferLike> | {
|
|
36
36
|
readonly __json?: never;
|
|
37
37
|
};
|
|
38
|
-
|
|
38
|
+
/** Fills each field `callbackKey` generates on `payload` in place, where the caller left it unset. */
|
|
39
|
+
export declare function fillOnFields<E, R extends EntityData<E> | UpdatePayload<E>>(meta: EntityMeta<E>, payload: R | R[], callbackKey: CallbackKey): R[];
|
|
39
40
|
/**
|
|
40
41
|
* The relation keys present in `payload` whose cascade configuration allows `action`. Only
|
|
41
42
|
* `payload`'s keys are read, so any keys-bearing object works (an entity, an update payload,
|
|
@@ -169,4 +170,4 @@ export declare function assertNonNegativeInteger(value: number, clause: string):
|
|
|
169
170
|
*/
|
|
170
171
|
export declare function throwUnknownAggregateColumn(key: string, clause: string): never;
|
|
171
172
|
/** {@link throwUnknownAggregateColumn} over every key of a clause, for backends that check up front. */
|
|
172
|
-
export declare function assertAggregateColumns(clauseMap: object
|
|
173
|
+
export declare function assertAggregateColumns(clauseMap: object, emitted: ReadonlySet<string>, clause: string): void;
|
|
@@ -73,6 +73,7 @@ export function getFieldCallbackValue(val) {
|
|
|
73
73
|
export function getSoftDeleteValue(field) {
|
|
74
74
|
return field.softDelete === true ? new Date() : getFieldCallbackValue(field.softDelete);
|
|
75
75
|
}
|
|
76
|
+
/** Fills each field `callbackKey` generates on `payload` in place, where the caller left it unset. */
|
|
76
77
|
export function fillOnFields(meta, payload, callbackKey) {
|
|
77
78
|
const payloads = Array.isArray(payload) ? payload : [payload];
|
|
78
79
|
const keys = getKeys(meta.fields).filter((key) => meta.fields[key][callbackKey]);
|
|
@@ -417,7 +418,7 @@ export function throwUnknownAggregateColumn(key, clause) {
|
|
|
417
418
|
}
|
|
418
419
|
/** {@link throwUnknownAggregateColumn} over every key of a clause, for backends that check up front. */
|
|
419
420
|
export function assertAggregateColumns(clauseMap, emitted, clause) {
|
|
420
|
-
for (const key of getKeys(clauseMap
|
|
421
|
+
for (const key of getKeys(clauseMap)) {
|
|
421
422
|
if (!emitted.has(key)) {
|
|
422
423
|
throwUnknownAggregateColumn(key, clause);
|
|
423
424
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { EntityMeta, FieldOptions } from '../type/index.js';
|
|
2
|
-
import type { QueryRaw } from '../type/queryRaw.js';
|
|
3
2
|
/**
|
|
4
3
|
* The kind of column a field lands on, which is what decides whether an option means anything on it:
|
|
5
4
|
* `length` is a string's, `precision` a number's, `dimensions` a vector's. Named in the words an
|
|
@@ -23,26 +22,15 @@ export declare const COLUMN_TYPES_BY_FAMILY: {
|
|
|
23
22
|
};
|
|
24
23
|
/** The family of a logical field type, or `undefined` where it names none. */
|
|
25
24
|
export declare function columnFamily(type: unknown): ColumnFamily | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* The expression the database computes for this field, whichever key declared it.
|
|
28
|
-
*
|
|
29
|
-
* `virtual` is `computed` under its old name and is read here so both spell one behaviour. Giving
|
|
30
|
-
* both is refused at registration rather than resolved, since only the author knows which was meant.
|
|
31
|
-
*/
|
|
32
|
-
export declare function computedExpression(field: FieldOptions): QueryRaw | undefined;
|
|
33
25
|
/**
|
|
34
26
|
* Whether the field's expression is spliced into each statement that reads it, rather than stored.
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* the projection, the `$where` operand, the `ORDER BY` operand - because an inlined field has no
|
|
38
|
-
* column to name, while a stored one is read exactly like any other.
|
|
27
|
+
* Every read site asks this - the DDL skip, the projection, the `$where` and `ORDER BY` operands -
|
|
28
|
+
* because an inlined field has no column to name, while a stored one is read like any other.
|
|
39
29
|
*/
|
|
40
30
|
export declare function isInlinedExpression(field: FieldOptions): boolean;
|
|
41
31
|
/**
|
|
42
|
-
* Whether the database supplies this field's value, so no insert or update may write it
|
|
43
|
-
*
|
|
44
|
-
* The other question, and the one that makes `stored` more than a rename: a stored computed column
|
|
45
|
-
* *is* a real column, so it is read like one - but writing to it is an error on every engine.
|
|
32
|
+
* Whether the database supplies this field's value, so no insert or update may write it: a stored
|
|
33
|
+
* computed column *is* a real column, read like one, but writing to it is an error on every engine.
|
|
46
34
|
*/
|
|
47
35
|
export declare function isDatabaseWritten(field: FieldOptions): boolean;
|
|
48
36
|
/**
|
package/dist/util/field.util.js
CHANGED
|
@@ -46,33 +46,20 @@ for (const family of getKeys(COLUMN_TYPES_BY_FAMILY)) {
|
|
|
46
46
|
export function columnFamily(type) {
|
|
47
47
|
return FAMILY_OF.get(typeof type === 'string' ? type.toLowerCase() : type);
|
|
48
48
|
}
|
|
49
|
-
/**
|
|
50
|
-
* The expression the database computes for this field, whichever key declared it.
|
|
51
|
-
*
|
|
52
|
-
* `virtual` is `computed` under its old name and is read here so both spell one behaviour. Giving
|
|
53
|
-
* both is refused at registration rather than resolved, since only the author knows which was meant.
|
|
54
|
-
*/
|
|
55
|
-
export function computedExpression(field) {
|
|
56
|
-
return field.computed ?? field.virtual;
|
|
57
|
-
}
|
|
58
49
|
/**
|
|
59
50
|
* Whether the field's expression is spliced into each statement that reads it, rather than stored.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* the projection, the `$where` operand, the `ORDER BY` operand - because an inlined field has no
|
|
63
|
-
* column to name, while a stored one is read exactly like any other.
|
|
51
|
+
* Every read site asks this - the DDL skip, the projection, the `$where` and `ORDER BY` operands -
|
|
52
|
+
* because an inlined field has no column to name, while a stored one is read like any other.
|
|
64
53
|
*/
|
|
65
54
|
export function isInlinedExpression(field) {
|
|
66
|
-
return
|
|
55
|
+
return field.computed !== undefined && field.stored !== true;
|
|
67
56
|
}
|
|
68
57
|
/**
|
|
69
|
-
* Whether the database supplies this field's value, so no insert or update may write it
|
|
70
|
-
*
|
|
71
|
-
* The other question, and the one that makes `stored` more than a rename: a stored computed column
|
|
72
|
-
* *is* a real column, so it is read like one - but writing to it is an error on every engine.
|
|
58
|
+
* Whether the database supplies this field's value, so no insert or update may write it: a stored
|
|
59
|
+
* computed column *is* a real column, read like one, but writing to it is an error on every engine.
|
|
73
60
|
*/
|
|
74
61
|
export function isDatabaseWritten(field) {
|
|
75
|
-
return
|
|
62
|
+
return field.computed !== undefined;
|
|
76
63
|
}
|
|
77
64
|
/**
|
|
78
65
|
* Whether the field is the entity's *whole* primary key - the only kind a serial can stand in for,
|
|
@@ -14,7 +14,6 @@ declare const FIELD_OPTION_FAMILY: {
|
|
|
14
14
|
readonly references: '*';
|
|
15
15
|
readonly onDelete: '*';
|
|
16
16
|
readonly enum: '*';
|
|
17
|
-
readonly virtual: '*';
|
|
18
17
|
readonly computed: '*';
|
|
19
18
|
readonly stored: '*';
|
|
20
19
|
readonly updatable: '*';
|
|
@@ -39,7 +38,7 @@ declare const FIELD_OPTION_FAMILY: {
|
|
|
39
38
|
* rather than on each option that dies, because it is one fact rather than nineteen - and because an
|
|
40
39
|
* option added without a thought then lands on the safe side of it.
|
|
41
40
|
*/
|
|
42
|
-
declare const INLINE_READS: readonly ["type", "
|
|
41
|
+
declare const INLINE_READS: readonly ["type", "computed", "stored", "enum", "eager", "distance"];
|
|
43
42
|
type InlineRead = (typeof INLINE_READS)[number];
|
|
44
43
|
/**
|
|
45
44
|
* What a column the *database* writes cannot use. A stored computed column is a real column - it has
|
|
@@ -66,8 +65,6 @@ type FamilyOfType<T> = T extends NumericColumnType | NumberConstructor | BigIntC
|
|
|
66
65
|
type DeadOptions<O> = (O extends {
|
|
67
66
|
readonly stored: true;
|
|
68
67
|
} ? GeneratedWrite : O extends {
|
|
69
|
-
readonly virtual: QueryRaw;
|
|
70
|
-
} | {
|
|
71
68
|
readonly computed: QueryRaw;
|
|
72
69
|
} ? Exclude<keyof FieldOptions, InlineRead> : never) | (O extends {
|
|
73
70
|
readonly isId: true;
|
|
@@ -14,7 +14,6 @@ const FIELD_OPTION_FAMILY = {
|
|
|
14
14
|
references: '*',
|
|
15
15
|
onDelete: '*',
|
|
16
16
|
enum: '*',
|
|
17
|
-
virtual: '*',
|
|
18
17
|
computed: '*',
|
|
19
18
|
stored: '*',
|
|
20
19
|
updatable: '*',
|
|
@@ -41,7 +40,6 @@ const FIELD_OPTION_FAMILY = {
|
|
|
41
40
|
*/
|
|
42
41
|
const INLINE_READS = [
|
|
43
42
|
'type',
|
|
44
|
-
'virtual',
|
|
45
43
|
'computed',
|
|
46
44
|
'stored',
|
|
47
45
|
'enum',
|
package/dist/util/logger.d.ts
CHANGED
|
@@ -12,9 +12,6 @@ export declare class DefaultLogger implements Logger {
|
|
|
12
12
|
logMigration(message: string): void;
|
|
13
13
|
logSkippedMigration(message: string): void;
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
16
|
-
* A wrapper class that implements the Logger interface and handles different logging options.
|
|
17
|
-
*/
|
|
18
15
|
/**
|
|
19
16
|
* Secondary {@link LoggerWrapper} settings, alongside the primary `options: LoggingOptions`
|
|
20
17
|
* constructor argument.
|
|
@@ -28,6 +25,9 @@ export interface LoggerWrapperConfig {
|
|
|
28
25
|
/** Threshold in milliseconds - queries exceeding this are logged as slow. */
|
|
29
26
|
slowQuery?: number;
|
|
30
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* A wrapper class that implements the Logger interface and handles different logging options.
|
|
30
|
+
*/
|
|
31
31
|
export declare class LoggerWrapper implements Logger {
|
|
32
32
|
private readonly levels;
|
|
33
33
|
private readonly logger?;
|
|
@@ -54,12 +54,11 @@ export interface ErrorEmittingPool {
|
|
|
54
54
|
on(event: 'error', listener: (err: Error) => void): unknown;
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
|
-
* Attaches an error listener to a connection pool so a dropped connection is
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* swallowed pool error is exactly the failure mode this guards against.
|
|
57
|
+
* Attaches an error listener to a connection pool so a dropped connection is logged instead of left
|
|
58
|
+
* unhandled - which crashes the process for drivers that don't guard against it themselves
|
|
59
|
+
* (node-postgres, `mssql`), or is silently swallowed by those that install a no-op of their own
|
|
60
|
+
* (`mariadb`). Reported through the pool's own logger when it has one, and through the default one
|
|
61
|
+
* otherwise: never dropped, whatever levels were configured, since a swallowed pool error is exactly
|
|
62
|
+
* the failure this guards against.
|
|
64
63
|
*/
|
|
65
|
-
export declare function attachPoolErrorHandler(pool: ErrorEmittingPool, message: string): void;
|
|
64
|
+
export declare function attachPoolErrorHandler(pool: ErrorEmittingPool, message: string, logging?: LoggingOptions): void;
|
package/dist/util/logger.js
CHANGED
|
@@ -7,18 +7,22 @@ const DEFAULT_LOG_LEVELS = [
|
|
|
7
7
|
'migration',
|
|
8
8
|
'skippedMigration',
|
|
9
9
|
];
|
|
10
|
+
/** Bound values as JSON, a `bigint` by its digits: `JSON.stringify` refuses one outright. */
|
|
11
|
+
function renderValues(values) {
|
|
12
|
+
return JSON.stringify(values, (_key, value) => (typeof value === 'bigint' ? value.toString() : value));
|
|
13
|
+
}
|
|
10
14
|
/**
|
|
11
15
|
* Default implementation of the Logger interface using console methods.
|
|
12
16
|
*/
|
|
13
17
|
export class DefaultLogger {
|
|
14
18
|
logQuery(query, values, duration) {
|
|
15
19
|
const time = duration !== undefined ? ` [${duration}ms]` : '';
|
|
16
|
-
const params = values?.length ? ` -- ${
|
|
20
|
+
const params = values?.length ? ` -- ${renderValues(values)}` : '';
|
|
17
21
|
console.log(`\x1b[36mquery:\x1b[0m ${query}${params}\x1b[32m${time}\x1b[0m`);
|
|
18
22
|
}
|
|
19
23
|
logSlowQuery(query, values, duration) {
|
|
20
24
|
const time = duration !== undefined ? ` [${duration}ms]` : '';
|
|
21
|
-
const params = values?.length ? ` -- ${
|
|
25
|
+
const params = values?.length ? ` -- ${renderValues(values)}` : '';
|
|
22
26
|
console.warn(`\x1b[33mslow query:\x1b[0m ${query}${params}\x1b[31m${time}\x1b[0m`);
|
|
23
27
|
}
|
|
24
28
|
logWarn(message) {
|
|
@@ -40,6 +44,9 @@ export class DefaultLogger {
|
|
|
40
44
|
console.info(`\x1b[33mskipped migration:\x1b[0m ${message}`);
|
|
41
45
|
}
|
|
42
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* A wrapper class that implements the Logger interface and handles different logging options.
|
|
49
|
+
*/
|
|
43
50
|
export class LoggerWrapper {
|
|
44
51
|
levels;
|
|
45
52
|
logger;
|
|
@@ -130,17 +137,20 @@ export class LoggerWrapper {
|
|
|
130
137
|
}
|
|
131
138
|
}
|
|
132
139
|
/**
|
|
133
|
-
* Attaches an error listener to a connection pool so a dropped connection is
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* swallowed pool error is exactly the failure mode this guards against.
|
|
140
|
+
* Attaches an error listener to a connection pool so a dropped connection is logged instead of left
|
|
141
|
+
* unhandled - which crashes the process for drivers that don't guard against it themselves
|
|
142
|
+
* (node-postgres, `mssql`), or is silently swallowed by those that install a no-op of their own
|
|
143
|
+
* (`mariadb`). Reported through the pool's own logger when it has one, and through the default one
|
|
144
|
+
* otherwise: never dropped, whatever levels were configured, since a swallowed pool error is exactly
|
|
145
|
+
* the failure this guards against.
|
|
140
146
|
*/
|
|
141
|
-
export function attachPoolErrorHandler(pool, message) {
|
|
142
|
-
const logger = new LoggerWrapper(true);
|
|
147
|
+
export function attachPoolErrorHandler(pool, message, logging) {
|
|
148
|
+
const logger = new LoggerWrapper(isOwnLogger(logging) ? logging : true);
|
|
143
149
|
pool.on('error', (err) => {
|
|
144
150
|
logger.logError(message, err);
|
|
145
151
|
});
|
|
146
152
|
}
|
|
153
|
+
/** A logger the consumer wrote, as opposed to a switch or a level list for the default one. */
|
|
154
|
+
function isOwnLogger(logging) {
|
|
155
|
+
return typeof logging === 'function' || (typeof logging === 'object' && !Array.isArray(logging));
|
|
156
|
+
}
|
package/dist/util/raw.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { QueryRaw, type QueryRawFn
|
|
1
|
+
import { QueryRaw, type QueryRawFn } from '../type/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Create a raw SQL expression.
|
|
4
4
|
*
|
|
@@ -19,18 +19,11 @@ import { QueryRaw, type QueryRawFn, type Scalar } from '../type/index.js';
|
|
|
19
19
|
* The callback form remains for SQL a template cannot express, such as a sub-query generated through
|
|
20
20
|
* `dialect.find(...)`. See {@link col} for a context-aware column reference.
|
|
21
21
|
*
|
|
22
|
-
* **⚠️ Security:** the tag is safe because it binds;
|
|
23
|
-
*
|
|
24
|
-
* Inside a callback, bind with `ctx.addValue()`.
|
|
22
|
+
* **⚠️ Security:** the tag is safe because it binds; a callback is not, since it emits whatever it
|
|
23
|
+
* writes, so never build one from user input. Inside a callback, bind with `ctx.addValue()`.
|
|
25
24
|
*/
|
|
26
25
|
export declare function raw(strings: TemplateStringsArray, ...values: readonly unknown[]): QueryRaw;
|
|
27
26
|
export declare function raw(value: QueryRawFn, alias?: string): QueryRaw;
|
|
28
|
-
/**
|
|
29
|
-
* @deprecated Emits its argument verbatim, so it cannot bind a value. Use the tagged template:
|
|
30
|
-
* `raw('"a" > 1')` becomes `` raw`"a" > 1` ``, and `raw('LOG10(x)', 'score')` becomes
|
|
31
|
-
* `` raw`LOG10(x)`.as('score') ``. `npx uql-codemod` rewrites both.
|
|
32
|
-
*/
|
|
33
|
-
export declare function raw(value: Scalar, alias?: string): QueryRaw;
|
|
34
27
|
/**
|
|
35
28
|
* A column of the entity being queried, alias-qualified and escaped for the dialect. This is what a
|
|
36
29
|
* template cannot know on its own: the alias is decided while the statement is built, not where the
|
package/dist/util/raw.js
CHANGED
|
@@ -7,11 +7,11 @@ export function raw(value, ...rest) {
|
|
|
7
7
|
if (!rest.length) {
|
|
8
8
|
// Nothing to bind, so this is the string form: keep it one, for the DDL paths that need to read
|
|
9
9
|
// the expression back as text (an index expression cannot carry a parameter).
|
|
10
|
-
return new QueryRaw(value[0]
|
|
10
|
+
return new QueryRaw(value[0]);
|
|
11
11
|
}
|
|
12
12
|
return new QueryRaw((opts) => {
|
|
13
13
|
const { ctx } = opts;
|
|
14
|
-
ctx.append(value[0]
|
|
14
|
+
ctx.append(value[0]);
|
|
15
15
|
rest.forEach((interpolated, i) => {
|
|
16
16
|
if (interpolated instanceof QueryRaw) {
|
|
17
17
|
interpolated.render(opts);
|
|
@@ -19,7 +19,7 @@ export function raw(value, ...rest) {
|
|
|
19
19
|
else {
|
|
20
20
|
ctx.addValue(interpolated);
|
|
21
21
|
}
|
|
22
|
-
ctx.append(value[i + 1]
|
|
22
|
+
ctx.append(value[i + 1]);
|
|
23
23
|
});
|
|
24
24
|
});
|
|
25
25
|
}
|
package/dist/util/sql.util.js
CHANGED
|
@@ -200,8 +200,8 @@ export function buildUpdateResult(payload) {
|
|
|
200
200
|
// UPDATE` convention makes `changes` a per-row weighted sum (1=insert, 2=update, 0=no-op), so a
|
|
201
201
|
// batch mixing an insert and an update would fabricate ids for rows that were never touched. This
|
|
202
202
|
// function has no way to tell the two call sites apart (`internalRun` reports the same header
|
|
203
|
-
// shape either way), so `AbstractSqlQuerier
|
|
204
|
-
//
|
|
203
|
+
// shape either way), so `AbstractSqlQuerier`'s `runUpsert` discards them for a multi-row `firstId`
|
|
204
|
+
// upsert and reads the ids back by the conflict columns instead.
|
|
205
205
|
let ids = [];
|
|
206
206
|
if (rows?.length) {
|
|
207
207
|
ids = rows.map((r) => r['id']);
|
package/dist/util/sqlLiteral.js
CHANGED
|
@@ -33,9 +33,6 @@ const MYSQL_ESCAPES = {
|
|
|
33
33
|
};
|
|
34
34
|
const mysqlStringLiteral = (val) => `'${val.replace(MYSQL_SPECIALS, (char) => MYSQL_ESCAPES[char])}'`;
|
|
35
35
|
const pad = (value, len) => String(value).padStart(len, '0');
|
|
36
|
-
function isByteSource(val) {
|
|
37
|
-
return (typeof Buffer !== 'undefined' && Buffer.isBuffer(val)) || val instanceof Uint8Array;
|
|
38
|
-
}
|
|
39
36
|
const HEX_BYTES = Array.from({ length: 256 }, (_, byte) => byte.toString(16).padStart(2, '0'));
|
|
40
37
|
/** Native hex encoder where available (~130x faster on 4 KB); lookup table for browsers. */
|
|
41
38
|
function bytesToHexLiteral(bytes) {
|
|
@@ -72,7 +69,8 @@ function createEscaper(escapeString) {
|
|
|
72
69
|
if (Array.isArray(value)) {
|
|
73
70
|
return sqlList(value);
|
|
74
71
|
}
|
|
75
|
-
|
|
72
|
+
// A Node `Buffer` is a `Uint8Array` too.
|
|
73
|
+
if (value instanceof Uint8Array) {
|
|
76
74
|
return bytesToHexLiteral(value);
|
|
77
75
|
}
|
|
78
76
|
if ('toSqlString' in value && typeof value.toSqlString === 'function') {
|
|
@@ -95,11 +93,8 @@ function createEscaper(escapeString) {
|
|
|
95
93
|
return escapeString(value);
|
|
96
94
|
case 'object':
|
|
97
95
|
return escapeObject(value);
|
|
98
|
-
case 'symbol':
|
|
99
|
-
case 'function':
|
|
100
|
-
throw new TypeError('escapeSqlLiteral: symbol and function values are not supported; use bound parameters.');
|
|
101
96
|
default:
|
|
102
|
-
//
|
|
97
|
+
// A symbol or a function, or a future JS type: none of them may silently become SQL.
|
|
103
98
|
throw new TypeError(`escapeSqlLiteral: unsupported value type '${typeof value}'; use bound parameters.`);
|
|
104
99
|
}
|
|
105
100
|
};
|