envio 3.12.0 → 3.13.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/package.json +6 -6
  2. package/src/BatchProcessing.res +9 -9
  3. package/src/BatchProcessing.res.mjs +5 -5
  4. package/src/Bin.res +24 -17
  5. package/src/Bin.res.mjs +5 -0
  6. package/src/ChainFetching.res +31 -13
  7. package/src/ChainFetching.res.mjs +9 -4
  8. package/src/ChainState.res +55 -3
  9. package/src/ChainState.res.mjs +46 -3
  10. package/src/ChainState.resi +3 -1
  11. package/src/Config.res +35 -0
  12. package/src/Config.res.mjs +39 -0
  13. package/src/Core.res +4 -0
  14. package/src/Core.res.mjs +4 -0
  15. package/src/CrossChainState.res +61 -4
  16. package/src/CrossChainState.res.mjs +39 -5
  17. package/src/CrossChainState.resi +10 -1
  18. package/src/Env.res +4 -0
  19. package/src/FetchState.res +51 -46
  20. package/src/FetchState.res.mjs +54 -36
  21. package/src/InMemoryTable.res +155 -67
  22. package/src/InMemoryTable.res.mjs +151 -60
  23. package/src/IndexerLoop.res +2 -0
  24. package/src/IndexerLoop.res.mjs +1 -0
  25. package/src/IndexerState.res +41 -1
  26. package/src/IndexerState.res.mjs +43 -4
  27. package/src/IndexerState.resi +10 -0
  28. package/src/LoadLayer.res +57 -34
  29. package/src/LoadLayer.res.mjs +45 -62
  30. package/src/LoadLayer.resi +1 -1
  31. package/src/Logging.res +38 -6
  32. package/src/Logging.res.mjs +32 -5
  33. package/src/Main.res +131 -268
  34. package/src/Main.res.mjs +28 -152
  35. package/src/Metrics.res +263 -102
  36. package/src/Metrics.res.mjs +227 -48
  37. package/src/Persistence.res +27 -2
  38. package/src/Persistence.res.mjs +9 -2
  39. package/src/PgStorage.res +109 -71
  40. package/src/PgStorage.res.mjs +88 -58
  41. package/src/Server.res +181 -0
  42. package/src/Server.res.mjs +143 -0
  43. package/src/Supervisor.res +415 -0
  44. package/src/Supervisor.res.mjs +325 -0
  45. package/src/TestIndexer.res +9 -25
  46. package/src/TestIndexer.res.mjs +5 -4
  47. package/src/UserContext.res +13 -32
  48. package/src/UserContext.res.mjs +1 -7
  49. package/src/Utils.res +1 -4
  50. package/src/Utils.res.mjs +7 -16
  51. package/src/Worker.res +95 -0
  52. package/src/Worker.res.mjs +80 -0
  53. package/src/bindings/NodeJs.res +41 -0
  54. package/src/db/EntityFilter.res +487 -275
  55. package/src/db/EntityFilter.res.mjs +557 -309
  56. package/src/db/InternalTable.res +8 -1
  57. package/src/db/InternalTable.res.mjs +5 -1
  58. package/src/db/Table.res +21 -6
  59. package/src/db/Table.res.mjs +13 -4
  60. package/src/sources/BlockStore.res +7 -2
  61. package/src/sources/EvmHyperSyncSource.res +2 -0
  62. package/src/sources/EvmHyperSyncSource.res.mjs +2 -2
  63. package/src/sources/FuelHyperSyncSource.res +1 -0
  64. package/src/sources/FuelHyperSyncSource.res.mjs +1 -1
  65. package/src/sources/HyperSync.res +4 -0
  66. package/src/sources/HyperSync.res.mjs +4 -2
  67. package/src/sources/HyperSync.resi +1 -0
  68. package/src/sources/HyperSyncClient.res +3 -0
  69. package/src/sources/HyperSyncSSE.res +1 -1
  70. package/src/sources/HyperSyncSSE.res.mjs +4 -10
  71. package/src/sources/RpcSource.res +1 -0
  72. package/src/sources/RpcSource.res.mjs +1 -1
  73. package/src/sources/SimulateSource.res +1 -0
  74. package/src/sources/SimulateSource.res.mjs +1 -1
  75. package/src/sources/Source.res +7 -0
  76. package/src/sources/SourceManager.res +4 -3
  77. package/src/sources/SourceManager.res.mjs +2 -2
  78. package/src/sources/SvmHyperSyncClient.res +5 -0
  79. package/src/sources/SvmHyperSyncSource.res +3 -0
  80. package/src/sources/SvmHyperSyncSource.res.mjs +4 -2
  81. package/src/tui/Tui.res +24 -0
  82. package/src/tui/Tui.res.mjs +18 -0
  83. package/src/tui/components/SyncETA.res +12 -6
  84. package/src/tui/components/SyncETA.res.mjs +12 -8
@@ -2,104 +2,48 @@
2
2
 
3
3
  import * as Table from "./Table.res.mjs";
4
4
  import * as Utils from "../Utils.res.mjs";
5
- import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
6
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
7
7
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
8
8
 
9
- function toString(tNonOptional) {
10
- if (Array.isArray(tNonOptional)) {
11
- return `[` + tNonOptional.map(toString).join(",") + `]`;
12
- }
13
- switch (typeof tNonOptional) {
14
- case "string" :
15
- return tNonOptional;
16
- case "bigint" :
17
- case "number" :
18
- return tNonOptional.toString();
19
- case "object" :
20
- return tNonOptional.toString();
21
- case "boolean" :
22
- if (tNonOptional) {
23
- return "true";
24
- } else {
25
- return "false";
26
- }
27
- }
28
- }
9
+ let nullish = (v => v === undefined || v === null);
29
10
 
30
- function asBytes(value) {
31
- return Utils.Bytes.asUint8Array(value);
11
+ function asArray(v) {
12
+ return v;
32
13
  }
33
14
 
34
- function toString$1(value) {
35
- let match = Utils.Bytes.asUint8Array(value);
36
- if (match !== undefined) {
37
- return Utils.Bytes.toHex(match);
38
- } else if (value !== undefined) {
39
- return toString(value);
40
- } else {
41
- return "undefined";
15
+ let encodeValueKey = (v => {
16
+ if (v === null) return "z"
17
+ switch (typeof v) {
18
+ case "string": return "s" + v.length + ":" + v
19
+ case "number": { const s = "" + v; return "n" + s.length + ":" + s }
20
+ case "bigint": { const s = "" + v; return "g" + s.length + ":" + s }
21
+ case "boolean": return v ? "t" : "f"
22
+ case "undefined": return "u"
23
+ default: { const s = JSON.stringify(v); return "o" + s.length + ":" + s }
42
24
  }
43
- }
25
+ });
44
26
 
45
- function compareWith(a, b, bigDecimal, bytes, fallback) {
46
- let match = Utils.Bytes.asUint8Array(a);
47
- let match$1 = Utils.Bytes.asUint8Array(b);
48
- if (match !== undefined && match$1 !== undefined) {
49
- return bytes(Utils.Bytes.compare(match, match$1));
50
- }
51
- if (typeof a === "object" && !Array.isArray(a) && typeof b === "object" && !Array.isArray(b)) {
52
- return bigDecimal(a, b);
53
- } else {
54
- return fallback(a, b);
55
- }
56
- }
27
+ let isKeyable = (function isKeyable(v) {
28
+ if (typeof v !== "object" || v === null) return true
29
+ if (Array.isArray(v)) return v.every(isKeyable)
30
+ try { JSON.stringify(v); return true } catch { return false }
31
+ });
57
32
 
58
- function eq(a, b) {
59
- return compareWith(a, b, (prim0, prim1) => prim0.isEqualTo(prim1), order => order === 0, Primitive_object.equal);
60
- }
61
-
62
- function gt(a, b) {
63
- return compareWith(a, b, (prim0, prim1) => prim0.isGreaterThan(prim1), order => order > 0, Primitive_object.greaterthan);
64
- }
65
-
66
- function lt(a, b) {
67
- return compareWith(a, b, (prim0, prim1) => prim0.isLessThan(prim1), order => order < 0, Primitive_object.lessthan);
68
- }
69
-
70
- let FieldValue = {
71
- asBytes: asBytes,
72
- toString: toString$1,
73
- compareWith: compareWith,
74
- eq: eq,
75
- gt: gt,
76
- lt: lt
77
- };
78
-
79
- function toString$2(filter) {
80
- switch (filter.operator) {
81
- case "=" :
82
- return filter.fieldName + `:Eq:` + toString$1(filter.fieldValue);
83
- case ">" :
84
- return filter.fieldName + `:Gt:` + toString$1(filter.fieldValue);
85
- case "<" :
86
- return filter.fieldName + `:Lt:` + toString$1(filter.fieldValue);
87
- case "in" :
88
- return filter.fieldName + `:In:[` + filter.fieldValue.map(toString$1).join(",") + `]`;
89
- case "and" :
90
- return `And(` + filter.filters.map(toString$2).join(",") + `)`;
91
- }
33
+ function entries(filter) {
34
+ return filter;
92
35
  }
93
36
 
94
37
  function valuesCount(filter) {
95
- switch (filter.operator) {
96
- case "in" :
97
- return filter.fieldValue.length;
98
- case "and" :
99
- return Stdlib_Array.reduce(filter.filters, 0, (acc, filter) => acc + valuesCount(filter) | 0);
100
- default:
101
- return 1;
102
- }
38
+ let count = {
39
+ contents: 0
40
+ };
41
+ Utils.Dict.forEachWithKey(filter, (operators, param) => Utils.Dict.forEachWithKey(operators, (fieldValue, operator) => {
42
+ count.contents = count.contents + (
43
+ operator === "_in" ? fieldValue.length : 1
44
+ ) | 0;
45
+ }));
46
+ return count.contents;
103
47
  }
104
48
 
105
49
  let codegenHelpMessage = `Rerun 'pnpm dev' to update generated code after schema.graphql changes.`;
@@ -119,12 +63,69 @@ function throwUnsupportedGetWhereValue(valueName, entityName, filterDisplay, hin
119
63
  return Stdlib_JsError.throwWithMessage(`Invalid ` + valueName + ` value passed to context.` + entityName + `.getWhere(` + filterDisplay + `). Filtering by null or undefined values is not supported in getWhere.` + hint);
120
64
  }
121
65
 
122
- function parseGetWhereOrThrow(filter, entityName, table) {
66
+ let isDate = (v => v instanceof Date);
67
+
68
+ function expectedValueType(field) {
69
+ let match = field.fieldType;
70
+ if (typeof match === "object") {
71
+ return;
72
+ }
73
+ switch (match) {
74
+ case "Bytea" :
75
+ return field.isArray ? "an array of Uint8Array" : "a Uint8Array";
76
+ case "Date" :
77
+ return field.isArray ? "an array of Date" : "a Date";
78
+ default:
79
+ return;
80
+ }
81
+ }
82
+
83
+ function keyUsesSerializer(field) {
84
+ let match = field.fieldType;
85
+ if (typeof match === "object") {
86
+ return match.type !== "BigDecimal";
87
+ }
88
+ switch (match) {
89
+ case "Bytea" :
90
+ case "Date" :
91
+ return false;
92
+ default:
93
+ return true;
94
+ }
95
+ }
96
+
97
+ function matchesFieldType(value, field) {
98
+ let matchesScalar = value => {
99
+ let match = field.fieldType;
100
+ if (typeof match === "object") {
101
+ return true;
102
+ }
103
+ switch (match) {
104
+ case "Bytea" :
105
+ return Stdlib_Option.isSome(Utils.Bytes.asUint8Array(value));
106
+ case "Date" :
107
+ return isDate(value);
108
+ default:
109
+ return true;
110
+ }
111
+ };
112
+ if (field.isArray) {
113
+ if (Array.isArray(value)) {
114
+ return value.every(matchesScalar);
115
+ } else {
116
+ return false;
117
+ }
118
+ } else {
119
+ return matchesScalar(value);
120
+ }
121
+ }
122
+
123
+ function parseOrThrow(filter, entityName, table) {
123
124
  let filterKeys = Object.keys(filter);
124
125
  if (filterKeys.length === 0) {
125
126
  Stdlib_JsError.throwWithMessage(`Empty filter passed to context.` + entityName + `.getWhere(). Please provide a filter like { fieldName: { _eq: value } }.`);
126
127
  }
127
- let filterGroups = filterKeys.flatMap(apiFieldName => {
128
+ filterKeys.forEach(apiFieldName => {
128
129
  let operatorObj = filter[apiFieldName];
129
130
  let valueName = getUndefinedOrNullName(operatorObj);
130
131
  if (valueName !== undefined) {
@@ -137,7 +138,6 @@ function parseGetWhereOrThrow(filter, entityName, table) {
137
138
  if (operatorKeys.length === 0) {
138
139
  Stdlib_JsError.throwWithMessage(`Empty operator passed to context.` + entityName + `.getWhere({ ` + apiFieldName + `: {} }). Please provide an operator like { _eq: value }, { _gt: value }, { _lt: value }, { _gte: value }, { _lte: value }, or { _in: [values] }.`);
139
140
  }
140
- let throwInvalidOperator = operatorKey => Stdlib_JsError.throwWithMessage(`Invalid operator "` + operatorKey + `" in context.` + entityName + `.getWhere({ ` + apiFieldName + `: { ` + operatorKey + `: ... } }). Valid operators are _eq, _gt, _lt, _gte, _lte, _in.`);
141
141
  operatorKeys.forEach(operatorKey => {
142
142
  switch (operatorKey) {
143
143
  case "_eq" :
@@ -148,167 +148,108 @@ function parseGetWhereOrThrow(filter, entityName, table) {
148
148
  case "_lte" :
149
149
  return;
150
150
  default:
151
- return throwInvalidOperator(operatorKey);
151
+ return Stdlib_JsError.throwWithMessage(`Invalid operator "` + operatorKey + `" in context.` + entityName + `.getWhere({ ` + apiFieldName + `: { ` + operatorKey + `: ... } }). Valid operators are _eq, _gt, _lt, _gte, _lte, _in.`);
152
152
  }
153
153
  });
154
154
  let match = Table.getFieldByApiName(table, apiFieldName);
155
- if (match !== undefined) {
156
- if (match.TAG !== "Field") {
157
- Stdlib_JsError.throwWithMessage(`The field "` + apiFieldName + `" on entity "` + entityName + `" is a derived field and cannot be used in getWhere(). Use the source entity's indexed field instead.`);
158
- }
159
- } else {
160
- Stdlib_JsError.throwWithMessage(`Invalid field "` + apiFieldName + `" in context.` + entityName + `.getWhere(). The field doesn't exist. ` + codegenHelpMessage);
161
- }
162
- return operatorKeys.map(operatorKey => {
155
+ let field = match !== undefined ? (
156
+ match.TAG === "Field" ? match._0 : Stdlib_JsError.throwWithMessage(`The field "` + apiFieldName + `" on entity "` + entityName + `" is a derived field and cannot be used in getWhere(). Use the source entity's indexed field instead.`)
157
+ ) : Stdlib_JsError.throwWithMessage(`Invalid field "` + apiFieldName + `" in context.` + entityName + `.getWhere(). The field doesn't exist. ` + codegenHelpMessage);
158
+ let expectedType = expectedValueType(field);
159
+ let checkKeyable = keyUsesSerializer(field);
160
+ operatorKeys.forEach(operatorKey => {
163
161
  let fieldValue = operatorObj[operatorKey];
164
162
  let valueName = getUndefinedOrNullName(fieldValue);
165
163
  if (valueName !== undefined) {
166
164
  throwUnsupportedGetWhereValue(valueName, entityName, `{ ` + apiFieldName + `: { ` + operatorKey + `: ` + valueName + ` } }`, undefined);
167
165
  }
168
- switch (operatorKey) {
169
- case "_eq" :
170
- return [{
171
- operator: "=",
172
- fieldName: apiFieldName,
173
- fieldValue: fieldValue
174
- }];
175
- case "_gt" :
176
- return [{
177
- operator: ">",
178
- fieldName: apiFieldName,
179
- fieldValue: fieldValue
180
- }];
181
- case "_gte" :
182
- return [
183
- {
184
- operator: "=",
185
- fieldName: apiFieldName,
186
- fieldValue: fieldValue
187
- },
188
- {
189
- operator: ">",
190
- fieldName: apiFieldName,
191
- fieldValue: fieldValue
192
- }
193
- ];
194
- case "_in" :
195
- if (!Array.isArray(fieldValue)) {
196
- Stdlib_JsError.throwWithMessage(`Invalid value passed to context.` + entityName + `.getWhere({ ` + apiFieldName + `: { _in: ... } }). The _in operator expects an array of values.`);
166
+ let throwUnexpectedType = (typeName, hint) => Stdlib_JsError.throwWithMessage(`Invalid value passed to context.` + entityName + `.getWhere({ ` + apiFieldName + `: { ` + operatorKey + `: ... } }). The field "` + apiFieldName + `" expects ` + typeName + `.` + hint);
167
+ let throwUnkeyable = hint => Stdlib_JsError.throwWithMessage(`Invalid value passed to context.` + entityName + `.getWhere({ ` + apiFieldName + `: { ` + operatorKey + `: ... } }). The value can't be serialized, so it can't be used as a filter. An object holding a bigint, or a circular reference, is not supported.` + hint);
168
+ if (operatorKey === "_in") {
169
+ if (!Array.isArray(fieldValue)) {
170
+ Stdlib_JsError.throwWithMessage(`Invalid value passed to context.` + entityName + `.getWhere({ ` + apiFieldName + `: { _in: ... } }). The _in operator expects an array of values.`);
171
+ }
172
+ fieldValue.forEach((fieldValue, index) => {
173
+ let valueName = getUndefinedOrNullName(fieldValue);
174
+ if (valueName !== undefined) {
175
+ throwUnsupportedGetWhereValue(valueName, entityName, `{ ` + apiFieldName + `: { _in: [...] } }`, ` The ` + valueName + ` value is at index ` + index.toString() + ` of the _in array.`);
197
176
  }
198
- return fieldValue.map((fieldValue, index) => {
199
- let valueName = getUndefinedOrNullName(fieldValue);
200
- if (valueName !== undefined) {
201
- throwUnsupportedGetWhereValue(valueName, entityName, `{ ` + apiFieldName + `: { _in: [...] } }`, ` The ` + valueName + ` value is at index ` + index.toString() + ` of the _in array.`);
202
- }
203
- return {
204
- operator: "=",
205
- fieldName: apiFieldName,
206
- fieldValue: fieldValue
207
- };
208
- });
209
- case "_lt" :
210
- return [{
211
- operator: "<",
212
- fieldName: apiFieldName,
213
- fieldValue: fieldValue
214
- }];
215
- case "_lte" :
216
- return [
217
- {
218
- operator: "=",
219
- fieldName: apiFieldName,
220
- fieldValue: fieldValue
221
- },
222
- {
223
- operator: "<",
224
- fieldName: apiFieldName,
225
- fieldValue: fieldValue
226
- }
227
- ];
228
- default:
229
- return throwInvalidOperator(operatorKey);
177
+ if (expectedType !== undefined && !matchesFieldType(fieldValue, field)) {
178
+ throwUnexpectedType(expectedType, ` The value is at index ` + index.toString() + ` of the _in array.`);
179
+ }
180
+ if (checkKeyable && !isKeyable(fieldValue)) {
181
+ return throwUnkeyable(` The value is at index ` + index.toString() + ` of the _in array.`);
182
+ }
183
+ });
184
+ return;
185
+ }
186
+ if (expectedType !== undefined && !matchesFieldType(fieldValue, field)) {
187
+ throwUnexpectedType(expectedType, "");
188
+ }
189
+ if (checkKeyable && !isKeyable(fieldValue)) {
190
+ return throwUnkeyable("");
230
191
  }
231
192
  });
232
193
  });
233
- return Stdlib_Array.reduce(filterGroups, [[]], (combinations, group) => combinations.flatMap(combination => group.map(filter => combination.concat([filter])))).map(filters => {
234
- if (filters.length !== 1) {
235
- return {
236
- operator: "and",
237
- filters: filters
238
- };
239
- } else {
240
- return filters[0];
241
- }
242
- });
194
+ return filter;
243
195
  }
244
196
 
245
- function printOperationFilter(filter, paramsCount) {
246
- switch (filter.operator) {
247
- case "=" :
248
- paramsCount.contents = paramsCount.contents + 1 | 0;
249
- return filter.fieldName + `: $` + paramsCount.contents.toString();
250
- case ">" :
251
- paramsCount.contents = paramsCount.contents + 1 | 0;
252
- return filter.fieldName + `: {_gt: $` + paramsCount.contents.toString() + `}`;
253
- case "<" :
254
- paramsCount.contents = paramsCount.contents + 1 | 0;
255
- return filter.fieldName + `: {_lt: $` + paramsCount.contents.toString() + `}`;
256
- case "in" :
257
- paramsCount.contents = paramsCount.contents + 1 | 0;
258
- return filter.fieldName + `: {_in: $` + paramsCount.contents.toString() + `}`;
259
- case "and" :
260
- let filters = filter.filters;
261
- let acc = "";
262
- for (let idx = 0, idx_finish = filters.length; idx < idx_finish; ++idx) {
263
- let part = printOperationFilter(filters[idx], paramsCount);
264
- acc = acc === "" ? part : acc + `, ` + part;
197
+ function byIds(ids) {
198
+ return Object.fromEntries([[
199
+ Table.idFieldName,
200
+ {
201
+ _in: ids
265
202
  }
266
- return acc;
267
- }
203
+ ]]);
268
204
  }
269
205
 
270
- function toOperationKey(filter, entityName) {
271
- switch (filter.operator) {
272
- case "=" :
273
- return entityName + `.getWhere({` + filter.fieldName + `: $1})`;
274
- case ">" :
275
- return entityName + `.getWhere({` + filter.fieldName + `: {_gt: $1}})`;
276
- case "<" :
277
- return entityName + `.getWhere({` + filter.fieldName + `: {_lt: $1}})`;
278
- case "in" :
279
- return entityName + `.getWhere({` + filter.fieldName + `: {_in: $1}})`;
280
- case "and" :
281
- return entityName + `.getWhere({` + printOperationFilter(filter, {
282
- contents: 0
283
- }) + `})`;
206
+ function scoped(filter, table, scope) {
207
+ let match = Table.getChainIdField(table);
208
+ if (scope === "crossChain") {
209
+ return filter;
210
+ }
211
+ if (match === undefined) {
212
+ return filter;
284
213
  }
214
+ let scoped$1 = Utils.Dict.shallowCopy(filter);
215
+ scoped$1[match.fieldName] = {
216
+ _eq: scope
217
+ };
218
+ return scoped$1;
285
219
  }
286
220
 
287
221
  function getParams(filter) {
288
- switch (filter.operator) {
289
- case "in" :
290
- return filter.fieldValue;
291
- case "and" :
292
- let acc = [];
293
- let collect = filter => {
294
- switch (filter.operator) {
295
- case "and" :
296
- filter.filters.forEach(collect);
297
- return;
298
- default:
299
- acc.push(filter.fieldValue);
300
- return;
301
- }
302
- };
303
- collect(filter);
304
- return acc;
305
- default:
306
- return [filter.fieldValue];
222
+ let params = [];
223
+ Utils.Dict.forEachWithKey(filter, (operators, param) => Utils.Dict.forEachWithKey(operators, (fieldValue, param) => {
224
+ params.push(fieldValue);
225
+ }));
226
+ return params;
227
+ }
228
+
229
+ function asSingleOperator(filter) {
230
+ let match = Object.keys(filter);
231
+ if (match.length !== 1) {
232
+ return;
233
+ }
234
+ let fieldName = match[0];
235
+ let operators = filter[fieldName];
236
+ let match$1 = Object.keys(operators);
237
+ if (match$1.length !== 1) {
238
+ return;
307
239
  }
240
+ let operator = match$1[0];
241
+ return [
242
+ fieldName,
243
+ operator,
244
+ operators[operator]
245
+ ];
308
246
  }
309
247
 
310
248
  function throwUnmergeable(filter) {
311
- return Stdlib_JsError.throwWithMessage(`Unexpected filter ` + toString$2(filter) + ` in a merged batch. Filters batched into a single query must use the same operator and field.`);
249
+ let match = asSingleOperator(filter);
250
+ return Stdlib_JsError.throwWithMessage(`Unexpected ` + (
251
+ match !== undefined ? match[1] : "composite"
252
+ ) + ` filter in a merged batch. Filters batched into a single query must use the same operator and field.`);
312
253
  }
313
254
 
314
255
  function merge(filters) {
@@ -319,110 +260,417 @@ function merge(filters) {
319
260
  if (len === 0) {
320
261
  return filters;
321
262
  }
322
- let match = filters[0];
323
- switch (match.operator) {
324
- case "=" :
325
- return [{
326
- operator: "in",
327
- fieldName: match.fieldName,
328
- fieldValue: filters.map(filter => {
329
- if (filter.operator === "=") {
330
- return filter.fieldValue;
331
- } else {
332
- return throwUnmergeable(filter);
333
- }
334
- })
335
- }];
336
- case "in" :
337
- return [{
338
- operator: "in",
339
- fieldName: match.fieldName,
340
- fieldValue: filters.map(filter => {
341
- if (filter.operator === "in") {
342
- return filter.fieldValue;
343
- } else {
344
- return throwUnmergeable(filter);
345
- }
346
- }).flat()
347
- }];
263
+ let match = asSingleOperator(filters[0]);
264
+ if (match === undefined) {
265
+ return filters;
266
+ }
267
+ let operator = match[1];
268
+ let fieldName = match[0];
269
+ switch (operator) {
270
+ case "_eq" :
271
+ case "_in" :
272
+ break;
348
273
  default:
349
274
  return filters;
350
275
  }
276
+ let values = [];
277
+ filters.forEach(filter => {
278
+ let match = asSingleOperator(filter);
279
+ if (match === undefined) {
280
+ return throwUnmergeable(filter);
281
+ }
282
+ if (match[0] !== fieldName || match[1] !== operator) {
283
+ return throwUnmergeable(filter);
284
+ }
285
+ let fieldValue = match[2];
286
+ if (operator === "_in") {
287
+ fieldValue.forEach(value => {
288
+ values.push(value);
289
+ });
290
+ } else {
291
+ values.push(fieldValue);
292
+ }
293
+ });
294
+ return [Object.fromEntries([[
295
+ fieldName,
296
+ {
297
+ _in: values
298
+ }
299
+ ]])];
300
+ }
301
+
302
+ function nativeEq(a, b) {
303
+ return a === b;
304
+ }
305
+
306
+ let nativeGt = ((a, b) => a != null && a > b);
307
+
308
+ let nativeLt = ((a, b) => a != null && a < b);
309
+
310
+ function identityKey(v) {
311
+ return v;
351
312
  }
352
313
 
353
- function matches(filter, entity) {
354
- switch (filter.operator) {
355
- case "=" :
356
- return eq(entity[filter.fieldName], filter.fieldValue);
357
- case ">" :
358
- return gt(entity[filter.fieldName], filter.fieldValue);
359
- case "<" :
360
- return lt(entity[filter.fieldName], filter.fieldValue);
361
- case "in" :
362
- let entityFieldValue = entity[filter.fieldName];
363
- return filter.fieldValue.some(fieldValue => eq(entityFieldValue, fieldValue));
364
- case "and" :
365
- let filters = filter.filters;
366
- if (filters.length !== 0) {
367
- return filters.every(filter => matches(filter, entity));
314
+ let native = {
315
+ eq: nativeEq,
316
+ gt: nativeGt,
317
+ lt: nativeLt,
318
+ key: identityKey
319
+ };
320
+
321
+ function nullSafe(compare) {
322
+ return {
323
+ eq: (a, b) => {
324
+ if (nullish(a)) {
325
+ return false;
368
326
  } else {
369
- return Stdlib_JsError.throwWithMessage(`The "and" filter must contain at least one nested filter.`);
327
+ return compare.eq(a, b);
370
328
  }
329
+ },
330
+ gt: (a, b) => {
331
+ if (nullish(a)) {
332
+ return false;
333
+ } else {
334
+ return compare.gt(a, b);
335
+ }
336
+ },
337
+ lt: (a, b) => {
338
+ if (nullish(a)) {
339
+ return false;
340
+ } else {
341
+ return compare.lt(a, b);
342
+ }
343
+ },
344
+ key: compare.key
345
+ };
346
+ }
347
+
348
+ function asBigDecimal(v) {
349
+ return v;
350
+ }
351
+
352
+ let bigDecimal = nullSafe({
353
+ eq: (a, b) => a.isEqualTo(b),
354
+ gt: (a, b) => a.isGreaterThan(b),
355
+ lt: (a, b) => a.isLessThan(b),
356
+ key: v => v.toString()
357
+ });
358
+
359
+ function getTime(v) {
360
+ return v.getTime();
361
+ }
362
+
363
+ let date = nullSafe({
364
+ eq: (a, b) => a.getTime() === b.getTime(),
365
+ gt: (a, b) => a.getTime() > b.getTime(),
366
+ lt: (a, b) => a.getTime() < b.getTime(),
367
+ key: v => v.getTime()
368
+ });
369
+
370
+ let json = nullSafe({
371
+ eq: Primitive_object.equal,
372
+ gt: Primitive_object.greaterthan,
373
+ lt: Primitive_object.lessthan,
374
+ key: v => JSON.stringify(v)
375
+ });
376
+
377
+ function asBytes(v) {
378
+ return v;
379
+ }
380
+
381
+ let bytes = nullSafe({
382
+ eq: (a, b) => Utils.Bytes.compare(a, b) === 0,
383
+ gt: (a, b) => Utils.Bytes.compare(a, b) > 0,
384
+ lt: (a, b) => Utils.Bytes.compare(a, b) < 0,
385
+ key: v => Utils.Bytes.toHex(v)
386
+ });
387
+
388
+ function enum_(config) {
389
+ let ranks = {};
390
+ config.variants.forEach((variant, rank) => {
391
+ ranks[variant] = rank;
392
+ });
393
+ return {
394
+ eq: nativeEq,
395
+ gt: (a, b) => {
396
+ if (nullish(a)) {
397
+ return false;
398
+ } else {
399
+ return ranks[a] > ranks[b];
400
+ }
401
+ },
402
+ lt: (a, b) => {
403
+ if (nullish(a)) {
404
+ return false;
405
+ } else {
406
+ return ranks[a] < ranks[b];
407
+ }
408
+ },
409
+ key: identityKey
410
+ };
411
+ }
412
+
413
+ function scalarCompare(fieldType) {
414
+ if (typeof fieldType !== "object") {
415
+ switch (fieldType) {
416
+ case "Bytea" :
417
+ return bytes;
418
+ case "Json" :
419
+ return json;
420
+ case "Date" :
421
+ return date;
422
+ default:
423
+ return native;
424
+ }
425
+ } else {
426
+ switch (fieldType.type) {
427
+ case "BigDecimal" :
428
+ return bigDecimal;
429
+ case "Enum" :
430
+ return enum_(fieldType.config);
431
+ default:
432
+ return native;
433
+ }
371
434
  }
372
435
  }
373
436
 
374
- function mapValues(filter, mapValue) {
375
- switch (filter.operator) {
376
- case "=" :
377
- let fieldName = filter.fieldName;
378
- return {
379
- operator: "=",
380
- fieldName: fieldName,
381
- fieldValue: mapValue(fieldName, filter.fieldValue, false)
382
- };
383
- case ">" :
384
- let fieldName$1 = filter.fieldName;
385
- return {
386
- operator: ">",
387
- fieldName: fieldName$1,
388
- fieldValue: mapValue(fieldName$1, filter.fieldValue, false)
389
- };
390
- case "<" :
391
- let fieldName$2 = filter.fieldName;
392
- return {
393
- operator: "<",
394
- fieldName: fieldName$2,
395
- fieldValue: mapValue(fieldName$2, filter.fieldValue, false)
396
- };
397
- case "in" :
398
- let fieldName$3 = filter.fieldName;
399
- return {
400
- operator: "in",
401
- fieldName: fieldName$3,
402
- fieldValue: mapValue(fieldName$3, filter.fieldValue, true)
403
- };
404
- case "and" :
405
- return {
406
- operator: "and",
407
- filters: filter.filters.map(filter => mapValues(filter, mapValue))
437
+ function arrayCompare(element) {
438
+ let eq = (a, b) => {
439
+ let len = a.length;
440
+ if (len !== b.length) {
441
+ return false;
442
+ }
443
+ let _i = 0;
444
+ while (true) {
445
+ let i = _i;
446
+ if (i >= len) {
447
+ return true;
448
+ }
449
+ if (!element.eq(a[i], b[i])) {
450
+ return false;
451
+ }
452
+ _i = i + 1 | 0;
453
+ continue;
454
+ };
455
+ };
456
+ let order = gt => ((a, b) => {
457
+ let la = a.length;
458
+ let lb = b.length;
459
+ let len = la < lb ? la : lb;
460
+ let _i = 0;
461
+ while (true) {
462
+ let i = _i;
463
+ if (i >= len) {
464
+ if (gt) {
465
+ return la > lb;
466
+ } else {
467
+ return la < lb;
468
+ }
469
+ }
470
+ let x = a[i];
471
+ let y = b[i];
472
+ if (!element.eq(x, y)) {
473
+ if (gt) {
474
+ return element.gt(x, y);
475
+ } else {
476
+ return element.lt(x, y);
477
+ }
478
+ }
479
+ _i = i + 1 | 0;
480
+ continue;
481
+ };
482
+ });
483
+ return nullSafe({
484
+ eq: eq,
485
+ gt: order(true),
486
+ lt: order(false),
487
+ key: v => {
488
+ let key = {
489
+ contents: ""
408
490
  };
491
+ v.forEach(item => {
492
+ key.contents = key.contents + encodeValueKey(element.key(item));
493
+ });
494
+ return key.contents;
495
+ }
496
+ });
497
+ }
498
+
499
+ let comparesByField = Utils.$$WeakMap.memoize(table => {
500
+ let compares = {};
501
+ table.fields.forEach(field => {
502
+ if (field.TAG !== "Field") {
503
+ return;
504
+ }
505
+ let field$1 = field._0;
506
+ let element = scalarCompare(field$1.fieldType);
507
+ compares[Table.getApiFieldName(field$1)] = field$1.isArray ? arrayCompare(element) : element;
508
+ });
509
+ return compares;
510
+ });
511
+
512
+ function fieldCompare(table, fieldName) {
513
+ let compare = comparesByField(table)[fieldName];
514
+ if (compare !== undefined) {
515
+ return compare;
516
+ } else {
517
+ return Stdlib_JsError.throwWithMessage(`Internal error: no comparator for the field "` + fieldName + `" on the table "` + table.tableName + `". A filter is parsed against its table before it reaches the in-memory matcher.`);
518
+ }
519
+ }
520
+
521
+ function makeValueKey(table, fieldName) {
522
+ return fieldCompare(table, fieldName).key;
523
+ }
524
+
525
+ function toString(filter, table) {
526
+ let key = {
527
+ contents: ""
528
+ };
529
+ Utils.Dict.forEachWithKey(filter, (operators, fieldName) => {
530
+ let keyOf = fieldCompare(table, fieldName).key;
531
+ Utils.Dict.forEachWithKey(operators, (fieldValue, operator) => {
532
+ key.contents = key.contents + fieldName + operator;
533
+ if (operator === "_in") {
534
+ fieldValue.forEach(value => {
535
+ key.contents = key.contents + encodeValueKey(keyOf(value));
536
+ });
537
+ } else {
538
+ key.contents = key.contents + encodeValueKey(keyOf(fieldValue));
539
+ }
540
+ key.contents = key.contents + ";";
541
+ });
542
+ });
543
+ return key.contents;
544
+ }
545
+
546
+ function toOperationKey(filter, entityName) {
547
+ let params = {
548
+ contents: 0
549
+ };
550
+ let printed = {
551
+ contents: ""
552
+ };
553
+ Utils.Dict.forEachWithKey(filter, (operators, fieldName) => {
554
+ let ops = {
555
+ contents: ""
556
+ };
557
+ let loneEq = {
558
+ contents: false
559
+ };
560
+ Utils.Dict.forEachWithKey(operators, (param, operator) => {
561
+ params.contents = params.contents + 1 | 0;
562
+ let part = operator + `: $` + params.contents.toString();
563
+ loneEq.contents = ops.contents === "" && operator === "_eq";
564
+ ops.contents = ops.contents === "" ? part : ops.contents + ", " + part;
565
+ });
566
+ let part = loneEq.contents ? fieldName + `: $` + params.contents.toString() : fieldName + `: {` + ops.contents + `}`;
567
+ printed.contents = printed.contents === "" ? part : printed.contents + ", " + part;
568
+ });
569
+ return entityName + `.getWhere({` + printed.contents + `})`;
570
+ }
571
+
572
+ function makeMatcher(filter, table) {
573
+ let checks = [];
574
+ Utils.Dict.forEachWithKey(filter, (operators, fieldName) => {
575
+ let compare = fieldCompare(table, fieldName);
576
+ Utils.Dict.forEachWithKey(operators, (fieldValue, operator) => {
577
+ let check;
578
+ switch (operator) {
579
+ case "_eq" :
580
+ check = entity => compare.eq(entity[fieldName], fieldValue);
581
+ break;
582
+ case "_gt" :
583
+ check = entity => compare.gt(entity[fieldName], fieldValue);
584
+ break;
585
+ case "_gte" :
586
+ check = entity => {
587
+ let entityFieldValue = entity[fieldName];
588
+ if (compare.eq(entityFieldValue, fieldValue)) {
589
+ return true;
590
+ } else {
591
+ return compare.gt(entityFieldValue, fieldValue);
592
+ }
593
+ };
594
+ break;
595
+ case "_in" :
596
+ if (compare.eq === nativeEq) {
597
+ let set = new Set(fieldValue);
598
+ check = entity => set.has(entity[fieldName]);
599
+ } else {
600
+ check = entity => {
601
+ let entityFieldValue = entity[fieldName];
602
+ return fieldValue.some(candidate => compare.eq(entityFieldValue, candidate));
603
+ };
604
+ }
605
+ break;
606
+ case "_lt" :
607
+ check = entity => compare.lt(entity[fieldName], fieldValue);
608
+ break;
609
+ case "_lte" :
610
+ check = entity => {
611
+ let entityFieldValue = entity[fieldName];
612
+ if (compare.eq(entityFieldValue, fieldValue)) {
613
+ return true;
614
+ } else {
615
+ return compare.lt(entityFieldValue, fieldValue);
616
+ }
617
+ };
618
+ break;
619
+ default:
620
+ check = Stdlib_JsError.throwWithMessage(`Invalid operator "` + operator + `" in a getWhere filter. Valid operators are _eq, _gt, _lt, _gte, _lte, _in.`);
621
+ }
622
+ checks.push(check);
623
+ });
624
+ });
625
+ if (checks.length !== 1) {
626
+ return entity => checks.every(check => check(entity));
627
+ } else {
628
+ return checks[0];
409
629
  }
410
630
  }
411
631
 
412
632
  export {
413
- FieldValue,
414
- toString$2 as toString,
633
+ nullish,
634
+ asArray,
635
+ encodeValueKey,
636
+ isKeyable,
637
+ entries,
415
638
  valuesCount,
416
639
  codegenHelpMessage,
417
640
  getUndefinedOrNullName,
418
641
  throwUnsupportedGetWhereValue,
419
- parseGetWhereOrThrow,
420
- printOperationFilter,
421
- toOperationKey,
642
+ isDate,
643
+ expectedValueType,
644
+ keyUsesSerializer,
645
+ matchesFieldType,
646
+ parseOrThrow,
647
+ byIds,
648
+ scoped,
422
649
  getParams,
650
+ asSingleOperator,
423
651
  throwUnmergeable,
424
652
  merge,
425
- matches,
426
- mapValues,
653
+ nativeEq,
654
+ nativeGt,
655
+ nativeLt,
656
+ identityKey,
657
+ native,
658
+ nullSafe,
659
+ asBigDecimal,
660
+ bigDecimal,
661
+ getTime,
662
+ date,
663
+ json,
664
+ asBytes,
665
+ bytes,
666
+ enum_,
667
+ scalarCompare,
668
+ arrayCompare,
669
+ comparesByField,
670
+ fieldCompare,
671
+ makeValueKey,
672
+ toString,
673
+ toOperationKey,
674
+ makeMatcher,
427
675
  }
428
- /* Table Not a pure module */
676
+ /* bigDecimal Not a pure module */