@atscript/db-sqlite 0.1.38 → 0.1.40

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 CHANGED
@@ -1,21 +1,20 @@
1
- # @atscript/db-sqlite
1
+ <p align="center">
2
+ <img src="https://atscript.dev/logo.svg" alt="Atscript" width="120" />
3
+ </p>
2
4
 
3
- SQLite adapter for `@atscript/db` with a swappable driver architecture. Define your schema once in Atscript, then use it with any SQLite engine.
5
+ <h1 align="center">@atscript/db-sqlite</h1>
4
6
 
5
- ## Architecture
7
+ <p align="center">
8
+ <strong>Define your models once</strong> — get TypeScript types, runtime validation, and DB metadata from a single <code>.as</code> model.
9
+ </p>
6
10
 
7
- ```
8
- AtscriptDbTable ──delegates──▶ SqliteAdapter ──delegates──▶ TSqliteDriver
9
- (extends BaseDbAdapter) (interface)
10
-
11
- ┌─────────┴──────────┐
12
- │ │
13
- BetterSqlite3Driver (your own driver)
14
- (ships with package) node:sqlite
15
- sql.js, etc.
16
- ```
11
+ <p align="center">
12
+ <a href="https://db.atscript.dev">Documentation</a> · <a href="https://db.atscript.dev/adapters/sqlite">SQLite Adapter</a>
13
+ </p>
17
14
 
18
- The adapter defines a minimal `TSqliteDriver` interface — just raw SQL primitives (`run`, `all`, `get`, `exec`, `close`). The actual SQLite engine is injected, not hardcoded.
15
+ ---
16
+
17
+ SQLite adapter for `@atscript/db` with a swappable driver architecture. Ships with a `BetterSqlite3Driver` for `better-sqlite3` and supports custom drivers for `node:sqlite` (Node 22.5+), `sql.js`, or any other SQLite engine.
19
18
 
20
19
  ## Installation
21
20
 
@@ -23,186 +22,33 @@ The adapter defines a minimal `TSqliteDriver` interface — just raw SQL primiti
23
22
  pnpm add @atscript/db-sqlite better-sqlite3
24
23
  ```
25
24
 
26
- `better-sqlite3` is an **optional peer dependency** — only required if you use the built-in `BetterSqlite3Driver`. Bring your own driver if you prefer a different engine.
27
-
28
25
  ## Quick Start
29
26
 
30
27
  ```typescript
31
- import { AtscriptDbTable } from '@atscript/db'
32
- import { SqliteAdapter, BetterSqlite3Driver } from '@atscript/db-sqlite'
33
- import { User } from './user.as'
34
-
35
- // 1. Create a driver (in-memory or file-based)
36
- const driver = new BetterSqlite3Driver(':memory:')
37
- // or: new BetterSqlite3Driver('./data.db')
38
-
39
- // 2. Create adapter + table
40
- const adapter = new SqliteAdapter(driver)
41
- const users = new AtscriptDbTable(User, adapter)
42
-
43
- // 3. Set up schema
44
- await users.ensureTable() // CREATE TABLE IF NOT EXISTS
45
- await users.syncIndexes() // CREATE INDEX / DROP INDEX
46
-
47
- // 4. CRUD
48
- await users.insertOne({ name: 'John', email: 'john@example.com' })
49
- const john = await users.findOne({ name: 'John' })
50
- await users.findMany({ status: 'active' }, { limit: 10, sort: { name: 1 } })
51
- await users.count({ status: 'active' })
52
- await users.updateMany({ status: 'inactive' }, { status: 'archived' })
53
- await users.deleteOne(123)
54
- await users.deleteMany({ status: 'archived' })
55
- ```
56
-
57
- ## Swapping the Driver
58
-
59
- The `TSqliteDriver` interface is minimal — implement these 5 methods:
60
-
61
- ```typescript
62
- interface TSqliteDriver {
63
- run(sql: string, params?: unknown[]): TSqliteRunResult
64
- all<T>(sql: string, params?: unknown[]): T[]
65
- get<T>(sql: string, params?: unknown[]): T | null
66
- exec(sql: string): void
67
- close(): void
68
- }
69
-
70
- interface TSqliteRunResult {
71
- changes: number
72
- lastInsertRowid: number | bigint
73
- }
74
- ```
75
-
76
- ### Example: Custom driver
77
-
78
- ```typescript
79
- import { SqliteAdapter, type TSqliteDriver } from '@atscript/db-sqlite'
80
-
81
- class MyDriver implements TSqliteDriver {
82
- run(sql: string, params?: unknown[]) {
83
- // your implementation
84
- return { changes: 0, lastInsertRowid: 0 }
85
- }
86
- all(sql: string, params?: unknown[]) { /* ... */ }
87
- get(sql: string, params?: unknown[]) { /* ... */ }
88
- exec(sql: string) { /* ... */ }
89
- close() { /* ... */ }
90
- }
91
-
92
- const adapter = new SqliteAdapter(new MyDriver())
93
- ```
28
+ import { DbSpace } from "@atscript/db";
29
+ import { createAdapter } from "@atscript/db-sqlite";
94
30
 
95
- ### Example: node:sqlite (Node 22.5+)
31
+ const db = createAdapter("./myapp.db");
32
+ const users = db.getTable(UsersType);
96
33
 
97
- ```typescript
98
- import { DatabaseSync } from 'node:sqlite'
99
- import { SqliteAdapter, type TSqliteDriver } from '@atscript/db-sqlite'
100
-
101
- class NodeSqliteDriver implements TSqliteDriver {
102
- private db: DatabaseSync
103
-
104
- constructor(path: string) {
105
- this.db = new DatabaseSync(path)
106
- }
107
-
108
- run(sql: string, params?: unknown[]) {
109
- const stmt = this.db.prepare(sql)
110
- stmt.run(...(params ?? []))
111
- return {
112
- changes: this.db.changes,
113
- lastInsertRowid: this.db.lastInsertRowId,
114
- }
115
- }
116
-
117
- all<T>(sql: string, params?: unknown[]): T[] {
118
- return this.db.prepare(sql).all(...(params ?? [])) as T[]
119
- }
120
-
121
- get<T>(sql: string, params?: unknown[]): T | null {
122
- return (this.db.prepare(sql).get(...(params ?? [])) as T) ?? null
123
- }
124
-
125
- exec(sql: string) { this.db.exec(sql) }
126
- close() { this.db.close() }
127
- }
128
-
129
- const adapter = new SqliteAdapter(new NodeSqliteDriver(':memory:'))
34
+ await users.insertOne({ name: "John", email: "john@example.com" });
130
35
  ```
131
36
 
132
- ## Filter Syntax
133
-
134
- Filters use MongoDB-style query objects (same format as URLQL):
37
+ ## Features
135
38
 
136
- | Filter | SQL |
137
- |---|---|
138
- | `{ field: value }` | `field = ?` |
139
- | `{ field: { $gt: 5 } }` | `field > ?` |
140
- | `{ field: { $gte: 5 } }` | `field >= ?` |
141
- | `{ field: { $lt: 5 } }` | `field < ?` |
142
- | `{ field: { $lte: 5 } }` | `field <= ?` |
143
- | `{ field: { $ne: value } }` | `field != ?` |
144
- | `{ field: { $in: [1, 2] } }` | `field IN (?, ?)` |
145
- | `{ field: { $nin: [1, 2] } }` | `field NOT IN (?, ?)` |
146
- | `{ field: { $exists: true } }` | `field IS NOT NULL` |
147
- | `{ field: { $regex: '^abc' } }` | `field LIKE 'abc%'` |
148
- | `{ $and: [...] }` | `(... AND ...)` |
149
- | `{ $or: [...] }` | `(... OR ...)` |
150
- | `{ $not: {...} }` | `NOT (...)` |
151
-
152
- All values are parameterized — no SQL injection risk.
153
-
154
- ## Schema Operations
155
-
156
- ### `ensureTable()`
157
-
158
- Generates `CREATE TABLE IF NOT EXISTS` from the Atscript type:
159
- - Column types inferred from `designType` (`string` → TEXT, `number` → REAL, `boolean` → INTEGER)
160
- - Primary keys from `@meta.id`
161
- - `NOT NULL` for required fields
162
- - `@db.column` mappings applied (logical → physical column names)
163
- - `@db.ignore` fields excluded
164
-
165
- ### `syncIndexes()`
166
-
167
- Compares existing indexes with `@db.index.*` annotations:
168
- - Creates missing indexes (`CREATE INDEX` / `CREATE UNIQUE INDEX`)
169
- - Drops stale indexes no longer in the definition
170
- - Supports `@db.index.plain`, `@db.index.unique`
171
- - `@db.index.fulltext` is skipped (requires FTS5 virtual tables — not auto-managed)
172
-
173
- ## Write Pipeline
174
-
175
- When you call `insertOne(payload)`, `AtscriptDbTable` automatically:
176
-
177
- 1. Applies `@db.default` defaults for missing fields
178
- 2. Validates against the Atscript type
179
- 3. Strips `@db.ignore` fields
180
- 4. Maps `@db.column` logical names to physical column names
181
- 5. Delegates to `SqliteAdapter.insertOne()` which generates and runs the SQL
182
-
183
- ## Exports
184
-
185
- ```typescript
186
- // Classes
187
- export { SqliteAdapter } from './sqlite-adapter'
188
- export { BetterSqlite3Driver } from './better-sqlite3-driver'
189
-
190
- // Utilities
191
- export { buildWhere } from './filter-builder'
192
-
193
- // Types
194
- export type { TSqliteDriver, TSqliteRunResult } from './types'
195
- export type { TSqlFragment } from './filter-builder'
196
- ```
39
+ - Swappable driver via `TSqliteDriver` interface (5 methods)
40
+ - Built-in `BetterSqlite3Driver` for immediate use
41
+ - MongoDB-style filter translation to parameterized SQL (no injection risk)
42
+ - Automatic schema management from `@db.*` annotations
43
+ - FTS5 full-text search support
44
+ - Embedded object flattening and `@db.json` storage
45
+ - Schema sync via `@atscript/db/sync`
197
46
 
198
- ## Why Sync Driver Interface?
47
+ ## Documentation
199
48
 
200
- The driver interface is **synchronous** because:
201
- - SQLite is an embedded engine — no network I/O
202
- - `better-sqlite3` and `node:sqlite` are both synchronous
203
- - The `SqliteAdapter` wraps sync calls in promises for the async `BaseDbAdapter` contract
204
- - For truly async drivers, implement the interface with a synchronous wrapper or create a custom adapter subclass
49
+ - [SQLite Adapter Guide](https://db.atscript.dev/adapters/sqlite)
50
+ - [Full Documentation](https://db.atscript.dev)
205
51
 
206
52
  ## License
207
53
 
208
- ISC
54
+ MIT