@typesql/kysely 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/kysely
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
+ - 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/kysely
2
2
 
3
- Use the `DB` interface you already have for [Kysely](https://kysely.dev) as a typesql schema:
3
+ Use the `DB` interface you already have for [Kysely](https://kysely.dev) as a TypeSQL schema:
4
4
  the one generated by [kysely-codegen](https://github.com/RobinBlomberg/kysely-codegen), by
5
5
  [prisma-kysely](https://github.com/valtyr/prisma-kysely), or written by hand. The conversion is
6
6
  type-level only; nothing is generated and no database is contacted.
@@ -10,10 +10,10 @@ pnpm add @typesql/core @typesql/kysely kysely
10
10
  ```
11
11
 
12
12
  ```ts
13
- import { createSql, query } from "@typesql/kysely";
13
+ import { createSql } from "@typesql/kysely";
14
14
  import type { DB } from "./db"; // kysely-codegen output
15
15
 
16
- const sql = createSql<DB>();
16
+ const sql = createSql<DB>(db); // db: your Kysely<DB> instance, or a Transaction<DB>
17
17
 
18
18
  const q = sql(
19
19
  `SELECT u.id, u.email, p.title, p.views
@@ -23,18 +23,23 @@ const q = sql(
23
23
  );
24
24
  // ^? Query<{ id: number; email: string; title: string; views: string }, [number | null, boolean | null]>
25
25
 
26
- const rows = await query(db, q); // db: Kysely<DB> or a Transaction<DB>
26
+ const rows = await q.execute();
27
+
28
+ await sql.transaction(async (tx) => {
29
+ await tx("UPDATE posts SET published = true WHERE author_id = $1", 1).execute();
30
+ });
27
31
  ```
28
32
 
29
33
  ## API
30
34
 
31
35
  | Export | What it is |
32
36
  |---|---|
33
- | `createSql<DB, TM = DefaultTypeMap, Overrides = {}, Options = {}>(db?, options?)` | core's `createSql<FromKysely<DB, Overrides, Options>, TM>()`; `{ rowKeys: "camelCase" }` gives `CamelCasePlugin`-style row keys |
34
- | `FromKysely<DB, Overrides = {}, Options = {}>` | the converted schema type, for use with core's `createSql<Schema, TM>()` or the adapters' `createSql<Schema>()` |
35
- | `query(db, q)` | runs a typesql `Query` through Kysely, `Promise<Row[]>` |
36
- | `execute(db, q)` | runs a statement, `Promise<number>` (`numAffectedRows`; for other statements the number of rows returned, 0 for DDL) |
37
- | `executor(db)` | an `Executor` for `q.execute()` and `q.executeCount()`, also bypassing plugins |
37
+ | `createSql<DB, TM = DefaultTypeMap, Overrides = {}, Options = {}>(db, options?)` | core's `createSql<FromKysely<DB, Overrides, Options>, TM>()` with the queries running on `db`; `{ rowKeys: "camelCase" }` gives `CamelCasePlugin`-style row keys |
38
+ | `q.execute()`, `q.executeTakeFirst()`, `q.executeTakeFirstOrThrow()`, `q.executeCount()` | `Promise<Row[]>`, `Promise<Row \| undefined>`, `Promise<Row>` (`NoResultError` on 0 rows), `Promise<number>` (`numAffectedRows`; for other statements the number of rows returned, 0 for DDL) |
39
+ | `sql.transaction(fn)` | `db.transaction().execute(...)` with `tx` bound to the transaction; on a `Transaction`, and for `tx.transaction(fn)`, a savepoint |
40
+ | `FromKysely<DB, Overrides = {}, Options = {}>` | the converted schema type, for use with core's `createSql<Schema, TM>()` or the adapters' `createSql<Schema>(client)` |
41
+ | `KyselySql<DB, TM, Overrides, Options, Keys>` | the type `createSql` returns |
42
+ | `executor(db)` | an `Executor` for `q.execute(executor)` and core's `createSql(executor)`, also bypassing plugins |
38
43
  | `InferColumn<T>` | the descriptor inferred for one Kysely column type (handy to check a mapping) |
39
44
  | `SnakeCase<S>` | `CamelCasePlugin`'s default camelCase → snake_case mapping, at the type level |
40
45
  | `KyselyOverrides`, `TableOverride`, `ColumnOverride`, `KyselyOptions`, `KyselyExecutor` | parameter types |
@@ -48,19 +53,20 @@ import type { PgTypeMap } from "@typesql/pg";
48
53
  import { createSql, type FromKysely } from "@typesql/kysely";
49
54
  import { createSql as createCoreSql } from "@typesql/core";
50
55
 
51
- const sql = createSql<DB, PgTypeMap>();
52
- const same = createCoreSql<FromKysely<DB>, PgTypeMap>();
56
+ const sql = createSql<DB, PgTypeMap>(db);
57
+ const same = createCoreSql<FromKysely<DB>, PgTypeMap>(); // types only, no client
53
58
  ```
54
59
 
55
- `query` and `execute` send `CompiledQuery.raw(q.text, q.values)` through
56
- `db.withoutPlugins().executeQuery(...)`. Plugins are bypassed on purpose: typesql's row types
60
+ Queries are sent as `CompiledQuery.raw(q.text, q.values)` through
61
+ `db.withoutPlugins().executeQuery(...)`. Plugins are bypassed on purpose: TypeSQL's row types
57
62
  describe what Postgres returns (`created_at`), and a result transformer such as
58
- `CamelCasePlugin` would rename the keys (use `{ rowKeys: "camelCase" }` for camelCase rows). Logging, the dialect and the connection pool are
59
- unaffected. Any `sql(...)` result can also be run with `@typesql/pg` directly on the pool.
63
+ `CamelCasePlugin` would rename the keys (use `{ rowKeys: "camelCase" }` for camelCase rows).
64
+ Logging, the dialect and the connection pool are unaffected. Inside a Kysely transaction,
65
+ `createSql<DB>(trx)` binds a `sql` to it, so builder and SQL queries share the transaction.
60
66
 
61
67
  ## How columns are converted
62
68
 
63
- Kysely describes a column by its TS type; typesql needs a Postgres type name. The TS shape
69
+ Kysely describes a column by its TS type; TypeSQL needs a Postgres type name. The TS shape
64
70
  is read back as follows (for `ColumnType<S, I, U>` the select type `S` decides, the insert type
65
71
  `I` breaks ties):
66
72
 
@@ -104,7 +110,7 @@ const sql = createSql<DB, DefaultTypeMap, {
104
110
  "auth.users": { id: "uuid" };
105
111
  active_users: { $view: true }; // a view: INSERT/UPDATE/DELETE are rejected
106
112
  $types: { mood: Mood; "auth.role": AuthRole }; // enum names, see below
107
- }>();
113
+ }>(db);
108
114
  ```
109
115
 
110
116
  A descriptor may set any of `type`, `nullable` and `hasDefault`; the others stay inferred.
@@ -136,7 +142,7 @@ under `$types` and every column whose values are **exactly** that union gets the
136
142
  ```ts
137
143
  import type { Mood, AuthRole } from "./db"; // kysely-codegen exports one alias per enum
138
144
 
139
- createSql<DB, DefaultTypeMap, { $types: { mood: Mood; "auth.role": AuthRole } }>();
145
+ createSql<DB, DefaultTypeMap, { $types: { mood: Mood; "auth.role": AuthRole } }>(db);
140
146
  ```
141
147
 
142
148
  If two `$types` entries have the same values the column keeps its derived name; set the column's
@@ -152,7 +158,7 @@ back to the database's snake_case names the way `CamelCasePlugin` does by defaul
152
158
  `created_at`, `userID` → `user_id`), so the SQL you write and the rows you get use the real names:
153
159
 
154
160
  ```ts
155
- const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>();
161
+ const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>(db);
156
162
  const q = sql("SELECT author_id, created_at FROM blog_posts WHERE id = $1", 1);
157
163
  // ^? Query<{ author_id: number; created_at: Date }, [number | null]>
158
164
  ```
@@ -181,7 +187,7 @@ const post = await sql("SELECT author_id, created_at FROM blog_posts WHERE id =
181
187
  `unknown` either way; only `INSERT` stops requiring the column. Override with
182
188
  `{ nullable: false }` to get the not-null check back.
183
189
  - **JSON shapes are not kept.** `JSONColumnType<{ a: number }>` becomes `jsonb`, read as
184
- `unknown` (the type map decides; typesql has no per-column TS types).
190
+ `unknown` (the type map decides; TypeSQL has no per-column TS types).
185
191
  - **Views look like tables.** Kysely interfaces do not mark views; mark them with `$view: true`
186
192
  to have writes rejected.
187
193
  - **Defaults come from `Generated`/`GeneratedAlways` only.** A column with a default that the
package/dist/client.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { CompiledQuery, type QueryResult } from "kysely";
2
- import { type Executor, type Query, type RowType } from "@typesql/core";
2
+ import { type Executor, type SqlDriver } from "@typesql/core";
3
3
  /**
4
- * What the helpers use from a `Kysely<DB>` or `Transaction<DB>`. Queries run through
5
- * `withoutPlugins()`: typesql's row types describe what the driver returns, so result
4
+ * What the adapter uses from a `Kysely<DB>` or `Transaction<DB>`. Queries run through
5
+ * `withoutPlugins()`: TypeSQL's row types describe what the driver returns, so result
6
6
  * transformers such as `CamelCasePlugin` must not rename the columns (`createSql(db,
7
7
  * { rowKeys: "camelCase" })` renames the top-level keys instead, in the types too).
8
8
  */
@@ -10,19 +10,16 @@ export interface KyselyExecutor {
10
10
  withoutPlugins(): {
11
11
  executeQuery<R>(query: CompiledQuery<R>): Promise<QueryResult<R>>;
12
12
  };
13
+ transaction(): {
14
+ execute<T>(fn: (trx: KyselyExecutor) => Promise<T>): Promise<T>;
15
+ };
16
+ readonly isTransaction: boolean;
13
17
  }
14
- type AnyQuery = Query<unknown, readonly unknown[]>;
15
18
  /**
16
19
  * An `Executor` for core's `q.execute()`: runs queries on a Kysely instance (or transaction),
17
20
  * without its plugins, and resolves to `{ rows, rowCount }` so `q.executeCount()` works.
18
21
  */
19
22
  export declare function executor(db: KyselyExecutor): Executor;
20
- /** Run a typesql query on a Kysely instance (or transaction) and return its rows, typed from the query. */
21
- export declare function query<Q extends AnyQuery>(db: KyselyExecutor, q: Q): Promise<RowType<Q>[]>;
22
- /**
23
- * Run a statement for its side effect and return its row count: `numAffectedRows` for
24
- * INSERT/UPDATE/DELETE/MERGE, otherwise the number of rows returned (0 for DDL).
25
- */
26
- export declare function execute(db: KyselyExecutor, q: AnyQuery): Promise<number>;
27
- export {};
23
+ /** How `createSql(db)` runs queries and transactions. */
24
+ export declare const driver: SqlDriver<KyselyExecutor>;
28
25
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAW,KAAK,QAAQ,EAAE,KAAK,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,cAAc,IAAI;QAAE,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC;CACzF;AAED,KAAK,QAAQ,GAAG,KAAK,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC;AAcnD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,cAAc,GAAG,QAAQ,CAKrD;AAED,2GAA2G;AAC3G,wBAAsB,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAG/F;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAE9E"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,cAAc,IAAI;QAAE,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC;IACxF,WAAW,IAAI;QAAE,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC;IACnF,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAcD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,cAAc,GAAG,QAAQ,CAKrD;AAWD,yDAAyD;AACzD,eAAO,MAAM,MAAM,EAAE,SAAS,CAAC,cAAc,CAA6B,CAAC"}
package/dist/client.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CompiledQuery } from "kysely";
2
- import { mapRows } from "@typesql/core";
2
+ import { runTransaction } from "@typesql/core";
3
3
  function run(db, text, values) {
4
4
  return db.withoutPlugins().executeQuery(CompiledQuery.raw(text, Array.from(values)));
5
5
  }
@@ -20,16 +20,15 @@ export function executor(db) {
20
20
  return { rows: result.rows, rowCount: rowCount(result) };
21
21
  };
22
22
  }
23
- /** Run a typesql query on a Kysely instance (or transaction) and return its rows, typed from the query. */
24
- export async function query(db, q) {
25
- const result = await run(db, q.text, q.values);
26
- return mapRows(q, result.rows);
27
- }
28
23
  /**
29
- * Run a statement for its side effect and return its row count: `numAffectedRows` for
30
- * INSERT/UPDATE/DELETE/MERGE, otherwise the number of rows returned (0 for DDL).
24
+ * Run `fn` inside `db.transaction().execute()`. A Kysely `Transaction` cannot start another one,
25
+ * so inside one `fn` runs in a savepoint.
31
26
  */
32
- export async function execute(db, q) {
33
- return rowCount(await run(db, q.text, q.values));
27
+ function transaction(db, depth, fn) {
28
+ if (!db.isTransaction)
29
+ return db.transaction().execute(fn);
30
+ return runTransaction((statement) => run(db, statement, []), () => fn(db), { savepoint: `typesql_${depth + 1}` });
34
31
  }
32
+ /** How `createSql(db)` runs queries and transactions. */
33
+ export const driver = { executor, transaction };
35
34
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoB,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,OAAO,EAA2C,MAAM,eAAe,CAAC;AAcjF,SAAS,GAAG,CAAI,EAAkB,EAAE,IAAY,EAAE,MAA0B;IAC1E,OAAO,EAAE,CAAC,cAAc,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAqB,CAAC,CAAC;AAC3G,CAAC;AAED;;;GAGG;AACH,SAAS,QAAQ,CAAC,MAA4B;IAC5C,OAAO,MAAM,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;AACpG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAkB;IACzC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAU,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;IAC3D,CAAC,CAAC;AACJ,CAAC;AAED,2GAA2G;AAC3G,MAAM,CAAC,KAAK,UAAU,KAAK,CAAqB,EAAkB,EAAE,CAAI;IACtE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACxD,OAAO,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAkB,EAAE,CAAW;IAC3D,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5D,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoB,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,cAAc,EAAiC,MAAM,eAAe,CAAC;AAc9E,SAAS,GAAG,CAAI,EAAkB,EAAE,IAAY,EAAE,MAA0B;IAC1E,OAAO,EAAE,CAAC,cAAc,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAqB,CAAC,CAAC;AAC3G,CAAC;AAED;;;GAGG;AACH,SAAS,QAAQ,CAAC,MAA4B;IAC5C,OAAO,MAAM,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;AACpG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAkB;IACzC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAU,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;IAC3D,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAI,EAAkB,EAAE,KAAa,EAAE,EAAuC;IAChG,IAAI,CAAC,EAAE,CAAC,aAAa;QAAE,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3D,OAAO,cAAc,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,WAAW,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;AACpH,CAAC;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,MAAM,GAA8B,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { ColDesc, PgScalarName, View } from "@typesql/core";
2
2
  /**
3
3
  * Converting a Kysely `DB` interface (kysely-codegen, prisma-kysely or hand-written) into a
4
- * typesql schema. Kysely describes columns with TS types, typesql with Postgres type names, so
4
+ * TypeSQL schema. Kysely describes columns with TS types, TypeSQL with Postgres type names, so
5
5
  * the conversion reads the TS shape back into a type name. That is lossy (`number` may be
6
6
  * `int4` or `float8`); `Overrides` pins the exact type per column.
7
7
  *
@@ -46,10 +46,10 @@ export type KyselyOptions = {
46
46
  readonly camelCase?: boolean;
47
47
  };
48
48
  /**
49
- * A typesql schema from a Kysely `DB` interface.
49
+ * A TypeSQL schema from a Kysely `DB` interface.
50
50
  *
51
51
  * type Schema = FromKysely<DB, { users: { id: "int8" } }>;
52
- * const sql = createSql<Schema>(); // typesql's createSql
52
+ * const sql = createSql<Schema>(); // TypeSQL's createSql
53
53
  *
54
54
  * `"auth.users"` becomes `Schema["auth"]["users"]`; `"public.users"` becomes `Schema["users"]`.
55
55
  * String-literal unions become enums registered in `Schema["$types"]` (see `KyselyOverrides`).
package/dist/index.d.ts CHANGED
@@ -1,27 +1,30 @@
1
- import { type DefaultTypeMap, type Sql } from "@typesql/core";
1
+ import { type DefaultTypeMap, type RowKeys, type TransactionalSql } from "@typesql/core";
2
2
  import { type KyselyExecutor } from "./client.js";
3
3
  import type { FromKysely, KyselyOptions, KyselyOverrides } from "./from-kysely.js";
4
- export { NoResultError, type Executor } from "@typesql/core";
4
+ export { NoResultError, type Executor, type TransactionalSql } from "@typesql/core";
5
5
  export type { FromKysely, KyselyOverrides, KyselyOptions, TableOverride, ColumnOverride, InferColumn, SnakeCase } from "./from-kysely.js";
6
- export { query, execute, executor, type KyselyExecutor } from "./client.js";
6
+ export { executor, type KyselyExecutor } from "./client.js";
7
+ /** What `createSql<DB>(db)` returns: core's `Sql` over `FromKysely<DB, ...>`, with `transaction(fn)`. */
8
+ export type KyselySql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}, Keys extends RowKeys = "preserve"> = TransactionalSql<FromKysely<DB, Overrides, Options>, TM, Keys>;
7
9
  /**
8
10
  * `createSql` from core with a Kysely `DB` interface as the schema:
9
- * `createSql<DB>()` is `createSql<FromKysely<DB>, DefaultTypeMap>()`.
11
+ * `createSql<DB>(db)` is `createSql<FromKysely<DB>, DefaultTypeMap>()` bound to `db`.
10
12
  *
11
- * const sql = createSql<DB>();
12
- * const sql = createSql<DB, PgTypeMap, { users: { id: "int8" } }>();
13
- * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>();
13
+ * const sql = createSql<DB>(db);
14
+ * const sql = createSql<DB, PgTypeMap, { users: { id: "int8" } }>(db);
15
+ * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>(db);
14
16
  *
15
- * With a `db` (a `Kysely` instance or transaction), the queries' `execute*` methods run on it,
16
- * bypassing its plugins. `{ rowKeys: "camelCase" }` camelCases the rows' top-level keys as
17
- * `CamelCasePlugin` does, in the types and at runtime, without touching JSON values:
17
+ * The queries' `execute*` methods run on `db` (a `Kysely` instance or transaction), bypassing
18
+ * its plugins, and `sql.transaction(fn)` runs `fn` with a `sql` bound to one transaction.
19
+ * `{ rowKeys: "camelCase" }` camelCases the rows' top-level keys as `CamelCasePlugin` does, in
20
+ * the types and at runtime, without touching JSON values:
18
21
  *
19
22
  * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>(db, { rowKeys: "camelCase" });
20
23
  */
21
24
  export declare function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(db: KyselyExecutor | undefined, options: {
22
25
  readonly rowKeys: "camelCase";
23
- }): Sql<FromKysely<DB, Overrides, Options>, TM, "camelCase">;
26
+ }): KyselySql<DB, TM, Overrides, Options, "camelCase">;
24
27
  export declare function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(db?: KyselyExecutor, options?: {
25
28
  readonly rowKeys?: "preserve";
26
- }): Sql<FromKysely<DB, Overrides, Options>, TM>;
29
+ }): KyselySql<DB, TM, Overrides, Options>;
27
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,cAAc,EAAgB,KAAK,GAAG,EAAmB,MAAM,eAAe,CAAC;AACzH,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1I,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,cAAc,EAAE,SAAS,SAAS,eAAe,GAAG,EAAE,EAAE,OAAO,SAAS,aAAa,GAAG,EAAE,EAC3H,EAAE,EAAE,cAAc,GAAG,SAAS,EAC9B,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GACzC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;AAC5D,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,cAAc,EAAE,SAAS,SAAS,eAAe,GAAG,EAAE,EAAE,OAAO,SAAS,aAAa,GAAG,EAAE,EAC3H,EAAE,CAAC,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAA;CAAE,GAC1C,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,cAAc,EAAE,KAAK,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAClI,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACpF,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1I,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5D,yGAAyG;AACzG,MAAM,MAAM,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,cAAc,EAAE,SAAS,SAAS,eAAe,GAAG,EAAE,EAAE,OAAO,SAAS,aAAa,GAAG,EAAE,EAAE,IAAI,SAAS,OAAO,GAAG,UAAU,IAC1J,gBAAgB,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;AAEjE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,cAAc,EAAE,SAAS,SAAS,eAAe,GAAG,EAAE,EAAE,OAAO,SAAS,aAAa,GAAG,EAAE,EAC3H,EAAE,EAAE,cAAc,GAAG,SAAS,EAC9B,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GACzC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AACtD,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,cAAc,EAAE,SAAS,SAAS,eAAe,GAAG,EAAE,EAAE,OAAO,SAAS,aAAa,GAAG,EAAE,EAC3H,EAAE,CAAC,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAA;CAAE,GAC1C,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
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, execute, executor } from "./client.js";
4
+ export { executor } from "./client.js";
5
5
  export function createSql(db, options) {
6
- return createCoreSql(db && executor(db), options);
6
+ return createTransactionalSql(db, driver, options);
7
7
  }
8
8
  //# 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,EAAgE,MAAM,eAAe,CAAC;AACzH,OAAO,EAAE,QAAQ,EAAuB,MAAM,aAAa,CAAC;AAG5D,OAAO,EAAE,aAAa,EAAiB,MAAM,eAAe,CAAC;AAE7D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAuB,MAAM,aAAa,CAAC;AAwB5E,MAAM,UAAU,SAAS,CACvB,EAAmB,EACnB,OAAoB;IAEpB,OAAO,aAAa,CAAyC,EAAE,IAAI,QAAQ,CAAC,EAAE,CAAC,EAAE,OAA4C,CAAC,CAAC;AACjI,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAA6E,MAAM,eAAe,CAAC;AAClI,OAAO,EAAE,MAAM,EAAuB,MAAM,aAAa,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAwC,MAAM,eAAe,CAAC;AAEpF,OAAO,EAAE,QAAQ,EAAuB,MAAM,aAAa,CAAC;AA6B5D,MAAM,UAAU,SAAS,CACvB,EAAmB,EACnB,OAAoB;IAEpB,OAAO,sBAAsB,CAAyD,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAC7G,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@typesql/kysely",
3
- "version": "0.0.4",
4
- "description": "Use Kysely database interfaces (kysely-codegen, prisma-kysely) as a typesql schema.",
3
+ "version": "0.1.1",
4
+ "description": "Use Kysely database interfaces (kysely-codegen, prisma-kysely) as a TypeSQL schema.",
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
  "kysely": ">=0.27"
package/src/client.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  import { CompiledQuery, type QueryResult } from "kysely";
2
- import { mapRows, type Executor, type Query, type RowType } from "@typesql/core";
2
+ import { runTransaction, type Executor, type SqlDriver } from "@typesql/core";
3
3
 
4
4
  /**
5
- * What the helpers use from a `Kysely<DB>` or `Transaction<DB>`. Queries run through
6
- * `withoutPlugins()`: typesql's row types describe what the driver returns, so result
5
+ * What the adapter uses from a `Kysely<DB>` or `Transaction<DB>`. Queries run through
6
+ * `withoutPlugins()`: TypeSQL's row types describe what the driver returns, so result
7
7
  * transformers such as `CamelCasePlugin` must not rename the columns (`createSql(db,
8
8
  * { rowKeys: "camelCase" })` renames the top-level keys instead, in the types too).
9
9
  */
10
10
  export interface KyselyExecutor {
11
11
  withoutPlugins(): { executeQuery<R>(query: CompiledQuery<R>): Promise<QueryResult<R>> };
12
+ transaction(): { execute<T>(fn: (trx: KyselyExecutor) => Promise<T>): Promise<T> };
13
+ readonly isTransaction: boolean;
12
14
  }
13
15
 
14
- type AnyQuery = Query<unknown, readonly unknown[]>;
15
-
16
16
  function run<R>(db: KyselyExecutor, text: string, values: readonly unknown[]): Promise<QueryResult<R>> {
17
17
  return db.withoutPlugins().executeQuery(CompiledQuery.raw(text, Array.from(values)) as CompiledQuery<R>);
18
18
  }
@@ -36,16 +36,14 @@ export function executor(db: KyselyExecutor): Executor {
36
36
  };
37
37
  }
38
38
 
39
- /** Run a typesql query on a Kysely instance (or transaction) and return its rows, typed from the query. */
40
- export async function query<Q extends AnyQuery>(db: KyselyExecutor, q: Q): Promise<RowType<Q>[]> {
41
- const result = await run<unknown>(db, q.text, q.values);
42
- return mapRows(q, result.rows);
43
- }
44
-
45
39
  /**
46
- * Run a statement for its side effect and return its row count: `numAffectedRows` for
47
- * INSERT/UPDATE/DELETE/MERGE, otherwise the number of rows returned (0 for DDL).
40
+ * Run `fn` inside `db.transaction().execute()`. A Kysely `Transaction` cannot start another one,
41
+ * so inside one `fn` runs in a savepoint.
48
42
  */
49
- export async function execute(db: KyselyExecutor, q: AnyQuery): Promise<number> {
50
- return rowCount(await run<unknown>(db, q.text, q.values));
43
+ function transaction<T>(db: KyselyExecutor, depth: number, fn: (trx: KyselyExecutor) => Promise<T>): Promise<T> {
44
+ if (!db.isTransaction) return db.transaction().execute(fn);
45
+ return runTransaction((statement) => run(db, statement, []), () => fn(db), { savepoint: `typesql_${depth + 1}` });
51
46
  }
47
+
48
+ /** How `createSql(db)` runs queries and transactions. */
49
+ export const driver: SqlDriver<KyselyExecutor> = { executor, transaction };
@@ -2,7 +2,7 @@ import type { ColDesc, PgScalarName, View } from "@typesql/core";
2
2
 
3
3
  /**
4
4
  * Converting a Kysely `DB` interface (kysely-codegen, prisma-kysely or hand-written) into a
5
- * typesql schema. Kysely describes columns with TS types, typesql with Postgres type names, so
5
+ * TypeSQL schema. Kysely describes columns with TS types, TypeSQL with Postgres type names, so
6
6
  * the conversion reads the TS shape back into a type name. That is lossy (`number` may be
7
7
  * `int4` or `float8`); `Overrides` pins the exact type per column.
8
8
  *
@@ -48,10 +48,10 @@ export type KyselyOverrides = { readonly [table: string]: TableOverride };
48
48
  export type KyselyOptions = { readonly camelCase?: boolean };
49
49
 
50
50
  /**
51
- * A typesql schema from a Kysely `DB` interface.
51
+ * A TypeSQL schema from a Kysely `DB` interface.
52
52
  *
53
53
  * type Schema = FromKysely<DB, { users: { id: "int8" } }>;
54
- * const sql = createSql<Schema>(); // typesql's createSql
54
+ * const sql = createSql<Schema>(); // TypeSQL's createSql
55
55
  *
56
56
  * `"auth.users"` becomes `Schema["auth"]["users"]`; `"public.users"` becomes `Schema["users"]`.
57
57
  * String-literal unions become enums registered in `Schema["$types"]` (see `KyselyOverrides`).
package/src/index.ts CHANGED
@@ -1,36 +1,41 @@
1
- import { createSql as createCoreSql, type DefaultTypeMap, type RowKeys, type Sql, type SqlOptions } from "@typesql/core";
2
- import { executor, type KyselyExecutor } from "./client.js";
1
+ import { createTransactionalSql, type DefaultTypeMap, type RowKeys, type SqlOptions, type TransactionalSql } from "@typesql/core";
2
+ import { driver, type KyselyExecutor } from "./client.js";
3
3
  import type { FromKysely, KyselyOptions, KyselyOverrides } from "./from-kysely.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 { FromKysely, KyselyOverrides, KyselyOptions, TableOverride, ColumnOverride, InferColumn, SnakeCase } from "./from-kysely.js";
7
- export { query, execute, executor, type KyselyExecutor } from "./client.js";
7
+ export { executor, type KyselyExecutor } from "./client.js";
8
+
9
+ /** What `createSql<DB>(db)` returns: core's `Sql` over `FromKysely<DB, ...>`, with `transaction(fn)`. */
10
+ export type KyselySql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}, Keys extends RowKeys = "preserve"> =
11
+ TransactionalSql<FromKysely<DB, Overrides, Options>, TM, Keys>;
8
12
 
9
13
  /**
10
14
  * `createSql` from core with a Kysely `DB` interface as the schema:
11
- * `createSql<DB>()` is `createSql<FromKysely<DB>, DefaultTypeMap>()`.
15
+ * `createSql<DB>(db)` is `createSql<FromKysely<DB>, DefaultTypeMap>()` bound to `db`.
12
16
  *
13
- * const sql = createSql<DB>();
14
- * const sql = createSql<DB, PgTypeMap, { users: { id: "int8" } }>();
15
- * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>();
17
+ * const sql = createSql<DB>(db);
18
+ * const sql = createSql<DB, PgTypeMap, { users: { id: "int8" } }>(db);
19
+ * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>(db);
16
20
  *
17
- * With a `db` (a `Kysely` instance or transaction), the queries' `execute*` methods run on it,
18
- * bypassing its plugins. `{ rowKeys: "camelCase" }` camelCases the rows' top-level keys as
19
- * `CamelCasePlugin` does, in the types and at runtime, without touching JSON values:
21
+ * The queries' `execute*` methods run on `db` (a `Kysely` instance or transaction), bypassing
22
+ * its plugins, and `sql.transaction(fn)` runs `fn` with a `sql` bound to one transaction.
23
+ * `{ rowKeys: "camelCase" }` camelCases the rows' top-level keys as `CamelCasePlugin` does, in
24
+ * the types and at runtime, without touching JSON values:
20
25
  *
21
26
  * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>(db, { rowKeys: "camelCase" });
22
27
  */
23
28
  export function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(
24
29
  db: KyselyExecutor | undefined,
25
30
  options: { readonly rowKeys: "camelCase" },
26
- ): Sql<FromKysely<DB, Overrides, Options>, TM, "camelCase">;
31
+ ): KyselySql<DB, TM, Overrides, Options, "camelCase">;
27
32
  export function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(
28
33
  db?: KyselyExecutor,
29
34
  options?: { readonly rowKeys?: "preserve" },
30
- ): Sql<FromKysely<DB, Overrides, Options>, TM>;
35
+ ): KyselySql<DB, TM, Overrides, Options>;
31
36
  export function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(
32
37
  db?: KyselyExecutor,
33
38
  options?: SqlOptions,
34
- ): Sql<FromKysely<DB, Overrides, Options>, TM, RowKeys> {
35
- return createCoreSql<FromKysely<DB, Overrides, Options>, TM>(db && executor(db), options as { readonly rowKeys: "camelCase" });
39
+ ): KyselySql<DB, TM, Overrides, Options, RowKeys> {
40
+ return createTransactionalSql<FromKysely<DB, Overrides, Options>, TM, KyselyExecutor>(db, driver, options);
36
41
  }