deepbase-sqlite 3.6.5 → 3.6.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 +1 -1
- package/package.json +2 -2
- package/src/SqliteDriver.js +49 -2
- package/test/test.js +22 -0
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ Efficiently stores nested objects using a key-value schema:
|
|
|
82
82
|
- Values are stored as JSON
|
|
83
83
|
- Fast lookups for both exact keys and partial paths
|
|
84
84
|
|
|
85
|
-
Each row also stores a monotonic `seq` so reads that rebuild objects use `ORDER BY seq, key`. That matches JavaScript insertion order for sibling keys and keeps `shift()` / `pop()` (
|
|
85
|
+
Each row also stores a monotonic `seq` so reads that rebuild objects use `ORDER BY seq, key`. That matches JavaScript insertion order for sibling keys and keeps `shift()` / `pop()` aligned with `JsonDriver`. The driver now exposes `first()` / `last()` using SQL boundary queries in the same order semantics as `keys()`. Existing databases pick up `seq` via `ALTER TABLE` on connect (legacy rows default to `0`, then tie-break by `key`).
|
|
86
86
|
|
|
87
87
|
### ACID Compliance
|
|
88
88
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepbase-sqlite",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.7",
|
|
4
4
|
"description": "⚡ DeepBase SQLite - SQLite database driver",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.cjs",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"better-sqlite3": "^11.8.1"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"deepbase": "^3.6.
|
|
20
|
+
"deepbase": "^3.6.7"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"test": "mocha test/test.js"
|
package/src/SqliteDriver.js
CHANGED
|
@@ -112,6 +112,12 @@ export class SqliteDriver extends DeepBaseDriver {
|
|
|
112
112
|
this.getKeysLikeStmt = this.db.prepare(
|
|
113
113
|
"SELECT key, value FROM deepbase WHERE key LIKE ? ESCAPE '!' ORDER BY seq, key",
|
|
114
114
|
);
|
|
115
|
+
this.getFirstChildKeyStmt = this.db.prepare(
|
|
116
|
+
"SELECT key FROM deepbase WHERE key LIKE ? ESCAPE '!' ORDER BY seq, key LIMIT 1",
|
|
117
|
+
);
|
|
118
|
+
this.getLastChildKeyStmt = this.db.prepare(
|
|
119
|
+
"SELECT key FROM deepbase WHERE key LIKE ? ESCAPE '!' ORDER BY seq DESC, key DESC LIMIT 1",
|
|
120
|
+
);
|
|
115
121
|
this.delChildrenStmt = this.db.prepare("DELETE FROM deepbase WHERE key LIKE ? ESCAPE '!'");
|
|
116
122
|
this.hasChildrenStmt = this.db.prepare("SELECT 1 FROM deepbase WHERE key LIKE ? ESCAPE '!' LIMIT 1");
|
|
117
123
|
|
|
@@ -120,7 +126,8 @@ export class SqliteDriver extends DeepBaseDriver {
|
|
|
120
126
|
this.setStmt.run(key, jsonValue);
|
|
121
127
|
});
|
|
122
128
|
|
|
123
|
-
this._delTxn = this.db.transaction((key, likePattern) => {
|
|
129
|
+
this._delTxn = this.db.transaction((key, likePattern, keys) => {
|
|
130
|
+
this._expandParentObjects(keys);
|
|
124
131
|
this.delStmt.run(key);
|
|
125
132
|
this.delChildrenStmt.run(likePattern);
|
|
126
133
|
});
|
|
@@ -216,7 +223,7 @@ export class SqliteDriver extends DeepBaseDriver {
|
|
|
216
223
|
}
|
|
217
224
|
|
|
218
225
|
const key = this._pathToKey(keys);
|
|
219
|
-
this._delTxn(key, this._likePrefix(key));
|
|
226
|
+
this._delTxn(key, this._likePrefix(key), keys);
|
|
220
227
|
}
|
|
221
228
|
|
|
222
229
|
async inc(...args) {
|
|
@@ -242,6 +249,46 @@ export class SqliteDriver extends DeepBaseDriver {
|
|
|
242
249
|
return this._updTxn(keys, func);
|
|
243
250
|
}
|
|
244
251
|
|
|
252
|
+
async first(...args) {
|
|
253
|
+
return this._firstOrLastKey(args, false);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async last(...args) {
|
|
257
|
+
return this._firstOrLastKey(args, true);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
_firstOrLastKey(path, fromEnd) {
|
|
261
|
+
const nestedKey = this._findBoundaryNestedKey(path, fromEnd);
|
|
262
|
+
if (nestedKey !== undefined) {
|
|
263
|
+
return nestedKey;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const value = this._getSync(path);
|
|
267
|
+
if (value === null || typeof value !== 'object') {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let keyResult;
|
|
272
|
+
for (const key in value) {
|
|
273
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
274
|
+
if (!fromEnd) return key;
|
|
275
|
+
keyResult = key;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return keyResult;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
_findBoundaryNestedKey(path, fromEnd) {
|
|
282
|
+
const likePattern = path.length === 0 ? '%' : this._likePrefix(this._pathToKey(path));
|
|
283
|
+
const row = (fromEnd ? this.getLastChildKeyStmt : this.getFirstChildKeyStmt).get(likePattern);
|
|
284
|
+
if (!row) return undefined;
|
|
285
|
+
|
|
286
|
+
const fullPath = this._keyToPath(row.key);
|
|
287
|
+
if (fullPath.length <= path.length) return undefined;
|
|
288
|
+
|
|
289
|
+
return fullPath[path.length];
|
|
290
|
+
}
|
|
291
|
+
|
|
245
292
|
_getRootObject() {
|
|
246
293
|
const rows = this.getAllStmt.all();
|
|
247
294
|
const result = {};
|
package/test/test.js
CHANGED
|
@@ -159,6 +159,15 @@ for (const pragma of PRAGMA_MODES) {
|
|
|
159
159
|
assert.deepStrictEqual(await db.get('user'), { name: 'Alice' });
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
+
it('should delete a deep key from an object value', async function () {
|
|
163
|
+
await db.set('a', {
|
|
164
|
+
b: { c: 1, d: 2 },
|
|
165
|
+
e: 3,
|
|
166
|
+
});
|
|
167
|
+
await db.del('a', 'b', 'c');
|
|
168
|
+
assert.deepStrictEqual(await db.get('a'), { b: { d: 2 }, e: 3 });
|
|
169
|
+
});
|
|
170
|
+
|
|
162
171
|
it('should delete parent and all children', async function () {
|
|
163
172
|
await db.set('parent', 'child1', 'value1');
|
|
164
173
|
await db.set('parent', 'child2', 'value2');
|
|
@@ -278,6 +287,19 @@ for (const pragma of PRAGMA_MODES) {
|
|
|
278
287
|
assert.deepStrictEqual(await db.values('simple'), []);
|
|
279
288
|
assert.deepStrictEqual(await db.entries('simple'), []);
|
|
280
289
|
});
|
|
290
|
+
|
|
291
|
+
it('first/last should match keys() boundaries', async function () {
|
|
292
|
+
const keys = await db.keys('users');
|
|
293
|
+
const driver = db.getDriver(0);
|
|
294
|
+
assert.strictEqual(await driver.first('users'), keys[0]);
|
|
295
|
+
assert.strictEqual(await driver.last('users'), keys[keys.length - 1]);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('first/last should return undefined for missing path', async function () {
|
|
299
|
+
const driver = db.getDriver(0);
|
|
300
|
+
assert.strictEqual(await driver.first('missing'), undefined);
|
|
301
|
+
assert.strictEqual(await driver.last('missing'), undefined);
|
|
302
|
+
});
|
|
281
303
|
});
|
|
282
304
|
|
|
283
305
|
describe('Persistence', function () {
|