tinybase 6.0.0 → 6.1.0-beta.1

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 (103) hide show
  1. package/@types/_internal/ui-react/with-schemas/index.d.cts +1 -1
  2. package/@types/_internal/ui-react/with-schemas/index.d.ts +1 -1
  3. package/@types/index.d.cts +1 -1
  4. package/@types/index.d.ts +1 -1
  5. package/@types/persisters/persister-automerge/index.d.cts +1 -1
  6. package/@types/persisters/persister-automerge/index.d.ts +1 -1
  7. package/@types/persisters/persister-automerge/with-schemas/index.d.cts +1 -1
  8. package/@types/persisters/persister-automerge/with-schemas/index.d.ts +1 -1
  9. package/@types/persisters/persister-cr-sqlite-wasm/index.d.cts +1 -1
  10. package/@types/persisters/persister-cr-sqlite-wasm/index.d.ts +1 -1
  11. package/@types/persisters/persister-cr-sqlite-wasm/with-schemas/index.d.cts +1 -1
  12. package/@types/persisters/persister-cr-sqlite-wasm/with-schemas/index.d.ts +1 -1
  13. package/@types/persisters/persister-electric-sql/index.d.cts +4 -4
  14. package/@types/persisters/persister-electric-sql/index.d.ts +4 -4
  15. package/@types/persisters/persister-electric-sql/with-schemas/index.d.cts +4 -4
  16. package/@types/persisters/persister-electric-sql/with-schemas/index.d.ts +4 -4
  17. package/@types/persisters/persister-expo-sqlite/index.d.cts +1 -1
  18. package/@types/persisters/persister-expo-sqlite/index.d.ts +1 -1
  19. package/@types/persisters/persister-expo-sqlite/with-schemas/index.d.cts +1 -1
  20. package/@types/persisters/persister-expo-sqlite/with-schemas/index.d.ts +1 -1
  21. package/@types/persisters/persister-libsql/index.d.cts +1 -1
  22. package/@types/persisters/persister-libsql/index.d.ts +1 -1
  23. package/@types/persisters/persister-libsql/with-schemas/index.d.cts +1 -1
  24. package/@types/persisters/persister-libsql/with-schemas/index.d.ts +1 -1
  25. package/@types/persisters/persister-partykit-client/index.d.cts +1 -1
  26. package/@types/persisters/persister-partykit-client/index.d.ts +1 -1
  27. package/@types/persisters/persister-partykit-client/with-schemas/index.d.cts +1 -1
  28. package/@types/persisters/persister-partykit-client/with-schemas/index.d.ts +1 -1
  29. package/@types/persisters/persister-partykit-server/index.d.cts +7 -7
  30. package/@types/persisters/persister-partykit-server/index.d.ts +7 -7
  31. package/@types/persisters/persister-partykit-server/with-schemas/index.d.cts +1 -1
  32. package/@types/persisters/persister-partykit-server/with-schemas/index.d.ts +1 -1
  33. package/@types/persisters/persister-pglite/index.d.cts +1 -1
  34. package/@types/persisters/persister-pglite/index.d.ts +1 -1
  35. package/@types/persisters/persister-pglite/with-schemas/index.d.cts +1 -1
  36. package/@types/persisters/persister-pglite/with-schemas/index.d.ts +1 -1
  37. package/@types/persisters/persister-postgres/index.d.cts +1 -1
  38. package/@types/persisters/persister-postgres/index.d.ts +1 -1
  39. package/@types/persisters/persister-postgres/with-schemas/index.d.cts +1 -1
  40. package/@types/persisters/persister-postgres/with-schemas/index.d.ts +1 -1
  41. package/@types/persisters/persister-powersync/index.d.cts +1 -1
  42. package/@types/persisters/persister-powersync/index.d.ts +1 -1
  43. package/@types/persisters/persister-powersync/with-schemas/index.d.cts +1 -1
  44. package/@types/persisters/persister-powersync/with-schemas/index.d.ts +1 -1
  45. package/@types/persisters/persister-sqlite3/index.d.cts +1 -1
  46. package/@types/persisters/persister-sqlite3/index.d.ts +1 -1
  47. package/@types/persisters/persister-sqlite3/with-schemas/index.d.cts +1 -1
  48. package/@types/persisters/persister-sqlite3/with-schemas/index.d.ts +1 -1
  49. package/@types/persisters/persister-yjs/index.d.cts +1 -1
  50. package/@types/persisters/persister-yjs/index.d.ts +1 -1
  51. package/@types/persisters/persister-yjs/with-schemas/index.d.cts +1 -1
  52. package/@types/persisters/persister-yjs/with-schemas/index.d.ts +1 -1
  53. package/@types/synchronizers/synchronizer-ws-client/index.d.cts +1 -1
  54. package/@types/synchronizers/synchronizer-ws-client/index.d.ts +1 -1
  55. package/@types/synchronizers/synchronizer-ws-client/with-schemas/index.d.cts +1 -1
  56. package/@types/synchronizers/synchronizer-ws-client/with-schemas/index.d.ts +1 -1
  57. package/@types/synchronizers/synchronizer-ws-server/index.d.cts +1 -1
  58. package/@types/synchronizers/synchronizer-ws-server/index.d.ts +1 -1
  59. package/@types/synchronizers/synchronizer-ws-server/with-schemas/index.d.cts +1 -1
  60. package/@types/synchronizers/synchronizer-ws-server/with-schemas/index.d.ts +1 -1
  61. package/@types/synchronizers/synchronizer-ws-server-durable-object/index.d.cts +1 -1
  62. package/@types/synchronizers/synchronizer-ws-server-durable-object/index.d.ts +1 -1
  63. package/@types/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.d.cts +1 -1
  64. package/@types/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.d.ts +1 -1
  65. package/@types/ui-react/index.d.cts +3 -3
  66. package/@types/ui-react/index.d.ts +3 -3
  67. package/@types/ui-react/with-schemas/index.d.cts +1 -1
  68. package/@types/ui-react/with-schemas/index.d.ts +1 -1
  69. package/@types/ui-react-dom/index.d.cts +1 -1
  70. package/@types/ui-react-dom/index.d.ts +1 -1
  71. package/@types/ui-react-dom/with-schemas/index.d.cts +1 -1
  72. package/@types/ui-react-dom/with-schemas/index.d.ts +1 -1
  73. package/@types/ui-react-inspector/with-schemas/index.d.cts +1 -1
  74. package/@types/ui-react-inspector/with-schemas/index.d.ts +1 -1
  75. package/@types/with-schemas/index.d.cts +1 -1
  76. package/@types/with-schemas/index.d.ts +1 -1
  77. package/index.js +1564 -1564
  78. package/min/index.js +1 -1
  79. package/min/index.js.gz +0 -0
  80. package/min/persisters/index.js +1 -1
  81. package/min/persisters/index.js.gz +0 -0
  82. package/min/persisters/with-schemas/index.js +1 -1
  83. package/min/persisters/with-schemas/index.js.gz +0 -0
  84. package/min/ui-react/index.js +1 -1
  85. package/min/ui-react/index.js.gz +0 -0
  86. package/min/ui-react/with-schemas/index.js +1 -1
  87. package/min/ui-react/with-schemas/index.js.gz +0 -0
  88. package/min/with-schemas/index.js +1 -1
  89. package/min/with-schemas/index.js.gz +0 -0
  90. package/package.json +1 -4
  91. package/persisters/index.js +95 -95
  92. package/persisters/with-schemas/index.js +95 -95
  93. package/readme.md +13 -13
  94. package/releases.md +25 -25
  95. package/synchronizers/synchronizer-ws-server-durable-object/index.js +1 -1
  96. package/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +1 -1
  97. package/ui-react/index.js +64 -53
  98. package/ui-react/with-schemas/index.js +64 -53
  99. package/ui-react-dom/index.js +3 -3
  100. package/ui-react-dom/with-schemas/index.js +3 -3
  101. package/ui-react-inspector/index.js +4 -4
  102. package/ui-react-inspector/with-schemas/index.js +4 -4
  103. package/with-schemas/index.js +1564 -1564
package/index.js CHANGED
@@ -977,1118 +977,297 @@ const createIndexes = getCreateFunction((store) => {
977
977
  return objFreeze(indexes);
978
978
  });
979
979
 
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
- }
980
+ const textEncoder = /* @__PURE__ */ new GLOBAL.TextEncoder();
981
+ const getHash = (value) => {
982
+ let hash = 2166136261;
983
+ arrayForEach(textEncoder.encode(value), (char) => {
984
+ hash ^= char;
985
+ hash +=
986
+ (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
1043
987
  });
1044
- return force
1045
- ? aggregate(collValues(newValues), collSize(newValues))
1046
- : aggregateValue;
988
+ return hash >>> 0;
1047
989
  };
1048
990
 
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,
991
+ const SHIFT36 = 2 ** 36;
992
+ const SHIFT30 = 2 ** 30;
993
+ const SHIFT24 = 2 ** 24;
994
+ const SHIFT18 = 2 ** 18;
995
+ const SHIFT12 = 2 ** 12;
996
+ const SHIFT6 = 2 ** 6;
997
+ const encodeTimeAndCounter = (logicalTime42, counter24) =>
998
+ encode(logicalTime42 / SHIFT36) +
999
+ encode(logicalTime42 / SHIFT30) +
1000
+ encode(logicalTime42 / SHIFT24) +
1001
+ encode(logicalTime42 / SHIFT18) +
1002
+ encode(logicalTime42 / SHIFT12) +
1003
+ encode(logicalTime42 / SHIFT6) +
1004
+ encode(logicalTime42) +
1005
+ encode(counter24 / SHIFT18) +
1006
+ encode(counter24 / SHIFT12) +
1007
+ encode(counter24 / SHIFT6) +
1008
+ encode(counter24);
1009
+ const decodeTimeAndCounter = (hlc16) => [
1010
+ decode(hlc16, 0) * SHIFT36 +
1011
+ decode(hlc16, 1) * SHIFT30 +
1012
+ decode(hlc16, 2) * SHIFT24 +
1013
+ decode(hlc16, 3) * SHIFT18 +
1014
+ decode(hlc16, 4) * SHIFT12 +
1015
+ decode(hlc16, 5) * SHIFT6 +
1016
+ decode(hlc16, 6),
1017
+ decode(hlc16, 7) * SHIFT18 +
1018
+ decode(hlc16, 8) * SHIFT12 +
1019
+ decode(hlc16, 9) * SHIFT6 +
1020
+ decode(hlc16, 10),
1021
+ ];
1022
+ const getHlcFunctions = (uniqueId) => {
1023
+ let logicalTime = 0;
1024
+ let lastCounter = -1;
1025
+ const clientPart = ifNotUndefined(
1026
+ uniqueId,
1027
+ (uniqueId2) => {
1028
+ const clientHash30 = getHash(uniqueId2);
1029
+ return (
1030
+ encode(clientHash30 / SHIFT24) +
1031
+ encode(clientHash30 / SHIFT18) +
1032
+ encode(clientHash30 / SHIFT12) +
1033
+ encode(clientHash30 / SHIFT6) +
1034
+ encode(clientHash30)
1035
+ );
1036
+ },
1037
+ () => getUniqueId(5),
1080
1038
  );
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;
1039
+ const getHlc = () => {
1040
+ seenHlc();
1041
+ return encodeTimeAndCounter(logicalTime, ++lastCounter) + clientPart;
1131
1042
  };
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,
1043
+ const seenHlc = (hlc) => {
1044
+ const previousLogicalTime = logicalTime;
1045
+ const [remoteLogicalTime, remoteCounter] =
1046
+ isUndefined(hlc) || hlc == '' ? [0, 0] : decodeTimeAndCounter(hlc);
1047
+ logicalTime = mathMax(
1048
+ previousLogicalTime,
1049
+ remoteLogicalTime,
1050
+ GLOBAL.HLC_TIME ?? Date.now(),
1051
+ );
1052
+ lastCounter =
1053
+ logicalTime == previousLogicalTime
1054
+ ? logicalTime == remoteLogicalTime
1055
+ ? mathMax(lastCounter, remoteCounter)
1056
+ : lastCounter
1057
+ : logicalTime == remoteLogicalTime
1058
+ ? remoteCounter
1059
+ : -1;
1149
1060
  };
1150
- return objFreeze(metrics);
1151
- });
1061
+ return [getHlc, seenHlc];
1062
+ };
1152
1063
 
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,
1064
+ const jsonString = JSON.stringify;
1065
+ const jsonParse = JSON.parse;
1066
+ const jsonStringWithMap = (obj) =>
1067
+ jsonString(obj, (_key, value) =>
1068
+ isInstanceOf(value, Map) ? object.fromEntries([...value]) : value,
1184
1069
  );
1185
- const addPreStoreListener = (preStore2, queryId, ...listenerIds) =>
1186
- arrayForEach(listenerIds, (listenerId) =>
1187
- setAdd(
1188
- mapEnsure(
1189
- mapEnsure(preStoreListenerIds, queryId, mapNew),
1190
- preStore2,
1191
- setNew,
1070
+
1071
+ const stampClone = ([value, time]) => stampNew(value, time);
1072
+ const stampCloneWithHash = ([value, time, hash]) => [value, time, hash];
1073
+ const stampNew = (value, time) => (time ? [value, time] : [value]);
1074
+ const stampNewWithHash = (value, time, hash) => [value, time, hash];
1075
+ const getStampHash = (stamp) => stamp[2];
1076
+ const hashIdAndHash = (id, hash) => getHash(id + ':' + hash);
1077
+ const replaceTimeHash = (oldTime, newTime) =>
1078
+ newTime > oldTime ? (oldTime ? getHash(oldTime) : 0) ^ getHash(newTime) : 0;
1079
+ const getLatestTime = (time1, time2) =>
1080
+ /* istanbul ignore next */
1081
+ ((time1 ?? '') > (time2 ?? '') ? time1 : time2) ?? '';
1082
+ const stampUpdate = (stamp, time, hash) => {
1083
+ if (time > stamp[1]) {
1084
+ stamp[1] = time;
1085
+ }
1086
+ stamp[2] = hash >>> 0;
1087
+ };
1088
+ const stampNewObj = (time = EMPTY_STRING) => stampNew(objNew(), time);
1089
+ const stampNewMap = (time = EMPTY_STRING) => [mapNew(), time, 0];
1090
+ const stampMapToObjWithHash = (
1091
+ [map, time, hash],
1092
+ mapper = stampCloneWithHash,
1093
+ ) => [mapToObj(map, mapper), time, hash];
1094
+ const stampMapToObjWithoutHash = ([map, time], mapper = stampClone) =>
1095
+ stampNew(mapToObj(map, mapper), time);
1096
+ const stampValidate = (stamp, validateThing) =>
1097
+ isArray(stamp) &&
1098
+ size(stamp) == 3 &&
1099
+ isString(stamp[1]) &&
1100
+ getTypeOf(stamp[2]) == NUMBER &&
1101
+ isFiniteNumber(stamp[2]) &&
1102
+ validateThing(stamp[0]);
1103
+
1104
+ const pairNew = (value) => [value, value];
1105
+ const pairCollSize2 = (pair, func = collSize2) => func(pair[0]) + func(pair[1]);
1106
+ const pairNewMap = () => [mapNew(), mapNew()];
1107
+ const pairClone = (array) => [...array];
1108
+ const pairIsEqual = ([entry1, entry2]) => entry1 === entry2;
1109
+
1110
+ const idsChanged = (changedIds, id2, addedOrRemoved) =>
1111
+ mapSet(
1112
+ changedIds,
1113
+ id2,
1114
+ mapGet(changedIds, id2) == -addedOrRemoved ? void 0 : addedOrRemoved,
1115
+ );
1116
+ const createStore = () => {
1117
+ let hasTablesSchema;
1118
+ let hasValuesSchema;
1119
+ let hadTables = false;
1120
+ let hadValues = false;
1121
+ let transactions = 0;
1122
+ let internalListeners = [];
1123
+ const changedTableIds = mapNew();
1124
+ const changedTableCellIds = mapNew();
1125
+ const changedRowCount = mapNew();
1126
+ const changedRowIds = mapNew();
1127
+ const changedCellIds = mapNew();
1128
+ const changedCells = mapNew();
1129
+ const changedValueIds = mapNew();
1130
+ const changedValues = mapNew();
1131
+ const invalidCells = mapNew();
1132
+ const invalidValues = mapNew();
1133
+ const tablesSchemaMap = mapNew();
1134
+ const tablesSchemaRowCache = mapNew();
1135
+ const valuesSchemaMap = mapNew();
1136
+ const valuesDefaulted = mapNew();
1137
+ const valuesNonDefaulted = setNew();
1138
+ const tablePoolFunctions = mapNew();
1139
+ const tableCellIds = mapNew();
1140
+ const tablesMap = mapNew();
1141
+ const valuesMap = mapNew();
1142
+ const hasTablesListeners = pairNewMap();
1143
+ const tablesListeners = pairNewMap();
1144
+ const tableIdsListeners = pairNewMap();
1145
+ const hasTableListeners = pairNewMap();
1146
+ const tableListeners = pairNewMap();
1147
+ const tableCellIdsListeners = pairNewMap();
1148
+ const hasTableCellListeners = pairNewMap();
1149
+ const rowCountListeners = pairNewMap();
1150
+ const rowIdsListeners = pairNewMap();
1151
+ const sortedRowIdsListeners = pairNewMap();
1152
+ const hasRowListeners = pairNewMap();
1153
+ const rowListeners = pairNewMap();
1154
+ const cellIdsListeners = pairNewMap();
1155
+ const hasCellListeners = pairNewMap();
1156
+ const cellListeners = pairNewMap();
1157
+ const invalidCellListeners = pairNewMap();
1158
+ const invalidValueListeners = pairNewMap();
1159
+ const hasValuesListeners = pairNewMap();
1160
+ const valuesListeners = pairNewMap();
1161
+ const valueIdsListeners = pairNewMap();
1162
+ const hasValueListeners = pairNewMap();
1163
+ const valueListeners = pairNewMap();
1164
+ const startTransactionListeners = mapNew();
1165
+ const finishTransactionListeners = pairNewMap();
1166
+ const [addListener, callListeners, delListenerImpl, callListenerImpl] =
1167
+ getListenerFunctions(() => store);
1168
+ const validateTablesSchema = (tableSchema) =>
1169
+ objValidate(tableSchema, (tableSchema2) =>
1170
+ objValidate(tableSchema2, validateCellOrValueSchema),
1171
+ );
1172
+ const validateValuesSchema = (valuesSchema) =>
1173
+ objValidate(valuesSchema, validateCellOrValueSchema);
1174
+ const validateCellOrValueSchema = (schema) => {
1175
+ if (!objValidate(schema, (_child, id2) => arrayHas([TYPE, DEFAULT], id2))) {
1176
+ return false;
1177
+ }
1178
+ const type = schema[TYPE];
1179
+ if (!isTypeStringOrBoolean(type) && type != NUMBER) {
1180
+ return false;
1181
+ }
1182
+ if (getCellOrValueType(schema[DEFAULT]) != type) {
1183
+ objDel(schema, DEFAULT);
1184
+ }
1185
+ return true;
1186
+ };
1187
+ const validateContent = isArray;
1188
+ const validateTables = (tables) =>
1189
+ objValidate(tables, validateTable, cellInvalid);
1190
+ const validateTable = (table, tableId) =>
1191
+ (!hasTablesSchema ||
1192
+ collHas(tablesSchemaMap, tableId) ||
1193
+ /* istanbul ignore next */
1194
+ cellInvalid(tableId)) &&
1195
+ objValidate(
1196
+ table,
1197
+ (row, rowId) => validateRow(tableId, rowId, row),
1198
+ () => cellInvalid(tableId),
1199
+ );
1200
+ const validateRow = (tableId, rowId, row, skipDefaults) =>
1201
+ objValidate(
1202
+ skipDefaults ? row : addDefaultsToRow(row, tableId, rowId),
1203
+ (cell, cellId) =>
1204
+ ifNotUndefined(
1205
+ getValidatedCell(tableId, rowId, cellId, cell),
1206
+ (validCell) => {
1207
+ row[cellId] = validCell;
1208
+ return true;
1209
+ },
1210
+ () => false,
1192
1211
  ),
1193
- listenerId,
1194
- ),
1212
+ () => cellInvalid(tableId, rowId),
1195
1213
  );
1196
- const resetPreStores = (queryId) => {
1214
+ const getValidatedCell = (tableId, rowId, cellId, cell) =>
1215
+ hasTablesSchema
1216
+ ? ifNotUndefined(
1217
+ mapGet(mapGet(tablesSchemaMap, tableId), cellId),
1218
+ (cellSchema) =>
1219
+ getCellOrValueType(cell) != cellSchema[TYPE]
1220
+ ? cellInvalid(tableId, rowId, cellId, cell, cellSchema[DEFAULT])
1221
+ : cell,
1222
+ () => cellInvalid(tableId, rowId, cellId, cell),
1223
+ )
1224
+ : isUndefined(getCellOrValueType(cell))
1225
+ ? cellInvalid(tableId, rowId, cellId, cell)
1226
+ : cell;
1227
+ const validateValues = (values, skipDefaults) =>
1228
+ objValidate(
1229
+ skipDefaults ? values : addDefaultsToValues(values),
1230
+ (value, valueId) =>
1231
+ ifNotUndefined(
1232
+ getValidatedValue(valueId, value),
1233
+ (validValue) => {
1234
+ values[valueId] = validValue;
1235
+ return true;
1236
+ },
1237
+ () => false,
1238
+ ),
1239
+ () => valueInvalid(),
1240
+ );
1241
+ const getValidatedValue = (valueId, value) =>
1242
+ hasValuesSchema
1243
+ ? ifNotUndefined(
1244
+ mapGet(valuesSchemaMap, valueId),
1245
+ (valueSchema) =>
1246
+ getCellOrValueType(value) != valueSchema[TYPE]
1247
+ ? valueInvalid(valueId, value, valueSchema[DEFAULT])
1248
+ : value,
1249
+ () => valueInvalid(valueId, value),
1250
+ )
1251
+ : isUndefined(getCellOrValueType(value))
1252
+ ? valueInvalid(valueId, value)
1253
+ : value;
1254
+ const addDefaultsToRow = (row, tableId, rowId) => {
1197
1255
  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);
1256
+ mapGet(tablesSchemaRowCache, tableId),
1257
+ ([rowDefaulted, rowNonDefaulted]) => {
1258
+ collForEach(rowDefaulted, (cell, cellId) => {
1259
+ if (!objHas(row, cellId)) {
1260
+ row[cellId] = cell;
1261
+ }
1262
+ });
1263
+ collForEach(rowNonDefaulted, (cellId) => {
1264
+ if (!objHas(row, cellId)) {
1265
+ cellInvalid(tableId, rowId, cellId);
1266
+ }
1267
+ });
1206
1268
  },
1207
1269
  );
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;
1270
+ return row;
2092
1271
  };
2093
1272
  const addDefaultsToValues = (values) => {
2094
1273
  if (hasValuesSchema) {
@@ -3238,508 +2417,1329 @@ const createStore = () => {
3238
2417
  [VALUE_IDS]: [0, valueIdsListeners],
3239
2418
  [HAS + VALUE]: [
3240
2419
  1,
3241
- hasValueListeners,
3242
- [getValueIds],
3243
- (ids) => [hasValue(...ids)],
3244
- ],
3245
- [VALUE]: [
2420
+ hasValueListeners,
2421
+ [getValueIds],
2422
+ (ids) => [hasValue(...ids)],
2423
+ ],
2424
+ [VALUE]: [
2425
+ 1,
2426
+ valueListeners,
2427
+ [getValueIds],
2428
+ (ids) => pairNew(getValue(ids[0])),
2429
+ ],
2430
+ InvalidValue: [1, invalidValueListeners],
2431
+ },
2432
+ ([argumentCount, idSetNode, pathGetters, extraArgsGetter], listenable) => {
2433
+ store[ADD + listenable + LISTENER] = (...args) =>
2434
+ addListener(
2435
+ args[argumentCount],
2436
+ idSetNode[args[argumentCount + 1] ? 1 : 0],
2437
+ argumentCount > 0 ? slice(args, 0, argumentCount) : void 0,
2438
+ pathGetters,
2439
+ extraArgsGetter,
2440
+ );
2441
+ },
2442
+ );
2443
+ return objFreeze(store);
2444
+ };
2445
+
2446
+ const LISTENER_ARGS = {
2447
+ HasTable: 1,
2448
+ Table: 1,
2449
+ TableCellIds: 1,
2450
+ HasTableCell: 2,
2451
+ RowCount: 1,
2452
+ RowIds: 1,
2453
+ SortedRowIds: 5,
2454
+ HasRow: 2,
2455
+ Row: 2,
2456
+ CellIds: 2,
2457
+ HasCell: 3,
2458
+ Cell: 3,
2459
+ HasValue: 1,
2460
+ Value: 1,
2461
+ InvalidCell: 3,
2462
+ InvalidValue: 1,
2463
+ };
2464
+ const newContentStampMap = (time = EMPTY_STRING) => [
2465
+ stampNewMap(time),
2466
+ stampNewMap(time),
2467
+ ];
2468
+ const validateMergeableContent = (mergeableContent) =>
2469
+ isArray(mergeableContent) &&
2470
+ size(mergeableContent) == 2 &&
2471
+ stampValidate(mergeableContent[0], (tableStamps) =>
2472
+ objValidate(
2473
+ tableStamps,
2474
+ (tableStamp) =>
2475
+ stampValidate(tableStamp, (rowStamps) =>
2476
+ objValidate(
2477
+ rowStamps,
2478
+ (rowStamp) =>
2479
+ stampValidate(rowStamp, (cellStamps) =>
2480
+ objValidate(
2481
+ cellStamps,
2482
+ (cellStamp) =>
2483
+ stampValidate(cellStamp, isCellOrValueOrNullOrUndefined),
2484
+ void 0,
2485
+ 1,
2486
+ ),
2487
+ ),
2488
+ void 0,
2489
+ 1,
2490
+ ),
2491
+ ),
2492
+ void 0,
2493
+ 1,
2494
+ ),
2495
+ ) &&
2496
+ stampValidate(mergeableContent[1], (values) =>
2497
+ objValidate(
2498
+ values,
2499
+ (value) => stampValidate(value, isCellOrValueOrNullOrUndefined),
2500
+ void 0,
2501
+ 1,
2502
+ ),
2503
+ );
2504
+ const createMergeableStore = (uniqueId) => {
2505
+ let listeningToRawStoreChanges = 1;
2506
+ let contentStampMap = newContentStampMap();
2507
+ let defaultingContent = 0;
2508
+ const touchedCells = mapNew();
2509
+ const touchedValues = setNew();
2510
+ const [getHlc, seenHlc] = getHlcFunctions(uniqueId);
2511
+ const store = createStore();
2512
+ const disableListeningToRawStoreChanges = (actions) => {
2513
+ const wasListening = listeningToRawStoreChanges;
2514
+ listeningToRawStoreChanges = 0;
2515
+ actions();
2516
+ listeningToRawStoreChanges = wasListening;
2517
+ return mergeableStore;
2518
+ };
2519
+ const mergeContentOrChanges = (contentOrChanges, isContent = 0) => {
2520
+ const tablesChanges = {};
2521
+ const valuesChanges = {};
2522
+ const [
2523
+ [tablesObj, incomingTablesTime = EMPTY_STRING, incomingTablesHash = 0],
2524
+ values,
2525
+ ] = contentOrChanges;
2526
+ const [tablesStampMap, valuesStampMap] = contentStampMap;
2527
+ const [tableStampMaps, oldTablesTime, oldTablesHash] = tablesStampMap;
2528
+ let tablesHash = isContent ? incomingTablesHash : oldTablesHash;
2529
+ let tablesTime = incomingTablesTime;
2530
+ objForEach(
2531
+ tablesObj,
2532
+ (
2533
+ [rowsObj, incomingTableTime = EMPTY_STRING, incomingTableHash = 0],
2534
+ tableId,
2535
+ ) => {
2536
+ const tableStampMap = mapEnsure(tableStampMaps, tableId, stampNewMap);
2537
+ const [rowStampMaps, oldTableTime, oldTableHash] = tableStampMap;
2538
+ let tableHash = isContent ? incomingTableHash : oldTableHash;
2539
+ let tableTime = incomingTableTime;
2540
+ objForEach(rowsObj, (row, rowId) => {
2541
+ const [rowTime, oldRowHash, rowHash] = mergeCellsOrValues(
2542
+ row,
2543
+ mapEnsure(rowStampMaps, rowId, stampNewMap),
2544
+ objEnsure(objEnsure(tablesChanges, tableId, objNew), rowId, objNew),
2545
+ isContent,
2546
+ );
2547
+ tableHash ^= isContent
2548
+ ? 0
2549
+ : (oldRowHash ? hashIdAndHash(rowId, oldRowHash) : 0) ^
2550
+ hashIdAndHash(rowId, rowHash);
2551
+ tableTime = getLatestTime(tableTime, rowTime);
2552
+ });
2553
+ tableHash ^= isContent
2554
+ ? 0
2555
+ : replaceTimeHash(oldTableTime, incomingTableTime);
2556
+ stampUpdate(tableStampMap, incomingTableTime, tableHash);
2557
+ tablesHash ^= isContent
2558
+ ? 0
2559
+ : (oldTableHash ? hashIdAndHash(tableId, oldTableHash) : 0) ^
2560
+ hashIdAndHash(tableId, tableStampMap[2]);
2561
+ tablesTime = getLatestTime(tablesTime, tableTime);
2562
+ },
2563
+ );
2564
+ tablesHash ^= isContent
2565
+ ? 0
2566
+ : replaceTimeHash(oldTablesTime, incomingTablesTime);
2567
+ stampUpdate(tablesStampMap, incomingTablesTime, tablesHash);
2568
+ const [valuesTime] = mergeCellsOrValues(
2569
+ values,
2570
+ valuesStampMap,
2571
+ valuesChanges,
2572
+ isContent,
2573
+ );
2574
+ seenHlc(getLatestTime(tablesTime, valuesTime));
2575
+ return [tablesChanges, valuesChanges, 1];
2576
+ };
2577
+ const mergeCellsOrValues = (
2578
+ things,
2579
+ thingsStampMap,
2580
+ thingsChanges,
2581
+ isContent,
2582
+ ) => {
2583
+ const [
2584
+ thingsObj,
2585
+ incomingThingsTime = EMPTY_STRING,
2586
+ incomingThingsHash = 0,
2587
+ ] = things;
2588
+ const [thingStampMaps, oldThingsTime, oldThingsHash] = thingsStampMap;
2589
+ let thingsTime = incomingThingsTime;
2590
+ let thingsHash = isContent ? incomingThingsHash : oldThingsHash;
2591
+ objForEach(
2592
+ thingsObj,
2593
+ ([thing, thingTime = EMPTY_STRING, incomingThingHash = 0], thingId) => {
2594
+ const thingStampMap = mapEnsure(thingStampMaps, thingId, () => [
2595
+ void 0,
2596
+ EMPTY_STRING,
2597
+ 0,
2598
+ ]);
2599
+ const [, oldThingTime, oldThingHash] = thingStampMap;
2600
+ if (!oldThingTime || thingTime > oldThingTime) {
2601
+ stampUpdate(
2602
+ thingStampMap,
2603
+ thingTime,
2604
+ isContent
2605
+ ? incomingThingHash
2606
+ : getHash(jsonStringWithMap(thing ?? null) + ':' + thingTime),
2607
+ );
2608
+ thingStampMap[0] = thing;
2609
+ thingsChanges[thingId] = thing;
2610
+ thingsHash ^= isContent
2611
+ ? 0
2612
+ : hashIdAndHash(thingId, oldThingHash) ^
2613
+ hashIdAndHash(thingId, thingStampMap[2]);
2614
+ thingsTime = getLatestTime(thingsTime, thingTime);
2615
+ }
2616
+ },
2617
+ );
2618
+ thingsHash ^= isContent
2619
+ ? 0
2620
+ : replaceTimeHash(oldThingsTime, incomingThingsTime);
2621
+ stampUpdate(thingsStampMap, incomingThingsTime, thingsHash);
2622
+ return [thingsTime, oldThingsHash, thingsStampMap[2]];
2623
+ };
2624
+ const preStartTransaction = () => {};
2625
+ const preFinishTransaction = () => {};
2626
+ const postFinishTransaction = () => {
2627
+ collClear(touchedCells);
2628
+ collClear(touchedValues);
2629
+ };
2630
+ const cellChanged = (tableId, rowId, cellId, newCell) => {
2631
+ setAdd(
2632
+ mapEnsure(mapEnsure(touchedCells, tableId, mapNew), rowId, setNew),
2633
+ cellId,
2634
+ );
2635
+ if (listeningToRawStoreChanges) {
2636
+ mergeContentOrChanges([
2637
+ [
2638
+ {
2639
+ [tableId]: [
2640
+ {
2641
+ [rowId]: [
2642
+ {
2643
+ [cellId]: [
2644
+ newCell,
2645
+ defaultingContent ? EMPTY_STRING : getHlc(),
2646
+ ],
2647
+ },
2648
+ ],
2649
+ },
2650
+ ],
2651
+ },
2652
+ ],
2653
+ [{}],
2654
+ 1,
2655
+ ]);
2656
+ }
2657
+ };
2658
+ const valueChanged = (valueId, newValue) => {
2659
+ setAdd(touchedValues, valueId);
2660
+ if (listeningToRawStoreChanges) {
2661
+ mergeContentOrChanges([
2662
+ [{}],
2663
+ [{[valueId]: [newValue, defaultingContent ? EMPTY_STRING : getHlc()]}],
3246
2664
  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,
2665
+ ]);
2666
+ }
2667
+ };
2668
+ const getMergeableContent = () => [
2669
+ stampMapToObjWithHash(contentStampMap[0], (tableStampMap) =>
2670
+ stampMapToObjWithHash(tableStampMap, (rowStampMap) =>
2671
+ stampMapToObjWithHash(rowStampMap),
2672
+ ),
2673
+ ),
2674
+ stampMapToObjWithHash(contentStampMap[1]),
2675
+ ];
2676
+ const getMergeableContentHashes = () => [
2677
+ contentStampMap[0][2],
2678
+ contentStampMap[1][2],
2679
+ ];
2680
+ const getMergeableTableHashes = () =>
2681
+ mapToObj(contentStampMap[0][0], getStampHash);
2682
+ const getMergeableTableDiff = (otherTableHashes) => {
2683
+ const newTables = stampNewObj(contentStampMap[0][1]);
2684
+ const differingTableHashes = {};
2685
+ mapForEach(
2686
+ contentStampMap[0][0],
2687
+ (tableId, [tableStampMap, tableTime, hash]) =>
2688
+ objHas(otherTableHashes, tableId)
2689
+ ? hash != otherTableHashes[tableId]
2690
+ ? (differingTableHashes[tableId] = hash)
2691
+ : 0
2692
+ : (newTables[0][tableId] = stampMapToObjWithoutHash(
2693
+ [tableStampMap, tableTime],
2694
+ (rowStampMap) => stampMapToObjWithoutHash(rowStampMap),
2695
+ )),
2696
+ );
2697
+ return [newTables, differingTableHashes];
2698
+ };
2699
+ const getMergeableRowHashes = (otherTableHashes) => {
2700
+ const rowHashes = {};
2701
+ objForEach(otherTableHashes, (otherTableHash, tableId) =>
2702
+ ifNotUndefined(
2703
+ mapGet(contentStampMap[0][0], tableId),
2704
+ ([rowStampMaps, , tableHash]) =>
2705
+ tableHash != otherTableHash
2706
+ ? mapForEach(
2707
+ rowStampMaps,
2708
+ (rowId, [, , rowHash]) =>
2709
+ (objEnsure(rowHashes, tableId, objNew)[rowId] = rowHash),
2710
+ )
2711
+ : 0,
2712
+ ),
2713
+ );
2714
+ return rowHashes;
2715
+ };
2716
+ const getMergeableRowDiff = (otherTableRowHashes) => {
2717
+ const newRows = stampNewObj(contentStampMap[0][1]);
2718
+ const differingRowHashes = {};
2719
+ objForEach(otherTableRowHashes, (otherRowHashes, tableId) =>
2720
+ mapForEach(
2721
+ mapGet(contentStampMap[0][0], tableId)?.[0],
2722
+ (rowId, [rowStampMap, rowTime, hash]) =>
2723
+ objHas(otherRowHashes, rowId)
2724
+ ? hash !== otherRowHashes[rowId]
2725
+ ? (objEnsure(differingRowHashes, tableId, objNew)[rowId] = hash)
2726
+ : 0
2727
+ : (objEnsure(newRows[0], tableId, stampNewObj)[0][rowId] =
2728
+ stampMapToObjWithoutHash([rowStampMap, rowTime])),
2729
+ ),
2730
+ );
2731
+ return [newRows, differingRowHashes];
2732
+ };
2733
+ const getMergeableCellHashes = (otherTableRowHashes) => {
2734
+ const cellHashes = {};
2735
+ objForEach(otherTableRowHashes, (otherRowHashes, tableId) =>
2736
+ ifNotUndefined(mapGet(contentStampMap[0][0], tableId), ([rowStampMaps]) =>
2737
+ objForEach(otherRowHashes, (otherRowHash, rowId) =>
2738
+ ifNotUndefined(
2739
+ mapGet(rowStampMaps, rowId),
2740
+ ([cellStampMaps, , rowHash]) =>
2741
+ rowHash !== otherRowHash
2742
+ ? mapForEach(
2743
+ cellStampMaps,
2744
+ (cellId, [, , cellHash]) =>
2745
+ (objEnsure(
2746
+ objEnsure(cellHashes, tableId, objNew),
2747
+ rowId,
2748
+ objNew,
2749
+ )[cellId] = cellHash),
2750
+ )
2751
+ : 0,
3311
2752
  ),
3312
2753
  ),
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;
2754
+ ),
2755
+ );
2756
+ return cellHashes;
2757
+ };
2758
+ const getMergeableCellDiff = (otherTableRowCellHashes) => {
2759
+ const [[tableStampMaps, tablesTime]] = contentStampMap;
2760
+ const tablesObj = {};
2761
+ objForEach(otherTableRowCellHashes, (otherRowCellHashes, tableId) =>
2762
+ objForEach(otherRowCellHashes, (otherCellHashes, rowId) =>
2763
+ ifNotUndefined(
2764
+ mapGet(tableStampMaps, tableId),
2765
+ ([rowStampMaps, tableTime]) =>
2766
+ ifNotUndefined(
2767
+ mapGet(rowStampMaps, rowId),
2768
+ ([cellStampMaps, rowTime]) =>
2769
+ mapForEach(cellStampMaps, (cellId, [cell, cellTime, hash]) =>
2770
+ hash !== otherCellHashes[cellId]
2771
+ ? (objEnsure(
2772
+ objEnsure(tablesObj, tableId, () =>
2773
+ stampNewObj(tableTime),
2774
+ )[0],
2775
+ rowId,
2776
+ () => stampNewObj(rowTime),
2777
+ )[0][cellId] = [cell, cellTime])
2778
+ : 0,
2779
+ ),
2780
+ ),
2781
+ ),
2782
+ ),
2783
+ );
2784
+ return stampNew(tablesObj, tablesTime);
2785
+ };
2786
+ const getMergeableValueHashes = () =>
2787
+ mapToObj(contentStampMap[1][0], getStampHash);
2788
+ const getMergeableValueDiff = (otherValueHashes) => {
2789
+ const [, [valueStampMaps, valuesTime]] = contentStampMap;
2790
+ const values = mapToObj(
2791
+ valueStampMaps,
2792
+ stampClone,
2793
+ ([, , hash], valueId) => hash == otherValueHashes?.[valueId],
2794
+ );
2795
+ return stampNew(values, valuesTime);
2796
+ };
2797
+ const setMergeableContent = (mergeableContent) =>
2798
+ disableListeningToRawStoreChanges(() =>
2799
+ validateMergeableContent(mergeableContent)
2800
+ ? store.transaction(() => {
2801
+ store.delTables().delValues();
2802
+ contentStampMap = newContentStampMap();
2803
+ store.applyChanges(mergeContentOrChanges(mergeableContent, 1));
2804
+ })
2805
+ : 0,
2806
+ );
2807
+ const setDefaultContent = (content) => {
2808
+ store.transaction(() => {
2809
+ defaultingContent = 1;
2810
+ store.setContent(content);
2811
+ defaultingContent = 0;
2812
+ });
3338
2813
  return mergeableStore;
3339
2814
  };
3340
- const mergeContentOrChanges = (contentOrChanges, isContent = 0) => {
3341
- const tablesChanges = {};
3342
- const valuesChanges = {};
2815
+ const getTransactionMergeableChanges = (withHashes = false) => {
3343
2816
  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,
2817
+ [tableStampMaps, tablesTime, tablesHash],
2818
+ [valueStampMaps, valuesTime, valuesHash],
2819
+ ] = contentStampMap;
2820
+ const newStamp = withHashes ? stampNewWithHash : stampNew;
2821
+ const tablesObj = {};
2822
+ collForEach(touchedCells, (touchedTable, tableId) =>
2823
+ ifNotUndefined(
2824
+ mapGet(tableStampMaps, tableId),
2825
+ ([rowStampMaps, tableTime, tableHash]) => {
2826
+ const tableObj = {};
2827
+ collForEach(touchedTable, (touchedRow, rowId) =>
2828
+ ifNotUndefined(
2829
+ mapGet(rowStampMaps, rowId),
2830
+ ([cellStampMaps, rowTime, rowHash]) => {
2831
+ const rowObj = {};
2832
+ collForEach(touchedRow, (cellId) => {
2833
+ ifNotUndefined(
2834
+ mapGet(cellStampMaps, cellId),
2835
+ ([cell, time, hash]) =>
2836
+ (rowObj[cellId] = newStamp(cell, time, hash)),
2837
+ );
2838
+ });
2839
+ tableObj[rowId] = newStamp(rowObj, rowTime, rowHash);
2840
+ },
2841
+ ),
3367
2842
  );
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
- },
2843
+ tablesObj[tableId] = newStamp(tableObj, tableTime, tableHash);
2844
+ },
2845
+ ),
3384
2846
  );
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,
2847
+ const valuesObj = {};
2848
+ collForEach(touchedValues, (valueId) =>
2849
+ ifNotUndefined(
2850
+ mapGet(valueStampMaps, valueId),
2851
+ ([value, time, hash]) =>
2852
+ (valuesObj[valueId] = newStamp(value, time, hash)),
2853
+ ),
3394
2854
  );
3395
- seenHlc(getLatestTime(tablesTime, valuesTime));
3396
- return [tablesChanges, valuesChanges, 1];
2855
+ return [
2856
+ newStamp(tablesObj, tablesTime, tablesHash),
2857
+ newStamp(valuesObj, valuesTime, valuesHash),
2858
+ 1,
2859
+ ];
3397
2860
  };
3398
- const mergeCellsOrValues = (
3399
- things,
3400
- thingsStampMap,
3401
- thingsChanges,
3402
- isContent,
2861
+ const applyMergeableChanges = (mergeableChanges) =>
2862
+ disableListeningToRawStoreChanges(() =>
2863
+ store.applyChanges(mergeContentOrChanges(mergeableChanges)),
2864
+ );
2865
+ const merge = (mergeableStore2) => {
2866
+ const mergeableChanges = getMergeableContent();
2867
+ const mergeableChanges2 = mergeableStore2.getMergeableContent();
2868
+ mergeableStore2.applyMergeableChanges(mergeableChanges);
2869
+ return applyMergeableChanges(mergeableChanges2);
2870
+ };
2871
+ const mergeableStore = {
2872
+ getMergeableContent,
2873
+ getMergeableContentHashes,
2874
+ getMergeableTableHashes,
2875
+ getMergeableTableDiff,
2876
+ getMergeableRowHashes,
2877
+ getMergeableRowDiff,
2878
+ getMergeableCellHashes,
2879
+ getMergeableCellDiff,
2880
+ getMergeableValueHashes,
2881
+ getMergeableValueDiff,
2882
+ setMergeableContent,
2883
+ setDefaultContent,
2884
+ getTransactionMergeableChanges,
2885
+ applyMergeableChanges,
2886
+ merge,
2887
+ };
2888
+ store.setInternalListeners(
2889
+ preStartTransaction,
2890
+ preFinishTransaction,
2891
+ postFinishTransaction,
2892
+ cellChanged,
2893
+ valueChanged,
2894
+ );
2895
+ objMap(
2896
+ store,
2897
+ (method, name) =>
2898
+ (mergeableStore[name] = // fluent methods
2899
+ strStartsWith(name, SET) ||
2900
+ strStartsWith(name, DEL) ||
2901
+ strStartsWith(name, 'apply') ||
2902
+ strEndsWith(name, TRANSACTION) ||
2903
+ name == 'call' + LISTENER
2904
+ ? (...args) => {
2905
+ method(...args);
2906
+ return mergeableStore;
2907
+ }
2908
+ : strStartsWith(name, ADD) && strEndsWith(name, LISTENER)
2909
+ ? (...args) => {
2910
+ const listenerArg = LISTENER_ARGS[slice(name, 3, -8)] ?? 0;
2911
+ const listener = args[listenerArg];
2912
+ args[listenerArg] = (_store, ...args2) =>
2913
+ listener(mergeableStore, ...args2);
2914
+ return method(...args);
2915
+ }
2916
+ : name == 'isMergeable'
2917
+ ? () => true
2918
+ : method),
2919
+ );
2920
+ return objFreeze(mergeableStore);
2921
+ };
2922
+
2923
+ const numericAggregators = /* @__PURE__ */ mapNew([
2924
+ [
2925
+ AVG,
2926
+ [
2927
+ (numbers, length) => arraySum(numbers) / length,
2928
+ (metric, add, length) => metric + (add - metric) / (length + 1),
2929
+ (metric, remove, length) => metric + (metric - remove) / (length - 1),
2930
+ (metric, add, remove, length) => metric + (add - remove) / length,
2931
+ ],
2932
+ ],
2933
+ [
2934
+ MAX,
2935
+ [
2936
+ (numbers) => mathMax(...numbers),
2937
+ (metric, add) => mathMax(add, metric),
2938
+ (metric, remove) => (remove == metric ? void 0 : metric),
2939
+ (metric, add, remove) =>
2940
+ remove == metric ? void 0 : mathMax(add, metric),
2941
+ ],
2942
+ ],
2943
+ [
2944
+ MIN,
2945
+ [
2946
+ (numbers) => mathMin(...numbers),
2947
+ (metric, add) => mathMin(add, metric),
2948
+ (metric, remove) => (remove == metric ? void 0 : metric),
2949
+ (metric, add, remove) =>
2950
+ remove == metric ? void 0 : mathMin(add, metric),
2951
+ ],
2952
+ ],
2953
+ [
2954
+ SUM,
2955
+ [
2956
+ (numbers) => arraySum(numbers),
2957
+ (metric, add) => metric + add,
2958
+ (metric, remove) => metric - remove,
2959
+ (metric, add, remove) => metric - remove + add,
2960
+ ],
2961
+ ],
2962
+ ]);
2963
+ const getAggregateValue = (
2964
+ aggregateValue,
2965
+ oldLength,
2966
+ newValues,
2967
+ changedValues,
2968
+ aggregators,
2969
+ force = false,
2970
+ ) => {
2971
+ if (collIsEmpty(newValues)) {
2972
+ return void 0;
2973
+ }
2974
+ const [aggregate, aggregateAdd, aggregateRemove, aggregateReplace] =
2975
+ aggregators;
2976
+ force ||= isUndefined(aggregateValue);
2977
+ collForEach(changedValues, ([oldValue, newValue]) => {
2978
+ if (!force) {
2979
+ aggregateValue = isUndefined(oldValue)
2980
+ ? aggregateAdd?.(aggregateValue, newValue, oldLength++)
2981
+ : isUndefined(newValue)
2982
+ ? aggregateRemove?.(aggregateValue, oldValue, oldLength--)
2983
+ : aggregateReplace?.(aggregateValue, newValue, oldValue, oldLength);
2984
+ force ||= isUndefined(aggregateValue);
2985
+ }
2986
+ });
2987
+ return force
2988
+ ? aggregate(collValues(newValues), collSize(newValues))
2989
+ : aggregateValue;
2990
+ };
2991
+
2992
+ const createMetrics = getCreateFunction((store) => {
2993
+ const metricListeners = mapNew();
2994
+ const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
2995
+ () => metrics,
2996
+ );
2997
+ const [
2998
+ getStore,
2999
+ getMetricIds,
3000
+ forEachMetric,
3001
+ hasMetric,
3002
+ getTableId,
3003
+ getMetric,
3004
+ setMetric,
3005
+ ,
3006
+ setDefinitionAndListen,
3007
+ delDefinition,
3008
+ addMetricIdsListener,
3009
+ destroy,
3010
+ ] = getDefinableFunctions(
3011
+ store,
3012
+ getUndefined,
3013
+ (value) =>
3014
+ isNaN(value) ||
3015
+ isUndefined(value) ||
3016
+ value === true ||
3017
+ value === false ||
3018
+ value === EMPTY_STRING
3019
+ ? void 0
3020
+ : value * 1,
3021
+ addListener,
3022
+ callListeners,
3023
+ );
3024
+ const setMetricDefinition = (
3025
+ metricId,
3026
+ tableId,
3027
+ aggregate,
3028
+ getNumber,
3029
+ aggregateAdd,
3030
+ aggregateRemove,
3031
+ aggregateReplace,
3403
3032
  ) => {
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);
3033
+ const aggregators = isFunction(aggregate)
3034
+ ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
3035
+ : (mapGet(numericAggregators, aggregate) ??
3036
+ mapGet(numericAggregators, SUM));
3037
+ setDefinitionAndListen(
3038
+ metricId,
3039
+ tableId,
3040
+ (change, changedNumbers, _changedSortKeys, numbers, _sortKeys, force) => {
3041
+ const oldMetric = getMetric(metricId);
3042
+ const oldLength = collSize(numbers);
3043
+ force ||= isUndefined(oldMetric);
3044
+ change();
3045
+ let newMetric = getAggregateValue(
3046
+ oldMetric,
3047
+ oldLength,
3048
+ numbers,
3049
+ changedNumbers,
3050
+ aggregators,
3051
+ force,
3052
+ );
3053
+ if (!isFiniteNumber(newMetric)) {
3054
+ newMetric = void 0;
3055
+ }
3056
+ if (newMetric != oldMetric) {
3057
+ setMetric(metricId, newMetric);
3058
+ callListeners(metricListeners, [metricId], newMetric, oldMetric);
3436
3059
  }
3437
3060
  },
3061
+ getRowCellFunction(getNumber, 1),
3438
3062
  );
3439
- thingsHash ^= isContent
3440
- ? 0
3441
- : replaceTimeHash(oldThingsTime, incomingThingsTime);
3442
- stampUpdate(thingsStampMap, incomingThingsTime, thingsHash);
3443
- return [thingsTime, oldThingsHash, thingsStampMap[2]];
3063
+ return metrics;
3444
3064
  };
3445
- const preStartTransaction = () => {};
3446
- const preFinishTransaction = () => {};
3447
- const postFinishTransaction = () => {
3448
- collClear(touchedCells);
3449
- collClear(touchedValues);
3065
+ const delMetricDefinition = (metricId) => {
3066
+ delDefinition(metricId);
3067
+ return metrics;
3450
3068
  };
3451
- const cellChanged = (tableId, rowId, cellId, newCell) => {
3452
- setAdd(
3453
- mapEnsure(mapEnsure(touchedCells, tableId, mapNew), rowId, setNew),
3454
- cellId,
3069
+ const addMetricListener = (metricId, listener) =>
3070
+ addListener(listener, metricListeners, [metricId]);
3071
+ const delListener = (listenerId) => {
3072
+ delListenerImpl(listenerId);
3073
+ return metrics;
3074
+ };
3075
+ const getListenerStats = () => ({
3076
+ metric: collSize2(metricListeners),
3077
+ });
3078
+ const metrics = {
3079
+ setMetricDefinition,
3080
+ delMetricDefinition,
3081
+ getStore,
3082
+ getMetricIds,
3083
+ forEachMetric,
3084
+ hasMetric,
3085
+ getTableId,
3086
+ getMetric,
3087
+ addMetricIdsListener,
3088
+ addMetricListener,
3089
+ delListener,
3090
+ destroy,
3091
+ getListenerStats,
3092
+ };
3093
+ return objFreeze(metrics);
3094
+ });
3095
+
3096
+ const createQueries = getCreateFunction((store) => {
3097
+ const createStore = store.createStore;
3098
+ const preStore = createStore();
3099
+ const resultStore = createStore();
3100
+ const preStoreListenerIds = mapNew();
3101
+ const {
3102
+ addListener,
3103
+ callListeners,
3104
+ delListener: delListenerImpl,
3105
+ } = resultStore;
3106
+ const [
3107
+ getStore,
3108
+ getQueryIds,
3109
+ forEachQuery,
3110
+ hasQuery,
3111
+ getTableId,
3112
+ ,
3113
+ ,
3114
+ setDefinition,
3115
+ ,
3116
+ delDefinition,
3117
+ addQueryIdsListenerImpl,
3118
+ destroy,
3119
+ addStoreListeners,
3120
+ delStoreListeners,
3121
+ ] = getDefinableFunctions(
3122
+ store,
3123
+ () => true,
3124
+ getUndefined,
3125
+ addListener,
3126
+ callListeners,
3127
+ );
3128
+ const addPreStoreListener = (preStore2, queryId, ...listenerIds) =>
3129
+ arrayForEach(listenerIds, (listenerId) =>
3130
+ setAdd(
3131
+ mapEnsure(
3132
+ mapEnsure(preStoreListenerIds, queryId, mapNew),
3133
+ preStore2,
3134
+ setNew,
3135
+ ),
3136
+ listenerId,
3137
+ ),
3138
+ );
3139
+ const resetPreStores = (queryId) => {
3140
+ ifNotUndefined(
3141
+ mapGet(preStoreListenerIds, queryId),
3142
+ (queryPreStoreListenerIds) => {
3143
+ mapForEach(queryPreStoreListenerIds, (preStore2, listenerIds) =>
3144
+ collForEach(listenerIds, (listenerId) =>
3145
+ preStore2.delListener(listenerId),
3146
+ ),
3147
+ );
3148
+ collClear(queryPreStoreListenerIds);
3149
+ },
3150
+ );
3151
+ arrayForEach([resultStore, preStore], (store2) => store2.delTable(queryId));
3152
+ };
3153
+ const synchronizeTransactions = (queryId, fromStore, toStore) =>
3154
+ addPreStoreListener(
3155
+ fromStore,
3156
+ queryId,
3157
+ fromStore.addStartTransactionListener(toStore.startTransaction),
3158
+ fromStore.addDidFinishTransactionListener(() =>
3159
+ toStore.finishTransaction(),
3160
+ ),
3161
+ );
3162
+ const setQueryDefinition = (queryId, tableId, build) => {
3163
+ setDefinition(queryId, tableId);
3164
+ resetPreStores(queryId);
3165
+ const selectEntries = [];
3166
+ const joinEntries = [[null, [tableId, null, null, [], mapNew()]]];
3167
+ const wheres = [];
3168
+ const groupEntries = [];
3169
+ const havings = [];
3170
+ const select = (arg1, arg2) => {
3171
+ const selectEntry = isFunction(arg1)
3172
+ ? [size(selectEntries) + EMPTY_STRING, arg1]
3173
+ : [
3174
+ isUndefined(arg2) ? arg1 : arg2,
3175
+ (getTableCell) => getTableCell(arg1, arg2),
3176
+ ];
3177
+ arrayPush(selectEntries, selectEntry);
3178
+ return {as: (selectedCellId) => (selectEntry[0] = selectedCellId)};
3179
+ };
3180
+ const join = (joinedTableId, arg1, arg2) => {
3181
+ const fromIntermediateJoinedTableId =
3182
+ isUndefined(arg2) || isFunction(arg1) ? null : arg1;
3183
+ const onArg = isUndefined(fromIntermediateJoinedTableId) ? arg1 : arg2;
3184
+ const joinEntry = [
3185
+ joinedTableId,
3186
+ [
3187
+ joinedTableId,
3188
+ fromIntermediateJoinedTableId,
3189
+ isFunction(onArg) ? onArg : (getCell) => getCell(onArg),
3190
+ [],
3191
+ mapNew(),
3192
+ ],
3193
+ ];
3194
+ arrayPush(joinEntries, joinEntry);
3195
+ return {as: (joinedTableId2) => (joinEntry[0] = joinedTableId2)};
3196
+ };
3197
+ const where = (arg1, arg2, arg3) =>
3198
+ arrayPush(
3199
+ wheres,
3200
+ isFunction(arg1)
3201
+ ? arg1
3202
+ : isUndefined(arg3)
3203
+ ? (getTableCell) => getTableCell(arg1) === arg2
3204
+ : (getTableCell) => getTableCell(arg1, arg2) === arg3,
3205
+ );
3206
+ const group = (
3207
+ selectedCellId,
3208
+ aggregate,
3209
+ aggregateAdd,
3210
+ aggregateRemove,
3211
+ aggregateReplace,
3212
+ ) => {
3213
+ const groupEntry = [
3214
+ selectedCellId,
3215
+ [
3216
+ selectedCellId,
3217
+ isFunction(aggregate)
3218
+ ? [aggregate, aggregateAdd, aggregateRemove, aggregateReplace]
3219
+ : (mapGet(numericAggregators, aggregate) ?? [
3220
+ (_cells, length) => length,
3221
+ ]),
3222
+ ],
3223
+ ];
3224
+ arrayPush(groupEntries, groupEntry);
3225
+ return {as: (groupedCellId) => (groupEntry[0] = groupedCellId)};
3226
+ };
3227
+ const having = (arg1, arg2) =>
3228
+ arrayPush(
3229
+ havings,
3230
+ isFunction(arg1)
3231
+ ? arg1
3232
+ : (getSelectedOrGroupedCell) =>
3233
+ getSelectedOrGroupedCell(arg1) === arg2,
3234
+ );
3235
+ build({select, join, where, group, having});
3236
+ const selects = mapNew(selectEntries);
3237
+ if (collIsEmpty(selects)) {
3238
+ return queries;
3239
+ }
3240
+ const joins = mapNew(joinEntries);
3241
+ mapForEach(joins, (asTableId, [, fromAsTableId]) =>
3242
+ ifNotUndefined(mapGet(joins, fromAsTableId), ({3: toAsTableIds}) =>
3243
+ isUndefined(asTableId) ? 0 : arrayPush(toAsTableIds, asTableId),
3244
+ ),
3455
3245
  );
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
- ],
3246
+ const groups = mapNew(groupEntries);
3247
+ let selectJoinWhereStore = preStore;
3248
+ if (collIsEmpty(groups) && arrayIsEmpty(havings)) {
3249
+ selectJoinWhereStore = resultStore;
3250
+ } else {
3251
+ synchronizeTransactions(queryId, selectJoinWhereStore, resultStore);
3252
+ const groupedSelectedCellIds = mapNew();
3253
+ mapForEach(groups, (groupedCellId, [selectedCellId, aggregators]) =>
3254
+ setAdd(mapEnsure(groupedSelectedCellIds, selectedCellId, setNew), [
3255
+ groupedCellId,
3256
+ aggregators,
3257
+ ]),
3258
+ );
3259
+ const groupBySelectedCellIds = setNew();
3260
+ mapForEach(selects, (selectedCellId) =>
3261
+ collHas(groupedSelectedCellIds, selectedCellId)
3262
+ ? 0
3263
+ : setAdd(groupBySelectedCellIds, selectedCellId),
3264
+ );
3265
+ const tree = mapNew();
3266
+ const writeGroupRow = (
3267
+ leaf,
3268
+ changedGroupedSelectedCells,
3269
+ selectedRowId,
3270
+ forceRemove,
3271
+ ) =>
3272
+ ifNotUndefined(
3273
+ leaf,
3274
+ ([selectedCells, selectedRowIds, groupRowId, groupRow]) => {
3275
+ mapForEach(
3276
+ changedGroupedSelectedCells,
3277
+ (selectedCellId, [newCell]) => {
3278
+ const selectedCell = mapEnsure(
3279
+ selectedCells,
3280
+ selectedCellId,
3281
+ mapNew,
3282
+ );
3283
+ const oldLeafCell = mapGet(selectedCell, selectedRowId);
3284
+ const newLeafCell = forceRemove ? void 0 : newCell;
3285
+ if (oldLeafCell !== newLeafCell) {
3286
+ const oldNewSet = setNew([[oldLeafCell, newLeafCell]]);
3287
+ const oldLength = collSize(selectedCell);
3288
+ mapSet(selectedCell, selectedRowId, newLeafCell);
3289
+ collForEach(
3290
+ mapGet(groupedSelectedCellIds, selectedCellId),
3291
+ ([groupedCellId, aggregators]) => {
3292
+ const aggregateValue = getAggregateValue(
3293
+ groupRow[groupedCellId],
3294
+ oldLength,
3295
+ selectedCell,
3296
+ oldNewSet,
3297
+ aggregators,
3298
+ );
3299
+ groupRow[groupedCellId] = isUndefined(
3300
+ getCellOrValueType(aggregateValue),
3301
+ )
3302
+ ? null
3303
+ : aggregateValue;
3304
+ },
3305
+ );
3306
+ }
3470
3307
  },
3471
- ],
3308
+ );
3309
+ if (
3310
+ collIsEmpty(selectedRowIds) ||
3311
+ !arrayEvery(havings, (having2) =>
3312
+ having2((cellId) => groupRow[cellId]),
3313
+ )
3314
+ ) {
3315
+ resultStore.delRow(queryId, groupRowId);
3316
+ } else if (isUndefined(groupRowId)) {
3317
+ leaf[2] = resultStore.addRow(queryId, groupRow);
3318
+ } else {
3319
+ resultStore.setRow(queryId, groupRowId, groupRow);
3320
+ }
3472
3321
  },
3473
- ],
3474
- [{}],
3475
- 1,
3476
- ]);
3322
+ );
3323
+ addPreStoreListener(
3324
+ selectJoinWhereStore,
3325
+ queryId,
3326
+ selectJoinWhereStore.addRowListener(
3327
+ queryId,
3328
+ null,
3329
+ (_store, _tableId, selectedRowId, getCellChange) => {
3330
+ const oldPath = [];
3331
+ const newPath = [];
3332
+ const changedGroupedSelectedCells = mapNew();
3333
+ const rowExists = selectJoinWhereStore.hasRow(
3334
+ queryId,
3335
+ selectedRowId,
3336
+ );
3337
+ let changedLeaf = !rowExists;
3338
+ collForEach(groupBySelectedCellIds, (selectedCellId) => {
3339
+ const [changed, oldCell, newCell] = getCellChange(
3340
+ queryId,
3341
+ selectedRowId,
3342
+ selectedCellId,
3343
+ );
3344
+ arrayPush(oldPath, oldCell);
3345
+ arrayPush(newPath, newCell);
3346
+ changedLeaf ||= changed;
3347
+ });
3348
+ mapForEach(groupedSelectedCellIds, (selectedCellId) => {
3349
+ const [changed, , newCell] = getCellChange(
3350
+ queryId,
3351
+ selectedRowId,
3352
+ selectedCellId,
3353
+ );
3354
+ if (changedLeaf || changed) {
3355
+ mapSet(changedGroupedSelectedCells, selectedCellId, [newCell]);
3356
+ }
3357
+ });
3358
+ if (changedLeaf) {
3359
+ writeGroupRow(
3360
+ visitTree(tree, oldPath, void 0, ([, selectedRowIds]) => {
3361
+ collDel(selectedRowIds, selectedRowId);
3362
+ return collIsEmpty(selectedRowIds);
3363
+ }),
3364
+ changedGroupedSelectedCells,
3365
+ selectedRowId,
3366
+ 1,
3367
+ );
3368
+ }
3369
+ if (rowExists) {
3370
+ writeGroupRow(
3371
+ visitTree(
3372
+ tree,
3373
+ newPath,
3374
+ () => {
3375
+ const groupRow = {};
3376
+ collForEach(
3377
+ groupBySelectedCellIds,
3378
+ (selectedCellId) =>
3379
+ (groupRow[selectedCellId] =
3380
+ selectJoinWhereStore.getCell(
3381
+ queryId,
3382
+ selectedRowId,
3383
+ selectedCellId,
3384
+ )),
3385
+ );
3386
+ return [mapNew(), setNew(), void 0, groupRow];
3387
+ },
3388
+ ([, selectedRowIds]) => {
3389
+ setAdd(selectedRowIds, selectedRowId);
3390
+ },
3391
+ ),
3392
+ changedGroupedSelectedCells,
3393
+ selectedRowId,
3394
+ );
3395
+ }
3396
+ },
3397
+ ),
3398
+ );
3477
3399
  }
3478
- };
3479
- const valueChanged = (valueId, newValue) => {
3480
- setAdd(touchedValues, valueId);
3481
- if (listeningToRawStoreChanges) {
3482
- mergeContentOrChanges([
3483
- [{}],
3484
- [{[valueId]: [newValue, defaultingContent ? EMPTY_STRING : getHlc()]}],
3400
+ synchronizeTransactions(queryId, store, selectJoinWhereStore);
3401
+ const writeSelectRow = (rootRowId) => {
3402
+ const getTableCell = (arg1, arg2) =>
3403
+ store.getCell(
3404
+ ...(isUndefined(arg2)
3405
+ ? [tableId, rootRowId, arg1]
3406
+ : arg1 === tableId
3407
+ ? [tableId, rootRowId, arg2]
3408
+ : [
3409
+ mapGet(joins, arg1)?.[0],
3410
+ mapGet(mapGet(joins, arg1)?.[4], rootRowId)?.[0],
3411
+ arg2,
3412
+ ]),
3413
+ );
3414
+ selectJoinWhereStore.transaction(() =>
3415
+ arrayEvery(wheres, (where2) => where2(getTableCell))
3416
+ ? mapForEach(selects, (asCellId, tableCellGetter) =>
3417
+ setOrDelCell(
3418
+ selectJoinWhereStore,
3419
+ queryId,
3420
+ rootRowId,
3421
+ asCellId,
3422
+ tableCellGetter(getTableCell, rootRowId),
3423
+ ),
3424
+ )
3425
+ : selectJoinWhereStore.delRow(queryId, rootRowId),
3426
+ );
3427
+ };
3428
+ const listenToTable = (rootRowId, tableId2, rowId, joinedTableIds2) => {
3429
+ const getCell = (cellId) => store.getCell(tableId2, rowId, cellId);
3430
+ arrayForEach(joinedTableIds2, (remoteAsTableId) => {
3431
+ const [realJoinedTableId, , on, nextJoinedTableIds, remoteIdPair] =
3432
+ mapGet(joins, remoteAsTableId);
3433
+ const remoteRowId = on?.(getCell, rootRowId);
3434
+ const [previousRemoteRowId, previousRemoteListenerId] =
3435
+ mapGet(remoteIdPair, rootRowId) ?? [];
3436
+ if (remoteRowId != previousRemoteRowId) {
3437
+ if (!isUndefined(previousRemoteListenerId)) {
3438
+ delStoreListeners(queryId, previousRemoteListenerId);
3439
+ }
3440
+ mapSet(
3441
+ remoteIdPair,
3442
+ rootRowId,
3443
+ isUndefined(remoteRowId)
3444
+ ? null
3445
+ : [
3446
+ remoteRowId,
3447
+ ...addStoreListeners(
3448
+ queryId,
3449
+ 1,
3450
+ store.addRowListener(realJoinedTableId, remoteRowId, () =>
3451
+ listenToTable(
3452
+ rootRowId,
3453
+ realJoinedTableId,
3454
+ remoteRowId,
3455
+ nextJoinedTableIds,
3456
+ ),
3457
+ ),
3458
+ ),
3459
+ ],
3460
+ );
3461
+ }
3462
+ });
3463
+ writeSelectRow(rootRowId);
3464
+ };
3465
+ const {3: joinedTableIds} = mapGet(joins, null);
3466
+ selectJoinWhereStore.transaction(() =>
3467
+ addStoreListeners(
3468
+ queryId,
3485
3469
  1,
3486
- ]);
3487
- }
3488
- };
3489
- const getMergeableContent = () => [
3490
- stampMapToObjWithHash(contentStampMap[0], (tableStampMap) =>
3491
- stampMapToObjWithHash(tableStampMap, (rowStampMap) =>
3492
- stampMapToObjWithHash(rowStampMap),
3470
+ store.addRowListener(tableId, null, (_store, _tableId, rootRowId) => {
3471
+ if (store.hasRow(tableId, rootRowId)) {
3472
+ listenToTable(rootRowId, tableId, rootRowId, joinedTableIds);
3473
+ } else {
3474
+ selectJoinWhereStore.delRow(queryId, rootRowId);
3475
+ collForEach(joins, ({4: idsByRootRowId}) =>
3476
+ ifNotUndefined(
3477
+ mapGet(idsByRootRowId, rootRowId),
3478
+ ([, listenerId]) => {
3479
+ delStoreListeners(queryId, listenerId);
3480
+ mapSet(idsByRootRowId, rootRowId);
3481
+ },
3482
+ ),
3483
+ );
3484
+ }
3485
+ }),
3493
3486
  ),
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
3487
  );
3518
- return [newTables, differingTableHashes];
3488
+ return queries;
3519
3489
  };
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;
3490
+ const delQueryDefinition = (queryId) => {
3491
+ resetPreStores(queryId);
3492
+ delDefinition(queryId);
3493
+ return queries;
3536
3494
  };
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];
3495
+ const addQueryIdsListener = (listener) =>
3496
+ addQueryIdsListenerImpl(() => listener(queries));
3497
+ const delListener = (listenerId) => {
3498
+ delListenerImpl(listenerId);
3499
+ return queries;
3553
3500
  };
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;
3501
+ const getListenerStats = () => {
3502
+ const {
3503
+ tables: _1,
3504
+ tableIds: _2,
3505
+ transaction: _3,
3506
+ ...stats
3507
+ } = resultStore.getListenerStats();
3508
+ return stats;
3578
3509
  };
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);
3510
+ const queries = {
3511
+ setQueryDefinition,
3512
+ delQueryDefinition,
3513
+ getStore,
3514
+ getQueryIds,
3515
+ forEachQuery,
3516
+ hasQuery,
3517
+ getTableId,
3518
+ addQueryIdsListener,
3519
+ delListener,
3520
+ destroy,
3521
+ getListenerStats,
3606
3522
  };
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],
3523
+ objMap(
3524
+ {
3525
+ [TABLE]: [1, 1],
3526
+ [TABLE + CELL_IDS]: [0, 1],
3527
+ [ROW_COUNT]: [0, 1],
3528
+ [ROW_IDS]: [0, 1],
3529
+ [SORTED_ROW_IDS]: [0, 5],
3530
+ [ROW]: [1, 2],
3531
+ [CELL_IDS]: [0, 2],
3532
+ [CELL]: [1, 3],
3533
+ },
3534
+ ([hasAndForEach, argumentCount], gettable) => {
3535
+ arrayForEach(
3536
+ hasAndForEach ? [GET, 'has', 'forEach'] : [GET],
3537
+ (prefix) =>
3538
+ (queries[prefix + RESULT + gettable] = (...args) =>
3539
+ resultStore[prefix + gettable](...args)),
3540
+ );
3541
+ queries[ADD + RESULT + gettable + LISTENER] = (...args) =>
3542
+ resultStore[ADD + gettable + LISTENER](
3543
+ ...slice(args, 0, argumentCount),
3544
+ (_store, ...listenerArgs) =>
3545
+ args[argumentCount](queries, ...listenerArgs),
3546
+ true,
3547
+ );
3548
+ },
3549
+ );
3550
+ return objFreeze(queries);
3551
+ });
3552
+
3553
+ const createRelationships = getCreateFunction((store) => {
3554
+ const remoteTableIds = mapNew();
3555
+ const remoteRowIdListeners = mapNew();
3556
+ const localRowIdsListeners = mapNew();
3557
+ const linkedRowIdsListeners = mapNew();
3558
+ const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
3559
+ () => relationships,
3560
+ );
3561
+ const [
3562
+ getStore,
3563
+ getRelationshipIds,
3564
+ forEachRelationshipImpl,
3565
+ hasRelationship,
3566
+ getLocalTableId,
3567
+ getRelationship,
3568
+ ,
3569
+ ,
3570
+ setDefinitionAndListen,
3571
+ delDefinition,
3572
+ addRelationshipIdsListener,
3573
+ destroy,
3574
+ ] = getDefinableFunctions(
3575
+ store,
3576
+ () => [mapNew(), mapNew(), mapNew(), mapNew()],
3577
+ (value) => (isUndefined(value) ? void 0 : value + EMPTY_STRING),
3578
+ addListener,
3579
+ callListeners,
3580
+ );
3581
+ const getLinkedRowIdsCache = (relationshipId, firstRowId, skipCache) =>
3582
+ ifNotUndefined(
3583
+ getRelationship(relationshipId),
3584
+ ([remoteRows, , linkedRowsCache]) => {
3585
+ if (!collHas(linkedRowsCache, firstRowId)) {
3586
+ const linkedRows = setNew();
3587
+ if (
3588
+ getLocalTableId(relationshipId) != getRemoteTableId(relationshipId)
3589
+ ) {
3590
+ setAdd(linkedRows, firstRowId);
3591
+ } else {
3592
+ let rowId = firstRowId;
3593
+ while (!isUndefined(rowId) && !collHas(linkedRows, rowId)) {
3594
+ setAdd(linkedRows, rowId);
3595
+ rowId = mapGet(remoteRows, rowId);
3596
+ }
3597
+ }
3598
+ if (skipCache) {
3599
+ return linkedRows;
3600
+ }
3601
+ mapSet(linkedRowsCache, firstRowId, linkedRows);
3602
+ }
3603
+ return mapGet(linkedRowsCache, firstRowId);
3604
+ },
3615
3605
  );
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,
3606
+ const delLinkedRowIdsCache = (relationshipId, firstRowId) =>
3607
+ ifNotUndefined(getRelationship(relationshipId), ([, , linkedRowsCache]) =>
3608
+ mapSet(linkedRowsCache, firstRowId),
3627
3609
  );
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);
3610
+ const setRelationshipDefinition = (
3611
+ relationshipId,
3612
+ localTableId,
3613
+ remoteTableId,
3614
+ getRemoteRowId2,
3615
+ ) => {
3616
+ mapSet(remoteTableIds, relationshipId, remoteTableId);
3617
+ setDefinitionAndListen(
3618
+ relationshipId,
3619
+ localTableId,
3620
+ (change, changedRemoteRowIds) => {
3621
+ const changedLocalRows = setNew();
3622
+ const changedRemoteRows = setNew();
3623
+ const changedLinkedRows = setNew();
3624
+ const [localRows, remoteRows] = getRelationship(relationshipId);
3625
+ collForEach(
3626
+ changedRemoteRowIds,
3627
+ ([oldRemoteRowId, newRemoteRowId], localRowId) => {
3628
+ if (!isUndefined(oldRemoteRowId)) {
3629
+ setAdd(changedRemoteRows, oldRemoteRowId);
3630
+ ifNotUndefined(
3631
+ mapGet(remoteRows, oldRemoteRowId),
3632
+ (oldRemoteRow) => {
3633
+ collDel(oldRemoteRow, localRowId);
3634
+ if (collIsEmpty(oldRemoteRow)) {
3635
+ mapSet(remoteRows, oldRemoteRowId);
3636
+ }
3637
+ },
3638
+ );
3639
+ }
3640
+ if (!isUndefined(newRemoteRowId)) {
3641
+ setAdd(changedRemoteRows, newRemoteRowId);
3642
+ if (!collHas(remoteRows, newRemoteRowId)) {
3643
+ mapSet(remoteRows, newRemoteRowId, setNew());
3644
+ }
3645
+ setAdd(mapGet(remoteRows, newRemoteRowId), localRowId);
3646
+ }
3647
+ setAdd(changedLocalRows, localRowId);
3648
+ mapSet(localRows, localRowId, newRemoteRowId);
3649
+ mapForEach(
3650
+ mapGet(linkedRowIdsListeners, relationshipId),
3651
+ (firstRowId) => {
3652
+ if (
3653
+ collHas(
3654
+ getLinkedRowIdsCache(relationshipId, firstRowId),
3655
+ localRowId,
3656
+ )
3657
+ ) {
3658
+ setAdd(changedLinkedRows, firstRowId);
3659
+ }
3661
3660
  },
3662
- ),
3663
- );
3664
- tablesObj[tableId] = newStamp(tableObj, tableTime, tableHash);
3665
- },
3666
- ),
3661
+ );
3662
+ },
3663
+ );
3664
+ change();
3665
+ collForEach(changedLocalRows, (localRowId) =>
3666
+ callListeners(remoteRowIdListeners, [relationshipId, localRowId]),
3667
+ );
3668
+ collForEach(changedRemoteRows, (remoteRowId) =>
3669
+ callListeners(localRowIdsListeners, [relationshipId, remoteRowId]),
3670
+ );
3671
+ collForEach(changedLinkedRows, (firstRowId) => {
3672
+ delLinkedRowIdsCache(relationshipId, firstRowId);
3673
+ callListeners(linkedRowIdsListeners, [relationshipId, firstRowId]);
3674
+ });
3675
+ },
3676
+ getRowCellFunction(getRemoteRowId2),
3667
3677
  );
3668
- const valuesObj = {};
3669
- collForEach(touchedValues, (valueId) =>
3670
- ifNotUndefined(
3671
- mapGet(valueStampMaps, valueId),
3672
- ([value, time, hash]) =>
3673
- (valuesObj[valueId] = newStamp(value, time, hash)),
3678
+ return relationships;
3679
+ };
3680
+ const forEachRelationship = (relationshipCallback) =>
3681
+ forEachRelationshipImpl((relationshipId) =>
3682
+ relationshipCallback(relationshipId, (rowCallback) =>
3683
+ store.forEachRow(getLocalTableId(relationshipId), rowCallback),
3674
3684
  ),
3675
3685
  );
3676
- return [
3677
- newStamp(tablesObj, tablesTime, tablesHash),
3678
- newStamp(valuesObj, valuesTime, valuesHash),
3679
- 1,
3680
- ];
3686
+ const delRelationshipDefinition = (relationshipId) => {
3687
+ mapSet(remoteTableIds, relationshipId);
3688
+ delDefinition(relationshipId);
3689
+ return relationships;
3681
3690
  };
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);
3691
+ const getRemoteTableId = (relationshipId) =>
3692
+ mapGet(remoteTableIds, relationshipId);
3693
+ const getRemoteRowId = (relationshipId, localRowId) =>
3694
+ mapGet(getRelationship(relationshipId)?.[0], localRowId);
3695
+ const getLocalRowIds = (relationshipId, remoteRowId) =>
3696
+ collValues(mapGet(getRelationship(relationshipId)?.[1], remoteRowId));
3697
+ const getLinkedRowIds = (relationshipId, firstRowId) =>
3698
+ isUndefined(getRelationship(relationshipId))
3699
+ ? [firstRowId]
3700
+ : collValues(getLinkedRowIdsCache(relationshipId, firstRowId, true));
3701
+ const addRemoteRowIdListener = (relationshipId, localRowId, listener) =>
3702
+ addListener(listener, remoteRowIdListeners, [relationshipId, localRowId]);
3703
+ const addLocalRowIdsListener = (relationshipId, remoteRowId, listener) =>
3704
+ addListener(listener, localRowIdsListeners, [relationshipId, remoteRowId]);
3705
+ const addLinkedRowIdsListener = (relationshipId, firstRowId, listener) => {
3706
+ getLinkedRowIdsCache(relationshipId, firstRowId);
3707
+ return addListener(listener, linkedRowIdsListeners, [
3708
+ relationshipId,
3709
+ firstRowId,
3710
+ ]);
3691
3711
  };
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,
3712
+ const delListener = (listenerId) => {
3713
+ delLinkedRowIdsCache(...(delListenerImpl(listenerId) ?? []));
3714
+ return relationships;
3708
3715
  };
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
- };
3716
+ const getListenerStats = () => ({
3717
+ remoteRowId: collSize3(remoteRowIdListeners),
3718
+ localRowIds: collSize3(localRowIdsListeners),
3719
+ linkedRowIds: collSize3(linkedRowIdsListeners),
3720
+ });
3721
+ const relationships = {
3722
+ setRelationshipDefinition,
3723
+ delRelationshipDefinition,
3724
+ getStore,
3725
+ getRelationshipIds,
3726
+ forEachRelationship,
3727
+ hasRelationship,
3728
+ getLocalTableId,
3729
+ getRemoteTableId,
3730
+ getRemoteRowId,
3731
+ getLocalRowIds,
3732
+ getLinkedRowIds,
3733
+ addRelationshipIdsListener,
3734
+ addRemoteRowIdListener,
3735
+ addLocalRowIdsListener,
3736
+ addLinkedRowIdsListener,
3737
+ delListener,
3738
+ destroy,
3739
+ getListenerStats,
3740
+ };
3741
+ return objFreeze(relationships);
3742
+ });
3743
3743
 
3744
3744
  export {
3745
3745
  createCheckpoints,