@typesql/postgres 0.0.3 → 0.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @typesql/postgres
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Queries run from the `sql` bound to your client: `createSql<DB>(client)` then `sql("…").execute()` (or `executeTakeFirst`, `executeTakeFirstOrThrow`, `executeCount`), and `sql.transaction(async (tx) => …)` for transactions, nested with savepoints; the `query`, `one`, `maybeOne`, `many`, `execute`, `transaction` and `RowCountError` exports of `@typesql/pg` and `@typesql/postgres`, `query` and `execute` of `@typesql/kysely`, and `queryRaw` and `executeRaw` of `@typesql/prisma` are removed.
8
+
9
+ ### Patch Changes
10
+
11
+ - The README links to the type map tables on the new node-postgres and postgres.js adapter pages of the docs.
12
+
13
+ - Updated dependencies:
14
+ - @typesql/core@0.1.0
15
+
16
+ ## 0.0.4
17
+
18
+ ### Patch Changes
19
+
20
+ - Queries have `executeCount()`, which resolves to the affected row count: an `Executor` may resolve to `{ rows, rowCount }` instead of the rows, as the `executor()` of `@typesql/pg`, `@typesql/postgres` and `@typesql/kysely` now do.
21
+
22
+ - `execute(db, q)` resolves to 0 instead of `null` for statements without a count, such as DDL, and `PostgresJsRows["count"]` is `number | null`.
23
+
24
+ - `createSql(executor, { rowKeys: "camelCase" })` (and the adapters' `createSql(client, { rowKeys: "camelCase" })`) camelCases the top-level row keys the way Kysely's `CamelCasePlugin` does, in the row types and in the rows `execute*` and the `query`/`one`/`maybeOne`/`many` helpers return, leaving JSON values untouched.
25
+
26
+ - The type maps declare what parameters accept (`PgParamTypeMap`, `PostgresJsParamTypeMap`), so `int8`/`numeric` parameters take numbers and bigints and timestamp parameters take strings; postgres.js timestamp parameters also take epoch milliseconds.
27
+
28
+ - Updated dependencies:
29
+ - @typesql/core@0.0.4
30
+
3
31
  ## 0.0.3
4
32
 
5
33
  ### Patch Changes
package/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  [postgres.js](https://github.com/porsager/postgres) (`postgres` 3.x) adapter for
4
4
  [`@typesql/core`](https://www.npmjs.com/package/@typesql/core): a `createSql` bound to the type
5
- map of postgres.js' default parsers, and helpers that run a query and return rows typed from it.
5
+ map of postgres.js' default parsers, whose queries run on your `sql` instance and return rows
6
+ typed from the SQL.
6
7
 
7
8
  ```sh
8
9
  pnpm add @typesql/core @typesql/postgres postgres
@@ -12,29 +13,29 @@ pnpm add @typesql/core @typesql/postgres postgres
12
13
 
13
14
  ```ts
14
15
  import postgres from "postgres";
15
- import { createSql, execute, query, transaction } from "@typesql/postgres";
16
+ import { createSql } from "@typesql/postgres";
16
17
  import type { DB } from "./schema";
17
18
 
18
19
  const db = postgres(process.env.DATABASE_URL!);
19
- const sql = createSql<DB>(); // PostgresJsTypeMap
20
+ const sql = createSql<DB>(db); // PostgresJsTypeMap
20
21
 
21
- const posts = await query(db, sql("SELECT id, title FROM posts WHERE author_id = $1", 1));
22
+ const posts = await sql("SELECT id, title FROM posts WHERE author_id = $1", 1).execute();
22
23
  // { id: string; title: string }[] int8 is a string by default
23
24
 
24
- await transaction(db, async (tx) => {
25
- await execute(tx, sql("UPDATE posts SET title = upper(title) WHERE author_id = $1", 1));
25
+ await sql.transaction(async (tx) => {
26
+ await tx("UPDATE posts SET title = upper(title) WHERE author_id = $1", 1).execute();
26
27
  });
27
28
  ```
28
29
 
29
30
  With bigint parsing enabled on the connection, use `createBigIntSql`:
30
31
 
31
32
  ```ts
32
- import { createBigIntSql, query } from "@typesql/postgres";
33
+ import { createBigIntSql } from "@typesql/postgres";
33
34
 
34
35
  const dbBig = postgres(process.env.DATABASE_URL!, { types: { bigint: postgres.BigInt } });
35
- const big = createBigIntSql<DB>(); // PostgresJsBigIntTypeMap
36
+ const big = createBigIntSql<DB>(dbBig); // PostgresJsBigIntTypeMap
36
37
 
37
- const counts = await query(dbBig, big("SELECT author_id, count(*) AS n FROM posts GROUP BY author_id"));
38
+ const counts = await big("SELECT author_id, count(*) AS n FROM posts GROUP BY author_id").execute();
38
39
  // { author_id: number; n: bigint }[]
39
40
  ```
40
41
 
@@ -42,17 +43,15 @@ const counts = await query(dbBig, big("SELECT author_id, count(*) AS n FROM post
42
43
 
43
44
  | Export | |
44
45
  |---|---|
45
- | `createSql<DB>()` | core's `createSql<DB, PostgresJsTypeMap>()` |
46
- | `createBigIntSql<DB>()` | core's `createSql<DB, PostgresJsBigIntTypeMap>()`, for `types: { bigint: postgres.BigInt }` |
47
- | `query(db, q)` | `Promise<Row[]>` (a plain array, result metadata stripped) |
48
- | `one(db, q)` | `Promise<Row>`; `RowCountError` unless exactly one row |
49
- | `maybeOne(db, q)` | `Promise<Row \| null>`; `RowCountError` on more than one row |
50
- | `many(db, q)` | `Promise<[Row, ...Row[]]>`; `RowCountError` on zero rows |
51
- | `execute(db, q)` | `Promise<number>`, the affected row count |
52
- | `transaction(db, fn)` | `db.begin(fn)` |
46
+ | `createSql<DB>(db, options?)` | core's `createSql<DB, PostgresJsTypeMap>()` with the queries running on `db`; `{ rowKeys: "camelCase" }` camelCases the row keys |
47
+ | `createBigIntSql<DB>(db, options?)` | the same with `PostgresJsBigIntTypeMap`, for `types: { bigint: postgres.BigInt }` |
48
+ | `q.execute()`, `q.executeTakeFirst()`, `q.executeTakeFirstOrThrow()`, `q.executeCount()` | `Promise<Row[]>` (a plain array, result metadata stripped), `Promise<Row \| undefined>`, `Promise<Row>` (`NoResultError` on 0 rows), `Promise<number>` (`.count`, 0 for DDL) |
49
+ | `sql.transaction(fn)` | `db.begin(fn)` with `tx` bound to the transaction; `tx.transaction(fn)` is `savepoint(fn)` |
50
+ | `executor(db)` | an `Executor` for `q.execute(executor)` and core's `createSql(executor)` (reports `.count`) |
53
51
  | `migrate(db, m)` | runs `m.statements` (e.g. from core's `migrations()`) in one transaction |
54
- | `PostgresJsTypeMap`, `PostgresJsBigIntTypeMap` | the type maps |
55
- | `RowCountError`, `PostgresJsQueryable`, `PostgresJsTransactable`, `PostgresJsRows`, `MigrationSource` | errors and parameter types |
52
+ | `PostgresJsSql<DB, Keys>`, `PostgresJsBigIntSql<DB, Keys>` | the types `createSql` and `createBigIntSql` return |
53
+ | `PostgresJsTypeMap`, `PostgresJsBigIntTypeMap`, `PostgresJsParamTypeMap` | the type maps (rows), and what parameters also accept |
54
+ | `NoResultError`, `PostgresJsQueryable`, `PostgresJsTransactable`, `PostgresJsRows`, `MigrationSource` | errors and parameter types |
56
55
 
57
56
  Queries run with `db.unsafe(text, values)`, so the text reaches the server unchanged and values
58
57
  are bind parameters. `db` is the `Sql` instance, a `TransactionSql` or a `ReservedSql`.
@@ -72,4 +71,9 @@ postgres.js parses only a few types by default; everything else is the text Post
72
71
  | `numeric`, `interval`, `point`, text-like and other types | `string` | `string` |
73
72
 
74
73
  Arrays map element-wise. Details in the
75
- [Adapters guide](https://github.com/ismailkarsli/typesql/blob/main/packages/docs/guide/adapters.md).
74
+ [postgres.js adapter page](https://github.com/ismailkarsli/typesql/blob/main/packages/docs/adapters/postgres.md).
75
+
76
+ Parameters accept the row type and what postgres.js serializes for the type
77
+ (`PostgresJsParamTypeMap`): `number | bigint | string` for `int8`, `numeric` and `money`,
78
+ `Date | string | number` (epoch ms) for dates and timestamps, `string` for `interval`,
79
+ `Uint8Array` for `bytea`.
package/dist/client.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- import type { Executor, Query, RowType } from "@typesql/core";
2
- /** The shape of a resolved `sql.unsafe()` result the helpers rely on: an array with `count`. */
1
+ import type { Executor, SqlDriver } from "@typesql/core";
2
+ /**
3
+ * The shape of a resolved `sql.unsafe()` result the adapter relies on: an array with `count`
4
+ * (`null` for statements without a count, such as DDL).
5
+ */
3
6
  export type PostgresJsRows = readonly unknown[] & {
4
- readonly count: number;
7
+ readonly count: number | null;
5
8
  };
6
9
  /**
7
10
  * Anything with postgres.js' `unsafe(query, parameters)` method: the `Sql` instance,
@@ -14,33 +17,13 @@ export interface PostgresJsQueryable {
14
17
  export interface PostgresJsTransactable<Tx extends PostgresJsQueryable = PostgresJsQueryable> {
15
18
  begin(fn: (tx: Tx) => Promise<unknown>): Promise<unknown>;
16
19
  }
17
- /** Thrown by `one`, `maybeOne` and `many` when the row count does not match. */
18
- export declare class RowCountError extends Error {
19
- readonly code: "NO_ROWS" | "TOO_MANY_ROWS";
20
- readonly expected: string;
21
- readonly actual: number;
22
- readonly text: string;
23
- readonly name = "RowCountError";
24
- constructor(code: "NO_ROWS" | "TOO_MANY_ROWS", expected: string, actual: number, text: string);
25
- }
26
- type AnyQuery = Query<unknown, readonly unknown[]>;
27
- /** An `Executor` for core's `q.execute()`: runs queries through `sql.unsafe` and resolves to the rows. */
28
- export declare function executor(sql: PostgresJsQueryable): Executor;
29
- /** Run a query and return all rows (a plain array, without postgres.js' result metadata). */
30
- export declare function query<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q>[]>;
31
- /** Exactly one row, otherwise throws `RowCountError`. */
32
- export declare function one<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q>>;
33
- /** Zero or one row (`null` for zero); throws `RowCountError` on more than one. */
34
- export declare function maybeOne<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q> | null>;
35
- /** At least one row, otherwise throws `RowCountError`. */
36
- export declare function many<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<[RowType<Q>, ...RowType<Q>[]]>;
37
- /** Run a statement for its side effect and return the affected row count (postgres.js' `.count`). */
38
- export declare function execute(sql: PostgresJsQueryable, q: AnyQuery): Promise<number>;
39
20
  /**
40
- * Run `fn` inside `sql.begin()`: postgres.js issues BEGIN, runs the callback with a
41
- * transaction-bound `sql`, then COMMIT — or ROLLBACK and rethrow if the callback throws.
21
+ * An `Executor` for core's `q.execute()`: runs queries through `sql.unsafe` and resolves to
22
+ * `{ rows, rowCount }` (postgres.js' `.count`, so `q.executeCount()` works).
42
23
  */
43
- export declare function transaction<Tx extends PostgresJsQueryable, T>(sql: PostgresJsTransactable<Tx>, fn: (tx: Tx) => Promise<T>): Promise<T>;
24
+ export declare function executor(sql: PostgresJsQueryable): Executor;
25
+ /** How `createSql(sql)` runs queries and transactions. */
26
+ export declare const driver: SqlDriver<PostgresJsQueryable>;
44
27
  /** Anything carrying an ordered list of DDL statements, e.g. a `migrations()` builder from core. */
45
28
  export interface MigrationSource {
46
29
  readonly statements: readonly string[];
@@ -51,5 +34,4 @@ export interface MigrationSource {
51
34
  * `$$`-quoted function bodies work.
52
35
  */
53
36
  export declare function migrate<Tx extends PostgresJsQueryable>(sql: PostgresJsTransactable<Tx>, m: MigrationSource): Promise<void>;
54
- export {};
55
37
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEzD;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,OAAO,EAAE,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAEpF;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;CAC5E;AAED,qFAAqF;AACrF,MAAM,WAAW,sBAAsB,CAAC,EAAE,SAAS,mBAAmB,GAAG,mBAAmB;IAC1F,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAOD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,mBAAmB,GAAG,QAAQ,CAK3D;AAcD,0DAA0D;AAC1D,eAAO,MAAM,MAAM,EAAE,SAAS,CAAC,mBAAmB,CAA6B,CAAC;AAEhF,oGAAoG;AACpG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,EAAE,SAAS,mBAAmB,EAAE,GAAG,EAAE,sBAAsB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhI"}
package/dist/client.js CHANGED
@@ -1,71 +1,35 @@
1
- /** Thrown by `one`, `maybeOne` and `many` when the row count does not match. */
2
- export class RowCountError extends Error {
3
- code;
4
- expected;
5
- actual;
6
- text;
7
- name = "RowCountError";
8
- constructor(code, expected, actual, text) {
9
- super(`Expected ${expected} row(s) but the query returned ${actual}`);
10
- this.code = code;
11
- this.expected = expected;
12
- this.actual = actual;
13
- this.text = text;
14
- }
15
- }
16
- function run(sql, q) {
17
- return sql.unsafe(q.text, Array.from(q.values));
18
- }
19
- /** An `Executor` for core's `q.execute()`: runs queries through `sql.unsafe` and resolves to the rows. */
1
+ /**
2
+ * An `Executor` for core's `q.execute()`: runs queries through `sql.unsafe` and resolves to
3
+ * `{ rows, rowCount }` (postgres.js' `.count`, so `q.executeCount()` works).
4
+ */
20
5
  export function executor(sql) {
21
- return async (text, values) => Array.from(await sql.unsafe(text, Array.from(values)));
22
- }
23
- /** Run a query and return all rows (a plain array, without postgres.js' result metadata). */
24
- export async function query(sql, q) {
25
- const result = await run(sql, q);
26
- return Array.from(result);
27
- }
28
- /** Exactly one row, otherwise throws `RowCountError`. */
29
- export async function one(sql, q) {
30
- const rows = await query(sql, q);
31
- if (rows.length !== 1) {
32
- throw new RowCountError(rows.length === 0 ? "NO_ROWS" : "TOO_MANY_ROWS", "exactly 1", rows.length, q.text);
33
- }
34
- return rows[0];
35
- }
36
- /** Zero or one row (`null` for zero); throws `RowCountError` on more than one. */
37
- export async function maybeOne(sql, q) {
38
- const rows = await query(sql, q);
39
- if (rows.length > 1)
40
- throw new RowCountError("TOO_MANY_ROWS", "at most 1", rows.length, q.text);
41
- return rows.length === 0 ? null : rows[0];
42
- }
43
- /** At least one row, otherwise throws `RowCountError`. */
44
- export async function many(sql, q) {
45
- const rows = await query(sql, q);
46
- if (rows.length === 0)
47
- throw new RowCountError("NO_ROWS", "at least 1", 0, q.text);
48
- return rows;
49
- }
50
- /** Run a statement for its side effect and return the affected row count (postgres.js' `.count`). */
51
- export async function execute(sql, q) {
52
- const result = await run(sql, q);
53
- return result.count;
6
+ return async (text, values) => {
7
+ const result = await sql.unsafe(text, Array.from(values));
8
+ return { rows: Array.from(result), rowCount: result.count ?? null };
9
+ };
54
10
  }
55
11
  /**
56
- * Run `fn` inside `sql.begin()`: postgres.js issues BEGIN, runs the callback with a
57
- * transaction-bound `sql`, then COMMIT — or ROLLBACK and rethrow if the callback throws.
12
+ * Run `fn` inside a transaction: `tx.savepoint(fn)` on a `TransactionSql` (only those have it),
13
+ * otherwise `sql.begin(fn)`. postgres.js issues BEGIN (or SAVEPOINT), runs the callback with a
14
+ * transaction-bound `sql`, then COMMIT, or ROLLBACK and rethrow when the callback throws.
58
15
  */
59
- export async function transaction(sql, fn) {
60
- return (await sql.begin(fn));
61
- }
16
+ async function transaction(sql, _depth, fn) {
17
+ const { savepoint, begin } = sql;
18
+ if (savepoint)
19
+ return (await savepoint.call(sql, fn));
20
+ if (begin)
21
+ return (await begin.call(sql, fn));
22
+ throw new Error("typesql: sql.transaction() needs a postgres.js Sql, ReservedSql or TransactionSql (with begin or savepoint)");
23
+ }
24
+ /** How `createSql(sql)` runs queries and transactions. */
25
+ export const driver = { executor, transaction };
62
26
  /**
63
27
  * Run a migration's statements in order inside one transaction (`sql.begin`), all or nothing.
64
28
  * Each statement goes through `unsafe` without parameters (simple protocol), so scripts with
65
29
  * `$$`-quoted function bodies work.
66
30
  */
67
31
  export async function migrate(sql, m) {
68
- await transaction(sql, async (tx) => {
32
+ await sql.begin(async (tx) => {
69
33
  for (const statement of m.statements)
70
34
  await tx.unsafe(statement);
71
35
  });
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AA0BA;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAwB;IAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1D,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;IACtE,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAI,GAAwB,EAAE,MAAc,EAAE,EAA2C;IACjH,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,GAAgE,CAAC;IAC9F,IAAI,SAAS;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAM,CAAC;IAC3D,IAAI,KAAK;QAAE,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAM,CAAC;IACnD,MAAM,IAAI,KAAK,CAAC,6GAA6G,CAAC,CAAC;AACjI,CAAC;AAED,0DAA0D;AAC1D,MAAM,CAAC,MAAM,MAAM,GAAmC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AAOhF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAiC,GAA+B,EAAE,CAAkB;IAC/G,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QAC3B,KAAK,MAAM,SAAS,IAAI,CAAC,CAAC,UAAU;YAAE,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,14 +1,30 @@
1
- import { type Sql } from "@typesql/core";
1
+ import { type RowKeys, type TransactionalSql } from "@typesql/core";
2
2
  import { type PostgresJsQueryable } from "./client.js";
3
3
  import type { PostgresJsBigIntTypeMap, PostgresJsTypeMap } from "./type-map.js";
4
- export { NoResultError, type Executor } from "@typesql/core";
5
- export type { PostgresJsTypeMap, PostgresJsBigIntTypeMap } from "./type-map.js";
6
- export { query, one, maybeOne, many, execute, executor, transaction, migrate, type MigrationSource, RowCountError, type PostgresJsQueryable, type PostgresJsRows, type PostgresJsTransactable, } from "./client.js";
4
+ export { NoResultError, type Executor, type TransactionalSql } from "@typesql/core";
5
+ export type { PostgresJsTypeMap, PostgresJsBigIntTypeMap, PostgresJsParamTypeMap } from "./type-map.js";
6
+ export { executor, migrate, type MigrationSource, type PostgresJsQueryable, type PostgresJsRows, type PostgresJsTransactable, } from "./client.js";
7
+ /** What `createSql<DB>(sql)` returns: core's `Sql` under `PostgresJsTypeMap`, with `transaction(fn)`. */
8
+ export type PostgresJsSql<DB, Keys extends RowKeys = "preserve"> = TransactionalSql<DB, PostgresJsTypeMap, Keys>;
9
+ /** What `createBigIntSql<DB>(sql)` returns: core's `Sql` under `PostgresJsBigIntTypeMap`, with `transaction(fn)`. */
10
+ export type PostgresJsBigIntSql<DB, Keys extends RowKeys = "preserve"> = TransactionalSql<DB, PostgresJsBigIntTypeMap, Keys>;
7
11
  /**
8
12
  * `createSql<DB>()` from core, pre-bound to `PostgresJsTypeMap` (default parsers: `int8` and `count(*)` are `string`).
9
- * With a postgres.js `sql` instance, the queries' `execute*` methods run on it.
13
+ * The queries' `execute*` methods run on the postgres.js `sql` instance (or a `TransactionSql`,
14
+ * `ReservedSql`), and `sql.transaction(fn)` runs `fn` with a `sql` bound to one transaction.
15
+ * `{ rowKeys: "camelCase" }` camelCases the rows' keys, in the types and at runtime.
10
16
  */
11
- export declare function createSql<DB>(sql?: PostgresJsQueryable): Sql<DB, PostgresJsTypeMap>;
17
+ export declare function createSql<DB>(sql: PostgresJsQueryable | undefined, options: {
18
+ readonly rowKeys: "camelCase";
19
+ }): PostgresJsSql<DB, "camelCase">;
20
+ export declare function createSql<DB>(sql?: PostgresJsQueryable, options?: {
21
+ readonly rowKeys?: "preserve";
22
+ }): PostgresJsSql<DB>;
12
23
  /** For `postgres({ types: { bigint: postgres.BigInt } })` connections: `int8` and `count(*)` are `bigint`. */
13
- export declare function createBigIntSql<DB>(sql?: PostgresJsQueryable): Sql<DB, PostgresJsBigIntTypeMap>;
24
+ export declare function createBigIntSql<DB>(sql: PostgresJsQueryable | undefined, options: {
25
+ readonly rowKeys: "camelCase";
26
+ }): PostgresJsBigIntSql<DB, "camelCase">;
27
+ export declare function createBigIntSql<DB>(sql?: PostgresJsQueryable, options?: {
28
+ readonly rowKeys?: "preserve";
29
+ }): PostgresJsBigIntSql<DB>;
14
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,GAAG,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAY,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EACL,KAAK,EACL,GAAG,EACH,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,WAAW,EACX,OAAO,EACP,KAAK,eAAe,EACpB,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,GAAG,GAAG,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAEnF;AAED,8GAA8G;AAC9G,wBAAgB,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,GAAG,GAAG,CAAC,EAAE,EAAE,uBAAuB,CAAC,CAE/F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAU,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACpF,YAAY,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACxG,OAAO,EACL,QAAQ,EACR,OAAO,EACP,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AAErB,yGAAyG;AACzG,MAAM,MAAM,aAAa,CAAC,EAAE,EAAE,IAAI,SAAS,OAAO,GAAG,UAAU,IAAI,gBAAgB,CAAC,EAAE,EAAE,iBAAiB,EAAE,IAAI,CAAC,CAAC;AACjH,qHAAqH;AACrH,MAAM,MAAM,mBAAmB,CAAC,EAAE,EAAE,IAAI,SAAS,OAAO,GAAG,UAAU,IAAI,gBAAgB,CAAC,EAAE,EAAE,uBAAuB,EAAE,IAAI,CAAC,CAAC;AAE7H;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,SAAS,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAAG,aAAa,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;AAChJ,wBAAgB,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;AAKzH,8GAA8G;AAC9G,wBAAgB,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,SAAS,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAAG,mBAAmB,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;AAC5J,wBAAgB,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,mBAAmB,CAAC,EAAE,CAAC,CAAC"}
package/dist/index.js CHANGED
@@ -1,16 +1,11 @@
1
- import { createSql as createCoreSql } from "@typesql/core";
2
- import { executor } from "./client.js";
1
+ import { createTransactionalSql } from "@typesql/core";
2
+ import { driver } from "./client.js";
3
3
  export { NoResultError } from "@typesql/core";
4
- export { query, one, maybeOne, many, execute, executor, transaction, migrate, RowCountError, } from "./client.js";
5
- /**
6
- * `createSql<DB>()` from core, pre-bound to `PostgresJsTypeMap` (default parsers: `int8` and `count(*)` are `string`).
7
- * With a postgres.js `sql` instance, the queries' `execute*` methods run on it.
8
- */
9
- export function createSql(sql) {
10
- return createCoreSql(sql && executor(sql));
4
+ export { executor, migrate, } from "./client.js";
5
+ export function createSql(sql, options) {
6
+ return createTransactionalSql(sql, driver, options);
11
7
  }
12
- /** For `postgres({ types: { bigint: postgres.BigInt } })` connections: `int8` and `count(*)` are `bigint`. */
13
- export function createBigIntSql(sql) {
14
- return createCoreSql(sql && executor(sql));
8
+ export function createBigIntSql(sql, options) {
9
+ return createTransactionalSql(sql, driver, options);
15
10
  }
16
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,aAAa,EAAY,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,QAAQ,EAA4B,MAAM,aAAa,CAAC;AAGjE,OAAO,EAAE,aAAa,EAAiB,MAAM,eAAe,CAAC;AAE7D,OAAO,EACL,KAAK,EACL,GAAG,EACH,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,WAAW,EACX,OAAO,EAEP,aAAa,GAId,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAK,GAAyB;IACrD,OAAO,aAAa,CAAwB,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,8GAA8G;AAC9G,MAAM,UAAU,eAAe,CAAK,GAAyB;IAC3D,OAAO,aAAa,CAA8B,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1E,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAwD,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAE,MAAM,EAA4B,MAAM,aAAa,CAAC;AAG/D,OAAO,EAAE,aAAa,EAAwC,MAAM,eAAe,CAAC;AAEpF,OAAO,EACL,QAAQ,EACR,OAAO,GAKR,MAAM,aAAa,CAAC;AAerB,MAAM,UAAU,SAAS,CAAK,GAAyB,EAAE,OAAoB;IAC3E,OAAO,sBAAsB,CAA6C,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAClG,CAAC;AAKD,MAAM,UAAU,eAAe,CAAK,GAAyB,EAAE,OAAoB;IACjF,OAAO,sBAAsB,CAAmD,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AACxG,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { DefaultTypeMap } from "@typesql/core";
1
+ import type { DefaultParamTypeMap, DefaultTypeMap } from "@typesql/core";
2
2
  /**
3
3
  * Canonical Postgres type name → TS type as postgres.js 3.x returns it with its default
4
4
  * parsers. Verified against `postgres/src/types.js` (3.4.9), which parses only:
@@ -22,6 +22,8 @@ import type { DefaultTypeMap } from "@typesql/core";
22
22
  * element-type[] mapping is exact (int8[] → string[], timestamptz[] → Date[], ...).
23
23
  */
24
24
  export interface PostgresJsTypeMap extends Omit<DefaultTypeMap, "bytea" | "interval" | "point" | "circle" | "record" | "void"> {
25
+ /** What parameters accept on top of the row types. */
26
+ $params: PostgresJsParamTypeMap;
25
27
  bytea: Buffer;
26
28
  /** No default parser: the Postgres text form, e.g. `"1 day 02:00:00"`. */
27
29
  interval: string;
@@ -34,6 +36,25 @@ export interface PostgresJsTypeMap extends Omit<DefaultTypeMap, "bytea" | "inter
34
36
  /** `void`-returning functions (`pg_sleep`) yield an empty string. */
35
37
  void: string;
36
38
  }
39
+ /**
40
+ * TS types postgres.js parameters accept on top of the row type
41
+ * (`PostgresJsTypeMap["$params"]`). Verified against `postgres/src/types.js` and `Bind` in
42
+ * `connection.js` (3.4.9): a value is serialized by the serializer of the parameter type the
43
+ * server reports, and types without one (int8, numeric, money, interval, …) with `'' + x`.
44
+ *
45
+ * int8, numeric, money number | bigint | string
46
+ * date, timestamp, timestamptz Date | string | number: serialized as `new Date(x).toISOString()`,
47
+ * so a string must be one JS `Date` parses, a number is epoch ms
48
+ * interval string
49
+ * bytea Uint8Array, besides `Buffer`
50
+ *
51
+ * `bool` takes only booleans: its serializer sends `'f'` for anything but `true`.
52
+ */
53
+ export interface PostgresJsParamTypeMap extends Omit<DefaultParamTypeMap, "date" | "timestamp" | "timestamptz"> {
54
+ date: Date | string | number;
55
+ timestamp: Date | string | number;
56
+ timestamptz: Date | string | number;
57
+ }
37
58
  /**
38
59
  * Type map for connections created with `postgres({ types: { bigint: postgres.BigInt } })`,
39
60
  * which registers a parser for int8 (20) that returns JS `bigint`. `count(*)`, `sum(int4)`
@@ -1 +1 @@
1
- {"version":3,"file":"type-map.d.ts","sourceRoot":"","sources":["../src/type-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC5H,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC9E,IAAI,EAAE,MAAM,CAAC;CACd"}
1
+ {"version":3,"file":"type-map.d.ts","sourceRoot":"","sources":["../src/type-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC5H,sDAAsD;IACtD,OAAO,EAAE,sBAAsB,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,CAAC;IAC7G,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7B,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,WAAW,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;CACrC;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC9E,IAAI,EAAE,MAAM,CAAC;CACd"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typesql/postgres",
3
- "version": "0.0.3",
3
+ "version": "0.1.0",
4
4
  "description": "postgres.js adapter for typesql.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@typesql/core": "0.0.3"
31
+ "@typesql/core": "0.1.0"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "postgres": ">=3"
package/src/client.ts CHANGED
@@ -1,7 +1,10 @@
1
- import type { Executor, Query, RowType } from "@typesql/core";
1
+ import type { Executor, SqlDriver } from "@typesql/core";
2
2
 
3
- /** The shape of a resolved `sql.unsafe()` result the helpers rely on: an array with `count`. */
4
- export type PostgresJsRows = readonly unknown[] & { readonly count: number };
3
+ /**
4
+ * The shape of a resolved `sql.unsafe()` result the adapter relies on: an array with `count`
5
+ * (`null` for statements without a count, such as DDL).
6
+ */
7
+ export type PostgresJsRows = readonly unknown[] & { readonly count: number | null };
5
8
 
6
9
  /**
7
10
  * Anything with postgres.js' `unsafe(query, parameters)` method: the `Sql` instance,
@@ -16,76 +19,37 @@ export interface PostgresJsTransactable<Tx extends PostgresJsQueryable = Postgre
16
19
  begin(fn: (tx: Tx) => Promise<unknown>): Promise<unknown>;
17
20
  }
18
21
 
19
- /** Thrown by `one`, `maybeOne` and `many` when the row count does not match. */
20
- export class RowCountError extends Error {
21
- override readonly name = "RowCountError";
22
- constructor(
23
- readonly code: "NO_ROWS" | "TOO_MANY_ROWS",
24
- readonly expected: string,
25
- readonly actual: number,
26
- readonly text: string,
27
- ) {
28
- super(`Expected ${expected} row(s) but the query returned ${actual}`);
29
- }
30
- }
31
-
32
- type AnyQuery = Query<unknown, readonly unknown[]>;
33
-
34
- function run(sql: PostgresJsQueryable, q: AnyQuery): PromiseLike<PostgresJsRows> {
35
- return sql.unsafe(q.text, Array.from(q.values));
22
+ /** A `TransactionSql`'s `savepoint(fn)`. */
23
+ interface PostgresJsSavepointable {
24
+ savepoint(fn: (tx: PostgresJsQueryable) => Promise<unknown>): Promise<unknown>;
36
25
  }
37
26
 
38
- /** An `Executor` for core's `q.execute()`: runs queries through `sql.unsafe` and resolves to the rows. */
27
+ /**
28
+ * An `Executor` for core's `q.execute()`: runs queries through `sql.unsafe` and resolves to
29
+ * `{ rows, rowCount }` (postgres.js' `.count`, so `q.executeCount()` works).
30
+ */
39
31
  export function executor(sql: PostgresJsQueryable): Executor {
40
- return async (text, values) => Array.from(await sql.unsafe(text, Array.from(values)));
41
- }
42
-
43
- /** Run a query and return all rows (a plain array, without postgres.js' result metadata). */
44
- export async function query<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q>[]> {
45
- const result = await run(sql, q);
46
- return Array.from(result) as RowType<Q>[];
47
- }
48
-
49
- /** Exactly one row, otherwise throws `RowCountError`. */
50
- export async function one<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q>> {
51
- const rows = await query(sql, q);
52
- if (rows.length !== 1) {
53
- throw new RowCountError(rows.length === 0 ? "NO_ROWS" : "TOO_MANY_ROWS", "exactly 1", rows.length, q.text);
54
- }
55
- return rows[0] as RowType<Q>;
56
- }
57
-
58
- /** Zero or one row (`null` for zero); throws `RowCountError` on more than one. */
59
- export async function maybeOne<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q> | null> {
60
- const rows = await query(sql, q);
61
- if (rows.length > 1) throw new RowCountError("TOO_MANY_ROWS", "at most 1", rows.length, q.text);
62
- return rows.length === 0 ? null : (rows[0] as RowType<Q>);
63
- }
64
-
65
- /** At least one row, otherwise throws `RowCountError`. */
66
- export async function many<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<[RowType<Q>, ...RowType<Q>[]]> {
67
- const rows = await query(sql, q);
68
- if (rows.length === 0) throw new RowCountError("NO_ROWS", "at least 1", 0, q.text);
69
- return rows as [RowType<Q>, ...RowType<Q>[]];
70
- }
71
-
72
- /** Run a statement for its side effect and return the affected row count (postgres.js' `.count`). */
73
- export async function execute(sql: PostgresJsQueryable, q: AnyQuery): Promise<number> {
74
- const result = await run(sql, q);
75
- return result.count;
32
+ return async (text, values) => {
33
+ const result = await sql.unsafe(text, Array.from(values));
34
+ return { rows: Array.from(result), rowCount: result.count ?? null };
35
+ };
76
36
  }
77
37
 
78
38
  /**
79
- * Run `fn` inside `sql.begin()`: postgres.js issues BEGIN, runs the callback with a
80
- * transaction-bound `sql`, then COMMIT — or ROLLBACK and rethrow if the callback throws.
39
+ * Run `fn` inside a transaction: `tx.savepoint(fn)` on a `TransactionSql` (only those have it),
40
+ * otherwise `sql.begin(fn)`. postgres.js issues BEGIN (or SAVEPOINT), runs the callback with a
41
+ * transaction-bound `sql`, then COMMIT, or ROLLBACK and rethrow when the callback throws.
81
42
  */
82
- export async function transaction<Tx extends PostgresJsQueryable, T>(
83
- sql: PostgresJsTransactable<Tx>,
84
- fn: (tx: Tx) => Promise<T>,
85
- ): Promise<T> {
86
- return (await sql.begin(fn)) as T;
43
+ async function transaction<T>(sql: PostgresJsQueryable, _depth: number, fn: (tx: PostgresJsQueryable) => Promise<T>): Promise<T> {
44
+ const { savepoint, begin } = sql as Partial<PostgresJsSavepointable & PostgresJsTransactable>;
45
+ if (savepoint) return (await savepoint.call(sql, fn)) as T;
46
+ if (begin) return (await begin.call(sql, fn)) as T;
47
+ throw new Error("typesql: sql.transaction() needs a postgres.js Sql, ReservedSql or TransactionSql (with begin or savepoint)");
87
48
  }
88
49
 
50
+ /** How `createSql(sql)` runs queries and transactions. */
51
+ export const driver: SqlDriver<PostgresJsQueryable> = { executor, transaction };
52
+
89
53
  /** Anything carrying an ordered list of DDL statements, e.g. a `migrations()` builder from core. */
90
54
  export interface MigrationSource {
91
55
  readonly statements: readonly string[];
@@ -97,7 +61,7 @@ export interface MigrationSource {
97
61
  * `$$`-quoted function bodies work.
98
62
  */
99
63
  export async function migrate<Tx extends PostgresJsQueryable>(sql: PostgresJsTransactable<Tx>, m: MigrationSource): Promise<void> {
100
- await transaction(sql, async (tx) => {
64
+ await sql.begin(async (tx) => {
101
65
  for (const statement of m.statements) await tx.unsafe(statement);
102
66
  });
103
67
  }
package/src/index.ts CHANGED
@@ -1,34 +1,38 @@
1
- import { createSql as createCoreSql, type Sql } from "@typesql/core";
2
- import { executor, type PostgresJsQueryable } from "./client.js";
1
+ import { createTransactionalSql, type RowKeys, type SqlOptions, type TransactionalSql } from "@typesql/core";
2
+ import { driver, type PostgresJsQueryable } from "./client.js";
3
3
  import type { PostgresJsBigIntTypeMap, PostgresJsTypeMap } from "./type-map.js";
4
4
 
5
- export { NoResultError, type Executor } from "@typesql/core";
6
- export type { PostgresJsTypeMap, PostgresJsBigIntTypeMap } from "./type-map.js";
5
+ export { NoResultError, type Executor, type TransactionalSql } from "@typesql/core";
6
+ export type { PostgresJsTypeMap, PostgresJsBigIntTypeMap, PostgresJsParamTypeMap } from "./type-map.js";
7
7
  export {
8
- query,
9
- one,
10
- maybeOne,
11
- many,
12
- execute,
13
8
  executor,
14
- transaction,
15
9
  migrate,
16
10
  type MigrationSource,
17
- RowCountError,
18
11
  type PostgresJsQueryable,
19
12
  type PostgresJsRows,
20
13
  type PostgresJsTransactable,
21
14
  } from "./client.js";
22
15
 
16
+ /** What `createSql<DB>(sql)` returns: core's `Sql` under `PostgresJsTypeMap`, with `transaction(fn)`. */
17
+ export type PostgresJsSql<DB, Keys extends RowKeys = "preserve"> = TransactionalSql<DB, PostgresJsTypeMap, Keys>;
18
+ /** What `createBigIntSql<DB>(sql)` returns: core's `Sql` under `PostgresJsBigIntTypeMap`, with `transaction(fn)`. */
19
+ export type PostgresJsBigIntSql<DB, Keys extends RowKeys = "preserve"> = TransactionalSql<DB, PostgresJsBigIntTypeMap, Keys>;
20
+
23
21
  /**
24
22
  * `createSql<DB>()` from core, pre-bound to `PostgresJsTypeMap` (default parsers: `int8` and `count(*)` are `string`).
25
- * With a postgres.js `sql` instance, the queries' `execute*` methods run on it.
23
+ * The queries' `execute*` methods run on the postgres.js `sql` instance (or a `TransactionSql`,
24
+ * `ReservedSql`), and `sql.transaction(fn)` runs `fn` with a `sql` bound to one transaction.
25
+ * `{ rowKeys: "camelCase" }` camelCases the rows' keys, in the types and at runtime.
26
26
  */
27
- export function createSql<DB>(sql?: PostgresJsQueryable): Sql<DB, PostgresJsTypeMap> {
28
- return createCoreSql<DB, PostgresJsTypeMap>(sql && executor(sql));
27
+ export function createSql<DB>(sql: PostgresJsQueryable | undefined, options: { readonly rowKeys: "camelCase" }): PostgresJsSql<DB, "camelCase">;
28
+ export function createSql<DB>(sql?: PostgresJsQueryable, options?: { readonly rowKeys?: "preserve" }): PostgresJsSql<DB>;
29
+ export function createSql<DB>(sql?: PostgresJsQueryable, options?: SqlOptions): PostgresJsSql<DB, RowKeys> {
30
+ return createTransactionalSql<DB, PostgresJsTypeMap, PostgresJsQueryable>(sql, driver, options);
29
31
  }
30
32
 
31
33
  /** For `postgres({ types: { bigint: postgres.BigInt } })` connections: `int8` and `count(*)` are `bigint`. */
32
- export function createBigIntSql<DB>(sql?: PostgresJsQueryable): Sql<DB, PostgresJsBigIntTypeMap> {
33
- return createCoreSql<DB, PostgresJsBigIntTypeMap>(sql && executor(sql));
34
+ export function createBigIntSql<DB>(sql: PostgresJsQueryable | undefined, options: { readonly rowKeys: "camelCase" }): PostgresJsBigIntSql<DB, "camelCase">;
35
+ export function createBigIntSql<DB>(sql?: PostgresJsQueryable, options?: { readonly rowKeys?: "preserve" }): PostgresJsBigIntSql<DB>;
36
+ export function createBigIntSql<DB>(sql?: PostgresJsQueryable, options?: SqlOptions): PostgresJsBigIntSql<DB, RowKeys> {
37
+ return createTransactionalSql<DB, PostgresJsBigIntTypeMap, PostgresJsQueryable>(sql, driver, options);
34
38
  }
package/src/type-map.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { DefaultTypeMap } from "@typesql/core";
1
+ import type { DefaultParamTypeMap, DefaultTypeMap } from "@typesql/core";
2
2
 
3
3
  /**
4
4
  * Canonical Postgres type name → TS type as postgres.js 3.x returns it with its default
@@ -23,6 +23,8 @@ import type { DefaultTypeMap } from "@typesql/core";
23
23
  * element-type[] mapping is exact (int8[] → string[], timestamptz[] → Date[], ...).
24
24
  */
25
25
  export interface PostgresJsTypeMap extends Omit<DefaultTypeMap, "bytea" | "interval" | "point" | "circle" | "record" | "void"> {
26
+ /** What parameters accept on top of the row types. */
27
+ $params: PostgresJsParamTypeMap;
26
28
  bytea: Buffer;
27
29
  /** No default parser: the Postgres text form, e.g. `"1 day 02:00:00"`. */
28
30
  interval: string;
@@ -36,6 +38,26 @@ export interface PostgresJsTypeMap extends Omit<DefaultTypeMap, "bytea" | "inter
36
38
  void: string;
37
39
  }
38
40
 
41
+ /**
42
+ * TS types postgres.js parameters accept on top of the row type
43
+ * (`PostgresJsTypeMap["$params"]`). Verified against `postgres/src/types.js` and `Bind` in
44
+ * `connection.js` (3.4.9): a value is serialized by the serializer of the parameter type the
45
+ * server reports, and types without one (int8, numeric, money, interval, …) with `'' + x`.
46
+ *
47
+ * int8, numeric, money number | bigint | string
48
+ * date, timestamp, timestamptz Date | string | number: serialized as `new Date(x).toISOString()`,
49
+ * so a string must be one JS `Date` parses, a number is epoch ms
50
+ * interval string
51
+ * bytea Uint8Array, besides `Buffer`
52
+ *
53
+ * `bool` takes only booleans: its serializer sends `'f'` for anything but `true`.
54
+ */
55
+ export interface PostgresJsParamTypeMap extends Omit<DefaultParamTypeMap, "date" | "timestamp" | "timestamptz"> {
56
+ date: Date | string | number;
57
+ timestamp: Date | string | number;
58
+ timestamptz: Date | string | number;
59
+ }
60
+
39
61
  /**
40
62
  * Type map for connections created with `postgres({ types: { bigint: postgres.BigInt } })`,
41
63
  * which registers a parser for int8 (20) that returns JS `bigint`. `count(*)`, `sum(int4)`