@dockstat/sqlite-wrapper 1.2.5 → 1.2.7
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 +51 -5
- package/index.ts +4 -3
- package/package.json +1 -1
- package/query-builder/base.ts +18 -13
- package/query-builder/insert.ts +6 -0
- package/types.ts +4 -7
package/README.md
CHANGED
|
@@ -16,19 +16,32 @@ bun add @dockstat/sqlite-wrapper
|
|
|
16
16
|
|
|
17
17
|
## 10-second quickstart
|
|
18
18
|
|
|
19
|
-
```
|
|
19
|
+
```typescript
|
|
20
20
|
import { DB, column } from "@dockstat/sqlite-wrapper";
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
type User = {
|
|
23
|
+
id?: number,
|
|
24
|
+
name: string,
|
|
25
|
+
active: boolean,
|
|
26
|
+
email: string,
|
|
27
|
+
}
|
|
23
28
|
|
|
24
|
-
db
|
|
29
|
+
const db = new DB("app.db", {
|
|
30
|
+
pragmas: [
|
|
31
|
+
["journal_mode","WAL"],
|
|
32
|
+
["foreign_keys","ON"]
|
|
33
|
+
]
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const userTable = db.createTable<User>("users", {
|
|
25
37
|
id: column.id(),
|
|
26
38
|
name: column.text({ notNull: true }),
|
|
39
|
+
active: column.boolean(),
|
|
27
40
|
email: column.text({ unique: true, notNull: true }),
|
|
28
41
|
created_at: column.createdAt()
|
|
29
42
|
});
|
|
30
43
|
|
|
31
|
-
const users =
|
|
44
|
+
const users = userTable
|
|
32
45
|
.select(["id","name","email"])
|
|
33
46
|
.where({ active: true })
|
|
34
47
|
.orderBy("created_at").desc()
|
|
@@ -44,10 +57,43 @@ const users = db.table("users")
|
|
|
44
57
|
* 🛡️ Safety-first defaults — prevents accidental full-table updates/deletes
|
|
45
58
|
* 🚀 Designed for production workflows: WAL, pragmatic PRAGMAs, bulk ops, transactions
|
|
46
59
|
|
|
60
|
+
## Core Features
|
|
61
|
+
|
|
62
|
+
### Type Safety
|
|
63
|
+
|
|
64
|
+
* **Compile-time validation** of column names and data shapes
|
|
65
|
+
* **IntelliSense support** for all operations
|
|
66
|
+
* **Generic interfaces** that adapt to your data models
|
|
67
|
+
* **Type-safe column definitions** with comprehensive constraint support
|
|
68
|
+
|
|
69
|
+
### Safety-First Design
|
|
70
|
+
|
|
71
|
+
* **Mandatory WHERE conditions** for UPDATE and DELETE operations to prevent accidental data loss
|
|
72
|
+
* **Parameter binding** for all queries to prevent SQL injection
|
|
73
|
+
* **Prepared statements** used internally for optimal performance
|
|
74
|
+
* **Transaction support** with automatic rollback on errors
|
|
75
|
+
|
|
76
|
+
### Production Ready
|
|
77
|
+
|
|
78
|
+
* **WAL mode** support for concurrent read/write operations
|
|
79
|
+
* **Comprehensive PRAGMA management** for performance tuning
|
|
80
|
+
* **Connection pooling** considerations built-in
|
|
81
|
+
* **Bulk operation** support with transaction batching
|
|
82
|
+
* **Schema introspection** tools for migrations and debugging
|
|
83
|
+
|
|
84
|
+
### Complete SQLite Support
|
|
85
|
+
|
|
86
|
+
* **All SQLite data types** with proper TypeScript mappings
|
|
87
|
+
* **Generated columns** (both VIRTUAL and STORED)
|
|
88
|
+
* **Foreign key constraints** with cascade options
|
|
89
|
+
* **JSON columns** with validation and transformation
|
|
90
|
+
* **Full-text search** preparation
|
|
91
|
+
* **Custom functions** and extensions support
|
|
92
|
+
|
|
47
93
|
## Docs & examples
|
|
48
94
|
|
|
49
95
|
See full technical docs [here](https://outline.itsnik.de/s/9d88c471-373e-4ef2-a955-b1058eb7dc99/doc/dockstatsqlite-wrapper-Lxt4IphXI5).
|
|
50
96
|
|
|
51
97
|
## License
|
|
52
98
|
|
|
53
|
-
|
|
99
|
+
MPL-2.0 — maintained by Dockstat. Contributions welcome.
|
package/index.ts
CHANGED
|
@@ -102,7 +102,7 @@ class DB {
|
|
|
102
102
|
tableName: string,
|
|
103
103
|
jsonConfig?: JsonColumnConfig<T>
|
|
104
104
|
): QueryBuilder<T> {
|
|
105
|
-
logger.debug(`Creating QueryBuilder for table: ${tableName}`)
|
|
105
|
+
logger.debug(`Creating QueryBuilder for table: ${tableName} - JSONConfig: ${JSON.stringify(jsonConfig)}`)
|
|
106
106
|
return new QueryBuilder<T>(this.db, tableName, jsonConfig)
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -209,7 +209,8 @@ class DB {
|
|
|
209
209
|
*/
|
|
210
210
|
createTable<_T extends Record<string, unknown>>(
|
|
211
211
|
tableName: string,
|
|
212
|
-
columns: string | Record<string, string> | Partial<Record<Extract<keyof _T, string>, ColumnDefinition>> | TableSchema,
|
|
212
|
+
columns: string | Record<string, string> | Partial<Record<Extract<keyof _T, string>, ColumnDefinition>> | TableSchema,
|
|
213
|
+
options?: TableOptions<_T>,
|
|
213
214
|
): QueryBuilder<_T> {
|
|
214
215
|
const temp = options?.temporary ? 'TEMPORARY ' : ''
|
|
215
216
|
const ifNot = options?.ifNotExists ? 'IF NOT EXISTS ' : ''
|
|
@@ -276,7 +277,7 @@ class DB {
|
|
|
276
277
|
this.setTableComment(tableName, options.comment)
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
return this.table<_T>(tableName)
|
|
280
|
+
return this.table<_T>(tableName, options?.jsonConfig)
|
|
280
281
|
}
|
|
281
282
|
|
|
282
283
|
/**
|
package/package.json
CHANGED
package/query-builder/base.ts
CHANGED
|
@@ -34,24 +34,24 @@ export abstract class BaseQueryBuilder<T extends Record<string, unknown>> {
|
|
|
34
34
|
whereConditions: [],
|
|
35
35
|
whereParams: [],
|
|
36
36
|
regexConditions: [],
|
|
37
|
-
jsonColumns: jsonConfig
|
|
37
|
+
jsonColumns: jsonConfig,
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Reset query builder state
|
|
43
43
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
44
|
+
protected reset(): void {
|
|
45
|
+
this.state.whereConditions = []
|
|
46
|
+
this.state.whereParams = []
|
|
47
|
+
this.state.regexConditions = []
|
|
48
|
+
// Reset any ordering, limit, offset, selected columns if present
|
|
49
|
+
if ('orderColumn' in this) (this as any).orderColumn = undefined
|
|
50
|
+
if ('orderDirection' in this) (this as any).orderDirection = 'ASC'
|
|
51
|
+
if ('limitValue' in this) (this as any).limitValue = undefined
|
|
52
|
+
if ('offsetValue' in this) (this as any).offsetValue = undefined
|
|
53
|
+
if ('selectedColumns' in this) (this as any).selectedColumns = ['*']
|
|
54
|
+
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Get the database instance
|
|
@@ -197,11 +197,16 @@ export abstract class BaseQueryBuilder<T extends Record<string, unknown>> {
|
|
|
197
197
|
* Transform row data before inserting/updating to database (serialize JSON columns).
|
|
198
198
|
*/
|
|
199
199
|
protected transformRowToDb(row: Partial<T>): DatabaseRowData {
|
|
200
|
-
|
|
200
|
+
this.logger.debug(`Transforming row (${JSON.stringify(row)}) to row Data`)
|
|
201
|
+
if (!this.state.jsonColumns || !row) {
|
|
202
|
+
return row as DatabaseRowData
|
|
203
|
+
}
|
|
201
204
|
|
|
202
205
|
const transformed: DatabaseRowData = { ...row } as DatabaseRowData
|
|
206
|
+
|
|
203
207
|
for (const column of this.state.jsonColumns) {
|
|
204
208
|
const columnKey = String(column)
|
|
209
|
+
this.logger.debug(`Checking: ${columnKey}`)
|
|
205
210
|
if (
|
|
206
211
|
transformed[columnKey] !== undefined &&
|
|
207
212
|
transformed[columnKey] !== null
|
package/query-builder/insert.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { WhereQueryBuilder } from "./where";
|
|
|
9
9
|
export class InsertQueryBuilder<
|
|
10
10
|
T extends Record<string, unknown>,
|
|
11
11
|
> extends WhereQueryBuilder<T> {
|
|
12
|
+
|
|
12
13
|
/**
|
|
13
14
|
* Insert a single row or multiple rows into the table.
|
|
14
15
|
*
|
|
@@ -20,11 +21,16 @@ export class InsertQueryBuilder<
|
|
|
20
21
|
data: Partial<T> | Partial<T>[],
|
|
21
22
|
options?: InsertOptions,
|
|
22
23
|
): InsertResult {
|
|
24
|
+
this.getLogger().debug(`Building Data Array: ${data}`)
|
|
23
25
|
const rows = Array.isArray(data) ? data : [data];
|
|
24
26
|
|
|
27
|
+
|
|
28
|
+
|
|
25
29
|
// Transform rows to handle JSON serialization
|
|
26
30
|
const transformedRows = rows.map((row) => this.transformRowToDb(row));
|
|
27
31
|
|
|
32
|
+
this.getLogger().debug(`Transformed row: ${JSON.stringify(transformedRows)}`)
|
|
33
|
+
|
|
28
34
|
if (transformedRows.length === 0) {
|
|
29
35
|
throw new Error("insert: data cannot be empty");
|
|
30
36
|
}
|
package/types.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// Enhanced types.ts with comprehensive SQLite support
|
|
2
1
|
import type { Database, SQLQueryBindings } from "bun:sqlite";
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -262,8 +261,8 @@ export interface TableOptions<T> {
|
|
|
262
261
|
temporary?: boolean;
|
|
263
262
|
/** Table comment */
|
|
264
263
|
comment?: string;
|
|
265
|
-
|
|
266
|
-
jsonConfig?:
|
|
264
|
+
|
|
265
|
+
jsonConfig?: JsonColumnConfig<T>
|
|
267
266
|
}
|
|
268
267
|
|
|
269
268
|
/**
|
|
@@ -380,7 +379,7 @@ export const column = {
|
|
|
380
379
|
constraints: ColumnConstraints & { validateJson?: boolean },
|
|
381
380
|
): ColumnDefinition => ({
|
|
382
381
|
type: SQLiteTypes.JSON,
|
|
383
|
-
check: constraints?.validateJson
|
|
382
|
+
check: constraints?.validateJson
|
|
384
383
|
? "JSON_VALID({{COLUMN}})"
|
|
385
384
|
: constraints?.check,
|
|
386
385
|
...constraints,
|
|
@@ -606,9 +605,7 @@ export interface InsertOptions {
|
|
|
606
605
|
/**
|
|
607
606
|
* JSON column configuration
|
|
608
607
|
*/
|
|
609
|
-
export
|
|
610
|
-
jsonColumns?: Array<keyof T>;
|
|
611
|
-
}
|
|
608
|
+
export type JsonColumnConfig<T> = Array<keyof T>
|
|
612
609
|
|
|
613
610
|
/**
|
|
614
611
|
* Generic database row type
|