@typesql/drizzle 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,25 @@
1
1
  # @typesql/drizzle
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
+ - `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`.
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies:
21
+ - @typesql/core@0.1.0
22
+
3
23
  ## 0.0.4
4
24
 
5
25
  ### Patch Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @typesql/drizzle
2
2
 
3
- Use your Drizzle ORM schema as a typesql schema. `FromDrizzle<typeof schema>` turns
3
+ Use your Drizzle ORM schema as a TypeSQL schema. `FromDrizzle<typeof schema>` turns
4
4
  `pgTable`, `pgView`, `pgMaterializedView`, `pgEnum` and `pgSchema` definitions into the
5
5
  `DB` type that `createSql` expects, entirely at the type level: no code generation, and the
6
6
  SQL you write is checked against the same tables Drizzle manages.
@@ -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
@@ -74,7 +113,7 @@ tables (`FromDrizzle<{ users: typeof users; posts: typeof posts }>`).
74
113
 
75
114
  ## What gets converted
76
115
 
77
- | Drizzle | typesql |
116
+ | Drizzle | TypeSQL |
78
117
  |---|---|
79
118
  | `pgTable("users", …)` | `DB["users"]`, keyed by the SQL table name, not the export name |
80
119
  | `displayName: text("display_name")` | column `display_name`; columns without an explicit name use the key |
@@ -89,7 +128,7 @@ tables (`FromDrizzle<{ users: typeof users; posts: typeof posts }>`).
89
128
  ## Column types
90
129
 
91
130
  The Postgres type comes from Drizzle's column kind. Drizzle's `mode` options change the JS
92
- value Drizzle produces, but typesql queries go straight to the driver, so the row type comes
131
+ value Drizzle produces, but TypeSQL queries go straight to the driver, so the row type comes
93
132
  from the type map: `bigint({ mode: "number" })` is `int8`, a `string` under node-postgres.
94
133
 
95
134
  | Drizzle | Postgres |
@@ -118,7 +157,7 @@ from the type map: `bigint({ mode: "number" })` is `int8`, a `string` under node
118
157
  | `customType(…)` | `unknown`, unless pinned with `pgType` |
119
158
  | `.array()`, `.array().array()` | `T[]`, `T[][]` |
120
159
 
121
- Types typesql has no TS mapping for (`geometry`, `vector`, …) read as `unknown` unless your
160
+ Types TypeSQL has no TS mapping for (`geometry`, `vector`, …) read as `unknown` unless your
122
161
  type map has an entry for them.
123
162
 
124
163
  ### `timestamp` with time zone, and other types Drizzle's types do not record
@@ -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,14 +202,14 @@ 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
 
170
209
  ## Limitations
171
210
 
172
211
  - **Generated-always columns** (`generatedAlwaysAs`, `generatedAlwaysAsIdentity`) are treated
173
- as columns with a default. typesql has no read-only columns, so an `INSERT` that sets one
212
+ as columns with a default. TypeSQL has no read-only columns, so an `INSERT` that sets one
174
213
  type-checks but fails in Postgres (unless `OVERRIDING SYSTEM VALUE` for identities).
175
214
  - **`$onUpdate` / `$onUpdateFn`** mark the column as having a default in Drizzle's types, with
176
215
  no way to tell them from a SQL default, so such a column is optional in `INSERT` even
@@ -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"}
@@ -150,7 +150,7 @@ type Flat<T> = {
150
150
  [K in keyof T]: T[K];
151
151
  } & {};
152
152
  /**
153
- * A typesql schema from Drizzle `pg-core` definitions: `FromDrizzle<typeof schema>` with
153
+ * A TypeSQL schema from Drizzle `pg-core` definitions: `FromDrizzle<typeof schema>` with
154
154
  * `import * as schema from "./schema"`. Also accepts a record of tables or a single table.
155
155
  *
156
156
  * Keys are SQL names (tables, columns, `pgSchema` namespaces); views become `View<…>`;
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,7 +1,7 @@
1
1
  {
2
2
  "name": "@typesql/drizzle",
3
- "version": "0.0.4",
4
- "description": "Use Drizzle ORM table definitions as a typesql schema.",
3
+ "version": "0.1.1",
4
+ "description": "Use Drizzle ORM table definitions as a TypeSQL schema.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -28,14 +28,17 @@
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
  "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.1",
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 };
@@ -145,7 +145,7 @@ type Build<S, Opts, E = Enums<S>> =
145
145
  type Flat<T> = { [K in keyof T]: T[K] } & {};
146
146
 
147
147
  /**
148
- * A typesql schema from Drizzle `pg-core` definitions: `FromDrizzle<typeof schema>` with
148
+ * A TypeSQL schema from Drizzle `pg-core` definitions: `FromDrizzle<typeof schema>` with
149
149
  * `import * as schema from "./schema"`. Also accepts a record of tables or a single table.
150
150
  *
151
151
  * Keys are SQL names (tables, columns, `pgSchema` namespaces); views become `View<…>`;
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
  }