sqlite-hub-client 0.2.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 +412 -0
- package/dist/adapters/http.d.ts +22 -0
- package/dist/adapters/http.js +38 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/index.js +5 -0
- package/dist/adapters/types.d.ts +29 -0
- package/dist/adapters/types.js +2 -0
- package/dist/database.d.ts +141 -0
- package/dist/database.js +232 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +25 -0
- package/package.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
# sqlite-db-client
|
|
2
|
+
|
|
3
|
+
High-level TypeScript/JavaScript client for [sqlite-db-hub](https://github.com/0xdps/sqlite-db-hub).
|
|
4
|
+
Comes with a full set of APIs for schema management, reads, writes — all using an **adapter** abstraction so the same code works over HTTP today and can talk to SQLite directly later.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install sqlite-db-client
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { connect } from "sqlite-db-client";
|
|
16
|
+
|
|
17
|
+
const db = connect({
|
|
18
|
+
url: process.env.SQLITE_DB_HUB_URL, // e.g. https://my-app.up.railway.app
|
|
19
|
+
token: process.env.SQLITE_DB_HUB_TOKEN, // ADMIN_TOKEN set on the service
|
|
20
|
+
db: "my-service", // database name
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Create table
|
|
24
|
+
await db.createTable("users", [
|
|
25
|
+
{ name: "id", type: "INTEGER", primaryKey: true, autoIncrement: true },
|
|
26
|
+
{ name: "email", type: "TEXT", notNull: true, unique: true },
|
|
27
|
+
{ name: "name", type: "TEXT" },
|
|
28
|
+
{ name: "created_at", type: "TEXT", default: "(datetime('now'))" },
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
// Create index
|
|
32
|
+
await db.createIndex("idx_users_email", "users", ["email"], { unique: true });
|
|
33
|
+
|
|
34
|
+
// Insert
|
|
35
|
+
const { lastInsertRowid } = await db.insert("users", {
|
|
36
|
+
email: "alice@example.com",
|
|
37
|
+
name: "Alice",
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Bulk insert
|
|
41
|
+
await db.insertMany("users", [
|
|
42
|
+
{ email: "bob@example.com", name: "Bob" },
|
|
43
|
+
{ email: "carol@example.com", name: "Carol" },
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
// Read — find all
|
|
47
|
+
const users = await db.find<{ id: number; email: string; name: string }>(
|
|
48
|
+
"users"
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// Read — filtered, paginated, ordered
|
|
52
|
+
const page = await db.find(
|
|
53
|
+
"users",
|
|
54
|
+
{},
|
|
55
|
+
{
|
|
56
|
+
orderBy: "created_at",
|
|
57
|
+
order: "DESC",
|
|
58
|
+
limit: 10,
|
|
59
|
+
offset: 0,
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Read — single row by arbitrary filter
|
|
64
|
+
const alice = await db.findOne("users", { email: "alice@example.com" });
|
|
65
|
+
|
|
66
|
+
// Read — by primary key
|
|
67
|
+
const user = await db.findById("users", 1);
|
|
68
|
+
|
|
69
|
+
// Count
|
|
70
|
+
const total = await db.count("users");
|
|
71
|
+
const active = await db.count("users", { active: 1 });
|
|
72
|
+
|
|
73
|
+
// Exists check
|
|
74
|
+
const exists = await db.exists("users", { email: "alice@example.com" });
|
|
75
|
+
|
|
76
|
+
// Update
|
|
77
|
+
await db.update("users", { name: "Alice Smith" }, { id: 1 });
|
|
78
|
+
|
|
79
|
+
// Delete
|
|
80
|
+
await db.delete("users", { id: 1 });
|
|
81
|
+
|
|
82
|
+
// Drop table
|
|
83
|
+
await db.dropTable("users");
|
|
84
|
+
|
|
85
|
+
// Raw SQL escape hatch
|
|
86
|
+
const result = await db.exec("PRAGMA table_info(users)");
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## API
|
|
90
|
+
|
|
91
|
+
### `connect(options)` — create a database client
|
|
92
|
+
|
|
93
|
+
| Option | Type | Required | Description |
|
|
94
|
+
| --------- | -------- | -------- | ----------------------------------------------------- |
|
|
95
|
+
| `url` | `string` | ✅ | Base URL of your sqlite-db-hub deployment |
|
|
96
|
+
| `token` | `string` | ✅ | `ADMIN_TOKEN` configured on the sqlite-db-hub service |
|
|
97
|
+
| `db` | `string` | ✅ | Name of the database to operate on |
|
|
98
|
+
| `timeout` | `number` | ❌ | Request timeout in ms (default: `10000`) |
|
|
99
|
+
|
|
100
|
+
Returns a `Database` instance.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### Schema
|
|
105
|
+
|
|
106
|
+
#### `db.createTable(table, columns, options?)`
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
await db.createTable(
|
|
110
|
+
"posts",
|
|
111
|
+
[
|
|
112
|
+
{ name: "id", type: "INTEGER", primaryKey: true, autoIncrement: true },
|
|
113
|
+
{ name: "title", type: "TEXT", notNull: true },
|
|
114
|
+
{ name: "body", type: "TEXT" },
|
|
115
|
+
],
|
|
116
|
+
{ ifNotExists: true }
|
|
117
|
+
); // ifNotExists: true is the default
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**`ColumnDef` fields:**
|
|
121
|
+
|
|
122
|
+
| Field | Type | Description |
|
|
123
|
+
| --------------- | ------------------ | ---------------------------------------------- |
|
|
124
|
+
| `name` | `string` | Column name |
|
|
125
|
+
| `type` | `string` | SQLite type: `INTEGER`, `TEXT`, `REAL`, `BLOB` |
|
|
126
|
+
| `primaryKey` | `boolean` | Mark as PRIMARY KEY |
|
|
127
|
+
| `autoIncrement` | `boolean` | Add AUTOINCREMENT |
|
|
128
|
+
| `notNull` | `boolean` | Add NOT NULL constraint |
|
|
129
|
+
| `unique` | `boolean` | Add UNIQUE constraint |
|
|
130
|
+
| `default` | `string \| number` | DEFAULT value (raw SQL fragment) |
|
|
131
|
+
|
|
132
|
+
#### `db.dropTable(table, ifExists?)`
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
await db.dropTable("posts"); // IF EXISTS by default
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### `db.createIndex(indexName, table, columns, options?)`
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
await db.createIndex("idx_posts_title", "posts", ["title"]);
|
|
142
|
+
await db.createIndex("idx_unique_email", "users", ["email"], { unique: true });
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### `db.dropIndex(indexName, ifExists?)`
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
await db.dropIndex("idx_posts_title");
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### Write
|
|
154
|
+
|
|
155
|
+
#### `db.insert(table, data)` → `ExecResult`
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const { lastInsertRowid } = await db.insert("posts", {
|
|
159
|
+
title: "Hello",
|
|
160
|
+
body: "World",
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### `db.insertMany(table, rows)` → `ExecResult`
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
await db.insertMany("posts", [
|
|
168
|
+
{ title: "Post 1", body: "..." },
|
|
169
|
+
{ title: "Post 2", body: "..." },
|
|
170
|
+
]);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### `db.update(table, data, where)` → `ExecResult`
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
const { rowsAffected } = await db.update(
|
|
177
|
+
"posts",
|
|
178
|
+
{ title: "Updated" },
|
|
179
|
+
{ id: 1 }
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### `db.delete(table, where)` → `ExecResult`
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
await db.delete("posts", { id: 1 });
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### Read
|
|
192
|
+
|
|
193
|
+
#### `db.find<T>(table, where?, options?)` → `T[]`
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const posts = await db.find<Post>(
|
|
197
|
+
"posts",
|
|
198
|
+
{ published: 1 },
|
|
199
|
+
{
|
|
200
|
+
columns: ["id", "title"],
|
|
201
|
+
orderBy: "created_at",
|
|
202
|
+
order: "DESC", // "ASC" | "DESC"
|
|
203
|
+
limit: 20,
|
|
204
|
+
offset: 0,
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### `db.findOne<T>(table, where?)` → `T | null`
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
const post = await db.findOne<Post>("posts", { id: 5 });
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### `db.findById<T>(table, id, idColumn?)` → `T | null`
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const post = await db.findById<Post>("posts", 5); // uses "id" column
|
|
219
|
+
const item = await db.findById<Item>("items", "abc", "slug"); // custom PK column
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### `db.count(table, where?)` → `number`
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
const total = await db.count("posts");
|
|
226
|
+
const drafts = await db.count("posts", { published: 0 });
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### `db.exists(table, where)` → `boolean`
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
const taken = await db.exists("users", { email: "alice@example.com" });
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### Raw SQL
|
|
238
|
+
|
|
239
|
+
#### `db.exec<T>(sql, bindings?)` → `QueryResult<T> | ExecResult`
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
// SELECT → QueryResult
|
|
243
|
+
const result = await db.exec<{ n: number }>("SELECT COUNT(*) AS n FROM posts");
|
|
244
|
+
|
|
245
|
+
// DDL / DML → ExecResult
|
|
246
|
+
await db.exec("CREATE INDEX IF NOT EXISTS idx_title ON posts (title)");
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Architecture
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
sqlite-db-client
|
|
255
|
+
├── index.ts ← connect() factory + all public exports
|
|
256
|
+
├── database.ts ← Database class — all high-level APIs
|
|
257
|
+
└── adapters/
|
|
258
|
+
├── types.ts ← IAdapter interface (exec only)
|
|
259
|
+
├── http.ts ← HttpAdapter (sqlite-db-hub over HTTP)
|
|
260
|
+
└── index.ts ← re-exports
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Adding a direct SQLite adapter in the future is a one-liner:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
// future
|
|
267
|
+
import { Database } from "sqlite-db-client";
|
|
268
|
+
import { DirectAdapter } from "sqlite-db-client/adapters/direct"; // coming soon
|
|
269
|
+
|
|
270
|
+
const db = new Database(new DirectAdapter({ path: "./local.db" }));
|
|
271
|
+
// same API — createTable, find, insert, update, delete…
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
MIT
|
|
277
|
+
|
|
278
|
+
## Install
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
npm install sqlite-db-hub-client
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Or directly from GitHub (before the npm package is published):
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
npm install github:0xdps/sqlite-db-hub-client
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Quick start
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
import { createClient } from "sqlite-db-hub-client";
|
|
294
|
+
|
|
295
|
+
const db = createClient({
|
|
296
|
+
url: process.env.SQLITE_DB_HUB_URL, // e.g. https://my-app.up.railway.app
|
|
297
|
+
token: process.env.SQLITE_DB_HUB_TOKEN, // ADMIN_TOKEN set on the service
|
|
298
|
+
db: "my-service", // name of the database to use
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Create a table
|
|
302
|
+
await db.run(`
|
|
303
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
304
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
305
|
+
email TEXT NOT NULL UNIQUE,
|
|
306
|
+
name TEXT
|
|
307
|
+
)
|
|
308
|
+
`);
|
|
309
|
+
|
|
310
|
+
// Insert a row
|
|
311
|
+
await db.run("INSERT INTO users (email, name) VALUES (?, ?)", [
|
|
312
|
+
"alice@example.com",
|
|
313
|
+
"Alice",
|
|
314
|
+
]);
|
|
315
|
+
|
|
316
|
+
// Query rows (typed)
|
|
317
|
+
const users = await db.query<{ id: number; email: string; name: string }>(
|
|
318
|
+
"SELECT * FROM users"
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
// Query a single row (or null)
|
|
322
|
+
const user = await db.queryOne<{ id: number; email: string }>(
|
|
323
|
+
"SELECT * FROM users WHERE email = ?",
|
|
324
|
+
["alice@example.com"]
|
|
325
|
+
);
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## API
|
|
329
|
+
|
|
330
|
+
### `createClient(options)` / `new FileDbClient(options)`
|
|
331
|
+
|
|
332
|
+
| Option | Type | Required | Description |
|
|
333
|
+
| --------- | -------- | -------- | ----------------------------------------------------- |
|
|
334
|
+
| `url` | `string` | ✅ | Base URL of your sqlite-db-hub deployment |
|
|
335
|
+
| `token` | `string` | ✅ | `ADMIN_TOKEN` configured on the sqlite-db-hub service |
|
|
336
|
+
| `db` | `string` | ✅ | Name of the database to operate on |
|
|
337
|
+
| `timeout` | `number` | ❌ | Request timeout in ms (default: `10000`) |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
### `db.exec(sql, bindings?)`
|
|
342
|
+
|
|
343
|
+
Run any SQL statement. Returns a `QueryResult` for SELECT, or an `ExecResult` for writes.
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
const result = await db.exec("SELECT count(*) as n FROM users");
|
|
347
|
+
// { headers: [...], rows: [{ n: 1 }], rowsRead: 1 }
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
### `db.query<T>(sql, bindings?)`
|
|
353
|
+
|
|
354
|
+
Run a SELECT and return typed rows.
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
const rows = await db.query<{ id: number; name: string }>(
|
|
358
|
+
"SELECT id, name FROM users WHERE id > ?",
|
|
359
|
+
[5]
|
|
360
|
+
);
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
### `db.queryOne<T>(sql, bindings?)`
|
|
366
|
+
|
|
367
|
+
Run a SELECT and return the first row, or `null` if no results.
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
const row = await db.queryOne<{ name: string }>(
|
|
371
|
+
"SELECT name FROM users WHERE id = ?",
|
|
372
|
+
[1]
|
|
373
|
+
);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
### `db.run(sql, bindings?)`
|
|
379
|
+
|
|
380
|
+
Run a write statement (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP). Returns `{ rowsAffected, lastInsertRowid }`.
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
const { rowsAffected, lastInsertRowid } = await db.run(
|
|
384
|
+
"INSERT INTO jobs (payload) VALUES (?)",
|
|
385
|
+
[JSON.stringify({ task: "send-email" })]
|
|
386
|
+
);
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Types
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
interface QueryResult<T> {
|
|
393
|
+
headers: ColumnHeader[];
|
|
394
|
+
rows: T[];
|
|
395
|
+
rowsRead: number;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
interface ExecResult {
|
|
399
|
+
rowsAffected: number;
|
|
400
|
+
lastInsertRowid: number | null;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
interface ColumnHeader {
|
|
404
|
+
name: string;
|
|
405
|
+
displayName: string;
|
|
406
|
+
originalType: string | null;
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## License
|
|
411
|
+
|
|
412
|
+
MIT
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IAdapter, RawResult } from "./types.js";
|
|
2
|
+
export interface HttpAdapterOptions {
|
|
3
|
+
/** Base URL of the sqlite-db-hub deployment, e.g. https://my-app.up.railway.app */
|
|
4
|
+
url: string;
|
|
5
|
+
/** ADMIN_TOKEN configured on the sqlite-db-hub service */
|
|
6
|
+
token: string;
|
|
7
|
+
/** Name of the database to operate on */
|
|
8
|
+
db: string;
|
|
9
|
+
/** Request timeout in ms (default: 10 000) */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Adapter that executes SQL via the sqlite-db-hub HTTP API
|
|
14
|
+
* (POST /api/db/:name/exec).
|
|
15
|
+
*/
|
|
16
|
+
export declare class HttpAdapter implements IAdapter {
|
|
17
|
+
private readonly options;
|
|
18
|
+
private readonly http;
|
|
19
|
+
private readonly dbPath;
|
|
20
|
+
constructor(options: HttpAdapterOptions);
|
|
21
|
+
exec<T = Record<string, unknown>>(sql: string, bindings?: unknown[]): Promise<RawResult<T>>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.HttpAdapter = void 0;
|
|
7
|
+
const fetch_1 = __importDefault(require("@pingpong-js/fetch"));
|
|
8
|
+
/**
|
|
9
|
+
* Adapter that executes SQL via the sqlite-db-hub HTTP API
|
|
10
|
+
* (POST /api/db/:name/exec).
|
|
11
|
+
*/
|
|
12
|
+
class HttpAdapter {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
this.dbPath = `/api/db/${encodeURIComponent(options.db)}/exec`;
|
|
16
|
+
this.http = fetch_1.default.create({
|
|
17
|
+
baseURL: options.url.replace(/\/$/, ""),
|
|
18
|
+
timeout: options.timeout ?? 10000,
|
|
19
|
+
headers: {
|
|
20
|
+
Authorization: `Bearer ${options.token}`,
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async exec(sql, bindings) {
|
|
26
|
+
const res = await this.http.post(this.dbPath, {
|
|
27
|
+
sql,
|
|
28
|
+
...(bindings?.length ? { bindings } : {}),
|
|
29
|
+
});
|
|
30
|
+
if (res.isError()) {
|
|
31
|
+
const body = res.data;
|
|
32
|
+
throw new Error(body?.error ??
|
|
33
|
+
`sqlite-db-hub: HTTP ${res.status} for db "${this.options.db}"`);
|
|
34
|
+
}
|
|
35
|
+
return res.data;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.HttpAdapter = HttpAdapter;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpAdapter = void 0;
|
|
4
|
+
var http_js_1 = require("./http.js");
|
|
5
|
+
Object.defineProperty(exports, "HttpAdapter", { enumerable: true, get: function () { return http_js_1.HttpAdapter; } });
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** A single column header returned by a SELECT */
|
|
2
|
+
export interface ColumnHeader {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
originalType: string | null;
|
|
6
|
+
}
|
|
7
|
+
/** Result of a SELECT statement */
|
|
8
|
+
export interface QueryResult<T = Record<string, unknown>> {
|
|
9
|
+
headers: ColumnHeader[];
|
|
10
|
+
rows: T[];
|
|
11
|
+
rowsRead: number;
|
|
12
|
+
}
|
|
13
|
+
/** Result of INSERT / UPDATE / DELETE / DDL */
|
|
14
|
+
export interface ExecResult {
|
|
15
|
+
rowsAffected: number;
|
|
16
|
+
lastInsertRowid: number | null;
|
|
17
|
+
}
|
|
18
|
+
export type RawResult<T = Record<string, unknown>> = QueryResult<T> | ExecResult;
|
|
19
|
+
/**
|
|
20
|
+
* Minimal contract every adapter must fulfil.
|
|
21
|
+
* Only `exec` is required — all high-level APIs are built on top of it.
|
|
22
|
+
*/
|
|
23
|
+
export interface IAdapter {
|
|
24
|
+
/**
|
|
25
|
+
* Execute a SQL statement with optional positional bindings.
|
|
26
|
+
* Returns QueryResult for SELECT, ExecResult for everything else.
|
|
27
|
+
*/
|
|
28
|
+
exec<T = Record<string, unknown>>(sql: string, bindings?: unknown[]): Promise<RawResult<T>>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { IAdapter, ExecResult, RawResult } from "./adapters/types.js";
|
|
2
|
+
export type WhereClause = Record<string, unknown>;
|
|
3
|
+
export type OrderDirection = "ASC" | "DESC";
|
|
4
|
+
export interface FindOptions {
|
|
5
|
+
/** Columns to SELECT (default: all) */
|
|
6
|
+
columns?: string[];
|
|
7
|
+
orderBy?: string;
|
|
8
|
+
order?: OrderDirection;
|
|
9
|
+
limit?: number;
|
|
10
|
+
offset?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface ColumnDef {
|
|
13
|
+
name: string;
|
|
14
|
+
type: "INTEGER" | "TEXT" | "REAL" | "BLOB" | "NUMERIC" | string;
|
|
15
|
+
primaryKey?: boolean;
|
|
16
|
+
autoIncrement?: boolean;
|
|
17
|
+
notNull?: boolean;
|
|
18
|
+
unique?: boolean;
|
|
19
|
+
default?: string | number;
|
|
20
|
+
}
|
|
21
|
+
export interface CreateTableOptions {
|
|
22
|
+
ifNotExists?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface CreateIndexOptions {
|
|
25
|
+
unique?: boolean;
|
|
26
|
+
ifNotExists?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* High-level database client.
|
|
30
|
+
* Accepts any `IAdapter` — currently `HttpAdapter`, extensible to direct
|
|
31
|
+
* SQLite (via better-sqlite3 or sql.js) without changing business code.
|
|
32
|
+
*/
|
|
33
|
+
export declare class Database {
|
|
34
|
+
private readonly adapter;
|
|
35
|
+
constructor(adapter: IAdapter);
|
|
36
|
+
/**
|
|
37
|
+
* Create a table.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* await db.createTable("users", [
|
|
41
|
+
* { name: "id", type: "INTEGER", primaryKey: true, autoIncrement: true },
|
|
42
|
+
* { name: "email", type: "TEXT", notNull: true, unique: true },
|
|
43
|
+
* { name: "name", type: "TEXT" },
|
|
44
|
+
* ]);
|
|
45
|
+
*/
|
|
46
|
+
createTable(table: string, columns: ColumnDef[], options?: CreateTableOptions): Promise<ExecResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Drop a table.
|
|
49
|
+
*/
|
|
50
|
+
dropTable(table: string, ifExists?: boolean): Promise<ExecResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Create an index on one or more columns.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* await db.createIndex("idx_users_email", "users", ["email"], { unique: true });
|
|
56
|
+
*/
|
|
57
|
+
createIndex(indexName: string, table: string, columns: string[], options?: CreateIndexOptions): Promise<ExecResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Drop an index.
|
|
60
|
+
*/
|
|
61
|
+
dropIndex(indexName: string, ifExists?: boolean): Promise<ExecResult>;
|
|
62
|
+
/**
|
|
63
|
+
* Insert a single row. Returns `{ rowsAffected, lastInsertRowid }`.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* const { lastInsertRowid } = await db.insert("users", { email: "a@b.com", name: "Alice" });
|
|
67
|
+
*/
|
|
68
|
+
insert(table: string, data: Record<string, unknown>): Promise<ExecResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Insert multiple rows in a single transaction.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* await db.insertMany("users", [
|
|
74
|
+
* { email: "a@b.com", name: "Alice" },
|
|
75
|
+
* { email: "b@c.com", name: "Bob" },
|
|
76
|
+
* ]);
|
|
77
|
+
*/
|
|
78
|
+
insertMany(table: string, rows: Record<string, unknown>[]): Promise<ExecResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Update rows matching `where`.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* await db.update("users", { name: "Bob" }, { id: 1 });
|
|
84
|
+
*/
|
|
85
|
+
update(table: string, data: Record<string, unknown>, where: WhereClause): Promise<ExecResult>;
|
|
86
|
+
/**
|
|
87
|
+
* Delete rows matching `where`.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* await db.delete("users", { id: 1 });
|
|
91
|
+
*/
|
|
92
|
+
delete(table: string, where: WhereClause): Promise<ExecResult>;
|
|
93
|
+
/**
|
|
94
|
+
* Find rows with optional filtering, ordering, and pagination.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* const users = await db.find<User>("users", { active: 1 }, {
|
|
98
|
+
* columns: ["id", "email"],
|
|
99
|
+
* orderBy: "created_at",
|
|
100
|
+
* order: "DESC",
|
|
101
|
+
* limit: 20,
|
|
102
|
+
* offset: 0,
|
|
103
|
+
* });
|
|
104
|
+
*/
|
|
105
|
+
find<T = Record<string, unknown>>(table: string, where?: WhereClause, options?: FindOptions): Promise<T[]>;
|
|
106
|
+
/**
|
|
107
|
+
* Find the first row matching `where`, or `null`.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* const user = await db.findOne<User>("users", { email: "a@b.com" });
|
|
111
|
+
*/
|
|
112
|
+
findOne<T = Record<string, unknown>>(table: string, where?: WhereClause): Promise<T | null>;
|
|
113
|
+
/**
|
|
114
|
+
* Find a row by its primary key value (column `id` by default).
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* const user = await db.findById<User>("users", 42);
|
|
118
|
+
*/
|
|
119
|
+
findById<T = Record<string, unknown>>(table: string, id: unknown, idColumn?: string): Promise<T | null>;
|
|
120
|
+
/**
|
|
121
|
+
* Count rows matching `where`.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* const total = await db.count("users");
|
|
125
|
+
* const active = await db.count("users", { active: 1 });
|
|
126
|
+
*/
|
|
127
|
+
count(table: string, where?: WhereClause): Promise<number>;
|
|
128
|
+
/**
|
|
129
|
+
* Check whether any row matching `where` exists.
|
|
130
|
+
*/
|
|
131
|
+
exists(table: string, where: WhereClause): Promise<boolean>;
|
|
132
|
+
/**
|
|
133
|
+
* Run any raw SQL statement.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* const result = await db.exec("PRAGMA table_info(users)");
|
|
137
|
+
*/
|
|
138
|
+
exec<T = Record<string, unknown>>(sql: string, bindings?: unknown[]): Promise<RawResult<T>>;
|
|
139
|
+
private _read;
|
|
140
|
+
private _write;
|
|
141
|
+
}
|
package/dist/database.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Database = void 0;
|
|
4
|
+
// ── SQL builder helpers ─────────────────────────────────────────────────────
|
|
5
|
+
function buildWhere(where) {
|
|
6
|
+
const keys = Object.keys(where);
|
|
7
|
+
if (keys.length === 0)
|
|
8
|
+
return { clause: "", bindings: [] };
|
|
9
|
+
const parts = keys.map((k) => `"${k}" = ?`);
|
|
10
|
+
return {
|
|
11
|
+
clause: " WHERE " + parts.join(" AND "),
|
|
12
|
+
bindings: keys.map((k) => where[k]),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function isQueryResult(r) {
|
|
16
|
+
return "rows" in r;
|
|
17
|
+
}
|
|
18
|
+
function isExecResult(r) {
|
|
19
|
+
return "rowsAffected" in r;
|
|
20
|
+
}
|
|
21
|
+
// ── Database ─────────────────────────────────────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* High-level database client.
|
|
24
|
+
* Accepts any `IAdapter` — currently `HttpAdapter`, extensible to direct
|
|
25
|
+
* SQLite (via better-sqlite3 or sql.js) without changing business code.
|
|
26
|
+
*/
|
|
27
|
+
class Database {
|
|
28
|
+
constructor(adapter) {
|
|
29
|
+
this.adapter = adapter;
|
|
30
|
+
}
|
|
31
|
+
// ── Schema ──────────────────────────────────────────────────────────────
|
|
32
|
+
/**
|
|
33
|
+
* Create a table.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* await db.createTable("users", [
|
|
37
|
+
* { name: "id", type: "INTEGER", primaryKey: true, autoIncrement: true },
|
|
38
|
+
* { name: "email", type: "TEXT", notNull: true, unique: true },
|
|
39
|
+
* { name: "name", type: "TEXT" },
|
|
40
|
+
* ]);
|
|
41
|
+
*/
|
|
42
|
+
async createTable(table, columns, options = {}) {
|
|
43
|
+
const ifNotExists = options.ifNotExists !== false ? "IF NOT EXISTS" : "";
|
|
44
|
+
const cols = columns.map((c) => {
|
|
45
|
+
let def = `"${c.name}" ${c.type}`;
|
|
46
|
+
if (c.primaryKey)
|
|
47
|
+
def += " PRIMARY KEY";
|
|
48
|
+
if (c.autoIncrement)
|
|
49
|
+
def += " AUTOINCREMENT";
|
|
50
|
+
if (c.notNull)
|
|
51
|
+
def += " NOT NULL";
|
|
52
|
+
if (c.unique)
|
|
53
|
+
def += " UNIQUE";
|
|
54
|
+
if (c.default !== undefined)
|
|
55
|
+
def += ` DEFAULT ${c.default}`;
|
|
56
|
+
return def;
|
|
57
|
+
});
|
|
58
|
+
const sql = `CREATE TABLE ${ifNotExists} "${table}" (${cols.join(", ")})`;
|
|
59
|
+
return this._write(sql);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Drop a table.
|
|
63
|
+
*/
|
|
64
|
+
async dropTable(table, ifExists = true) {
|
|
65
|
+
const ie = ifExists ? "IF EXISTS" : "";
|
|
66
|
+
return this._write(`DROP TABLE ${ie} "${table}"`);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create an index on one or more columns.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* await db.createIndex("idx_users_email", "users", ["email"], { unique: true });
|
|
73
|
+
*/
|
|
74
|
+
async createIndex(indexName, table, columns, options = {}) {
|
|
75
|
+
const unique = options.unique ? "UNIQUE" : "";
|
|
76
|
+
const ifNotExists = options.ifNotExists !== false ? "IF NOT EXISTS" : "";
|
|
77
|
+
const cols = columns.map((c) => `"${c}"`).join(", ");
|
|
78
|
+
const sql = `CREATE ${unique} INDEX ${ifNotExists} "${indexName}" ON "${table}" (${cols})`;
|
|
79
|
+
return this._write(sql);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Drop an index.
|
|
83
|
+
*/
|
|
84
|
+
async dropIndex(indexName, ifExists = true) {
|
|
85
|
+
const ie = ifExists ? "IF EXISTS" : "";
|
|
86
|
+
return this._write(`DROP INDEX ${ie} "${indexName}"`);
|
|
87
|
+
}
|
|
88
|
+
// ── Write ────────────────────────────────────────────────────────────────
|
|
89
|
+
/**
|
|
90
|
+
* Insert a single row. Returns `{ rowsAffected, lastInsertRowid }`.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* const { lastInsertRowid } = await db.insert("users", { email: "a@b.com", name: "Alice" });
|
|
94
|
+
*/
|
|
95
|
+
async insert(table, data) {
|
|
96
|
+
const keys = Object.keys(data);
|
|
97
|
+
const cols = keys.map((k) => `"${k}"`).join(", ");
|
|
98
|
+
const placeholders = keys.map(() => "?").join(", ");
|
|
99
|
+
const bindings = keys.map((k) => data[k]);
|
|
100
|
+
return this._write(`INSERT INTO "${table}" (${cols}) VALUES (${placeholders})`, bindings);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Insert multiple rows in a single transaction.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* await db.insertMany("users", [
|
|
107
|
+
* { email: "a@b.com", name: "Alice" },
|
|
108
|
+
* { email: "b@c.com", name: "Bob" },
|
|
109
|
+
* ]);
|
|
110
|
+
*/
|
|
111
|
+
async insertMany(table, rows) {
|
|
112
|
+
if (rows.length === 0)
|
|
113
|
+
return { rowsAffected: 0, lastInsertRowid: null };
|
|
114
|
+
const keys = Object.keys(rows[0]);
|
|
115
|
+
const cols = keys.map((k) => `"${k}"`).join(", ");
|
|
116
|
+
const rowPlaceholders = rows.map(() => `(${keys.map(() => "?").join(", ")})`).join(", ");
|
|
117
|
+
const bindings = rows.flatMap((row) => keys.map((k) => row[k]));
|
|
118
|
+
return this._write(`INSERT INTO "${table}" (${cols}) VALUES ${rowPlaceholders}`, bindings);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Update rows matching `where`.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* await db.update("users", { name: "Bob" }, { id: 1 });
|
|
125
|
+
*/
|
|
126
|
+
async update(table, data, where) {
|
|
127
|
+
const setKeys = Object.keys(data);
|
|
128
|
+
const setClauses = setKeys.map((k) => `"${k}" = ?`).join(", ");
|
|
129
|
+
const setBindings = setKeys.map((k) => data[k]);
|
|
130
|
+
const { clause, bindings: whereBindings } = buildWhere(where);
|
|
131
|
+
return this._write(`UPDATE "${table}" SET ${setClauses}${clause}`, [...setBindings, ...whereBindings]);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Delete rows matching `where`.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* await db.delete("users", { id: 1 });
|
|
138
|
+
*/
|
|
139
|
+
async delete(table, where) {
|
|
140
|
+
const { clause, bindings } = buildWhere(where);
|
|
141
|
+
return this._write(`DELETE FROM "${table}"${clause}`, bindings);
|
|
142
|
+
}
|
|
143
|
+
// ── Read ─────────────────────────────────────────────────────────────────
|
|
144
|
+
/**
|
|
145
|
+
* Find rows with optional filtering, ordering, and pagination.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* const users = await db.find<User>("users", { active: 1 }, {
|
|
149
|
+
* columns: ["id", "email"],
|
|
150
|
+
* orderBy: "created_at",
|
|
151
|
+
* order: "DESC",
|
|
152
|
+
* limit: 20,
|
|
153
|
+
* offset: 0,
|
|
154
|
+
* });
|
|
155
|
+
*/
|
|
156
|
+
async find(table, where = {}, options = {}) {
|
|
157
|
+
const cols = options.columns?.map((c) => `"${c}"`).join(", ") ?? "*";
|
|
158
|
+
const { clause, bindings } = buildWhere(where);
|
|
159
|
+
let sql = `SELECT ${cols} FROM "${table}"${clause}`;
|
|
160
|
+
if (options.orderBy)
|
|
161
|
+
sql += ` ORDER BY "${options.orderBy}" ${options.order ?? "ASC"}`;
|
|
162
|
+
if (options.limit !== undefined)
|
|
163
|
+
sql += ` LIMIT ${options.limit}`;
|
|
164
|
+
if (options.offset !== undefined)
|
|
165
|
+
sql += ` OFFSET ${options.offset}`;
|
|
166
|
+
return this._read(sql, bindings);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Find the first row matching `where`, or `null`.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* const user = await db.findOne<User>("users", { email: "a@b.com" });
|
|
173
|
+
*/
|
|
174
|
+
async findOne(table, where = {}) {
|
|
175
|
+
const rows = await this.find(table, where, { limit: 1 });
|
|
176
|
+
return rows[0] ?? null;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Find a row by its primary key value (column `id` by default).
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* const user = await db.findById<User>("users", 42);
|
|
183
|
+
*/
|
|
184
|
+
async findById(table, id, idColumn = "id") {
|
|
185
|
+
return this.findOne(table, { [idColumn]: id });
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Count rows matching `where`.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* const total = await db.count("users");
|
|
192
|
+
* const active = await db.count("users", { active: 1 });
|
|
193
|
+
*/
|
|
194
|
+
async count(table, where = {}) {
|
|
195
|
+
const { clause, bindings } = buildWhere(where);
|
|
196
|
+
const sql = `SELECT COUNT(*) AS n FROM "${table}"${clause}`;
|
|
197
|
+
const rows = await this._read(sql, bindings);
|
|
198
|
+
return rows[0]?.n ?? 0;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Check whether any row matching `where` exists.
|
|
202
|
+
*/
|
|
203
|
+
async exists(table, where) {
|
|
204
|
+
return (await this.count(table, where)) > 0;
|
|
205
|
+
}
|
|
206
|
+
// ── Raw escape hatch ─────────────────────────────────────────────────────
|
|
207
|
+
/**
|
|
208
|
+
* Run any raw SQL statement.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* const result = await db.exec("PRAGMA table_info(users)");
|
|
212
|
+
*/
|
|
213
|
+
async exec(sql, bindings) {
|
|
214
|
+
return this.adapter.exec(sql, bindings);
|
|
215
|
+
}
|
|
216
|
+
// ── Internal ─────────────────────────────────────────────────────────────
|
|
217
|
+
async _read(sql, bindings) {
|
|
218
|
+
const result = await this.adapter.exec(sql, bindings);
|
|
219
|
+
if (!isQueryResult(result)) {
|
|
220
|
+
throw new Error(`sqlite-db-hub: expected SELECT, got write result for: ${sql}`);
|
|
221
|
+
}
|
|
222
|
+
return result.rows;
|
|
223
|
+
}
|
|
224
|
+
async _write(sql, bindings) {
|
|
225
|
+
const result = await this.adapter.exec(sql, bindings);
|
|
226
|
+
if (!isExecResult(result)) {
|
|
227
|
+
throw new Error(`sqlite-db-hub: expected write result, got SELECT for: ${sql}`);
|
|
228
|
+
}
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
exports.Database = Database;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { Database } from "./database.js";
|
|
2
|
+
export type { WhereClause, FindOptions, ColumnDef, CreateTableOptions, CreateIndexOptions, OrderDirection, } from "./database.js";
|
|
3
|
+
export { HttpAdapter } from "./adapters/http.js";
|
|
4
|
+
export type { HttpAdapterOptions } from "./adapters/http.js";
|
|
5
|
+
export type { IAdapter, ColumnHeader, QueryResult, ExecResult, RawResult, } from "./adapters/types.js";
|
|
6
|
+
import { Database } from "./database.js";
|
|
7
|
+
import { type HttpAdapterOptions } from "./adapters/http.js";
|
|
8
|
+
/**
|
|
9
|
+
* Create a Database connected to a sqlite-db-hub service over HTTP.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const db = connect({
|
|
13
|
+
* url: process.env.SQLITE_DB_HUB_URL,
|
|
14
|
+
* token: process.env.SQLITE_DB_HUB_TOKEN,
|
|
15
|
+
* db: "my-service",
|
|
16
|
+
* });
|
|
17
|
+
*/
|
|
18
|
+
export declare function connect(options: HttpAdapterOptions): Database;
|
|
19
|
+
export default connect;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpAdapter = exports.Database = void 0;
|
|
4
|
+
exports.connect = connect;
|
|
5
|
+
var database_js_1 = require("./database.js");
|
|
6
|
+
Object.defineProperty(exports, "Database", { enumerable: true, get: function () { return database_js_1.Database; } });
|
|
7
|
+
var http_js_1 = require("./adapters/http.js");
|
|
8
|
+
Object.defineProperty(exports, "HttpAdapter", { enumerable: true, get: function () { return http_js_1.HttpAdapter; } });
|
|
9
|
+
// ── Convenience factory ──────────────────────────────────────────────────────
|
|
10
|
+
const database_js_2 = require("./database.js");
|
|
11
|
+
const http_js_2 = require("./adapters/http.js");
|
|
12
|
+
/**
|
|
13
|
+
* Create a Database connected to a sqlite-db-hub service over HTTP.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const db = connect({
|
|
17
|
+
* url: process.env.SQLITE_DB_HUB_URL,
|
|
18
|
+
* token: process.env.SQLITE_DB_HUB_TOKEN,
|
|
19
|
+
* db: "my-service",
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
function connect(options) {
|
|
23
|
+
return new database_js_2.Database(new http_js_2.HttpAdapter(options));
|
|
24
|
+
}
|
|
25
|
+
exports.default = connect;
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sqlite-hub-client",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "High-level SQLite client for sqlite-db-hub — HTTP adapter included, direct SQLite coming soon",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": ["dist", "README.md"],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc"
|
|
10
|
+
},
|
|
11
|
+
"keywords": ["sqlite", "sqlite-db-hub", "railway", "orm", "database"],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@pingpong-js/fetch": "^1.0.2"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"typescript": "^5"
|
|
18
|
+
}
|
|
19
|
+
}
|