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.
Files changed (158) hide show
  1. package/README.md +2 -2
  2. package/dist/browser/uql-browser.min.js.map +2 -2
  3. package/dist/bunSql/bunSql.util.d.ts +3 -14
  4. package/dist/bunSql/bunSql.util.js +33 -56
  5. package/dist/bunSql/bunSqlQuerier.d.ts +3 -6
  6. package/dist/bunSql/bunSqlQuerier.js +7 -13
  7. package/dist/bunSql/bunSqlQuerierPool.d.ts +10 -5
  8. package/dist/bunSql/bunSqlQuerierPool.js +25 -10
  9. package/dist/cockroachdb/cockroachDialect.d.ts +2 -5
  10. package/dist/cockroachdb/cockroachDialect.js +2 -5
  11. package/dist/cockroachdb/crdbQuerierPool.d.ts +1 -3
  12. package/dist/cockroachdb/crdbQuerierPool.js +0 -4
  13. package/dist/cockroachdb/index.d.ts +0 -1
  14. package/dist/cockroachdb/index.js +0 -1
  15. package/dist/d1/d1SqliteDialect.d.ts +5 -0
  16. package/dist/d1/d1SqliteDialect.js +7 -0
  17. package/dist/dialect/abstractSqlDialect.d.ts +15 -9
  18. package/dist/dialect/abstractSqlDialect.js +47 -54
  19. package/dist/dialect/hydrateColumn.js +2 -2
  20. package/dist/dialect/mergeSqlDialect.d.ts +2 -2
  21. package/dist/dialect/mergeSqlDialect.js +0 -4
  22. package/dist/dialect/mysqlLikeSqlDialect.d.ts +0 -3
  23. package/dist/dialect/mysqlLikeSqlDialect.js +0 -3
  24. package/dist/dialect/pgLikeSqlDialect.d.ts +5 -0
  25. package/dist/dialect/pgLikeSqlDialect.js +12 -2
  26. package/dist/entity/decorator/members.d.ts +3 -10
  27. package/dist/entity/index.d.ts +1 -1
  28. package/dist/entity/index.js +1 -1
  29. package/dist/entity/metadata/definition.d.ts +3 -1
  30. package/dist/entity/metadata/definition.js +8 -4
  31. package/dist/libsql/index.d.ts +0 -1
  32. package/dist/libsql/index.js +0 -1
  33. package/dist/libsql/libsqlQuerierPool.d.ts +3 -5
  34. package/dist/libsql/libsqlQuerierPool.js +2 -5
  35. package/dist/maria/mariadbQuerier.d.ts +0 -3
  36. package/dist/maria/mariadbQuerier.js +6 -7
  37. package/dist/maria/mariadbQuerierPool.js +4 -7
  38. package/dist/migrate/builder/migrationBuilder.js +0 -4
  39. package/dist/migrate/ddl/index.d.ts +3 -3
  40. package/dist/migrate/ddl/index.js +3 -3
  41. package/dist/migrate/migrator.d.ts +3 -7
  42. package/dist/migrate/migrator.js +3 -7
  43. package/dist/migrate/schemaGenerator.d.ts +0 -13
  44. package/dist/migrate/schemaGenerator.js +0 -13
  45. package/dist/migrate/storage/databaseStorage.d.ts +2 -2
  46. package/dist/migrate/storage/databaseStorage.js +2 -2
  47. package/dist/mongo/index.d.ts +0 -1
  48. package/dist/mongo/index.js +0 -1
  49. package/dist/mongo/mongoDialect.d.ts +0 -1
  50. package/dist/mongo/mongoDialect.js +3 -14
  51. package/dist/mongo/mongodbQuerier.d.ts +3 -5
  52. package/dist/mongo/mongodbQuerier.js +23 -23
  53. package/dist/mongo/mongodbQuerierPool.d.ts +2 -2
  54. package/dist/mongo/mongodbQuerierPool.js +2 -2
  55. package/dist/mssql/mssqlDialect.d.ts +5 -5
  56. package/dist/mssql/mssqlDialect.js +11 -8
  57. package/dist/mssql/mssqlQuerier.d.ts +13 -6
  58. package/dist/mssql/mssqlQuerier.js +30 -75
  59. package/dist/mssql/mssqlQuerierPool.js +2 -0
  60. package/dist/mssql/mssqlWireTypes.d.ts +3 -4
  61. package/dist/mssql/mssqlWireTypes.js +5 -8
  62. package/dist/mysql/index.d.ts +0 -1
  63. package/dist/mysql/index.js +0 -1
  64. package/dist/mysql/mysql2Querier.d.ts +1 -4
  65. package/dist/mysql/mysql2Querier.js +0 -3
  66. package/dist/mysql/mysql2QuerierPool.d.ts +2 -2
  67. package/dist/mysql/mysql2QuerierPool.js +5 -3
  68. package/dist/neon/index.d.ts +0 -2
  69. package/dist/neon/index.js +0 -2
  70. package/dist/neon/neonQuerierPool.d.ts +2 -4
  71. package/dist/neon/neonQuerierPool.js +2 -6
  72. package/dist/pglite/index.d.ts +0 -1
  73. package/dist/pglite/index.js +0 -1
  74. package/dist/pglite/pgliteQuerier.d.ts +3 -3
  75. package/dist/pglite/pgliteQuerier.js +1 -1
  76. package/dist/pglite/pgliteQuerierPool.d.ts +7 -2
  77. package/dist/pglite/pgliteQuerierPool.js +16 -6
  78. package/dist/postgres/abstractPgQuerierPool.d.ts +8 -12
  79. package/dist/postgres/abstractPgQuerierPool.js +8 -6
  80. package/dist/postgres/index.d.ts +0 -1
  81. package/dist/postgres/index.js +0 -1
  82. package/dist/postgres/pgNumericTypes.d.ts +5 -5
  83. package/dist/postgres/pgNumericTypes.js +11 -7
  84. package/dist/postgres/pgQuerier.d.ts +22 -4
  85. package/dist/postgres/pgQuerier.js +29 -2
  86. package/dist/postgres/pgQuerierPool.d.ts +2 -4
  87. package/dist/postgres/pgQuerierPool.js +2 -6
  88. package/dist/postgres/postgresDialect.d.ts +5 -5
  89. package/dist/postgres/postgresDialect.js +5 -5
  90. package/dist/postgres/postgresWireDriverCapabilities.d.ts +2 -2
  91. package/dist/postgres/postgresWireDriverCapabilities.js +2 -2
  92. package/dist/querier/abstractPoolQuerier.d.ts +1 -1
  93. package/dist/querier/abstractPoolQuerier.js +1 -1
  94. package/dist/querier/abstractQuerier.d.ts +17 -22
  95. package/dist/querier/abstractQuerier.js +80 -57
  96. package/dist/querier/abstractSqlQuerier.d.ts +20 -13
  97. package/dist/querier/abstractSqlQuerier.js +96 -100
  98. package/dist/schema/schemaASTBuilder.js +7 -7
  99. package/dist/sqlite/hranaQuerier.d.ts +6 -8
  100. package/dist/sqlite/hranaQuerier.js +13 -30
  101. package/dist/sqlite/hranaQuerierPool.d.ts +3 -4
  102. package/dist/sqlite/hranaQuerierPool.js +2 -1
  103. package/dist/sqlite/localSqliteQuerierPool.d.ts +3 -3
  104. package/dist/sqlite/localSqliteQuerierPool.js +4 -2
  105. package/dist/sqlite/nodeSqliteAdapter.d.ts +0 -1
  106. package/dist/sqlite/nodeSqliteQuerierPool.js +0 -2
  107. package/dist/sqlite/sqlitePragmas.d.ts +12 -0
  108. package/dist/sqlite/sqlitePragmas.js +15 -0
  109. package/dist/sqlite/sqliteQuerierPool.d.ts +0 -5
  110. package/dist/sqlite/sqliteQuerierPool.js +2 -13
  111. package/dist/turso/index.d.ts +0 -1
  112. package/dist/turso/index.js +0 -1
  113. package/dist/turso/tursoLocalQuerier.d.ts +0 -1
  114. package/dist/turso/tursoLocalQuerierPool.js +2 -2
  115. package/dist/turso/tursoQuerierPool.d.ts +1 -3
  116. package/dist/turso/tursoQuerierPool.js +0 -4
  117. package/dist/type/dialect.d.ts +1 -1
  118. package/dist/type/entity.d.ts +6 -11
  119. package/dist/type/migration.d.ts +0 -3
  120. package/dist/type/query.d.ts +12 -12
  121. package/dist/type/query.js +0 -6
  122. package/dist/type/universalQuerier.d.ts +3 -3
  123. package/dist/util/dialect.util.d.ts +4 -3
  124. package/dist/util/dialect.util.js +2 -1
  125. package/dist/util/field.util.d.ts +4 -16
  126. package/dist/util/field.util.js +6 -19
  127. package/dist/util/fieldOption.util.d.ts +1 -4
  128. package/dist/util/fieldOption.util.js +0 -2
  129. package/dist/util/logger.d.ts +10 -11
  130. package/dist/util/logger.js +21 -11
  131. package/dist/util/raw.d.ts +3 -10
  132. package/dist/util/raw.js +3 -3
  133. package/dist/util/sql.util.js +2 -2
  134. package/dist/util/sqlLiteral.js +3 -8
  135. package/dist/util/string.util.js +2 -6
  136. package/dist/util/wideNumber.d.ts +14 -0
  137. package/dist/util/wideNumber.js +24 -0
  138. package/package.json +1 -1
  139. package/dist/cockroachdb/crdbQuerier.d.ts +0 -8
  140. package/dist/cockroachdb/crdbQuerier.js +0 -6
  141. package/dist/libsql/libsqlQuerier.d.ts +0 -10
  142. package/dist/libsql/libsqlQuerier.js +0 -10
  143. package/dist/mongo/mongodbNativeDialect.d.ts +0 -9
  144. package/dist/mongo/mongodbNativeDialect.js +0 -9
  145. package/dist/mysql/mysql2Dialect.d.ts +0 -9
  146. package/dist/mysql/mysql2Dialect.js +0 -9
  147. package/dist/neon/neonDialect.d.ts +0 -10
  148. package/dist/neon/neonDialect.js +0 -10
  149. package/dist/neon/neonQuerier.d.ts +0 -5
  150. package/dist/neon/neonQuerier.js +0 -3
  151. package/dist/pglite/pgliteDialect.d.ts +0 -14
  152. package/dist/pglite/pgliteDialect.js +0 -14
  153. package/dist/postgres/abstractPgQuerier.d.ts +0 -24
  154. package/dist/postgres/abstractPgQuerier.js +0 -32
  155. package/dist/postgres/pgDialect.d.ts +0 -10
  156. package/dist/postgres/pgDialect.js +0 -10
  157. package/dist/turso/tursoQuerier.d.ts +0 -10
  158. 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
- const bunDb = new BunDatabase(this.filename, opts);
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
- const db = new BetterSqlite3(this.filename, opts);
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
  }
@@ -1,3 +1,2 @@
1
1
  export * from './tursoDialect.js';
2
- export * from './tursoQuerier.js';
3
2
  export * from './tursoQuerierPool.js';
@@ -1,3 +1,2 @@
1
1
  export * from './tursoDialect.js';
2
- export * from './tursoQuerier.js';
3
2
  export * from './tursoQuerierPool.js';
@@ -7,7 +7,6 @@ import type { ExtraOptions } from '../type/index.js';
7
7
  */
8
8
  export type TursoDatabase = {
9
9
  prepare(sql: string): Promise<SqlitePreparedStatement>;
10
- pragma(source: string, options?: unknown): Promise<unknown[]>;
11
10
  close(): Promise<void>;
12
11
  };
13
12
  /**
@@ -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.pragma('journal_mode = WAL');
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<TursoQuerier, TursoDialect> {
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
  }
@@ -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
- * `PgDialect` keeps this `true` for node-postgres; Bun SQL PostgreSQL uses `false` and
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;
@@ -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
  /**
@@ -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
  /**
@@ -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
  };
@@ -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 from the payload instead.
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 operation metadata; see {@link QueryUpdateResult}
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 operation metadata; see {@link QueryUpdateResult}
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
- export declare function fillOnFields<E>(meta: EntityMeta<E>, payload: EntityData<E> | EntityData<E>[], callbackKey: CallbackKey): EntityData<E>[];
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 | undefined, emitted: ReadonlySet<string>, clause: string): void;
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
- * One of the two questions `virtual` used to answer alone. Every read site asks this - the DDL skip,
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
  /**
@@ -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
- * One of the two questions `virtual` used to answer alone. Every read site asks this - the DDL skip,
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 computedExpression(field) !== undefined && field.stored !== true;
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 computedExpression(field) !== undefined;
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", "virtual", "computed", "stored", "enum", "eager", "distance"];
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',
@@ -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
- * logged instead of left unhandled - which crashes the process for drivers
59
- * that don't guard against it themselves (node-postgres), or silently
60
- * swallowed with zero visibility for drivers that already install their own
61
- * no-op safety net (`mariadb`'s `createPool`). Always logs via a dedicated
62
- * logger (ignoring the consumer's configured log level) since a silently
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;
@@ -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 ? ` -- ${JSON.stringify(values)}` : '';
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 ? ` -- ${JSON.stringify(values)}` : '';
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
- * logged instead of left unhandled - which crashes the process for drivers
135
- * that don't guard against it themselves (node-postgres), or silently
136
- * swallowed with zero visibility for drivers that already install their own
137
- * no-op safety net (`mariadb`'s `createPool`). Always logs via a dedicated
138
- * logger (ignoring the consumer's configured log level) since a silently
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
+ }
@@ -1,4 +1,4 @@
1
- import { QueryRaw, type QueryRawFn, type Scalar } from '../type/index.js';
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; the other two forms are not. `raw('SQL')` emits
23
- * its argument verbatim and a callback emits whatever it writes, so build neither from user input.
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
  }
@@ -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.upsertMany` strips `ids`/`firstId`/`created` back down
204
- // to just `changes` for a multi-row `firstId`-dialect upsert after calling this.
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']);
@@ -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
- if (isByteSource(value)) {
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
- // Unreachable today; throwing keeps a future JS type from silently becoming SQL.
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
  };