tinybase 4.0.0-beta.5.2 → 4.0.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.
Files changed (138) hide show
  1. package/lib/cjs/persisters/persister-automerge.cjs +1 -1
  2. package/lib/cjs/persisters/persister-automerge.cjs.gz +0 -0
  3. package/lib/cjs/persisters/persister-browser.cjs +1 -1
  4. package/lib/cjs/persisters/persister-browser.cjs.gz +0 -0
  5. package/lib/cjs/persisters/persister-cr-sqlite-wasm.cjs +1 -1
  6. package/lib/cjs/persisters/persister-cr-sqlite-wasm.cjs.gz +0 -0
  7. package/lib/cjs/persisters/persister-file.cjs +1 -1
  8. package/lib/cjs/persisters/persister-file.cjs.gz +0 -0
  9. package/lib/cjs/persisters/persister-remote.cjs +1 -1
  10. package/lib/cjs/persisters/persister-remote.cjs.gz +0 -0
  11. package/lib/cjs/persisters/persister-sqlite-wasm.cjs +1 -1
  12. package/lib/cjs/persisters/persister-sqlite-wasm.cjs.gz +0 -0
  13. package/lib/cjs/persisters/persister-sqlite3.cjs +1 -1
  14. package/lib/cjs/persisters/persister-sqlite3.cjs.gz +0 -0
  15. package/lib/cjs/persisters/persister-yjs.cjs +1 -1
  16. package/lib/cjs/persisters/persister-yjs.cjs.gz +0 -0
  17. package/lib/cjs/persisters.cjs +1 -1
  18. package/lib/cjs/persisters.cjs.gz +0 -0
  19. package/lib/cjs/tinybase.cjs +1 -1
  20. package/lib/cjs/tinybase.cjs.gz +0 -0
  21. package/lib/cjs-es6/persisters/persister-automerge.cjs +1 -1
  22. package/lib/cjs-es6/persisters/persister-automerge.cjs.gz +0 -0
  23. package/lib/cjs-es6/persisters/persister-browser.cjs +1 -1
  24. package/lib/cjs-es6/persisters/persister-browser.cjs.gz +0 -0
  25. package/lib/cjs-es6/persisters/persister-cr-sqlite-wasm.cjs +1 -1
  26. package/lib/cjs-es6/persisters/persister-cr-sqlite-wasm.cjs.gz +0 -0
  27. package/lib/cjs-es6/persisters/persister-file.cjs +1 -1
  28. package/lib/cjs-es6/persisters/persister-file.cjs.gz +0 -0
  29. package/lib/cjs-es6/persisters/persister-remote.cjs +1 -1
  30. package/lib/cjs-es6/persisters/persister-remote.cjs.gz +0 -0
  31. package/lib/cjs-es6/persisters/persister-sqlite-wasm.cjs +1 -1
  32. package/lib/cjs-es6/persisters/persister-sqlite-wasm.cjs.gz +0 -0
  33. package/lib/cjs-es6/persisters/persister-sqlite3.cjs +1 -1
  34. package/lib/cjs-es6/persisters/persister-sqlite3.cjs.gz +0 -0
  35. package/lib/cjs-es6/persisters/persister-yjs.cjs +1 -1
  36. package/lib/cjs-es6/persisters/persister-yjs.cjs.gz +0 -0
  37. package/lib/cjs-es6/persisters.cjs +1 -1
  38. package/lib/cjs-es6/persisters.cjs.gz +0 -0
  39. package/lib/cjs-es6/tinybase.cjs +1 -1
  40. package/lib/cjs-es6/tinybase.cjs.gz +0 -0
  41. package/lib/debug/persisters/persister-automerge.js +22 -20
  42. package/lib/debug/persisters/persister-browser.js +28 -20
  43. package/lib/debug/persisters/persister-cr-sqlite-wasm.js +199 -150
  44. package/lib/debug/persisters/persister-file.js +28 -20
  45. package/lib/debug/persisters/persister-remote.js +28 -20
  46. package/lib/debug/persisters/persister-sqlite-wasm.js +204 -150
  47. package/lib/debug/persisters/persister-sqlite3.js +199 -150
  48. package/lib/debug/persisters/persister-yjs.js +28 -20
  49. package/lib/debug/persisters.js +29 -20
  50. package/lib/debug/tinybase.js +22 -20
  51. package/lib/es6/persisters/persister-automerge.js +1 -1
  52. package/lib/es6/persisters/persister-automerge.js.gz +0 -0
  53. package/lib/es6/persisters/persister-browser.js +1 -1
  54. package/lib/es6/persisters/persister-browser.js.gz +0 -0
  55. package/lib/es6/persisters/persister-cr-sqlite-wasm.js +1 -1
  56. package/lib/es6/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  57. package/lib/es6/persisters/persister-file.js +1 -1
  58. package/lib/es6/persisters/persister-file.js.gz +0 -0
  59. package/lib/es6/persisters/persister-remote.js +1 -1
  60. package/lib/es6/persisters/persister-remote.js.gz +0 -0
  61. package/lib/es6/persisters/persister-sqlite-wasm.js +1 -1
  62. package/lib/es6/persisters/persister-sqlite-wasm.js.gz +0 -0
  63. package/lib/es6/persisters/persister-sqlite3.js +1 -1
  64. package/lib/es6/persisters/persister-sqlite3.js.gz +0 -0
  65. package/lib/es6/persisters/persister-yjs.js +1 -1
  66. package/lib/es6/persisters/persister-yjs.js.gz +0 -0
  67. package/lib/es6/persisters.js +1 -1
  68. package/lib/es6/persisters.js.gz +0 -0
  69. package/lib/es6/tinybase.js +1 -1
  70. package/lib/es6/tinybase.js.gz +0 -0
  71. package/lib/persisters/persister-automerge.js +1 -1
  72. package/lib/persisters/persister-automerge.js.gz +0 -0
  73. package/lib/persisters/persister-browser.js +1 -1
  74. package/lib/persisters/persister-browser.js.gz +0 -0
  75. package/lib/persisters/persister-cr-sqlite-wasm.js +1 -1
  76. package/lib/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  77. package/lib/persisters/persister-file.js +1 -1
  78. package/lib/persisters/persister-file.js.gz +0 -0
  79. package/lib/persisters/persister-remote.js +1 -1
  80. package/lib/persisters/persister-remote.js.gz +0 -0
  81. package/lib/persisters/persister-sqlite-wasm.js +1 -1
  82. package/lib/persisters/persister-sqlite-wasm.js.gz +0 -0
  83. package/lib/persisters/persister-sqlite3.js +1 -1
  84. package/lib/persisters/persister-sqlite3.js.gz +0 -0
  85. package/lib/persisters/persister-yjs.js +1 -1
  86. package/lib/persisters/persister-yjs.js.gz +0 -0
  87. package/lib/persisters.js +1 -1
  88. package/lib/persisters.js.gz +0 -0
  89. package/lib/tinybase.js +1 -1
  90. package/lib/tinybase.js.gz +0 -0
  91. package/lib/types/persisters/persister-cr-sqlite-wasm.d.ts +2 -0
  92. package/lib/types/persisters/persister-sqlite-wasm.d.ts +2 -0
  93. package/lib/types/persisters/persister-sqlite3.d.ts +2 -0
  94. package/lib/types/with-schemas/persisters/persister-cr-sqlite-wasm.d.ts +2 -0
  95. package/lib/types/with-schemas/persisters/persister-sqlite-wasm.d.ts +2 -0
  96. package/lib/types/with-schemas/persisters/persister-sqlite3.d.ts +2 -0
  97. package/lib/umd/persisters/persister-automerge.js +1 -1
  98. package/lib/umd/persisters/persister-automerge.js.gz +0 -0
  99. package/lib/umd/persisters/persister-browser.js +1 -1
  100. package/lib/umd/persisters/persister-browser.js.gz +0 -0
  101. package/lib/umd/persisters/persister-cr-sqlite-wasm.js +1 -1
  102. package/lib/umd/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  103. package/lib/umd/persisters/persister-file.js +1 -1
  104. package/lib/umd/persisters/persister-file.js.gz +0 -0
  105. package/lib/umd/persisters/persister-remote.js +1 -1
  106. package/lib/umd/persisters/persister-remote.js.gz +0 -0
  107. package/lib/umd/persisters/persister-sqlite-wasm.js +1 -1
  108. package/lib/umd/persisters/persister-sqlite-wasm.js.gz +0 -0
  109. package/lib/umd/persisters/persister-sqlite3.js +1 -1
  110. package/lib/umd/persisters/persister-sqlite3.js.gz +0 -0
  111. package/lib/umd/persisters/persister-yjs.js +1 -1
  112. package/lib/umd/persisters/persister-yjs.js.gz +0 -0
  113. package/lib/umd/persisters.js +1 -1
  114. package/lib/umd/persisters.js.gz +0 -0
  115. package/lib/umd/tinybase.js +1 -1
  116. package/lib/umd/tinybase.js.gz +0 -0
  117. package/lib/umd-es6/persisters/persister-automerge.js +1 -1
  118. package/lib/umd-es6/persisters/persister-automerge.js.gz +0 -0
  119. package/lib/umd-es6/persisters/persister-browser.js +1 -1
  120. package/lib/umd-es6/persisters/persister-browser.js.gz +0 -0
  121. package/lib/umd-es6/persisters/persister-cr-sqlite-wasm.js +1 -1
  122. package/lib/umd-es6/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  123. package/lib/umd-es6/persisters/persister-file.js +1 -1
  124. package/lib/umd-es6/persisters/persister-file.js.gz +0 -0
  125. package/lib/umd-es6/persisters/persister-remote.js +1 -1
  126. package/lib/umd-es6/persisters/persister-remote.js.gz +0 -0
  127. package/lib/umd-es6/persisters/persister-sqlite-wasm.js +1 -1
  128. package/lib/umd-es6/persisters/persister-sqlite-wasm.js.gz +0 -0
  129. package/lib/umd-es6/persisters/persister-sqlite3.js +1 -1
  130. package/lib/umd-es6/persisters/persister-sqlite3.js.gz +0 -0
  131. package/lib/umd-es6/persisters/persister-yjs.js +1 -1
  132. package/lib/umd-es6/persisters/persister-yjs.js.gz +0 -0
  133. package/lib/umd-es6/persisters.js +1 -1
  134. package/lib/umd-es6/persisters.js.gz +0 -0
  135. package/lib/umd-es6/tinybase.js +1 -1
  136. package/lib/umd-es6/tinybase.js.gz +0 -0
  137. package/package.json +16 -16
  138. package/readme.md +14 -14
@@ -39,6 +39,11 @@ const isArray = (thing) => Array.isArray(thing);
39
39
  const promiseNew = (resolver) => new promise(resolver);
40
40
  const promiseAll = async (promises) => promise.all(promises);
41
41
 
42
+ const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
43
+ const collValues = (coll) => [...(coll?.values() ?? [])];
44
+ const collForEach = (coll, cb) => coll?.forEach(cb);
45
+ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
46
+
42
47
  const object = Object;
43
48
  const objIds = object.keys;
44
49
  const objFreeze = object.freeze;
@@ -58,11 +63,6 @@ const objValues = (obj) => object.values(obj);
58
63
  const objSize = (obj) => arrayLength(objIds(obj));
59
64
  const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
60
65
 
61
- const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
62
- const collValues = (coll) => [...(coll?.values() ?? [])];
63
- const collForEach = (coll, cb) => coll?.forEach(cb);
64
- const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
65
-
66
66
  const mapNew = (entries) => new Map(entries);
67
67
  const mapKeys = (map) => [...(map?.keys() ?? [])];
68
68
  const mapGet = (map, key) => map?.get(key);
@@ -99,9 +99,7 @@ const setAdd = (set, value) => set?.add(value);
99
99
  const SELECT_STAR_FROM = 'SELECT*FROM';
100
100
  const FROM_PRAGMA_TABLE = 'FROM pragma_table_';
101
101
  const WHERE = 'WHERE';
102
- const WHERE_MAIN_TABLE =
103
- WHERE + ` schema='main'AND type='table'AND name!='sqlite_schema'`;
104
- const getCommandFunctions = (cmd) => {
102
+ const getCommandFunctions = (cmd, managedTableNames) => {
105
103
  const schemaMap = mapNew();
106
104
  const canSelect = (tableName, rowIdColumnName) =>
107
105
  !isUndefined(mapGet(mapGet(schemaMap, tableName), rowIdColumnName));
@@ -112,7 +110,12 @@ const getCommandFunctions = (cmd) => {
112
110
  await promiseAll(
113
111
  arrayMap(
114
112
  await cmd(
115
- 'SELECT name ' + FROM_PRAGMA_TABLE + 'list ' + WHERE_MAIN_TABLE,
113
+ 'SELECT name ' +
114
+ FROM_PRAGMA_TABLE +
115
+ `list WHERE schema='main'AND type='table'AND name IN(` +
116
+ getPlaceholders(managedTableNames) +
117
+ `)`,
118
+ managedTableNames,
116
119
  ),
117
120
  async ({name: tableName}) => [
118
121
  tableName,
@@ -246,15 +249,19 @@ const getCommandFunctions = (cmd) => {
246
249
  const insertSlots = [];
247
250
  const insertBinds = [];
248
251
  const deleteRowIds = [];
252
+ const allColumnNames = arrayFilter(
253
+ mapKeys(mapGet(schemaMap, tableName)),
254
+ (columnName) => columnName != rowIdColumnName,
255
+ );
249
256
  objMap(table, (row, rowId) => {
250
257
  arrayPush(
251
258
  insertSlots,
252
- `(?${strRepeat(',?', arrayLength(columnNames))})`,
259
+ `(?${strRepeat(',?', arrayLength(allColumnNames))})`,
253
260
  );
254
261
  arrayPush(
255
262
  insertBinds,
256
263
  rowId,
257
- ...arrayMap(columnNames, (cellId) => row[cellId]),
264
+ ...arrayMap(allColumnNames, (cellId) => row[cellId]),
258
265
  );
259
266
  arrayPush(deleteRowIds, rowId);
260
267
  });
@@ -264,10 +271,24 @@ const getCommandFunctions = (cmd) => {
264
271
  '(' +
265
272
  escapeId(rowIdColumnName) +
266
273
  arrayJoin(
267
- arrayMap(columnNames, (columnName) => COMMA + escapeId(columnName)),
274
+ arrayMap(
275
+ allColumnNames,
276
+ (columnName) => COMMA + escapeId(columnName),
277
+ ),
268
278
  ) +
269
279
  ')VALUES' +
270
- arrayJoin(insertSlots, COMMA),
280
+ arrayJoin(insertSlots, COMMA) +
281
+ 'ON CONFLICT(' +
282
+ escapeId(rowIdColumnName) +
283
+ ')DO UPDATE SET' +
284
+ arrayJoin(
285
+ arrayMap(
286
+ allColumnNames,
287
+ (columnName) =>
288
+ escapeId(columnName) + '=excluded.' + escapeId(columnName),
289
+ ),
290
+ COMMA,
291
+ ),
271
292
  insertBinds,
272
293
  );
273
294
  await cmd(
@@ -276,19 +297,21 @@ const getCommandFunctions = (cmd) => {
276
297
  WHERE +
277
298
  escapeId(rowIdColumnName) +
278
299
  'NOT IN(' +
279
- arrayJoin(
280
- arrayMap(deleteRowIds, () => '?'),
281
- COMMA,
282
- ) +
300
+ getPlaceholders(deleteRowIds) +
283
301
  ')',
284
302
  deleteRowIds,
285
303
  );
286
- } else {
304
+ } else if (collHas(schemaMap, tableName)) {
287
305
  await cmd('DELETE FROM' + escapeId(tableName));
288
306
  }
289
307
  };
290
308
  return [refreshSchema, loadSingleRow, saveSingleRow, loadTable, saveTable];
291
309
  };
310
+ const getPlaceholders = (array) =>
311
+ arrayJoin(
312
+ arrayMap(array, () => '?'),
313
+ COMMA,
314
+ );
292
315
 
293
316
  const createCustomPersister = (
294
317
  store,
@@ -325,27 +348,28 @@ const createCustomPersister = (
325
348
  {
326
349
  loads++;
327
350
  }
328
- await actions();
329
- loadSave = 0;
351
+ await persister.schedule(async () => {
352
+ await actions();
353
+ loadSave = 0;
354
+ });
330
355
  }
356
+ return persister;
331
357
  };
332
358
  const persister = {
333
- load: async (initialTables, initialValues) => {
359
+ load: async (initialTables, initialValues) =>
334
360
  await loadLock(async () => {
335
361
  try {
336
362
  store.setContent(await getPersisted());
337
363
  } catch {
338
364
  store.setContent([initialTables, initialValues]);
339
365
  }
340
- });
341
- return persister;
342
- },
366
+ }),
343
367
  startAutoLoad: async (initialTables = {}, initialValues = {}) => {
344
368
  persister.stopAutoLoad();
345
369
  await persister.load(initialTables, initialValues);
346
370
  listening = 1;
347
371
  listeningHandle = addPersisterListener(
348
- async (getContent, getTransactionChanges) => {
372
+ async (getContent, getTransactionChanges) =>
349
373
  await loadLock(async () => {
350
374
  if (getTransactionChanges) {
351
375
  store.setTransactionChanges(getTransactionChanges());
@@ -354,8 +378,7 @@ const createCustomPersister = (
354
378
  store.setContent(getContent?.() ?? (await getPersisted()));
355
379
  } catch {}
356
380
  }
357
- });
358
- },
381
+ }),
359
382
  );
360
383
  return persister;
361
384
  },
@@ -368,27 +391,29 @@ const createCustomPersister = (
368
391
  return persister;
369
392
  },
370
393
  save: async (getTransactionChanges) => {
371
- await persister.schedule(async () => {
372
- /* istanbul ignore else */
373
- if (loadSave != 1) {
374
- loadSave = 2;
375
- {
376
- saves++;
377
- }
394
+ /* istanbul ignore else */
395
+ if (loadSave != 1) {
396
+ loadSave = 2;
397
+ {
398
+ saves++;
399
+ }
400
+ await persister.schedule(async () => {
378
401
  try {
379
402
  await setPersisted(store.getContent, getTransactionChanges);
380
403
  } catch {}
381
404
  loadSave = 0;
382
- }
383
- });
405
+ });
406
+ }
384
407
  return persister;
385
408
  },
386
409
  startAutoSave: async () => {
387
410
  await persister.stopAutoSave().save();
388
411
  listenerId = store.addDidFinishTransactionListener(
389
412
  (_store, getTransactionChanges) => {
390
- const transactionChanges = getTransactionChanges();
391
- persister.save(() => transactionChanges);
413
+ const [tableChanges, valueChanges] = getTransactionChanges();
414
+ if (!objIsEmpty(tableChanges) || !objIsEmpty(valueChanges)) {
415
+ persister.save(() => [tableChanges, valueChanges]);
416
+ }
392
417
  },
393
418
  );
394
419
  return persister;
@@ -415,10 +440,13 @@ const createJsonSqlitePersister = (
415
440
  cmd,
416
441
  addPersisterListener,
417
442
  delPersisterListener,
418
- {storeTableName = TINYBASE},
443
+ [storeTableName],
444
+ managedTableNames,
419
445
  ) => {
420
- const [refreshSchema, loadSingleRow, saveSingleRow] =
421
- getCommandFunctions(cmd);
446
+ const [refreshSchema, loadSingleRow, saveSingleRow] = getCommandFunctions(
447
+ cmd,
448
+ managedTableNames,
449
+ );
422
450
  const getPersisted = async () => {
423
451
  await refreshSchema();
424
452
  return jsonParse(
@@ -446,97 +474,28 @@ const createJsonSqlitePersister = (
446
474
  return persister;
447
475
  };
448
476
 
449
- const ROW_ID_COLUMN_NAME = 'rowIdColumnName';
450
- const TABLE_ID = 'tableId';
451
- const TABLE_NAME = 'tableName';
452
- const DELETE_EMPTY_COLUMNS = 'deleteEmptyColumns';
453
- const DELETE_EMPTY_TABLE = 'deleteEmptyTable';
454
- const DEFAULTED_VALUES_CONFIG = {
455
- load: 0,
456
- save: 0,
457
- [TABLE_NAME]: TINYBASE + '_values',
458
- };
459
- const getDefaultedTableConfigMap = (
460
- configsObj,
461
- defaultObj,
462
- tableField,
463
- filter,
464
- ) => {
465
- const configMap = mapNew();
466
- objMap(configsObj, (configObj, id) => {
467
- const defaultedConfig = arraySlice(
468
- objValues(
469
- objMerge(
470
- defaultObj,
471
- isString(configObj) ? {[tableField]: configObj} : configObj,
472
- ),
473
- ),
474
- 0,
475
- objSize(defaultObj),
476
- );
477
- if (!isUndefined(defaultedConfig[0]) && !filter(id, defaultedConfig[0])) {
478
- mapSet(configMap, id, defaultedConfig);
479
- }
480
- });
481
- return configMap;
482
- };
483
- const getDefaultedConfig = ({
484
- tables: {load = {}, save = {}} = {},
485
- values = {},
486
- }) => {
487
- const valuesConfig = arraySlice(
488
- objValues(objMerge(DEFAULTED_VALUES_CONFIG, values)),
489
- 0,
490
- objSize(DEFAULTED_VALUES_CONFIG),
491
- );
492
- const valuesTable = valuesConfig[2];
493
- return [
494
- getDefaultedTableConfigMap(
495
- load,
496
- {
497
- [TABLE_ID]: null,
498
- [ROW_ID_COLUMN_NAME]: DEFAULT_ROW_ID_COLUMN_NAME,
499
- },
500
- TABLE_ID,
501
- (tableName) => tableName == valuesTable,
502
- ),
503
- getDefaultedTableConfigMap(
504
- save,
505
- {
506
- [TABLE_NAME]: null,
507
- [ROW_ID_COLUMN_NAME]: DEFAULT_ROW_ID_COLUMN_NAME,
508
- [DELETE_EMPTY_COLUMNS]: 0,
509
- [DELETE_EMPTY_TABLE]: 0,
510
- },
511
- TABLE_NAME,
512
- (_, tableName) => tableName == valuesTable,
513
- ),
514
- valuesConfig,
515
- ];
516
- };
517
-
518
477
  const createTabularSqlitePersister = (
519
478
  store,
520
479
  cmd,
521
480
  addPersisterListener,
522
481
  delPersisterListener,
523
- config,
524
- ) => {
525
- const [
482
+ [
526
483
  tablesLoadConfig,
527
484
  tablesSaveConfig,
528
485
  [valuesLoad, valuesSave, valuesTableName],
529
- ] = getDefaultedConfig(config);
486
+ ],
487
+ managedTableNames,
488
+ ) => {
530
489
  const [refreshSchema, loadSingleRow, saveSingleRow, loadTable, saveTable] =
531
- getCommandFunctions(cmd);
532
- const getSaveTablesActions = (tables) =>
533
- mapMap(
534
- tablesSaveConfig,
535
- (
490
+ getCommandFunctions(cmd, managedTableNames);
491
+ const saveTables = async (tables) =>
492
+ await promiseAll(
493
+ mapMap(
494
+ tablesSaveConfig,
495
+ async (
536
496
  [tableName, rowIdColumnName, deleteEmptyColumns, deleteEmptyTable],
537
497
  tableId,
538
498
  ) =>
539
- async () =>
540
499
  await saveTable(
541
500
  tableName,
542
501
  rowIdColumnName,
@@ -544,16 +503,16 @@ const createTabularSqlitePersister = (
544
503
  deleteEmptyTable,
545
504
  tables[tableId],
546
505
  ),
506
+ ),
547
507
  );
548
- const getSaveValuesAction = (values) =>
508
+ const saveValues = async (values) =>
549
509
  valuesSave
550
- ? async () =>
551
- await saveSingleRow(
552
- valuesTableName,
553
- DEFAULT_ROW_ID_COLUMN_NAME,
554
- SINGLE_ROW_ID,
555
- values,
556
- )
510
+ ? await saveSingleRow(
511
+ valuesTableName,
512
+ DEFAULT_ROW_ID_COLUMN_NAME,
513
+ SINGLE_ROW_ID,
514
+ values,
515
+ )
557
516
  : null;
558
517
  const loadTables = async () =>
559
518
  objNew(
@@ -584,11 +543,9 @@ const createTabularSqlitePersister = (
584
543
  };
585
544
  const setPersisted = async (getContent) => {
586
545
  const [tables, values] = getContent();
587
- persister.schedule(
588
- refreshSchema,
589
- ...getSaveTablesActions(tables),
590
- getSaveValuesAction(values),
591
- );
546
+ await refreshSchema();
547
+ await saveTables(tables);
548
+ await saveValues(values);
592
549
  };
593
550
  const persister = createCustomPersister(
594
551
  store,
@@ -602,10 +559,97 @@ const createTabularSqlitePersister = (
602
559
 
603
560
  const JSON$1 = 'json';
604
561
  const AUTO_LOAD_INTERVAL_SECONDS = 'autoLoadIntervalSeconds';
562
+ const STORE_TABLE_NAME = 'storeTableName';
563
+ const ROW_ID_COLUMN_NAME = 'rowIdColumnName';
564
+ const TABLE_ID = 'tableId';
565
+ const TABLE_NAME = 'tableName';
566
+ const DELETE_EMPTY_COLUMNS = 'deleteEmptyColumns';
567
+ const DELETE_EMPTY_TABLE = 'deleteEmptyTable';
605
568
  const DEFAULT_CONFIG = {
606
569
  mode: JSON$1,
607
570
  [AUTO_LOAD_INTERVAL_SECONDS]: 1,
608
571
  };
572
+ const DEFAULT_TABULAR_VALUES_CONFIG = {
573
+ load: 0,
574
+ save: 0,
575
+ [TABLE_NAME]: TINYBASE + '_values',
576
+ };
577
+ const getDefaultedConfig = (configOrStoreTableName) =>
578
+ objMerge(
579
+ DEFAULT_CONFIG,
580
+ isString(configOrStoreTableName)
581
+ ? {[STORE_TABLE_NAME]: configOrStoreTableName}
582
+ : configOrStoreTableName ?? {},
583
+ );
584
+ const getDefaultedTabularConfigMap = (
585
+ configsObj,
586
+ defaultObj,
587
+ tableField,
588
+ filter,
589
+ ) => {
590
+ const configMap = mapNew();
591
+ objMap(configsObj, (configObj, id) => {
592
+ const defaultedConfig = arraySlice(
593
+ objValues(
594
+ objMerge(
595
+ defaultObj,
596
+ isString(configObj) ? {[tableField]: configObj} : configObj,
597
+ ),
598
+ ),
599
+ 0,
600
+ objSize(defaultObj),
601
+ );
602
+ if (!isUndefined(defaultedConfig[0]) && !filter(id, defaultedConfig[0])) {
603
+ mapSet(configMap, id, defaultedConfig);
604
+ }
605
+ });
606
+ return configMap;
607
+ };
608
+ const getConfigStructures = (configOrStoreTableName) => {
609
+ const config = getDefaultedConfig(configOrStoreTableName);
610
+ const autoLoadIntervalSeconds = config[AUTO_LOAD_INTERVAL_SECONDS];
611
+ if (config.mode == JSON$1) {
612
+ const {storeTableName = TINYBASE} = config;
613
+ return [
614
+ 1,
615
+ autoLoadIntervalSeconds,
616
+ [storeTableName],
617
+ setNew(storeTableName),
618
+ ];
619
+ }
620
+ const {tables: {load = {}, save = {}} = {}, values = {}} = config;
621
+ const valuesConfig = arraySlice(
622
+ objValues(objMerge(DEFAULT_TABULAR_VALUES_CONFIG, values)),
623
+ 0,
624
+ objSize(DEFAULT_TABULAR_VALUES_CONFIG),
625
+ );
626
+ const valuesTable = valuesConfig[2];
627
+ const managedTableNames = setNew(valuesTable);
628
+ const tabularConfig = [
629
+ getDefaultedTabularConfigMap(
630
+ load,
631
+ {[TABLE_ID]: null, [ROW_ID_COLUMN_NAME]: DEFAULT_ROW_ID_COLUMN_NAME},
632
+ TABLE_ID,
633
+ (tableName) =>
634
+ setAdd(managedTableNames, tableName) && tableName == valuesTable,
635
+ ),
636
+ getDefaultedTabularConfigMap(
637
+ save,
638
+ {
639
+ [TABLE_NAME]: null,
640
+ [ROW_ID_COLUMN_NAME]: DEFAULT_ROW_ID_COLUMN_NAME,
641
+ [DELETE_EMPTY_COLUMNS]: 0,
642
+ [DELETE_EMPTY_TABLE]: 0,
643
+ },
644
+ TABLE_NAME,
645
+ (_, tableName) =>
646
+ setAdd(managedTableNames, tableName) && tableName == valuesTable,
647
+ ),
648
+ valuesConfig,
649
+ ];
650
+ return [0, autoLoadIntervalSeconds, tabularConfig, managedTableNames];
651
+ };
652
+
609
653
  const PRAGMA = 'pragma ';
610
654
  const DATA_VERSION = 'data_version';
611
655
  const SCHEMA_VERSION = 'schema_version';
@@ -613,17 +657,17 @@ const createSqlitePersister = (
613
657
  store,
614
658
  configOrStoreTableName,
615
659
  cmd,
616
- addPersisterLocalListener,
617
- delPersisterLocalListener,
660
+ addUpdateListener,
661
+ delUpdateListener,
618
662
  ) => {
619
- const config = objMerge(
620
- DEFAULT_CONFIG,
621
- isString(configOrStoreTableName)
622
- ? {storeTableName: configOrStoreTableName}
623
- : configOrStoreTableName ?? {},
624
- );
625
663
  let dataVersion;
626
664
  let schemaVersion;
665
+ const [
666
+ isJson,
667
+ autoLoadIntervalSeconds,
668
+ defaultedConfig,
669
+ managedTableNamesSet,
670
+ ] = getConfigStructures(configOrStoreTableName);
627
671
  const addPersisterListener = (listener) => [
628
672
  setInterval(async () => {
629
673
  try {
@@ -642,19 +686,24 @@ const createSqlitePersister = (
642
686
  schemaVersion = newSchemaVersion;
643
687
  }
644
688
  } catch {}
645
- }, config[AUTO_LOAD_INTERVAL_SECONDS] * 1e3),
646
- addPersisterLocalListener(listener),
689
+ }, autoLoadIntervalSeconds * 1e3),
690
+ addUpdateListener((tableName) =>
691
+ managedTableNamesSet.has(tableName) ? listener() : 0,
692
+ ),
647
693
  ];
648
694
  const delPersisterListener = ([interval, listeningHandle]) => {
649
695
  clearInterval(interval);
650
696
  dataVersion = schemaVersion = null;
651
- delPersisterLocalListener(listeningHandle);
697
+ delUpdateListener(listeningHandle);
652
698
  };
653
- return (
654
- config.mode == JSON$1
655
- ? createJsonSqlitePersister
656
- : createTabularSqlitePersister
657
- )(store, cmd, addPersisterListener, delPersisterListener, config);
699
+ return (isJson ? createJsonSqlitePersister : createTabularSqlitePersister)(
700
+ store,
701
+ cmd,
702
+ addPersisterListener,
703
+ delPersisterListener,
704
+ defaultedConfig,
705
+ collValues(managedTableNamesSet),
706
+ );
658
707
  };
659
708
 
660
709
  const CHANGE = 'change';
@@ -669,7 +718,7 @@ const createSqlite3Persister = (store, db, configOrStoreTableName) =>
669
718
  ),
670
719
  ),
671
720
  (listener) => {
672
- const observer = () => listener();
721
+ const observer = (_, _2, tableName) => listener(tableName);
673
722
  db.on(CHANGE, observer);
674
723
  return observer;
675
724
  },
@@ -9,17 +9,23 @@ const arrayIsEmpty = (array) => arrayLength(array) == 0;
9
9
  const arrayPush = (array, ...values) => array.push(...values);
10
10
  const arrayShift = (array) => array.shift();
11
11
 
12
+ const isInstanceOf = (thing, cls) => thing instanceof cls;
12
13
  const isUndefined = (thing) => thing == void 0;
13
14
  const ifNotUndefined = (value, then, otherwise) =>
14
15
  isUndefined(value) ? otherwise?.() : then(value);
15
16
 
16
17
  const object = Object;
18
+ const objIds = object.keys;
17
19
  const objFreeze = object.freeze;
20
+ const isObject = (obj) =>
21
+ isInstanceOf(obj, object) && obj.constructor == object;
18
22
  const objNew = (entries = []) => object.fromEntries(entries);
19
23
  const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
20
24
  const objHas = (obj, id) => !isUndefined(objGet(obj, id));
21
25
  const objMap = (obj, cb) =>
22
26
  arrayMap(object.entries(obj), ([id, value]) => cb(value, id));
27
+ const objSize = (obj) => arrayLength(objIds(obj));
28
+ const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
23
29
  const objEnsure = (obj, id, getDefaultValue) => {
24
30
  if (!objHas(obj, id)) {
25
31
  obj[id] = getDefaultValue();
@@ -62,27 +68,28 @@ const createCustomPersister = (
62
68
  {
63
69
  loads++;
64
70
  }
65
- await actions();
66
- loadSave = 0;
71
+ await persister.schedule(async () => {
72
+ await actions();
73
+ loadSave = 0;
74
+ });
67
75
  }
76
+ return persister;
68
77
  };
69
78
  const persister = {
70
- load: async (initialTables, initialValues) => {
79
+ load: async (initialTables, initialValues) =>
71
80
  await loadLock(async () => {
72
81
  try {
73
82
  store.setContent(await getPersisted());
74
83
  } catch {
75
84
  store.setContent([initialTables, initialValues]);
76
85
  }
77
- });
78
- return persister;
79
- },
86
+ }),
80
87
  startAutoLoad: async (initialTables = {}, initialValues = {}) => {
81
88
  persister.stopAutoLoad();
82
89
  await persister.load(initialTables, initialValues);
83
90
  listening = 1;
84
91
  listeningHandle = addPersisterListener(
85
- async (getContent, getTransactionChanges) => {
92
+ async (getContent, getTransactionChanges) =>
86
93
  await loadLock(async () => {
87
94
  if (getTransactionChanges) {
88
95
  store.setTransactionChanges(getTransactionChanges());
@@ -91,8 +98,7 @@ const createCustomPersister = (
91
98
  store.setContent(getContent?.() ?? (await getPersisted()));
92
99
  } catch {}
93
100
  }
94
- });
95
- },
101
+ }),
96
102
  );
97
103
  return persister;
98
104
  },
@@ -105,27 +111,29 @@ const createCustomPersister = (
105
111
  return persister;
106
112
  },
107
113
  save: async (getTransactionChanges) => {
108
- await persister.schedule(async () => {
109
- /* istanbul ignore else */
110
- if (loadSave != 1) {
111
- loadSave = 2;
112
- {
113
- saves++;
114
- }
114
+ /* istanbul ignore else */
115
+ if (loadSave != 1) {
116
+ loadSave = 2;
117
+ {
118
+ saves++;
119
+ }
120
+ await persister.schedule(async () => {
115
121
  try {
116
122
  await setPersisted(store.getContent, getTransactionChanges);
117
123
  } catch {}
118
124
  loadSave = 0;
119
- }
120
- });
125
+ });
126
+ }
121
127
  return persister;
122
128
  },
123
129
  startAutoSave: async () => {
124
130
  await persister.stopAutoSave().save();
125
131
  listenerId = store.addDidFinishTransactionListener(
126
132
  (_store, getTransactionChanges) => {
127
- const transactionChanges = getTransactionChanges();
128
- persister.save(() => transactionChanges);
133
+ const [tableChanges, valueChanges] = getTransactionChanges();
134
+ if (!objIsEmpty(tableChanges) || !objIsEmpty(valueChanges)) {
135
+ persister.save(() => [tableChanges, valueChanges]);
136
+ }
129
137
  },
130
138
  );
131
139
  return persister;