@telorun/sql-sqlite 0.2.1 → 0.3.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 +1 -140
- package/dist/connection-controller.d.ts +11 -2
- package/dist/connection-controller.js +23 -2
- package/dist/sqlite-driver-bun.d.ts +1 -1
- package/dist/sqlite-driver-interface.d.ts +14 -0
- package/dist/sqlite-driver-interface.js +1 -0
- package/dist/sqlite-driver-node.d.ts +1 -1
- package/package.json +3 -3
- package/src/connection-controller.ts +29 -3
- package/src/sqlite-driver-bun.ts +1 -1
- package/src/sqlite-driver-interface.ts +15 -0
- package/src/sqlite-driver-node.ts +1 -1
package/README.md
CHANGED
|
@@ -44,146 +44,7 @@ $ telo ./examples/hello-api
|
|
|
44
44
|
|
|
45
45
|
## Example manifest
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
```yaml
|
|
50
|
-
kind: Telo.Application
|
|
51
|
-
metadata:
|
|
52
|
-
name: feedback
|
|
53
|
-
version: 1.0.0
|
|
54
|
-
description: |
|
|
55
|
-
A complete feedback collection REST API — no code, pure YAML.
|
|
56
|
-
Persists entries to SQLite and serves them over HTTP.
|
|
57
|
-
imports:
|
|
58
|
-
Http: std/http-server@0.12.0
|
|
59
|
-
Sql: std/sql@0.9.2
|
|
60
|
-
targets:
|
|
61
|
-
- !ref Migrations
|
|
62
|
-
- !ref Server
|
|
63
|
-
---
|
|
64
|
-
# SQLite database — swap driver/host/database for PostgreSQL with zero YAML changes
|
|
65
|
-
kind: Sql.Connection
|
|
66
|
-
metadata:
|
|
67
|
-
name: Db
|
|
68
|
-
driver: sqlite
|
|
69
|
-
file: ./tmp/feedback.db
|
|
70
|
-
---
|
|
71
|
-
# Migrations: applied automatically before the server starts
|
|
72
|
-
kind: Sql.Migrations
|
|
73
|
-
metadata:
|
|
74
|
-
name: Migrations
|
|
75
|
-
connection: !ref Db
|
|
76
|
-
---
|
|
77
|
-
kind: Sql.Migration
|
|
78
|
-
metadata:
|
|
79
|
-
name: Migration_20260413_182154_CreateFeedback
|
|
80
|
-
version: 20260413_182154_CreateFeedback
|
|
81
|
-
sql: |
|
|
82
|
-
CREATE TABLE IF NOT EXISTS feedback (
|
|
83
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
84
|
-
text TEXT NOT NULL,
|
|
85
|
-
source TEXT,
|
|
86
|
-
score INTEGER NOT NULL DEFAULT 0,
|
|
87
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
88
|
-
)
|
|
89
|
-
---
|
|
90
|
-
kind: Http.Server
|
|
91
|
-
metadata:
|
|
92
|
-
name: Server
|
|
93
|
-
baseUrl: http://localhost:8844
|
|
94
|
-
port: 8844
|
|
95
|
-
logger: true
|
|
96
|
-
openapi:
|
|
97
|
-
info:
|
|
98
|
-
title: Feedback API
|
|
99
|
-
version: 1.0.0
|
|
100
|
-
mounts:
|
|
101
|
-
- path: /v1
|
|
102
|
-
mount: !ref FeedbackRoutes
|
|
103
|
-
---
|
|
104
|
-
kind: Http.Api
|
|
105
|
-
metadata:
|
|
106
|
-
name: FeedbackRoutes
|
|
107
|
-
routes:
|
|
108
|
-
# POST /v1/feedback — insert a new entry, score derived from body length heuristic
|
|
109
|
-
- request:
|
|
110
|
-
path: /feedback
|
|
111
|
-
method: POST
|
|
112
|
-
schema:
|
|
113
|
-
body:
|
|
114
|
-
type: object
|
|
115
|
-
properties:
|
|
116
|
-
text:
|
|
117
|
-
type: string
|
|
118
|
-
minLength: 1
|
|
119
|
-
source:
|
|
120
|
-
type: string
|
|
121
|
-
required: [ text ]
|
|
122
|
-
handler:
|
|
123
|
-
kind: Sql.Exec
|
|
124
|
-
connection: !ref Db
|
|
125
|
-
inputs:
|
|
126
|
-
sql: "INSERT INTO feedback (text, source, score) VALUES (?, ?, ?)"
|
|
127
|
-
bindings:
|
|
128
|
-
- "${{ request.body.text }}"
|
|
129
|
-
- "${{ request.body.source }}"
|
|
130
|
-
- "${{ size(request.body.text) }}"
|
|
131
|
-
response:
|
|
132
|
-
- status: 201
|
|
133
|
-
headers:
|
|
134
|
-
Content-Type: application/json
|
|
135
|
-
body:
|
|
136
|
-
ok: true
|
|
137
|
-
message: Feedback received
|
|
138
|
-
|
|
139
|
-
# GET /v1/feedback — list all entries, newest first
|
|
140
|
-
- request:
|
|
141
|
-
path: /feedback
|
|
142
|
-
method: GET
|
|
143
|
-
handler:
|
|
144
|
-
kind: Sql.Select
|
|
145
|
-
connection: !ref Db
|
|
146
|
-
from: feedback
|
|
147
|
-
columns: [ id, text, source, score, created_at ]
|
|
148
|
-
orderBy:
|
|
149
|
-
- { column: created_at, direction: desc }
|
|
150
|
-
response:
|
|
151
|
-
- status: 200
|
|
152
|
-
headers:
|
|
153
|
-
Content-Type: application/json
|
|
154
|
-
body: "${{ result.rows }}"
|
|
155
|
-
|
|
156
|
-
# GET /v1/feedback/{id} — fetch a single entry
|
|
157
|
-
- request:
|
|
158
|
-
path: /feedback/{id}
|
|
159
|
-
method: GET
|
|
160
|
-
schema:
|
|
161
|
-
params:
|
|
162
|
-
type: object
|
|
163
|
-
properties:
|
|
164
|
-
id:
|
|
165
|
-
type: integer
|
|
166
|
-
required: [ id ]
|
|
167
|
-
handler:
|
|
168
|
-
kind: Sql.Select
|
|
169
|
-
connection: !ref Db
|
|
170
|
-
from: feedback
|
|
171
|
-
columns: [ id, text, source, score, created_at ]
|
|
172
|
-
where:
|
|
173
|
-
- { column: id, op: "=", value: "${{ request.params.id }}" }
|
|
174
|
-
response:
|
|
175
|
-
- status: 200
|
|
176
|
-
when: "size(result.rows) > 0"
|
|
177
|
-
headers:
|
|
178
|
-
Content-Type: application/json
|
|
179
|
-
body: "${{ result.rows[0] }}"
|
|
180
|
-
- status: 404
|
|
181
|
-
headers:
|
|
182
|
-
Content-Type: application/json
|
|
183
|
-
body:
|
|
184
|
-
ok: false
|
|
185
|
-
message: Not found
|
|
186
|
-
```
|
|
47
|
+
See [examples/](./examples/) for a list of working applications.
|
|
187
48
|
|
|
188
49
|
## Status
|
|
189
50
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ResourceContext } from "@telorun/sdk";
|
|
2
|
-
import {
|
|
2
|
+
import { SqlConnectionBase } from "@telorun/sql";
|
|
3
|
+
import { Kysely } from "kysely";
|
|
4
|
+
import type { SqliteDb } from "./sqlite-driver-interface.js";
|
|
3
5
|
interface SqliteConnectionManifest {
|
|
4
6
|
metadata: {
|
|
5
7
|
name: string;
|
|
@@ -8,6 +10,13 @@ interface SqliteConnectionManifest {
|
|
|
8
10
|
/** File path, or omitted / `:memory:` for an in-memory database. */
|
|
9
11
|
file?: string;
|
|
10
12
|
}
|
|
13
|
+
declare class SqliteConnection extends SqlConnectionBase {
|
|
14
|
+
private readonly sqlite;
|
|
15
|
+
constructor(db: Kysely<any>, sqlite: SqliteDb);
|
|
16
|
+
/** The driver's native multi-statement entry point — kysely binds one
|
|
17
|
+
* statement per call. */
|
|
18
|
+
executeScript(sql: string): Promise<void>;
|
|
19
|
+
}
|
|
11
20
|
export declare function register(): void;
|
|
12
|
-
export declare function create(resource: SqliteConnectionManifest, _ctx: ResourceContext): Promise<
|
|
21
|
+
export declare function create(resource: SqliteConnectionManifest, _ctx: ResourceContext): Promise<SqliteConnection>;
|
|
13
22
|
export {};
|
|
@@ -1,5 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { quoteAnsiIdentifier, SqlConnectionBase } from "@telorun/sql";
|
|
2
2
|
import { Kysely, SqliteAdapter, SqliteDialect } from "kysely";
|
|
3
|
+
const sqliteDialect = {
|
|
4
|
+
placeholderStyle: "qmark",
|
|
5
|
+
quoteIdentifier: quoteAnsiIdentifier,
|
|
6
|
+
// SQLite has no array type, so set membership expands to one placeholder per
|
|
7
|
+
// element.
|
|
8
|
+
renderIn(column, values, addParam) {
|
|
9
|
+
return `${column} IN (${values.map((value) => addParam(value)).join(", ")})`;
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
class SqliteConnection extends SqlConnectionBase {
|
|
13
|
+
sqlite;
|
|
14
|
+
constructor(db, sqlite) {
|
|
15
|
+
super(db, sqliteDialect);
|
|
16
|
+
this.sqlite = sqlite;
|
|
17
|
+
}
|
|
18
|
+
/** The driver's native multi-statement entry point — kysely binds one
|
|
19
|
+
* statement per call. */
|
|
20
|
+
async executeScript(sql) {
|
|
21
|
+
this.sqlite.exec(sql);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
3
24
|
// Kysely's stock SQLite adapter reports `supportsTransactionalDdl = false`, so
|
|
4
25
|
// its Migrator runs migrations without a transaction. SQLite does support
|
|
5
26
|
// transactional DDL, so we flip the flag — letting the Migrator wrap the whole
|
|
@@ -42,5 +63,5 @@ export async function create(resource, _ctx) {
|
|
|
42
63
|
const db = new Kysely({
|
|
43
64
|
dialect: new TransactionalSqliteDialect({ database: sqlite }),
|
|
44
65
|
});
|
|
45
|
-
return
|
|
66
|
+
return new SqliteConnection(db, sqlite);
|
|
46
67
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { SqliteDb } from "
|
|
1
|
+
import type { SqliteDb } from "./sqlite-driver-interface.js";
|
|
2
2
|
export declare function openDatabase(file: string): SqliteDb;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SqliteStatement {
|
|
2
|
+
readonly reader: boolean;
|
|
3
|
+
all(params: ReadonlyArray<unknown>): unknown[];
|
|
4
|
+
run(params: ReadonlyArray<unknown>): {
|
|
5
|
+
changes: number | bigint;
|
|
6
|
+
lastInsertRowid: number | bigint;
|
|
7
|
+
};
|
|
8
|
+
iterate(params: ReadonlyArray<unknown>): IterableIterator<unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface SqliteDb {
|
|
11
|
+
prepare(sql: string): SqliteStatement;
|
|
12
|
+
exec(sql: string): void;
|
|
13
|
+
close(): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { SqliteDb } from "
|
|
1
|
+
import type { SqliteDb } from "./sqlite-driver-interface.js";
|
|
2
2
|
export declare function openDatabase(file: string): SqliteDb;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telorun/sql-sqlite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Telo SqlSqlite.Connection — SQLite backend for the Sql.Connection abstract (better-sqlite3 / bun:sqlite, transactional DDL).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"telo",
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"better-sqlite3": "^12.8.0",
|
|
38
38
|
"kysely": "^0.28.15",
|
|
39
|
-
"@telorun/sql": "0.
|
|
39
|
+
"@telorun/sql": "0.10.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/better-sqlite3": "^7.0.0",
|
|
43
43
|
"@types/bun": "^1.3.10",
|
|
44
44
|
"@types/node": "^20.0.0",
|
|
45
45
|
"typescript": "^5.0.0",
|
|
46
|
-
"@telorun/sdk": "0.
|
|
46
|
+
"@telorun/sdk": "0.58.0"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"@telorun/sdk": "*"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ResourceContext } from "@telorun/sdk";
|
|
2
|
-
import {
|
|
2
|
+
import { quoteAnsiIdentifier, SqlConnectionBase, type SqlDialect } from "@telorun/sql";
|
|
3
3
|
import { Kysely, SqliteAdapter, SqliteDialect } from "kysely";
|
|
4
|
+
import type { SqliteDb } from "./sqlite-driver-interface.js";
|
|
4
5
|
|
|
5
6
|
interface SqliteConnectionManifest {
|
|
6
7
|
metadata: { name: string; module: string };
|
|
@@ -8,6 +9,31 @@ interface SqliteConnectionManifest {
|
|
|
8
9
|
file?: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
const sqliteDialect: SqlDialect = {
|
|
13
|
+
placeholderStyle: "qmark",
|
|
14
|
+
quoteIdentifier: quoteAnsiIdentifier,
|
|
15
|
+
// SQLite has no array type, so set membership expands to one placeholder per
|
|
16
|
+
// element.
|
|
17
|
+
renderIn(column, values, addParam) {
|
|
18
|
+
return `${column} IN (${values.map((value) => addParam(value)).join(", ")})`;
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
class SqliteConnection extends SqlConnectionBase {
|
|
23
|
+
constructor(
|
|
24
|
+
db: Kysely<any>,
|
|
25
|
+
private readonly sqlite: SqliteDb,
|
|
26
|
+
) {
|
|
27
|
+
super(db, sqliteDialect);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** The driver's native multi-statement entry point — kysely binds one
|
|
31
|
+
* statement per call. */
|
|
32
|
+
override async executeScript(sql: string): Promise<void> {
|
|
33
|
+
this.sqlite.exec(sql);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
11
37
|
// Kysely's stock SQLite adapter reports `supportsTransactionalDdl = false`, so
|
|
12
38
|
// its Migrator runs migrations without a transaction. SQLite does support
|
|
13
39
|
// transactional DDL, so we flip the flag — letting the Migrator wrap the whole
|
|
@@ -53,10 +79,10 @@ export function register(): void {}
|
|
|
53
79
|
export async function create(
|
|
54
80
|
resource: SqliteConnectionManifest,
|
|
55
81
|
_ctx: ResourceContext,
|
|
56
|
-
): Promise<
|
|
82
|
+
): Promise<SqliteConnection> {
|
|
57
83
|
const sqlite = await openSqliteDatabase(resource.file ?? ":memory:");
|
|
58
84
|
const db = new Kysely<any>({
|
|
59
85
|
dialect: new TransactionalSqliteDialect({ database: sqlite }),
|
|
60
86
|
});
|
|
61
|
-
return
|
|
87
|
+
return new SqliteConnection(db, sqlite);
|
|
62
88
|
}
|
package/src/sqlite-driver-bun.ts
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SqliteStatement {
|
|
2
|
+
readonly reader: boolean;
|
|
3
|
+
all(params: ReadonlyArray<unknown>): unknown[];
|
|
4
|
+
run(params: ReadonlyArray<unknown>): {
|
|
5
|
+
changes: number | bigint;
|
|
6
|
+
lastInsertRowid: number | bigint;
|
|
7
|
+
};
|
|
8
|
+
iterate(params: ReadonlyArray<unknown>): IterableIterator<unknown>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SqliteDb {
|
|
12
|
+
prepare(sql: string): SqliteStatement;
|
|
13
|
+
exec(sql: string): void;
|
|
14
|
+
close(): void;
|
|
15
|
+
}
|