uql-orm 0.54.0 → 0.56.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 (162) hide show
  1. package/README.md +2 -2
  2. package/dist/browser/uql-browser.min.js +2 -2
  3. package/dist/browser/uql-browser.min.js.map +4 -4
  4. package/dist/bunSql/bunSql.util.d.ts +3 -14
  5. package/dist/bunSql/bunSql.util.js +33 -56
  6. package/dist/bunSql/bunSqlQuerier.d.ts +3 -6
  7. package/dist/bunSql/bunSqlQuerier.js +7 -13
  8. package/dist/bunSql/bunSqlQuerierPool.d.ts +10 -5
  9. package/dist/bunSql/bunSqlQuerierPool.js +25 -10
  10. package/dist/cockroachdb/crdbQuerierPool.d.ts +1 -3
  11. package/dist/cockroachdb/crdbQuerierPool.js +0 -4
  12. package/dist/cockroachdb/index.d.ts +0 -1
  13. package/dist/cockroachdb/index.js +0 -1
  14. package/dist/d1/d1SqliteDialect.d.ts +5 -0
  15. package/dist/d1/d1SqliteDialect.js +7 -0
  16. package/dist/dialect/abstractSqlDialect.d.ts +9 -9
  17. package/dist/dialect/abstractSqlDialect.js +38 -51
  18. package/dist/dialect/hydrateColumn.js +2 -2
  19. package/dist/dialect/mergeSqlDialect.d.ts +2 -2
  20. package/dist/dialect/mergeSqlDialect.js +0 -4
  21. package/dist/dialect/mysqlLikeSqlDialect.js +2 -3
  22. package/dist/dialect/pgLikeSqlDialect.d.ts +5 -0
  23. package/dist/dialect/pgLikeSqlDialect.js +14 -4
  24. package/dist/dialect/queryJoins.js +2 -4
  25. package/dist/entity/index.d.ts +1 -1
  26. package/dist/entity/index.js +1 -1
  27. package/dist/entity/metadata/definition.d.ts +5 -1
  28. package/dist/entity/metadata/definition.js +32 -26
  29. package/dist/libsql/index.d.ts +0 -1
  30. package/dist/libsql/index.js +0 -1
  31. package/dist/libsql/libsqlQuerierPool.d.ts +3 -5
  32. package/dist/libsql/libsqlQuerierPool.js +2 -5
  33. package/dist/maria/mariadbQuerier.d.ts +0 -3
  34. package/dist/maria/mariadbQuerier.js +6 -7
  35. package/dist/maria/mariadbQuerierPool.js +4 -7
  36. package/dist/migrate/builder/splitSqlStatements.js +2 -2
  37. package/dist/migrate/cli.js +2 -9
  38. package/dist/migrate/codegen/fieldOptionsSource.js +1 -1
  39. package/dist/migrate/ddl/index.d.ts +3 -3
  40. package/dist/migrate/ddl/index.js +3 -3
  41. package/dist/migrate/ddl/pgIndexDdl.d.ts +5 -0
  42. package/dist/migrate/ddl/pgIndexDdl.js +9 -0
  43. package/dist/migrate/drift/driftDetector.js +21 -8
  44. package/dist/migrate/generator/mongoSchemaGenerator.js +1 -1
  45. package/dist/migrate/introspection/baseSqlIntrospector.d.ts +1 -1
  46. package/dist/migrate/introspection/baseSqlIntrospector.js +65 -76
  47. package/dist/migrate/introspection/mssqlIntrospector.js +2 -1
  48. package/dist/migrate/introspection/mysqlIntrospector.js +5 -8
  49. package/dist/migrate/introspection/sqliteIntrospector.js +2 -5
  50. package/dist/migrate/migrator.d.ts +5 -2
  51. package/dist/migrate/migrator.js +9 -14
  52. package/dist/migrate/schemaGenerator.js +2 -6
  53. package/dist/mongo/index.d.ts +0 -1
  54. package/dist/mongo/index.js +0 -1
  55. package/dist/mongo/mongoDialect.d.ts +1 -2
  56. package/dist/mongo/mongoDialect.js +7 -21
  57. package/dist/mongo/mongodbQuerier.js +12 -11
  58. package/dist/mongo/mongodbQuerierPool.d.ts +2 -2
  59. package/dist/mongo/mongodbQuerierPool.js +2 -2
  60. package/dist/mssql/mssqlDialect.d.ts +3 -5
  61. package/dist/mssql/mssqlDialect.js +9 -8
  62. package/dist/mssql/mssqlQuerier.d.ts +13 -6
  63. package/dist/mssql/mssqlQuerier.js +30 -75
  64. package/dist/mssql/mssqlQuerierPool.js +2 -0
  65. package/dist/mssql/mssqlWireTypes.d.ts +3 -4
  66. package/dist/mssql/mssqlWireTypes.js +5 -8
  67. package/dist/mysql/index.d.ts +0 -1
  68. package/dist/mysql/index.js +0 -1
  69. package/dist/mysql/mysql2Querier.d.ts +1 -4
  70. package/dist/mysql/mysql2Querier.js +0 -3
  71. package/dist/mysql/mysql2QuerierPool.d.ts +2 -2
  72. package/dist/mysql/mysql2QuerierPool.js +5 -3
  73. package/dist/neon/index.d.ts +0 -2
  74. package/dist/neon/index.js +0 -2
  75. package/dist/neon/neonQuerierPool.d.ts +2 -4
  76. package/dist/neon/neonQuerierPool.js +2 -6
  77. package/dist/pglite/index.d.ts +0 -1
  78. package/dist/pglite/index.js +0 -1
  79. package/dist/pglite/pgliteQuerier.d.ts +3 -3
  80. package/dist/pglite/pgliteQuerier.js +1 -1
  81. package/dist/pglite/pgliteQuerierPool.d.ts +7 -2
  82. package/dist/pglite/pgliteQuerierPool.js +16 -6
  83. package/dist/postgres/abstractPgQuerierPool.d.ts +8 -12
  84. package/dist/postgres/abstractPgQuerierPool.js +8 -6
  85. package/dist/postgres/index.d.ts +0 -1
  86. package/dist/postgres/index.js +0 -1
  87. package/dist/postgres/pgNumericTypes.d.ts +5 -5
  88. package/dist/postgres/pgNumericTypes.js +11 -7
  89. package/dist/postgres/pgQuerier.d.ts +22 -4
  90. package/dist/postgres/pgQuerier.js +29 -2
  91. package/dist/postgres/pgQuerierPool.d.ts +2 -4
  92. package/dist/postgres/pgQuerierPool.js +2 -6
  93. package/dist/postgres/postgresDialect.d.ts +5 -5
  94. package/dist/postgres/postgresDialect.js +5 -5
  95. package/dist/postgres/postgresWireDriverCapabilities.d.ts +2 -2
  96. package/dist/postgres/postgresWireDriverCapabilities.js +2 -2
  97. package/dist/querier/abstractPoolQuerier.d.ts +1 -1
  98. package/dist/querier/abstractPoolQuerier.js +1 -1
  99. package/dist/querier/abstractQuerier.js +17 -22
  100. package/dist/querier/abstractSqlQuerier.d.ts +21 -12
  101. package/dist/querier/abstractSqlQuerier.js +61 -43
  102. package/dist/schema/canonicalType.js +0 -2
  103. package/dist/schema/dependencyGraph.js +2 -4
  104. package/dist/schema/indexDifferences.js +2 -2
  105. package/dist/schema/schemaASTBuilder.js +3 -10
  106. package/dist/schema/schemaASTDiffer.d.ts +10 -2
  107. package/dist/schema/schemaASTDiffer.js +12 -11
  108. package/dist/schema/types.d.ts +1 -1
  109. package/dist/sqlite/hranaQuerier.d.ts +6 -8
  110. package/dist/sqlite/hranaQuerier.js +13 -30
  111. package/dist/sqlite/hranaQuerierPool.d.ts +3 -4
  112. package/dist/sqlite/hranaQuerierPool.js +2 -1
  113. package/dist/sqlite/localSqliteQuerierPool.d.ts +3 -3
  114. package/dist/sqlite/localSqliteQuerierPool.js +4 -2
  115. package/dist/sqlite/nodeSqliteAdapter.d.ts +0 -1
  116. package/dist/sqlite/nodeSqliteQuerierPool.js +0 -2
  117. package/dist/sqlite/sqliteDialect.js +2 -1
  118. package/dist/sqlite/sqlitePragmas.d.ts +12 -0
  119. package/dist/sqlite/sqlitePragmas.js +15 -0
  120. package/dist/sqlite/sqliteQuerierPool.d.ts +0 -5
  121. package/dist/sqlite/sqliteQuerierPool.js +2 -13
  122. package/dist/turso/index.d.ts +0 -1
  123. package/dist/turso/index.js +0 -1
  124. package/dist/turso/tursoLocalQuerier.d.ts +0 -1
  125. package/dist/turso/tursoLocalQuerierPool.js +2 -2
  126. package/dist/turso/tursoQuerierPool.d.ts +1 -3
  127. package/dist/turso/tursoQuerierPool.js +0 -4
  128. package/dist/type/dialect.d.ts +1 -1
  129. package/dist/util/dialect.util.d.ts +8 -2
  130. package/dist/util/dialect.util.js +20 -1
  131. package/dist/util/logger.d.ts +17 -9
  132. package/dist/util/logger.js +36 -11
  133. package/dist/util/object.util.d.ts +2 -0
  134. package/dist/util/object.util.js +4 -0
  135. package/dist/util/raw.js +3 -3
  136. package/dist/util/relationQuery.util.d.ts +3 -3
  137. package/dist/util/relationQuery.util.js +8 -2
  138. package/dist/util/sqlLiteral.js +3 -8
  139. package/dist/util/string.util.js +2 -6
  140. package/dist/util/wideNumber.d.ts +14 -0
  141. package/dist/util/wideNumber.js +24 -0
  142. package/package.json +1 -1
  143. package/dist/cockroachdb/crdbQuerier.d.ts +0 -8
  144. package/dist/cockroachdb/crdbQuerier.js +0 -6
  145. package/dist/libsql/libsqlQuerier.d.ts +0 -10
  146. package/dist/libsql/libsqlQuerier.js +0 -10
  147. package/dist/mongo/mongodbNativeDialect.d.ts +0 -9
  148. package/dist/mongo/mongodbNativeDialect.js +0 -9
  149. package/dist/mysql/mysql2Dialect.d.ts +0 -9
  150. package/dist/mysql/mysql2Dialect.js +0 -9
  151. package/dist/neon/neonDialect.d.ts +0 -10
  152. package/dist/neon/neonDialect.js +0 -10
  153. package/dist/neon/neonQuerier.d.ts +0 -5
  154. package/dist/neon/neonQuerier.js +0 -3
  155. package/dist/pglite/pgliteDialect.d.ts +0 -14
  156. package/dist/pglite/pgliteDialect.js +0 -14
  157. package/dist/postgres/abstractPgQuerier.d.ts +0 -24
  158. package/dist/postgres/abstractPgQuerier.js +0 -32
  159. package/dist/postgres/pgDialect.d.ts +0 -10
  160. package/dist/postgres/pgDialect.js +0 -10
  161. package/dist/turso/tursoQuerier.d.ts +0 -10
  162. package/dist/turso/tursoQuerier.js +0 -10
@@ -1,6 +1,6 @@
1
+ import type { PostgresDialect } from '../postgres/postgresDialect.js';
1
2
  import { AbstractSqlQuerier } from '../querier/index.js';
2
3
  import type { ExtraOptions } from '../type/index.js';
3
- import type { PgliteDialect } from './pgliteDialect.js';
4
4
  /**
5
5
  * Structural subset of the `@electric-sql/pglite` API actually used here, declared locally so this
6
6
  * package does not couple its published types to a pre-1.0 dependency.
@@ -20,7 +20,7 @@ export type PgliteDatabase = {
20
20
  /**
21
21
  * Querier for PGlite, Postgres compiled to WASM and run in this process.
22
22
  *
23
- * @remarks Extends {@link AbstractSqlQuerier} rather than `AbstractPgQuerier`, whose `internalStream`
23
+ * @remarks Extends {@link AbstractSqlQuerier} rather than `PgQuerier`, whose `internalStream`
24
24
  * hands a `pg-query-stream` object to `query()`, which PGlite's client has no equivalent of - so
25
25
  * streaming pages the rows in SQL instead. `BEGIN`/`COMMIT` are plain statements on the single
26
26
  * connection, leaving transactions to the base class.
@@ -28,7 +28,7 @@ export type PgliteDatabase = {
28
28
  export declare class PgliteQuerier extends AbstractSqlQuerier {
29
29
  readonly db: PgliteDatabase;
30
30
  readonly extra?: ExtraOptions | undefined;
31
- constructor(db: PgliteDatabase, dialect: PgliteDialect, extra?: ExtraOptions | undefined);
31
+ constructor(db: PgliteDatabase, dialect: PostgresDialect, extra?: ExtraOptions | undefined);
32
32
  internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
33
33
  internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
34
34
  /** Postgres compiled to WASM is still Postgres: `DECLARE`/`FETCH` streams what the client cannot. */
@@ -3,7 +3,7 @@ import { AbstractSqlQuerier } from '../querier/index.js';
3
3
  /**
4
4
  * Querier for PGlite, Postgres compiled to WASM and run in this process.
5
5
  *
6
- * @remarks Extends {@link AbstractSqlQuerier} rather than `AbstractPgQuerier`, whose `internalStream`
6
+ * @remarks Extends {@link AbstractSqlQuerier} rather than `PgQuerier`, whose `internalStream`
7
7
  * hands a `pg-query-stream` object to `query()`, which PGlite's client has no equivalent of - so
8
8
  * streaming pages the rows in SQL instead. `BEGIN`/`COMMIT` are plain statements on the single
9
9
  * connection, leaving transactions to the base class.
@@ -1,7 +1,7 @@
1
1
  import type { PGliteOptions } from '@electric-sql/pglite';
2
+ import { PostgresDialect } from '../postgres/postgresDialect.js';
2
3
  import { AbstractSharedHandleQuerierPool } from '../querier/abstractSharedHandleQuerierPool.js';
3
4
  import type { ExtraOptions } from '../type/index.js';
4
- import { PgliteDialect } from './pgliteDialect.js';
5
5
  import { type PgliteDatabase, PgliteQuerier } from './pgliteQuerier.js';
6
6
  /**
7
7
  * The driver's own options, minus the `dataDir` this pool takes as its first argument.
@@ -26,8 +26,13 @@ export type PglitePoolOptions = Omit<PGliteOptions, 'dataDir'>;
26
26
  * The cost is that PGlite cannot see the transaction, so it flushes to the filesystem after each
27
27
  * statement within one: pass `relaxedDurability: true` on a persistent `dataDir` to skip waiting on
28
28
  * those flushes.
29
+ *
30
+ * The dialect is plain `PostgresDialect`, `dialectName` included: PGlite *is* Postgres, so the
31
+ * introspector, schema generator and CLI resolve to Postgres's. Both driver capabilities hold as
32
+ * they are - PGlite serializes every built-in array type itself, and the `$n::jsonb` cast is what
33
+ * makes its `Describe` report JSONB and pick its JSON serializer; a bare `$n` binds `[object Object]`.
29
34
  */
30
- export declare class PgliteQuerierPool extends AbstractSharedHandleQuerierPool<PgliteDatabase, PgliteQuerier, PgliteDialect> {
35
+ export declare class PgliteQuerierPool extends AbstractSharedHandleQuerierPool<PgliteDatabase, PgliteQuerier, PostgresDialect> {
31
36
  readonly dataDir: string;
32
37
  readonly opts?: PglitePoolOptions | undefined;
33
38
  constructor(dataDir?: string, opts?: PglitePoolOptions | undefined, extra?: ExtraOptions);
@@ -1,6 +1,7 @@
1
1
  import { dialectOptionsFrom } from '../dialect/abstractDialect.js';
2
+ import { PostgresDialect } from '../postgres/postgresDialect.js';
2
3
  import { AbstractSharedHandleQuerierPool } from '../querier/abstractSharedHandleQuerierPool.js';
3
- import { PgliteDialect } from './pgliteDialect.js';
4
+ import { decodeWideNumber } from '../util/wideNumber.js';
4
5
  import { PgliteQuerier } from './pgliteQuerier.js';
5
6
  /**
6
7
  * Pool for PGlite, Postgres compiled to WASM and run in this process. No server, no container.
@@ -16,20 +17,29 @@ import { PgliteQuerier } from './pgliteQuerier.js';
16
17
  * The cost is that PGlite cannot see the transaction, so it flushes to the filesystem after each
17
18
  * statement within one: pass `relaxedDurability: true` on a persistent `dataDir` to skip waiting on
18
19
  * those flushes.
20
+ *
21
+ * The dialect is plain `PostgresDialect`, `dialectName` included: PGlite *is* Postgres, so the
22
+ * introspector, schema generator and CLI resolve to Postgres's. Both driver capabilities hold as
23
+ * they are - PGlite serializes every built-in array type itself, and the `$n::jsonb` cast is what
24
+ * makes its `Describe` report JSONB and pick its JSON serializer; a bare `$n` binds `[object Object]`.
19
25
  */
20
26
  export class PgliteQuerierPool extends AbstractSharedHandleQuerierPool {
21
27
  dataDir;
22
28
  opts;
23
29
  constructor(dataDir = 'memory://', opts, extra) {
24
- super(new PgliteDialect(dialectOptionsFrom(extra)), extra);
30
+ super(new PostgresDialect(dialectOptionsFrom(extra)), extra);
25
31
  this.dataDir = dataDir;
26
32
  this.opts = opts;
27
33
  }
28
34
  async openDb() {
29
- const { PGlite } = await import('@electric-sql/pglite');
30
- // The declared return type is what checks {@link PgliteDatabase} against the real driver, so no
31
- // cast is needed here or anywhere below it.
32
- return PGlite.create(this.dataDir, this.opts);
35
+ const { PGlite, types } = await import('@electric-sql/pglite');
36
+ // INT8 by the one wide-integer rule, where PGlite's own answers a `bigint` past 2^53; a caller's own
37
+ // `parsers` still win. The declared return type is what checks {@link PgliteDatabase} against the
38
+ // real driver, so no cast is needed here or anywhere below it.
39
+ return PGlite.create(this.dataDir, {
40
+ ...this.opts,
41
+ parsers: { [types.INT8]: decodeWideNumber, ...this.opts?.parsers },
42
+ });
33
43
  }
34
44
  buildQuerier(db) {
35
45
  return new PgliteQuerier(db, this.dialect, this.extra);
@@ -2,26 +2,22 @@ import type { AbstractSqlDialect } from '../dialect/index.js';
2
2
  import { AbstractSqlQuerierPool } from '../querier/index.js';
3
3
  import type { ExtraOptions } from '../type/index.js';
4
4
  import { type ErrorEmittingPool } from '../util/index.js';
5
- import type { AbstractPgQuerier, PgAnyClient } from './abstractPgQuerier.js';
5
+ import { type PgAnyClient, PgQuerier } from './pgQuerier.js';
6
6
  export interface PgAnyPool<C extends PgAnyClient> extends ErrorEmittingPool {
7
7
  connect: () => Promise<C>;
8
8
  end: () => Promise<void>;
9
9
  }
10
10
  /**
11
- * Shared base class for Postgres-compatible querier pools.
11
+ * Shared base class for Postgres-compatible querier pools. Each hands out a {@link PgQuerier} over its
12
+ * driver's client, so a subclass supplies only the dialect and the driver's pool.
12
13
  *
13
- * Wires the crash-preventing error handler here, once, so a new pg-compatible
14
- * pool subclass can't be added without it - the constructor takes the already
15
- * constructed pool and attaches the handler unconditionally.
14
+ * Wires the crash-preventing error handler here, once, so a new pg-compatible pool subclass can't be
15
+ * added without it - the constructor takes the already constructed pool and attaches the handler
16
+ * unconditionally.
16
17
  */
17
- export declare abstract class AbstractPgQuerierPool<C extends PgAnyClient, Q extends AbstractPgQuerier<C, D>, D extends AbstractSqlDialect> extends AbstractSqlQuerierPool<Q, D> {
18
+ export declare abstract class AbstractPgQuerierPool<C extends PgAnyClient, D extends AbstractSqlDialect> extends AbstractSqlQuerierPool<PgQuerier<C>, D> {
18
19
  readonly pool: PgAnyPool<C>;
19
20
  constructor(dialect: D, pool: PgAnyPool<C>, extra?: ExtraOptions);
20
- /**
21
- * Every pg-compatible pool acquires a client the same way, so only the querier class varies.
22
- * Subclasses name that instead of restating the lazy `connect` the querier expects.
23
- */
24
- protected abstract buildQuerier(connect: () => Promise<C>): Q;
25
- getQuerier(): Promise<Q>;
21
+ getQuerier(): Promise<PgQuerier<C>>;
26
22
  end(): Promise<void>;
27
23
  }
@@ -1,21 +1,23 @@
1
1
  import { AbstractSqlQuerierPool } from '../querier/index.js';
2
2
  import { attachPoolErrorHandler } from '../util/index.js';
3
+ import { PgQuerier } from './pgQuerier.js';
3
4
  /**
4
- * Shared base class for Postgres-compatible querier pools.
5
+ * Shared base class for Postgres-compatible querier pools. Each hands out a {@link PgQuerier} over its
6
+ * driver's client, so a subclass supplies only the dialect and the driver's pool.
5
7
  *
6
- * Wires the crash-preventing error handler here, once, so a new pg-compatible
7
- * pool subclass can't be added without it - the constructor takes the already
8
- * constructed pool and attaches the handler unconditionally.
8
+ * Wires the crash-preventing error handler here, once, so a new pg-compatible pool subclass can't be
9
+ * added without it - the constructor takes the already constructed pool and attaches the handler
10
+ * unconditionally.
9
11
  */
10
12
  export class AbstractPgQuerierPool extends AbstractSqlQuerierPool {
11
13
  pool;
12
14
  constructor(dialect, pool, extra) {
13
15
  super(dialect, extra);
14
16
  this.pool = pool;
15
- attachPoolErrorHandler(pool, 'Idle Postgres pool client encountered an error');
17
+ attachPoolErrorHandler(pool, 'Idle Postgres pool client encountered an error', extra?.logger);
16
18
  }
17
19
  async getQuerier() {
18
- return this.buildQuerier(() => this.pool.connect());
20
+ return new PgQuerier(() => this.pool.connect(), this.dialect, this.extra);
19
21
  }
20
22
  async end() {
21
23
  await this.pool.end();
@@ -1,4 +1,3 @@
1
- export * from './pgDialect.js';
2
1
  export * from './pgQuerier.js';
3
2
  export * from './pgQuerierPool.js';
4
3
  export * from './postgresDialect.js';
@@ -1,4 +1,3 @@
1
- export * from './pgDialect.js';
2
1
  export * from './pgQuerier.js';
3
2
  export * from './pgQuerierPool.js';
4
3
  export * from './postgresDialect.js';
@@ -10,7 +10,8 @@ type PgTypes = {
10
10
  getTypeParser(oid: number, format?: 'text' | 'binary'): (value: string) => unknown;
11
11
  };
12
12
  /**
13
- * Decode `INT8` and `FLOAT8` as JS numbers, leaving every other type to the driver.
13
+ * Decode `INT8` and `FLOAT8`, leaving every other type to the driver: an INT8 by `decodeWideNumber` - a
14
+ * number where one is exact, its exact text past 2^53 - and a FLOAT8 as the float64 it already is.
14
15
  *
15
16
  * uql owes this to the caller because uql picks the column: `type: Number` maps to BIGINT (see
16
17
  * `schema/canonicalType.ts`), so without it a field declared `number` read back as `'9'` - including
@@ -32,10 +33,9 @@ type PgTypes = {
32
33
  * `types.setTypeParser` calls in `neon/neonQuerier.test.ts` - and both made the suite pass on
33
34
  * behaviour the library never shipped. Do not reintroduce one.
34
35
  *
35
- * Exact to 2^53, which covers any auto-increment id. A caller who needs more passes their own
36
- * `types` in the pool options: it is spread after this one and therefore wins. For a decimal, the
37
- * lighter escape hatch is the declaration itself: `@Field({ type: String, columnType: 'decimal' })`
38
- * keeps the column DECIMAL while leaving the value as the exact text the driver returned.
36
+ * A caller's own `types` in the pool options are spread after this one and therefore win. For a
37
+ * decimal, the lighter escape hatch is the declaration itself: `@Field({ type: String, columnType:
38
+ * 'decimal' })` keeps the column DECIMAL while leaving the value as the exact text the driver returned.
39
39
  */
40
40
  export declare function numericTypes(types: PgTypes): CustomTypesConfig;
41
41
  export {};
@@ -1,5 +1,7 @@
1
+ import { decodeWideNumber } from '../util/wideNumber.js';
1
2
  /**
2
- * Decode `INT8` and `FLOAT8` as JS numbers, leaving every other type to the driver.
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
- * Exact to 2^53, which covers any auto-increment id. A caller who needs more passes their own
25
- * `types` in the pool options: it is spread after this one and therefore wins. For a decimal, the
26
- * lighter escape hatch is the declaration itself: `@Field({ type: String, columnType: 'decimal' })`
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 textNumeric = new Set([types.builtins['INT8'], types.builtins['FLOAT8']]);
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' && textNumeric.has(oid) ? Number : types.getTypeParser(oid, format),
37
+ getTypeParser: (oid, format) => (format === 'text' && decoders.get(oid)) || types.getTypeParser(oid, format),
34
38
  };
35
39
  }
@@ -1,5 +1,23 @@
1
- import type { PoolClient } from 'pg';
2
- import { AbstractPgQuerier } from './abstractPgQuerier.js';
3
- import type { PostgresDialect } from './postgresDialect.js';
4
- export declare class PgQuerier extends AbstractPgQuerier<PoolClient, PostgresDialect> {
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 { AbstractPgQuerier } from './abstractPgQuerier.js';
2
- export class PgQuerier extends AbstractPgQuerier {
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 { PgDialect } from './pgDialect.js';
5
- import { PgQuerier } from './pgQuerier.js';
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 { PgQuerier } from './pgQuerier.js';
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 PgDialect(dialectOptionsFrom(extra)), new Pool({ keepAlive: true, types: numericTypes(types), ...opts }), extra);
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. For node-pg use PgDialect. Neon, Bun SQL, and Cockroach use driver-specific
5
- * subclasses. Shared Postgres-wire AST/quoting/JSONB/full-text-search/vector-search logic
6
- * (including BIGINT IDENTITY PKs) lives in {@link PgLikeSqlDialect}; this class adds what's
7
- * Postgres-only: the `vector` extension requirement, pgvector's index syntax, and `xmax`-based
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. For node-pg use PgDialect. Neon, Bun SQL, and Cockroach use driver-specific
6
- * subclasses. Shared Postgres-wire AST/quoting/JSONB/full-text-search/vector-search logic
7
- * (including BIGINT IDENTITY PKs) lives in {@link PgLikeSqlDialect}; this class adds what's
8
- * Postgres-only: the `vector` extension requirement, pgvector's index syntax, and `xmax`-based
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. `PgDialect` uses neither, keeping the base
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 `NeonDialect` is a separate, unverified case - do not assume it needs this without testing.
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. `PgDialect` uses neither, keeping the base
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 `NeonDialect` is a separate, unverified case - do not assume it needs this without testing.
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(dialect: AbstractSqlDialect, connect: () => Promise<C>, extra?: ExtraOptions | undefined);
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(dialect, connect, extra) {
11
+ constructor(connect, dialect, extra) {
12
12
  super(dialect, extra);
13
13
  this.connect = connect;
14
14
  this.extra = extra;
@@ -1,5 +1,5 @@
1
- import { assertSoleId, getMeta, idOf, namesKey, soleIdOf } from '../entity/index.js';
2
- import { asSelectMap, childrenOf, clone, dataKeyed, fillOnFields, filterPersistableRelationKeys, forEachRequestedRelation, getKeys, getRelationRequestSummary, idOnlyQuery, isScalarId, joinedColumns, keyColumns, LoggerWrapper, isBoundedPerParent, parentJoins, queryChildrenOfAll, parseRelationAtKey, parseRelationQueryValue, rowKey, runHooks, someKey, targetKeyColumns, whereIds, withoutSoftDeleteFilter, } from '../util/index.js';
1
+ import { assertSoleId, getMeta, idOf, namesKey, relationOf, soleIdOf } from '../entity/index.js';
2
+ import { asSelectMap, childrenOf, clone, dataKeyed, entityName, fillOnFields, filterPersistableRelationKeys, forEachRequestedRelation, getKeys, getRelationRequestSummary, idOnlyQuery, isScalarId, joinedColumns, keyColumns, LoggerWrapper, isBoundedPerParent, parentJoins, queryChildrenOfAll, queryLoggerFor, parseRelationAtKey, parseRelationQueryValue, rowKey, runHooks, someKey, targetKeyColumns, whereIds, withoutSoftDeleteFilter, } from '../util/index.js';
3
3
  import { enrichError } from './queryError.js';
4
4
  import { fillRelationCounts, withIdForCounts } from './relationCount.js';
5
5
  /**
@@ -78,13 +78,10 @@ export class AbstractQuerier {
78
78
  logger;
79
79
  constructor(extra) {
80
80
  this.extra = extra;
81
- this.logger = new LoggerWrapper(extra?.logger, {
82
- logValues: extra?.logValues,
83
- slowQuery: extra?.slowQuery,
84
- });
81
+ this.logger = queryLoggerFor(extra);
85
82
  }
86
83
  validateProjectionQuery(entity, q) {
87
- this.validateProjectionQueryRecursive(entity, q, getMeta(entity).name ?? entity.name);
84
+ this.validateProjectionQueryRecursive(entity, q, entityName(getMeta(entity)));
88
85
  }
89
86
  validateProjectionQueryRecursive(entity, q, path) {
90
87
  const meta = getMeta(entity);
@@ -96,9 +93,7 @@ export class AbstractQuerier {
96
93
  }
97
94
  }
98
95
  forEachRequestedRelation(meta, q.$populate, (relKey, relValue) => {
99
- const relOpts = meta.relations[relKey];
100
- if (!relOpts)
101
- return;
96
+ const relOpts = relationOf(meta, relKey);
102
97
  const relEntity = relOpts.entity();
103
98
  const parsed = parseRelationQueryValue(relValue);
104
99
  if (parsed.nested) {
@@ -136,8 +131,14 @@ export class AbstractQuerier {
136
131
  const [entity, q, opts] = this.resolveEntityQuery(entityOrQuery, maybeQueryOrOpts, maybeOpts);
137
132
  this.validateProjectionQuery(entity, q);
138
133
  const founds = await this.internalFindMany(entity, withIdForCounts(entity, q), opts);
139
- await fillRelationCounts(this, entity, founds, q.$count);
140
- await this.emitHook(entity, 'afterLoad', founds);
134
+ // Guarded here rather than only inside: awaiting a call that returns at once still costs every read
135
+ // a promise and a turn of the microtask queue, and most reads count nothing and hook nothing.
136
+ if (q.$count) {
137
+ await fillRelationCounts(this, entity, founds, q.$count);
138
+ }
139
+ if (this.hasHook(entity, 'afterLoad')) {
140
+ await this.emitHook(entity, 'afterLoad', founds);
141
+ }
141
142
  return founds;
142
143
  }
143
144
  findManyStream(entityOrQuery, maybeQueryOrOpts, maybeOpts) {
@@ -348,9 +349,7 @@ export class AbstractQuerier {
348
349
  const meta = getMeta(entity);
349
350
  const relKeys = getRelationRequestSummary(meta, populate).toManyKeys;
350
351
  for (const relKey of relKeys) {
351
- const relOpts = meta.relations[relKey];
352
- if (!relOpts)
353
- continue;
352
+ const relOpts = relationOf(meta, relKey);
354
353
  const relEntity = relOpts.entity();
355
354
  const relationQuery = clone(parseRelationAtKey(relKey, populate).query);
356
355
  if (relOpts.through) {
@@ -498,9 +497,7 @@ export class AbstractQuerier {
498
497
  const relKeys = filterPersistableRelationKeys(meta, meta.relations, 'delete');
499
498
  // Cascade forwards `opts` (including `hardDelete`); each child soft-deletes only if it can.
500
499
  for (const relKey of relKeys) {
501
- const relOpts = meta.relations[relKey];
502
- if (!relOpts)
503
- continue;
500
+ const relOpts = relationOf(meta, relKey);
504
501
  const relEntity = relOpts.entity();
505
502
  const target = relOpts.through ? relOpts.through() : relEntity;
506
503
  const where = childrenOf(parentJoins(relOpts, meta.ids.length), ids);
@@ -514,9 +511,7 @@ export class AbstractQuerier {
514
511
  */
515
512
  async saveRelation(entity, ids, relValue, relKey, isUpdate) {
516
513
  const meta = getMeta(entity);
517
- const relOpts = meta.relations[relKey];
518
- if (!relOpts)
519
- return;
514
+ const relOpts = relationOf(meta, relKey);
520
515
  // Here rather than only in the callers below: writing the parent's key into a child is one column
521
516
  // per key, so a composite takes a statement per parent. `soleParentColumn` and the sole
522
517
  // `targetKeyColumns` under it read the *first* pair, which is a real column of a wrong pairing
@@ -684,7 +679,7 @@ export class AbstractQuerier {
684
679
  * another one would wait for a task queued behind itself. Callers below keep their `serialize` calls
685
680
  * sequential rather than nested.
686
681
  */
687
- async serialize(task) {
682
+ serialize(task) {
688
683
  const res = this.taskQueue.then(task);
689
684
  this.taskQueue = res.catch(() => { });
690
685
  return res;
@@ -100,14 +100,16 @@ export declare abstract class AbstractSqlQuerier extends AbstractQuerier impleme
100
100
  */
101
101
  protected internalStream<T>(query: string, values?: unknown[]): AsyncIterable<T>;
102
102
  /**
103
- * Turn what a driver returned back into the types the entity declares, for the row and everything
104
- * populated under it. Which columns, and as what, is `hydratableFields`; the per-cell decode is
105
- * `decodeColumn`. Both live with the dialect, because a `sparsevec` is only sparse on Postgres.
106
- *
107
- * `visited` guards a populated graph that points back at itself, and makes a node two paths reach
108
- * decode once. Only a relation can lead the walk back somewhere it has been, so an entity that
109
- * declares none skips the guard rather than allocating a set per row to hold a single object -
110
- * which cost more than the decoding it guards, on a flat read.
103
+ * Turn what a driver returned back into the types the entity declares, for every row and everything
104
+ * populated under them. Which columns, and as what, is `hydratableFields`, resolved once for all the
105
+ * rows; the per-cell decode is `decodeColumn`. Both live with the dialect, because a `sparsevec` is
106
+ * only sparse on Postgres.
107
+ */
108
+ private hydrateAll;
109
+ /**
110
+ * One row of {@link hydrateAll}. `visited` guards a populated graph that points back at itself, and
111
+ * makes a node two paths reach decode once. Only a populated relation can lead the walk back, so the
112
+ * guard is created at the first one a row carries: rows that populated nothing never allocate one.
111
113
  */
112
114
  private hydrateFields;
113
115
  /**
@@ -129,14 +131,21 @@ export declare abstract class AbstractSqlQuerier extends AbstractQuerier impleme
129
131
  protected internalDeleteMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): Promise<number>;
130
132
  get hasOpenTransaction(): boolean;
131
133
  beginTransaction(opts?: TransactionOptions): Promise<void>;
134
+ /**
135
+ * Only an end that succeeded ends the transaction. A `COMMIT` that fails can leave it open (SQLite
136
+ * answers `SQLITE_BUSY` and keeps it), so the flag has to stay set for the `catch` in
137
+ * {@link AbstractQuerier.transaction} or {@link AbstractQuerier.release} to roll it back.
138
+ */
132
139
  commitTransaction(): Promise<void>;
133
140
  rollbackTransaction(): Promise<void>;
134
141
  /**
135
- * Only a statement that succeeded ends the transaction. A `COMMIT` that fails can leave it open
136
- * (SQLite answers `SQLITE_BUSY` and keeps it), so the flag has to stay set for the `catch` in
137
- * {@link AbstractQuerier.transaction} or {@link AbstractQuerier.release} to roll it back.
142
+ * How this driver opens, commits and rolls back: the dialect's statements, unless its transactions
143
+ * are objects rather than statements - Hrana's session handle, `mssql`'s `Transaction` - in which
144
+ * case it overrides all three. The bookkeeping around them stays above, written once.
138
145
  */
139
- private endTransactionWith;
146
+ protected internalBegin(opts?: TransactionOptions): Promise<void>;
147
+ protected internalCommit(): Promise<void>;
148
+ protected internalRollback(): Promise<void>;
140
149
  /** Transaction statements skip `timed()`, so they attach their own query context to a failure. */
141
150
  private runTransactionCommand;
142
151
  }