@dockstat/sqlite-wrapper 1.0.0 → 1.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/LICENSE +373 -0
- package/README.md +33 -558
- package/dist/index.d.ts +649 -122
- package/dist/index.js +20 -4
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,578 +1,53 @@
|
|
|
1
|
-
# @dockstat/
|
|
1
|
+
# @dockstat/sqlite-wrapper
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
**A fast, type-safe TypeScript wrapper for Bun's `bun:sqlite`.**
|
|
8
|
+
Schema-first table helpers, an expressive chainable QueryBuilder, safe defaults (WHERE required for destructive ops), JSON + generated columns, and production-minded pragmas & transactions.
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* regex `.whereRgx(...)` (applied client-side)
|
|
11
|
-
* raw fragments `.whereRaw(...)` / `.whereExpr(...)`
|
|
12
|
-
* `IN` helper `.whereIn(...)`
|
|
13
|
-
* operator helper `.whereOp(...)`
|
|
14
|
-
* ordering, limit, offset, and result helpers: `all()`, `get()`, `first()`, `count()`
|
|
10
|
+
## Install
|
|
11
|
+
> Requires **Bun** runtime
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
```bash
|
|
14
|
+
bun add @dockstat/sqlite-wrapper
|
|
15
|
+
````
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
* safe updates `.update(...)` (requires WHERE conditions)
|
|
22
|
-
|
|
23
|
-
**DELETE operations:**
|
|
24
|
-
* safe deletes `.delete()` (requires WHERE conditions)
|
|
25
|
-
|
|
26
|
-
> **Important** — Bun's `bun:sqlite` currently doesn't provide a JS `registerFunction` to add custom SQL functions. Regex conditions added with `whereRgx()` are collected and applied **in JavaScript** after fetching rows that match the non-regex SQL conditions. See the **Performance** section below for implications.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Quick start
|
|
17
|
+
## 10-second quickstart
|
|
31
18
|
|
|
32
19
|
```ts
|
|
33
|
-
import DB,
|
|
20
|
+
import { DB, column } from "@dockstat/sqlite-wrapper";
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
id: number;
|
|
37
|
-
name: string;
|
|
38
|
-
email: string;
|
|
39
|
-
type: string;
|
|
40
|
-
created_at: number;
|
|
41
|
-
}
|
|
22
|
+
const db = new DB("app.db", { pragmas: [["journal_mode","WAL"], ["foreign_keys","ON"]] });
|
|
42
23
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
["foreign_keys", "ON"]
|
|
49
|
-
],
|
|
50
|
-
loadExtensions: [
|
|
51
|
-
"/absolute/path/to/my_extension" // optional compiled SQLite extension
|
|
52
|
-
]
|
|
24
|
+
db.createTable("users", {
|
|
25
|
+
id: column.id(),
|
|
26
|
+
name: column.text({ notNull: true }),
|
|
27
|
+
email: column.text({ unique: true, notNull: true }),
|
|
28
|
+
created_at: column.createdAt()
|
|
53
29
|
});
|
|
54
30
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
id: "INTEGER PRIMARY KEY AUTOINCREMENT",
|
|
60
|
-
name: "TEXT NOT NULL",
|
|
61
|
-
email: "TEXT UNIQUE NOT NULL",
|
|
62
|
-
type: "TEXT NOT NULL",
|
|
63
|
-
created_at: "INTEGER NOT NULL DEFAULT (strftime('%s','now'))"
|
|
64
|
-
},
|
|
65
|
-
{ ifNotExists: true }
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
// SELECT - basic select (SQL filter only)
|
|
69
|
-
const containers = db
|
|
70
|
-
.table<User>("users")
|
|
71
|
-
.select(["id", "name", "email"])
|
|
72
|
-
.where({ type: "container" }) // SQL: type = 'container'
|
|
73
|
-
.orderBy("id")
|
|
74
|
-
.desc()
|
|
31
|
+
const users = db.table("users")
|
|
32
|
+
.select(["id","name","email"])
|
|
33
|
+
.where({ active: true })
|
|
34
|
+
.orderBy("created_at").desc()
|
|
75
35
|
.limit(10)
|
|
76
36
|
.all();
|
|
77
|
-
|
|
78
|
-
console.log(containers);
|
|
79
|
-
|
|
80
|
-
// SELECT - regex + SQL filters together
|
|
81
|
-
const gmailUsers = db
|
|
82
|
-
.table<User>("users")
|
|
83
|
-
.select(["id", "email"])
|
|
84
|
-
.where({ type: "container" }) // SQL
|
|
85
|
-
.whereRgx({ email: /@gmail\.com$/i }) // client-side regex
|
|
86
|
-
.all();
|
|
87
|
-
|
|
88
|
-
console.log(gmailUsers);
|
|
89
|
-
|
|
90
|
-
// INSERT - single row
|
|
91
|
-
const insertResult = db
|
|
92
|
-
.table<User>("users")
|
|
93
|
-
.insert({
|
|
94
|
-
name: "John Doe",
|
|
95
|
-
email: "john@example.com",
|
|
96
|
-
type: "container"
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
console.log(`Inserted user with ID: ${insertResult.insertId}`);
|
|
100
|
-
|
|
101
|
-
// INSERT - multiple rows with conflict resolution
|
|
102
|
-
const bulkResult = db
|
|
103
|
-
.table<User>("users")
|
|
104
|
-
.insertOrIgnore([
|
|
105
|
-
{ name: "Alice", email: "alice@example.com", type: "container" },
|
|
106
|
-
{ name: "Bob", email: "bob@example.com", type: "container" }
|
|
107
|
-
]);
|
|
108
|
-
|
|
109
|
-
console.log(`Inserted ${bulkResult.changes} users`);
|
|
110
|
-
|
|
111
|
-
// UPDATE - with WHERE conditions
|
|
112
|
-
const updateResult = db
|
|
113
|
-
.table<User>("users")
|
|
114
|
-
.where({ type: "container" })
|
|
115
|
-
.whereRgx({ email: /@gmail\.com$/i })
|
|
116
|
-
.update({ type: "gmail_user" });
|
|
117
|
-
|
|
118
|
-
console.log(`Updated ${updateResult.changes} users`);
|
|
119
|
-
|
|
120
|
-
// DELETE - with WHERE conditions
|
|
121
|
-
const deleteResult = db
|
|
122
|
-
.table<User>("users")
|
|
123
|
-
.where({ type: "gmail_user" })
|
|
124
|
-
.delete();
|
|
125
|
-
|
|
126
|
-
console.log(`Deleted ${deleteResult.changes} users`);
|
|
127
|
-
|
|
128
|
-
db.close();
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## 1) Creating tables
|
|
134
|
-
|
|
135
|
-
**Object style (recommended):**
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
db.createTable("posts", {
|
|
139
|
-
id: "INTEGER PRIMARY KEY AUTOINCREMENT",
|
|
140
|
-
title: "TEXT NOT NULL",
|
|
141
|
-
body: "TEXT",
|
|
142
|
-
author_id: "INTEGER NOT NULL",
|
|
143
|
-
published: "INTEGER NOT NULL DEFAULT 0"
|
|
144
|
-
}, { ifNotExists: true });
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
**String style:**
|
|
148
|
-
|
|
149
|
-
```ts
|
|
150
|
-
db.createTable(
|
|
151
|
-
"events",
|
|
152
|
-
`id INTEGER PRIMARY KEY,
|
|
153
|
-
name TEXT NOT NULL,
|
|
154
|
-
occurred_at INTEGER NOT NULL`
|
|
155
|
-
);
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## 2) Running PRAGMA statements
|
|
161
|
-
|
|
162
|
-
You can pass PRAGMAs at construction:
|
|
163
|
-
|
|
164
|
-
```ts
|
|
165
|
-
const db = new DB("app.db", {
|
|
166
|
-
pragmas: [
|
|
167
|
-
["journal_mode", "WAL"],
|
|
168
|
-
["cache_size", -64000]
|
|
169
|
-
]
|
|
170
|
-
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Or run them later:
|
|
174
|
-
|
|
175
|
-
```ts
|
|
176
|
-
db.pragma("cache_size", -32000);
|
|
177
|
-
const foreignKeysOn = db.pragma("foreign_keys");
|
|
178
|
-
console.log(foreignKeysOn); // should print ON
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## 3) Loading SQLite extensions
|
|
184
|
-
|
|
185
|
-
At DB construction:
|
|
186
|
-
|
|
187
|
-
```ts
|
|
188
|
-
const db = new DB("app.db", {
|
|
189
|
-
loadExtensions: [
|
|
190
|
-
"/absolute/path/to/regexp_extension"
|
|
191
|
-
]
|
|
192
|
-
});
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
Or after creation:
|
|
196
|
-
|
|
197
|
-
```ts
|
|
198
|
-
db.loadExtension("/absolute/path/to/my_extension");
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
## 4) Basic QueryBuilder usage
|
|
204
|
-
|
|
205
|
-
**Select specific columns:**
|
|
206
|
-
|
|
207
|
-
```ts
|
|
208
|
-
const users = db
|
|
209
|
-
.table<User>("users")
|
|
210
|
-
.select(["id", "name"])
|
|
211
|
-
.where({ type: "container" })
|
|
212
|
-
.all();
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
**Select all columns:**
|
|
216
|
-
|
|
217
|
-
```ts
|
|
218
|
-
const allUsers = db.table<User>("users").select(["*"]).all();
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
**Get a single row:**
|
|
222
|
-
|
|
223
|
-
```ts
|
|
224
|
-
const userOrNull = db.table<User>("users").where({ id: 1 }).get();
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
**Get first matching row:**
|
|
228
|
-
|
|
229
|
-
```ts
|
|
230
|
-
const first = db.table<User>("users").where({ type: "container" }).first();
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
**Count rows:**
|
|
234
|
-
|
|
235
|
-
```ts
|
|
236
|
-
const count = db.table<User>("users").where({ type: "container" }).count();
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
## 5) Mixing equality and regex
|
|
242
|
-
|
|
243
|
-
Plain equality uses `.where()` (SQL). Regex uses `.whereRgx()` (client-side):
|
|
244
|
-
|
|
245
|
-
```ts
|
|
246
|
-
const matches = db
|
|
247
|
-
.table<User>("users")
|
|
248
|
-
.select(["id", "name", "email", "type"])
|
|
249
|
-
.where({ type: "container" }) // SQL
|
|
250
|
-
.whereRgx({ email: /@example\.com$/i }) // JS regex after SQL fetch
|
|
251
|
-
.orderBy("created_at")
|
|
252
|
-
.desc()
|
|
253
|
-
.limit(50)
|
|
254
|
-
.all();
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
> **Note:** If `.whereRgx()` is used, ordering, offset, and limit are applied in JS after regex filtering.
|
|
258
|
-
|
|
259
|
-
---
|
|
260
|
-
|
|
261
|
-
## 6) Raw expressions, IN, and operators
|
|
262
|
-
|
|
263
|
-
**Raw WHERE fragment:**
|
|
264
|
-
|
|
265
|
-
```ts
|
|
266
|
-
const rows = db
|
|
267
|
-
.table<User>("users")
|
|
268
|
-
.whereRaw("created_at > ? AND published = ?", [1625097600, 1])
|
|
269
|
-
.all();
|
|
270
37
|
```
|
|
271
38
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
```ts
|
|
275
|
-
const some = db.table<User>("users").whereIn("id", [1, 2, 5, 7]).all();
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
**Operator helper:**
|
|
279
|
-
|
|
280
|
-
```ts
|
|
281
|
-
db.table<User>("users")
|
|
282
|
-
.whereOp("created_at", ">", 1622505600)
|
|
283
|
-
.whereOp("email", "LIKE", "%@gmail.com")
|
|
284
|
-
.all();
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
---
|
|
288
|
-
|
|
289
|
-
## 7) Pagination
|
|
290
|
-
|
|
291
|
-
```ts
|
|
292
|
-
const page = 2;
|
|
293
|
-
const pageSize = 20;
|
|
294
|
-
|
|
295
|
-
const paged = db
|
|
296
|
-
.table<User>("users")
|
|
297
|
-
.where({ type: "container" })
|
|
298
|
-
.orderBy("created_at")
|
|
299
|
-
.desc()
|
|
300
|
-
.offset((page - 1) * pageSize)
|
|
301
|
-
.limit(pageSize)
|
|
302
|
-
.all();
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
> With `.whereRgx()`, paging happens in JS after filtering.
|
|
306
|
-
|
|
307
|
-
---
|
|
308
|
-
|
|
309
|
-
## 8) INSERT operations
|
|
310
|
-
|
|
311
|
-
**Single row insert:**
|
|
312
|
-
|
|
313
|
-
```ts
|
|
314
|
-
const result = db
|
|
315
|
-
.table<User>("users")
|
|
316
|
-
.insert({
|
|
317
|
-
name: "John Doe",
|
|
318
|
-
email: "john@example.com",
|
|
319
|
-
type: "container"
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
console.log(result.insertId, result.changes);
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
**Bulk insert:**
|
|
326
|
-
|
|
327
|
-
```ts
|
|
328
|
-
const users = [
|
|
329
|
-
{ name: "Alice", email: "alice@example.com", type: "container" },
|
|
330
|
-
{ name: "Bob", email: "bob@example.com", type: "container" }
|
|
331
|
-
];
|
|
332
|
-
|
|
333
|
-
const result = db.table<User>("users").insert(users);
|
|
334
|
-
console.log(`Inserted ${result.changes} users`);
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
**Insert with conflict resolution:**
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
// INSERT OR IGNORE - skip duplicates
|
|
341
|
-
const result1 = db.table<User>("users").insertOrIgnore({
|
|
342
|
-
name: "Duplicate User",
|
|
343
|
-
email: "existing@example.com"
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
// INSERT OR REPLACE - replace duplicates
|
|
347
|
-
const result2 = db.table<User>("users").insertOrReplace({
|
|
348
|
-
name: "Updated User",
|
|
349
|
-
email: "existing@example.com"
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
// Custom conflict resolution
|
|
353
|
-
const result3 = db.table<User>("users").insert(userData, {
|
|
354
|
-
orIgnore: true,
|
|
355
|
-
// or: orReplace, orAbort, orFail, orRollback
|
|
356
|
-
});
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
---
|
|
360
|
-
|
|
361
|
-
## 9) UPDATE operations
|
|
362
|
-
|
|
363
|
-
**Basic update (requires WHERE conditions):**
|
|
364
|
-
|
|
365
|
-
```ts
|
|
366
|
-
const result = db
|
|
367
|
-
.table<User>("users")
|
|
368
|
-
.where({ id: 1 })
|
|
369
|
-
.update({ name: "Updated Name", type: "admin" });
|
|
370
|
-
|
|
371
|
-
console.log(`Updated ${result.changes} rows`);
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
**Update with complex conditions:**
|
|
375
|
-
|
|
376
|
-
```ts
|
|
377
|
-
const result = db
|
|
378
|
-
.table<User>("users")
|
|
379
|
-
.where({ type: "container" })
|
|
380
|
-
.whereRgx({ email: /@gmail\.com$/i })
|
|
381
|
-
.update({ type: "gmail_container" });
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
**Update with raw WHERE conditions:**
|
|
385
|
-
|
|
386
|
-
```ts
|
|
387
|
-
const result = db
|
|
388
|
-
.table<User>("users")
|
|
389
|
-
.whereRaw("created_at > ? AND active = ?", [Date.now() - 86400000, true])
|
|
390
|
-
.update({ last_active: Date.now() });
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
> **Safety Note:** UPDATE operations require at least one WHERE condition to prevent accidental full table updates.
|
|
394
|
-
|
|
395
|
-
---
|
|
396
|
-
|
|
397
|
-
## 10) DELETE operations
|
|
398
|
-
|
|
399
|
-
**Basic delete (requires WHERE conditions):**
|
|
400
|
-
|
|
401
|
-
```ts
|
|
402
|
-
const result = db
|
|
403
|
-
.table<User>("users")
|
|
404
|
-
.where({ active: false })
|
|
405
|
-
.delete();
|
|
406
|
-
|
|
407
|
-
console.log(`Deleted ${result.changes} rows`);
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
**Delete with complex conditions:**
|
|
411
|
-
|
|
412
|
-
```ts
|
|
413
|
-
const result = db
|
|
414
|
-
.table<User>("users")
|
|
415
|
-
.where({ type: "temporary" })
|
|
416
|
-
.whereOp("created_at", "<", Date.now() - 604800000) // older than 1 week
|
|
417
|
-
.delete();
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
**Delete with regex conditions:**
|
|
421
|
-
|
|
422
|
-
```ts
|
|
423
|
-
const result = db
|
|
424
|
-
.table<User>("users")
|
|
425
|
-
.whereRgx({ email: /^test.*@example\.com$/i })
|
|
426
|
-
.delete();
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
> **Safety Note:** DELETE operations require at least one WHERE condition to prevent accidental full table deletion.
|
|
430
|
-
|
|
431
|
-
---
|
|
432
|
-
|
|
433
|
-
## 11) Complex query example
|
|
434
|
-
|
|
435
|
-
```ts
|
|
436
|
-
const results = db
|
|
437
|
-
.table<User>("users")
|
|
438
|
-
.select(["id", "name", "email", "created_at"])
|
|
439
|
-
.whereRaw("created_at > ?", [1672531200])
|
|
440
|
-
.whereIn("id", [10, 20, 30, 40])
|
|
441
|
-
.whereRgx({ email: /\b(hey@example|test@example)\.com$/i })
|
|
442
|
-
.orderBy("created_at")
|
|
443
|
-
.desc()
|
|
444
|
-
.limit(100)
|
|
445
|
-
.all();
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
---
|
|
449
|
-
|
|
450
|
-
## 12) Result types and error handling
|
|
451
|
-
|
|
452
|
-
**INSERT results:**
|
|
453
|
-
|
|
454
|
-
```ts
|
|
455
|
-
interface InsertResult {
|
|
456
|
-
insertId: number; // rowid of the last inserted row
|
|
457
|
-
changes: number; // number of rows inserted
|
|
458
|
-
}
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
**UPDATE/DELETE results:**
|
|
462
|
-
|
|
463
|
-
```ts
|
|
464
|
-
interface UpdateResult {
|
|
465
|
-
changes: number; // number of rows affected
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
interface DeleteResult {
|
|
469
|
-
changes: number; // number of rows deleted
|
|
470
|
-
}
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
**Error handling:**
|
|
474
|
-
|
|
475
|
-
```ts
|
|
476
|
-
try {
|
|
477
|
-
// This will throw - UPDATE without WHERE conditions
|
|
478
|
-
db.table<User>("users").update({ active: true });
|
|
479
|
-
} catch (error) {
|
|
480
|
-
console.error("UPDATE operation requires WHERE conditions");
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
try {
|
|
484
|
-
// This will throw - empty insert data
|
|
485
|
-
db.table<User>("users").insert({});
|
|
486
|
-
} catch (error) {
|
|
487
|
-
console.error("Insert data cannot be empty");
|
|
488
|
-
}
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
---
|
|
492
|
-
|
|
493
|
-
## Advanced: Native `REGEXP` support
|
|
494
|
-
|
|
495
|
-
If you load a compiled SQLite extension that adds `REGEXP`, you can do regex filtering directly in SQL:
|
|
496
|
-
|
|
497
|
-
```ts
|
|
498
|
-
db.loadExtension("/path/to/regexp_extension");
|
|
499
|
-
const rows = db
|
|
500
|
-
.table<User>("users")
|
|
501
|
-
.whereExpr("email REGEXP ?", ["@example\\.com$"])
|
|
502
|
-
.all();
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
---
|
|
506
|
-
|
|
507
|
-
## Performance & Practical tips
|
|
508
|
-
|
|
509
|
-
### SELECT performance:
|
|
510
|
-
* Prefer `.where()` SQL filters for large datasets — `.whereRgx()` fetches rows and filters in JS.
|
|
511
|
-
* Use `.whereIn()` and `.whereRaw()` to reduce rows before regex filtering.
|
|
512
|
-
* Use indexes on frequently queried columns.
|
|
513
|
-
|
|
514
|
-
### INSERT performance:
|
|
515
|
-
* Use bulk inserts with arrays for multiple rows instead of individual insert calls.
|
|
516
|
-
* Consider transaction wrapping for large batch operations.
|
|
517
|
-
* Use appropriate conflict resolution (`OR IGNORE`, `OR REPLACE`) to avoid exception handling.
|
|
518
|
-
|
|
519
|
-
### UPDATE/DELETE with regex:
|
|
520
|
-
* When using `.whereRgx()`, the operation fetches candidate rows first, then applies regex filtering client-side.
|
|
521
|
-
* For better performance with regex conditions, consider using SQL `LIKE` patterns where possible.
|
|
522
|
-
|
|
523
|
-
### General tips:
|
|
524
|
-
* Use PRAGMAs to tune performance (e.g. WAL mode, cache size).
|
|
525
|
-
* Load extensions to enable advanced SQLite features without manual filtering.
|
|
526
|
-
* Always use WHERE conditions for UPDATE/DELETE to prevent accidents.
|
|
527
|
-
* The library automatically handles parameter binding to prevent SQL injection.
|
|
528
|
-
|
|
529
|
-
---
|
|
530
|
-
|
|
531
|
-
## API Reference
|
|
532
|
-
|
|
533
|
-
### `DB` (default export)
|
|
534
|
-
|
|
535
|
-
* `constructor(path: string, opts?: { pragmas?: [string, any][], loadExtensions?: string[] })`
|
|
536
|
-
* `table<T>(tableName: string): QueryBuilder<T>`
|
|
537
|
-
* `createTable(tableName: string, columns: string | Record<string,string>, options?: { ifNotExists?: boolean; withoutRowId?: boolean })`
|
|
538
|
-
* `pragma(name: string, value?: any): any`
|
|
539
|
-
* `loadExtension(path: string): void`
|
|
540
|
-
* `close(): void`
|
|
541
|
-
|
|
542
|
-
### `QueryBuilder<T>` (named export)
|
|
543
|
-
|
|
544
|
-
**WHERE methods (shared across operations):**
|
|
545
|
-
* `where(cond: Partial<Record<keyof T, string | number | boolean | null>>)`
|
|
546
|
-
* `whereRgx(cond: Partial<Record<keyof T, string | RegExp>>)`
|
|
547
|
-
* `whereExpr(expr: string, params?: any[])`
|
|
548
|
-
* `whereRaw(expr: string, params?: any[])`
|
|
549
|
-
* `whereIn(column: keyof T, values: any[])`
|
|
550
|
-
* `whereOp(column: keyof T, op: string, value: any)`
|
|
551
|
-
|
|
552
|
-
**SELECT methods:**
|
|
553
|
-
* `select(columns: Array<keyof T> | ["*"])`
|
|
554
|
-
* `orderBy(column: keyof T)`
|
|
555
|
-
* `asc()`, `desc()`
|
|
556
|
-
* `limit(n)`, `offset(n)`
|
|
557
|
-
* `all(): T[]`, `get(): T | null`, `first(): T | null`, `count(): number`
|
|
39
|
+
## Why use it?
|
|
558
40
|
|
|
559
|
-
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
41
|
+
* ⚡ Bun-native, high-performance bindings
|
|
42
|
+
* 🔒 Type-safe table & query APIs (compile-time checks)
|
|
43
|
+
* 🧭 Full SQLite feature support: JSON, generated columns, foreign keys, indexes
|
|
44
|
+
* 🛡️ Safety-first defaults — prevents accidental full-table updates/deletes
|
|
45
|
+
* 🚀 Designed for production workflows: WAL, pragmatic PRAGMAs, bulk ops, transactions
|
|
563
46
|
|
|
564
|
-
|
|
565
|
-
* `update(data: Partial<T>): UpdateResult` *(requires WHERE conditions)*
|
|
47
|
+
## Docs & examples
|
|
566
48
|
|
|
567
|
-
|
|
568
|
-
* `delete(): DeleteResult` *(requires WHERE conditions)*
|
|
49
|
+
See full technical docs in `docs/technical.md` and `examples/` for e-commerce, migrations, and transactions.
|
|
569
50
|
|
|
570
|
-
|
|
51
|
+
## License
|
|
571
52
|
|
|
572
|
-
|
|
573
|
-
* `UpdateResult` — `{ changes: number }`
|
|
574
|
-
* `DeleteResult` — `{ changes: number }`
|
|
575
|
-
* `InsertOptions` — conflict resolution options
|
|
576
|
-
* `ColumnNames<T>` — column selection type
|
|
577
|
-
* `WhereCondition<T>` — WHERE condition type
|
|
578
|
-
* `RegexCondition<T>` — regex condition type
|
|
53
|
+
MIT — maintained by Dockstat. Contributions welcome.
|