@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 +20 -0
- package/README.md +26 -20
- package/dist/client.d.ts +9 -12
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -10
- package/dist/client.js.map +1 -1
- package/dist/from-kysely.d.ts +3 -3
- package/dist/index.d.ts +15 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/client.ts +13 -15
- package/src/from-kysely.ts +3 -3
- package/src/index.ts +20 -15
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
|
|
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
|
|
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
|
|
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
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
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
|
-
|
|
56
|
-
`db.withoutPlugins().executeQuery(...)`. Plugins are bypassed on purpose:
|
|
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).
|
|
59
|
-
|
|
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;
|
|
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;
|
|
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
|
|
2
|
+
import { type Executor, type SqlDriver } from "@typesql/core";
|
|
3
3
|
/**
|
|
4
|
-
* What the
|
|
5
|
-
* `withoutPlugins()`:
|
|
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
|
-
/**
|
|
21
|
-
export declare
|
|
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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -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,
|
|
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 {
|
|
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
|
|
30
|
-
*
|
|
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
|
-
|
|
33
|
-
|
|
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
|
package/dist/client.js.map
CHANGED
|
@@ -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,
|
|
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/from-kysely.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
|
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>(); //
|
|
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
|
|
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 {
|
|
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
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `
|
|
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
|
-
}):
|
|
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
|
-
}):
|
|
29
|
+
}): KyselySql<DB, TM, Overrides, Options>;
|
|
27
30
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
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 {
|
|
2
|
-
import {
|
|
1
|
+
import { createTransactionalSql } from "@typesql/core";
|
|
2
|
+
import { driver } from "./client.js";
|
|
3
3
|
export { NoResultError } from "@typesql/core";
|
|
4
|
-
export {
|
|
4
|
+
export { executor } from "./client.js";
|
|
5
5
|
export function createSql(db, options) {
|
|
6
|
-
return
|
|
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,
|
|
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.
|
|
4
|
-
"description": "Use Kysely database interfaces (kysely-codegen, prisma-kysely) as a
|
|
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.
|
|
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 {
|
|
2
|
+
import { runTransaction, type Executor, type SqlDriver } from "@typesql/core";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* What the
|
|
6
|
-
* `withoutPlugins()`:
|
|
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
|
|
47
|
-
*
|
|
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
|
-
|
|
50
|
-
|
|
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/from-kysely.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
|
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>(); //
|
|
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 {
|
|
2
|
-
import {
|
|
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 {
|
|
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
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* `
|
|
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
|
-
):
|
|
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
|
-
):
|
|
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
|
-
):
|
|
35
|
-
return
|
|
39
|
+
): KyselySql<DB, TM, Overrides, Options, RowKeys> {
|
|
40
|
+
return createTransactionalSql<FromKysely<DB, Overrides, Options>, TM, KyselyExecutor>(db, driver, options);
|
|
36
41
|
}
|