@typesql/drizzle 0.0.4 → 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,16 @@
1
1
  # @typesql/drizzle
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - `createSql<typeof schema>(db)` takes a Drizzle database or transaction on node-postgres or postgres.js instead of an `Executor`, runs the queries on its driver client, and has `sql.transaction(fn)`, which runs in `db.transaction`.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies:
12
+ - @typesql/core@0.1.0
13
+
3
14
  ## 0.0.4
4
15
 
5
16
  ### Patch Changes
package/README.md CHANGED
@@ -9,7 +9,8 @@ SQL you write is checked against the same tables Drizzle manages.
9
9
  npm install @typesql/drizzle @typesql/core
10
10
  ```
11
11
 
12
- `drizzle-orm` (0.45 or later) is a peer dependency.
12
+ `drizzle-orm` (0.45 or later) is a peer dependency. Queries run on node-postgres or postgres.js
13
+ databases.
13
14
 
14
15
  ## Usage
15
16
 
@@ -39,10 +40,13 @@ export const usersRelations = relations(users, ({ many }) => ({ posts: many(post
39
40
 
40
41
  ```ts
41
42
  // db.ts
43
+ import { drizzle } from "drizzle-orm/node-postgres";
44
+ import { Pool } from "pg";
42
45
  import { createSql } from "@typesql/drizzle";
43
- import type * as schema from "./schema";
46
+ import * as schema from "./schema";
44
47
 
45
- const sql = createSql<typeof schema>();
48
+ const db = drizzle(new Pool(), { schema });
49
+ const sql = createSql<typeof schema>(db);
46
50
 
47
51
  const q = sql(
48
52
  "SELECT u.email, u.display_name, p.title FROM users u JOIN posts p ON p.author_id = u.id WHERE u.mood = $1",
@@ -50,23 +54,58 @@ const q = sql(
50
54
  );
51
55
  // Query<{ email: string; display_name: string | null; title: string }, ["happy" | "sad"]>
52
56
 
53
- sql("INSERT INTO posts (author_id, title) VALUES ($1, $2) RETURNING id, created_at", 1, "Hello");
57
+ const post = await sql("INSERT INTO posts (author_id, title) VALUES ($1, $2) RETURNING id, created_at", 1, "Hello").executeTakeFirstOrThrow();
54
58
  // id and created_at have defaults, so they can be left out
59
+
60
+ await sql.transaction(async (tx) => {
61
+ await tx("UPDATE posts SET title = upper(title) WHERE author_id = $1", 1).execute();
62
+ });
55
63
  ```
56
64
 
57
65
  Queries use SQL names: `display_name`, not `displayName`. Relations and any other
58
66
  non-table exports are ignored, so `typeof schema` can be passed as is.
59
67
 
60
- `createSql<Schema, TypeMap, Options>()` uses core's `DefaultTypeMap` unless you pass
61
- another one. To pair the schema with a driver adapter, convert it with `FromDrizzle` and use
62
- the adapter's `createSql`:
68
+ `createSql<Schema, TypeMap, Options>(db)` uses core's `DefaultTypeMap` unless you pass
69
+ another one, such as `PgTypeMap` from `@typesql/pg` for node-postgres' exact types:
70
+ `createSql<typeof schema, PgTypeMap>(db)`.
71
+
72
+ ## Running queries
73
+
74
+ `db` is a Drizzle database on node-postgres or postgres.js (`drizzle-orm/node-postgres`,
75
+ `drizzle-orm/postgres-js`), or a transaction from `db.transaction(fn)`. Queries run on the
76
+ driver client Drizzle holds: the `Pool`, `Client` or postgres.js `sql` you gave `drizzle()`, or
77
+ the transaction's connection. Rows are what the driver returns; Drizzle's column mappers and
78
+ its logger are not involved.
79
+
80
+ | | |
81
+ |---|---|
82
+ | `q.execute()`, `q.executeTakeFirst()`, `q.executeTakeFirstOrThrow()`, `q.executeCount()` | `Promise<Row[]>`, `Promise<Row \| undefined>`, `Promise<Row>` (`NoResultError` on 0 rows), `Promise<number>` (the driver's row count) |
83
+ | `sql.transaction(fn)` | `db.transaction(fn)` with `tx` bound to the transaction; `tx.transaction(fn)` is Drizzle's nested transaction (a savepoint) |
84
+ | `executor(db)` | an `Executor` for `q.execute(executor)` and core's `createSql(executor)` |
85
+ | `DrizzleSql<Schema, TM, Options>`, `DrizzleDatabase` | the type `createSql` returns, and what it accepts |
86
+
87
+ To mix ORM and SQL queries in one transaction, bind a `sql` to Drizzle's `tx`:
88
+
89
+ ```ts
90
+ await db.transaction(async (tx) => {
91
+ await tx.insert(schema.users).values({ email: "a@b.c" });
92
+ await createSql<typeof schema>(tx)("UPDATE users SET mood = 'happy' WHERE email = $1", "a@b.c").execute();
93
+ });
94
+ ```
95
+
96
+ `drizzle-orm/postgres-js` turns off postgres.js' date parsers on the client it is given, so on
97
+ that driver `date`, `timestamp`, `timestamptz` and `interval` come back as strings: pass a type
98
+ map that says so.
99
+
100
+ To pair the schema with a driver adapter instead, convert it with `FromDrizzle` and use the
101
+ adapter's `createSql` on the same pool:
63
102
 
64
103
  ```ts
65
104
  import { createSql } from "@typesql/pg";
66
105
  import type { FromDrizzle } from "@typesql/drizzle";
67
106
  import type * as schema from "./schema";
68
107
 
69
- const sql = createSql<FromDrizzle<typeof schema>>();
108
+ const sql = createSql<FromDrizzle<typeof schema>>(pool);
70
109
  ```
71
110
 
72
111
  `FromDrizzle` also accepts a single table (`FromDrizzle<typeof users>`) or a record of
@@ -129,7 +168,7 @@ type maps, but `timestamp` and `timestamptz` behave differently in SQL (`AT TIME
129
168
  `date_trunc`, comparisons with `now()`). Either set the default for all of them:
130
169
 
131
170
  ```ts
132
- createSql<typeof schema, DefaultTypeMap, { timestamp: "timestamptz"; time: "timetz" }>();
171
+ createSql<typeof schema, DefaultTypeMap, { timestamp: "timestamptz"; time: "timetz" }>(db);
133
172
  // or: FromDrizzle<typeof schema, { timestamp: "timestamptz" }>
134
173
  ```
135
174
 
@@ -163,7 +202,7 @@ If you create Drizzle with `drizzle(client, { casing: "snake_case" })`, pass the
163
202
  setting so column names match what Drizzle sends to Postgres:
164
203
 
165
204
  ```ts
166
- createSql<typeof schema, DefaultTypeMap, { casing: "snake_case" }>();
205
+ createSql<typeof schema, DefaultTypeMap, { casing: "snake_case" }>(db);
167
206
  // createdAt: timestamp() → column created_at
168
207
  ```
169
208
 
@@ -0,0 +1,20 @@
1
+ import type { Executor, SqlDriver } from "@typesql/core";
2
+ /**
3
+ * What the adapter uses from a Drizzle database (`drizzle(client)` from `drizzle-orm/node-postgres`,
4
+ * `drizzle-orm/postgres-js`, ...) or a transaction from `db.transaction(fn)`.
5
+ */
6
+ export interface DrizzleDatabase {
7
+ readonly _: {
8
+ readonly session: object;
9
+ };
10
+ transaction<T>(fn: (tx: DrizzleDatabase) => Promise<T>): Promise<T>;
11
+ }
12
+ /**
13
+ * An `Executor` for core's `q.execute()`: runs queries on the driver client under `db`, so rows
14
+ * come back as the driver parses them (Drizzle's column mappers are not involved), and resolves to
15
+ * `{ rows, rowCount }` so `q.executeCount()` works.
16
+ */
17
+ export declare function executor(db: DrizzleDatabase): Executor;
18
+ /** How `createSql(db)` runs queries and transactions. */
19
+ export declare const driver: SqlDriver<DrizzleDatabase>;
20
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
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,WAAW,eAAe;IAC9B,QAAQ,CAAC,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACrE;AAmBD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,eAAe,GAAG,QAAQ,CAUtD;AAOD,yDAAyD;AACzD,eAAO,MAAM,MAAM,EAAE,SAAS,CAAC,eAAe,CAA6B,CAAC"}
package/dist/client.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The driver client under `db`: the `Pool`, `Client` or postgres.js `sql` given to `drizzle()`,
3
+ * or, inside `db.transaction(fn)`, the connection the transaction runs on. Drizzle keeps it as
4
+ * `session.client`.
5
+ */
6
+ function clientOf(db) {
7
+ const client = db._.session.client;
8
+ if (client && (typeof client.unsafe === "function" || typeof client.query === "function"))
9
+ return client;
10
+ throw new Error("typesql: createSql(db) needs a Drizzle database on node-postgres or postgres.js (its session client has no query or unsafe method)");
11
+ }
12
+ /**
13
+ * An `Executor` for core's `q.execute()`: runs queries on the driver client under `db`, so rows
14
+ * come back as the driver parses them (Drizzle's column mappers are not involved), and resolves to
15
+ * `{ rows, rowCount }` so `q.executeCount()` works.
16
+ */
17
+ export function executor(db) {
18
+ return async (text, values) => {
19
+ const client = clientOf(db);
20
+ if (client.unsafe) {
21
+ const result = (await client.unsafe(text, Array.from(values)));
22
+ return { rows: Array.from(result), rowCount: result.count ?? null };
23
+ }
24
+ const result = (await client.query(text, Array.from(values)));
25
+ return { rows: result.rows, rowCount: result.rowCount ?? null };
26
+ };
27
+ }
28
+ /** Run `fn` inside `db.transaction(fn)`; Drizzle nests a transaction inside one with a savepoint. */
29
+ function transaction(db, _depth, fn) {
30
+ return db.transaction(fn);
31
+ }
32
+ /** How `createSql(db)` runs queries and transactions. */
33
+ export const driver = { executor, transaction };
34
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH,SAAS,QAAQ,CAAC,EAAmB;IACnC,MAAM,MAAM,GAAI,EAAE,CAAC,CAAC,CAAC,OAA8C,CAAC,MAAM,CAAC;IAC3E,IAAI,MAAM,IAAI,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,UAAU,CAAC;QAAE,OAAO,MAAM,CAAC;IACzG,MAAM,IAAI,KAAK,CAAC,oIAAoI,CAAC,CAAC;AACxJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAmB;IAC1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;QAC5B,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAmD,CAAC;YACjH,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QACtE,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,KAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAkD,CAAC;QAChH,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;IAClE,CAAC,CAAC;AACJ,CAAC;AAED,qGAAqG;AACrG,SAAS,WAAW,CAAI,EAAmB,EAAE,MAAc,EAAE,EAAuC;IAClG,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,MAAM,GAA+B,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,14 +1,18 @@
1
- import { type DefaultTypeMap, type Executor, type Sql } from "@typesql/core";
1
+ import { type DefaultTypeMap, type TransactionalSql } from "@typesql/core";
2
+ import { type DrizzleDatabase } from "./client.js";
2
3
  import type { FromDrizzle, FromDrizzleOptions } from "./from-drizzle.js";
3
4
  export type { FromDrizzle, FromDrizzleOptions, DrizzleColumnTypes } from "./from-drizzle.js";
4
5
  export { pgType } from "./pg-type.js";
5
- export type { Sql, Query, RowType, ParamsType, DefaultTypeMap, TypeMap, Executor } from "@typesql/core";
6
+ export { executor, type DrizzleDatabase } from "./client.js";
7
+ export type { Sql, Query, RowType, ParamsType, DefaultTypeMap, TypeMap, Executor, TransactionalSql } from "@typesql/core";
6
8
  export { NoResultError } from "@typesql/core";
9
+ /** What `createSql<typeof schema>(db)` returns: core's `Sql` over `FromDrizzle<Schema, Opts>`, with `transaction(fn)`. */
10
+ export type DrizzleSql<Schema, TM = DefaultTypeMap, Opts extends FromDrizzleOptions = {}> = TransactionalSql<FromDrizzle<Schema, Opts>, TM>;
7
11
  /**
8
12
  * `createSql` from core with the schema converted from Drizzle definitions:
9
- * `createSql<typeof schema>()`, or `createSql<typeof schema, PgTypeMap>()` for a driver's type map.
10
- * With an `executor` from a driver adapter (`executor(pool)` from `@typesql/pg`), the queries'
11
- * `execute*` methods run on it.
13
+ * `createSql<typeof schema>(db)`, or `createSql<typeof schema, PgTypeMap>(db)` for a driver's type map.
14
+ * The queries' `execute*` methods run on `db` (a Drizzle database or transaction, on node-postgres
15
+ * or postgres.js), and `sql.transaction(fn)` runs `fn` with a `sql` bound to `db.transaction`.
12
16
  */
13
- export declare function createSql<Schema, TM = DefaultTypeMap, Opts extends FromDrizzleOptions = {}>(executor?: Executor): Sql<FromDrizzle<Schema, Opts>, TM>;
17
+ export declare function createSql<Schema, TM = DefaultTypeMap, Opts extends FromDrizzleOptions = {}>(db?: DrizzleDatabase): DrizzleSql<Schema, TM, Opts>;
14
18
  //# 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,cAAc,EAAE,KAAK,QAAQ,EAAE,KAAK,GAAG,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,YAAY,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,EAAE,GAAG,cAAc,EAAE,IAAI,SAAS,kBAAkB,GAAG,EAAE,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAEpJ"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAU,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,YAAY,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC1H,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,0HAA0H;AAC1H,MAAM,MAAM,UAAU,CAAC,MAAM,EAAE,EAAE,GAAG,cAAc,EAAE,IAAI,SAAS,kBAAkB,GAAG,EAAE,IAAI,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;AAE5I;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,EAAE,GAAG,cAAc,EAAE,IAAI,SAAS,kBAAkB,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,eAAe,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAE/I"}
package/dist/index.js CHANGED
@@ -1,13 +1,15 @@
1
- import { createSql as createCoreSql } from "@typesql/core";
1
+ import { createTransactionalSql } from "@typesql/core";
2
+ import { driver } from "./client.js";
2
3
  export { pgType } from "./pg-type.js";
4
+ export { executor } from "./client.js";
3
5
  export { NoResultError } from "@typesql/core";
4
6
  /**
5
7
  * `createSql` from core with the schema converted from Drizzle definitions:
6
- * `createSql<typeof schema>()`, or `createSql<typeof schema, PgTypeMap>()` for a driver's type map.
7
- * With an `executor` from a driver adapter (`executor(pool)` from `@typesql/pg`), the queries'
8
- * `execute*` methods run on it.
8
+ * `createSql<typeof schema>(db)`, or `createSql<typeof schema, PgTypeMap>(db)` for a driver's type map.
9
+ * The queries' `execute*` methods run on `db` (a Drizzle database or transaction, on node-postgres
10
+ * or postgres.js), and `sql.transaction(fn)` runs `fn` with a `sql` bound to `db.transaction`.
9
11
  */
10
- export function createSql(executor) {
11
- return createCoreSql(executor);
12
+ export function createSql(db) {
13
+ return createTransactionalSql(db, driver);
12
14
  }
13
15
  //# 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,EAAgD,MAAM,eAAe,CAAC;AAIzG,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAoE,QAAmB;IAC9G,OAAO,aAAa,CAAgC,QAAQ,CAAC,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAA8C,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,MAAM,EAAwB,MAAM,aAAa,CAAC;AAI3D,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAK9C;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAoE,EAAoB;IAC/G,OAAO,sBAAsB,CAAiD,EAAE,EAAE,MAAM,CAAiC,CAAC;AAC5H,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typesql/drizzle",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
4
4
  "description": "Use Drizzle ORM table definitions as a typesql schema.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,14 +28,17 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@typesql/core": "0.0.4"
31
+ "@typesql/core": "0.1.0"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "drizzle-orm": ">=0.45"
35
35
  },
36
36
  "devDependencies": {
37
- "@typesql/pg": "0.0.4",
37
+ "@types/pg": "^8.23.1",
38
+ "@typesql/pg": "0.1.0",
38
39
  "drizzle-orm": "^0.45.4",
40
+ "pg": "^8.23.1",
41
+ "postgres": "^3.4.9",
39
42
  "typescript": "7.0.2",
40
43
  "vitest": "^5.0.4"
41
44
  },
package/src/client.ts ADDED
@@ -0,0 +1,52 @@
1
+ import type { Executor, SqlDriver } from "@typesql/core";
2
+
3
+ /**
4
+ * What the adapter uses from a Drizzle database (`drizzle(client)` from `drizzle-orm/node-postgres`,
5
+ * `drizzle-orm/postgres-js`, ...) or a transaction from `db.transaction(fn)`.
6
+ */
7
+ export interface DrizzleDatabase {
8
+ readonly _: { readonly session: object };
9
+ transaction<T>(fn: (tx: DrizzleDatabase) => Promise<T>): Promise<T>;
10
+ }
11
+
12
+ /** The driver client a Drizzle session holds: node-postgres' `query` or postgres.js' `unsafe`. */
13
+ interface DriverClient {
14
+ query?(text: string, values: unknown[]): Promise<unknown>;
15
+ unsafe?(text: string, values: unknown[]): PromiseLike<unknown>;
16
+ }
17
+
18
+ /**
19
+ * The driver client under `db`: the `Pool`, `Client` or postgres.js `sql` given to `drizzle()`,
20
+ * or, inside `db.transaction(fn)`, the connection the transaction runs on. Drizzle keeps it as
21
+ * `session.client`.
22
+ */
23
+ function clientOf(db: DrizzleDatabase): DriverClient {
24
+ const client = (db._.session as { readonly client?: DriverClient }).client;
25
+ if (client && (typeof client.unsafe === "function" || typeof client.query === "function")) return client;
26
+ throw new Error("typesql: createSql(db) needs a Drizzle database on node-postgres or postgres.js (its session client has no query or unsafe method)");
27
+ }
28
+
29
+ /**
30
+ * An `Executor` for core's `q.execute()`: runs queries on the driver client under `db`, so rows
31
+ * come back as the driver parses them (Drizzle's column mappers are not involved), and resolves to
32
+ * `{ rows, rowCount }` so `q.executeCount()` works.
33
+ */
34
+ export function executor(db: DrizzleDatabase): Executor {
35
+ return async (text, values) => {
36
+ const client = clientOf(db);
37
+ if (client.unsafe) {
38
+ const result = (await client.unsafe(text, Array.from(values))) as unknown[] & { readonly count?: number | null };
39
+ return { rows: Array.from(result), rowCount: result.count ?? null };
40
+ }
41
+ const result = (await client.query!(text, Array.from(values))) as { rows: unknown[]; rowCount?: number | null };
42
+ return { rows: result.rows, rowCount: result.rowCount ?? null };
43
+ };
44
+ }
45
+
46
+ /** Run `fn` inside `db.transaction(fn)`; Drizzle nests a transaction inside one with a savepoint. */
47
+ function transaction<T>(db: DrizzleDatabase, _depth: number, fn: (tx: DrizzleDatabase) => Promise<T>): Promise<T> {
48
+ return db.transaction(fn);
49
+ }
50
+
51
+ /** How `createSql(db)` runs queries and transactions. */
52
+ export const driver: SqlDriver<DrizzleDatabase> = { executor, transaction };
package/src/index.ts CHANGED
@@ -1,17 +1,22 @@
1
- import { createSql as createCoreSql, type DefaultTypeMap, type Executor, type Sql } from "@typesql/core";
1
+ import { createTransactionalSql, type DefaultTypeMap, type TransactionalSql } from "@typesql/core";
2
+ import { driver, type DrizzleDatabase } from "./client.js";
2
3
  import type { FromDrizzle, FromDrizzleOptions } from "./from-drizzle.js";
3
4
 
4
5
  export type { FromDrizzle, FromDrizzleOptions, DrizzleColumnTypes } from "./from-drizzle.js";
5
6
  export { pgType } from "./pg-type.js";
6
- export type { Sql, Query, RowType, ParamsType, DefaultTypeMap, TypeMap, Executor } from "@typesql/core";
7
+ export { executor, type DrizzleDatabase } from "./client.js";
8
+ export type { Sql, Query, RowType, ParamsType, DefaultTypeMap, TypeMap, Executor, TransactionalSql } from "@typesql/core";
7
9
  export { NoResultError } from "@typesql/core";
8
10
 
11
+ /** What `createSql<typeof schema>(db)` returns: core's `Sql` over `FromDrizzle<Schema, Opts>`, with `transaction(fn)`. */
12
+ export type DrizzleSql<Schema, TM = DefaultTypeMap, Opts extends FromDrizzleOptions = {}> = TransactionalSql<FromDrizzle<Schema, Opts>, TM>;
13
+
9
14
  /**
10
15
  * `createSql` from core with the schema converted from Drizzle definitions:
11
- * `createSql<typeof schema>()`, or `createSql<typeof schema, PgTypeMap>()` for a driver's type map.
12
- * With an `executor` from a driver adapter (`executor(pool)` from `@typesql/pg`), the queries'
13
- * `execute*` methods run on it.
16
+ * `createSql<typeof schema>(db)`, or `createSql<typeof schema, PgTypeMap>(db)` for a driver's type map.
17
+ * The queries' `execute*` methods run on `db` (a Drizzle database or transaction, on node-postgres
18
+ * or postgres.js), and `sql.transaction(fn)` runs `fn` with a `sql` bound to `db.transaction`.
14
19
  */
15
- export function createSql<Schema, TM = DefaultTypeMap, Opts extends FromDrizzleOptions = {}>(executor?: Executor): Sql<FromDrizzle<Schema, Opts>, TM> {
16
- return createCoreSql<FromDrizzle<Schema, Opts>, TM>(executor);
20
+ export function createSql<Schema, TM = DefaultTypeMap, Opts extends FromDrizzleOptions = {}>(db?: DrizzleDatabase): DrizzleSql<Schema, TM, Opts> {
21
+ return createTransactionalSql<FromDrizzle<Schema, Opts>, TM, DrizzleDatabase>(db, driver) as DrizzleSql<Schema, TM, Opts>;
17
22
  }