@typesql/kysely 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/kysely
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Queries run from the `sql` bound to your client: `createSql<DB>(client)` then `sql("…").execute()` (or `executeTakeFirst`, `executeTakeFirstOrThrow`, `executeCount`), and `sql.transaction(async (tx) => …)` for transactions, nested with savepoints; the `query`, `one`, `maybeOne`, `many`, `execute`, `transaction` and `RowCountError` exports of `@typesql/pg` and `@typesql/postgres`, `query` and `execute` of `@typesql/kysely`, and `queryRaw` and `executeRaw` of `@typesql/prisma` are removed.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies:
12
+ - @typesql/core@0.1.0
13
+
3
14
  ## 0.0.4
4
15
 
5
16
  ### Patch Changes
package/README.md CHANGED
@@ -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,15 +53,16 @@ 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
60
+ Queries are sent as `CompiledQuery.raw(q.text, q.values)` through
56
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
 
@@ -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
  ```
package/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
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
4
+ * What the adapter uses from a `Kysely<DB>` or `Transaction<DB>`. Queries run through
5
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).
@@ -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"}
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@typesql/kysely",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
4
4
  "description": "Use Kysely database interfaces (kysely-codegen, prisma-kysely) as a typesql schema.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@typesql/core": "0.0.4"
31
+ "@typesql/core": "0.1.0"
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
5
+ * What the adapter uses from a `Kysely<DB>` or `Transaction<DB>`. Queries run through
6
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 };
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
  }