deepbase-sqlite 3.6.8 → 3.6.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepbase-sqlite",
3
- "version": "3.6.8",
3
+ "version": "3.6.10",
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.8"
20
+ "deepbase": "^3.6.10"
21
21
  },
22
22
  "scripts": {
23
23
  "test": "mocha test/test.js"
@@ -125,7 +125,7 @@ export class SqliteDriver extends DeepBaseDriver {
125
125
 
126
126
  this._setTxn = this.db.transaction((key, jsonValue, keys) => {
127
127
  this._expandParentObjects(keys);
128
- this.setStmt.run(key, jsonValue, this._consumeSeq());
128
+ this._replaceRow(key, jsonValue);
129
129
  });
130
130
 
131
131
  this._delTxn = this.db.transaction((key, likePattern, keys) => {
@@ -139,7 +139,7 @@ export class SqliteDriver extends DeepBaseDriver {
139
139
  const newValue = func(currentValue);
140
140
  const key = this._pathToKey(keys);
141
141
  this._expandParentObjects(keys);
142
- this.setStmt.run(key, JSON.stringify(newValue), this._consumeSeq());
142
+ this._replaceRow(key, JSON.stringify(newValue));
143
143
  return keys;
144
144
  });
145
145
 
@@ -220,6 +220,11 @@ export class SqliteDriver extends DeepBaseDriver {
220
220
  return keys;
221
221
  }
222
222
 
223
+ _replaceRow(key, jsonValue) {
224
+ this.delChildrenStmt.run(this._likePrefix(key));
225
+ this.setStmt.run(key, jsonValue, this._consumeSeq());
226
+ }
227
+
223
228
  async del(...keys) {
224
229
  if (keys.length === 0) {
225
230
  this.db.exec('DELETE FROM deepbase');
@@ -347,12 +352,24 @@ export class SqliteDriver extends DeepBaseDriver {
347
352
  if (path.length === 0) return;
348
353
 
349
354
  if (path.length === 1) {
350
- obj[path[0]] = value;
355
+ const key = path[0];
356
+ const existing = obj[key];
357
+ if (
358
+ value === null &&
359
+ existing !== null &&
360
+ typeof existing === 'object' &&
361
+ !Array.isArray(existing) &&
362
+ Object.keys(existing).length > 0
363
+ ) {
364
+ return;
365
+ }
366
+ obj[key] = value;
351
367
  return;
352
368
  }
353
369
 
354
370
  const key = path[0];
355
- if (!obj.hasOwnProperty(key) || typeof obj[key] !== 'object') {
371
+ const current = obj[key];
372
+ if (!obj.hasOwnProperty(key) || current === null || typeof current !== 'object' || Array.isArray(current)) {
356
373
  obj[key] = {};
357
374
  }
358
375
 
package/test/test.js CHANGED
@@ -394,6 +394,37 @@ for (const pragma of PRAGMA_MODES) {
394
394
  assert.deepStrictEqual(await db.get(), { new: 'data' });
395
395
  assert.strictEqual(await db.get('old'), null);
396
396
  });
397
+
398
+ it('should read root when a null parent row coexists with child rows', async function () {
399
+ const itemPath = await db.add('user1', 'message', 'pending', { test: 1 });
400
+ const itemId = itemPath[itemPath.length - 1];
401
+ const driver = db.getDriver(0);
402
+ driver.db.prepare('INSERT OR REPLACE INTO deepbase (key, value, seq) VALUES (?, ?, ?)').run(
403
+ 'user1.message.pending',
404
+ 'null',
405
+ 999,
406
+ );
407
+
408
+ const pending = {
409
+ [itemId]: { test: 1 },
410
+ };
411
+ const message = {
412
+ pending,
413
+ };
414
+ const user = {
415
+ message,
416
+ };
417
+
418
+ assert.deepStrictEqual(await db.get(), {
419
+ user1: {
420
+ message,
421
+ },
422
+ });
423
+ assert.deepStrictEqual(await db.get('user1'), user);
424
+ assert.deepStrictEqual(await db.get('user1', 'message'), message);
425
+ assert.deepStrictEqual(await db.get('user1', 'message', 'pending'), pending);
426
+ assert.deepStrictEqual(await db.keys('user1', 'message', 'pending'), [itemId]);
427
+ });
397
428
  });
398
429
 
399
430
  describe('Deep Nesting', function () {
@@ -429,6 +460,32 @@ for (const pragma of PRAGMA_MODES) {
429
460
  assert.deepStrictEqual(await db.get('settings'), { a: 1, b: 99, c: 3, d: 4 });
430
461
  });
431
462
 
463
+ it('should replace stale child keys when setting a parent object', async function () {
464
+ await db.set('profile', 'chinchon:MZM3Z', 'remoteData', 'denounces', 1000);
465
+ await db.set('profile', 'chinchon:MZM3Z', {
466
+ game: 'chinchon',
467
+ remoteData: {
468
+ hid: 'MZM3Z',
469
+ denounces: 0,
470
+ },
471
+ });
472
+
473
+ const profile = await db.get('profile', 'chinchon:MZM3Z');
474
+ assert.strictEqual(profile.remoteData.denounces, 0);
475
+ assert.strictEqual(await db.get('profile', 'chinchon:MZM3Z', 'remoteData', 'denounces'), 0);
476
+ });
477
+
478
+ it('should keep sibling keys with similar prefixes when replacing a parent object', async function () {
479
+ await db.set('a', 'b', 'c', 1);
480
+ await db.set('a', 'bc', 'c', 2);
481
+ await db.set('a', 'b', { c: 0 });
482
+
483
+ assert.deepStrictEqual(await db.get('a'), {
484
+ b: { c: 0 },
485
+ bc: { c: 2 },
486
+ });
487
+ });
488
+
432
489
  it('should handle nested object then deeper nesting', async function () {
433
490
  await db.set('user', { name: 'Alice', meta: { role: 'admin' } });
434
491
  await db.set('user', 'meta', 'role', 'user');