@telorun/sql 0.7.2 → 0.8.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/README.md CHANGED
@@ -55,8 +55,8 @@ metadata:
55
55
  A complete feedback collection REST API — no code, pure YAML.
56
56
  Persists entries to SQLite and serves them over HTTP.
57
57
  imports:
58
- Http: std/http-server@0.11.0
59
- Sql: std/sql@0.9.0
58
+ Http: std/http-server@0.12.0
59
+ Sql: std/sql@0.9.2
60
60
  targets:
61
61
  - !ref Migrations
62
62
  - !ref Server
@@ -0,0 +1,3 @@
1
+ export { SqlConnectionResource, createSqlConnection, type SqlDriver, type PlaceholderStyle, } from "./sql-connection-controller.js";
2
+ export { resolveSqlConnection } from "./sql-connection-ref.js";
3
+ export type { SqliteDb, SqliteStatement } from "./sqlite-driver-interface.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { SqlConnectionResource, createSqlConnection, } from "./sql-connection-controller.js";
2
+ export { resolveSqlConnection } from "./sql-connection-ref.js";
@@ -2,7 +2,7 @@ import type { ResourceContext, ResourceInstance } from "@telorun/sdk";
2
2
  import type { SqlConnectionResource } from "./sql-connection-controller.js";
3
3
  import type { SqlResult } from "./sql-query-controller.js";
4
4
  import type { SqlTransactionResource } from "./sql-transaction-controller.js";
5
- interface SqlExecManifest {
5
+ interface SqlCommandManifest {
6
6
  metadata: {
7
7
  name: string;
8
8
  module: string;
@@ -14,12 +14,12 @@ interface SqlExecManifest {
14
14
  bindings?: unknown[];
15
15
  };
16
16
  }
17
- declare class SqlExecResource implements ResourceInstance {
17
+ declare class SqlCommandResource implements ResourceInstance {
18
18
  private readonly manifest;
19
19
  private readonly ctx;
20
- constructor(manifest: SqlExecManifest, ctx: ResourceContext);
20
+ constructor(manifest: SqlCommandManifest, ctx: ResourceContext);
21
21
  invoke(input: unknown): Promise<SqlResult>;
22
22
  }
23
23
  export declare function register(): void;
24
- export declare function create(resource: SqlExecManifest, ctx: ResourceContext): Promise<SqlExecResource>;
24
+ export declare function create(resource: SqlCommandManifest, ctx: ResourceContext): Promise<SqlCommandResource>;
25
25
  export {};
@@ -1,6 +1,6 @@
1
1
  import { resolveSqlConnection } from "./sql-connection-ref.js";
2
2
  import { runSql } from "./sql-run.js";
3
- class SqlExecResource {
3
+ class SqlCommandResource {
4
4
  manifest;
5
5
  ctx;
6
6
  constructor(manifest, ctx) {
@@ -20,5 +20,5 @@ class SqlExecResource {
20
20
  }
21
21
  export function register() { }
22
22
  export async function create(resource, ctx) {
23
- return new SqlExecResource(resource, ctx);
23
+ return new SqlCommandResource(resource, ctx);
24
24
  }
@@ -2,27 +2,22 @@ import type { ResourceInstance } from "@telorun/sdk";
2
2
  import { Kysely, type QueryResult } from "kysely";
3
3
  import type { SqlTransactionResource } from "./sql-transaction-controller.js";
4
4
  import type { SqliteDb } from "./sqlite-driver-interface.js";
5
- interface PoolConfig {
6
- min?: number;
7
- max?: number;
8
- idleTimeoutMs?: number;
9
- connectionTimeoutMs?: number;
10
- }
11
5
  export type SqlDriver = "postgres" | "sqlite";
12
6
  /** Native bind-placeholder syntax per driver: SQLite binds anonymous `?`,
13
7
  * PostgreSQL binds numbered `$1`, `$2`, … */
14
8
  export type PlaceholderStyle = "qmark" | "numbered";
15
- export interface SqlConnectionConfig {
16
- driver: SqlDriver;
17
- /** Required for `postgres`; ignored for `sqlite` (which opens via `sqlite`). */
18
- connectionString?: string;
19
- pool?: PoolConfig;
20
- }
9
+ /**
10
+ * Driver-agnostic SQL connection. The kysely instance (and, for SQLite, the
11
+ * underlying database handle used by `executeScript`) is built by the driver
12
+ * backend (`sql-postgres`, `sql-sqlite`) and handed in via
13
+ * {@link createSqlConnection}. Everything here — execution, transactions,
14
+ * placeholder style, row-count normalization — is transport-neutral.
15
+ */
21
16
  export declare class SqlConnectionResource implements ResourceInstance {
22
17
  readonly driver: SqlDriver;
23
18
  private readonly db;
24
19
  private readonly sqlite?;
25
- constructor(config: SqlConnectionConfig, sqlite?: SqliteDb);
20
+ constructor(driver: SqlDriver, db: Kysely<any>, sqlite?: SqliteDb);
26
21
  init(): Promise<void>;
27
22
  teardown(): Promise<void>;
28
23
  transaction<T>(cb: () => Promise<T>): Promise<T>;
@@ -39,5 +34,10 @@ export declare class SqlConnectionResource implements ResourceInstance {
39
34
  snapshot(): Record<string, unknown>;
40
35
  private resolveExecutor;
41
36
  }
42
- export declare function openSqliteDatabase(file?: string): Promise<SqliteDb>;
43
- export {};
37
+ /**
38
+ * Build a connection from a driver-constructed kysely instance. Driver backends
39
+ * (`sql-postgres`, `sql-sqlite`) own dialect construction and call this; the
40
+ * `sqlite` handle is required only for SQLite (its `executeScript` runs through
41
+ * the native handle).
42
+ */
43
+ export declare function createSqlConnection(driver: SqlDriver, db: Kysely<any>, sqlite?: SqliteDb): SqlConnectionResource;
@@ -1,44 +1,21 @@
1
1
  import { randomUUID } from "crypto";
2
- import { CompiledQuery, Kysely, PostgresDialect, SqliteAdapter, SqliteDialect, } from "kysely";
3
- import { Pool } from "pg";
2
+ import { CompiledQuery } from "kysely";
4
3
  import { currentTxId, deleteTx, getTx, setTx, txStorage } from "./transaction-store.js";
4
+ /**
5
+ * Driver-agnostic SQL connection. The kysely instance (and, for SQLite, the
6
+ * underlying database handle used by `executeScript`) is built by the driver
7
+ * backend (`sql-postgres`, `sql-sqlite`) and handed in via
8
+ * {@link createSqlConnection}. Everything here — execution, transactions,
9
+ * placeholder style, row-count normalization — is transport-neutral.
10
+ */
5
11
  export class SqlConnectionResource {
6
12
  driver;
7
13
  db;
8
14
  sqlite;
9
- constructor(config, sqlite) {
10
- this.driver = config.driver;
11
- if (this.driver === "postgres") {
12
- if (!config.connectionString) {
13
- throw new Error("Sql: postgres connection requires a connectionString");
14
- }
15
- const url = new URL(config.connectionString);
16
- const ssl = sslFromSslmode(url.searchParams.get("sslmode"));
17
- url.searchParams.delete("sslmode");
18
- this.db = new Kysely({
19
- dialect: new PostgresDialect({
20
- pool: new Pool({
21
- connectionString: url.toString(),
22
- ssl,
23
- min: config.pool?.min ?? 1,
24
- max: config.pool?.max ?? 10,
25
- idleTimeoutMillis: config.pool?.idleTimeoutMs,
26
- connectionTimeoutMillis: config.pool?.connectionTimeoutMs,
27
- }),
28
- }),
29
- });
30
- }
31
- else {
32
- if (!sqlite) {
33
- throw new Error("Sql: sqlite database was not initialized");
34
- }
35
- this.sqlite = sqlite;
36
- this.db = new Kysely({
37
- dialect: new TransactionalSqliteDialect({
38
- database: this.sqlite,
39
- }),
40
- });
41
- }
15
+ constructor(driver, db, sqlite) {
16
+ this.driver = driver;
17
+ this.db = db;
18
+ this.sqlite = sqlite;
42
19
  }
43
20
  async init() {
44
21
  await this.db.connection().execute(async () => {
@@ -113,57 +90,12 @@ export class SqlConnectionResource {
113
90
  return this.db;
114
91
  }
115
92
  }
116
- // Kysely's stock SQLite adapter reports `supportsTransactionalDdl = false`, so
117
- // its Migrator runs migrations without a transaction. SQLite does support
118
- // transactional DDL, so we flip the flag letting the Migrator wrap the whole
119
- // migration batch in a single transaction, matching PostgreSQL.
120
- class TransactionalSqliteAdapter extends SqliteAdapter {
121
- get supportsTransactionalDdl() {
122
- return true;
123
- }
124
- }
125
- class TransactionalSqliteDialect extends SqliteDialect {
126
- createAdapter() {
127
- return new TransactionalSqliteAdapter();
128
- }
129
- }
130
- function sslFromSslmode(mode) {
131
- switch (mode) {
132
- case null:
133
- case "disable":
134
- return false;
135
- case "require":
136
- return { rejectUnauthorized: false };
137
- case "verify-ca":
138
- // libpq `verify-ca` validates the CA chain but not the hostname; Node's
139
- // default `checkServerIdentity` enforces the hostname, so disable it.
140
- return { rejectUnauthorized: true, checkServerIdentity: () => undefined };
141
- case "verify-full":
142
- return { rejectUnauthorized: true };
143
- default:
144
- throw new Error(`Sql.Connection: unsupported sslmode '${mode}'. ` +
145
- `Use 'disable', 'require', 'verify-ca', or 'verify-full'.`);
146
- }
147
- }
148
- export async function openSqliteDatabase(file = ":memory:") {
149
- // Auto-create the parent directory for file-backed databases. SQLite
150
- // drivers fail-fast when the directory doesn't exist; mirroring `mkdir
151
- // -p` here lets manifests use paths like `./tmp/foo.sqlite` without a
152
- // separate filesystem-prep step. `:memory:` skips filesystem entirely.
153
- if (file !== ":memory:") {
154
- const { mkdir } = await import("node:fs/promises");
155
- const { dirname } = await import("node:path");
156
- const dir = dirname(file);
157
- if (dir && dir !== "." && dir !== "/") {
158
- await mkdir(dir, { recursive: true });
159
- }
160
- }
161
- // Route through the package's own `./sqlite-driver` subpath export so the
162
- // resolver selects the driver per runtime (Bun → bun:sqlite, Node →
163
- // better-sqlite3). A manual `typeof Bun` check with relative imports gets
164
- // flattened by the controller bundler into an unconditional top-level
165
- // `import "bun:sqlite"`, which Node's ESM loader rejects before the guard
166
- // runs; an external `@telorun/*` specifier stays a deferred dynamic import.
167
- const { openDatabase } = await import("@telorun/sql/sqlite-driver");
168
- return openDatabase(file);
93
+ /**
94
+ * Build a connection from a driver-constructed kysely instance. Driver backends
95
+ * (`sql-postgres`, `sql-sqlite`) own dialect construction and call this; the
96
+ * `sqlite` handle is required only for SQLite (its `executeScript` runs through
97
+ * the native handle).
98
+ */
99
+ export function createSqlConnection(driver, db, sqlite) {
100
+ return new SqlConnectionResource(driver, db, sqlite);
169
101
  }
@@ -58,12 +58,12 @@ interface SelectManifest {
58
58
  offset?: unknown;
59
59
  inputType?: string | Record<string, any>;
60
60
  }
61
- declare class SqlSelectResource implements ResourceInstance {
61
+ declare class SqlSelectionResource implements ResourceInstance {
62
62
  private readonly manifest;
63
63
  private readonly ctx;
64
64
  constructor(manifest: SelectManifest, ctx: ResourceContext);
65
65
  invoke(input: unknown): Promise<SqlResult>;
66
66
  }
67
67
  export declare function register(): void;
68
- export declare function create(resource: SelectManifest, ctx: ResourceContext): Promise<SqlSelectResource>;
68
+ export declare function create(resource: SelectManifest, ctx: ResourceContext): Promise<SqlSelectionResource>;
69
69
  export {};
@@ -1,6 +1,6 @@
1
1
  import { resolveSqlConnection } from "./sql-connection-ref.js";
2
2
  // ── Controller ────────────────────────────────────────────────────────────────
3
- class SqlSelectResource {
3
+ class SqlSelectionResource {
4
4
  manifest;
5
5
  ctx;
6
6
  constructor(manifest, ctx) {
@@ -21,7 +21,7 @@ class SqlSelectResource {
21
21
  const offset = m.offset != null ? ctx.expandValue(m.offset, expandCtx) : undefined;
22
22
  const connection = resolveSqlConnection(m.connection, ctx) ?? m.transaction?.getConnection();
23
23
  if (!connection) {
24
- throw new Error("Sql.Select: either 'connection' or 'transaction' must be set");
24
+ throw new Error("Sql.Selection: either 'connection' or 'transaction' must be set");
25
25
  }
26
26
  const { sql, params } = buildSelect(m, where, having, limit, offset, connection.driver);
27
27
  const result = await connection.execute(sql, params, m.transaction);
@@ -157,7 +157,7 @@ function opToSql(op) {
157
157
  };
158
158
  const sql = map[op];
159
159
  if (!sql)
160
- throw new Error(`Sql.Select: unknown operator '${op}'`);
160
+ throw new Error(`Sql.Selection: unknown operator '${op}'`);
161
161
  return sql;
162
162
  }
163
163
  // ── Exports ───────────────────────────────────────────────────────────────────
@@ -190,5 +190,5 @@ function extractDefaults(inputType, ctx) {
190
190
  }
191
191
  export function register() { }
192
192
  export async function create(resource, ctx) {
193
- return new SqlSelectResource(resource, ctx);
193
+ return new SqlSelectionResource(resource, ctx);
194
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/sql",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "Telo SQL module - SQL database resource kinds for Telo manifests.",
5
5
  "keywords": [
6
6
  "telo",
@@ -21,35 +21,36 @@
21
21
  "url": "https://github.com/telorun/telo/issues"
22
22
  },
23
23
  "type": "module",
24
+ "main": "./dist/index.js",
25
+ "module": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
24
27
  "exports": {
25
- "./sql-postgres-connection": {
26
- "bun": "./src/sql-postgres-connection-controller.ts",
27
- "import": "./dist/sql-postgres-connection-controller.js"
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "bun": "./src/index.ts",
31
+ "import": "./dist/index.js"
28
32
  },
29
- "./sql-sqlite-connection": {
30
- "bun": "./src/sql-sqlite-connection-controller.ts",
31
- "import": "./dist/sql-sqlite-connection-controller.js"
33
+ "./connection": {
34
+ "types": "./dist/sql-connection-controller.d.ts",
35
+ "bun": "./src/sql-connection-controller.ts",
36
+ "import": "./dist/sql-connection-controller.js"
32
37
  },
33
38
  "./sql-query": {
34
39
  "bun": "./src/sql-query-controller.ts",
35
40
  "import": "./dist/sql-query-controller.js"
36
41
  },
37
- "./sql-select": {
38
- "bun": "./src/sql-select-controller.ts",
39
- "import": "./dist/sql-select-controller.js"
42
+ "./sql-selection": {
43
+ "bun": "./src/sql-selection-controller.ts",
44
+ "import": "./dist/sql-selection-controller.js"
40
45
  },
41
- "./sql-exec": {
42
- "bun": "./src/sql-exec-controller.ts",
43
- "import": "./dist/sql-exec-controller.js"
46
+ "./sql-command": {
47
+ "bun": "./src/sql-command-controller.ts",
48
+ "import": "./dist/sql-command-controller.js"
44
49
  },
45
50
  "./sql-transaction": {
46
51
  "bun": "./src/sql-transaction-controller.ts",
47
52
  "import": "./dist/sql-transaction-controller.js"
48
53
  },
49
- "./sqlite-driver": {
50
- "bun": "./src/sqlite-driver-bun.ts",
51
- "import": "./dist/sqlite-driver-node.js"
52
- },
53
54
  "./sql-migration": {
54
55
  "bun": "./src/sql-migration-controller.ts",
55
56
  "import": "./dist/sql-migration-controller.js"
@@ -64,17 +65,12 @@
64
65
  "src/**"
65
66
  ],
66
67
  "dependencies": {
67
- "better-sqlite3": "^12.8.0",
68
- "pg": "^8.20.0",
69
68
  "kysely": "^0.28.15"
70
69
  },
71
70
  "devDependencies": {
72
- "@types/better-sqlite3": "^7.0.0",
73
- "@types/bun": "^1.3.10",
74
71
  "@types/node": "^20.0.0",
75
- "@types/pg": "^8.0.0",
76
72
  "typescript": "^5.0.0",
77
- "@telorun/sdk": "0.26.0"
73
+ "@telorun/sdk": "0.34.0"
78
74
  },
79
75
  "peerDependencies": {
80
76
  "@telorun/sdk": "*"
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ export {
2
+ SqlConnectionResource,
3
+ createSqlConnection,
4
+ type SqlDriver,
5
+ type PlaceholderStyle,
6
+ } from "./sql-connection-controller.js";
7
+ export { resolveSqlConnection } from "./sql-connection-ref.js";
8
+ export type { SqliteDb, SqliteStatement } from "./sqlite-driver-interface.js";
@@ -5,7 +5,7 @@ import type { SqlResult } from "./sql-query-controller.js";
5
5
  import { runSql } from "./sql-run.js";
6
6
  import type { SqlTransactionResource } from "./sql-transaction-controller.js";
7
7
 
8
- interface SqlExecManifest {
8
+ interface SqlCommandManifest {
9
9
  metadata: { name: string; module: string };
10
10
  connection?: SqlConnectionResource;
11
11
  transaction?: SqlTransactionResource;
@@ -15,9 +15,9 @@ interface SqlExecManifest {
15
15
  };
16
16
  }
17
17
 
18
- class SqlExecResource implements ResourceInstance {
18
+ class SqlCommandResource implements ResourceInstance {
19
19
  constructor(
20
- private readonly manifest: SqlExecManifest,
20
+ private readonly manifest: SqlCommandManifest,
21
21
  private readonly ctx: ResourceContext,
22
22
  ) {}
23
23
 
@@ -38,8 +38,8 @@ class SqlExecResource implements ResourceInstance {
38
38
  export function register(): void {}
39
39
 
40
40
  export async function create(
41
- resource: SqlExecManifest,
41
+ resource: SqlCommandManifest,
42
42
  ctx: ResourceContext,
43
- ): Promise<SqlExecResource> {
44
- return new SqlExecResource(resource, ctx);
43
+ ): Promise<SqlCommandResource> {
44
+ return new SqlCommandResource(resource, ctx);
45
45
  }
@@ -1,77 +1,34 @@
1
1
  import type { ResourceInstance } from "@telorun/sdk";
2
2
  import { randomUUID } from "crypto";
3
- import {
4
- CompiledQuery,
5
- Kysely,
6
- PostgresDialect,
7
- SqliteAdapter,
8
- SqliteDialect,
9
- type QueryResult,
10
- type Transaction,
11
- } from "kysely";
12
- import { Pool } from "pg";
3
+ import { CompiledQuery, Kysely, type QueryResult, type Transaction } from "kysely";
13
4
  import type { SqlTransactionResource } from "./sql-transaction-controller.js";
14
5
  import type { SqliteDb } from "./sqlite-driver-interface.js";
15
6
  import { currentTxId, deleteTx, getTx, setTx, txStorage } from "./transaction-store.js";
16
7
 
17
- interface PoolConfig {
18
- min?: number;
19
- max?: number;
20
- idleTimeoutMs?: number;
21
- connectionTimeoutMs?: number;
22
- }
23
-
24
8
  export type SqlDriver = "postgres" | "sqlite";
25
9
 
26
10
  /** Native bind-placeholder syntax per driver: SQLite binds anonymous `?`,
27
11
  * PostgreSQL binds numbered `$1`, `$2`, … */
28
12
  export type PlaceholderStyle = "qmark" | "numbered";
29
13
 
30
- export interface SqlConnectionConfig {
31
- driver: SqlDriver;
32
- /** Required for `postgres`; ignored for `sqlite` (which opens via `sqlite`). */
33
- connectionString?: string;
34
- pool?: PoolConfig;
35
- }
36
-
14
+ /**
15
+ * Driver-agnostic SQL connection. The kysely instance (and, for SQLite, the
16
+ * underlying database handle used by `executeScript`) is built by the driver
17
+ * backend (`sql-postgres`, `sql-sqlite`) and handed in via
18
+ * {@link createSqlConnection}. Everything here — execution, transactions,
19
+ * placeholder style, row-count normalization — is transport-neutral.
20
+ */
37
21
  export class SqlConnectionResource implements ResourceInstance {
38
- readonly driver: SqlDriver;
39
22
  private readonly db: Kysely<any>;
40
23
  private readonly sqlite?: SqliteDb;
41
24
 
42
- constructor(config: SqlConnectionConfig, sqlite?: SqliteDb) {
43
- this.driver = config.driver;
44
-
45
- if (this.driver === "postgres") {
46
- if (!config.connectionString) {
47
- throw new Error("Sql: postgres connection requires a connectionString");
48
- }
49
- const url = new URL(config.connectionString);
50
- const ssl = sslFromSslmode(url.searchParams.get("sslmode"));
51
- url.searchParams.delete("sslmode");
52
- this.db = new Kysely({
53
- dialect: new PostgresDialect({
54
- pool: new Pool({
55
- connectionString: url.toString(),
56
- ssl,
57
- min: config.pool?.min ?? 1,
58
- max: config.pool?.max ?? 10,
59
- idleTimeoutMillis: config.pool?.idleTimeoutMs,
60
- connectionTimeoutMillis: config.pool?.connectionTimeoutMs,
61
- }),
62
- }),
63
- });
64
- } else {
65
- if (!sqlite) {
66
- throw new Error("Sql: sqlite database was not initialized");
67
- }
68
- this.sqlite = sqlite;
69
- this.db = new Kysely({
70
- dialect: new TransactionalSqliteDialect({
71
- database: this.sqlite,
72
- }),
73
- });
74
- }
25
+ constructor(
26
+ readonly driver: SqlDriver,
27
+ db: Kysely<any>,
28
+ sqlite?: SqliteDb,
29
+ ) {
30
+ this.db = db;
31
+ this.sqlite = sqlite;
75
32
  }
76
33
 
77
34
  async init() {
@@ -171,67 +128,16 @@ export class SqlConnectionResource implements ResourceInstance {
171
128
  }
172
129
  }
173
130
 
174
- // Kysely's stock SQLite adapter reports `supportsTransactionalDdl = false`, so
175
- // its Migrator runs migrations without a transaction. SQLite does support
176
- // transactional DDL, so we flip the flag letting the Migrator wrap the whole
177
- // migration batch in a single transaction, matching PostgreSQL.
178
- class TransactionalSqliteAdapter extends SqliteAdapter {
179
- override get supportsTransactionalDdl(): boolean {
180
- return true;
181
- }
182
- }
183
-
184
- class TransactionalSqliteDialect extends SqliteDialect {
185
- override createAdapter(): SqliteAdapter {
186
- return new TransactionalSqliteAdapter();
187
- }
188
- }
189
-
190
- type SslOption =
191
- | false
192
- | { rejectUnauthorized: boolean; checkServerIdentity?: () => undefined };
193
-
194
- function sslFromSslmode(mode: string | null): SslOption {
195
- switch (mode) {
196
- case null:
197
- case "disable":
198
- return false;
199
- case "require":
200
- return { rejectUnauthorized: false };
201
- case "verify-ca":
202
- // libpq `verify-ca` validates the CA chain but not the hostname; Node's
203
- // default `checkServerIdentity` enforces the hostname, so disable it.
204
- return { rejectUnauthorized: true, checkServerIdentity: () => undefined };
205
- case "verify-full":
206
- return { rejectUnauthorized: true };
207
- default:
208
- throw new Error(
209
- `Sql.Connection: unsupported sslmode '${mode}'. ` +
210
- `Use 'disable', 'require', 'verify-ca', or 'verify-full'.`,
211
- );
212
- }
213
- }
214
-
215
- export async function openSqliteDatabase(file = ":memory:"): Promise<SqliteDb> {
216
- // Auto-create the parent directory for file-backed databases. SQLite
217
- // drivers fail-fast when the directory doesn't exist; mirroring `mkdir
218
- // -p` here lets manifests use paths like `./tmp/foo.sqlite` without a
219
- // separate filesystem-prep step. `:memory:` skips filesystem entirely.
220
- if (file !== ":memory:") {
221
- const { mkdir } = await import("node:fs/promises");
222
- const { dirname } = await import("node:path");
223
- const dir = dirname(file);
224
- if (dir && dir !== "." && dir !== "/") {
225
- await mkdir(dir, { recursive: true });
226
- }
227
- }
228
-
229
- // Route through the package's own `./sqlite-driver` subpath export so the
230
- // resolver selects the driver per runtime (Bun → bun:sqlite, Node →
231
- // better-sqlite3). A manual `typeof Bun` check with relative imports gets
232
- // flattened by the controller bundler into an unconditional top-level
233
- // `import "bun:sqlite"`, which Node's ESM loader rejects before the guard
234
- // runs; an external `@telorun/*` specifier stays a deferred dynamic import.
235
- const { openDatabase } = await import("@telorun/sql/sqlite-driver");
236
- return openDatabase(file);
131
+ /**
132
+ * Build a connection from a driver-constructed kysely instance. Driver backends
133
+ * (`sql-postgres`, `sql-sqlite`) own dialect construction and call this; the
134
+ * `sqlite` handle is required only for SQLite (its `executeScript` runs through
135
+ * the native handle).
136
+ */
137
+ export function createSqlConnection(
138
+ driver: SqlDriver,
139
+ db: Kysely<any>,
140
+ sqlite?: SqliteDb,
141
+ ): SqlConnectionResource {
142
+ return new SqlConnectionResource(driver, db, sqlite);
237
143
  }
@@ -76,7 +76,7 @@ interface SelectManifest {
76
76
 
77
77
  // ── Controller ────────────────────────────────────────────────────────────────
78
78
 
79
- class SqlSelectResource implements ResourceInstance {
79
+ class SqlSelectionResource implements ResourceInstance {
80
80
  constructor(
81
81
  private readonly manifest: SelectManifest,
82
82
  private readonly ctx: ResourceContext,
@@ -98,7 +98,7 @@ class SqlSelectResource implements ResourceInstance {
98
98
 
99
99
  const connection = resolveSqlConnection(m.connection, ctx) ?? m.transaction?.getConnection();
100
100
  if (!connection) {
101
- throw new Error("Sql.Select: either 'connection' or 'transaction' must be set");
101
+ throw new Error("Sql.Selection: either 'connection' or 'transaction' must be set");
102
102
  }
103
103
 
104
104
  const { sql, params } = buildSelect(m, where, having, limit, offset, connection.driver);
@@ -266,7 +266,7 @@ function opToSql(op: Op): string {
266
266
  ilike: "ILIKE",
267
267
  };
268
268
  const sql = map[op];
269
- if (!sql) throw new Error(`Sql.Select: unknown operator '${op}'`);
269
+ if (!sql) throw new Error(`Sql.Selection: unknown operator '${op}'`);
270
270
  return sql;
271
271
  }
272
272
 
@@ -306,6 +306,6 @@ export function register(): void {}
306
306
  export async function create(
307
307
  resource: SelectManifest,
308
308
  ctx: ResourceContext,
309
- ): Promise<SqlSelectResource> {
310
- return new SqlSelectResource(resource, ctx);
309
+ ): Promise<SqlSelectionResource> {
310
+ return new SqlSelectionResource(resource, ctx);
311
311
  }
@@ -1,19 +0,0 @@
1
- import type { ResourceContext } from "@telorun/sdk";
2
- import { SqlConnectionResource } from "./sql-connection-controller.js";
3
- interface PoolConfig {
4
- min?: number;
5
- max?: number;
6
- idleTimeoutMs?: number;
7
- connectionTimeoutMs?: number;
8
- }
9
- interface PostgresConnectionManifest {
10
- metadata: {
11
- name: string;
12
- module: string;
13
- };
14
- connectionString: string;
15
- pool?: PoolConfig;
16
- }
17
- export declare function register(): void;
18
- export declare function create(resource: PostgresConnectionManifest, ctx: ResourceContext): Promise<SqlConnectionResource>;
19
- export {};
@@ -1,9 +0,0 @@
1
- import { SqlConnectionResource } from "./sql-connection-controller.js";
2
- export function register() { }
3
- export async function create(resource, ctx) {
4
- return new SqlConnectionResource({
5
- driver: "postgres",
6
- connectionString: resource.connectionString,
7
- pool: resource.pool,
8
- });
9
- }
@@ -1,13 +0,0 @@
1
- import type { ResourceContext } from "@telorun/sdk";
2
- import { SqlConnectionResource } from "./sql-connection-controller.js";
3
- interface SqliteConnectionManifest {
4
- metadata: {
5
- name: string;
6
- module: string;
7
- };
8
- /** File path, or omitted / `:memory:` for an in-memory database. */
9
- file?: string;
10
- }
11
- export declare function register(): void;
12
- export declare function create(resource: SqliteConnectionManifest, ctx: ResourceContext): Promise<SqlConnectionResource>;
13
- export {};
@@ -1,6 +0,0 @@
1
- import { openSqliteDatabase, SqlConnectionResource } from "./sql-connection-controller.js";
2
- export function register() { }
3
- export async function create(resource, ctx) {
4
- const sqlite = await openSqliteDatabase(resource.file ?? ":memory:");
5
- return new SqlConnectionResource({ driver: "sqlite" }, sqlite);
6
- }
@@ -1,2 +0,0 @@
1
- import type { SqliteDb } from "./sqlite-driver-interface.js";
2
- export declare function openDatabase(file: string): SqliteDb;
@@ -1,31 +0,0 @@
1
- import { Database } from "bun:sqlite";
2
- export function openDatabase(file) {
3
- const db = new Database(file);
4
- return {
5
- prepare(sql) {
6
- const stmt = db.prepare(sql);
7
- return {
8
- reader: true,
9
- all(params) {
10
- return stmt.all(...params);
11
- },
12
- run(params) {
13
- const result = stmt.run(...params);
14
- return {
15
- changes: result.changes,
16
- lastInsertRowid: result.lastInsertRowid,
17
- };
18
- },
19
- iterate(params) {
20
- return stmt.iterate(...params);
21
- },
22
- };
23
- },
24
- exec(sql) {
25
- db.exec(sql);
26
- },
27
- close() {
28
- db.close();
29
- },
30
- };
31
- }
@@ -1,2 +0,0 @@
1
- import type { SqliteDb } from "./sqlite-driver-interface.js";
2
- export declare function openDatabase(file: string): SqliteDb;
@@ -1,31 +0,0 @@
1
- import Database from "better-sqlite3";
2
- export function openDatabase(file) {
3
- const db = new Database(file);
4
- return {
5
- prepare(sql) {
6
- const stmt = db.prepare(sql);
7
- return {
8
- reader: stmt.reader,
9
- all(params) {
10
- return stmt.all(...params);
11
- },
12
- run(params) {
13
- const result = stmt.run(...params);
14
- return {
15
- changes: result.changes,
16
- lastInsertRowid: result.lastInsertRowid,
17
- };
18
- },
19
- iterate(params) {
20
- return stmt.iterate(...params);
21
- },
22
- };
23
- },
24
- exec(sql) {
25
- db.exec(sql);
26
- },
27
- close() {
28
- db.close();
29
- },
30
- };
31
- }
@@ -1,28 +0,0 @@
1
- import type { ResourceContext } from "@telorun/sdk";
2
- import { SqlConnectionResource } from "./sql-connection-controller.js";
3
-
4
- interface PoolConfig {
5
- min?: number;
6
- max?: number;
7
- idleTimeoutMs?: number;
8
- connectionTimeoutMs?: number;
9
- }
10
-
11
- interface PostgresConnectionManifest {
12
- metadata: { name: string; module: string };
13
- connectionString: string;
14
- pool?: PoolConfig;
15
- }
16
-
17
- export function register(): void {}
18
-
19
- export async function create(
20
- resource: PostgresConnectionManifest,
21
- ctx: ResourceContext,
22
- ): Promise<SqlConnectionResource> {
23
- return new SqlConnectionResource({
24
- driver: "postgres",
25
- connectionString: resource.connectionString,
26
- pool: resource.pool,
27
- });
28
- }
@@ -1,18 +0,0 @@
1
- import type { ResourceContext } from "@telorun/sdk";
2
- import { openSqliteDatabase, SqlConnectionResource } from "./sql-connection-controller.js";
3
-
4
- interface SqliteConnectionManifest {
5
- metadata: { name: string; module: string };
6
- /** File path, or omitted / `:memory:` for an in-memory database. */
7
- file?: string;
8
- }
9
-
10
- export function register(): void {}
11
-
12
- export async function create(
13
- resource: SqliteConnectionManifest,
14
- ctx: ResourceContext,
15
- ): Promise<SqlConnectionResource> {
16
- const sqlite = await openSqliteDatabase(resource.file ?? ":memory:");
17
- return new SqlConnectionResource({ driver: "sqlite" }, sqlite);
18
- }
@@ -1,34 +0,0 @@
1
- import { Database } from "bun:sqlite";
2
- import type { SqliteDb } from "./sqlite-driver-interface.js";
3
-
4
- export function openDatabase(file: string): SqliteDb {
5
- const db = new Database(file);
6
-
7
- return {
8
- prepare(sql: string) {
9
- const stmt = db.prepare(sql);
10
- return {
11
- reader: true,
12
- all(params: ReadonlyArray<unknown>) {
13
- return stmt.all(...(params as any[]));
14
- },
15
- run(params: ReadonlyArray<unknown>) {
16
- const result = stmt.run(...(params as any[]));
17
- return {
18
- changes: result.changes,
19
- lastInsertRowid: result.lastInsertRowid,
20
- };
21
- },
22
- iterate(params: ReadonlyArray<unknown>) {
23
- return stmt.iterate(...(params as any[])) as IterableIterator<unknown>;
24
- },
25
- };
26
- },
27
- exec(sql: string) {
28
- db.exec(sql);
29
- },
30
- close() {
31
- db.close();
32
- },
33
- };
34
- }
@@ -1,35 +0,0 @@
1
- import Database from "better-sqlite3";
2
- import type { SqliteDb } from "./sqlite-driver-interface.js";
3
-
4
- export function openDatabase(file: string): SqliteDb {
5
- const db = new Database(file);
6
-
7
- return {
8
- prepare(sql: string) {
9
- const stmt = db.prepare(sql);
10
-
11
- return {
12
- reader: stmt.reader,
13
- all(params: ReadonlyArray<unknown>) {
14
- return stmt.all(...(params as unknown[]));
15
- },
16
- run(params: ReadonlyArray<unknown>) {
17
- const result = stmt.run(...(params as unknown[]));
18
- return {
19
- changes: result.changes,
20
- lastInsertRowid: result.lastInsertRowid,
21
- };
22
- },
23
- iterate(params: ReadonlyArray<unknown>) {
24
- return stmt.iterate(...(params as unknown[])) as IterableIterator<unknown>;
25
- },
26
- };
27
- },
28
- exec(sql: string) {
29
- db.exec(sql);
30
- },
31
- close() {
32
- db.close();
33
- },
34
- };
35
- }