@typesql/postgres 0.0.4 → 0.1.1

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,27 @@
1
1
  # @typesql/postgres
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Docs, package descriptions and error messages spell the project name TypeSQL.
8
+
9
+ - Updated dependencies:
10
+ - @typesql/core@0.1.1
11
+
12
+ ## 0.1.0
13
+
14
+ ### Minor Changes
15
+
16
+ - 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.
17
+
18
+ ### Patch Changes
19
+
20
+ - The README links to the type map tables on the new node-postgres and postgres.js adapter pages of the docs.
21
+
22
+ - Updated dependencies:
23
+ - @typesql/core@0.1.0
24
+
3
25
  ## 0.0.4
4
26
 
5
27
  ### 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,18 +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>(db?, options?)` | core's `createSql<DB, PostgresJsTypeMap>()`; `{ rowKeys: "camelCase" }` camelCases the row keys |
46
- | `createBigIntSql<DB>(db?, options?)` | 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 (0 for DDL) |
52
- | `executor(db)` | an `Executor` for `q.execute()` and `q.executeCount()` (reports `.count`); `createSql<DB>(db)` binds one |
53
- | `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`) |
54
51
  | `migrate(db, m)` | runs `m.statements` (e.g. from core's `migrations()`) in one transaction |
52
+ | `PostgresJsSql<DB, Keys>`, `PostgresJsBigIntSql<DB, Keys>` | the types `createSql` and `createBigIntSql` return |
55
53
  | `PostgresJsTypeMap`, `PostgresJsBigIntTypeMap`, `PostgresJsParamTypeMap` | the type maps (rows), and what parameters also accept |
56
- | `RowCountError`, `PostgresJsQueryable`, `PostgresJsTransactable`, `PostgresJsRows`, `MigrationSource` | errors and parameter types |
54
+ | `NoResultError`, `PostgresJsQueryable`, `PostgresJsTransactable`, `PostgresJsRows`, `MigrationSource` | errors and parameter types |
57
55
 
58
56
  Queries run with `db.unsafe(text, values)`, so the text reaches the server unchanged and values
59
57
  are bind parameters. `db` is the `Sql` instance, a `TransactionSql` or a `ReservedSql`.
@@ -73,7 +71,7 @@ postgres.js parses only a few types by default; everything else is the text Post
73
71
  | `numeric`, `interval`, `point`, text-like and other types | `string` | `string` |
74
72
 
75
73
  Arrays map element-wise. Details in the
76
- [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).
77
75
 
78
76
  Parameters accept the row type and what postgres.js serializes for the type
79
77
  (`PostgresJsParamTypeMap`): `number | bigint | string` for `int8`, `numeric` and `money`,
package/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { type Executor, type Query, type 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`
3
+ * The shape of a resolved `sql.unsafe()` result the adapter relies on: an array with `count`
4
4
  * (`null` for statements without a count, such as DDL).
5
5
  */
6
6
  export type PostgresJsRows = readonly unknown[] & {
@@ -17,36 +17,13 @@ export interface PostgresJsQueryable {
17
17
  export interface PostgresJsTransactable<Tx extends PostgresJsQueryable = PostgresJsQueryable> {
18
18
  begin(fn: (tx: Tx) => Promise<unknown>): Promise<unknown>;
19
19
  }
20
- /** Thrown by `one`, `maybeOne` and `many` when the row count does not match. */
21
- export declare class RowCountError extends Error {
22
- readonly code: "NO_ROWS" | "TOO_MANY_ROWS";
23
- readonly expected: string;
24
- readonly actual: number;
25
- readonly text: string;
26
- readonly name = "RowCountError";
27
- constructor(code: "NO_ROWS" | "TOO_MANY_ROWS", expected: string, actual: number, text: string);
28
- }
29
- type AnyQuery = Query<unknown, readonly unknown[]>;
30
20
  /**
31
21
  * An `Executor` for core's `q.execute()`: runs queries through `sql.unsafe` and resolves to
32
22
  * `{ rows, rowCount }` (postgres.js' `.count`, so `q.executeCount()` works).
33
23
  */
34
24
  export declare function executor(sql: PostgresJsQueryable): Executor;
35
- /** Run a query and return all rows (a plain array, without postgres.js' result metadata). */
36
- export declare function query<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q>[]>;
37
- /** Exactly one row, otherwise throws `RowCountError`. */
38
- export declare function one<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q>>;
39
- /** Zero or one row (`null` for zero); throws `RowCountError` on more than one. */
40
- export declare function maybeOne<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q> | null>;
41
- /** At least one row, otherwise throws `RowCountError`. */
42
- export declare function many<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<[RowType<Q>, ...RowType<Q>[]]>;
43
- /** Run a statement for its side effect and return the affected row count (postgres.js' `.count`, 0 when it is `null`). */
44
- export declare function execute(sql: PostgresJsQueryable, q: AnyQuery): Promise<number>;
45
- /**
46
- * Run `fn` inside `sql.begin()`: postgres.js issues BEGIN, runs the callback with a
47
- * transaction-bound `sql`, then COMMIT — or ROLLBACK and rethrow if the callback throws.
48
- */
49
- export declare function transaction<Tx extends PostgresJsQueryable, T>(sql: PostgresJsTransactable<Tx>, fn: (tx: Tx) => Promise<T>): Promise<T>;
25
+ /** How `createSql(sql)` runs queries and transactions. */
26
+ export declare const driver: SqlDriver<PostgresJsQueryable>;
50
27
  /** Anything carrying an ordered list of DDL statements, e.g. a `migrations()` builder from core. */
51
28
  export interface MigrationSource {
52
29
  readonly statements: readonly string[];
@@ -57,5 +34,4 @@ export interface MigrationSource {
57
34
  * `$$`-quoted function bodies work.
58
35
  */
59
36
  export declare function migrate<Tx extends PostgresJsQueryable>(sql: PostgresJsTransactable<Tx>, m: MigrationSource): Promise<void>;
60
- export {};
61
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,22 +1,3 @@
1
- import { mapRows } from "@typesql/core";
2
- /** Thrown by `one`, `maybeOne` and `many` when the row count does not match. */
3
- export class RowCountError extends Error {
4
- code;
5
- expected;
6
- actual;
7
- text;
8
- name = "RowCountError";
9
- constructor(code, expected, actual, text) {
10
- super(`Expected ${expected} row(s) but the query returned ${actual}`);
11
- this.code = code;
12
- this.expected = expected;
13
- this.actual = actual;
14
- this.text = text;
15
- }
16
- }
17
- function run(sql, q) {
18
- return sql.unsafe(q.text, Array.from(q.values));
19
- }
20
1
  /**
21
2
  * An `Executor` for core's `q.execute()`: runs queries through `sql.unsafe` and resolves to
22
3
  * `{ rows, rowCount }` (postgres.js' `.count`, so `q.executeCount()` works).
@@ -27,52 +8,28 @@ export function executor(sql) {
27
8
  return { rows: Array.from(result), rowCount: result.count ?? null };
28
9
  };
29
10
  }
30
- /** Run a query and return all rows (a plain array, without postgres.js' result metadata). */
31
- export async function query(sql, q) {
32
- const result = await run(sql, q);
33
- return mapRows(q, Array.from(result));
34
- }
35
- /** Exactly one row, otherwise throws `RowCountError`. */
36
- export async function one(sql, q) {
37
- const rows = await query(sql, q);
38
- if (rows.length !== 1) {
39
- throw new RowCountError(rows.length === 0 ? "NO_ROWS" : "TOO_MANY_ROWS", "exactly 1", rows.length, q.text);
40
- }
41
- return rows[0];
42
- }
43
- /** Zero or one row (`null` for zero); throws `RowCountError` on more than one. */
44
- export async function maybeOne(sql, q) {
45
- const rows = await query(sql, q);
46
- if (rows.length > 1)
47
- throw new RowCountError("TOO_MANY_ROWS", "at most 1", rows.length, q.text);
48
- return rows.length === 0 ? null : rows[0];
49
- }
50
- /** At least one row, otherwise throws `RowCountError`. */
51
- export async function many(sql, q) {
52
- const rows = await query(sql, q);
53
- if (rows.length === 0)
54
- throw new RowCountError("NO_ROWS", "at least 1", 0, q.text);
55
- return rows;
56
- }
57
- /** Run a statement for its side effect and return the affected row count (postgres.js' `.count`, 0 when it is `null`). */
58
- export async function execute(sql, q) {
59
- const result = await run(sql, q);
60
- return result.count ?? 0;
61
- }
62
11
  /**
63
- * Run `fn` inside `sql.begin()`: postgres.js issues BEGIN, runs the callback with a
64
- * 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.
65
15
  */
66
- export async function transaction(sql, fn) {
67
- return (await sql.begin(fn));
68
- }
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 };
69
26
  /**
70
27
  * Run a migration's statements in order inside one transaction (`sql.begin`), all or nothing.
71
28
  * Each statement goes through `unsafe` without parameters (simple protocol), so scripts with
72
29
  * `$$`-quoted function bodies work.
73
30
  */
74
31
  export async function migrate(sql, m) {
75
- await transaction(sql, async (tx) => {
32
+ await sql.begin(async (tx) => {
76
33
  for (const statement of m.statements)
77
34
  await tx.unsafe(statement);
78
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,25 +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";
4
+ export { NoResultError, type Executor, type TransactionalSql } from "@typesql/core";
5
5
  export type { PostgresJsTypeMap, PostgresJsBigIntTypeMap, PostgresJsParamTypeMap } 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";
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.
10
15
  * `{ rowKeys: "camelCase" }` camelCases the rows' keys, in the types and at runtime.
11
16
  */
12
17
  export declare function createSql<DB>(sql: PostgresJsQueryable | undefined, options: {
13
18
  readonly rowKeys: "camelCase";
14
- }): Sql<DB, PostgresJsTypeMap, "camelCase">;
19
+ }): PostgresJsSql<DB, "camelCase">;
15
20
  export declare function createSql<DB>(sql?: PostgresJsQueryable, options?: {
16
21
  readonly rowKeys?: "preserve";
17
- }): Sql<DB, PostgresJsTypeMap>;
22
+ }): PostgresJsSql<DB>;
18
23
  /** For `postgres({ types: { bigint: postgres.BigInt } })` connections: `int8` and `count(*)` are `bigint`. */
19
24
  export declare function createBigIntSql<DB>(sql: PostgresJsQueryable | undefined, options: {
20
25
  readonly rowKeys: "camelCase";
21
- }): Sql<DB, PostgresJsBigIntTypeMap, "camelCase">;
26
+ }): PostgresJsBigIntSql<DB, "camelCase">;
22
27
  export declare function createBigIntSql<DB>(sql?: PostgresJsQueryable, options?: {
23
28
  readonly rowKeys?: "preserve";
24
- }): Sql<DB, PostgresJsBigIntTypeMap>;
29
+ }): PostgresJsBigIntSql<DB>;
25
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,GAAG,EAAmB,MAAM,eAAe,CAAC;AACpG,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,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACxG,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;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,SAAS,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAAG,GAAG,CAAC,EAAE,EAAE,iBAAiB,EAAE,WAAW,CAAC,CAAC;AACzJ,wBAAgB,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,GAAG,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;AAKlI,8GAA8G;AAC9G,wBAAgB,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,SAAS,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAAG,GAAG,CAAC,EAAE,EAAE,uBAAuB,EAAE,WAAW,CAAC,CAAC;AACrK,wBAAgB,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,GAAG,CAAC,EAAE,EAAE,uBAAuB,CAAC,CAAC"}
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,11 +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";
4
+ export { executor, migrate, } from "./client.js";
5
5
  export function createSql(sql, options) {
6
- return createCoreSql(sql && executor(sql), options);
6
+ return createTransactionalSql(sql, driver, options);
7
7
  }
8
8
  export function createBigIntSql(sql, options) {
9
- return createCoreSql(sql && executor(sql), options);
9
+ return createTransactionalSql(sql, driver, options);
10
10
  }
11
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,EAA2C,MAAM,eAAe,CAAC;AACpG,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;AASrB,MAAM,UAAU,SAAS,CAAK,GAAyB,EAAE,OAAoB;IAC3E,OAAO,aAAa,CAAwB,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,OAA4C,CAAC,CAAC;AAClH,CAAC;AAKD,MAAM,UAAU,eAAe,CAAK,GAAyB,EAAE,OAAoB;IACjF,OAAO,aAAa,CAA8B,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,OAA4C,CAAC,CAAC;AACxH,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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@typesql/postgres",
3
- "version": "0.0.4",
4
- "description": "postgres.js adapter for typesql.",
3
+ "version": "0.1.1",
4
+ "description": "postgres.js adapter for TypeSQL.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@typesql/core": "0.0.4"
31
+ "@typesql/core": "0.1.1"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "postgres": ">=3"
package/src/client.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { mapRows, type Executor, type Query, type RowType } from "@typesql/core";
1
+ import type { Executor, SqlDriver } from "@typesql/core";
2
2
 
3
3
  /**
4
- * The shape of a resolved `sql.unsafe()` result the helpers rely on: an array with `count`
4
+ * The shape of a resolved `sql.unsafe()` result the adapter relies on: an array with `count`
5
5
  * (`null` for statements without a count, such as DDL).
6
6
  */
7
7
  export type PostgresJsRows = readonly unknown[] & { readonly count: number | null };
@@ -19,23 +19,9 @@ export interface PostgresJsTransactable<Tx extends PostgresJsQueryable = Postgre
19
19
  begin(fn: (tx: Tx) => Promise<unknown>): Promise<unknown>;
20
20
  }
21
21
 
22
- /** Thrown by `one`, `maybeOne` and `many` when the row count does not match. */
23
- export class RowCountError extends Error {
24
- override readonly name = "RowCountError";
25
- constructor(
26
- readonly code: "NO_ROWS" | "TOO_MANY_ROWS",
27
- readonly expected: string,
28
- readonly actual: number,
29
- readonly text: string,
30
- ) {
31
- super(`Expected ${expected} row(s) but the query returned ${actual}`);
32
- }
33
- }
34
-
35
- type AnyQuery = Query<unknown, readonly unknown[]>;
36
-
37
- function run(sql: PostgresJsQueryable, q: AnyQuery): PromiseLike<PostgresJsRows> {
38
- 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>;
39
25
  }
40
26
 
41
27
  /**
@@ -49,52 +35,21 @@ export function executor(sql: PostgresJsQueryable): Executor {
49
35
  };
50
36
  }
51
37
 
52
- /** Run a query and return all rows (a plain array, without postgres.js' result metadata). */
53
- export async function query<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q>[]> {
54
- const result = await run(sql, q);
55
- return mapRows(q, Array.from(result));
56
- }
57
-
58
- /** Exactly one row, otherwise throws `RowCountError`. */
59
- export async function one<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q>> {
60
- const rows = await query(sql, q);
61
- if (rows.length !== 1) {
62
- throw new RowCountError(rows.length === 0 ? "NO_ROWS" : "TOO_MANY_ROWS", "exactly 1", rows.length, q.text);
63
- }
64
- return rows[0] as RowType<Q>;
65
- }
66
-
67
- /** Zero or one row (`null` for zero); throws `RowCountError` on more than one. */
68
- export async function maybeOne<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<RowType<Q> | null> {
69
- const rows = await query(sql, q);
70
- if (rows.length > 1) throw new RowCountError("TOO_MANY_ROWS", "at most 1", rows.length, q.text);
71
- return rows.length === 0 ? null : (rows[0] as RowType<Q>);
72
- }
73
-
74
- /** At least one row, otherwise throws `RowCountError`. */
75
- export async function many<Q extends AnyQuery>(sql: PostgresJsQueryable, q: Q): Promise<[RowType<Q>, ...RowType<Q>[]]> {
76
- const rows = await query(sql, q);
77
- if (rows.length === 0) throw new RowCountError("NO_ROWS", "at least 1", 0, q.text);
78
- return rows as [RowType<Q>, ...RowType<Q>[]];
79
- }
80
-
81
- /** Run a statement for its side effect and return the affected row count (postgres.js' `.count`, 0 when it is `null`). */
82
- export async function execute(sql: PostgresJsQueryable, q: AnyQuery): Promise<number> {
83
- const result = await run(sql, q);
84
- return result.count ?? 0;
85
- }
86
-
87
38
  /**
88
- * Run `fn` inside `sql.begin()`: postgres.js issues BEGIN, runs the callback with a
89
- * 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.
90
42
  */
91
- export async function transaction<Tx extends PostgresJsQueryable, T>(
92
- sql: PostgresJsTransactable<Tx>,
93
- fn: (tx: Tx) => Promise<T>,
94
- ): Promise<T> {
95
- 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)");
96
48
  }
97
49
 
50
+ /** How `createSql(sql)` runs queries and transactions. */
51
+ export const driver: SqlDriver<PostgresJsQueryable> = { executor, transaction };
52
+
98
53
  /** Anything carrying an ordered list of DDL statements, e.g. a `migrations()` builder from core. */
99
54
  export interface MigrationSource {
100
55
  readonly statements: readonly string[];
@@ -106,7 +61,7 @@ export interface MigrationSource {
106
61
  * `$$`-quoted function bodies work.
107
62
  */
108
63
  export async function migrate<Tx extends PostgresJsQueryable>(sql: PostgresJsTransactable<Tx>, m: MigrationSource): Promise<void> {
109
- await transaction(sql, async (tx) => {
64
+ await sql.begin(async (tx) => {
110
65
  for (const statement of m.statements) await tx.unsafe(statement);
111
66
  });
112
67
  }
package/src/index.ts CHANGED
@@ -1,39 +1,38 @@
1
- import { createSql as createCoreSql, type RowKeys, type Sql, type SqlOptions } 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";
5
+ export { NoResultError, type Executor, type TransactionalSql } from "@typesql/core";
6
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.
26
25
  * `{ rowKeys: "camelCase" }` camelCases the rows' keys, in the types and at runtime.
27
26
  */
28
- export function createSql<DB>(sql: PostgresJsQueryable | undefined, options: { readonly rowKeys: "camelCase" }): Sql<DB, PostgresJsTypeMap, "camelCase">;
29
- export function createSql<DB>(sql?: PostgresJsQueryable, options?: { readonly rowKeys?: "preserve" }): Sql<DB, PostgresJsTypeMap>;
30
- export function createSql<DB>(sql?: PostgresJsQueryable, options?: SqlOptions): Sql<DB, PostgresJsTypeMap, RowKeys> {
31
- return createCoreSql<DB, PostgresJsTypeMap>(sql && executor(sql), options as { readonly rowKeys: "camelCase" });
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);
32
31
  }
33
32
 
34
33
  /** For `postgres({ types: { bigint: postgres.BigInt } })` connections: `int8` and `count(*)` are `bigint`. */
35
- export function createBigIntSql<DB>(sql: PostgresJsQueryable | undefined, options: { readonly rowKeys: "camelCase" }): Sql<DB, PostgresJsBigIntTypeMap, "camelCase">;
36
- export function createBigIntSql<DB>(sql?: PostgresJsQueryable, options?: { readonly rowKeys?: "preserve" }): Sql<DB, PostgresJsBigIntTypeMap>;
37
- export function createBigIntSql<DB>(sql?: PostgresJsQueryable, options?: SqlOptions): Sql<DB, PostgresJsBigIntTypeMap, RowKeys> {
38
- return createCoreSql<DB, PostgresJsBigIntTypeMap>(sql && executor(sql), options as { readonly rowKeys: "camelCase" });
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);
39
38
  }