tinybase 6.1.0-beta.0 → 6.1.0-beta.2

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 (155) hide show
  1. package/@types/_internal/ui-react/with-schemas/index.d.ts +1 -1
  2. package/@types/common/index.d.ts +4 -4
  3. package/@types/common/with-schemas/index.d.ts +4 -4
  4. package/@types/index.d.ts +1 -1
  5. package/@types/persisters/persister-automerge/index.d.ts +1 -1
  6. package/@types/persisters/persister-automerge/with-schemas/index.d.ts +1 -1
  7. package/@types/persisters/persister-cr-sqlite-wasm/index.d.ts +1 -1
  8. package/@types/persisters/persister-cr-sqlite-wasm/with-schemas/index.d.ts +1 -1
  9. package/@types/persisters/persister-electric-sql/index.d.ts +4 -4
  10. package/@types/persisters/persister-electric-sql/with-schemas/index.d.ts +4 -4
  11. package/@types/persisters/persister-expo-sqlite/index.d.ts +1 -1
  12. package/@types/persisters/persister-expo-sqlite/with-schemas/index.d.ts +1 -1
  13. package/@types/persisters/persister-libsql/index.d.ts +1 -1
  14. package/@types/persisters/persister-libsql/with-schemas/index.d.ts +1 -1
  15. package/@types/persisters/persister-partykit-client/index.d.ts +1 -1
  16. package/@types/persisters/persister-partykit-client/with-schemas/index.d.ts +1 -1
  17. package/@types/persisters/persister-partykit-server/index.d.ts +7 -7
  18. package/@types/persisters/persister-partykit-server/with-schemas/index.d.ts +1 -1
  19. package/@types/persisters/persister-pglite/index.d.ts +1 -1
  20. package/@types/persisters/persister-pglite/with-schemas/index.d.ts +1 -1
  21. package/@types/persisters/persister-postgres/index.d.ts +1 -1
  22. package/@types/persisters/persister-postgres/with-schemas/index.d.ts +1 -1
  23. package/@types/persisters/persister-powersync/index.d.ts +1 -1
  24. package/@types/persisters/persister-powersync/with-schemas/index.d.ts +1 -1
  25. package/@types/persisters/persister-sqlite3/index.d.ts +1 -1
  26. package/@types/persisters/persister-sqlite3/with-schemas/index.d.ts +1 -1
  27. package/@types/persisters/persister-yjs/index.d.ts +1 -1
  28. package/@types/persisters/persister-yjs/with-schemas/index.d.ts +1 -1
  29. package/@types/synchronizers/synchronizer-ws-client/index.d.ts +1 -1
  30. package/@types/synchronizers/synchronizer-ws-client/with-schemas/index.d.ts +1 -1
  31. package/@types/synchronizers/synchronizer-ws-server/index.d.ts +1 -1
  32. package/@types/synchronizers/synchronizer-ws-server/with-schemas/index.d.ts +1 -1
  33. package/@types/synchronizers/synchronizer-ws-server-durable-object/index.d.ts +1 -1
  34. package/@types/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.d.ts +1 -1
  35. package/@types/ui-react/index.d.ts +3 -3
  36. package/@types/ui-react/with-schemas/index.d.ts +1 -1
  37. package/@types/ui-react-dom/index.d.ts +1 -1
  38. package/@types/ui-react-dom/with-schemas/index.d.ts +1 -1
  39. package/@types/ui-react-inspector/with-schemas/index.d.ts +1 -1
  40. package/@types/with-schemas/index.d.ts +1 -1
  41. package/index.js +1579 -1567
  42. package/indexes/index.js +15 -3
  43. package/indexes/with-schemas/index.js +15 -3
  44. package/min/index.js +1 -1
  45. package/min/index.js.gz +0 -0
  46. package/min/indexes/index.js +1 -1
  47. package/min/indexes/index.js.gz +0 -0
  48. package/min/indexes/with-schemas/index.js +1 -1
  49. package/min/indexes/with-schemas/index.js.gz +0 -0
  50. package/min/persisters/index.js +1 -1
  51. package/min/persisters/index.js.gz +0 -0
  52. package/min/persisters/with-schemas/index.js +1 -1
  53. package/min/persisters/with-schemas/index.js.gz +0 -0
  54. package/min/ui-react/index.js +1 -1
  55. package/min/ui-react/index.js.gz +0 -0
  56. package/min/ui-react/with-schemas/index.js +1 -1
  57. package/min/ui-react/with-schemas/index.js.gz +0 -0
  58. package/min/with-schemas/index.js +1 -1
  59. package/min/with-schemas/index.js.gz +0 -0
  60. package/package.json +7 -10
  61. package/persisters/index.js +95 -95
  62. package/persisters/with-schemas/index.js +95 -95
  63. package/readme.md +13 -13
  64. package/releases.md +25 -25
  65. package/synchronizers/synchronizer-ws-server-durable-object/index.js +1 -1
  66. package/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +1 -1
  67. package/ui-react/index.js +64 -53
  68. package/ui-react/with-schemas/index.js +64 -53
  69. package/ui-react-dom/index.js +3 -3
  70. package/ui-react-dom/with-schemas/index.js +3 -3
  71. package/ui-react-inspector/index.js +4 -4
  72. package/ui-react-inspector/with-schemas/index.js +4 -4
  73. package/with-schemas/index.js +1579 -1567
  74. package/@types/_internal/queries/index.d.cts +0 -0
  75. package/@types/_internal/queries/with-schemas/index.d.cts +0 -22
  76. package/@types/_internal/store/index.d.cts +0 -3
  77. package/@types/_internal/store/with-schemas/index.d.cts +0 -106
  78. package/@types/_internal/ui-react/index.d.cts +0 -0
  79. package/@types/_internal/ui-react/with-schemas/index.d.cts +0 -1130
  80. package/@types/checkpoints/index.d.cts +0 -1059
  81. package/@types/checkpoints/with-schemas/index.d.cts +0 -1151
  82. package/@types/common/index.d.cts +0 -158
  83. package/@types/common/with-schemas/index.d.cts +0 -158
  84. package/@types/index.d.cts +0 -17
  85. package/@types/indexes/index.d.cts +0 -1064
  86. package/@types/indexes/with-schemas/index.d.cts +0 -1210
  87. package/@types/mergeable-store/index.d.cts +0 -1139
  88. package/@types/mergeable-store/with-schemas/index.d.cts +0 -1628
  89. package/@types/metrics/index.d.cts +0 -917
  90. package/@types/metrics/with-schemas/index.d.cts +0 -1004
  91. package/@types/persisters/index.d.cts +0 -1877
  92. package/@types/persisters/persister-automerge/index.d.cts +0 -165
  93. package/@types/persisters/persister-automerge/with-schemas/index.d.cts +0 -180
  94. package/@types/persisters/persister-browser/index.d.cts +0 -185
  95. package/@types/persisters/persister-browser/with-schemas/index.d.cts +0 -208
  96. package/@types/persisters/persister-cr-sqlite-wasm/index.d.cts +0 -159
  97. package/@types/persisters/persister-cr-sqlite-wasm/with-schemas/index.d.cts +0 -178
  98. package/@types/persisters/persister-durable-object-storage/index.d.cts +0 -122
  99. package/@types/persisters/persister-durable-object-storage/with-schemas/index.d.cts +0 -136
  100. package/@types/persisters/persister-electric-sql/index.d.cts +0 -185
  101. package/@types/persisters/persister-electric-sql/with-schemas/index.d.cts +0 -204
  102. package/@types/persisters/persister-expo-sqlite/index.d.cts +0 -186
  103. package/@types/persisters/persister-expo-sqlite/with-schemas/index.d.cts +0 -205
  104. package/@types/persisters/persister-file/index.d.cts +0 -94
  105. package/@types/persisters/persister-file/with-schemas/index.d.cts +0 -107
  106. package/@types/persisters/persister-indexed-db/index.d.cts +0 -120
  107. package/@types/persisters/persister-indexed-db/with-schemas/index.d.cts +0 -135
  108. package/@types/persisters/persister-libsql/index.d.cts +0 -158
  109. package/@types/persisters/persister-libsql/with-schemas/index.d.cts +0 -177
  110. package/@types/persisters/persister-partykit-client/index.d.cts +0 -195
  111. package/@types/persisters/persister-partykit-client/with-schemas/index.d.cts +0 -210
  112. package/@types/persisters/persister-partykit-server/index.d.cts +0 -650
  113. package/@types/persisters/persister-partykit-server/with-schemas/index.d.cts +0 -695
  114. package/@types/persisters/persister-pglite/index.d.cts +0 -177
  115. package/@types/persisters/persister-pglite/with-schemas/index.d.cts +0 -196
  116. package/@types/persisters/persister-postgres/index.d.cts +0 -166
  117. package/@types/persisters/persister-postgres/with-schemas/index.d.cts +0 -185
  118. package/@types/persisters/persister-powersync/index.d.cts +0 -174
  119. package/@types/persisters/persister-powersync/with-schemas/index.d.cts +0 -193
  120. package/@types/persisters/persister-remote/index.d.cts +0 -117
  121. package/@types/persisters/persister-remote/with-schemas/index.d.cts +0 -133
  122. package/@types/persisters/persister-sqlite-wasm/index.d.cts +0 -175
  123. package/@types/persisters/persister-sqlite-wasm/with-schemas/index.d.cts +0 -195
  124. package/@types/persisters/persister-sqlite3/index.d.cts +0 -176
  125. package/@types/persisters/persister-sqlite3/with-schemas/index.d.cts +0 -195
  126. package/@types/persisters/persister-yjs/index.d.cts +0 -161
  127. package/@types/persisters/persister-yjs/with-schemas/index.d.cts +0 -176
  128. package/@types/persisters/with-schemas/index.d.cts +0 -2054
  129. package/@types/queries/index.d.cts +0 -3695
  130. package/@types/queries/with-schemas/index.d.cts +0 -4016
  131. package/@types/relationships/index.d.cts +0 -1320
  132. package/@types/relationships/with-schemas/index.d.cts +0 -1474
  133. package/@types/store/index.d.cts +0 -7598
  134. package/@types/store/with-schemas/index.d.cts +0 -9278
  135. package/@types/synchronizers/index.d.cts +0 -485
  136. package/@types/synchronizers/synchronizer-broadcast-channel/index.d.cts +0 -121
  137. package/@types/synchronizers/synchronizer-broadcast-channel/with-schemas/index.d.cts +0 -137
  138. package/@types/synchronizers/synchronizer-local/index.d.cts +0 -95
  139. package/@types/synchronizers/synchronizer-local/with-schemas/index.d.cts +0 -114
  140. package/@types/synchronizers/synchronizer-ws-client/index.d.cts +0 -160
  141. package/@types/synchronizers/synchronizer-ws-client/with-schemas/index.d.cts +0 -179
  142. package/@types/synchronizers/synchronizer-ws-server/index.d.cts +0 -736
  143. package/@types/synchronizers/synchronizer-ws-server/with-schemas/index.d.cts +0 -765
  144. package/@types/synchronizers/synchronizer-ws-server-durable-object/index.d.cts +0 -311
  145. package/@types/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.d.cts +0 -349
  146. package/@types/synchronizers/synchronizer-ws-server-simple/index.d.cts +0 -144
  147. package/@types/synchronizers/synchronizer-ws-server-simple/with-schemas/index.d.cts +0 -144
  148. package/@types/synchronizers/with-schemas/index.d.cts +0 -503
  149. package/@types/ui-react/index.d.cts +0 -16640
  150. package/@types/ui-react/with-schemas/index.d.cts +0 -17281
  151. package/@types/ui-react-dom/index.d.cts +0 -1862
  152. package/@types/ui-react-dom/with-schemas/index.d.cts +0 -1994
  153. package/@types/ui-react-inspector/index.d.cts +0 -79
  154. package/@types/ui-react-inspector/with-schemas/index.d.cts +0 -1985
  155. package/@types/with-schemas/index.d.cts +0 -17
package/index.js CHANGED
@@ -825,7 +825,14 @@ const createIndexes = getCreateFunction((store) => {
825
825
  setDefinitionAndListen(
826
826
  indexId,
827
827
  tableId,
828
- (change, changedSliceIds, changedSortKeys, sliceIds, sortKeys, force) => {
828
+ (
829
+ change,
830
+ changedSliceIds,
831
+ changedSortKeys,
832
+ sliceIdOrIdsByRowId,
833
+ sortKeys,
834
+ force,
835
+ ) => {
829
836
  let sliceIdsChanged = 0;
830
837
  const changedSlices = setNew();
831
838
  const unsortedSlices = setNew();
@@ -869,8 +876,13 @@ const createIndexes = getCreateFunction((store) => {
869
876
  mapForEach(index, (sliceId) => setAdd(unsortedSlices, sliceId));
870
877
  } else {
871
878
  mapForEach(changedSortKeys, (rowId) =>
872
- ifNotUndefined(mapGet(sliceIds, rowId), (sliceId) =>
873
- setAdd(unsortedSlices, sliceId),
879
+ ifNotUndefined(
880
+ mapGet(sliceIdOrIdsByRowId, rowId),
881
+ (sliceIdOrIds) =>
882
+ arrayForEach(
883
+ isArray(sliceIdOrIds) ? sliceIdOrIds : [sliceIdOrIds],
884
+ (sliceId) => setAdd(unsortedSlices, sliceId),
885
+ ),
874
886
  ),
875
887
  );
876
888
  }
@@ -977,1118 +989,297 @@ const createIndexes = getCreateFunction((store) => {
977
989
  return objFreeze(indexes);
978
990
  });
979
991
 
980
- const numericAggregators = /* @__PURE__ */ mapNew([
981
- [
982
- AVG,
983
- [
984
- (numbers, length) => arraySum(numbers) / length,
985
- (metric, add, length) => metric + (add - metric) / (length + 1),
986
- (metric, remove, length) => metric + (metric - remove) / (length - 1),
987
- (metric, add, remove, length) => metric + (add - remove) / length,
988
- ],
989
- ],
990
- [
991
- MAX,
992
- [
993
- (numbers) => mathMax(...numbers),
994
- (metric, add) => mathMax(add, metric),
995
- (metric, remove) => (remove == metric ? void 0 : metric),
996
- (metric, add, remove) =>
997
- remove == metric ? void 0 : mathMax(add, metric),
998
- ],
999
- ],
1000
- [
1001
- MIN,
1002
- [
1003
- (numbers) => mathMin(...numbers),
1004
- (metric, add) => mathMin(add, metric),
1005
- (metric, remove) => (remove == metric ? void 0 : metric),
1006
- (metric, add, remove) =>
1007
- remove == metric ? void 0 : mathMin(add, metric),
1008
- ],
1009
- ],
1010
- [
1011
- SUM,
1012
- [
1013
- (numbers) => arraySum(numbers),
1014
- (metric, add) => metric + add,
1015
- (metric, remove) => metric - remove,
1016
- (metric, add, remove) => metric - remove + add,
1017
- ],
1018
- ],
1019
- ]);
1020
- const getAggregateValue = (
1021
- aggregateValue,
1022
- oldLength,
1023
- newValues,
1024
- changedValues,
1025
- aggregators,
1026
- force = false,
1027
- ) => {
1028
- if (collIsEmpty(newValues)) {
1029
- return void 0;
1030
- }
1031
- const [aggregate, aggregateAdd, aggregateRemove, aggregateReplace] =
1032
- aggregators;
1033
- force ||= isUndefined(aggregateValue);
1034
- collForEach(changedValues, ([oldValue, newValue]) => {
1035
- if (!force) {
1036
- aggregateValue = isUndefined(oldValue)
1037
- ? aggregateAdd?.(aggregateValue, newValue, oldLength++)
1038
- : isUndefined(newValue)
1039
- ? aggregateRemove?.(aggregateValue, oldValue, oldLength--)
1040
- : aggregateReplace?.(aggregateValue, newValue, oldValue, oldLength);
1041
- force ||= isUndefined(aggregateValue);
1042
- }
992
+ const textEncoder = /* @__PURE__ */ new GLOBAL.TextEncoder();
993
+ const getHash = (value) => {
994
+ let hash = 2166136261;
995
+ arrayForEach(textEncoder.encode(value), (char) => {
996
+ hash ^= char;
997
+ hash +=
998
+ (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
1043
999
  });
1044
- return force
1045
- ? aggregate(collValues(newValues), collSize(newValues))
1046
- : aggregateValue;
1000
+ return hash >>> 0;
1047
1001
  };
1048
1002
 
1049
- const createMetrics = getCreateFunction((store) => {
1050
- const metricListeners = mapNew();
1051
- const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
1052
- () => metrics,
1053
- );
1054
- const [
1055
- getStore,
1056
- getMetricIds,
1057
- forEachMetric,
1058
- hasMetric,
1059
- getTableId,
1060
- getMetric,
1061
- setMetric,
1062
- ,
1063
- setDefinitionAndListen,
1064
- delDefinition,
1065
- addMetricIdsListener,
1066
- destroy,
1067
- ] = getDefinableFunctions(
1068
- store,
1069
- getUndefined,
1070
- (value) =>
1071
- isNaN(value) ||
1072
- isUndefined(value) ||
1073
- value === true ||
1074
- value === false ||
1075
- value === EMPTY_STRING
1076
- ? void 0
1077
- : value * 1,
1078
- addListener,
1079
- callListeners,
1003
+ const SHIFT36 = 2 ** 36;
1004
+ const SHIFT30 = 2 ** 30;
1005
+ const SHIFT24 = 2 ** 24;
1006
+ const SHIFT18 = 2 ** 18;
1007
+ const SHIFT12 = 2 ** 12;
1008
+ const SHIFT6 = 2 ** 6;
1009
+ const encodeTimeAndCounter = (logicalTime42, counter24) =>
1010
+ encode(logicalTime42 / SHIFT36) +
1011
+ encode(logicalTime42 / SHIFT30) +
1012
+ encode(logicalTime42 / SHIFT24) +
1013
+ encode(logicalTime42 / SHIFT18) +
1014
+ encode(logicalTime42 / SHIFT12) +
1015
+ encode(logicalTime42 / SHIFT6) +
1016
+ encode(logicalTime42) +
1017
+ encode(counter24 / SHIFT18) +
1018
+ encode(counter24 / SHIFT12) +
1019
+ encode(counter24 / SHIFT6) +
1020
+ encode(counter24);
1021
+ const decodeTimeAndCounter = (hlc16) => [
1022
+ decode(hlc16, 0) * SHIFT36 +
1023
+ decode(hlc16, 1) * SHIFT30 +
1024
+ decode(hlc16, 2) * SHIFT24 +
1025
+ decode(hlc16, 3) * SHIFT18 +
1026
+ decode(hlc16, 4) * SHIFT12 +
1027
+ decode(hlc16, 5) * SHIFT6 +
1028
+ decode(hlc16, 6),
1029
+ decode(hlc16, 7) * SHIFT18 +
1030
+ decode(hlc16, 8) * SHIFT12 +
1031
+ decode(hlc16, 9) * SHIFT6 +
1032
+ decode(hlc16, 10),
1033
+ ];
1034
+ const getHlcFunctions = (uniqueId) => {
1035
+ let logicalTime = 0;
1036
+ let lastCounter = -1;
1037
+ const clientPart = ifNotUndefined(
1038
+ uniqueId,
1039
+ (uniqueId2) => {
1040
+ const clientHash30 = getHash(uniqueId2);
1041
+ return (
1042
+ encode(clientHash30 / SHIFT24) +
1043
+ encode(clientHash30 / SHIFT18) +
1044
+ encode(clientHash30 / SHIFT12) +
1045
+ encode(clientHash30 / SHIFT6) +
1046
+ encode(clientHash30)
1047
+ );
1048
+ },
1049
+ () => getUniqueId(5),
1080
1050
  );
1081
- const setMetricDefinition = (
1082
- metricId,
1083
- tableId,
1084
- aggregate,
1085
- getNumber,
1086
- aggregateAdd,
1087
- aggregateRemove,
1088
- aggregateReplace,
1089
- ) => {
1090
- const aggregators = isFunction(aggregate)
1091
- ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
1092
- : (mapGet(numericAggregators, aggregate) ??
1093
- mapGet(numericAggregators, SUM));
1094
- setDefinitionAndListen(
1095
- metricId,
1096
- tableId,
1097
- (change, changedNumbers, _changedSortKeys, numbers, _sortKeys, force) => {
1098
- const oldMetric = getMetric(metricId);
1099
- const oldLength = collSize(numbers);
1100
- force ||= isUndefined(oldMetric);
1101
- change();
1102
- let newMetric = getAggregateValue(
1103
- oldMetric,
1104
- oldLength,
1105
- numbers,
1106
- changedNumbers,
1107
- aggregators,
1108
- force,
1109
- );
1110
- if (!isFiniteNumber(newMetric)) {
1111
- newMetric = void 0;
1112
- }
1113
- if (newMetric != oldMetric) {
1114
- setMetric(metricId, newMetric);
1115
- callListeners(metricListeners, [metricId], newMetric, oldMetric);
1116
- }
1117
- },
1118
- getRowCellFunction(getNumber, 1),
1119
- );
1120
- return metrics;
1121
- };
1122
- const delMetricDefinition = (metricId) => {
1123
- delDefinition(metricId);
1124
- return metrics;
1125
- };
1126
- const addMetricListener = (metricId, listener) =>
1127
- addListener(listener, metricListeners, [metricId]);
1128
- const delListener = (listenerId) => {
1129
- delListenerImpl(listenerId);
1130
- return metrics;
1051
+ const getHlc = () => {
1052
+ seenHlc();
1053
+ return encodeTimeAndCounter(logicalTime, ++lastCounter) + clientPart;
1131
1054
  };
1132
- const getListenerStats = () => ({
1133
- metric: collSize2(metricListeners),
1134
- });
1135
- const metrics = {
1136
- setMetricDefinition,
1137
- delMetricDefinition,
1138
- getStore,
1139
- getMetricIds,
1140
- forEachMetric,
1141
- hasMetric,
1142
- getTableId,
1143
- getMetric,
1144
- addMetricIdsListener,
1145
- addMetricListener,
1146
- delListener,
1147
- destroy,
1148
- getListenerStats,
1055
+ const seenHlc = (hlc) => {
1056
+ const previousLogicalTime = logicalTime;
1057
+ const [remoteLogicalTime, remoteCounter] =
1058
+ isUndefined(hlc) || hlc == '' ? [0, 0] : decodeTimeAndCounter(hlc);
1059
+ logicalTime = mathMax(
1060
+ previousLogicalTime,
1061
+ remoteLogicalTime,
1062
+ GLOBAL.HLC_TIME ?? Date.now(),
1063
+ );
1064
+ lastCounter =
1065
+ logicalTime == previousLogicalTime
1066
+ ? logicalTime == remoteLogicalTime
1067
+ ? mathMax(lastCounter, remoteCounter)
1068
+ : lastCounter
1069
+ : logicalTime == remoteLogicalTime
1070
+ ? remoteCounter
1071
+ : -1;
1149
1072
  };
1150
- return objFreeze(metrics);
1151
- });
1073
+ return [getHlc, seenHlc];
1074
+ };
1152
1075
 
1153
- const createQueries = getCreateFunction((store) => {
1154
- const createStore = store.createStore;
1155
- const preStore = createStore();
1156
- const resultStore = createStore();
1157
- const preStoreListenerIds = mapNew();
1158
- const {
1159
- addListener,
1160
- callListeners,
1161
- delListener: delListenerImpl,
1162
- } = resultStore;
1163
- const [
1164
- getStore,
1165
- getQueryIds,
1166
- forEachQuery,
1167
- hasQuery,
1168
- getTableId,
1169
- ,
1170
- ,
1171
- setDefinition,
1172
- ,
1173
- delDefinition,
1174
- addQueryIdsListenerImpl,
1175
- destroy,
1176
- addStoreListeners,
1177
- delStoreListeners,
1178
- ] = getDefinableFunctions(
1179
- store,
1180
- () => true,
1181
- getUndefined,
1182
- addListener,
1183
- callListeners,
1076
+ const jsonString = JSON.stringify;
1077
+ const jsonParse = JSON.parse;
1078
+ const jsonStringWithMap = (obj) =>
1079
+ jsonString(obj, (_key, value) =>
1080
+ isInstanceOf(value, Map) ? object.fromEntries([...value]) : value,
1184
1081
  );
1185
- const addPreStoreListener = (preStore2, queryId, ...listenerIds) =>
1186
- arrayForEach(listenerIds, (listenerId) =>
1187
- setAdd(
1188
- mapEnsure(
1189
- mapEnsure(preStoreListenerIds, queryId, mapNew),
1190
- preStore2,
1191
- setNew,
1082
+
1083
+ const stampClone = ([value, time]) => stampNew(value, time);
1084
+ const stampCloneWithHash = ([value, time, hash]) => [value, time, hash];
1085
+ const stampNew = (value, time) => (time ? [value, time] : [value]);
1086
+ const stampNewWithHash = (value, time, hash) => [value, time, hash];
1087
+ const getStampHash = (stamp) => stamp[2];
1088
+ const hashIdAndHash = (id, hash) => getHash(id + ':' + hash);
1089
+ const replaceTimeHash = (oldTime, newTime) =>
1090
+ newTime > oldTime ? (oldTime ? getHash(oldTime) : 0) ^ getHash(newTime) : 0;
1091
+ const getLatestTime = (time1, time2) =>
1092
+ /* istanbul ignore next */
1093
+ ((time1 ?? '') > (time2 ?? '') ? time1 : time2) ?? '';
1094
+ const stampUpdate = (stamp, time, hash) => {
1095
+ if (time > stamp[1]) {
1096
+ stamp[1] = time;
1097
+ }
1098
+ stamp[2] = hash >>> 0;
1099
+ };
1100
+ const stampNewObj = (time = EMPTY_STRING) => stampNew(objNew(), time);
1101
+ const stampNewMap = (time = EMPTY_STRING) => [mapNew(), time, 0];
1102
+ const stampMapToObjWithHash = (
1103
+ [map, time, hash],
1104
+ mapper = stampCloneWithHash,
1105
+ ) => [mapToObj(map, mapper), time, hash];
1106
+ const stampMapToObjWithoutHash = ([map, time], mapper = stampClone) =>
1107
+ stampNew(mapToObj(map, mapper), time);
1108
+ const stampValidate = (stamp, validateThing) =>
1109
+ isArray(stamp) &&
1110
+ size(stamp) == 3 &&
1111
+ isString(stamp[1]) &&
1112
+ getTypeOf(stamp[2]) == NUMBER &&
1113
+ isFiniteNumber(stamp[2]) &&
1114
+ validateThing(stamp[0]);
1115
+
1116
+ const pairNew = (value) => [value, value];
1117
+ const pairCollSize2 = (pair, func = collSize2) => func(pair[0]) + func(pair[1]);
1118
+ const pairNewMap = () => [mapNew(), mapNew()];
1119
+ const pairClone = (array) => [...array];
1120
+ const pairIsEqual = ([entry1, entry2]) => entry1 === entry2;
1121
+
1122
+ const idsChanged = (changedIds, id2, addedOrRemoved) =>
1123
+ mapSet(
1124
+ changedIds,
1125
+ id2,
1126
+ mapGet(changedIds, id2) == -addedOrRemoved ? void 0 : addedOrRemoved,
1127
+ );
1128
+ const createStore = () => {
1129
+ let hasTablesSchema;
1130
+ let hasValuesSchema;
1131
+ let hadTables = false;
1132
+ let hadValues = false;
1133
+ let transactions = 0;
1134
+ let internalListeners = [];
1135
+ const changedTableIds = mapNew();
1136
+ const changedTableCellIds = mapNew();
1137
+ const changedRowCount = mapNew();
1138
+ const changedRowIds = mapNew();
1139
+ const changedCellIds = mapNew();
1140
+ const changedCells = mapNew();
1141
+ const changedValueIds = mapNew();
1142
+ const changedValues = mapNew();
1143
+ const invalidCells = mapNew();
1144
+ const invalidValues = mapNew();
1145
+ const tablesSchemaMap = mapNew();
1146
+ const tablesSchemaRowCache = mapNew();
1147
+ const valuesSchemaMap = mapNew();
1148
+ const valuesDefaulted = mapNew();
1149
+ const valuesNonDefaulted = setNew();
1150
+ const tablePoolFunctions = mapNew();
1151
+ const tableCellIds = mapNew();
1152
+ const tablesMap = mapNew();
1153
+ const valuesMap = mapNew();
1154
+ const hasTablesListeners = pairNewMap();
1155
+ const tablesListeners = pairNewMap();
1156
+ const tableIdsListeners = pairNewMap();
1157
+ const hasTableListeners = pairNewMap();
1158
+ const tableListeners = pairNewMap();
1159
+ const tableCellIdsListeners = pairNewMap();
1160
+ const hasTableCellListeners = pairNewMap();
1161
+ const rowCountListeners = pairNewMap();
1162
+ const rowIdsListeners = pairNewMap();
1163
+ const sortedRowIdsListeners = pairNewMap();
1164
+ const hasRowListeners = pairNewMap();
1165
+ const rowListeners = pairNewMap();
1166
+ const cellIdsListeners = pairNewMap();
1167
+ const hasCellListeners = pairNewMap();
1168
+ const cellListeners = pairNewMap();
1169
+ const invalidCellListeners = pairNewMap();
1170
+ const invalidValueListeners = pairNewMap();
1171
+ const hasValuesListeners = pairNewMap();
1172
+ const valuesListeners = pairNewMap();
1173
+ const valueIdsListeners = pairNewMap();
1174
+ const hasValueListeners = pairNewMap();
1175
+ const valueListeners = pairNewMap();
1176
+ const startTransactionListeners = mapNew();
1177
+ const finishTransactionListeners = pairNewMap();
1178
+ const [addListener, callListeners, delListenerImpl, callListenerImpl] =
1179
+ getListenerFunctions(() => store);
1180
+ const validateTablesSchema = (tableSchema) =>
1181
+ objValidate(tableSchema, (tableSchema2) =>
1182
+ objValidate(tableSchema2, validateCellOrValueSchema),
1183
+ );
1184
+ const validateValuesSchema = (valuesSchema) =>
1185
+ objValidate(valuesSchema, validateCellOrValueSchema);
1186
+ const validateCellOrValueSchema = (schema) => {
1187
+ if (!objValidate(schema, (_child, id2) => arrayHas([TYPE, DEFAULT], id2))) {
1188
+ return false;
1189
+ }
1190
+ const type = schema[TYPE];
1191
+ if (!isTypeStringOrBoolean(type) && type != NUMBER) {
1192
+ return false;
1193
+ }
1194
+ if (getCellOrValueType(schema[DEFAULT]) != type) {
1195
+ objDel(schema, DEFAULT);
1196
+ }
1197
+ return true;
1198
+ };
1199
+ const validateContent = isArray;
1200
+ const validateTables = (tables) =>
1201
+ objValidate(tables, validateTable, cellInvalid);
1202
+ const validateTable = (table, tableId) =>
1203
+ (!hasTablesSchema ||
1204
+ collHas(tablesSchemaMap, tableId) ||
1205
+ /* istanbul ignore next */
1206
+ cellInvalid(tableId)) &&
1207
+ objValidate(
1208
+ table,
1209
+ (row, rowId) => validateRow(tableId, rowId, row),
1210
+ () => cellInvalid(tableId),
1211
+ );
1212
+ const validateRow = (tableId, rowId, row, skipDefaults) =>
1213
+ objValidate(
1214
+ skipDefaults ? row : addDefaultsToRow(row, tableId, rowId),
1215
+ (cell, cellId) =>
1216
+ ifNotUndefined(
1217
+ getValidatedCell(tableId, rowId, cellId, cell),
1218
+ (validCell) => {
1219
+ row[cellId] = validCell;
1220
+ return true;
1221
+ },
1222
+ () => false,
1192
1223
  ),
1193
- listenerId,
1194
- ),
1224
+ () => cellInvalid(tableId, rowId),
1195
1225
  );
1196
- const resetPreStores = (queryId) => {
1226
+ const getValidatedCell = (tableId, rowId, cellId, cell) =>
1227
+ hasTablesSchema
1228
+ ? ifNotUndefined(
1229
+ mapGet(mapGet(tablesSchemaMap, tableId), cellId),
1230
+ (cellSchema) =>
1231
+ getCellOrValueType(cell) != cellSchema[TYPE]
1232
+ ? cellInvalid(tableId, rowId, cellId, cell, cellSchema[DEFAULT])
1233
+ : cell,
1234
+ () => cellInvalid(tableId, rowId, cellId, cell),
1235
+ )
1236
+ : isUndefined(getCellOrValueType(cell))
1237
+ ? cellInvalid(tableId, rowId, cellId, cell)
1238
+ : cell;
1239
+ const validateValues = (values, skipDefaults) =>
1240
+ objValidate(
1241
+ skipDefaults ? values : addDefaultsToValues(values),
1242
+ (value, valueId) =>
1243
+ ifNotUndefined(
1244
+ getValidatedValue(valueId, value),
1245
+ (validValue) => {
1246
+ values[valueId] = validValue;
1247
+ return true;
1248
+ },
1249
+ () => false,
1250
+ ),
1251
+ () => valueInvalid(),
1252
+ );
1253
+ const getValidatedValue = (valueId, value) =>
1254
+ hasValuesSchema
1255
+ ? ifNotUndefined(
1256
+ mapGet(valuesSchemaMap, valueId),
1257
+ (valueSchema) =>
1258
+ getCellOrValueType(value) != valueSchema[TYPE]
1259
+ ? valueInvalid(valueId, value, valueSchema[DEFAULT])
1260
+ : value,
1261
+ () => valueInvalid(valueId, value),
1262
+ )
1263
+ : isUndefined(getCellOrValueType(value))
1264
+ ? valueInvalid(valueId, value)
1265
+ : value;
1266
+ const addDefaultsToRow = (row, tableId, rowId) => {
1197
1267
  ifNotUndefined(
1198
- mapGet(preStoreListenerIds, queryId),
1199
- (queryPreStoreListenerIds) => {
1200
- mapForEach(queryPreStoreListenerIds, (preStore2, listenerIds) =>
1201
- collForEach(listenerIds, (listenerId) =>
1202
- preStore2.delListener(listenerId),
1203
- ),
1204
- );
1205
- collClear(queryPreStoreListenerIds);
1268
+ mapGet(tablesSchemaRowCache, tableId),
1269
+ ([rowDefaulted, rowNonDefaulted]) => {
1270
+ collForEach(rowDefaulted, (cell, cellId) => {
1271
+ if (!objHas(row, cellId)) {
1272
+ row[cellId] = cell;
1273
+ }
1274
+ });
1275
+ collForEach(rowNonDefaulted, (cellId) => {
1276
+ if (!objHas(row, cellId)) {
1277
+ cellInvalid(tableId, rowId, cellId);
1278
+ }
1279
+ });
1206
1280
  },
1207
1281
  );
1208
- arrayForEach([resultStore, preStore], (store2) => store2.delTable(queryId));
1209
- };
1210
- const synchronizeTransactions = (queryId, fromStore, toStore) =>
1211
- addPreStoreListener(
1212
- fromStore,
1213
- queryId,
1214
- fromStore.addStartTransactionListener(toStore.startTransaction),
1215
- fromStore.addDidFinishTransactionListener(() =>
1216
- toStore.finishTransaction(),
1217
- ),
1218
- );
1219
- const setQueryDefinition = (queryId, tableId, build) => {
1220
- setDefinition(queryId, tableId);
1221
- resetPreStores(queryId);
1222
- const selectEntries = [];
1223
- const joinEntries = [[null, [tableId, null, null, [], mapNew()]]];
1224
- const wheres = [];
1225
- const groupEntries = [];
1226
- const havings = [];
1227
- const select = (arg1, arg2) => {
1228
- const selectEntry = isFunction(arg1)
1229
- ? [size(selectEntries) + EMPTY_STRING, arg1]
1230
- : [
1231
- isUndefined(arg2) ? arg1 : arg2,
1232
- (getTableCell) => getTableCell(arg1, arg2),
1233
- ];
1234
- arrayPush(selectEntries, selectEntry);
1235
- return {as: (selectedCellId) => (selectEntry[0] = selectedCellId)};
1236
- };
1237
- const join = (joinedTableId, arg1, arg2) => {
1238
- const fromIntermediateJoinedTableId =
1239
- isUndefined(arg2) || isFunction(arg1) ? null : arg1;
1240
- const onArg = isUndefined(fromIntermediateJoinedTableId) ? arg1 : arg2;
1241
- const joinEntry = [
1242
- joinedTableId,
1243
- [
1244
- joinedTableId,
1245
- fromIntermediateJoinedTableId,
1246
- isFunction(onArg) ? onArg : (getCell) => getCell(onArg),
1247
- [],
1248
- mapNew(),
1249
- ],
1250
- ];
1251
- arrayPush(joinEntries, joinEntry);
1252
- return {as: (joinedTableId2) => (joinEntry[0] = joinedTableId2)};
1253
- };
1254
- const where = (arg1, arg2, arg3) =>
1255
- arrayPush(
1256
- wheres,
1257
- isFunction(arg1)
1258
- ? arg1
1259
- : isUndefined(arg3)
1260
- ? (getTableCell) => getTableCell(arg1) === arg2
1261
- : (getTableCell) => getTableCell(arg1, arg2) === arg3,
1262
- );
1263
- const group = (
1264
- selectedCellId,
1265
- aggregate,
1266
- aggregateAdd,
1267
- aggregateRemove,
1268
- aggregateReplace,
1269
- ) => {
1270
- const groupEntry = [
1271
- selectedCellId,
1272
- [
1273
- selectedCellId,
1274
- isFunction(aggregate)
1275
- ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
1276
- : (mapGet(numericAggregators, aggregate) ?? [
1277
- (_cells, length) => length,
1278
- ]),
1279
- ],
1280
- ];
1281
- arrayPush(groupEntries, groupEntry);
1282
- return {as: (groupedCellId) => (groupEntry[0] = groupedCellId)};
1283
- };
1284
- const having = (arg1, arg2) =>
1285
- arrayPush(
1286
- havings,
1287
- isFunction(arg1)
1288
- ? arg1
1289
- : (getSelectedOrGroupedCell) =>
1290
- getSelectedOrGroupedCell(arg1) === arg2,
1291
- );
1292
- build({select, join, where, group, having});
1293
- const selects = mapNew(selectEntries);
1294
- if (collIsEmpty(selects)) {
1295
- return queries;
1296
- }
1297
- const joins = mapNew(joinEntries);
1298
- mapForEach(joins, (asTableId, [, fromAsTableId]) =>
1299
- ifNotUndefined(mapGet(joins, fromAsTableId), ({3: toAsTableIds}) =>
1300
- isUndefined(asTableId) ? 0 : arrayPush(toAsTableIds, asTableId),
1301
- ),
1302
- );
1303
- const groups = mapNew(groupEntries);
1304
- let selectJoinWhereStore = preStore;
1305
- if (collIsEmpty(groups) && arrayIsEmpty(havings)) {
1306
- selectJoinWhereStore = resultStore;
1307
- } else {
1308
- synchronizeTransactions(queryId, selectJoinWhereStore, resultStore);
1309
- const groupedSelectedCellIds = mapNew();
1310
- mapForEach(groups, (groupedCellId, [selectedCellId, aggregators]) =>
1311
- setAdd(mapEnsure(groupedSelectedCellIds, selectedCellId, setNew), [
1312
- groupedCellId,
1313
- aggregators,
1314
- ]),
1315
- );
1316
- const groupBySelectedCellIds = setNew();
1317
- mapForEach(selects, (selectedCellId) =>
1318
- collHas(groupedSelectedCellIds, selectedCellId)
1319
- ? 0
1320
- : setAdd(groupBySelectedCellIds, selectedCellId),
1321
- );
1322
- const tree = mapNew();
1323
- const writeGroupRow = (
1324
- leaf,
1325
- changedGroupedSelectedCells,
1326
- selectedRowId,
1327
- forceRemove,
1328
- ) =>
1329
- ifNotUndefined(
1330
- leaf,
1331
- ([selectedCells, selectedRowIds, groupRowId, groupRow]) => {
1332
- mapForEach(
1333
- changedGroupedSelectedCells,
1334
- (selectedCellId, [newCell]) => {
1335
- const selectedCell = mapEnsure(
1336
- selectedCells,
1337
- selectedCellId,
1338
- mapNew,
1339
- );
1340
- const oldLeafCell = mapGet(selectedCell, selectedRowId);
1341
- const newLeafCell = forceRemove ? void 0 : newCell;
1342
- if (oldLeafCell !== newLeafCell) {
1343
- const oldNewSet = setNew([[oldLeafCell, newLeafCell]]);
1344
- const oldLength = collSize(selectedCell);
1345
- mapSet(selectedCell, selectedRowId, newLeafCell);
1346
- collForEach(
1347
- mapGet(groupedSelectedCellIds, selectedCellId),
1348
- ([groupedCellId, aggregators]) => {
1349
- const aggregateValue = getAggregateValue(
1350
- groupRow[groupedCellId],
1351
- oldLength,
1352
- selectedCell,
1353
- oldNewSet,
1354
- aggregators,
1355
- );
1356
- groupRow[groupedCellId] = isUndefined(
1357
- getCellOrValueType(aggregateValue),
1358
- )
1359
- ? null
1360
- : aggregateValue;
1361
- },
1362
- );
1363
- }
1364
- },
1365
- );
1366
- if (
1367
- collIsEmpty(selectedRowIds) ||
1368
- !arrayEvery(havings, (having2) =>
1369
- having2((cellId) => groupRow[cellId]),
1370
- )
1371
- ) {
1372
- resultStore.delRow(queryId, groupRowId);
1373
- } else if (isUndefined(groupRowId)) {
1374
- leaf[2] = resultStore.addRow(queryId, groupRow);
1375
- } else {
1376
- resultStore.setRow(queryId, groupRowId, groupRow);
1377
- }
1378
- },
1379
- );
1380
- addPreStoreListener(
1381
- selectJoinWhereStore,
1382
- queryId,
1383
- selectJoinWhereStore.addRowListener(
1384
- queryId,
1385
- null,
1386
- (_store, _tableId, selectedRowId, getCellChange) => {
1387
- const oldPath = [];
1388
- const newPath = [];
1389
- const changedGroupedSelectedCells = mapNew();
1390
- const rowExists = selectJoinWhereStore.hasRow(
1391
- queryId,
1392
- selectedRowId,
1393
- );
1394
- let changedLeaf = !rowExists;
1395
- collForEach(groupBySelectedCellIds, (selectedCellId) => {
1396
- const [changed, oldCell, newCell] = getCellChange(
1397
- queryId,
1398
- selectedRowId,
1399
- selectedCellId,
1400
- );
1401
- arrayPush(oldPath, oldCell);
1402
- arrayPush(newPath, newCell);
1403
- changedLeaf ||= changed;
1404
- });
1405
- mapForEach(groupedSelectedCellIds, (selectedCellId) => {
1406
- const [changed, , newCell] = getCellChange(
1407
- queryId,
1408
- selectedRowId,
1409
- selectedCellId,
1410
- );
1411
- if (changedLeaf || changed) {
1412
- mapSet(changedGroupedSelectedCells, selectedCellId, [newCell]);
1413
- }
1414
- });
1415
- if (changedLeaf) {
1416
- writeGroupRow(
1417
- visitTree(tree, oldPath, void 0, ([, selectedRowIds]) => {
1418
- collDel(selectedRowIds, selectedRowId);
1419
- return collIsEmpty(selectedRowIds);
1420
- }),
1421
- changedGroupedSelectedCells,
1422
- selectedRowId,
1423
- 1,
1424
- );
1425
- }
1426
- if (rowExists) {
1427
- writeGroupRow(
1428
- visitTree(
1429
- tree,
1430
- newPath,
1431
- () => {
1432
- const groupRow = {};
1433
- collForEach(
1434
- groupBySelectedCellIds,
1435
- (selectedCellId) =>
1436
- (groupRow[selectedCellId] =
1437
- selectJoinWhereStore.getCell(
1438
- queryId,
1439
- selectedRowId,
1440
- selectedCellId,
1441
- )),
1442
- );
1443
- return [mapNew(), setNew(), void 0, groupRow];
1444
- },
1445
- ([, selectedRowIds]) => {
1446
- setAdd(selectedRowIds, selectedRowId);
1447
- },
1448
- ),
1449
- changedGroupedSelectedCells,
1450
- selectedRowId,
1451
- );
1452
- }
1453
- },
1454
- ),
1455
- );
1456
- }
1457
- synchronizeTransactions(queryId, store, selectJoinWhereStore);
1458
- const writeSelectRow = (rootRowId) => {
1459
- const getTableCell = (arg1, arg2) =>
1460
- store.getCell(
1461
- ...(isUndefined(arg2)
1462
- ? [tableId, rootRowId, arg1]
1463
- : arg1 === tableId
1464
- ? [tableId, rootRowId, arg2]
1465
- : [
1466
- mapGet(joins, arg1)?.[0],
1467
- mapGet(mapGet(joins, arg1)?.[4], rootRowId)?.[0],
1468
- arg2,
1469
- ]),
1470
- );
1471
- selectJoinWhereStore.transaction(() =>
1472
- arrayEvery(wheres, (where2) => where2(getTableCell))
1473
- ? mapForEach(selects, (asCellId, tableCellGetter) =>
1474
- setOrDelCell(
1475
- selectJoinWhereStore,
1476
- queryId,
1477
- rootRowId,
1478
- asCellId,
1479
- tableCellGetter(getTableCell, rootRowId),
1480
- ),
1481
- )
1482
- : selectJoinWhereStore.delRow(queryId, rootRowId),
1483
- );
1484
- };
1485
- const listenToTable = (rootRowId, tableId2, rowId, joinedTableIds2) => {
1486
- const getCell = (cellId) => store.getCell(tableId2, rowId, cellId);
1487
- arrayForEach(joinedTableIds2, (remoteAsTableId) => {
1488
- const [realJoinedTableId, , on, nextJoinedTableIds, remoteIdPair] =
1489
- mapGet(joins, remoteAsTableId);
1490
- const remoteRowId = on?.(getCell, rootRowId);
1491
- const [previousRemoteRowId, previousRemoteListenerId] =
1492
- mapGet(remoteIdPair, rootRowId) ?? [];
1493
- if (remoteRowId != previousRemoteRowId) {
1494
- if (!isUndefined(previousRemoteListenerId)) {
1495
- delStoreListeners(queryId, previousRemoteListenerId);
1496
- }
1497
- mapSet(
1498
- remoteIdPair,
1499
- rootRowId,
1500
- isUndefined(remoteRowId)
1501
- ? null
1502
- : [
1503
- remoteRowId,
1504
- ...addStoreListeners(
1505
- queryId,
1506
- 1,
1507
- store.addRowListener(realJoinedTableId, remoteRowId, () =>
1508
- listenToTable(
1509
- rootRowId,
1510
- realJoinedTableId,
1511
- remoteRowId,
1512
- nextJoinedTableIds,
1513
- ),
1514
- ),
1515
- ),
1516
- ],
1517
- );
1518
- }
1519
- });
1520
- writeSelectRow(rootRowId);
1521
- };
1522
- const {3: joinedTableIds} = mapGet(joins, null);
1523
- selectJoinWhereStore.transaction(() =>
1524
- addStoreListeners(
1525
- queryId,
1526
- 1,
1527
- store.addRowListener(tableId, null, (_store, _tableId, rootRowId) => {
1528
- if (store.hasRow(tableId, rootRowId)) {
1529
- listenToTable(rootRowId, tableId, rootRowId, joinedTableIds);
1530
- } else {
1531
- selectJoinWhereStore.delRow(queryId, rootRowId);
1532
- collForEach(joins, ({4: idsByRootRowId}) =>
1533
- ifNotUndefined(
1534
- mapGet(idsByRootRowId, rootRowId),
1535
- ([, listenerId]) => {
1536
- delStoreListeners(queryId, listenerId);
1537
- mapSet(idsByRootRowId, rootRowId);
1538
- },
1539
- ),
1540
- );
1541
- }
1542
- }),
1543
- ),
1544
- );
1545
- return queries;
1546
- };
1547
- const delQueryDefinition = (queryId) => {
1548
- resetPreStores(queryId);
1549
- delDefinition(queryId);
1550
- return queries;
1551
- };
1552
- const addQueryIdsListener = (listener) =>
1553
- addQueryIdsListenerImpl(() => listener(queries));
1554
- const delListener = (listenerId) => {
1555
- delListenerImpl(listenerId);
1556
- return queries;
1557
- };
1558
- const getListenerStats = () => {
1559
- const {
1560
- tables: _1,
1561
- tableIds: _2,
1562
- transaction: _3,
1563
- ...stats
1564
- } = resultStore.getListenerStats();
1565
- return stats;
1566
- };
1567
- const queries = {
1568
- setQueryDefinition,
1569
- delQueryDefinition,
1570
- getStore,
1571
- getQueryIds,
1572
- forEachQuery,
1573
- hasQuery,
1574
- getTableId,
1575
- addQueryIdsListener,
1576
- delListener,
1577
- destroy,
1578
- getListenerStats,
1579
- };
1580
- objMap(
1581
- {
1582
- [TABLE]: [1, 1],
1583
- [TABLE + CELL_IDS]: [0, 1],
1584
- [ROW_COUNT]: [0, 1],
1585
- [ROW_IDS]: [0, 1],
1586
- [SORTED_ROW_IDS]: [0, 5],
1587
- [ROW]: [1, 2],
1588
- [CELL_IDS]: [0, 2],
1589
- [CELL]: [1, 3],
1590
- },
1591
- ([hasAndForEach, argumentCount], gettable) => {
1592
- arrayForEach(
1593
- hasAndForEach ? [GET, 'has', 'forEach'] : [GET],
1594
- (prefix) =>
1595
- (queries[prefix + RESULT + gettable] = (...args) =>
1596
- resultStore[prefix + gettable](...args)),
1597
- );
1598
- queries[ADD + RESULT + gettable + LISTENER] = (...args) =>
1599
- resultStore[ADD + gettable + LISTENER](
1600
- ...slice(args, 0, argumentCount),
1601
- (_store, ...listenerArgs) =>
1602
- args[argumentCount](queries, ...listenerArgs),
1603
- true,
1604
- );
1605
- },
1606
- );
1607
- return objFreeze(queries);
1608
- });
1609
-
1610
- const createRelationships = getCreateFunction((store) => {
1611
- const remoteTableIds = mapNew();
1612
- const remoteRowIdListeners = mapNew();
1613
- const localRowIdsListeners = mapNew();
1614
- const linkedRowIdsListeners = mapNew();
1615
- const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
1616
- () => relationships,
1617
- );
1618
- const [
1619
- getStore,
1620
- getRelationshipIds,
1621
- forEachRelationshipImpl,
1622
- hasRelationship,
1623
- getLocalTableId,
1624
- getRelationship,
1625
- ,
1626
- ,
1627
- setDefinitionAndListen,
1628
- delDefinition,
1629
- addRelationshipIdsListener,
1630
- destroy,
1631
- ] = getDefinableFunctions(
1632
- store,
1633
- () => [mapNew(), mapNew(), mapNew(), mapNew()],
1634
- (value) => (isUndefined(value) ? void 0 : value + EMPTY_STRING),
1635
- addListener,
1636
- callListeners,
1637
- );
1638
- const getLinkedRowIdsCache = (relationshipId, firstRowId, skipCache) =>
1639
- ifNotUndefined(
1640
- getRelationship(relationshipId),
1641
- ([remoteRows, , linkedRowsCache]) => {
1642
- if (!collHas(linkedRowsCache, firstRowId)) {
1643
- const linkedRows = setNew();
1644
- if (
1645
- getLocalTableId(relationshipId) != getRemoteTableId(relationshipId)
1646
- ) {
1647
- setAdd(linkedRows, firstRowId);
1648
- } else {
1649
- let rowId = firstRowId;
1650
- while (!isUndefined(rowId) && !collHas(linkedRows, rowId)) {
1651
- setAdd(linkedRows, rowId);
1652
- rowId = mapGet(remoteRows, rowId);
1653
- }
1654
- }
1655
- if (skipCache) {
1656
- return linkedRows;
1657
- }
1658
- mapSet(linkedRowsCache, firstRowId, linkedRows);
1659
- }
1660
- return mapGet(linkedRowsCache, firstRowId);
1661
- },
1662
- );
1663
- const delLinkedRowIdsCache = (relationshipId, firstRowId) =>
1664
- ifNotUndefined(getRelationship(relationshipId), ([, , linkedRowsCache]) =>
1665
- mapSet(linkedRowsCache, firstRowId),
1666
- );
1667
- const setRelationshipDefinition = (
1668
- relationshipId,
1669
- localTableId,
1670
- remoteTableId,
1671
- getRemoteRowId2,
1672
- ) => {
1673
- mapSet(remoteTableIds, relationshipId, remoteTableId);
1674
- setDefinitionAndListen(
1675
- relationshipId,
1676
- localTableId,
1677
- (change, changedRemoteRowIds) => {
1678
- const changedLocalRows = setNew();
1679
- const changedRemoteRows = setNew();
1680
- const changedLinkedRows = setNew();
1681
- const [localRows, remoteRows] = getRelationship(relationshipId);
1682
- collForEach(
1683
- changedRemoteRowIds,
1684
- ([oldRemoteRowId, newRemoteRowId], localRowId) => {
1685
- if (!isUndefined(oldRemoteRowId)) {
1686
- setAdd(changedRemoteRows, oldRemoteRowId);
1687
- ifNotUndefined(
1688
- mapGet(remoteRows, oldRemoteRowId),
1689
- (oldRemoteRow) => {
1690
- collDel(oldRemoteRow, localRowId);
1691
- if (collIsEmpty(oldRemoteRow)) {
1692
- mapSet(remoteRows, oldRemoteRowId);
1693
- }
1694
- },
1695
- );
1696
- }
1697
- if (!isUndefined(newRemoteRowId)) {
1698
- setAdd(changedRemoteRows, newRemoteRowId);
1699
- if (!collHas(remoteRows, newRemoteRowId)) {
1700
- mapSet(remoteRows, newRemoteRowId, setNew());
1701
- }
1702
- setAdd(mapGet(remoteRows, newRemoteRowId), localRowId);
1703
- }
1704
- setAdd(changedLocalRows, localRowId);
1705
- mapSet(localRows, localRowId, newRemoteRowId);
1706
- mapForEach(
1707
- mapGet(linkedRowIdsListeners, relationshipId),
1708
- (firstRowId) => {
1709
- if (
1710
- collHas(
1711
- getLinkedRowIdsCache(relationshipId, firstRowId),
1712
- localRowId,
1713
- )
1714
- ) {
1715
- setAdd(changedLinkedRows, firstRowId);
1716
- }
1717
- },
1718
- );
1719
- },
1720
- );
1721
- change();
1722
- collForEach(changedLocalRows, (localRowId) =>
1723
- callListeners(remoteRowIdListeners, [relationshipId, localRowId]),
1724
- );
1725
- collForEach(changedRemoteRows, (remoteRowId) =>
1726
- callListeners(localRowIdsListeners, [relationshipId, remoteRowId]),
1727
- );
1728
- collForEach(changedLinkedRows, (firstRowId) => {
1729
- delLinkedRowIdsCache(relationshipId, firstRowId);
1730
- callListeners(linkedRowIdsListeners, [relationshipId, firstRowId]);
1731
- });
1732
- },
1733
- getRowCellFunction(getRemoteRowId2),
1734
- );
1735
- return relationships;
1736
- };
1737
- const forEachRelationship = (relationshipCallback) =>
1738
- forEachRelationshipImpl((relationshipId) =>
1739
- relationshipCallback(relationshipId, (rowCallback) =>
1740
- store.forEachRow(getLocalTableId(relationshipId), rowCallback),
1741
- ),
1742
- );
1743
- const delRelationshipDefinition = (relationshipId) => {
1744
- mapSet(remoteTableIds, relationshipId);
1745
- delDefinition(relationshipId);
1746
- return relationships;
1747
- };
1748
- const getRemoteTableId = (relationshipId) =>
1749
- mapGet(remoteTableIds, relationshipId);
1750
- const getRemoteRowId = (relationshipId, localRowId) =>
1751
- mapGet(getRelationship(relationshipId)?.[0], localRowId);
1752
- const getLocalRowIds = (relationshipId, remoteRowId) =>
1753
- collValues(mapGet(getRelationship(relationshipId)?.[1], remoteRowId));
1754
- const getLinkedRowIds = (relationshipId, firstRowId) =>
1755
- isUndefined(getRelationship(relationshipId))
1756
- ? [firstRowId]
1757
- : collValues(getLinkedRowIdsCache(relationshipId, firstRowId, true));
1758
- const addRemoteRowIdListener = (relationshipId, localRowId, listener) =>
1759
- addListener(listener, remoteRowIdListeners, [relationshipId, localRowId]);
1760
- const addLocalRowIdsListener = (relationshipId, remoteRowId, listener) =>
1761
- addListener(listener, localRowIdsListeners, [relationshipId, remoteRowId]);
1762
- const addLinkedRowIdsListener = (relationshipId, firstRowId, listener) => {
1763
- getLinkedRowIdsCache(relationshipId, firstRowId);
1764
- return addListener(listener, linkedRowIdsListeners, [
1765
- relationshipId,
1766
- firstRowId,
1767
- ]);
1768
- };
1769
- const delListener = (listenerId) => {
1770
- delLinkedRowIdsCache(...(delListenerImpl(listenerId) ?? []));
1771
- return relationships;
1772
- };
1773
- const getListenerStats = () => ({
1774
- remoteRowId: collSize3(remoteRowIdListeners),
1775
- localRowIds: collSize3(localRowIdsListeners),
1776
- linkedRowIds: collSize3(linkedRowIdsListeners),
1777
- });
1778
- const relationships = {
1779
- setRelationshipDefinition,
1780
- delRelationshipDefinition,
1781
- getStore,
1782
- getRelationshipIds,
1783
- forEachRelationship,
1784
- hasRelationship,
1785
- getLocalTableId,
1786
- getRemoteTableId,
1787
- getRemoteRowId,
1788
- getLocalRowIds,
1789
- getLinkedRowIds,
1790
- addRelationshipIdsListener,
1791
- addRemoteRowIdListener,
1792
- addLocalRowIdsListener,
1793
- addLinkedRowIdsListener,
1794
- delListener,
1795
- destroy,
1796
- getListenerStats,
1797
- };
1798
- return objFreeze(relationships);
1799
- });
1800
-
1801
- const textEncoder = /* @__PURE__ */ new GLOBAL.TextEncoder();
1802
- const getHash = (value) => {
1803
- let hash = 2166136261;
1804
- arrayForEach(textEncoder.encode(value), (char) => {
1805
- hash ^= char;
1806
- hash +=
1807
- (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
1808
- });
1809
- return hash >>> 0;
1810
- };
1811
-
1812
- const SHIFT36 = 2 ** 36;
1813
- const SHIFT30 = 2 ** 30;
1814
- const SHIFT24 = 2 ** 24;
1815
- const SHIFT18 = 2 ** 18;
1816
- const SHIFT12 = 2 ** 12;
1817
- const SHIFT6 = 2 ** 6;
1818
- const encodeTimeAndCounter = (logicalTime42, counter24) =>
1819
- encode(logicalTime42 / SHIFT36) +
1820
- encode(logicalTime42 / SHIFT30) +
1821
- encode(logicalTime42 / SHIFT24) +
1822
- encode(logicalTime42 / SHIFT18) +
1823
- encode(logicalTime42 / SHIFT12) +
1824
- encode(logicalTime42 / SHIFT6) +
1825
- encode(logicalTime42) +
1826
- encode(counter24 / SHIFT18) +
1827
- encode(counter24 / SHIFT12) +
1828
- encode(counter24 / SHIFT6) +
1829
- encode(counter24);
1830
- const decodeTimeAndCounter = (hlc16) => [
1831
- decode(hlc16, 0) * SHIFT36 +
1832
- decode(hlc16, 1) * SHIFT30 +
1833
- decode(hlc16, 2) * SHIFT24 +
1834
- decode(hlc16, 3) * SHIFT18 +
1835
- decode(hlc16, 4) * SHIFT12 +
1836
- decode(hlc16, 5) * SHIFT6 +
1837
- decode(hlc16, 6),
1838
- decode(hlc16, 7) * SHIFT18 +
1839
- decode(hlc16, 8) * SHIFT12 +
1840
- decode(hlc16, 9) * SHIFT6 +
1841
- decode(hlc16, 10),
1842
- ];
1843
- const getHlcFunctions = (uniqueId) => {
1844
- let logicalTime = 0;
1845
- let lastCounter = -1;
1846
- const clientPart = ifNotUndefined(
1847
- uniqueId,
1848
- (uniqueId2) => {
1849
- const clientHash30 = getHash(uniqueId2);
1850
- return (
1851
- encode(clientHash30 / SHIFT24) +
1852
- encode(clientHash30 / SHIFT18) +
1853
- encode(clientHash30 / SHIFT12) +
1854
- encode(clientHash30 / SHIFT6) +
1855
- encode(clientHash30)
1856
- );
1857
- },
1858
- () => getUniqueId(5),
1859
- );
1860
- const getHlc = () => {
1861
- seenHlc();
1862
- return encodeTimeAndCounter(logicalTime, ++lastCounter) + clientPart;
1863
- };
1864
- const seenHlc = (hlc) => {
1865
- const previousLogicalTime = logicalTime;
1866
- const [remoteLogicalTime, remoteCounter] =
1867
- isUndefined(hlc) || hlc == '' ? [0, 0] : decodeTimeAndCounter(hlc);
1868
- logicalTime = mathMax(
1869
- previousLogicalTime,
1870
- remoteLogicalTime,
1871
- GLOBAL.HLC_TIME ?? Date.now(),
1872
- );
1873
- lastCounter =
1874
- logicalTime == previousLogicalTime
1875
- ? logicalTime == remoteLogicalTime
1876
- ? mathMax(lastCounter, remoteCounter)
1877
- : lastCounter
1878
- : logicalTime == remoteLogicalTime
1879
- ? remoteCounter
1880
- : -1;
1881
- };
1882
- return [getHlc, seenHlc];
1883
- };
1884
-
1885
- const jsonString = JSON.stringify;
1886
- const jsonParse = JSON.parse;
1887
- const jsonStringWithMap = (obj) =>
1888
- jsonString(obj, (_key, value) =>
1889
- isInstanceOf(value, Map) ? object.fromEntries([...value]) : value,
1890
- );
1891
-
1892
- const stampClone = ([value, time]) => stampNew(value, time);
1893
- const stampCloneWithHash = ([value, time, hash]) => [value, time, hash];
1894
- const stampNew = (value, time) => (time ? [value, time] : [value]);
1895
- const stampNewWithHash = (value, time, hash) => [value, time, hash];
1896
- const getStampHash = (stamp) => stamp[2];
1897
- const hashIdAndHash = (id, hash) => getHash(id + ':' + hash);
1898
- const replaceTimeHash = (oldTime, newTime) =>
1899
- newTime > oldTime ? (oldTime ? getHash(oldTime) : 0) ^ getHash(newTime) : 0;
1900
- const getLatestTime = (time1, time2) =>
1901
- /* istanbul ignore next */
1902
- ((time1 ?? '') > (time2 ?? '') ? time1 : time2) ?? '';
1903
- const stampUpdate = (stamp, time, hash) => {
1904
- if (time > stamp[1]) {
1905
- stamp[1] = time;
1906
- }
1907
- stamp[2] = hash >>> 0;
1908
- };
1909
- const stampNewObj = (time = EMPTY_STRING) => stampNew(objNew(), time);
1910
- const stampNewMap = (time = EMPTY_STRING) => [mapNew(), time, 0];
1911
- const stampMapToObjWithHash = (
1912
- [map, time, hash],
1913
- mapper = stampCloneWithHash,
1914
- ) => [mapToObj(map, mapper), time, hash];
1915
- const stampMapToObjWithoutHash = ([map, time], mapper = stampClone) =>
1916
- stampNew(mapToObj(map, mapper), time);
1917
- const stampValidate = (stamp, validateThing) =>
1918
- isArray(stamp) &&
1919
- size(stamp) == 3 &&
1920
- isString(stamp[1]) &&
1921
- getTypeOf(stamp[2]) == NUMBER &&
1922
- isFiniteNumber(stamp[2]) &&
1923
- validateThing(stamp[0]);
1924
-
1925
- const pairNew = (value) => [value, value];
1926
- const pairCollSize2 = (pair, func = collSize2) => func(pair[0]) + func(pair[1]);
1927
- const pairNewMap = () => [mapNew(), mapNew()];
1928
- const pairClone = (array) => [...array];
1929
- const pairIsEqual = ([entry1, entry2]) => entry1 === entry2;
1930
-
1931
- const idsChanged = (changedIds, id2, addedOrRemoved) =>
1932
- mapSet(
1933
- changedIds,
1934
- id2,
1935
- mapGet(changedIds, id2) == -addedOrRemoved ? void 0 : addedOrRemoved,
1936
- );
1937
- const createStore = () => {
1938
- let hasTablesSchema;
1939
- let hasValuesSchema;
1940
- let hadTables = false;
1941
- let hadValues = false;
1942
- let transactions = 0;
1943
- let internalListeners = [];
1944
- const changedTableIds = mapNew();
1945
- const changedTableCellIds = mapNew();
1946
- const changedRowCount = mapNew();
1947
- const changedRowIds = mapNew();
1948
- const changedCellIds = mapNew();
1949
- const changedCells = mapNew();
1950
- const changedValueIds = mapNew();
1951
- const changedValues = mapNew();
1952
- const invalidCells = mapNew();
1953
- const invalidValues = mapNew();
1954
- const tablesSchemaMap = mapNew();
1955
- const tablesSchemaRowCache = mapNew();
1956
- const valuesSchemaMap = mapNew();
1957
- const valuesDefaulted = mapNew();
1958
- const valuesNonDefaulted = setNew();
1959
- const tablePoolFunctions = mapNew();
1960
- const tableCellIds = mapNew();
1961
- const tablesMap = mapNew();
1962
- const valuesMap = mapNew();
1963
- const hasTablesListeners = pairNewMap();
1964
- const tablesListeners = pairNewMap();
1965
- const tableIdsListeners = pairNewMap();
1966
- const hasTableListeners = pairNewMap();
1967
- const tableListeners = pairNewMap();
1968
- const tableCellIdsListeners = pairNewMap();
1969
- const hasTableCellListeners = pairNewMap();
1970
- const rowCountListeners = pairNewMap();
1971
- const rowIdsListeners = pairNewMap();
1972
- const sortedRowIdsListeners = pairNewMap();
1973
- const hasRowListeners = pairNewMap();
1974
- const rowListeners = pairNewMap();
1975
- const cellIdsListeners = pairNewMap();
1976
- const hasCellListeners = pairNewMap();
1977
- const cellListeners = pairNewMap();
1978
- const invalidCellListeners = pairNewMap();
1979
- const invalidValueListeners = pairNewMap();
1980
- const hasValuesListeners = pairNewMap();
1981
- const valuesListeners = pairNewMap();
1982
- const valueIdsListeners = pairNewMap();
1983
- const hasValueListeners = pairNewMap();
1984
- const valueListeners = pairNewMap();
1985
- const startTransactionListeners = mapNew();
1986
- const finishTransactionListeners = pairNewMap();
1987
- const [addListener, callListeners, delListenerImpl, callListenerImpl] =
1988
- getListenerFunctions(() => store);
1989
- const validateTablesSchema = (tableSchema) =>
1990
- objValidate(tableSchema, (tableSchema2) =>
1991
- objValidate(tableSchema2, validateCellOrValueSchema),
1992
- );
1993
- const validateValuesSchema = (valuesSchema) =>
1994
- objValidate(valuesSchema, validateCellOrValueSchema);
1995
- const validateCellOrValueSchema = (schema) => {
1996
- if (!objValidate(schema, (_child, id2) => arrayHas([TYPE, DEFAULT], id2))) {
1997
- return false;
1998
- }
1999
- const type = schema[TYPE];
2000
- if (!isTypeStringOrBoolean(type) && type != NUMBER) {
2001
- return false;
2002
- }
2003
- if (getCellOrValueType(schema[DEFAULT]) != type) {
2004
- objDel(schema, DEFAULT);
2005
- }
2006
- return true;
2007
- };
2008
- const validateContent = isArray;
2009
- const validateTables = (tables) =>
2010
- objValidate(tables, validateTable, cellInvalid);
2011
- const validateTable = (table, tableId) =>
2012
- (!hasTablesSchema ||
2013
- collHas(tablesSchemaMap, tableId) ||
2014
- /* istanbul ignore next */
2015
- cellInvalid(tableId)) &&
2016
- objValidate(
2017
- table,
2018
- (row, rowId) => validateRow(tableId, rowId, row),
2019
- () => cellInvalid(tableId),
2020
- );
2021
- const validateRow = (tableId, rowId, row, skipDefaults) =>
2022
- objValidate(
2023
- skipDefaults ? row : addDefaultsToRow(row, tableId, rowId),
2024
- (cell, cellId) =>
2025
- ifNotUndefined(
2026
- getValidatedCell(tableId, rowId, cellId, cell),
2027
- (validCell) => {
2028
- row[cellId] = validCell;
2029
- return true;
2030
- },
2031
- () => false,
2032
- ),
2033
- () => cellInvalid(tableId, rowId),
2034
- );
2035
- const getValidatedCell = (tableId, rowId, cellId, cell) =>
2036
- hasTablesSchema
2037
- ? ifNotUndefined(
2038
- mapGet(mapGet(tablesSchemaMap, tableId), cellId),
2039
- (cellSchema) =>
2040
- getCellOrValueType(cell) != cellSchema[TYPE]
2041
- ? cellInvalid(tableId, rowId, cellId, cell, cellSchema[DEFAULT])
2042
- : cell,
2043
- () => cellInvalid(tableId, rowId, cellId, cell),
2044
- )
2045
- : isUndefined(getCellOrValueType(cell))
2046
- ? cellInvalid(tableId, rowId, cellId, cell)
2047
- : cell;
2048
- const validateValues = (values, skipDefaults) =>
2049
- objValidate(
2050
- skipDefaults ? values : addDefaultsToValues(values),
2051
- (value, valueId) =>
2052
- ifNotUndefined(
2053
- getValidatedValue(valueId, value),
2054
- (validValue) => {
2055
- values[valueId] = validValue;
2056
- return true;
2057
- },
2058
- () => false,
2059
- ),
2060
- () => valueInvalid(),
2061
- );
2062
- const getValidatedValue = (valueId, value) =>
2063
- hasValuesSchema
2064
- ? ifNotUndefined(
2065
- mapGet(valuesSchemaMap, valueId),
2066
- (valueSchema) =>
2067
- getCellOrValueType(value) != valueSchema[TYPE]
2068
- ? valueInvalid(valueId, value, valueSchema[DEFAULT])
2069
- : value,
2070
- () => valueInvalid(valueId, value),
2071
- )
2072
- : isUndefined(getCellOrValueType(value))
2073
- ? valueInvalid(valueId, value)
2074
- : value;
2075
- const addDefaultsToRow = (row, tableId, rowId) => {
2076
- ifNotUndefined(
2077
- mapGet(tablesSchemaRowCache, tableId),
2078
- ([rowDefaulted, rowNonDefaulted]) => {
2079
- collForEach(rowDefaulted, (cell, cellId) => {
2080
- if (!objHas(row, cellId)) {
2081
- row[cellId] = cell;
2082
- }
2083
- });
2084
- collForEach(rowNonDefaulted, (cellId) => {
2085
- if (!objHas(row, cellId)) {
2086
- cellInvalid(tableId, rowId, cellId);
2087
- }
2088
- });
2089
- },
2090
- );
2091
- return row;
1282
+ return row;
2092
1283
  };
2093
1284
  const addDefaultsToValues = (values) => {
2094
1285
  if (hasValuesSchema) {
@@ -3238,508 +2429,1329 @@ const createStore = () => {
3238
2429
  [VALUE_IDS]: [0, valueIdsListeners],
3239
2430
  [HAS + VALUE]: [
3240
2431
  1,
3241
- hasValueListeners,
3242
- [getValueIds],
3243
- (ids) => [hasValue(...ids)],
3244
- ],
3245
- [VALUE]: [
2432
+ hasValueListeners,
2433
+ [getValueIds],
2434
+ (ids) => [hasValue(...ids)],
2435
+ ],
2436
+ [VALUE]: [
2437
+ 1,
2438
+ valueListeners,
2439
+ [getValueIds],
2440
+ (ids) => pairNew(getValue(ids[0])),
2441
+ ],
2442
+ InvalidValue: [1, invalidValueListeners],
2443
+ },
2444
+ ([argumentCount, idSetNode, pathGetters, extraArgsGetter], listenable) => {
2445
+ store[ADD + listenable + LISTENER] = (...args) =>
2446
+ addListener(
2447
+ args[argumentCount],
2448
+ idSetNode[args[argumentCount + 1] ? 1 : 0],
2449
+ argumentCount > 0 ? slice(args, 0, argumentCount) : void 0,
2450
+ pathGetters,
2451
+ extraArgsGetter,
2452
+ );
2453
+ },
2454
+ );
2455
+ return objFreeze(store);
2456
+ };
2457
+
2458
+ const LISTENER_ARGS = {
2459
+ HasTable: 1,
2460
+ Table: 1,
2461
+ TableCellIds: 1,
2462
+ HasTableCell: 2,
2463
+ RowCount: 1,
2464
+ RowIds: 1,
2465
+ SortedRowIds: 5,
2466
+ HasRow: 2,
2467
+ Row: 2,
2468
+ CellIds: 2,
2469
+ HasCell: 3,
2470
+ Cell: 3,
2471
+ HasValue: 1,
2472
+ Value: 1,
2473
+ InvalidCell: 3,
2474
+ InvalidValue: 1,
2475
+ };
2476
+ const newContentStampMap = (time = EMPTY_STRING) => [
2477
+ stampNewMap(time),
2478
+ stampNewMap(time),
2479
+ ];
2480
+ const validateMergeableContent = (mergeableContent) =>
2481
+ isArray(mergeableContent) &&
2482
+ size(mergeableContent) == 2 &&
2483
+ stampValidate(mergeableContent[0], (tableStamps) =>
2484
+ objValidate(
2485
+ tableStamps,
2486
+ (tableStamp) =>
2487
+ stampValidate(tableStamp, (rowStamps) =>
2488
+ objValidate(
2489
+ rowStamps,
2490
+ (rowStamp) =>
2491
+ stampValidate(rowStamp, (cellStamps) =>
2492
+ objValidate(
2493
+ cellStamps,
2494
+ (cellStamp) =>
2495
+ stampValidate(cellStamp, isCellOrValueOrNullOrUndefined),
2496
+ void 0,
2497
+ 1,
2498
+ ),
2499
+ ),
2500
+ void 0,
2501
+ 1,
2502
+ ),
2503
+ ),
2504
+ void 0,
2505
+ 1,
2506
+ ),
2507
+ ) &&
2508
+ stampValidate(mergeableContent[1], (values) =>
2509
+ objValidate(
2510
+ values,
2511
+ (value) => stampValidate(value, isCellOrValueOrNullOrUndefined),
2512
+ void 0,
2513
+ 1,
2514
+ ),
2515
+ );
2516
+ const createMergeableStore = (uniqueId) => {
2517
+ let listeningToRawStoreChanges = 1;
2518
+ let contentStampMap = newContentStampMap();
2519
+ let defaultingContent = 0;
2520
+ const touchedCells = mapNew();
2521
+ const touchedValues = setNew();
2522
+ const [getHlc, seenHlc] = getHlcFunctions(uniqueId);
2523
+ const store = createStore();
2524
+ const disableListeningToRawStoreChanges = (actions) => {
2525
+ const wasListening = listeningToRawStoreChanges;
2526
+ listeningToRawStoreChanges = 0;
2527
+ actions();
2528
+ listeningToRawStoreChanges = wasListening;
2529
+ return mergeableStore;
2530
+ };
2531
+ const mergeContentOrChanges = (contentOrChanges, isContent = 0) => {
2532
+ const tablesChanges = {};
2533
+ const valuesChanges = {};
2534
+ const [
2535
+ [tablesObj, incomingTablesTime = EMPTY_STRING, incomingTablesHash = 0],
2536
+ values,
2537
+ ] = contentOrChanges;
2538
+ const [tablesStampMap, valuesStampMap] = contentStampMap;
2539
+ const [tableStampMaps, oldTablesTime, oldTablesHash] = tablesStampMap;
2540
+ let tablesHash = isContent ? incomingTablesHash : oldTablesHash;
2541
+ let tablesTime = incomingTablesTime;
2542
+ objForEach(
2543
+ tablesObj,
2544
+ (
2545
+ [rowsObj, incomingTableTime = EMPTY_STRING, incomingTableHash = 0],
2546
+ tableId,
2547
+ ) => {
2548
+ const tableStampMap = mapEnsure(tableStampMaps, tableId, stampNewMap);
2549
+ const [rowStampMaps, oldTableTime, oldTableHash] = tableStampMap;
2550
+ let tableHash = isContent ? incomingTableHash : oldTableHash;
2551
+ let tableTime = incomingTableTime;
2552
+ objForEach(rowsObj, (row, rowId) => {
2553
+ const [rowTime, oldRowHash, rowHash] = mergeCellsOrValues(
2554
+ row,
2555
+ mapEnsure(rowStampMaps, rowId, stampNewMap),
2556
+ objEnsure(objEnsure(tablesChanges, tableId, objNew), rowId, objNew),
2557
+ isContent,
2558
+ );
2559
+ tableHash ^= isContent
2560
+ ? 0
2561
+ : (oldRowHash ? hashIdAndHash(rowId, oldRowHash) : 0) ^
2562
+ hashIdAndHash(rowId, rowHash);
2563
+ tableTime = getLatestTime(tableTime, rowTime);
2564
+ });
2565
+ tableHash ^= isContent
2566
+ ? 0
2567
+ : replaceTimeHash(oldTableTime, incomingTableTime);
2568
+ stampUpdate(tableStampMap, incomingTableTime, tableHash);
2569
+ tablesHash ^= isContent
2570
+ ? 0
2571
+ : (oldTableHash ? hashIdAndHash(tableId, oldTableHash) : 0) ^
2572
+ hashIdAndHash(tableId, tableStampMap[2]);
2573
+ tablesTime = getLatestTime(tablesTime, tableTime);
2574
+ },
2575
+ );
2576
+ tablesHash ^= isContent
2577
+ ? 0
2578
+ : replaceTimeHash(oldTablesTime, incomingTablesTime);
2579
+ stampUpdate(tablesStampMap, incomingTablesTime, tablesHash);
2580
+ const [valuesTime] = mergeCellsOrValues(
2581
+ values,
2582
+ valuesStampMap,
2583
+ valuesChanges,
2584
+ isContent,
2585
+ );
2586
+ seenHlc(getLatestTime(tablesTime, valuesTime));
2587
+ return [tablesChanges, valuesChanges, 1];
2588
+ };
2589
+ const mergeCellsOrValues = (
2590
+ things,
2591
+ thingsStampMap,
2592
+ thingsChanges,
2593
+ isContent,
2594
+ ) => {
2595
+ const [
2596
+ thingsObj,
2597
+ incomingThingsTime = EMPTY_STRING,
2598
+ incomingThingsHash = 0,
2599
+ ] = things;
2600
+ const [thingStampMaps, oldThingsTime, oldThingsHash] = thingsStampMap;
2601
+ let thingsTime = incomingThingsTime;
2602
+ let thingsHash = isContent ? incomingThingsHash : oldThingsHash;
2603
+ objForEach(
2604
+ thingsObj,
2605
+ ([thing, thingTime = EMPTY_STRING, incomingThingHash = 0], thingId) => {
2606
+ const thingStampMap = mapEnsure(thingStampMaps, thingId, () => [
2607
+ void 0,
2608
+ EMPTY_STRING,
2609
+ 0,
2610
+ ]);
2611
+ const [, oldThingTime, oldThingHash] = thingStampMap;
2612
+ if (!oldThingTime || thingTime > oldThingTime) {
2613
+ stampUpdate(
2614
+ thingStampMap,
2615
+ thingTime,
2616
+ isContent
2617
+ ? incomingThingHash
2618
+ : getHash(jsonStringWithMap(thing ?? null) + ':' + thingTime),
2619
+ );
2620
+ thingStampMap[0] = thing;
2621
+ thingsChanges[thingId] = thing;
2622
+ thingsHash ^= isContent
2623
+ ? 0
2624
+ : hashIdAndHash(thingId, oldThingHash) ^
2625
+ hashIdAndHash(thingId, thingStampMap[2]);
2626
+ thingsTime = getLatestTime(thingsTime, thingTime);
2627
+ }
2628
+ },
2629
+ );
2630
+ thingsHash ^= isContent
2631
+ ? 0
2632
+ : replaceTimeHash(oldThingsTime, incomingThingsTime);
2633
+ stampUpdate(thingsStampMap, incomingThingsTime, thingsHash);
2634
+ return [thingsTime, oldThingsHash, thingsStampMap[2]];
2635
+ };
2636
+ const preStartTransaction = () => {};
2637
+ const preFinishTransaction = () => {};
2638
+ const postFinishTransaction = () => {
2639
+ collClear(touchedCells);
2640
+ collClear(touchedValues);
2641
+ };
2642
+ const cellChanged = (tableId, rowId, cellId, newCell) => {
2643
+ setAdd(
2644
+ mapEnsure(mapEnsure(touchedCells, tableId, mapNew), rowId, setNew),
2645
+ cellId,
2646
+ );
2647
+ if (listeningToRawStoreChanges) {
2648
+ mergeContentOrChanges([
2649
+ [
2650
+ {
2651
+ [tableId]: [
2652
+ {
2653
+ [rowId]: [
2654
+ {
2655
+ [cellId]: [
2656
+ newCell,
2657
+ defaultingContent ? EMPTY_STRING : getHlc(),
2658
+ ],
2659
+ },
2660
+ ],
2661
+ },
2662
+ ],
2663
+ },
2664
+ ],
2665
+ [{}],
2666
+ 1,
2667
+ ]);
2668
+ }
2669
+ };
2670
+ const valueChanged = (valueId, newValue) => {
2671
+ setAdd(touchedValues, valueId);
2672
+ if (listeningToRawStoreChanges) {
2673
+ mergeContentOrChanges([
2674
+ [{}],
2675
+ [{[valueId]: [newValue, defaultingContent ? EMPTY_STRING : getHlc()]}],
3246
2676
  1,
3247
- valueListeners,
3248
- [getValueIds],
3249
- (ids) => pairNew(getValue(ids[0])),
3250
- ],
3251
- InvalidValue: [1, invalidValueListeners],
3252
- },
3253
- ([argumentCount, idSetNode, pathGetters, extraArgsGetter], listenable) => {
3254
- store[ADD + listenable + LISTENER] = (...args) =>
3255
- addListener(
3256
- args[argumentCount],
3257
- idSetNode[args[argumentCount + 1] ? 1 : 0],
3258
- argumentCount > 0 ? slice(args, 0, argumentCount) : void 0,
3259
- pathGetters,
3260
- extraArgsGetter,
3261
- );
3262
- },
3263
- );
3264
- return objFreeze(store);
3265
- };
3266
-
3267
- const LISTENER_ARGS = {
3268
- HasTable: 1,
3269
- Table: 1,
3270
- TableCellIds: 1,
3271
- HasTableCell: 2,
3272
- RowCount: 1,
3273
- RowIds: 1,
3274
- SortedRowIds: 5,
3275
- HasRow: 2,
3276
- Row: 2,
3277
- CellIds: 2,
3278
- HasCell: 3,
3279
- Cell: 3,
3280
- HasValue: 1,
3281
- Value: 1,
3282
- InvalidCell: 3,
3283
- InvalidValue: 1,
3284
- };
3285
- const newContentStampMap = (time = EMPTY_STRING) => [
3286
- stampNewMap(time),
3287
- stampNewMap(time),
3288
- ];
3289
- const validateMergeableContent = (mergeableContent) =>
3290
- isArray(mergeableContent) &&
3291
- size(mergeableContent) == 2 &&
3292
- stampValidate(mergeableContent[0], (tableStamps) =>
3293
- objValidate(
3294
- tableStamps,
3295
- (tableStamp) =>
3296
- stampValidate(tableStamp, (rowStamps) =>
3297
- objValidate(
3298
- rowStamps,
3299
- (rowStamp) =>
3300
- stampValidate(rowStamp, (cellStamps) =>
3301
- objValidate(
3302
- cellStamps,
3303
- (cellStamp) =>
3304
- stampValidate(cellStamp, isCellOrValueOrNullOrUndefined),
3305
- void 0,
3306
- 1,
3307
- ),
3308
- ),
3309
- void 0,
3310
- 1,
2677
+ ]);
2678
+ }
2679
+ };
2680
+ const getMergeableContent = () => [
2681
+ stampMapToObjWithHash(contentStampMap[0], (tableStampMap) =>
2682
+ stampMapToObjWithHash(tableStampMap, (rowStampMap) =>
2683
+ stampMapToObjWithHash(rowStampMap),
2684
+ ),
2685
+ ),
2686
+ stampMapToObjWithHash(contentStampMap[1]),
2687
+ ];
2688
+ const getMergeableContentHashes = () => [
2689
+ contentStampMap[0][2],
2690
+ contentStampMap[1][2],
2691
+ ];
2692
+ const getMergeableTableHashes = () =>
2693
+ mapToObj(contentStampMap[0][0], getStampHash);
2694
+ const getMergeableTableDiff = (otherTableHashes) => {
2695
+ const newTables = stampNewObj(contentStampMap[0][1]);
2696
+ const differingTableHashes = {};
2697
+ mapForEach(
2698
+ contentStampMap[0][0],
2699
+ (tableId, [tableStampMap, tableTime, hash]) =>
2700
+ objHas(otherTableHashes, tableId)
2701
+ ? hash != otherTableHashes[tableId]
2702
+ ? (differingTableHashes[tableId] = hash)
2703
+ : 0
2704
+ : (newTables[0][tableId] = stampMapToObjWithoutHash(
2705
+ [tableStampMap, tableTime],
2706
+ (rowStampMap) => stampMapToObjWithoutHash(rowStampMap),
2707
+ )),
2708
+ );
2709
+ return [newTables, differingTableHashes];
2710
+ };
2711
+ const getMergeableRowHashes = (otherTableHashes) => {
2712
+ const rowHashes = {};
2713
+ objForEach(otherTableHashes, (otherTableHash, tableId) =>
2714
+ ifNotUndefined(
2715
+ mapGet(contentStampMap[0][0], tableId),
2716
+ ([rowStampMaps, , tableHash]) =>
2717
+ tableHash != otherTableHash
2718
+ ? mapForEach(
2719
+ rowStampMaps,
2720
+ (rowId, [, , rowHash]) =>
2721
+ (objEnsure(rowHashes, tableId, objNew)[rowId] = rowHash),
2722
+ )
2723
+ : 0,
2724
+ ),
2725
+ );
2726
+ return rowHashes;
2727
+ };
2728
+ const getMergeableRowDiff = (otherTableRowHashes) => {
2729
+ const newRows = stampNewObj(contentStampMap[0][1]);
2730
+ const differingRowHashes = {};
2731
+ objForEach(otherTableRowHashes, (otherRowHashes, tableId) =>
2732
+ mapForEach(
2733
+ mapGet(contentStampMap[0][0], tableId)?.[0],
2734
+ (rowId, [rowStampMap, rowTime, hash]) =>
2735
+ objHas(otherRowHashes, rowId)
2736
+ ? hash !== otherRowHashes[rowId]
2737
+ ? (objEnsure(differingRowHashes, tableId, objNew)[rowId] = hash)
2738
+ : 0
2739
+ : (objEnsure(newRows[0], tableId, stampNewObj)[0][rowId] =
2740
+ stampMapToObjWithoutHash([rowStampMap, rowTime])),
2741
+ ),
2742
+ );
2743
+ return [newRows, differingRowHashes];
2744
+ };
2745
+ const getMergeableCellHashes = (otherTableRowHashes) => {
2746
+ const cellHashes = {};
2747
+ objForEach(otherTableRowHashes, (otherRowHashes, tableId) =>
2748
+ ifNotUndefined(mapGet(contentStampMap[0][0], tableId), ([rowStampMaps]) =>
2749
+ objForEach(otherRowHashes, (otherRowHash, rowId) =>
2750
+ ifNotUndefined(
2751
+ mapGet(rowStampMaps, rowId),
2752
+ ([cellStampMaps, , rowHash]) =>
2753
+ rowHash !== otherRowHash
2754
+ ? mapForEach(
2755
+ cellStampMaps,
2756
+ (cellId, [, , cellHash]) =>
2757
+ (objEnsure(
2758
+ objEnsure(cellHashes, tableId, objNew),
2759
+ rowId,
2760
+ objNew,
2761
+ )[cellId] = cellHash),
2762
+ )
2763
+ : 0,
3311
2764
  ),
3312
2765
  ),
3313
- void 0,
3314
- 1,
3315
- ),
3316
- ) &&
3317
- stampValidate(mergeableContent[1], (values) =>
3318
- objValidate(
3319
- values,
3320
- (value) => stampValidate(value, isCellOrValueOrNullOrUndefined),
3321
- void 0,
3322
- 1,
3323
- ),
3324
- );
3325
- const createMergeableStore = (uniqueId) => {
3326
- let listeningToRawStoreChanges = 1;
3327
- let contentStampMap = newContentStampMap();
3328
- let defaultingContent = 0;
3329
- const touchedCells = mapNew();
3330
- const touchedValues = setNew();
3331
- const [getHlc, seenHlc] = getHlcFunctions(uniqueId);
3332
- const store = createStore();
3333
- const disableListeningToRawStoreChanges = (actions) => {
3334
- const wasListening = listeningToRawStoreChanges;
3335
- listeningToRawStoreChanges = 0;
3336
- actions();
3337
- listeningToRawStoreChanges = wasListening;
2766
+ ),
2767
+ );
2768
+ return cellHashes;
2769
+ };
2770
+ const getMergeableCellDiff = (otherTableRowCellHashes) => {
2771
+ const [[tableStampMaps, tablesTime]] = contentStampMap;
2772
+ const tablesObj = {};
2773
+ objForEach(otherTableRowCellHashes, (otherRowCellHashes, tableId) =>
2774
+ objForEach(otherRowCellHashes, (otherCellHashes, rowId) =>
2775
+ ifNotUndefined(
2776
+ mapGet(tableStampMaps, tableId),
2777
+ ([rowStampMaps, tableTime]) =>
2778
+ ifNotUndefined(
2779
+ mapGet(rowStampMaps, rowId),
2780
+ ([cellStampMaps, rowTime]) =>
2781
+ mapForEach(cellStampMaps, (cellId, [cell, cellTime, hash]) =>
2782
+ hash !== otherCellHashes[cellId]
2783
+ ? (objEnsure(
2784
+ objEnsure(tablesObj, tableId, () =>
2785
+ stampNewObj(tableTime),
2786
+ )[0],
2787
+ rowId,
2788
+ () => stampNewObj(rowTime),
2789
+ )[0][cellId] = [cell, cellTime])
2790
+ : 0,
2791
+ ),
2792
+ ),
2793
+ ),
2794
+ ),
2795
+ );
2796
+ return stampNew(tablesObj, tablesTime);
2797
+ };
2798
+ const getMergeableValueHashes = () =>
2799
+ mapToObj(contentStampMap[1][0], getStampHash);
2800
+ const getMergeableValueDiff = (otherValueHashes) => {
2801
+ const [, [valueStampMaps, valuesTime]] = contentStampMap;
2802
+ const values = mapToObj(
2803
+ valueStampMaps,
2804
+ stampClone,
2805
+ ([, , hash], valueId) => hash == otherValueHashes?.[valueId],
2806
+ );
2807
+ return stampNew(values, valuesTime);
2808
+ };
2809
+ const setMergeableContent = (mergeableContent) =>
2810
+ disableListeningToRawStoreChanges(() =>
2811
+ validateMergeableContent(mergeableContent)
2812
+ ? store.transaction(() => {
2813
+ store.delTables().delValues();
2814
+ contentStampMap = newContentStampMap();
2815
+ store.applyChanges(mergeContentOrChanges(mergeableContent, 1));
2816
+ })
2817
+ : 0,
2818
+ );
2819
+ const setDefaultContent = (content) => {
2820
+ store.transaction(() => {
2821
+ defaultingContent = 1;
2822
+ store.setContent(content);
2823
+ defaultingContent = 0;
2824
+ });
3338
2825
  return mergeableStore;
3339
2826
  };
3340
- const mergeContentOrChanges = (contentOrChanges, isContent = 0) => {
3341
- const tablesChanges = {};
3342
- const valuesChanges = {};
2827
+ const getTransactionMergeableChanges = (withHashes = false) => {
3343
2828
  const [
3344
- [tablesObj, incomingTablesTime = EMPTY_STRING, incomingTablesHash = 0],
3345
- values,
3346
- ] = contentOrChanges;
3347
- const [tablesStampMap, valuesStampMap] = contentStampMap;
3348
- const [tableStampMaps, oldTablesTime, oldTablesHash] = tablesStampMap;
3349
- let tablesHash = isContent ? incomingTablesHash : oldTablesHash;
3350
- let tablesTime = incomingTablesTime;
3351
- objForEach(
3352
- tablesObj,
3353
- (
3354
- [rowsObj, incomingTableTime = EMPTY_STRING, incomingTableHash = 0],
3355
- tableId,
3356
- ) => {
3357
- const tableStampMap = mapEnsure(tableStampMaps, tableId, stampNewMap);
3358
- const [rowStampMaps, oldTableTime, oldTableHash] = tableStampMap;
3359
- let tableHash = isContent ? incomingTableHash : oldTableHash;
3360
- let tableTime = incomingTableTime;
3361
- objForEach(rowsObj, (row, rowId) => {
3362
- const [rowTime, oldRowHash, rowHash] = mergeCellsOrValues(
3363
- row,
3364
- mapEnsure(rowStampMaps, rowId, stampNewMap),
3365
- objEnsure(objEnsure(tablesChanges, tableId, objNew), rowId, objNew),
3366
- isContent,
2829
+ [tableStampMaps, tablesTime, tablesHash],
2830
+ [valueStampMaps, valuesTime, valuesHash],
2831
+ ] = contentStampMap;
2832
+ const newStamp = withHashes ? stampNewWithHash : stampNew;
2833
+ const tablesObj = {};
2834
+ collForEach(touchedCells, (touchedTable, tableId) =>
2835
+ ifNotUndefined(
2836
+ mapGet(tableStampMaps, tableId),
2837
+ ([rowStampMaps, tableTime, tableHash]) => {
2838
+ const tableObj = {};
2839
+ collForEach(touchedTable, (touchedRow, rowId) =>
2840
+ ifNotUndefined(
2841
+ mapGet(rowStampMaps, rowId),
2842
+ ([cellStampMaps, rowTime, rowHash]) => {
2843
+ const rowObj = {};
2844
+ collForEach(touchedRow, (cellId) => {
2845
+ ifNotUndefined(
2846
+ mapGet(cellStampMaps, cellId),
2847
+ ([cell, time, hash]) =>
2848
+ (rowObj[cellId] = newStamp(cell, time, hash)),
2849
+ );
2850
+ });
2851
+ tableObj[rowId] = newStamp(rowObj, rowTime, rowHash);
2852
+ },
2853
+ ),
3367
2854
  );
3368
- tableHash ^= isContent
3369
- ? 0
3370
- : (oldRowHash ? hashIdAndHash(rowId, oldRowHash) : 0) ^
3371
- hashIdAndHash(rowId, rowHash);
3372
- tableTime = getLatestTime(tableTime, rowTime);
3373
- });
3374
- tableHash ^= isContent
3375
- ? 0
3376
- : replaceTimeHash(oldTableTime, incomingTableTime);
3377
- stampUpdate(tableStampMap, incomingTableTime, tableHash);
3378
- tablesHash ^= isContent
3379
- ? 0
3380
- : (oldTableHash ? hashIdAndHash(tableId, oldTableHash) : 0) ^
3381
- hashIdAndHash(tableId, tableStampMap[2]);
3382
- tablesTime = getLatestTime(tablesTime, tableTime);
3383
- },
2855
+ tablesObj[tableId] = newStamp(tableObj, tableTime, tableHash);
2856
+ },
2857
+ ),
3384
2858
  );
3385
- tablesHash ^= isContent
3386
- ? 0
3387
- : replaceTimeHash(oldTablesTime, incomingTablesTime);
3388
- stampUpdate(tablesStampMap, incomingTablesTime, tablesHash);
3389
- const [valuesTime] = mergeCellsOrValues(
3390
- values,
3391
- valuesStampMap,
3392
- valuesChanges,
3393
- isContent,
2859
+ const valuesObj = {};
2860
+ collForEach(touchedValues, (valueId) =>
2861
+ ifNotUndefined(
2862
+ mapGet(valueStampMaps, valueId),
2863
+ ([value, time, hash]) =>
2864
+ (valuesObj[valueId] = newStamp(value, time, hash)),
2865
+ ),
3394
2866
  );
3395
- seenHlc(getLatestTime(tablesTime, valuesTime));
3396
- return [tablesChanges, valuesChanges, 1];
2867
+ return [
2868
+ newStamp(tablesObj, tablesTime, tablesHash),
2869
+ newStamp(valuesObj, valuesTime, valuesHash),
2870
+ 1,
2871
+ ];
3397
2872
  };
3398
- const mergeCellsOrValues = (
3399
- things,
3400
- thingsStampMap,
3401
- thingsChanges,
3402
- isContent,
2873
+ const applyMergeableChanges = (mergeableChanges) =>
2874
+ disableListeningToRawStoreChanges(() =>
2875
+ store.applyChanges(mergeContentOrChanges(mergeableChanges)),
2876
+ );
2877
+ const merge = (mergeableStore2) => {
2878
+ const mergeableChanges = getMergeableContent();
2879
+ const mergeableChanges2 = mergeableStore2.getMergeableContent();
2880
+ mergeableStore2.applyMergeableChanges(mergeableChanges);
2881
+ return applyMergeableChanges(mergeableChanges2);
2882
+ };
2883
+ const mergeableStore = {
2884
+ getMergeableContent,
2885
+ getMergeableContentHashes,
2886
+ getMergeableTableHashes,
2887
+ getMergeableTableDiff,
2888
+ getMergeableRowHashes,
2889
+ getMergeableRowDiff,
2890
+ getMergeableCellHashes,
2891
+ getMergeableCellDiff,
2892
+ getMergeableValueHashes,
2893
+ getMergeableValueDiff,
2894
+ setMergeableContent,
2895
+ setDefaultContent,
2896
+ getTransactionMergeableChanges,
2897
+ applyMergeableChanges,
2898
+ merge,
2899
+ };
2900
+ store.setInternalListeners(
2901
+ preStartTransaction,
2902
+ preFinishTransaction,
2903
+ postFinishTransaction,
2904
+ cellChanged,
2905
+ valueChanged,
2906
+ );
2907
+ objMap(
2908
+ store,
2909
+ (method, name) =>
2910
+ (mergeableStore[name] = // fluent methods
2911
+ strStartsWith(name, SET) ||
2912
+ strStartsWith(name, DEL) ||
2913
+ strStartsWith(name, 'apply') ||
2914
+ strEndsWith(name, TRANSACTION) ||
2915
+ name == 'call' + LISTENER
2916
+ ? (...args) => {
2917
+ method(...args);
2918
+ return mergeableStore;
2919
+ }
2920
+ : strStartsWith(name, ADD) && strEndsWith(name, LISTENER)
2921
+ ? (...args) => {
2922
+ const listenerArg = LISTENER_ARGS[slice(name, 3, -8)] ?? 0;
2923
+ const listener = args[listenerArg];
2924
+ args[listenerArg] = (_store, ...args2) =>
2925
+ listener(mergeableStore, ...args2);
2926
+ return method(...args);
2927
+ }
2928
+ : name == 'isMergeable'
2929
+ ? () => true
2930
+ : method),
2931
+ );
2932
+ return objFreeze(mergeableStore);
2933
+ };
2934
+
2935
+ const numericAggregators = /* @__PURE__ */ mapNew([
2936
+ [
2937
+ AVG,
2938
+ [
2939
+ (numbers, length) => arraySum(numbers) / length,
2940
+ (metric, add, length) => metric + (add - metric) / (length + 1),
2941
+ (metric, remove, length) => metric + (metric - remove) / (length - 1),
2942
+ (metric, add, remove, length) => metric + (add - remove) / length,
2943
+ ],
2944
+ ],
2945
+ [
2946
+ MAX,
2947
+ [
2948
+ (numbers) => mathMax(...numbers),
2949
+ (metric, add) => mathMax(add, metric),
2950
+ (metric, remove) => (remove == metric ? void 0 : metric),
2951
+ (metric, add, remove) =>
2952
+ remove == metric ? void 0 : mathMax(add, metric),
2953
+ ],
2954
+ ],
2955
+ [
2956
+ MIN,
2957
+ [
2958
+ (numbers) => mathMin(...numbers),
2959
+ (metric, add) => mathMin(add, metric),
2960
+ (metric, remove) => (remove == metric ? void 0 : metric),
2961
+ (metric, add, remove) =>
2962
+ remove == metric ? void 0 : mathMin(add, metric),
2963
+ ],
2964
+ ],
2965
+ [
2966
+ SUM,
2967
+ [
2968
+ (numbers) => arraySum(numbers),
2969
+ (metric, add) => metric + add,
2970
+ (metric, remove) => metric - remove,
2971
+ (metric, add, remove) => metric - remove + add,
2972
+ ],
2973
+ ],
2974
+ ]);
2975
+ const getAggregateValue = (
2976
+ aggregateValue,
2977
+ oldLength,
2978
+ newValues,
2979
+ changedValues,
2980
+ aggregators,
2981
+ force = false,
2982
+ ) => {
2983
+ if (collIsEmpty(newValues)) {
2984
+ return void 0;
2985
+ }
2986
+ const [aggregate, aggregateAdd, aggregateRemove, aggregateReplace] =
2987
+ aggregators;
2988
+ force ||= isUndefined(aggregateValue);
2989
+ collForEach(changedValues, ([oldValue, newValue]) => {
2990
+ if (!force) {
2991
+ aggregateValue = isUndefined(oldValue)
2992
+ ? aggregateAdd?.(aggregateValue, newValue, oldLength++)
2993
+ : isUndefined(newValue)
2994
+ ? aggregateRemove?.(aggregateValue, oldValue, oldLength--)
2995
+ : aggregateReplace?.(aggregateValue, newValue, oldValue, oldLength);
2996
+ force ||= isUndefined(aggregateValue);
2997
+ }
2998
+ });
2999
+ return force
3000
+ ? aggregate(collValues(newValues), collSize(newValues))
3001
+ : aggregateValue;
3002
+ };
3003
+
3004
+ const createMetrics = getCreateFunction((store) => {
3005
+ const metricListeners = mapNew();
3006
+ const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
3007
+ () => metrics,
3008
+ );
3009
+ const [
3010
+ getStore,
3011
+ getMetricIds,
3012
+ forEachMetric,
3013
+ hasMetric,
3014
+ getTableId,
3015
+ getMetric,
3016
+ setMetric,
3017
+ ,
3018
+ setDefinitionAndListen,
3019
+ delDefinition,
3020
+ addMetricIdsListener,
3021
+ destroy,
3022
+ ] = getDefinableFunctions(
3023
+ store,
3024
+ getUndefined,
3025
+ (value) =>
3026
+ isNaN(value) ||
3027
+ isUndefined(value) ||
3028
+ value === true ||
3029
+ value === false ||
3030
+ value === EMPTY_STRING
3031
+ ? void 0
3032
+ : value * 1,
3033
+ addListener,
3034
+ callListeners,
3035
+ );
3036
+ const setMetricDefinition = (
3037
+ metricId,
3038
+ tableId,
3039
+ aggregate,
3040
+ getNumber,
3041
+ aggregateAdd,
3042
+ aggregateRemove,
3043
+ aggregateReplace,
3403
3044
  ) => {
3404
- const [
3405
- thingsObj,
3406
- incomingThingsTime = EMPTY_STRING,
3407
- incomingThingsHash = 0,
3408
- ] = things;
3409
- const [thingStampMaps, oldThingsTime, oldThingsHash] = thingsStampMap;
3410
- let thingsTime = incomingThingsTime;
3411
- let thingsHash = isContent ? incomingThingsHash : oldThingsHash;
3412
- objForEach(
3413
- thingsObj,
3414
- ([thing, thingTime = EMPTY_STRING, incomingThingHash = 0], thingId) => {
3415
- const thingStampMap = mapEnsure(thingStampMaps, thingId, () => [
3416
- void 0,
3417
- EMPTY_STRING,
3418
- 0,
3419
- ]);
3420
- const [, oldThingTime, oldThingHash] = thingStampMap;
3421
- if (!oldThingTime || thingTime > oldThingTime) {
3422
- stampUpdate(
3423
- thingStampMap,
3424
- thingTime,
3425
- isContent
3426
- ? incomingThingHash
3427
- : getHash(jsonStringWithMap(thing ?? null) + ':' + thingTime),
3428
- );
3429
- thingStampMap[0] = thing;
3430
- thingsChanges[thingId] = thing;
3431
- thingsHash ^= isContent
3432
- ? 0
3433
- : hashIdAndHash(thingId, oldThingHash) ^
3434
- hashIdAndHash(thingId, thingStampMap[2]);
3435
- thingsTime = getLatestTime(thingsTime, thingTime);
3045
+ const aggregators = isFunction(aggregate)
3046
+ ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
3047
+ : (mapGet(numericAggregators, aggregate) ??
3048
+ mapGet(numericAggregators, SUM));
3049
+ setDefinitionAndListen(
3050
+ metricId,
3051
+ tableId,
3052
+ (change, changedNumbers, _changedSortKeys, numbers, _sortKeys, force) => {
3053
+ const oldMetric = getMetric(metricId);
3054
+ const oldLength = collSize(numbers);
3055
+ force ||= isUndefined(oldMetric);
3056
+ change();
3057
+ let newMetric = getAggregateValue(
3058
+ oldMetric,
3059
+ oldLength,
3060
+ numbers,
3061
+ changedNumbers,
3062
+ aggregators,
3063
+ force,
3064
+ );
3065
+ if (!isFiniteNumber(newMetric)) {
3066
+ newMetric = void 0;
3067
+ }
3068
+ if (newMetric != oldMetric) {
3069
+ setMetric(metricId, newMetric);
3070
+ callListeners(metricListeners, [metricId], newMetric, oldMetric);
3436
3071
  }
3437
3072
  },
3073
+ getRowCellFunction(getNumber, 1),
3438
3074
  );
3439
- thingsHash ^= isContent
3440
- ? 0
3441
- : replaceTimeHash(oldThingsTime, incomingThingsTime);
3442
- stampUpdate(thingsStampMap, incomingThingsTime, thingsHash);
3443
- return [thingsTime, oldThingsHash, thingsStampMap[2]];
3075
+ return metrics;
3444
3076
  };
3445
- const preStartTransaction = () => {};
3446
- const preFinishTransaction = () => {};
3447
- const postFinishTransaction = () => {
3448
- collClear(touchedCells);
3449
- collClear(touchedValues);
3077
+ const delMetricDefinition = (metricId) => {
3078
+ delDefinition(metricId);
3079
+ return metrics;
3450
3080
  };
3451
- const cellChanged = (tableId, rowId, cellId, newCell) => {
3452
- setAdd(
3453
- mapEnsure(mapEnsure(touchedCells, tableId, mapNew), rowId, setNew),
3454
- cellId,
3081
+ const addMetricListener = (metricId, listener) =>
3082
+ addListener(listener, metricListeners, [metricId]);
3083
+ const delListener = (listenerId) => {
3084
+ delListenerImpl(listenerId);
3085
+ return metrics;
3086
+ };
3087
+ const getListenerStats = () => ({
3088
+ metric: collSize2(metricListeners),
3089
+ });
3090
+ const metrics = {
3091
+ setMetricDefinition,
3092
+ delMetricDefinition,
3093
+ getStore,
3094
+ getMetricIds,
3095
+ forEachMetric,
3096
+ hasMetric,
3097
+ getTableId,
3098
+ getMetric,
3099
+ addMetricIdsListener,
3100
+ addMetricListener,
3101
+ delListener,
3102
+ destroy,
3103
+ getListenerStats,
3104
+ };
3105
+ return objFreeze(metrics);
3106
+ });
3107
+
3108
+ const createQueries = getCreateFunction((store) => {
3109
+ const createStore = store.createStore;
3110
+ const preStore = createStore();
3111
+ const resultStore = createStore();
3112
+ const preStoreListenerIds = mapNew();
3113
+ const {
3114
+ addListener,
3115
+ callListeners,
3116
+ delListener: delListenerImpl,
3117
+ } = resultStore;
3118
+ const [
3119
+ getStore,
3120
+ getQueryIds,
3121
+ forEachQuery,
3122
+ hasQuery,
3123
+ getTableId,
3124
+ ,
3125
+ ,
3126
+ setDefinition,
3127
+ ,
3128
+ delDefinition,
3129
+ addQueryIdsListenerImpl,
3130
+ destroy,
3131
+ addStoreListeners,
3132
+ delStoreListeners,
3133
+ ] = getDefinableFunctions(
3134
+ store,
3135
+ () => true,
3136
+ getUndefined,
3137
+ addListener,
3138
+ callListeners,
3139
+ );
3140
+ const addPreStoreListener = (preStore2, queryId, ...listenerIds) =>
3141
+ arrayForEach(listenerIds, (listenerId) =>
3142
+ setAdd(
3143
+ mapEnsure(
3144
+ mapEnsure(preStoreListenerIds, queryId, mapNew),
3145
+ preStore2,
3146
+ setNew,
3147
+ ),
3148
+ listenerId,
3149
+ ),
3150
+ );
3151
+ const resetPreStores = (queryId) => {
3152
+ ifNotUndefined(
3153
+ mapGet(preStoreListenerIds, queryId),
3154
+ (queryPreStoreListenerIds) => {
3155
+ mapForEach(queryPreStoreListenerIds, (preStore2, listenerIds) =>
3156
+ collForEach(listenerIds, (listenerId) =>
3157
+ preStore2.delListener(listenerId),
3158
+ ),
3159
+ );
3160
+ collClear(queryPreStoreListenerIds);
3161
+ },
3162
+ );
3163
+ arrayForEach([resultStore, preStore], (store2) => store2.delTable(queryId));
3164
+ };
3165
+ const synchronizeTransactions = (queryId, fromStore, toStore) =>
3166
+ addPreStoreListener(
3167
+ fromStore,
3168
+ queryId,
3169
+ fromStore.addStartTransactionListener(toStore.startTransaction),
3170
+ fromStore.addDidFinishTransactionListener(() =>
3171
+ toStore.finishTransaction(),
3172
+ ),
3173
+ );
3174
+ const setQueryDefinition = (queryId, tableId, build) => {
3175
+ setDefinition(queryId, tableId);
3176
+ resetPreStores(queryId);
3177
+ const selectEntries = [];
3178
+ const joinEntries = [[null, [tableId, null, null, [], mapNew()]]];
3179
+ const wheres = [];
3180
+ const groupEntries = [];
3181
+ const havings = [];
3182
+ const select = (arg1, arg2) => {
3183
+ const selectEntry = isFunction(arg1)
3184
+ ? [size(selectEntries) + EMPTY_STRING, arg1]
3185
+ : [
3186
+ isUndefined(arg2) ? arg1 : arg2,
3187
+ (getTableCell) => getTableCell(arg1, arg2),
3188
+ ];
3189
+ arrayPush(selectEntries, selectEntry);
3190
+ return {as: (selectedCellId) => (selectEntry[0] = selectedCellId)};
3191
+ };
3192
+ const join = (joinedTableId, arg1, arg2) => {
3193
+ const fromIntermediateJoinedTableId =
3194
+ isUndefined(arg2) || isFunction(arg1) ? null : arg1;
3195
+ const onArg = isUndefined(fromIntermediateJoinedTableId) ? arg1 : arg2;
3196
+ const joinEntry = [
3197
+ joinedTableId,
3198
+ [
3199
+ joinedTableId,
3200
+ fromIntermediateJoinedTableId,
3201
+ isFunction(onArg) ? onArg : (getCell) => getCell(onArg),
3202
+ [],
3203
+ mapNew(),
3204
+ ],
3205
+ ];
3206
+ arrayPush(joinEntries, joinEntry);
3207
+ return {as: (joinedTableId2) => (joinEntry[0] = joinedTableId2)};
3208
+ };
3209
+ const where = (arg1, arg2, arg3) =>
3210
+ arrayPush(
3211
+ wheres,
3212
+ isFunction(arg1)
3213
+ ? arg1
3214
+ : isUndefined(arg3)
3215
+ ? (getTableCell) => getTableCell(arg1) === arg2
3216
+ : (getTableCell) => getTableCell(arg1, arg2) === arg3,
3217
+ );
3218
+ const group = (
3219
+ selectedCellId,
3220
+ aggregate,
3221
+ aggregateAdd,
3222
+ aggregateRemove,
3223
+ aggregateReplace,
3224
+ ) => {
3225
+ const groupEntry = [
3226
+ selectedCellId,
3227
+ [
3228
+ selectedCellId,
3229
+ isFunction(aggregate)
3230
+ ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
3231
+ : (mapGet(numericAggregators, aggregate) ?? [
3232
+ (_cells, length) => length,
3233
+ ]),
3234
+ ],
3235
+ ];
3236
+ arrayPush(groupEntries, groupEntry);
3237
+ return {as: (groupedCellId) => (groupEntry[0] = groupedCellId)};
3238
+ };
3239
+ const having = (arg1, arg2) =>
3240
+ arrayPush(
3241
+ havings,
3242
+ isFunction(arg1)
3243
+ ? arg1
3244
+ : (getSelectedOrGroupedCell) =>
3245
+ getSelectedOrGroupedCell(arg1) === arg2,
3246
+ );
3247
+ build({select, join, where, group, having});
3248
+ const selects = mapNew(selectEntries);
3249
+ if (collIsEmpty(selects)) {
3250
+ return queries;
3251
+ }
3252
+ const joins = mapNew(joinEntries);
3253
+ mapForEach(joins, (asTableId, [, fromAsTableId]) =>
3254
+ ifNotUndefined(mapGet(joins, fromAsTableId), ({3: toAsTableIds}) =>
3255
+ isUndefined(asTableId) ? 0 : arrayPush(toAsTableIds, asTableId),
3256
+ ),
3455
3257
  );
3456
- if (listeningToRawStoreChanges) {
3457
- mergeContentOrChanges([
3458
- [
3459
- {
3460
- [tableId]: [
3461
- {
3462
- [rowId]: [
3463
- {
3464
- [cellId]: [
3465
- newCell,
3466
- defaultingContent ? EMPTY_STRING : getHlc(),
3467
- ],
3468
- },
3469
- ],
3258
+ const groups = mapNew(groupEntries);
3259
+ let selectJoinWhereStore = preStore;
3260
+ if (collIsEmpty(groups) && arrayIsEmpty(havings)) {
3261
+ selectJoinWhereStore = resultStore;
3262
+ } else {
3263
+ synchronizeTransactions(queryId, selectJoinWhereStore, resultStore);
3264
+ const groupedSelectedCellIds = mapNew();
3265
+ mapForEach(groups, (groupedCellId, [selectedCellId, aggregators]) =>
3266
+ setAdd(mapEnsure(groupedSelectedCellIds, selectedCellId, setNew), [
3267
+ groupedCellId,
3268
+ aggregators,
3269
+ ]),
3270
+ );
3271
+ const groupBySelectedCellIds = setNew();
3272
+ mapForEach(selects, (selectedCellId) =>
3273
+ collHas(groupedSelectedCellIds, selectedCellId)
3274
+ ? 0
3275
+ : setAdd(groupBySelectedCellIds, selectedCellId),
3276
+ );
3277
+ const tree = mapNew();
3278
+ const writeGroupRow = (
3279
+ leaf,
3280
+ changedGroupedSelectedCells,
3281
+ selectedRowId,
3282
+ forceRemove,
3283
+ ) =>
3284
+ ifNotUndefined(
3285
+ leaf,
3286
+ ([selectedCells, selectedRowIds, groupRowId, groupRow]) => {
3287
+ mapForEach(
3288
+ changedGroupedSelectedCells,
3289
+ (selectedCellId, [newCell]) => {
3290
+ const selectedCell = mapEnsure(
3291
+ selectedCells,
3292
+ selectedCellId,
3293
+ mapNew,
3294
+ );
3295
+ const oldLeafCell = mapGet(selectedCell, selectedRowId);
3296
+ const newLeafCell = forceRemove ? void 0 : newCell;
3297
+ if (oldLeafCell !== newLeafCell) {
3298
+ const oldNewSet = setNew([[oldLeafCell, newLeafCell]]);
3299
+ const oldLength = collSize(selectedCell);
3300
+ mapSet(selectedCell, selectedRowId, newLeafCell);
3301
+ collForEach(
3302
+ mapGet(groupedSelectedCellIds, selectedCellId),
3303
+ ([groupedCellId, aggregators]) => {
3304
+ const aggregateValue = getAggregateValue(
3305
+ groupRow[groupedCellId],
3306
+ oldLength,
3307
+ selectedCell,
3308
+ oldNewSet,
3309
+ aggregators,
3310
+ );
3311
+ groupRow[groupedCellId] = isUndefined(
3312
+ getCellOrValueType(aggregateValue),
3313
+ )
3314
+ ? null
3315
+ : aggregateValue;
3316
+ },
3317
+ );
3318
+ }
3470
3319
  },
3471
- ],
3320
+ );
3321
+ if (
3322
+ collIsEmpty(selectedRowIds) ||
3323
+ !arrayEvery(havings, (having2) =>
3324
+ having2((cellId) => groupRow[cellId]),
3325
+ )
3326
+ ) {
3327
+ resultStore.delRow(queryId, groupRowId);
3328
+ } else if (isUndefined(groupRowId)) {
3329
+ leaf[2] = resultStore.addRow(queryId, groupRow);
3330
+ } else {
3331
+ resultStore.setRow(queryId, groupRowId, groupRow);
3332
+ }
3472
3333
  },
3473
- ],
3474
- [{}],
3475
- 1,
3476
- ]);
3334
+ );
3335
+ addPreStoreListener(
3336
+ selectJoinWhereStore,
3337
+ queryId,
3338
+ selectJoinWhereStore.addRowListener(
3339
+ queryId,
3340
+ null,
3341
+ (_store, _tableId, selectedRowId, getCellChange) => {
3342
+ const oldPath = [];
3343
+ const newPath = [];
3344
+ const changedGroupedSelectedCells = mapNew();
3345
+ const rowExists = selectJoinWhereStore.hasRow(
3346
+ queryId,
3347
+ selectedRowId,
3348
+ );
3349
+ let changedLeaf = !rowExists;
3350
+ collForEach(groupBySelectedCellIds, (selectedCellId) => {
3351
+ const [changed, oldCell, newCell] = getCellChange(
3352
+ queryId,
3353
+ selectedRowId,
3354
+ selectedCellId,
3355
+ );
3356
+ arrayPush(oldPath, oldCell);
3357
+ arrayPush(newPath, newCell);
3358
+ changedLeaf ||= changed;
3359
+ });
3360
+ mapForEach(groupedSelectedCellIds, (selectedCellId) => {
3361
+ const [changed, , newCell] = getCellChange(
3362
+ queryId,
3363
+ selectedRowId,
3364
+ selectedCellId,
3365
+ );
3366
+ if (changedLeaf || changed) {
3367
+ mapSet(changedGroupedSelectedCells, selectedCellId, [newCell]);
3368
+ }
3369
+ });
3370
+ if (changedLeaf) {
3371
+ writeGroupRow(
3372
+ visitTree(tree, oldPath, void 0, ([, selectedRowIds]) => {
3373
+ collDel(selectedRowIds, selectedRowId);
3374
+ return collIsEmpty(selectedRowIds);
3375
+ }),
3376
+ changedGroupedSelectedCells,
3377
+ selectedRowId,
3378
+ 1,
3379
+ );
3380
+ }
3381
+ if (rowExists) {
3382
+ writeGroupRow(
3383
+ visitTree(
3384
+ tree,
3385
+ newPath,
3386
+ () => {
3387
+ const groupRow = {};
3388
+ collForEach(
3389
+ groupBySelectedCellIds,
3390
+ (selectedCellId) =>
3391
+ (groupRow[selectedCellId] =
3392
+ selectJoinWhereStore.getCell(
3393
+ queryId,
3394
+ selectedRowId,
3395
+ selectedCellId,
3396
+ )),
3397
+ );
3398
+ return [mapNew(), setNew(), void 0, groupRow];
3399
+ },
3400
+ ([, selectedRowIds]) => {
3401
+ setAdd(selectedRowIds, selectedRowId);
3402
+ },
3403
+ ),
3404
+ changedGroupedSelectedCells,
3405
+ selectedRowId,
3406
+ );
3407
+ }
3408
+ },
3409
+ ),
3410
+ );
3477
3411
  }
3478
- };
3479
- const valueChanged = (valueId, newValue) => {
3480
- setAdd(touchedValues, valueId);
3481
- if (listeningToRawStoreChanges) {
3482
- mergeContentOrChanges([
3483
- [{}],
3484
- [{[valueId]: [newValue, defaultingContent ? EMPTY_STRING : getHlc()]}],
3412
+ synchronizeTransactions(queryId, store, selectJoinWhereStore);
3413
+ const writeSelectRow = (rootRowId) => {
3414
+ const getTableCell = (arg1, arg2) =>
3415
+ store.getCell(
3416
+ ...(isUndefined(arg2)
3417
+ ? [tableId, rootRowId, arg1]
3418
+ : arg1 === tableId
3419
+ ? [tableId, rootRowId, arg2]
3420
+ : [
3421
+ mapGet(joins, arg1)?.[0],
3422
+ mapGet(mapGet(joins, arg1)?.[4], rootRowId)?.[0],
3423
+ arg2,
3424
+ ]),
3425
+ );
3426
+ selectJoinWhereStore.transaction(() =>
3427
+ arrayEvery(wheres, (where2) => where2(getTableCell))
3428
+ ? mapForEach(selects, (asCellId, tableCellGetter) =>
3429
+ setOrDelCell(
3430
+ selectJoinWhereStore,
3431
+ queryId,
3432
+ rootRowId,
3433
+ asCellId,
3434
+ tableCellGetter(getTableCell, rootRowId),
3435
+ ),
3436
+ )
3437
+ : selectJoinWhereStore.delRow(queryId, rootRowId),
3438
+ );
3439
+ };
3440
+ const listenToTable = (rootRowId, tableId2, rowId, joinedTableIds2) => {
3441
+ const getCell = (cellId) => store.getCell(tableId2, rowId, cellId);
3442
+ arrayForEach(joinedTableIds2, (remoteAsTableId) => {
3443
+ const [realJoinedTableId, , on, nextJoinedTableIds, remoteIdPair] =
3444
+ mapGet(joins, remoteAsTableId);
3445
+ const remoteRowId = on?.(getCell, rootRowId);
3446
+ const [previousRemoteRowId, previousRemoteListenerId] =
3447
+ mapGet(remoteIdPair, rootRowId) ?? [];
3448
+ if (remoteRowId != previousRemoteRowId) {
3449
+ if (!isUndefined(previousRemoteListenerId)) {
3450
+ delStoreListeners(queryId, previousRemoteListenerId);
3451
+ }
3452
+ mapSet(
3453
+ remoteIdPair,
3454
+ rootRowId,
3455
+ isUndefined(remoteRowId)
3456
+ ? null
3457
+ : [
3458
+ remoteRowId,
3459
+ ...addStoreListeners(
3460
+ queryId,
3461
+ 1,
3462
+ store.addRowListener(realJoinedTableId, remoteRowId, () =>
3463
+ listenToTable(
3464
+ rootRowId,
3465
+ realJoinedTableId,
3466
+ remoteRowId,
3467
+ nextJoinedTableIds,
3468
+ ),
3469
+ ),
3470
+ ),
3471
+ ],
3472
+ );
3473
+ }
3474
+ });
3475
+ writeSelectRow(rootRowId);
3476
+ };
3477
+ const {3: joinedTableIds} = mapGet(joins, null);
3478
+ selectJoinWhereStore.transaction(() =>
3479
+ addStoreListeners(
3480
+ queryId,
3485
3481
  1,
3486
- ]);
3487
- }
3488
- };
3489
- const getMergeableContent = () => [
3490
- stampMapToObjWithHash(contentStampMap[0], (tableStampMap) =>
3491
- stampMapToObjWithHash(tableStampMap, (rowStampMap) =>
3492
- stampMapToObjWithHash(rowStampMap),
3482
+ store.addRowListener(tableId, null, (_store, _tableId, rootRowId) => {
3483
+ if (store.hasRow(tableId, rootRowId)) {
3484
+ listenToTable(rootRowId, tableId, rootRowId, joinedTableIds);
3485
+ } else {
3486
+ selectJoinWhereStore.delRow(queryId, rootRowId);
3487
+ collForEach(joins, ({4: idsByRootRowId}) =>
3488
+ ifNotUndefined(
3489
+ mapGet(idsByRootRowId, rootRowId),
3490
+ ([, listenerId]) => {
3491
+ delStoreListeners(queryId, listenerId);
3492
+ mapSet(idsByRootRowId, rootRowId);
3493
+ },
3494
+ ),
3495
+ );
3496
+ }
3497
+ }),
3493
3498
  ),
3494
- ),
3495
- stampMapToObjWithHash(contentStampMap[1]),
3496
- ];
3497
- const getMergeableContentHashes = () => [
3498
- contentStampMap[0][2],
3499
- contentStampMap[1][2],
3500
- ];
3501
- const getMergeableTableHashes = () =>
3502
- mapToObj(contentStampMap[0][0], getStampHash);
3503
- const getMergeableTableDiff = (otherTableHashes) => {
3504
- const newTables = stampNewObj(contentStampMap[0][1]);
3505
- const differingTableHashes = {};
3506
- mapForEach(
3507
- contentStampMap[0][0],
3508
- (tableId, [tableStampMap, tableTime, hash]) =>
3509
- objHas(otherTableHashes, tableId)
3510
- ? hash != otherTableHashes[tableId]
3511
- ? (differingTableHashes[tableId] = hash)
3512
- : 0
3513
- : (newTables[0][tableId] = stampMapToObjWithoutHash(
3514
- [tableStampMap, tableTime],
3515
- (rowStampMap) => stampMapToObjWithoutHash(rowStampMap),
3516
- )),
3517
3499
  );
3518
- return [newTables, differingTableHashes];
3500
+ return queries;
3519
3501
  };
3520
- const getMergeableRowHashes = (otherTableHashes) => {
3521
- const rowHashes = {};
3522
- objForEach(otherTableHashes, (otherTableHash, tableId) =>
3523
- ifNotUndefined(
3524
- mapGet(contentStampMap[0][0], tableId),
3525
- ([rowStampMaps, , tableHash]) =>
3526
- tableHash != otherTableHash
3527
- ? mapForEach(
3528
- rowStampMaps,
3529
- (rowId, [, , rowHash]) =>
3530
- (objEnsure(rowHashes, tableId, objNew)[rowId] = rowHash),
3531
- )
3532
- : 0,
3533
- ),
3534
- );
3535
- return rowHashes;
3502
+ const delQueryDefinition = (queryId) => {
3503
+ resetPreStores(queryId);
3504
+ delDefinition(queryId);
3505
+ return queries;
3536
3506
  };
3537
- const getMergeableRowDiff = (otherTableRowHashes) => {
3538
- const newRows = stampNewObj(contentStampMap[0][1]);
3539
- const differingRowHashes = {};
3540
- objForEach(otherTableRowHashes, (otherRowHashes, tableId) =>
3541
- mapForEach(
3542
- mapGet(contentStampMap[0][0], tableId)?.[0],
3543
- (rowId, [rowStampMap, rowTime, hash]) =>
3544
- objHas(otherRowHashes, rowId)
3545
- ? hash !== otherRowHashes[rowId]
3546
- ? (objEnsure(differingRowHashes, tableId, objNew)[rowId] = hash)
3547
- : 0
3548
- : (objEnsure(newRows[0], tableId, stampNewObj)[0][rowId] =
3549
- stampMapToObjWithoutHash([rowStampMap, rowTime])),
3550
- ),
3551
- );
3552
- return [newRows, differingRowHashes];
3507
+ const addQueryIdsListener = (listener) =>
3508
+ addQueryIdsListenerImpl(() => listener(queries));
3509
+ const delListener = (listenerId) => {
3510
+ delListenerImpl(listenerId);
3511
+ return queries;
3553
3512
  };
3554
- const getMergeableCellHashes = (otherTableRowHashes) => {
3555
- const cellHashes = {};
3556
- objForEach(otherTableRowHashes, (otherRowHashes, tableId) =>
3557
- ifNotUndefined(mapGet(contentStampMap[0][0], tableId), ([rowStampMaps]) =>
3558
- objForEach(otherRowHashes, (otherRowHash, rowId) =>
3559
- ifNotUndefined(
3560
- mapGet(rowStampMaps, rowId),
3561
- ([cellStampMaps, , rowHash]) =>
3562
- rowHash !== otherRowHash
3563
- ? mapForEach(
3564
- cellStampMaps,
3565
- (cellId, [, , cellHash]) =>
3566
- (objEnsure(
3567
- objEnsure(cellHashes, tableId, objNew),
3568
- rowId,
3569
- objNew,
3570
- )[cellId] = cellHash),
3571
- )
3572
- : 0,
3573
- ),
3574
- ),
3575
- ),
3576
- );
3577
- return cellHashes;
3513
+ const getListenerStats = () => {
3514
+ const {
3515
+ tables: _1,
3516
+ tableIds: _2,
3517
+ transaction: _3,
3518
+ ...stats
3519
+ } = resultStore.getListenerStats();
3520
+ return stats;
3578
3521
  };
3579
- const getMergeableCellDiff = (otherTableRowCellHashes) => {
3580
- const [[tableStampMaps, tablesTime]] = contentStampMap;
3581
- const tablesObj = {};
3582
- objForEach(otherTableRowCellHashes, (otherRowCellHashes, tableId) =>
3583
- objForEach(otherRowCellHashes, (otherCellHashes, rowId) =>
3584
- ifNotUndefined(
3585
- mapGet(tableStampMaps, tableId),
3586
- ([rowStampMaps, tableTime]) =>
3587
- ifNotUndefined(
3588
- mapGet(rowStampMaps, rowId),
3589
- ([cellStampMaps, rowTime]) =>
3590
- mapForEach(cellStampMaps, (cellId, [cell, cellTime, hash]) =>
3591
- hash !== otherCellHashes[cellId]
3592
- ? (objEnsure(
3593
- objEnsure(tablesObj, tableId, () =>
3594
- stampNewObj(tableTime),
3595
- )[0],
3596
- rowId,
3597
- () => stampNewObj(rowTime),
3598
- )[0][cellId] = [cell, cellTime])
3599
- : 0,
3600
- ),
3601
- ),
3602
- ),
3603
- ),
3604
- );
3605
- return stampNew(tablesObj, tablesTime);
3522
+ const queries = {
3523
+ setQueryDefinition,
3524
+ delQueryDefinition,
3525
+ getStore,
3526
+ getQueryIds,
3527
+ forEachQuery,
3528
+ hasQuery,
3529
+ getTableId,
3530
+ addQueryIdsListener,
3531
+ delListener,
3532
+ destroy,
3533
+ getListenerStats,
3606
3534
  };
3607
- const getMergeableValueHashes = () =>
3608
- mapToObj(contentStampMap[1][0], getStampHash);
3609
- const getMergeableValueDiff = (otherValueHashes) => {
3610
- const [, [valueStampMaps, valuesTime]] = contentStampMap;
3611
- const values = mapToObj(
3612
- valueStampMaps,
3613
- stampClone,
3614
- ([, , hash], valueId) => hash == otherValueHashes?.[valueId],
3535
+ objMap(
3536
+ {
3537
+ [TABLE]: [1, 1],
3538
+ [TABLE + CELL_IDS]: [0, 1],
3539
+ [ROW_COUNT]: [0, 1],
3540
+ [ROW_IDS]: [0, 1],
3541
+ [SORTED_ROW_IDS]: [0, 5],
3542
+ [ROW]: [1, 2],
3543
+ [CELL_IDS]: [0, 2],
3544
+ [CELL]: [1, 3],
3545
+ },
3546
+ ([hasAndForEach, argumentCount], gettable) => {
3547
+ arrayForEach(
3548
+ hasAndForEach ? [GET, 'has', 'forEach'] : [GET],
3549
+ (prefix) =>
3550
+ (queries[prefix + RESULT + gettable] = (...args) =>
3551
+ resultStore[prefix + gettable](...args)),
3552
+ );
3553
+ queries[ADD + RESULT + gettable + LISTENER] = (...args) =>
3554
+ resultStore[ADD + gettable + LISTENER](
3555
+ ...slice(args, 0, argumentCount),
3556
+ (_store, ...listenerArgs) =>
3557
+ args[argumentCount](queries, ...listenerArgs),
3558
+ true,
3559
+ );
3560
+ },
3561
+ );
3562
+ return objFreeze(queries);
3563
+ });
3564
+
3565
+ const createRelationships = getCreateFunction((store) => {
3566
+ const remoteTableIds = mapNew();
3567
+ const remoteRowIdListeners = mapNew();
3568
+ const localRowIdsListeners = mapNew();
3569
+ const linkedRowIdsListeners = mapNew();
3570
+ const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
3571
+ () => relationships,
3572
+ );
3573
+ const [
3574
+ getStore,
3575
+ getRelationshipIds,
3576
+ forEachRelationshipImpl,
3577
+ hasRelationship,
3578
+ getLocalTableId,
3579
+ getRelationship,
3580
+ ,
3581
+ ,
3582
+ setDefinitionAndListen,
3583
+ delDefinition,
3584
+ addRelationshipIdsListener,
3585
+ destroy,
3586
+ ] = getDefinableFunctions(
3587
+ store,
3588
+ () => [mapNew(), mapNew(), mapNew(), mapNew()],
3589
+ (value) => (isUndefined(value) ? void 0 : value + EMPTY_STRING),
3590
+ addListener,
3591
+ callListeners,
3592
+ );
3593
+ const getLinkedRowIdsCache = (relationshipId, firstRowId, skipCache) =>
3594
+ ifNotUndefined(
3595
+ getRelationship(relationshipId),
3596
+ ([remoteRows, , linkedRowsCache]) => {
3597
+ if (!collHas(linkedRowsCache, firstRowId)) {
3598
+ const linkedRows = setNew();
3599
+ if (
3600
+ getLocalTableId(relationshipId) != getRemoteTableId(relationshipId)
3601
+ ) {
3602
+ setAdd(linkedRows, firstRowId);
3603
+ } else {
3604
+ let rowId = firstRowId;
3605
+ while (!isUndefined(rowId) && !collHas(linkedRows, rowId)) {
3606
+ setAdd(linkedRows, rowId);
3607
+ rowId = mapGet(remoteRows, rowId);
3608
+ }
3609
+ }
3610
+ if (skipCache) {
3611
+ return linkedRows;
3612
+ }
3613
+ mapSet(linkedRowsCache, firstRowId, linkedRows);
3614
+ }
3615
+ return mapGet(linkedRowsCache, firstRowId);
3616
+ },
3615
3617
  );
3616
- return stampNew(values, valuesTime);
3617
- };
3618
- const setMergeableContent = (mergeableContent) =>
3619
- disableListeningToRawStoreChanges(() =>
3620
- validateMergeableContent(mergeableContent)
3621
- ? store.transaction(() => {
3622
- store.delTables().delValues();
3623
- contentStampMap = newContentStampMap();
3624
- store.applyChanges(mergeContentOrChanges(mergeableContent, 1));
3625
- })
3626
- : 0,
3618
+ const delLinkedRowIdsCache = (relationshipId, firstRowId) =>
3619
+ ifNotUndefined(getRelationship(relationshipId), ([, , linkedRowsCache]) =>
3620
+ mapSet(linkedRowsCache, firstRowId),
3627
3621
  );
3628
- const setDefaultContent = (content) => {
3629
- store.transaction(() => {
3630
- defaultingContent = 1;
3631
- store.setContent(content);
3632
- defaultingContent = 0;
3633
- });
3634
- return mergeableStore;
3635
- };
3636
- const getTransactionMergeableChanges = (withHashes = false) => {
3637
- const [
3638
- [tableStampMaps, tablesTime, tablesHash],
3639
- [valueStampMaps, valuesTime, valuesHash],
3640
- ] = contentStampMap;
3641
- const newStamp = withHashes ? stampNewWithHash : stampNew;
3642
- const tablesObj = {};
3643
- collForEach(touchedCells, (touchedTable, tableId) =>
3644
- ifNotUndefined(
3645
- mapGet(tableStampMaps, tableId),
3646
- ([rowStampMaps, tableTime, tableHash]) => {
3647
- const tableObj = {};
3648
- collForEach(touchedTable, (touchedRow, rowId) =>
3649
- ifNotUndefined(
3650
- mapGet(rowStampMaps, rowId),
3651
- ([cellStampMaps, rowTime, rowHash]) => {
3652
- const rowObj = {};
3653
- collForEach(touchedRow, (cellId) => {
3654
- ifNotUndefined(
3655
- mapGet(cellStampMaps, cellId),
3656
- ([cell, time, hash]) =>
3657
- (rowObj[cellId] = newStamp(cell, time, hash)),
3658
- );
3659
- });
3660
- tableObj[rowId] = newStamp(rowObj, rowTime, rowHash);
3622
+ const setRelationshipDefinition = (
3623
+ relationshipId,
3624
+ localTableId,
3625
+ remoteTableId,
3626
+ getRemoteRowId2,
3627
+ ) => {
3628
+ mapSet(remoteTableIds, relationshipId, remoteTableId);
3629
+ setDefinitionAndListen(
3630
+ relationshipId,
3631
+ localTableId,
3632
+ (change, changedRemoteRowIds) => {
3633
+ const changedLocalRows = setNew();
3634
+ const changedRemoteRows = setNew();
3635
+ const changedLinkedRows = setNew();
3636
+ const [localRows, remoteRows] = getRelationship(relationshipId);
3637
+ collForEach(
3638
+ changedRemoteRowIds,
3639
+ ([oldRemoteRowId, newRemoteRowId], localRowId) => {
3640
+ if (!isUndefined(oldRemoteRowId)) {
3641
+ setAdd(changedRemoteRows, oldRemoteRowId);
3642
+ ifNotUndefined(
3643
+ mapGet(remoteRows, oldRemoteRowId),
3644
+ (oldRemoteRow) => {
3645
+ collDel(oldRemoteRow, localRowId);
3646
+ if (collIsEmpty(oldRemoteRow)) {
3647
+ mapSet(remoteRows, oldRemoteRowId);
3648
+ }
3649
+ },
3650
+ );
3651
+ }
3652
+ if (!isUndefined(newRemoteRowId)) {
3653
+ setAdd(changedRemoteRows, newRemoteRowId);
3654
+ if (!collHas(remoteRows, newRemoteRowId)) {
3655
+ mapSet(remoteRows, newRemoteRowId, setNew());
3656
+ }
3657
+ setAdd(mapGet(remoteRows, newRemoteRowId), localRowId);
3658
+ }
3659
+ setAdd(changedLocalRows, localRowId);
3660
+ mapSet(localRows, localRowId, newRemoteRowId);
3661
+ mapForEach(
3662
+ mapGet(linkedRowIdsListeners, relationshipId),
3663
+ (firstRowId) => {
3664
+ if (
3665
+ collHas(
3666
+ getLinkedRowIdsCache(relationshipId, firstRowId),
3667
+ localRowId,
3668
+ )
3669
+ ) {
3670
+ setAdd(changedLinkedRows, firstRowId);
3671
+ }
3661
3672
  },
3662
- ),
3663
- );
3664
- tablesObj[tableId] = newStamp(tableObj, tableTime, tableHash);
3665
- },
3666
- ),
3673
+ );
3674
+ },
3675
+ );
3676
+ change();
3677
+ collForEach(changedLocalRows, (localRowId) =>
3678
+ callListeners(remoteRowIdListeners, [relationshipId, localRowId]),
3679
+ );
3680
+ collForEach(changedRemoteRows, (remoteRowId) =>
3681
+ callListeners(localRowIdsListeners, [relationshipId, remoteRowId]),
3682
+ );
3683
+ collForEach(changedLinkedRows, (firstRowId) => {
3684
+ delLinkedRowIdsCache(relationshipId, firstRowId);
3685
+ callListeners(linkedRowIdsListeners, [relationshipId, firstRowId]);
3686
+ });
3687
+ },
3688
+ getRowCellFunction(getRemoteRowId2),
3667
3689
  );
3668
- const valuesObj = {};
3669
- collForEach(touchedValues, (valueId) =>
3670
- ifNotUndefined(
3671
- mapGet(valueStampMaps, valueId),
3672
- ([value, time, hash]) =>
3673
- (valuesObj[valueId] = newStamp(value, time, hash)),
3690
+ return relationships;
3691
+ };
3692
+ const forEachRelationship = (relationshipCallback) =>
3693
+ forEachRelationshipImpl((relationshipId) =>
3694
+ relationshipCallback(relationshipId, (rowCallback) =>
3695
+ store.forEachRow(getLocalTableId(relationshipId), rowCallback),
3674
3696
  ),
3675
3697
  );
3676
- return [
3677
- newStamp(tablesObj, tablesTime, tablesHash),
3678
- newStamp(valuesObj, valuesTime, valuesHash),
3679
- 1,
3680
- ];
3698
+ const delRelationshipDefinition = (relationshipId) => {
3699
+ mapSet(remoteTableIds, relationshipId);
3700
+ delDefinition(relationshipId);
3701
+ return relationships;
3681
3702
  };
3682
- const applyMergeableChanges = (mergeableChanges) =>
3683
- disableListeningToRawStoreChanges(() =>
3684
- store.applyChanges(mergeContentOrChanges(mergeableChanges)),
3685
- );
3686
- const merge = (mergeableStore2) => {
3687
- const mergeableChanges = getMergeableContent();
3688
- const mergeableChanges2 = mergeableStore2.getMergeableContent();
3689
- mergeableStore2.applyMergeableChanges(mergeableChanges);
3690
- return applyMergeableChanges(mergeableChanges2);
3703
+ const getRemoteTableId = (relationshipId) =>
3704
+ mapGet(remoteTableIds, relationshipId);
3705
+ const getRemoteRowId = (relationshipId, localRowId) =>
3706
+ mapGet(getRelationship(relationshipId)?.[0], localRowId);
3707
+ const getLocalRowIds = (relationshipId, remoteRowId) =>
3708
+ collValues(mapGet(getRelationship(relationshipId)?.[1], remoteRowId));
3709
+ const getLinkedRowIds = (relationshipId, firstRowId) =>
3710
+ isUndefined(getRelationship(relationshipId))
3711
+ ? [firstRowId]
3712
+ : collValues(getLinkedRowIdsCache(relationshipId, firstRowId, true));
3713
+ const addRemoteRowIdListener = (relationshipId, localRowId, listener) =>
3714
+ addListener(listener, remoteRowIdListeners, [relationshipId, localRowId]);
3715
+ const addLocalRowIdsListener = (relationshipId, remoteRowId, listener) =>
3716
+ addListener(listener, localRowIdsListeners, [relationshipId, remoteRowId]);
3717
+ const addLinkedRowIdsListener = (relationshipId, firstRowId, listener) => {
3718
+ getLinkedRowIdsCache(relationshipId, firstRowId);
3719
+ return addListener(listener, linkedRowIdsListeners, [
3720
+ relationshipId,
3721
+ firstRowId,
3722
+ ]);
3691
3723
  };
3692
- const mergeableStore = {
3693
- getMergeableContent,
3694
- getMergeableContentHashes,
3695
- getMergeableTableHashes,
3696
- getMergeableTableDiff,
3697
- getMergeableRowHashes,
3698
- getMergeableRowDiff,
3699
- getMergeableCellHashes,
3700
- getMergeableCellDiff,
3701
- getMergeableValueHashes,
3702
- getMergeableValueDiff,
3703
- setMergeableContent,
3704
- setDefaultContent,
3705
- getTransactionMergeableChanges,
3706
- applyMergeableChanges,
3707
- merge,
3724
+ const delListener = (listenerId) => {
3725
+ delLinkedRowIdsCache(...(delListenerImpl(listenerId) ?? []));
3726
+ return relationships;
3708
3727
  };
3709
- store.setInternalListeners(
3710
- preStartTransaction,
3711
- preFinishTransaction,
3712
- postFinishTransaction,
3713
- cellChanged,
3714
- valueChanged,
3715
- );
3716
- objMap(
3717
- store,
3718
- (method, name) =>
3719
- (mergeableStore[name] = // fluent methods
3720
- strStartsWith(name, SET) ||
3721
- strStartsWith(name, DEL) ||
3722
- strStartsWith(name, 'apply') ||
3723
- strEndsWith(name, TRANSACTION) ||
3724
- name == 'call' + LISTENER
3725
- ? (...args) => {
3726
- method(...args);
3727
- return mergeableStore;
3728
- }
3729
- : strStartsWith(name, ADD) && strEndsWith(name, LISTENER)
3730
- ? (...args) => {
3731
- const listenerArg = LISTENER_ARGS[slice(name, 3, -8)] ?? 0;
3732
- const listener = args[listenerArg];
3733
- args[listenerArg] = (_store, ...args2) =>
3734
- listener(mergeableStore, ...args2);
3735
- return method(...args);
3736
- }
3737
- : name == 'isMergeable'
3738
- ? () => true
3739
- : method),
3740
- );
3741
- return objFreeze(mergeableStore);
3742
- };
3728
+ const getListenerStats = () => ({
3729
+ remoteRowId: collSize3(remoteRowIdListeners),
3730
+ localRowIds: collSize3(localRowIdsListeners),
3731
+ linkedRowIds: collSize3(linkedRowIdsListeners),
3732
+ });
3733
+ const relationships = {
3734
+ setRelationshipDefinition,
3735
+ delRelationshipDefinition,
3736
+ getStore,
3737
+ getRelationshipIds,
3738
+ forEachRelationship,
3739
+ hasRelationship,
3740
+ getLocalTableId,
3741
+ getRemoteTableId,
3742
+ getRemoteRowId,
3743
+ getLocalRowIds,
3744
+ getLinkedRowIds,
3745
+ addRelationshipIdsListener,
3746
+ addRemoteRowIdListener,
3747
+ addLocalRowIdsListener,
3748
+ addLinkedRowIdsListener,
3749
+ delListener,
3750
+ destroy,
3751
+ getListenerStats,
3752
+ };
3753
+ return objFreeze(relationships);
3754
+ });
3743
3755
 
3744
3756
  export {
3745
3757
  createCheckpoints,