@dothift/amarok-lite 1.5.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/Cargo.toml +18 -0
- package/README.md +90 -0
- package/amarok-lite.win32-x64-msvc.node +0 -0
- package/dist/amarok-lite.js +315 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +28 -0
- package/dist/event-log.d.ts +3 -0
- package/dist/event-log.js +31 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/jsonb.d.ts +16 -0
- package/dist/jsonb.js +24 -0
- package/dist/rows.d.ts +21 -0
- package/dist/rows.js +45 -0
- package/dist/store.d.ts +77 -0
- package/dist/store.js +212 -0
- package/dist/transaction.d.ts +28 -0
- package/dist/transaction.js +66 -0
- package/index.d.ts +35 -0
- package/index.js +315 -0
- package/package.json +62 -0
package/Cargo.toml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "amarok_lite_node"
|
|
3
|
+
version = "1.5.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "napi-rs bindings for dotHIFT://Amarok Lite"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
|
|
8
|
+
[lib]
|
|
9
|
+
crate-type = ["cdylib"]
|
|
10
|
+
|
|
11
|
+
[dependencies]
|
|
12
|
+
napi = { version = "2", features = ["napi8", "serde-json"] }
|
|
13
|
+
napi-derive = "2"
|
|
14
|
+
amarok-core = { path = "../../crates/amarok-core" }
|
|
15
|
+
serde_json = "1"
|
|
16
|
+
|
|
17
|
+
[build-dependencies]
|
|
18
|
+
napi-build = "2"
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# dotHIFT://Amarok — Amarok-Lite Node.js SDK
|
|
2
|
+
|
|
3
|
+
`@dothift/amarok-lite` is an embeddable TypeScript/Node.js database engine for
|
|
4
|
+
[dotHIFT://Amarok](https://gitea.local/dotHIFT/amarok). It wraps
|
|
5
|
+
[better-sqlite3](https://github.com/WiseLibs/better-sqlite3) in WAL mode and
|
|
6
|
+
exposes the Amarok API surface so that code written for Amarok-Lite is
|
|
7
|
+
compatible with the full Amarok server SDK.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @dothift/amarok-lite
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start — synchronous
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { Store } from '@dothift/amarok-lite'
|
|
19
|
+
|
|
20
|
+
const db = Store.open('./myapp.db')
|
|
21
|
+
|
|
22
|
+
db.exec('CREATE TABLE IF NOT EXISTS tickets (id TEXT PRIMARY KEY, data TEXT)')
|
|
23
|
+
db.exec('INSERT INTO tickets VALUES ($1, $2)', ['t-001', { title: 'First ticket' }])
|
|
24
|
+
|
|
25
|
+
const rows = db.query('SELECT * FROM tickets WHERE id = $1', ['t-001'])
|
|
26
|
+
console.log(rows.fetchall())
|
|
27
|
+
|
|
28
|
+
db.close()
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick start — async
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { Store } from '@dothift/amarok-lite'
|
|
35
|
+
|
|
36
|
+
const db = Store.open('./myapp.db')
|
|
37
|
+
|
|
38
|
+
await db.execAsync('CREATE TABLE IF NOT EXISTS tickets (id TEXT PRIMARY KEY, data TEXT)')
|
|
39
|
+
await db.execAsync('INSERT INTO tickets VALUES ($1, $2)', ['t-002', { title: 'Second' }])
|
|
40
|
+
|
|
41
|
+
const rows = await db.queryAsync('SELECT * FROM tickets')
|
|
42
|
+
console.log(rows.fetchall())
|
|
43
|
+
|
|
44
|
+
db.close()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Transactions
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { Store } from '@dothift/amarok-lite'
|
|
51
|
+
|
|
52
|
+
const db = Store.open('./bank.db')
|
|
53
|
+
db.exec('CREATE TABLE IF NOT EXISTS accounts (id TEXT PRIMARY KEY, balance INTEGER)')
|
|
54
|
+
db.exec('INSERT INTO accounts VALUES ($1, $2)', ['alice', 1000])
|
|
55
|
+
db.exec('INSERT INTO accounts VALUES ($1, $2)', ['bob', 500])
|
|
56
|
+
|
|
57
|
+
db.transaction((tx) => {
|
|
58
|
+
tx.exec('UPDATE accounts SET balance = balance - 100 WHERE id = $1', ['alice'])
|
|
59
|
+
tx.exec('UPDATE accounts SET balance = balance + 100 WHERE id = $1', ['bob'])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
db.close()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## JSONB operators
|
|
66
|
+
|
|
67
|
+
Queries using Amarok's PostgreSQL-style JSONB operators are automatically
|
|
68
|
+
rewritten to SQLite3 JSON functions:
|
|
69
|
+
|
|
70
|
+
| Amarok operator | SQLite equivalent |
|
|
71
|
+
|------------------------|----------------------------------------------|
|
|
72
|
+
| `col->>'key'` | `json_extract(col, '$.key')` |
|
|
73
|
+
| `col->'key'` | `json_extract(col, '$.key')` |
|
|
74
|
+
| `col ? 'key'` | `(json_type(col, '$.key') IS NOT NULL)` |
|
|
75
|
+
| `col @> '{"k":"v"}'` | `(json_patch(col, '{"k":"v"}') = col)` |
|
|
76
|
+
|
|
77
|
+
## Options
|
|
78
|
+
|
|
79
|
+
| Option | Default | Description |
|
|
80
|
+
|--------------------|---------|------------------------------------------|
|
|
81
|
+
| `wal` | `true` | Enable WAL journal mode |
|
|
82
|
+
| `cacheKB` | `8000` | Page cache size in KB (~8 MB) |
|
|
83
|
+
| `walAutocheckpoint`| `1000` | WAL auto-checkpoint threshold (pages) |
|
|
84
|
+
| `timeoutMs` | `30000` | Busy-wait timeout in milliseconds |
|
|
85
|
+
| `enableEventLog` | `true` | Create Phase 2 event log stub tables |
|
|
86
|
+
|
|
87
|
+
## Part of dotHIFT
|
|
88
|
+
|
|
89
|
+
See the [.platform](https://gitea.local/dotHIFT/.platform) repo for
|
|
90
|
+
cross-product architecture decisions and the dependency manifest.
|
|
Binary file
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/* prettier-ignore */
|
|
4
|
+
|
|
5
|
+
/* auto-generated by NAPI-RS */
|
|
6
|
+
|
|
7
|
+
const { existsSync, readFileSync } = require('fs')
|
|
8
|
+
const { join } = require('path')
|
|
9
|
+
|
|
10
|
+
const { platform, arch } = process
|
|
11
|
+
|
|
12
|
+
let nativeBinding = null
|
|
13
|
+
let localFileExisted = false
|
|
14
|
+
let loadError = null
|
|
15
|
+
|
|
16
|
+
function isMusl() {
|
|
17
|
+
// For Node 10
|
|
18
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
19
|
+
try {
|
|
20
|
+
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
|
21
|
+
return readFileSync(lddPath, 'utf8').includes('musl')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
27
|
+
return !glibcVersionRuntime
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (platform) {
|
|
32
|
+
case 'android':
|
|
33
|
+
switch (arch) {
|
|
34
|
+
case 'arm64':
|
|
35
|
+
localFileExisted = existsSync(join(__dirname, 'amarok-lite.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./amarok-lite.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('@dothift/amarok-lite-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'amarok-lite.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./amarok-lite.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('@dothift/amarok-lite-android-arm-eabi')
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
loadError = e
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'win32':
|
|
63
|
+
switch (arch) {
|
|
64
|
+
case 'x64':
|
|
65
|
+
localFileExisted = existsSync(
|
|
66
|
+
join(__dirname, 'amarok-lite.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./amarok-lite.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('@dothift/amarok-lite-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'amarok-lite.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./amarok-lite.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('@dothift/amarok-lite-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'amarok-lite.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./amarok-lite.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('@dothift/amarok-lite-win32-arm64-msvc')
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
loadError = e
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
|
108
|
+
}
|
|
109
|
+
break
|
|
110
|
+
case 'darwin':
|
|
111
|
+
localFileExisted = existsSync(join(__dirname, 'amarok-lite.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./amarok-lite.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('@dothift/amarok-lite-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'amarok-lite.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./amarok-lite.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('@dothift/amarok-lite-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'amarok-lite.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./amarok-lite.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('@dothift/amarok-lite-darwin-arm64')
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
loadError = e
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
case 'freebsd':
|
|
152
|
+
if (arch !== 'x64') {
|
|
153
|
+
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
|
154
|
+
}
|
|
155
|
+
localFileExisted = existsSync(join(__dirname, 'amarok-lite.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./amarok-lite.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('@dothift/amarok-lite-freebsd-x64')
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
loadError = e
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
case 'linux':
|
|
167
|
+
switch (arch) {
|
|
168
|
+
case 'x64':
|
|
169
|
+
if (isMusl()) {
|
|
170
|
+
localFileExisted = existsSync(
|
|
171
|
+
join(__dirname, 'amarok-lite.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./amarok-lite.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('@dothift/amarok-lite-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'amarok-lite.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./amarok-lite.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('@dothift/amarok-lite-linux-x64-gnu')
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
loadError = e
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 'arm64':
|
|
198
|
+
if (isMusl()) {
|
|
199
|
+
localFileExisted = existsSync(
|
|
200
|
+
join(__dirname, 'amarok-lite.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./amarok-lite.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('@dothift/amarok-lite-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'amarok-lite.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./amarok-lite.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('@dothift/amarok-lite-linux-arm64-gnu')
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadError = e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break
|
|
226
|
+
case 'arm':
|
|
227
|
+
if (isMusl()) {
|
|
228
|
+
localFileExisted = existsSync(
|
|
229
|
+
join(__dirname, 'amarok-lite.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./amarok-lite.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('@dothift/amarok-lite-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'amarok-lite.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./amarok-lite.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('@dothift/amarok-lite-linux-arm-gnueabihf')
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
loadError = e
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break
|
|
255
|
+
case 'riscv64':
|
|
256
|
+
if (isMusl()) {
|
|
257
|
+
localFileExisted = existsSync(
|
|
258
|
+
join(__dirname, 'amarok-lite.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./amarok-lite.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('@dothift/amarok-lite-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'amarok-lite.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./amarok-lite.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('@dothift/amarok-lite-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'amarok-lite.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./amarok-lite.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('@dothift/amarok-lite-linux-s390x-gnu')
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadError = e
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
|
300
|
+
}
|
|
301
|
+
break
|
|
302
|
+
default:
|
|
303
|
+
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!nativeBinding) {
|
|
307
|
+
if (loadError) {
|
|
308
|
+
throw loadError
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Failed to load native binding`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { AmarokStore } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.AmarokStore = AmarokStore
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Base class for all Amarok-Lite errors. */
|
|
2
|
+
export declare class AmarokError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/** Raised for operational errors (I/O, locking, WAL). */
|
|
6
|
+
export declare class AmarokOperationalError extends AmarokError {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
/** Raised for constraint violations (UNIQUE, NOT NULL, FK). */
|
|
10
|
+
export declare class AmarokIntegrityError extends AmarokError {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
/** Raised for programming errors (bad SQL, wrong param count). */
|
|
14
|
+
export declare class AmarokProgrammingError extends AmarokError {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Base class for all Amarok-Lite errors. */
|
|
2
|
+
export class AmarokError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = 'AmarokError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Raised for operational errors (I/O, locking, WAL). */
|
|
9
|
+
export class AmarokOperationalError extends AmarokError {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'AmarokOperationalError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Raised for constraint violations (UNIQUE, NOT NULL, FK). */
|
|
16
|
+
export class AmarokIntegrityError extends AmarokError {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'AmarokIntegrityError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Raised for programming errors (bad SQL, wrong param count). */
|
|
23
|
+
export class AmarokProgrammingError extends AmarokError {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = 'AmarokProgrammingError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const CREATE_EVENTS_TABLE = `
|
|
2
|
+
CREATE TABLE IF NOT EXISTS _amarok_events (
|
|
3
|
+
event_id TEXT NOT NULL,
|
|
4
|
+
sequence INTEGER NOT NULL,
|
|
5
|
+
region TEXT NOT NULL DEFAULT 'local',
|
|
6
|
+
node_id TEXT NOT NULL DEFAULT 'lite',
|
|
7
|
+
ts TEXT NOT NULL,
|
|
8
|
+
db_name TEXT NOT NULL DEFAULT 'default',
|
|
9
|
+
collection TEXT NOT NULL,
|
|
10
|
+
entity_id TEXT NOT NULL,
|
|
11
|
+
operation TEXT NOT NULL CHECK(operation IN ('insert','update','delete','schema')),
|
|
12
|
+
actor_type TEXT NOT NULL DEFAULT 'system',
|
|
13
|
+
actor_id TEXT NOT NULL DEFAULT 'lite',
|
|
14
|
+
correlation_id TEXT,
|
|
15
|
+
before_state TEXT,
|
|
16
|
+
after_state TEXT,
|
|
17
|
+
metadata TEXT,
|
|
18
|
+
PRIMARY KEY (sequence, node_id)
|
|
19
|
+
)`;
|
|
20
|
+
const CREATE_ENTITY_IDX = `
|
|
21
|
+
CREATE INDEX IF NOT EXISTS _amarok_events_entity_idx
|
|
22
|
+
ON _amarok_events(collection, entity_id, sequence)`;
|
|
23
|
+
const CREATE_SEQ_IDX = `
|
|
24
|
+
CREATE INDEX IF NOT EXISTS _amarok_events_seq_idx
|
|
25
|
+
ON _amarok_events(sequence)`;
|
|
26
|
+
/** Create Phase 2 event log stub tables if they do not exist. */
|
|
27
|
+
export function ensureEventLog(store) {
|
|
28
|
+
store.exec(CREATE_EVENTS_TABLE);
|
|
29
|
+
store.exec(CREATE_ENTITY_IDX);
|
|
30
|
+
store.exec(CREATE_SEQ_IDX);
|
|
31
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Store } from './store.js';
|
|
2
|
+
export type { Options } from './store.js';
|
|
3
|
+
export { Rows } from './rows.js';
|
|
4
|
+
export type { Row } from './rows.js';
|
|
5
|
+
export { Tx } from './transaction.js';
|
|
6
|
+
export { AmarokError, AmarokOperationalError, AmarokIntegrityError, AmarokProgrammingError, } from './errors.js';
|
package/dist/index.js
ADDED
package/dist/jsonb.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONB operator passthrough for Amarok-Lite.
|
|
3
|
+
*
|
|
4
|
+
* `amarok-core` natively understands PostgreSQL-style JSONB operators
|
|
5
|
+
* (`->`, `->>`, `@>`, `?`), so no SQL rewriting is required.
|
|
6
|
+
*
|
|
7
|
+
* The `rewrite`, `rewritePlaceholders`, and `normaliseParams` functions are
|
|
8
|
+
* kept as no-ops / identity functions for API compatibility with callers that
|
|
9
|
+
* were written against the SQLite-backed version of the SDK.
|
|
10
|
+
*/
|
|
11
|
+
/** Pass SQL through unchanged. amarok-core handles all JSONB operators natively. */
|
|
12
|
+
export declare function rewrite(sql: string): string;
|
|
13
|
+
/** Pass SQL through unchanged. The native engine uses $1/$2 syntax natively. */
|
|
14
|
+
export declare function rewritePlaceholders(sql: string): string;
|
|
15
|
+
/** Pass params through unchanged. */
|
|
16
|
+
export declare function normaliseParams(params: unknown[] | undefined): unknown[];
|
package/dist/jsonb.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONB operator passthrough for Amarok-Lite.
|
|
3
|
+
*
|
|
4
|
+
* `amarok-core` natively understands PostgreSQL-style JSONB operators
|
|
5
|
+
* (`->`, `->>`, `@>`, `?`), so no SQL rewriting is required.
|
|
6
|
+
*
|
|
7
|
+
* The `rewrite`, `rewritePlaceholders`, and `normaliseParams` functions are
|
|
8
|
+
* kept as no-ops / identity functions for API compatibility with callers that
|
|
9
|
+
* were written against the SQLite-backed version of the SDK.
|
|
10
|
+
*/
|
|
11
|
+
/** Pass SQL through unchanged. amarok-core handles all JSONB operators natively. */
|
|
12
|
+
export function rewrite(sql) {
|
|
13
|
+
return sql;
|
|
14
|
+
}
|
|
15
|
+
/** Pass SQL through unchanged. The native engine uses $1/$2 syntax natively. */
|
|
16
|
+
export function rewritePlaceholders(sql) {
|
|
17
|
+
return sql;
|
|
18
|
+
}
|
|
19
|
+
/** Pass params through unchanged. */
|
|
20
|
+
export function normaliseParams(params) {
|
|
21
|
+
if (!params || params.length === 0)
|
|
22
|
+
return [];
|
|
23
|
+
return params;
|
|
24
|
+
}
|
package/dist/rows.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Row type — a record of column name → value. */
|
|
2
|
+
export type Row = Record<string, unknown>;
|
|
3
|
+
/** Iterator over query results. */
|
|
4
|
+
export declare class Rows {
|
|
5
|
+
private readonly _columns;
|
|
6
|
+
private readonly _rows;
|
|
7
|
+
private _pos;
|
|
8
|
+
private _closed;
|
|
9
|
+
/** @internal */
|
|
10
|
+
constructor(rawRows: Record<string, unknown>[], columns: string[]);
|
|
11
|
+
/** Column names for the current result set. */
|
|
12
|
+
get columns(): string[];
|
|
13
|
+
/** Return the next row, or undefined if exhausted. */
|
|
14
|
+
fetchone(): Row | undefined;
|
|
15
|
+
/** Return all remaining rows. */
|
|
16
|
+
fetchall(): Row[];
|
|
17
|
+
/** Iterate rows with for…of. */
|
|
18
|
+
[Symbol.iterator](): Iterator<Row>;
|
|
19
|
+
get length(): number;
|
|
20
|
+
close(): void;
|
|
21
|
+
}
|
package/dist/rows.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Iterator over query results. */
|
|
2
|
+
export class Rows {
|
|
3
|
+
_columns;
|
|
4
|
+
_rows;
|
|
5
|
+
_pos = 0;
|
|
6
|
+
_closed = false;
|
|
7
|
+
/** @internal */
|
|
8
|
+
constructor(rawRows, columns) {
|
|
9
|
+
this._columns = columns;
|
|
10
|
+
this._rows = rawRows;
|
|
11
|
+
}
|
|
12
|
+
/** Column names for the current result set. */
|
|
13
|
+
get columns() {
|
|
14
|
+
return this._columns;
|
|
15
|
+
}
|
|
16
|
+
/** Return the next row, or undefined if exhausted. */
|
|
17
|
+
fetchone() {
|
|
18
|
+
if (this._closed || this._pos >= this._rows.length)
|
|
19
|
+
return undefined;
|
|
20
|
+
return this._rows[this._pos++];
|
|
21
|
+
}
|
|
22
|
+
/** Return all remaining rows. */
|
|
23
|
+
fetchall() {
|
|
24
|
+
const remaining = this._rows.slice(this._pos);
|
|
25
|
+
this._pos = this._rows.length;
|
|
26
|
+
return remaining;
|
|
27
|
+
}
|
|
28
|
+
/** Iterate rows with for…of. */
|
|
29
|
+
[Symbol.iterator]() {
|
|
30
|
+
return {
|
|
31
|
+
next: () => {
|
|
32
|
+
const row = this.fetchone();
|
|
33
|
+
return row !== undefined
|
|
34
|
+
? { value: row, done: false }
|
|
35
|
+
: { value: undefined, done: true };
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
get length() {
|
|
40
|
+
return this._rows.length;
|
|
41
|
+
}
|
|
42
|
+
close() {
|
|
43
|
+
this._closed = true;
|
|
44
|
+
}
|
|
45
|
+
}
|