tinybase 8.5.0 → 9.0.0-beta.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 (161) hide show
  1. package/@types/_internal/queries/with-schemas/index.d.ts +1 -2
  2. package/@types/_internal/ui/with-schemas/index.d.ts +8 -16
  3. package/@types/persisters/index.d.ts +32 -12
  4. package/@types/persisters/persister-durable-object-sql-storage/index.d.ts +9 -8
  5. package/@types/persisters/persister-durable-object-sql-storage/with-schemas/index.d.ts +10 -10
  6. package/@types/persisters/with-schemas/index.d.ts +56 -20
  7. package/@types/queries/index.d.ts +1 -7
  8. package/@types/queries/with-schemas/index.d.ts +5 -15
  9. package/@types/store/index.d.ts +1 -2
  10. package/@types/store/with-schemas/index.d.ts +19 -29
  11. package/@types/synchronizers/synchronizer-ws-client/index.d.ts +9 -3
  12. package/@types/synchronizers/synchronizer-ws-client/with-schemas/index.d.ts +10 -3
  13. package/@types/synchronizers/synchronizer-ws-server/index.d.ts +15 -2
  14. package/@types/synchronizers/synchronizer-ws-server/with-schemas/index.d.ts +17 -2
  15. package/@types/synchronizers/synchronizer-ws-server-durable-object/index.d.ts +51 -0
  16. package/@types/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.d.ts +51 -0
  17. package/@types/ui-react/with-schemas/index.d.ts +3 -6
  18. package/@types/ui-react-dom/index.d.ts +10 -10
  19. package/@types/ui-react-dom/with-schemas/index.d.ts +16 -22
  20. package/@types/ui-react-dom-charts/index.d.ts +7 -7
  21. package/@types/ui-react-dom-charts/with-schemas/index.d.ts +10 -11
  22. package/@types/ui-react-inspector/index.d.ts +1 -1
  23. package/@types/ui-react-inspector/with-schemas/index.d.ts +1 -1
  24. package/@types/ui-solid/with-schemas/index.d.ts +4 -8
  25. package/@types/ui-solid-dom/index.d.ts +10 -10
  26. package/@types/ui-solid-dom/with-schemas/index.d.ts +16 -22
  27. package/@types/ui-solid-inspector/index.d.ts +1 -1
  28. package/@types/ui-solid-inspector/with-schemas/index.d.ts +1 -1
  29. package/@types/ui-svelte-dom/index.d.ts +10 -10
  30. package/@types/ui-svelte-dom/with-schemas/index.d.ts +16 -22
  31. package/@types/ui-svelte-inspector/index.d.ts +1 -1
  32. package/@types/ui-svelte-inspector/with-schemas/index.d.ts +1 -1
  33. package/index.js +21 -19
  34. package/indexes/index.js +6 -8
  35. package/indexes/with-schemas/index.js +6 -8
  36. package/metrics/index.js +6 -8
  37. package/metrics/with-schemas/index.js +6 -8
  38. package/min/index.js +1 -1
  39. package/min/index.js.gz +0 -0
  40. package/min/omni/index.js +1 -1
  41. package/min/omni/index.js.gz +0 -0
  42. package/min/omni/with-schemas/index.js +1 -1
  43. package/min/omni/with-schemas/index.js.gz +0 -0
  44. package/min/persisters/index.js +1 -1
  45. package/min/persisters/index.js.gz +0 -0
  46. package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
  47. package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
  48. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
  49. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
  50. package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
  51. package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
  52. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
  53. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
  54. package/min/persisters/persister-electric-sql/index.js +1 -1
  55. package/min/persisters/persister-electric-sql/index.js.gz +0 -0
  56. package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
  57. package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
  58. package/min/persisters/persister-expo-sqlite/index.js +1 -1
  59. package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
  60. package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
  61. package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
  62. package/min/persisters/persister-libsql/index.js +1 -1
  63. package/min/persisters/persister-libsql/index.js.gz +0 -0
  64. package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
  65. package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
  66. package/min/persisters/persister-pglite/index.js +1 -1
  67. package/min/persisters/persister-pglite/index.js.gz +0 -0
  68. package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
  69. package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
  70. package/min/persisters/persister-postgres/index.js +1 -1
  71. package/min/persisters/persister-postgres/index.js.gz +0 -0
  72. package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
  73. package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
  74. package/min/persisters/persister-powersync/index.js +1 -1
  75. package/min/persisters/persister-powersync/index.js.gz +0 -0
  76. package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
  77. package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
  78. package/min/persisters/persister-react-native-sqlite/index.js +1 -1
  79. package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
  80. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
  81. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
  82. package/min/persisters/persister-sqlite-bun/index.js +1 -1
  83. package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
  84. package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
  85. package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
  86. package/min/persisters/persister-sqlite-wasm/index.js +1 -1
  87. package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
  88. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
  89. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
  90. package/min/persisters/persister-sqlite3/index.js +1 -1
  91. package/min/persisters/persister-sqlite3/index.js.gz +0 -0
  92. package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
  93. package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
  94. package/min/persisters/with-schemas/index.js +1 -1
  95. package/min/persisters/with-schemas/index.js.gz +0 -0
  96. package/min/queries/index.js +1 -1
  97. package/min/queries/index.js.gz +0 -0
  98. package/min/queries/with-schemas/index.js +1 -1
  99. package/min/queries/with-schemas/index.js.gz +0 -0
  100. package/min/synchronizers/synchronizer-ws-client/index.js +1 -1
  101. package/min/synchronizers/synchronizer-ws-client/index.js.gz +0 -0
  102. package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js +1 -1
  103. package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js.gz +0 -0
  104. package/min/synchronizers/synchronizer-ws-server/index.js +1 -1
  105. package/min/synchronizers/synchronizer-ws-server/index.js.gz +0 -0
  106. package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js +1 -1
  107. package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js.gz +0 -0
  108. package/min/synchronizers/synchronizer-ws-server-durable-object/index.js +1 -1
  109. package/min/synchronizers/synchronizer-ws-server-durable-object/index.js.gz +0 -0
  110. package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +1 -1
  111. package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js.gz +0 -0
  112. package/min/with-schemas/index.js +1 -1
  113. package/min/with-schemas/index.js.gz +0 -0
  114. package/omni/index.js +311 -141
  115. package/omni/with-schemas/index.js +311 -141
  116. package/package.json +7 -7
  117. package/persisters/index.js +129 -37
  118. package/persisters/persister-cr-sqlite-wasm/index.js +129 -37
  119. package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +129 -37
  120. package/persisters/persister-durable-object-sql-storage/index.js +271 -110
  121. package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +271 -110
  122. package/persisters/persister-electric-sql/index.js +129 -37
  123. package/persisters/persister-electric-sql/with-schemas/index.js +129 -37
  124. package/persisters/persister-expo-sqlite/index.js +129 -37
  125. package/persisters/persister-expo-sqlite/with-schemas/index.js +129 -37
  126. package/persisters/persister-libsql/index.js +129 -37
  127. package/persisters/persister-libsql/with-schemas/index.js +129 -37
  128. package/persisters/persister-pglite/index.js +130 -37
  129. package/persisters/persister-pglite/with-schemas/index.js +130 -37
  130. package/persisters/persister-postgres/index.js +130 -37
  131. package/persisters/persister-postgres/with-schemas/index.js +130 -37
  132. package/persisters/persister-powersync/index.js +182 -117
  133. package/persisters/persister-powersync/with-schemas/index.js +182 -117
  134. package/persisters/persister-react-native-sqlite/index.js +129 -37
  135. package/persisters/persister-react-native-sqlite/with-schemas/index.js +129 -37
  136. package/persisters/persister-sqlite-bun/index.js +129 -37
  137. package/persisters/persister-sqlite-bun/with-schemas/index.js +129 -37
  138. package/persisters/persister-sqlite-wasm/index.js +129 -37
  139. package/persisters/persister-sqlite-wasm/with-schemas/index.js +129 -37
  140. package/persisters/persister-sqlite3/index.js +129 -37
  141. package/persisters/persister-sqlite3/with-schemas/index.js +129 -37
  142. package/persisters/with-schemas/index.js +129 -37
  143. package/queries/index.js +21 -19
  144. package/queries/with-schemas/index.js +21 -19
  145. package/readme.md +14 -14
  146. package/relationships/index.js +6 -8
  147. package/relationships/with-schemas/index.js +6 -8
  148. package/releases.md +57 -57
  149. package/synchronizers/synchronizer-ws-client/index.js +116 -42
  150. package/synchronizers/synchronizer-ws-client/with-schemas/index.js +116 -42
  151. package/synchronizers/synchronizer-ws-server/index.js +109 -28
  152. package/synchronizers/synchronizer-ws-server/with-schemas/index.js +109 -28
  153. package/synchronizers/synchronizer-ws-server-durable-object/index.js +122 -38
  154. package/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +122 -38
  155. package/ui-svelte/index.js +1 -1
  156. package/ui-svelte/with-schemas/index.js +1 -1
  157. package/ui-svelte-dom/index.js +2 -2
  158. package/ui-svelte-dom/with-schemas/index.js +2 -2
  159. package/ui-svelte-inspector/index.js +2 -2
  160. package/ui-svelte-inspector/with-schemas/index.js +2 -2
  161. package/with-schemas/index.js +21 -19
@@ -51,6 +51,7 @@ const tryCatch = async (action, then1, then2) => {
51
51
  }
52
52
  };
53
53
 
54
+ const arrayHas = (array, value) => array.includes(value);
54
55
  const arrayForEach = (array, cb) => array.forEach(cb);
55
56
  const arrayJoin = (array, sep = EMPTY_STRING) => array.join(sep);
56
57
  const arrayMap = (array, cb) => array.map(cb);
@@ -60,6 +61,14 @@ const arrayClear = (array, to) => array.splice(0, to);
60
61
  const arrayPush = (array, ...values) => array.push(...values);
61
62
  const arrayShift = (array) => array.shift();
62
63
 
64
+ const collSize = (coll) => coll?.size ?? 0;
65
+ const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
66
+ const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
67
+ const collValues = (coll) => [...(coll?.values() ?? [])];
68
+ const collClear = (coll) => coll.clear();
69
+ const collForEach = (coll, cb) => coll?.forEach(cb);
70
+ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
71
+
63
72
  const object = Object;
64
73
  const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
65
74
  const objEntries = object.entries;
@@ -115,13 +124,13 @@ const replaceUndefinedString = (obj) =>
115
124
  ? objMap(obj, replaceUndefinedString)
116
125
  : obj;
117
126
 
118
- const collSize = (coll) => coll?.size ?? 0;
119
- const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
120
- const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
121
- const collValues = (coll) => [...(coll?.values() ?? [])];
122
- const collClear = (coll) => coll.clear();
123
- const collForEach = (coll, cb) => coll?.forEach(cb);
124
- const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
127
+ const setNew = (entryOrEntries) =>
128
+ new Set(
129
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
130
+ ? entryOrEntries
131
+ : [entryOrEntries],
132
+ );
133
+ const setAdd = (set, value) => set?.add(value);
125
134
 
126
135
  const map = Map;
127
136
  const mapNew = (entries) => new map(entries);
@@ -184,14 +193,6 @@ const getPoolFunctions = () => {
184
193
  ];
185
194
  };
186
195
 
187
- const setNew = (entryOrEntries) =>
188
- new Set(
189
- isArray(entryOrEntries) || isUndefined(entryOrEntries)
190
- ? entryOrEntries
191
- : [entryOrEntries],
192
- );
193
- const setAdd = (set, value) => set?.add(value);
194
-
195
196
  const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
196
197
  const leaves = [];
197
198
  const deep = (node, p) =>
@@ -573,6 +574,8 @@ const DEFAULT_TABULAR_VALUES_CONFIG = {
573
574
  save: 0,
574
575
  [TABLE_NAME]: TINYBASE + '_values',
575
576
  };
577
+ const getValuesIn = (config) => (isArray(config) ? config : void 0);
578
+ const hasValues = (config) => isTrue(config) || isArray(config);
576
579
  const getDefaultedConfig = (configOrStoreTableName) =>
577
580
  objMerge(
578
581
  DEFAULT_CONFIG,
@@ -623,11 +626,15 @@ const getConfigStructures = (configOrStoreTableName) => {
623
626
  ];
624
627
  }
625
628
  const {tables: {load = {}, save = {}} = {}, values = {}} = config;
626
- const valuesConfig = slice(
627
- objValues(objMerge(DEFAULT_TABULAR_VALUES_CONFIG, values)),
628
- 0,
629
- objSize(DEFAULT_TABULAR_VALUES_CONFIG),
630
- );
629
+ const valuesConfigObj = objMerge(DEFAULT_TABULAR_VALUES_CONFIG, values);
630
+ const {load: valuesLoad, save: valuesSave} = valuesConfigObj;
631
+ const valuesConfig = [
632
+ hasValues(valuesLoad),
633
+ hasValues(valuesSave),
634
+ valuesConfigObj[TABLE_NAME],
635
+ getValuesIn(valuesLoad),
636
+ getValuesIn(valuesSave),
637
+ ];
631
638
  const valuesTable = valuesConfig[2];
632
639
  const managedTableNames = setNew(valuesTable);
633
640
  const excludedTableNames = setNew(valuesTable);
@@ -689,8 +696,18 @@ const getCommandFunctions = (
689
696
  ({tn, cn}) => setAdd(mapEnsure(schemaMap, tn, setNew), cn),
690
697
  );
691
698
  };
692
- const loadTable = async (tableName, rowIdColumnName, condition) =>
693
- canSelect(tableName, rowIdColumnName)
699
+ const loadTable = async (
700
+ tableName,
701
+ rowIdColumnName,
702
+ condition,
703
+ contentSubIds,
704
+ ) => {
705
+ const contentSubIdSet = isUndefined(contentSubIds)
706
+ ? void 0
707
+ : setNew(contentSubIds);
708
+ const includeContentSubId = (contentSubId) =>
709
+ isUndefined(contentSubIdSet) || collHas(contentSubIdSet, contentSubId);
710
+ return canSelect(tableName, rowIdColumnName)
694
711
  ? objNew(
695
712
  arrayFilter(
696
713
  arrayMap(
@@ -699,17 +716,35 @@ const getCommandFunctions = (
699
716
  escapeId(tableName) +
700
717
  getWhereCondition(tableName, condition),
701
718
  ),
702
- (row) => [
703
- row[rowIdColumnName],
704
- decode
719
+ (row) => {
720
+ const rowId = row[rowIdColumnName];
721
+ const rowContent = decode
705
722
  ? objMap(objDel(row, rowIdColumnName), decode)
706
- : objDel(row, rowIdColumnName),
707
- ],
723
+ : objDel(row, rowIdColumnName);
724
+ return [
725
+ rowId,
726
+ isUndefined(contentSubIdSet)
727
+ ? rowContent
728
+ : objNew(
729
+ arrayFilter(
730
+ objToArray(
731
+ rowContent,
732
+ (cellOrValue, contentSubId) => [
733
+ contentSubId,
734
+ cellOrValue,
735
+ ],
736
+ ),
737
+ ([contentSubId]) => includeContentSubId(contentSubId),
738
+ ),
739
+ ),
740
+ ];
741
+ },
708
742
  ),
709
743
  (entry) => !isUndefined(entry[0]) && !objIsEmpty(entry[1]),
710
744
  ),
711
745
  )
712
746
  : {};
747
+ };
713
748
  const saveTable = async (
714
749
  tableName,
715
750
  rowIdColumnName,
@@ -718,15 +753,23 @@ const getCommandFunctions = (
718
753
  deleteEmptyTable,
719
754
  partial = false,
720
755
  condition = TRUE,
756
+ contentSubIds,
721
757
  ) => {
758
+ const contentSubIdSet = isUndefined(contentSubIds)
759
+ ? void 0
760
+ : setNew(contentSubIds);
761
+ const includeContentSubId = (contentSubId) =>
762
+ isUndefined(contentSubIdSet) || collHas(contentSubIdSet, contentSubId);
722
763
  const settingColumnNameSet = setNew();
723
764
  objMap(content ?? {}, (contentRow) =>
724
- arrayMap(objIds(contentRow ?? {}), (cellOrValueId) =>
725
- setAdd(settingColumnNameSet, cellOrValueId),
765
+ arrayMap(
766
+ arrayFilter(objIds(contentRow ?? {}), includeContentSubId),
767
+ (cellOrValueId) => setAdd(settingColumnNameSet, cellOrValueId),
726
768
  ),
727
769
  );
728
770
  const settingColumnNames = collValues(settingColumnNameSet);
729
771
  if (
772
+ isUndefined(contentSubIdSet) &&
730
773
  !partial &&
731
774
  deleteEmptyTable &&
732
775
  condition == TRUE &&
@@ -738,7 +781,13 @@ const getCommandFunctions = (
738
781
  return;
739
782
  }
740
783
  const currentColumnNames = mapGet(schemaMap, tableName);
741
- const unaccountedColumnNames = setNew(collValues(currentColumnNames));
784
+ const unaccountedColumnNames = setNew(
785
+ arrayFilter(
786
+ collValues(currentColumnNames),
787
+ (columnName) =>
788
+ columnName == rowIdColumnName || includeContentSubId(columnName),
789
+ ),
790
+ );
742
791
  if (!arrayIsEmpty(settingColumnNames)) {
743
792
  if (!collHas(schemaMap, tableName)) {
744
793
  await databaseExecuteCommand(
@@ -804,11 +853,13 @@ const getCommandFunctions = (
804
853
  ]);
805
854
  if (partial) {
806
855
  if (isUndefined(content)) {
807
- await databaseExecuteCommand(
808
- DELETE_FROM +
809
- escapeId(tableName) +
810
- getWhereCondition(tableName, condition),
811
- );
856
+ if (isUndefined(contentSubIdSet)) {
857
+ await databaseExecuteCommand(
858
+ DELETE_FROM +
859
+ escapeId(tableName) +
860
+ getWhereCondition(tableName, condition),
861
+ );
862
+ }
812
863
  } else {
813
864
  await promiseAll(
814
865
  objToArray(content, async (row, rowId) => {
@@ -821,18 +872,24 @@ const getCommandFunctions = (
821
872
  [rowId],
822
873
  );
823
874
  } else if (!arrayIsEmpty(settingColumnNames)) {
824
- await upsert(
825
- databaseExecuteCommand,
826
- tableName,
827
- rowIdColumnName,
875
+ const changingColumnNames = arrayFilter(
828
876
  objIds(row),
829
- {
830
- [rowId]: encode
831
- ? arrayMap(objValues(row), encode)
832
- : objValues(row),
833
- },
834
- currentColumnNames,
877
+ includeContentSubId,
835
878
  );
879
+ if (!arrayIsEmpty(changingColumnNames)) {
880
+ await upsert(
881
+ databaseExecuteCommand,
882
+ tableName,
883
+ rowIdColumnName,
884
+ changingColumnNames,
885
+ {
886
+ [rowId]: arrayMap(changingColumnNames, (cellId) =>
887
+ encode ? encode(row[cellId]) : row[cellId],
888
+ ),
889
+ },
890
+ currentColumnNames,
891
+ );
892
+ }
836
893
  }
837
894
  }),
838
895
  );
@@ -841,7 +898,9 @@ const getCommandFunctions = (
841
898
  if (!arrayIsEmpty(settingColumnNames)) {
842
899
  const changingColumnNames = arrayFilter(
843
900
  collValues(mapGet(schemaMap, tableName)),
844
- (changingColumnName) => changingColumnName != rowIdColumnName,
901
+ (changingColumnName) =>
902
+ changingColumnName != rowIdColumnName &&
903
+ includeContentSubId(changingColumnName),
845
904
  );
846
905
  const rows = {};
847
906
  const deleteRowIds = [];
@@ -857,6 +916,7 @@ const getCommandFunctions = (
857
916
  rowIdColumnName,
858
917
  changingColumnNames,
859
918
  rows,
919
+ currentColumnNames,
860
920
  );
861
921
  await databaseExecuteCommand(
862
922
  DELETE_FROM +
@@ -865,7 +925,10 @@ const getCommandFunctions = (
865
925
  `AND${escapeId(rowIdColumnName)}NOT IN(${getPlaceholders(deleteRowIds)})`,
866
926
  deleteRowIds,
867
927
  );
868
- } else if (collHas(schemaMap, tableName)) {
928
+ } else if (
929
+ isUndefined(contentSubIdSet) &&
930
+ collHas(schemaMap, tableName)
931
+ ) {
869
932
  await databaseExecuteCommand(
870
933
  DELETE_FROM +
871
934
  escapeId(tableName) +
@@ -1004,7 +1067,13 @@ const createTabularPersister = (
1004
1067
  [
1005
1068
  tablesLoadConfig,
1006
1069
  tablesSaveConfig,
1007
- [valuesLoad, valuesSave, valuesTableName],
1070
+ [
1071
+ valuesLoad,
1072
+ valuesSave,
1073
+ valuesTableName,
1074
+ valuesLoadValueIds,
1075
+ valuesSaveValueIds,
1076
+ ],
1008
1077
  ],
1009
1078
  managedTableNames,
1010
1079
  querySchema,
@@ -1054,15 +1123,33 @@ const createTabularPersister = (
1054
1123
  },
1055
1124
  ),
1056
1125
  );
1126
+ const getValuesSubset = (values, valueIds, partial) =>
1127
+ objNew(
1128
+ partial == true
1129
+ ? arrayFilter(
1130
+ objToArray(values, (value, valueId) => [valueId, value]),
1131
+ ([valueId]) => arrayHas(valueIds, valueId),
1132
+ )
1133
+ : arrayFilter(
1134
+ arrayMap(valueIds, (valueId) => [valueId, values[valueId]]),
1135
+ ([, value]) => !isUndefined(value),
1136
+ ),
1137
+ );
1057
1138
  const saveValues = async (values, partial) =>
1058
1139
  valuesSave
1059
1140
  ? await saveTable(
1060
1141
  valuesTableName,
1061
1142
  DEFAULT_ROW_ID_COLUMN_NAME,
1062
- {[SINGLE_ROW_ID]: values},
1143
+ {
1144
+ [SINGLE_ROW_ID]: isUndefined(valuesSaveValueIds)
1145
+ ? values
1146
+ : getValuesSubset(values, valuesSaveValueIds, partial),
1147
+ },
1063
1148
  true,
1064
1149
  true,
1065
1150
  partial,
1151
+ void 0,
1152
+ valuesSaveValueIds,
1066
1153
  )
1067
1154
  : null;
1068
1155
  const loadTables = async () =>
@@ -1082,9 +1169,14 @@ const createTabularPersister = (
1082
1169
  );
1083
1170
  const loadValues = async () =>
1084
1171
  valuesLoad
1085
- ? (await loadTable(valuesTableName, DEFAULT_ROW_ID_COLUMN_NAME))[
1086
- SINGLE_ROW_ID
1087
- ]
1172
+ ? (
1173
+ await loadTable(
1174
+ valuesTableName,
1175
+ DEFAULT_ROW_ID_COLUMN_NAME,
1176
+ void 0,
1177
+ valuesLoadValueIds,
1178
+ )
1179
+ )[SINGLE_ROW_ID]
1088
1180
  : {};
1089
1181
  const getPersisted = () =>
1090
1182
  transaction(async () => {
@@ -1217,6 +1309,8 @@ const createCustomSqlitePersister = (
1217
1309
  );
1218
1310
  };
1219
1311
 
1312
+ const getSqlRows = (sqlStorage, sql, ...params) =>
1313
+ sqlStorage.exec(sql, ...params).toArray();
1220
1314
  const createDurableObjectSqlStoragePersister = (
1221
1315
  store,
1222
1316
  sqlStorage,
@@ -1241,7 +1335,7 @@ const createDurableObjectSqlStoragePersister = (
1241
1335
  async (sql, params = []) => {
1242
1336
  if (!['BEGIN', 'END'].includes(sql)) {
1243
1337
  sql = sql.replace(/\$\d+/g, '?');
1244
- return sqlStorage.exec(sql, ...params).toArray();
1338
+ return getSqlRows(sqlStorage, sql, ...params);
1245
1339
  }
1246
1340
  return [];
1247
1341
  },
@@ -1266,6 +1360,10 @@ const createDurableObjectFragmentedSqlStoragePersister = (
1266
1360
  const tablePrefix = storagePrefix.replace(/[^a-zA-Z0-9_]/g, '_');
1267
1361
  const tablesTable = `${tablePrefix}tinybase_tables`;
1268
1362
  const valuesTable = `${tablePrefix}tinybase_values`;
1363
+ const insertTableSql = `INSERT INTO ${tablesTable} (type, table_id, row_id, cell_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?, ?, ?, ?)`;
1364
+ const insertValueSql = `INSERT INTO ${valuesTable} (value_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?)`;
1365
+ const getRowKey = (tableId, rowId) =>
1366
+ jsonStringWithUndefined([tableId, rowId]);
1269
1367
  const initializeTables = () => {
1270
1368
  sqlStorage.exec(`
1271
1369
  CREATE TABLE IF NOT EXISTS ${tablesTable} (
@@ -1288,11 +1386,74 @@ const createDurableObjectFragmentedSqlStoragePersister = (
1288
1386
  `);
1289
1387
  };
1290
1388
  initializeTables();
1389
+ const getCondition = (params, column, value) =>
1390
+ isNull(value)
1391
+ ? `${column} IS NULL`
1392
+ : (arrayPush(params, value), `${column} = ?`);
1393
+ const delTablesRow = (tableId, rowId, cellId) => {
1394
+ const params = [T];
1395
+ sqlStorage.exec(
1396
+ `DELETE FROM ${tablesTable} WHERE type = ? AND ` +
1397
+ getCondition(params, 'table_id', tableId) +
1398
+ ` AND ` +
1399
+ getCondition(params, 'row_id', rowId) +
1400
+ ` AND ` +
1401
+ getCondition(params, 'cell_id', cellId),
1402
+ ...params,
1403
+ );
1404
+ };
1405
+ const setTablesRow = (tableId, rowId, cellId, valueData, timestamp, hash) => {
1406
+ delTablesRow(tableId, rowId, cellId);
1407
+ sqlStorage.exec(
1408
+ insertTableSql,
1409
+ T,
1410
+ tableId,
1411
+ rowId,
1412
+ cellId,
1413
+ valueData,
1414
+ timestamp,
1415
+ hash,
1416
+ );
1417
+ };
1418
+ const delCellRows = (tableId, rowId) =>
1419
+ sqlStorage.exec(
1420
+ `DELETE FROM ${tablesTable} WHERE type = ? AND table_id = ? AND row_id = ? AND cell_id IS NOT NULL`,
1421
+ T,
1422
+ tableId,
1423
+ rowId,
1424
+ );
1425
+ const delValuesRow = (valueId) => {
1426
+ const params = [];
1427
+ sqlStorage.exec(
1428
+ `DELETE FROM ${valuesTable} WHERE ` +
1429
+ getCondition(params, 'value_id', valueId),
1430
+ ...params,
1431
+ );
1432
+ };
1433
+ const setValuesRow = (valueId, valueData, timestamp, hash) => {
1434
+ delValuesRow(valueId);
1435
+ sqlStorage.exec(insertValueSql, valueId, valueData, timestamp, hash);
1436
+ };
1291
1437
  const getPersisted = async () => {
1292
1438
  const tables = stampNewObjectWithHash();
1293
1439
  const values = stampNewObjectWithHash();
1294
- const tablesResult = sqlStorage.exec(`SELECT * FROM ${tablesTable}`);
1295
- for (const row of tablesResult.toArray()) {
1440
+ const rowDataKeys = setNew();
1441
+ const tablesRows = getSqlRows(sqlStorage, `SELECT * FROM ${tablesTable}`);
1442
+ arrayForEach(tablesRows, (row) => {
1443
+ const table_id = row.table_id ? string(row.table_id) : null;
1444
+ const row_id = row.row_id ? string(row.row_id) : null;
1445
+ const cell_id = row.cell_id ? string(row.cell_id) : null;
1446
+ const value_data = string(row.value_data);
1447
+ const timestamp = string(row.timestamp);
1448
+ const hash = number(row.hash);
1449
+ const [zeroOrCells] = jsonParseWithUndefined(value_data);
1450
+ if (table_id && row_id && !cell_id && isObject(zeroOrCells)) {
1451
+ const table = objEnsure(tables[0], table_id, stampNewObjectWithHash);
1452
+ table[0][row_id] = [zeroOrCells, timestamp, hash];
1453
+ setAdd(rowDataKeys, getRowKey(table_id, row_id));
1454
+ }
1455
+ });
1456
+ arrayForEach(tablesRows, (row) => {
1296
1457
  const type = string(row.type);
1297
1458
  const table_id = row.table_id ? string(row.table_id) : null;
1298
1459
  const row_id = row.row_id ? string(row.row_id) : null;
@@ -1300,16 +1461,36 @@ const createDurableObjectFragmentedSqlStoragePersister = (
1300
1461
  const value_data = string(row.value_data);
1301
1462
  const timestamp = string(row.timestamp);
1302
1463
  const hash = number(row.hash);
1303
- const [zeroOrCellOrValue] = JSON.parse(value_data);
1464
+ const [zeroOrCellOrValue] = jsonParseWithUndefined(value_data);
1304
1465
  if (type === T) {
1305
1466
  if (table_id && row_id && cell_id) {
1306
- const table = objEnsure(tables[0], table_id, stampNewObjectWithHash);
1307
- const tableRow = objEnsure(table[0], row_id, stampNewObjectWithHash);
1308
- tableRow[0][cell_id] = [zeroOrCellOrValue, timestamp, hash];
1467
+ if (!collHas(rowDataKeys, getRowKey(table_id, row_id))) {
1468
+ const table = objEnsure(
1469
+ tables[0],
1470
+ table_id,
1471
+ stampNewObjectWithHash,
1472
+ );
1473
+ const tableRow = objEnsure(
1474
+ table[0],
1475
+ row_id,
1476
+ stampNewObjectWithHash,
1477
+ );
1478
+ tableRow[0][cell_id] = [zeroOrCellOrValue, timestamp, hash];
1479
+ }
1309
1480
  } else if (table_id && row_id) {
1310
- const table = objEnsure(tables[0], table_id, stampNewObjectWithHash);
1311
- const tableRow = objEnsure(table[0], row_id, stampNewObjectWithHash);
1312
- stampUpdate(tableRow, timestamp, hash);
1481
+ if (!isObject(zeroOrCellOrValue)) {
1482
+ const table = objEnsure(
1483
+ tables[0],
1484
+ table_id,
1485
+ stampNewObjectWithHash,
1486
+ );
1487
+ const tableRow = objEnsure(
1488
+ table[0],
1489
+ row_id,
1490
+ stampNewObjectWithHash,
1491
+ );
1492
+ stampUpdate(tableRow, timestamp, hash);
1493
+ }
1313
1494
  } else if (table_id) {
1314
1495
  const table = objEnsure(tables[0], table_id, stampNewObjectWithHash);
1315
1496
  stampUpdate(table, timestamp, hash);
@@ -1317,20 +1498,22 @@ const createDurableObjectFragmentedSqlStoragePersister = (
1317
1498
  stampUpdate(tables, timestamp, hash);
1318
1499
  }
1319
1500
  }
1320
- }
1321
- const valuesResult = sqlStorage.exec(`SELECT * FROM ${valuesTable}`);
1322
- for (const row of valuesResult.toArray()) {
1323
- const value_id = row.value_id ? string(row.value_id) : null;
1324
- const value_data = string(row.value_data);
1325
- const timestamp = string(row.timestamp);
1326
- const hash = number(row.hash);
1327
- const [zeroOrCellOrValue] = JSON.parse(value_data);
1328
- if (value_id) {
1329
- values[0][value_id] = [zeroOrCellOrValue, timestamp, hash];
1330
- } else {
1331
- stampUpdate(values, timestamp, hash);
1332
- }
1333
- }
1501
+ });
1502
+ arrayForEach(
1503
+ getSqlRows(sqlStorage, `SELECT * FROM ${valuesTable}`),
1504
+ (row) => {
1505
+ const value_id = row.value_id ? string(row.value_id) : null;
1506
+ const value_data = string(row.value_data);
1507
+ const timestamp = string(row.timestamp);
1508
+ const hash = number(row.hash);
1509
+ const [zeroOrCellOrValue] = jsonParseWithUndefined(value_data);
1510
+ if (value_id) {
1511
+ values[0][value_id] = [zeroOrCellOrValue, timestamp, hash];
1512
+ } else {
1513
+ stampUpdate(values, timestamp, hash);
1514
+ }
1515
+ },
1516
+ );
1334
1517
  return [tables, values];
1335
1518
  };
1336
1519
  const setPersisted = async (
@@ -1340,64 +1523,42 @@ const createDurableObjectFragmentedSqlStoragePersister = (
1340
1523
  [valuesObj, valuesTime, valuesHash],
1341
1524
  ] = getContent(),
1342
1525
  ) => {
1343
- sqlStorage.exec(
1344
- `INSERT OR REPLACE INTO ${tablesTable} (type, table_id, row_id, cell_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?, ?, ?, ?)`,
1345
- T,
1526
+ const [fullTablesObj] = getContent()[0];
1527
+ setTablesRow(
1346
1528
  null,
1347
1529
  null,
1348
1530
  null,
1349
- JSON.stringify([0]),
1531
+ jsonStringWithUndefined([0]),
1350
1532
  tablesTime,
1351
1533
  tablesHash,
1352
1534
  );
1353
1535
  objForEach(tablesObj, ([tableObj, tableTime, tableHash], tableId) => {
1354
- sqlStorage.exec(
1355
- `INSERT OR REPLACE INTO ${tablesTable} (type, table_id, row_id, cell_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?, ?, ?, ?)`,
1356
- T,
1536
+ setTablesRow(
1357
1537
  tableId,
1358
1538
  null,
1359
1539
  null,
1360
- JSON.stringify([0]),
1540
+ jsonStringWithUndefined([0]),
1361
1541
  tableTime,
1362
1542
  tableHash,
1363
1543
  );
1364
1544
  objForEach(tableObj, ([rowObj, rowTime, rowHash], rowId) => {
1365
- sqlStorage.exec(
1366
- `INSERT OR REPLACE INTO ${tablesTable} (type, table_id, row_id, cell_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?, ?, ?, ?)`,
1367
- T,
1545
+ const fullRowObj = fullTablesObj[tableId]?.[0]?.[rowId]?.[0] ?? rowObj;
1546
+ delCellRows(tableId, rowId);
1547
+ setTablesRow(
1368
1548
  tableId,
1369
1549
  rowId,
1370
1550
  null,
1371
- JSON.stringify([0]),
1551
+ jsonStringWithUndefined([fullRowObj]),
1372
1552
  rowTime,
1373
1553
  rowHash,
1374
1554
  );
1375
- objForEach(rowObj, (cellStamp, cellId) => {
1376
- sqlStorage.exec(
1377
- `INSERT OR REPLACE INTO ${tablesTable} (type, table_id, row_id, cell_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?, ?, ?, ?)`,
1378
- T,
1379
- tableId,
1380
- rowId,
1381
- cellId,
1382
- JSON.stringify([cellStamp[0]]),
1383
- cellStamp[1],
1384
- cellStamp[2],
1385
- );
1386
- });
1387
1555
  });
1388
1556
  });
1389
- sqlStorage.exec(
1390
- `INSERT OR REPLACE INTO ${valuesTable} (value_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?)`,
1391
- null,
1392
- JSON.stringify([0]),
1393
- valuesTime,
1394
- valuesHash,
1395
- );
1557
+ setValuesRow(null, jsonStringWithUndefined([0]), valuesTime, valuesHash);
1396
1558
  objForEach(valuesObj, (valueStamp, valueId) => {
1397
- sqlStorage.exec(
1398
- `INSERT OR REPLACE INTO ${valuesTable} (value_id, value_data, timestamp, hash) VALUES (?, ?, ?, ?)`,
1559
+ setValuesRow(
1399
1560
  valueId,
1400
- JSON.stringify([valueStamp[0]]),
1561
+ jsonStringWithUndefined([valueStamp[0]]),
1401
1562
  valueStamp[1],
1402
1563
  valueStamp[2],
1403
1564
  );