@typesql/kysely 0.0.3 → 0.0.4

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,20 @@
1
1
  # @typesql/kysely
2
2
 
3
+ ## 0.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Queries have `executeCount()`, which resolves to the affected row count: an `Executor` may resolve to `{ rows, rowCount }` instead of the rows, as the `executor()` of `@typesql/pg`, `@typesql/postgres` and `@typesql/kysely` now do.
8
+
9
+ - `createSql(executor, { rowKeys: "camelCase" })` (and the adapters' `createSql(client, { rowKeys: "camelCase" })`) camelCases the top-level row keys the way Kysely's `CamelCasePlugin` does, in the row types and in the rows `execute*` and the `query`/`one`/`maybeOne`/`many` helpers return, leaving JSON values untouched.
10
+
11
+ - `execute(db, q)` returns the number of rows for statements Kysely reports no `numAffectedRows` for (`SELECT`), as `@typesql/pg` does, instead of 0.
12
+
13
+ - Parameters accept `null` wherever Postgres does: comparisons (`col = $1`, `IN`, `ANY`, `LIKE`), `LIMIT`/`OFFSET`, casts in comparisons and function arguments (`coalesce($1::text, 'x')`), and array elements (`(number | null)[]`); assigning `null` to a `NOT NULL` column is still an error.
14
+
15
+ - Updated dependencies:
16
+ - @typesql/core@0.0.4
17
+
3
18
  ## 0.0.3
4
19
 
5
20
  ### Patch Changes
package/README.md CHANGED
@@ -21,7 +21,7 @@ const q = sql(
21
21
  WHERE u.id = $1 AND p.published = $2`,
22
22
  1, true,
23
23
  );
24
- // ^? Query<{ id: number; email: string; title: string; views: string }, [number, boolean]>
24
+ // ^? Query<{ id: number; email: string; title: string; views: string }, [number | null, boolean | null]>
25
25
 
26
26
  const rows = await query(db, q); // db: Kysely<DB> or a Transaction<DB>
27
27
  ```
@@ -30,10 +30,11 @@ const rows = await query(db, q); // db: Kysely<DB> or a Transaction<DB>
30
30
 
31
31
  | Export | What it is |
32
32
  |---|---|
33
- | `createSql<DB, TM = DefaultTypeMap, Overrides = {}, Options = {}>()` | core's `createSql<FromKysely<DB, Overrides, Options>, TM>()` |
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
34
  | `FromKysely<DB, Overrides = {}, Options = {}>` | the converted schema type, for use with core's `createSql<Schema, TM>()` or the adapters' `createSql<Schema>()` |
35
35
  | `query(db, q)` | runs a typesql `Query` through Kysely, `Promise<Row[]>` |
36
- | `execute(db, q)` | runs a statement, `Promise<number>` (`numAffectedRows`, or 0) |
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
38
  | `InferColumn<T>` | the descriptor inferred for one Kysely column type (handy to check a mapping) |
38
39
  | `SnakeCase<S>` | `CamelCasePlugin`'s default camelCase → snake_case mapping, at the type level |
39
40
  | `KyselyOverrides`, `TableOverride`, `ColumnOverride`, `KyselyOptions`, `KyselyExecutor` | parameter types |
@@ -54,7 +55,7 @@ const same = createCoreSql<FromKysely<DB>, PgTypeMap>();
54
55
  `query` and `execute` send `CompiledQuery.raw(q.text, q.values)` through
55
56
  `db.withoutPlugins().executeQuery(...)`. Plugins are bypassed on purpose: typesql's row types
56
57
  describe what Postgres returns (`created_at`), and a result transformer such as
57
- `CamelCasePlugin` would rename the keys. Logging, the dialect and the connection pool are
58
+ `CamelCasePlugin` would rename the keys (use `{ rowKeys: "camelCase" }` for camelCase rows). Logging, the dialect and the connection pool are
58
59
  unaffected. Any `sql(...)` result can also be run with `@typesql/pg` directly on the pool.
59
60
 
60
61
  ## How columns are converted
@@ -153,12 +154,22 @@ back to the database's snake_case names the way `CamelCasePlugin` does by defaul
153
154
  ```ts
154
155
  const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>();
155
156
  const q = sql("SELECT author_id, created_at FROM blog_posts WHERE id = $1", 1);
156
- // ^? Query<{ author_id: number; created_at: Date }, [number]>
157
+ // ^? Query<{ author_id: number; created_at: Date }, [number | null]>
157
158
  ```
158
159
 
159
160
  Overrides still use the interface's (camelCase) keys. The plugin's non-default options
160
161
  (`upperCase`, `underscoreBeforeDigits`, `underscoreBetweenUppercaseLetters`) are not modelled.
161
162
 
163
+ For camelCase **rows**, add `{ rowKeys: "camelCase" }`. The top-level keys are renamed with
164
+ `CamelCasePlugin`'s default snake_case → camelCase mapping, in the row types and at runtime.
165
+ The plugin itself stays bypassed, so keys inside JSON values are left alone:
166
+
167
+ ```ts
168
+ const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>(db, { rowKeys: "camelCase" });
169
+ const post = await sql("SELECT author_id, created_at FROM blog_posts WHERE id = $1", 1).executeTakeFirstOrThrow();
170
+ // ^? { authorId: number; createdAt: Date }
171
+ ```
172
+
162
173
  ## Limitations
163
174
 
164
175
  - **The TS → Postgres mapping is lossy.** `number`, `string` and `Date` each stand for several
package/dist/client.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { CompiledQuery, type QueryResult } from "kysely";
2
- import type { Executor, Query, RowType } from "@typesql/core";
2
+ import { type Executor, type Query, type RowType } from "@typesql/core";
3
3
  /**
4
4
  * What the helpers use 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
- * transformers such as `CamelCasePlugin` must not rename the columns.
6
+ * transformers such as `CamelCasePlugin` must not rename the columns (`createSql(db,
7
+ * { rowKeys: "camelCase" })` renames the top-level keys instead, in the types too).
7
8
  */
8
9
  export interface KyselyExecutor {
9
10
  withoutPlugins(): {
@@ -11,11 +12,17 @@ export interface KyselyExecutor {
11
12
  };
12
13
  }
13
14
  type AnyQuery = Query<unknown, readonly unknown[]>;
14
- /** An `Executor` for core's `q.execute()`: runs queries on a Kysely instance (or transaction), without its plugins. */
15
+ /**
16
+ * An `Executor` for core's `q.execute()`: runs queries on a Kysely instance (or transaction),
17
+ * without its plugins, and resolves to `{ rows, rowCount }` so `q.executeCount()` works.
18
+ */
15
19
  export declare function executor(db: KyselyExecutor): Executor;
16
20
  /** Run a typesql query on a Kysely instance (or transaction) and return its rows, typed from the query. */
17
21
  export declare function query<Q extends AnyQuery>(db: KyselyExecutor, q: Q): Promise<RowType<Q>[]>;
18
- /** Run a statement for its side effect and return the affected row count (`numAffectedRows`, or 0). */
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
+ */
19
26
  export declare function execute(db: KyselyExecutor, q: AnyQuery): Promise<number>;
20
27
  export {};
21
28
  //# 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,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE9D;;;;GAIG;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;AAMnD,uHAAuH;AACvH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,cAAc,GAAG,QAAQ,CAErD;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,uGAAuG;AACvG,wBAAsB,OAAO,CAAC,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAG9E"}
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"}
package/dist/client.js CHANGED
@@ -1,19 +1,35 @@
1
1
  import { CompiledQuery } from "kysely";
2
+ import { mapRows } from "@typesql/core";
2
3
  function run(db, text, values) {
3
4
  return db.withoutPlugins().executeQuery(CompiledQuery.raw(text, Array.from(values)));
4
5
  }
5
- /** An `Executor` for core's `q.execute()`: runs queries on a Kysely instance (or transaction), without its plugins. */
6
+ /**
7
+ * Kysely reports `numAffectedRows` for INSERT/UPDATE/DELETE/MERGE only; for other statements the
8
+ * count is the rows returned (SELECT), or 0 (DDL), as Postgres' command tag says.
9
+ */
10
+ function rowCount(result) {
11
+ return result.numAffectedRows === undefined ? result.rows.length : Number(result.numAffectedRows);
12
+ }
13
+ /**
14
+ * An `Executor` for core's `q.execute()`: runs queries on a Kysely instance (or transaction),
15
+ * without its plugins, and resolves to `{ rows, rowCount }` so `q.executeCount()` works.
16
+ */
6
17
  export function executor(db) {
7
- return async (text, values) => (await run(db, text, values)).rows;
18
+ return async (text, values) => {
19
+ const result = await run(db, text, values);
20
+ return { rows: result.rows, rowCount: rowCount(result) };
21
+ };
8
22
  }
9
23
  /** Run a typesql query on a Kysely instance (or transaction) and return its rows, typed from the query. */
10
24
  export async function query(db, q) {
11
25
  const result = await run(db, q.text, q.values);
12
- return result.rows;
26
+ return mapRows(q, result.rows);
13
27
  }
14
- /** Run a statement for its side effect and return the affected row count (`numAffectedRows`, or 0). */
28
+ /**
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).
31
+ */
15
32
  export async function execute(db, q) {
16
- const result = await run(db, q.text, q.values);
17
- return Number(result.numAffectedRows ?? 0n);
33
+ return rowCount(await run(db, q.text, q.values));
18
34
  }
19
35
  //# 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,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,uHAAuH;AACvH,MAAM,UAAU,QAAQ,CAAC,EAAkB;IACzC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,CAAU,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7E,CAAC;AAED,2GAA2G;AAC3G,MAAM,CAAC,KAAK,UAAU,KAAK,CAAqB,EAAkB,EAAE,CAAI;IACtE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAa,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IAC3D,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,uGAAuG;AACvG,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAkB,EAAE,CAAW;IAC3D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;AAC9C,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,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"}
package/dist/index.d.ts CHANGED
@@ -12,7 +12,16 @@ export { query, execute, executor, type KyselyExecutor } from "./client.js";
12
12
  * const sql = createSql<DB, PgTypeMap, { users: { id: "int8" } }>();
13
13
  * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>();
14
14
  *
15
- * With a `db` (a `Kysely` instance or transaction), the queries' `execute*` methods run on it.
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:
18
+ *
19
+ * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>(db, { rowKeys: "camelCase" });
16
20
  */
17
- export declare function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(db?: KyselyExecutor): Sql<FromKysely<DB, Overrides, Options>, TM>;
21
+ export declare function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(db: KyselyExecutor | undefined, options: {
22
+ readonly rowKeys: "camelCase";
23
+ }): Sql<FromKysely<DB, Overrides, Options>, TM, "camelCase">;
24
+ export declare function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(db?: KyselyExecutor, options?: {
25
+ readonly rowKeys?: "preserve";
26
+ }): Sql<FromKysely<DB, Overrides, Options>, TM>;
18
27
  //# 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,GAAG,EAAE,MAAM,eAAe,CAAC;AAC1F,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;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,EAAE,EACF,EAAE,GAAG,cAAc,EACnB,SAAS,SAAS,eAAe,GAAG,EAAE,EACtC,OAAO,SAAS,aAAa,GAAG,EAAE,EAClC,EAAE,CAAC,EAAE,cAAc,GAAG,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAElE"}
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"}
package/dist/index.js CHANGED
@@ -2,17 +2,7 @@ import { createSql as createCoreSql } from "@typesql/core";
2
2
  import { executor } from "./client.js";
3
3
  export { NoResultError } from "@typesql/core";
4
4
  export { query, execute, executor } from "./client.js";
5
- /**
6
- * `createSql` from core with a Kysely `DB` interface as the schema:
7
- * `createSql<DB>()` is `createSql<FromKysely<DB>, DefaultTypeMap>()`.
8
- *
9
- * const sql = createSql<DB>();
10
- * const sql = createSql<DB, PgTypeMap, { users: { id: "int8" } }>();
11
- * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>();
12
- *
13
- * With a `db` (a `Kysely` instance or transaction), the queries' `execute*` methods run on it.
14
- */
15
- export function createSql(db) {
16
- return createCoreSql(db && executor(db));
5
+ export function createSql(db, options) {
6
+ return createCoreSql(db && executor(db), options);
17
7
  }
18
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,EAAiC,MAAM,eAAe,CAAC;AAC1F,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;AAE5E;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CAKvB,EAAmB;IACnB,OAAO,aAAa,CAAyC,EAAE,IAAI,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AACnF,CAAC"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typesql/kysely",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Use Kysely database interfaces (kysely-codegen, prisma-kysely) as a typesql schema.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,13 +28,15 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@typesql/core": "0.0.3"
31
+ "@typesql/core": "0.0.4"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "kysely": ">=0.27"
35
35
  },
36
36
  "devDependencies": {
37
+ "@types/pg": "^8.23.1",
37
38
  "kysely": "^0.29.6",
39
+ "pg": "^8.23.1",
38
40
  "typescript": "7.0.2",
39
41
  "vitest": "^5.0.4"
40
42
  },
package/src/client.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { CompiledQuery, type QueryResult } from "kysely";
2
- import type { Executor, Query, RowType } from "@typesql/core";
2
+ import { mapRows, type Executor, type Query, type RowType } from "@typesql/core";
3
3
 
4
4
  /**
5
5
  * What the helpers use 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
- * transformers such as `CamelCasePlugin` must not rename the columns.
7
+ * transformers such as `CamelCasePlugin` must not rename the columns (`createSql(db,
8
+ * { rowKeys: "camelCase" })` renames the top-level keys instead, in the types too).
8
9
  */
9
10
  export interface KyselyExecutor {
10
11
  withoutPlugins(): { executeQuery<R>(query: CompiledQuery<R>): Promise<QueryResult<R>> };
@@ -16,19 +17,35 @@ function run<R>(db: KyselyExecutor, text: string, values: readonly unknown[]): P
16
17
  return db.withoutPlugins().executeQuery(CompiledQuery.raw(text, Array.from(values)) as CompiledQuery<R>);
17
18
  }
18
19
 
19
- /** An `Executor` for core's `q.execute()`: runs queries on a Kysely instance (or transaction), without its plugins. */
20
+ /**
21
+ * Kysely reports `numAffectedRows` for INSERT/UPDATE/DELETE/MERGE only; for other statements the
22
+ * count is the rows returned (SELECT), or 0 (DDL), as Postgres' command tag says.
23
+ */
24
+ function rowCount(result: QueryResult<unknown>): number {
25
+ return result.numAffectedRows === undefined ? result.rows.length : Number(result.numAffectedRows);
26
+ }
27
+
28
+ /**
29
+ * An `Executor` for core's `q.execute()`: runs queries on a Kysely instance (or transaction),
30
+ * without its plugins, and resolves to `{ rows, rowCount }` so `q.executeCount()` works.
31
+ */
20
32
  export function executor(db: KyselyExecutor): Executor {
21
- return async (text, values) => (await run<unknown>(db, text, values)).rows;
33
+ return async (text, values) => {
34
+ const result = await run<unknown>(db, text, values);
35
+ return { rows: result.rows, rowCount: rowCount(result) };
36
+ };
22
37
  }
23
38
 
24
39
  /** Run a typesql query on a Kysely instance (or transaction) and return its rows, typed from the query. */
25
40
  export async function query<Q extends AnyQuery>(db: KyselyExecutor, q: Q): Promise<RowType<Q>[]> {
26
- const result = await run<RowType<Q>>(db, q.text, q.values);
27
- return result.rows;
41
+ const result = await run<unknown>(db, q.text, q.values);
42
+ return mapRows(q, result.rows);
28
43
  }
29
44
 
30
- /** Run a statement for its side effect and return the affected row count (`numAffectedRows`, or 0). */
45
+ /**
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).
48
+ */
31
49
  export async function execute(db: KyselyExecutor, q: AnyQuery): Promise<number> {
32
- const result = await run<unknown>(db, q.text, q.values);
33
- return Number(result.numAffectedRows ?? 0n);
50
+ return rowCount(await run<unknown>(db, q.text, q.values));
34
51
  }
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { createSql as createCoreSql, type DefaultTypeMap, type Sql } from "@typesql/core";
1
+ import { createSql as createCoreSql, type DefaultTypeMap, type RowKeys, type Sql, type SqlOptions } from "@typesql/core";
2
2
  import { executor, type KyselyExecutor } from "./client.js";
3
3
  import type { FromKysely, KyselyOptions, KyselyOverrides } from "./from-kysely.js";
4
4
 
@@ -14,13 +14,23 @@ export { query, execute, executor, type KyselyExecutor } from "./client.js";
14
14
  * const sql = createSql<DB, PgTypeMap, { users: { id: "int8" } }>();
15
15
  * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>();
16
16
  *
17
- * With a `db` (a `Kysely` instance or transaction), the queries' `execute*` methods run on it.
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:
20
+ *
21
+ * const sql = createSql<DB, DefaultTypeMap, {}, { camelCase: true }>(db, { rowKeys: "camelCase" });
18
22
  */
19
- export function createSql<
20
- DB,
21
- TM = DefaultTypeMap,
22
- Overrides extends KyselyOverrides = {},
23
- Options extends KyselyOptions = {},
24
- >(db?: KyselyExecutor): Sql<FromKysely<DB, Overrides, Options>, TM> {
25
- return createCoreSql<FromKysely<DB, Overrides, Options>, TM>(db && executor(db));
23
+ export function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(
24
+ db: KyselyExecutor | undefined,
25
+ options: { readonly rowKeys: "camelCase" },
26
+ ): Sql<FromKysely<DB, Overrides, Options>, TM, "camelCase">;
27
+ export function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(
28
+ db?: KyselyExecutor,
29
+ options?: { readonly rowKeys?: "preserve" },
30
+ ): Sql<FromKysely<DB, Overrides, Options>, TM>;
31
+ export function createSql<DB, TM = DefaultTypeMap, Overrides extends KyselyOverrides = {}, Options extends KyselyOptions = {}>(
32
+ db?: KyselyExecutor,
33
+ 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" });
26
36
  }