@dockstat/sqlite-wrapper 1.2.8 → 1.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/LICENSE +373 -373
- package/README.md +553 -99
- package/index.ts +1120 -858
- package/package.json +60 -54
- package/query-builder/base.ts +183 -221
- package/query-builder/delete.ts +441 -352
- package/query-builder/index.ts +409 -431
- package/query-builder/insert.ts +280 -249
- package/query-builder/select.ts +333 -358
- package/query-builder/update.ts +308 -278
- package/query-builder/where.ts +272 -307
- package/types.ts +608 -623
- package/utils/index.ts +44 -0
- package/utils/logger.ts +184 -0
- package/utils/sql.ts +241 -0
- package/utils/transformer.ts +256 -0
package/README.md
CHANGED
|
@@ -1,99 +1,553 @@
|
|
|
1
|
-
# @dockstat/sqlite-wrapper
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-

|
|
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 +
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
1
|
+
# @dockstat/sqlite-wrapper
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
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 + Boolean auto-detection, automatic backups with retention, and production-minded pragmas & transactions.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 🆕 What's New in v1.3
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
- **Fixed Boolean parsing** — Boolean columns now correctly convert SQLite's `0`/`1` to JavaScript `true`/`false`
|
|
16
|
+
|
|
17
|
+
### New Features
|
|
18
|
+
- **Auto-detection of JSON & Boolean columns** — No more manual parser configuration! Columns using `column.json()` or `column.boolean()` are automatically detected from schema
|
|
19
|
+
- **Automatic backups with retention** — Configure `autoBackup` to create periodic backups with automatic cleanup of old files
|
|
20
|
+
- **Backup & Restore API** — New `backup()`, `restore()`, and `listBackups()` methods
|
|
21
|
+
- **`getPath()` method** — Get the database file path
|
|
22
|
+
|
|
23
|
+
### Architecture Improvements
|
|
24
|
+
- **New `utils/` module** — Reusable utilities for SQL building, logging, and row transformation
|
|
25
|
+
- **Structured logging** — Cleaner, more consistent log output with dedicated loggers per component
|
|
26
|
+
- **Reduced code duplication** — Extracted common patterns into shared utilities
|
|
27
|
+
- **Better maintainability** — Clearer separation of concerns across modules
|
|
28
|
+
|
|
29
|
+
### Breaking Changes
|
|
30
|
+
- None! v1.3 is fully backward compatible with v1.2.x
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
> Requires **Bun** runtime
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bun add @dockstat/sqlite-wrapper
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 10-second quickstart
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { DB, column } from "@dockstat/sqlite-wrapper";
|
|
46
|
+
|
|
47
|
+
type User = {
|
|
48
|
+
id?: number;
|
|
49
|
+
name: string;
|
|
50
|
+
active: boolean;
|
|
51
|
+
email: string;
|
|
52
|
+
metadata: object;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const db = new DB("app.db", {
|
|
56
|
+
pragmas: [
|
|
57
|
+
["journal_mode", "WAL"],
|
|
58
|
+
["foreign_keys", "ON"],
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const userTable = db.createTable<User>("users", {
|
|
63
|
+
id: column.id(),
|
|
64
|
+
name: column.text({ notNull: true }),
|
|
65
|
+
active: column.boolean(), // Auto-detected as BOOLEAN ✨
|
|
66
|
+
email: column.text({ unique: true, notNull: true }),
|
|
67
|
+
metadata: column.json(), // Auto-detected as JSON ✨
|
|
68
|
+
created_at: column.createdAt(),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Insert with automatic JSON serialization & boolean handling
|
|
72
|
+
userTable.insert({
|
|
73
|
+
name: "Alice",
|
|
74
|
+
active: true,
|
|
75
|
+
email: "alice@example.com",
|
|
76
|
+
metadata: { role: "admin", preferences: { theme: "dark" } },
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Query with automatic JSON parsing & boolean conversion
|
|
80
|
+
const users = userTable
|
|
81
|
+
.select(["id", "name", "email", "metadata"])
|
|
82
|
+
.where({ active: true })
|
|
83
|
+
.orderBy("created_at")
|
|
84
|
+
.desc()
|
|
85
|
+
.limit(10)
|
|
86
|
+
.all();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Why use it?
|
|
90
|
+
|
|
91
|
+
- ⚡ Bun-native, high-performance bindings
|
|
92
|
+
- 🔒 Type-safe table & query APIs (compile-time checks)
|
|
93
|
+
- 🧭 Full SQLite feature support: JSON, generated columns, foreign keys, indexes
|
|
94
|
+
- 🛡️ Safety-first defaults — prevents accidental full-table updates/deletes
|
|
95
|
+
- 🚀 Designed for production workflows: WAL, pragmatic PRAGMAs, bulk ops, transactions
|
|
96
|
+
- 🔄 **Automatic JSON/Boolean detection** — no manual parser configuration needed
|
|
97
|
+
- 💾 **Built-in backup & restore** — with automatic retention policies
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Core Features
|
|
102
|
+
|
|
103
|
+
### Type Safety
|
|
104
|
+
|
|
105
|
+
- **Compile-time validation** of column names and data shapes
|
|
106
|
+
- **IntelliSense support** for all operations
|
|
107
|
+
- **Generic interfaces** that adapt to your data models
|
|
108
|
+
- **Type-safe column definitions** with comprehensive constraint support
|
|
109
|
+
|
|
110
|
+
### Safety-First Design
|
|
111
|
+
|
|
112
|
+
- **Mandatory WHERE conditions** for UPDATE and DELETE operations to prevent accidental data loss
|
|
113
|
+
- **Parameter binding** for all queries to prevent SQL injection
|
|
114
|
+
- **Prepared statements** used internally for optimal performance
|
|
115
|
+
- **Transaction support** with automatic rollback on errors
|
|
116
|
+
|
|
117
|
+
### Production Ready
|
|
118
|
+
|
|
119
|
+
- **WAL mode** support for concurrent read/write operations
|
|
120
|
+
- **Comprehensive PRAGMA management** for performance tuning
|
|
121
|
+
- **Connection pooling** considerations built-in
|
|
122
|
+
- **Bulk operation** support with transaction batching
|
|
123
|
+
- **Schema introspection** tools for migrations and debugging
|
|
124
|
+
- **Automatic backups** with configurable retention policies
|
|
125
|
+
|
|
126
|
+
### Complete SQLite Support
|
|
127
|
+
|
|
128
|
+
- **All SQLite data types** with proper TypeScript mappings
|
|
129
|
+
- **Generated columns** (both VIRTUAL and STORED)
|
|
130
|
+
- **Foreign key constraints** with cascade options
|
|
131
|
+
- **JSON columns** with automatic serialization/deserialization
|
|
132
|
+
- **Boolean columns** with automatic conversion (SQLite stores as 0/1)
|
|
133
|
+
- **Full-text search** preparation
|
|
134
|
+
- **Custom functions** and extensions support
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Automatic Type Detection
|
|
139
|
+
|
|
140
|
+
When using `column.json()` or `column.boolean()`, the wrapper **automatically detects** these columns and handles serialization/deserialization for you. No manual parser configuration required!
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// JSON and Boolean columns are auto-detected from schema
|
|
144
|
+
const table = db.createTable<{
|
|
145
|
+
id: number;
|
|
146
|
+
settings: object;
|
|
147
|
+
isActive: boolean;
|
|
148
|
+
}>("config", {
|
|
149
|
+
id: column.id(),
|
|
150
|
+
settings: column.json(), // Auto-detected ✨
|
|
151
|
+
isActive: column.boolean(), // Auto-detected ✨
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Insert - objects are automatically JSON.stringify'd, booleans work natively
|
|
155
|
+
table.insert({
|
|
156
|
+
settings: { theme: "dark", notifications: true },
|
|
157
|
+
isActive: true,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Select - JSON is automatically parsed, 0/1 converted to true/false
|
|
161
|
+
const row = table.select(["*"]).where({ id: 1 }).first();
|
|
162
|
+
console.log(row.settings.theme); // "dark" (not a string!)
|
|
163
|
+
console.log(row.isActive); // true (not 1!)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Manual Parser Override
|
|
167
|
+
|
|
168
|
+
You can still manually specify parsers if needed (e.g., for existing tables or edge cases):
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const table = db.createTable<MyType>(
|
|
172
|
+
"my_table",
|
|
173
|
+
{ ... },
|
|
174
|
+
{
|
|
175
|
+
parser: {
|
|
176
|
+
JSON: ["customJsonColumn"],
|
|
177
|
+
BOOLEAN: ["customBoolColumn"],
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Automatic Backups with Retention
|
|
186
|
+
|
|
187
|
+
Configure automatic backups with retention policies to protect your data:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
const db = new DB("app.db", {
|
|
191
|
+
pragmas: [["journal_mode", "WAL"]],
|
|
192
|
+
autoBackup: {
|
|
193
|
+
enabled: true,
|
|
194
|
+
directory: "./backups",
|
|
195
|
+
intervalMs: 60 * 60 * 1000, // Backup every hour
|
|
196
|
+
maxBackups: 10, // Keep only the 10 most recent backups
|
|
197
|
+
filenamePrefix: "app_backup", // Optional custom prefix
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Backups are created automatically:
|
|
202
|
+
// - On database open (initial backup)
|
|
203
|
+
// - At the specified interval
|
|
204
|
+
// - Old backups are automatically removed based on maxBackups
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Auto-Backup Options
|
|
208
|
+
|
|
209
|
+
| Option | Type | Default | Description |
|
|
210
|
+
| ---------------- | ------- | ---------- | -------------------------------------- |
|
|
211
|
+
| `enabled` | boolean | - | Enable/disable automatic backups |
|
|
212
|
+
| `directory` | string | - | Directory to store backup files |
|
|
213
|
+
| `intervalMs` | number | `3600000` | Backup interval in milliseconds (1 hr) |
|
|
214
|
+
| `maxBackups` | number | `10` | Maximum number of backups to retain |
|
|
215
|
+
| `filenamePrefix` | string | `"backup"` | Prefix for backup filenames |
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Manual Backup & Restore
|
|
220
|
+
|
|
221
|
+
### Creating Backups
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// Backup to auto-generated path (if auto-backup configured)
|
|
225
|
+
const backupPath = db.backup();
|
|
226
|
+
|
|
227
|
+
// Backup to custom path
|
|
228
|
+
const customPath = db.backup("./my-backup.db");
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Listing Backups
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
const backups = db.listBackups();
|
|
235
|
+
// Returns: Array<{ filename, path, size, created }>
|
|
236
|
+
|
|
237
|
+
console.log(backups[0]);
|
|
238
|
+
// {
|
|
239
|
+
// filename: "backup_2024-01-15T10-30-00-000Z.db",
|
|
240
|
+
// path: "/app/backups/backup_2024-01-15T10-30-00-000Z.db",
|
|
241
|
+
// size: 1048576,
|
|
242
|
+
// created: Date object
|
|
243
|
+
// }
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Restoring from Backup
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// Restore to the original database (closes and reopens connection)
|
|
250
|
+
db.restore("./backups/backup_2024-01-15.db");
|
|
251
|
+
|
|
252
|
+
// Restore to a different path
|
|
253
|
+
db.restore("./backups/backup_2024-01-15.db", "./restored.db");
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Stopping Auto-Backup
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
// Stop the automatic backup timer
|
|
260
|
+
db.stopAutoBackup();
|
|
261
|
+
|
|
262
|
+
// Note: close() automatically stops auto-backup
|
|
263
|
+
db.close();
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Query Builder Examples
|
|
269
|
+
|
|
270
|
+
### SELECT Operations
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// Select all columns
|
|
274
|
+
const allUsers = userTable.select(["*"]).all();
|
|
275
|
+
|
|
276
|
+
// Select specific columns with conditions
|
|
277
|
+
const activeAdmins = userTable
|
|
278
|
+
.select(["id", "name", "email"])
|
|
279
|
+
.where({ active: true, role: "admin" })
|
|
280
|
+
.orderBy("created_at")
|
|
281
|
+
.desc()
|
|
282
|
+
.limit(10)
|
|
283
|
+
.all();
|
|
284
|
+
|
|
285
|
+
// Get first match
|
|
286
|
+
const user = userTable.select(["*"]).where({ email: "alice@example.com" }).first();
|
|
287
|
+
|
|
288
|
+
// Count records
|
|
289
|
+
const count = userTable.where({ active: true }).count();
|
|
290
|
+
|
|
291
|
+
// Check existence
|
|
292
|
+
const exists = userTable.where({ email: "test@example.com" }).exists();
|
|
293
|
+
|
|
294
|
+
// Get single column value
|
|
295
|
+
const name = userTable.where({ id: 1 }).value("name");
|
|
296
|
+
|
|
297
|
+
// Pluck column values
|
|
298
|
+
const allEmails = userTable.where({ active: true }).pluck("email");
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### INSERT Operations
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
// Single insert
|
|
305
|
+
const result = userTable.insert({
|
|
306
|
+
name: "Bob",
|
|
307
|
+
email: "bob@example.com",
|
|
308
|
+
active: true,
|
|
309
|
+
});
|
|
310
|
+
console.log(result.insertId); // New row ID
|
|
311
|
+
|
|
312
|
+
// Bulk insert
|
|
313
|
+
userTable.insertBatch([
|
|
314
|
+
{ name: "User 1", email: "user1@example.com" },
|
|
315
|
+
{ name: "User 2", email: "user2@example.com" },
|
|
316
|
+
]);
|
|
317
|
+
|
|
318
|
+
// Insert with conflict resolution
|
|
319
|
+
userTable.insertOrIgnore({ email: "existing@example.com", name: "Name" });
|
|
320
|
+
userTable.insertOrReplace({ email: "existing@example.com", name: "New Name" });
|
|
321
|
+
|
|
322
|
+
// Insert and get the row back
|
|
323
|
+
const newUser = userTable.insertAndGet({ name: "Charlie", email: "charlie@example.com" });
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### UPDATE Operations
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// Update with WHERE (required!)
|
|
330
|
+
userTable.where({ id: 1 }).update({ name: "Updated Name" });
|
|
331
|
+
|
|
332
|
+
// Increment/decrement numeric columns
|
|
333
|
+
userTable.where({ id: 1 }).increment("login_count");
|
|
334
|
+
userTable.where({ id: 1 }).decrement("credits", 10);
|
|
335
|
+
|
|
336
|
+
// Upsert (insert or replace)
|
|
337
|
+
userTable.upsert({ email: "alice@example.com", name: "Alice Updated" });
|
|
338
|
+
|
|
339
|
+
// Batch update
|
|
340
|
+
userTable.updateBatch([
|
|
341
|
+
{ where: { id: 1 }, data: { active: false } },
|
|
342
|
+
{ where: { id: 2 }, data: { active: true } },
|
|
343
|
+
]);
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### DELETE Operations
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
// Delete with WHERE (required!)
|
|
350
|
+
userTable.where({ id: 1 }).delete();
|
|
351
|
+
|
|
352
|
+
// Soft delete (sets a timestamp column)
|
|
353
|
+
userTable.where({ id: 1 }).softDelete("deleted_at");
|
|
354
|
+
|
|
355
|
+
// Restore soft deleted
|
|
356
|
+
userTable.where({ id: 1 }).restore("deleted_at");
|
|
357
|
+
|
|
358
|
+
// Truncate table (delete all rows)
|
|
359
|
+
userTable.truncate();
|
|
360
|
+
|
|
361
|
+
// Delete older than timestamp
|
|
362
|
+
userTable.deleteOlderThan("created_at", Date.now() - 86400000);
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### WHERE Conditions
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
// Simple equality
|
|
369
|
+
userTable.where({ active: true, role: "admin" });
|
|
370
|
+
|
|
371
|
+
// Comparison operators
|
|
372
|
+
userTable.whereOp("age", ">=", 18);
|
|
373
|
+
userTable.whereOp("created_at", "<", Date.now());
|
|
374
|
+
|
|
375
|
+
// IN / NOT IN
|
|
376
|
+
userTable.whereIn("status", ["active", "pending"]);
|
|
377
|
+
userTable.whereNotIn("role", ["banned", "suspended"]);
|
|
378
|
+
|
|
379
|
+
// BETWEEN
|
|
380
|
+
userTable.whereBetween("age", 18, 65);
|
|
381
|
+
userTable.whereNotBetween("score", 0, 50);
|
|
382
|
+
|
|
383
|
+
// NULL checks
|
|
384
|
+
userTable.whereNull("deleted_at");
|
|
385
|
+
userTable.whereNotNull("email");
|
|
386
|
+
|
|
387
|
+
// Raw expressions
|
|
388
|
+
userTable.whereRaw("LENGTH(name) > ?", [5]);
|
|
389
|
+
|
|
390
|
+
// Regex (client-side filtering)
|
|
391
|
+
userTable.whereRgx({ email: /@gmail\.com$/ });
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Utility Methods
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
// Get database file path
|
|
400
|
+
const path = db.getPath(); // "app.db" or ":memory:"
|
|
401
|
+
|
|
402
|
+
// Direct SQL execution
|
|
403
|
+
db.run("CREATE INDEX idx_email ON users(email)");
|
|
404
|
+
|
|
405
|
+
// Prepare statements
|
|
406
|
+
const stmt = db.prepare("SELECT * FROM users WHERE id = ?");
|
|
407
|
+
|
|
408
|
+
// Transactions
|
|
409
|
+
db.transaction(() => {
|
|
410
|
+
userTable.insert({ name: "User 1" });
|
|
411
|
+
userTable.insert({ name: "User 2" });
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Manual transaction control
|
|
415
|
+
db.begin();
|
|
416
|
+
try {
|
|
417
|
+
// ... operations
|
|
418
|
+
db.commit();
|
|
419
|
+
} catch (e) {
|
|
420
|
+
db.rollback();
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Savepoints
|
|
424
|
+
db.savepoint("my_savepoint");
|
|
425
|
+
db.releaseSavepoint("my_savepoint");
|
|
426
|
+
db.rollbackToSavepoint("my_savepoint");
|
|
427
|
+
|
|
428
|
+
// Database maintenance
|
|
429
|
+
db.vacuum();
|
|
430
|
+
db.analyze();
|
|
431
|
+
const integrity = db.integrityCheck();
|
|
432
|
+
|
|
433
|
+
// Schema inspection
|
|
434
|
+
const schema = db.getSchema();
|
|
435
|
+
const tableInfo = db.getTableInfo("users");
|
|
436
|
+
const indexes = db.getIndexes("users");
|
|
437
|
+
const foreignKeys = db.getForeignKeys("users");
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Column Helpers
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
import { column } from "@dockstat/sqlite-wrapper";
|
|
446
|
+
|
|
447
|
+
column.id(); // INTEGER PRIMARY KEY AUTOINCREMENT
|
|
448
|
+
column.text({ notNull: true, unique: true });
|
|
449
|
+
column.integer({ default: 0 });
|
|
450
|
+
column.real();
|
|
451
|
+
column.blob();
|
|
452
|
+
column.boolean({ default: false });
|
|
453
|
+
column.json({ validateJson: true });
|
|
454
|
+
column.date();
|
|
455
|
+
column.datetime();
|
|
456
|
+
column.timestamp();
|
|
457
|
+
column.varchar(255);
|
|
458
|
+
column.char(10);
|
|
459
|
+
column.numeric({ precision: 10, scale: 2 });
|
|
460
|
+
column.uuid({ generateDefault: true });
|
|
461
|
+
column.createdAt();
|
|
462
|
+
column.updatedAt();
|
|
463
|
+
column.foreignKey("other_table", "id", { onDelete: "CASCADE" });
|
|
464
|
+
column.enum(["pending", "active", "completed"]);
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Package Structure
|
|
470
|
+
|
|
471
|
+
The package is organized into modular components for maintainability:
|
|
472
|
+
|
|
473
|
+
```
|
|
474
|
+
@dockstat/sqlite-wrapper
|
|
475
|
+
├── index.ts # Main exports & DB class
|
|
476
|
+
├── types.ts # Type definitions & column helpers
|
|
477
|
+
├── query-builder/
|
|
478
|
+
│ ├── index.ts # QueryBuilder facade
|
|
479
|
+
│ ├── base.ts # Base class with shared functionality
|
|
480
|
+
│ ├── where.ts # WHERE clause building
|
|
481
|
+
│ ├── select.ts # SELECT operations
|
|
482
|
+
│ ├── insert.ts # INSERT operations
|
|
483
|
+
│ ├── update.ts # UPDATE operations
|
|
484
|
+
│ └── delete.ts # DELETE operations
|
|
485
|
+
└── utils/
|
|
486
|
+
├── index.ts # Utility exports
|
|
487
|
+
├── logger.ts # Structured logging (wraps @dockstat/logger)
|
|
488
|
+
├── sql.ts # SQL building utilities
|
|
489
|
+
└── transformer.ts # Row serialization/deserialization
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Using Utilities Directly
|
|
493
|
+
|
|
494
|
+
The `utils` module is exported for advanced use cases:
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
import {
|
|
498
|
+
quoteIdentifier,
|
|
499
|
+
buildPlaceholders,
|
|
500
|
+
transformFromDb,
|
|
501
|
+
createLogger,
|
|
502
|
+
} from "@dockstat/sqlite-wrapper/utils";
|
|
503
|
+
|
|
504
|
+
// Quote identifiers safely
|
|
505
|
+
const quoted = quoteIdentifier("user name"); // "user name"
|
|
506
|
+
|
|
507
|
+
// Build placeholders
|
|
508
|
+
const placeholders = buildPlaceholders(3); // "?, ?, ?"
|
|
509
|
+
|
|
510
|
+
// Create a custom logger
|
|
511
|
+
const myLogger = createLogger("my-component");
|
|
512
|
+
myLogger.info("Custom log message");
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## Logging
|
|
518
|
+
|
|
519
|
+
The package uses `@dockstat/logger` with structured, component-specific logging:
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
// Log output examples:
|
|
523
|
+
// 16:30:00 INFO [db:sqlite] — Database open: app.db
|
|
524
|
+
// 16:30:00 DEBUG [table:sqlite] — CREATE TABLE users | columns=[id, name, email]
|
|
525
|
+
// 16:30:00 DEBUG [select:sqlite] — SELECT | SELECT * FROM "users" WHERE "id" = ? | params=[1]
|
|
526
|
+
// 16:30:00 DEBUG [select:sqlite] — SELECT | rows=1
|
|
527
|
+
// 16:30:00 INFO [backup:sqlite] — Backup create: ./backups/backup_2024-01-15.db
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Configure Logging
|
|
531
|
+
|
|
532
|
+
Control log levels via environment variables:
|
|
533
|
+
|
|
534
|
+
```bash
|
|
535
|
+
# Set log level (error, warn, info, debug)
|
|
536
|
+
DOCKSTAT_LOGGER_LEVEL=info
|
|
537
|
+
|
|
538
|
+
# Disable specific loggers
|
|
539
|
+
DOCKSTAT_LOGGER_DISABLED_LOGGERS=select,insert
|
|
540
|
+
|
|
541
|
+
# Show only specific loggers
|
|
542
|
+
DOCKSTAT_LOGGER_ONLY_SHOW=db,backup
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Docs & Examples
|
|
548
|
+
|
|
549
|
+
See full technical docs [here](https://outline.itsnik.de/s/9d88c471-373e-4ef2-a955-b1058eb7dc99/doc/dockstatsqlite-wrapper-Lxt4IphXI5).
|
|
550
|
+
|
|
551
|
+
## License
|
|
552
|
+
|
|
553
|
+
MPL-2.0 — maintained by Dockstat. Contributions welcome.
|