tinybase 4.0.1 → 4.0.3

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 (58) hide show
  1. package/lib/cjs/persisters/persister-cr-sqlite-wasm.cjs +1 -1
  2. package/lib/cjs/persisters/persister-cr-sqlite-wasm.cjs.gz +0 -0
  3. package/lib/cjs/persisters/persister-expo-sqlite.cjs +1 -0
  4. package/lib/cjs/persisters/persister-expo-sqlite.cjs.gz +0 -0
  5. package/lib/cjs/persisters/persister-sqlite-wasm.cjs +1 -1
  6. package/lib/cjs/persisters/persister-sqlite-wasm.cjs.gz +0 -0
  7. package/lib/cjs/persisters/persister-sqlite3.cjs +1 -1
  8. package/lib/cjs/persisters/persister-sqlite3.cjs.gz +0 -0
  9. package/lib/cjs-es6/persisters/persister-cr-sqlite-wasm.cjs +1 -1
  10. package/lib/cjs-es6/persisters/persister-cr-sqlite-wasm.cjs.gz +0 -0
  11. package/lib/cjs-es6/persisters/persister-expo-sqlite.cjs +1 -0
  12. package/lib/cjs-es6/persisters/persister-expo-sqlite.cjs.gz +0 -0
  13. package/lib/cjs-es6/persisters/persister-sqlite-wasm.cjs +1 -1
  14. package/lib/cjs-es6/persisters/persister-sqlite-wasm.cjs.gz +0 -0
  15. package/lib/cjs-es6/persisters/persister-sqlite3.cjs +1 -1
  16. package/lib/cjs-es6/persisters/persister-sqlite3.cjs.gz +0 -0
  17. package/lib/debug/persisters/persister-cr-sqlite-wasm.js +177 -117
  18. package/lib/debug/persisters/persister-expo-sqlite.js +764 -0
  19. package/lib/debug/persisters/persister-sqlite-wasm.js +172 -116
  20. package/lib/debug/persisters/persister-sqlite3.js +174 -119
  21. package/lib/es6/persisters/persister-cr-sqlite-wasm.js +1 -1
  22. package/lib/es6/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  23. package/lib/es6/persisters/persister-expo-sqlite.js +1 -0
  24. package/lib/es6/persisters/persister-expo-sqlite.js.gz +0 -0
  25. package/lib/es6/persisters/persister-sqlite-wasm.js +1 -1
  26. package/lib/es6/persisters/persister-sqlite-wasm.js.gz +0 -0
  27. package/lib/es6/persisters/persister-sqlite3.js +1 -1
  28. package/lib/es6/persisters/persister-sqlite3.js.gz +0 -0
  29. package/lib/persisters/persister-cr-sqlite-wasm.js +1 -1
  30. package/lib/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  31. package/lib/persisters/persister-expo-sqlite.js +1 -0
  32. package/lib/persisters/persister-expo-sqlite.js.gz +0 -0
  33. package/lib/persisters/persister-sqlite-wasm.js +1 -1
  34. package/lib/persisters/persister-sqlite-wasm.js.gz +0 -0
  35. package/lib/persisters/persister-sqlite3.js +1 -1
  36. package/lib/persisters/persister-sqlite3.js.gz +0 -0
  37. package/lib/types/persisters/persister-expo-sqlite.d.ts +118 -0
  38. package/lib/types/persisters.d.ts +7 -0
  39. package/lib/types/with-schemas/persisters/persister-expo-sqlite.d.ts +128 -0
  40. package/lib/types/with-schemas/persisters.d.ts +7 -0
  41. package/lib/umd/persisters/persister-cr-sqlite-wasm.js +1 -1
  42. package/lib/umd/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  43. package/lib/umd/persisters/persister-expo-sqlite.js +1 -0
  44. package/lib/umd/persisters/persister-expo-sqlite.js.gz +0 -0
  45. package/lib/umd/persisters/persister-sqlite-wasm.js +1 -1
  46. package/lib/umd/persisters/persister-sqlite-wasm.js.gz +0 -0
  47. package/lib/umd/persisters/persister-sqlite3.js +1 -1
  48. package/lib/umd/persisters/persister-sqlite3.js.gz +0 -0
  49. package/lib/umd-es6/persisters/persister-cr-sqlite-wasm.js +1 -1
  50. package/lib/umd-es6/persisters/persister-cr-sqlite-wasm.js.gz +0 -0
  51. package/lib/umd-es6/persisters/persister-expo-sqlite.js +1 -0
  52. package/lib/umd-es6/persisters/persister-expo-sqlite.js.gz +0 -0
  53. package/lib/umd-es6/persisters/persister-sqlite-wasm.js +1 -1
  54. package/lib/umd-es6/persisters/persister-sqlite-wasm.js.gz +0 -0
  55. package/lib/umd-es6/persisters/persister-sqlite3.js +1 -1
  56. package/lib/umd-es6/persisters/persister-sqlite3.js.gz +0 -0
  57. package/package.json +20 -19
  58. package/readme.md +1 -1
@@ -68,10 +68,6 @@ const mapMatch = (map, obj, set, del = mapSet) => {
68
68
  return map;
69
69
  };
70
70
 
71
- const SINGLE_ROW_ID = '_';
72
- const DEFAULT_ROW_ID_COLUMN_NAME = '_id';
73
- const escapeId = (str) => `"${str.replace(/"/g, '""')}"`;
74
-
75
71
  const setNew = (entryOrEntries) =>
76
72
  new Set(
77
73
  isArray(entryOrEntries) || isUndefined(entryOrEntries)
@@ -80,6 +76,10 @@ const setNew = (entryOrEntries) =>
80
76
  );
81
77
  const setAdd = (set, value) => set?.add(value);
82
78
 
79
+ const SINGLE_ROW_ID = '_';
80
+ const DEFAULT_ROW_ID_COLUMN_NAME = '_id';
81
+ const escapeId = (str) => `"${str.replace(/"/g, '""')}"`;
82
+
83
83
  const SELECT_STAR_FROM = 'SELECT*FROM';
84
84
  const FROM_PRAGMA_TABLE = 'FROM pragma_table_';
85
85
  const WHERE = 'WHERE';
@@ -133,21 +133,6 @@ const getCommandFunctions = (cmd, managedTableNames) => {
133
133
  ),
134
134
  (_, name) => mapSet(schemaMap, name),
135
135
  );
136
- const loadSingleRow = async (tableName, rowIdColumnName) => {
137
- const rows = canSelect(tableName, rowIdColumnName)
138
- ? await cmd(
139
- SELECT_STAR_FROM +
140
- escapeId(tableName) +
141
- WHERE +
142
- escapeId(rowIdColumnName) +
143
- '=?',
144
- [SINGLE_ROW_ID],
145
- )
146
- : [];
147
- return arrayIsEmpty(rows) ? null : objDel(rows[0], rowIdColumnName);
148
- };
149
- const saveSingleRow = async (tableName, rowIdColumnName, rowId, row) =>
150
- await saveTable(tableName, rowIdColumnName, true, true, {[rowId]: row});
151
136
  const loadTable = async (tableName, rowIdColumnName) =>
152
137
  canSelect(tableName, rowIdColumnName)
153
138
  ? objNew(
@@ -166,30 +151,32 @@ const getCommandFunctions = (cmd, managedTableNames) => {
166
151
  const saveTable = async (
167
152
  tableName,
168
153
  rowIdColumnName,
154
+ table,
169
155
  deleteEmptyColumns,
170
156
  deleteEmptyTable,
171
- table,
157
+ partial = false,
172
158
  ) => {
173
- const cellIds = setNew();
159
+ const tableCellIds = setNew();
174
160
  objMap(table ?? {}, (row) =>
175
- arrayMap(objIds(row), (cellId) => setAdd(cellIds, cellId)),
161
+ arrayMap(objIds(row ?? {}), (cellId) => setAdd(tableCellIds, cellId)),
176
162
  );
177
- const columnNames = collValues(cellIds);
163
+ const tableColumnNames = collValues(tableCellIds);
178
164
  if (
179
- arrayIsEmpty(columnNames) &&
180
- collHas(schemaMap, tableName) &&
181
- deleteEmptyTable
165
+ !partial &&
166
+ deleteEmptyTable &&
167
+ arrayIsEmpty(tableColumnNames) &&
168
+ collHas(schemaMap, tableName)
182
169
  ) {
183
170
  await cmd('DROP TABLE' + escapeId(tableName));
184
171
  mapSet(schemaMap, tableName);
185
172
  return;
186
173
  }
187
- if (!arrayIsEmpty(columnNames) && !collHas(schemaMap, tableName)) {
174
+ if (!arrayIsEmpty(tableColumnNames) && !collHas(schemaMap, tableName)) {
188
175
  await cmd(
189
176
  `CREATE TABLE${escapeId(tableName)}(${escapeId(
190
177
  rowIdColumnName,
191
178
  )} PRIMARY KEY ON CONFLICT REPLACE${arrayJoin(
192
- arrayMap(columnNames, (cellId) => COMMA + escapeId(cellId)),
179
+ arrayMap(tableColumnNames, (cellId) => COMMA + escapeId(cellId)),
193
180
  )});`,
194
181
  );
195
182
  mapSet(
@@ -197,14 +184,17 @@ const getCommandFunctions = (cmd, managedTableNames) => {
197
184
  tableName,
198
185
  mapNew([
199
186
  [rowIdColumnName, EMPTY_STRING],
200
- ...arrayMap(columnNames, (columnName) => [columnName, EMPTY_STRING]),
187
+ ...arrayMap(tableColumnNames, (columnName) => [
188
+ columnName,
189
+ EMPTY_STRING,
190
+ ]),
201
191
  ]),
202
192
  );
203
193
  } else {
204
194
  const tableSchemaMap = mapGet(schemaMap, tableName);
205
195
  const columnNamesAccountedFor = setNew(mapKeys(tableSchemaMap));
206
196
  await promiseAll([
207
- ...arrayMap(columnNames, async (columnName) => {
197
+ ...arrayMap(tableColumnNames, async (columnName) => {
208
198
  if (!collDel(columnNamesAccountedFor, columnName)) {
209
199
  await cmd(
210
200
  `ALTER TABLE${escapeId(tableName)}ADD${escapeId(columnName)}`,
@@ -212,7 +202,7 @@ const getCommandFunctions = (cmd, managedTableNames) => {
212
202
  mapSet(tableSchemaMap, columnName, EMPTY_STRING);
213
203
  }
214
204
  }),
215
- ...(deleteEmptyColumns
205
+ ...(!partial && deleteEmptyColumns
216
206
  ? arrayMap(
217
207
  collValues(columnNamesAccountedFor),
218
208
  async (columnName) => {
@@ -229,68 +219,106 @@ const getCommandFunctions = (cmd, managedTableNames) => {
229
219
  : []),
230
220
  ]);
231
221
  }
232
- if (!arrayIsEmpty(columnNames)) {
233
- const insertSlots = [];
234
- const insertBinds = [];
235
- const deleteRowIds = [];
236
- const allColumnNames = arrayFilter(
237
- mapKeys(mapGet(schemaMap, tableName)),
238
- (columnName) => columnName != rowIdColumnName,
239
- );
240
- objMap(table, (row, rowId) => {
241
- arrayPush(
242
- insertSlots,
243
- `(?${strRepeat(',?', arrayLength(allColumnNames))})`,
222
+ if (partial) {
223
+ if (isUndefined(table)) {
224
+ await cmd('DELETE FROM' + escapeId(tableName) + 'WHERE 1');
225
+ } else {
226
+ await promiseAll(
227
+ objMap(table, async (row, rowId) => {
228
+ if (isUndefined(row)) {
229
+ await cmd(
230
+ 'DELETE FROM' +
231
+ escapeId(tableName) +
232
+ WHERE +
233
+ escapeId(rowIdColumnName) +
234
+ '=?',
235
+ [rowId],
236
+ );
237
+ } else if (!arrayIsEmpty(tableColumnNames)) {
238
+ await upsert(cmd, tableName, rowIdColumnName, objIds(row), [
239
+ rowId,
240
+ ...objValues(row),
241
+ ]);
242
+ }
243
+ }),
244
244
  );
245
- arrayPush(
246
- insertBinds,
247
- rowId,
248
- ...arrayMap(allColumnNames, (cellId) => row[cellId]),
245
+ }
246
+ } else {
247
+ if (!arrayIsEmpty(tableColumnNames)) {
248
+ const changingColumnNames = arrayFilter(
249
+ mapKeys(mapGet(schemaMap, tableName)),
250
+ (columnName) => columnName != rowIdColumnName,
249
251
  );
250
- arrayPush(deleteRowIds, rowId);
251
- });
252
- await cmd(
253
- 'INSERT INTO' +
254
- escapeId(tableName) +
255
- '(' +
256
- escapeId(rowIdColumnName) +
257
- arrayJoin(
258
- arrayMap(
259
- allColumnNames,
260
- (columnName) => COMMA + escapeId(columnName),
261
- ),
262
- ) +
263
- ')VALUES' +
264
- arrayJoin(insertSlots, COMMA) +
265
- 'ON CONFLICT(' +
266
- escapeId(rowIdColumnName) +
267
- ')DO UPDATE SET' +
268
- arrayJoin(
269
- arrayMap(
270
- allColumnNames,
271
- (columnName) =>
272
- escapeId(columnName) + '=excluded.' + escapeId(columnName),
273
- ),
274
- COMMA,
275
- ),
276
- insertBinds,
277
- );
278
- await cmd(
279
- 'DELETE FROM' +
280
- escapeId(tableName) +
281
- WHERE +
282
- escapeId(rowIdColumnName) +
283
- 'NOT IN(' +
284
- getPlaceholders(deleteRowIds) +
285
- ')',
286
- deleteRowIds,
287
- );
288
- } else if (collHas(schemaMap, tableName)) {
289
- await cmd('DELETE FROM' + escapeId(tableName));
252
+ const args = [];
253
+ const deleteRowIds = [];
254
+ objMap(table ?? {}, (row, rowId) => {
255
+ arrayPush(
256
+ args,
257
+ rowId,
258
+ ...arrayMap(changingColumnNames, (cellId) => row?.[cellId]),
259
+ );
260
+ arrayPush(deleteRowIds, rowId);
261
+ });
262
+ await upsert(
263
+ cmd,
264
+ tableName,
265
+ rowIdColumnName,
266
+ changingColumnNames,
267
+ args,
268
+ );
269
+ await cmd(
270
+ 'DELETE FROM' +
271
+ escapeId(tableName) +
272
+ WHERE +
273
+ escapeId(rowIdColumnName) +
274
+ 'NOT IN(' +
275
+ getPlaceholders(deleteRowIds) +
276
+ ')',
277
+ deleteRowIds,
278
+ );
279
+ } else if (collHas(schemaMap, tableName)) {
280
+ await cmd('DELETE FROM' + escapeId(tableName) + 'WHERE 1');
281
+ }
290
282
  }
291
283
  };
292
- return [refreshSchema, loadSingleRow, saveSingleRow, loadTable, saveTable];
284
+ return [refreshSchema, loadTable, saveTable];
293
285
  };
286
+ const upsert = async (
287
+ cmd,
288
+ tableName,
289
+ rowIdColumnName,
290
+ changingColumnNames,
291
+ args,
292
+ ) =>
293
+ await cmd(
294
+ 'INSERT INTO' +
295
+ escapeId(tableName) +
296
+ '(' +
297
+ escapeId(rowIdColumnName) +
298
+ arrayJoin(
299
+ arrayMap(
300
+ changingColumnNames,
301
+ (columnName) => COMMA + escapeId(columnName),
302
+ ),
303
+ ) +
304
+ ')VALUES' +
305
+ strRepeat(
306
+ `,(?${strRepeat(',?', arrayLength(changingColumnNames))})`,
307
+ arrayLength(args) / (arrayLength(changingColumnNames) + 1),
308
+ ).substring(1) +
309
+ 'ON CONFLICT(' +
310
+ escapeId(rowIdColumnName) +
311
+ ')DO UPDATE SET' +
312
+ arrayJoin(
313
+ arrayMap(
314
+ changingColumnNames,
315
+ (columnName) =>
316
+ escapeId(columnName) + '=excluded.' + escapeId(columnName),
317
+ ),
318
+ COMMA,
319
+ ),
320
+ args,
321
+ );
294
322
  const getPlaceholders = (array) =>
295
323
  arrayJoin(
296
324
  arrayMap(array, () => '?'),
@@ -433,25 +461,28 @@ const createJsonSqlitePersister = (
433
461
  [storeTableName],
434
462
  managedTableNames,
435
463
  ) => {
436
- const [refreshSchema, loadSingleRow, saveSingleRow] = getCommandFunctions(
464
+ const [refreshSchema, loadTable, saveTable] = getCommandFunctions(
437
465
  cmd,
438
466
  managedTableNames,
439
467
  );
440
468
  const getPersisted = async () => {
441
469
  await refreshSchema();
442
470
  return jsonParse(
443
- ((await loadSingleRow(storeTableName, DEFAULT_ROW_ID_COLUMN_NAME)) ?? {})[
444
- STORE_COLUMN
445
- ],
471
+ (await loadTable(storeTableName, DEFAULT_ROW_ID_COLUMN_NAME))[
472
+ SINGLE_ROW_ID
473
+ ]?.[STORE_COLUMN],
446
474
  );
447
475
  };
448
476
  const setPersisted = async (getContent) =>
449
477
  persister.schedule(refreshSchema, async () => {
450
- await saveSingleRow(
478
+ await saveTable(
451
479
  storeTableName,
452
480
  DEFAULT_ROW_ID_COLUMN_NAME,
453
- SINGLE_ROW_ID,
454
- {[STORE_COLUMN]: jsonString(getContent())},
481
+ {
482
+ [SINGLE_ROW_ID]: {[STORE_COLUMN]: jsonString(getContent())},
483
+ },
484
+ true,
485
+ true,
455
486
  );
456
487
  });
457
488
  const persister = createCustomPersister(
@@ -476,32 +507,41 @@ const createTabularSqlitePersister = (
476
507
  ],
477
508
  managedTableNames,
478
509
  ) => {
479
- const [refreshSchema, loadSingleRow, saveSingleRow, loadTable, saveTable] =
480
- getCommandFunctions(cmd, managedTableNames);
481
- const saveTables = async (tables) =>
510
+ const [refreshSchema, loadTable, saveTable] = getCommandFunctions(
511
+ cmd,
512
+ managedTableNames,
513
+ );
514
+ const saveTables = async (tables, partial) =>
482
515
  await promiseAll(
483
516
  mapMap(
484
517
  tablesSaveConfig,
485
518
  async (
486
519
  [tableName, rowIdColumnName, deleteEmptyColumns, deleteEmptyTable],
487
520
  tableId,
488
- ) =>
489
- await saveTable(
490
- tableName,
491
- rowIdColumnName,
492
- deleteEmptyColumns,
493
- deleteEmptyTable,
494
- tables[tableId],
495
- ),
521
+ ) => {
522
+ const table = tables[tableId];
523
+ if (!partial || table !== void 0) {
524
+ await saveTable(
525
+ tableName,
526
+ rowIdColumnName,
527
+ table,
528
+ deleteEmptyColumns,
529
+ deleteEmptyTable,
530
+ partial,
531
+ );
532
+ }
533
+ },
496
534
  ),
497
535
  );
498
- const saveValues = async (values) =>
536
+ const saveValues = async (values, partial) =>
499
537
  valuesSave
500
- ? await saveSingleRow(
538
+ ? await saveTable(
501
539
  valuesTableName,
502
540
  DEFAULT_ROW_ID_COLUMN_NAME,
503
- SINGLE_ROW_ID,
504
- values,
541
+ {[SINGLE_ROW_ID]: values},
542
+ true,
543
+ true,
544
+ partial,
505
545
  )
506
546
  : null;
507
547
  const loadTables = async () =>
@@ -521,7 +561,9 @@ const createTabularSqlitePersister = (
521
561
  );
522
562
  const loadValues = async () =>
523
563
  valuesLoad
524
- ? await loadSingleRow(valuesTableName, DEFAULT_ROW_ID_COLUMN_NAME)
564
+ ? (await loadTable(valuesTableName, DEFAULT_ROW_ID_COLUMN_NAME))[
565
+ SINGLE_ROW_ID
566
+ ]
525
567
  : {};
526
568
  const getPersisted = async () => {
527
569
  await refreshSchema();
@@ -531,11 +573,17 @@ const createTabularSqlitePersister = (
531
573
  ? [tables, values]
532
574
  : void 0;
533
575
  };
534
- const setPersisted = async (getContent) => {
535
- const [tables, values] = getContent();
576
+ const setPersisted = async (getContent, getTransactionChanges) => {
536
577
  await refreshSchema();
537
- await saveTables(tables);
538
- await saveValues(values);
578
+ if (!isUndefined(getTransactionChanges)) {
579
+ const [tableChanges, valueChanges] = getTransactionChanges();
580
+ await saveTables(tableChanges, true);
581
+ await saveValues(valueChanges, true);
582
+ } else {
583
+ const [tables, values] = getContent();
584
+ await saveTables(tables);
585
+ await saveValues(values);
586
+ }
539
587
  };
540
588
  const persister = createCustomPersister(
541
589
  store,
@@ -649,6 +697,7 @@ const createSqlitePersister = (
649
697
  cmd,
650
698
  addUpdateListener,
651
699
  delUpdateListener,
700
+ logSql,
652
701
  ) => {
653
702
  let dataVersion;
654
703
  let schemaVersion;
@@ -688,7 +737,12 @@ const createSqlitePersister = (
688
737
  };
689
738
  return (isJson ? createJsonSqlitePersister : createTabularSqlitePersister)(
690
739
  store,
691
- cmd,
740
+ logSql
741
+ ? async (sql, args) => {
742
+ logSql(sql, args);
743
+ return await cmd(sql, args);
744
+ }
745
+ : cmd,
692
746
  addPersisterListener,
693
747
  delPersisterListener,
694
748
  defaultedConfig,
@@ -696,13 +750,19 @@ const createSqlitePersister = (
696
750
  );
697
751
  };
698
752
 
699
- const createCrSqliteWasmPersister = (store, db, configOrStoreTableName) =>
753
+ const createCrSqliteWasmPersister = (
754
+ store,
755
+ db,
756
+ configOrStoreTableName,
757
+ logSql,
758
+ ) =>
700
759
  createSqlitePersister(
701
760
  store,
702
761
  configOrStoreTableName,
703
762
  async (sql, args = []) => await db.execO(sql, args),
704
763
  (listener) => db.onUpdate((_, _2, tableName) => listener(tableName)),
705
764
  (removeListener) => removeListener(),
765
+ logSql,
706
766
  );
707
767
 
708
768
  export {createCrSqliteWasmPersister};