@effect-app/infra 4.0.0-beta.316 → 4.0.0-beta.318

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 (53) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/ClusterCosmos.d.ts +5 -1
  3. package/dist/ClusterCosmos.d.ts.map +1 -1
  4. package/dist/ClusterCosmos.js +42 -13
  5. package/dist/ClusterServiceBus.d.ts.map +1 -1
  6. package/dist/ClusterServiceBus.js +3 -1
  7. package/dist/Store/Cosmos/query.d.ts +2 -1
  8. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  9. package/dist/Store/Cosmos/query.js +60 -2
  10. package/dist/Store/Cosmos.d.ts.map +1 -1
  11. package/dist/Store/Cosmos.js +17 -12
  12. package/dist/Store/Disk.d.ts.map +1 -1
  13. package/dist/Store/Disk.js +12 -7
  14. package/dist/Store/Memory.d.ts +2 -1
  15. package/dist/Store/Memory.d.ts.map +1 -1
  16. package/dist/Store/Memory.js +28 -15
  17. package/dist/Store/SQL/Pg.d.ts.map +1 -1
  18. package/dist/Store/SQL/Pg.js +15 -11
  19. package/dist/Store/SQL/query.d.ts +5 -1
  20. package/dist/Store/SQL/query.d.ts.map +1 -1
  21. package/dist/Store/SQL/query.js +131 -2
  22. package/dist/Store/SQL.d.ts +1 -1
  23. package/dist/Store/SQL.d.ts.map +1 -1
  24. package/dist/Store/SQL.js +24 -18
  25. package/dist/Store/codeFilter.d.ts.map +1 -1
  26. package/dist/Store/codeFilter.js +67 -20
  27. package/dist/Store/jsonDocument.d.ts +13 -0
  28. package/dist/Store/jsonDocument.d.ts.map +1 -0
  29. package/dist/Store/jsonDocument.js +31 -0
  30. package/dist/Store/utils.d.ts +16 -0
  31. package/dist/Store/utils.d.ts.map +1 -1
  32. package/dist/Store/utils.js +245 -6
  33. package/dist/logger.d.ts +1 -1
  34. package/examples/query.ts +4 -4
  35. package/package.json +6 -6
  36. package/src/ClusterCosmos.ts +56 -20
  37. package/src/ClusterServiceBus.ts +2 -0
  38. package/src/Store/Cosmos/query.ts +65 -9
  39. package/src/Store/Cosmos.ts +17 -11
  40. package/src/Store/Disk.ts +28 -7
  41. package/src/Store/Memory.ts +40 -17
  42. package/src/Store/SQL/Pg.ts +23 -10
  43. package/src/Store/SQL/query.ts +152 -7
  44. package/src/Store/SQL.ts +37 -17
  45. package/src/Store/codeFilter.ts +71 -23
  46. package/src/Store/jsonDocument.ts +43 -0
  47. package/src/Store/utils.ts +275 -5
  48. package/test/cosmos-query.test.ts +100 -5
  49. package/test/dist/json-lower.test.d.ts.map +1 -0
  50. package/test/dist/query.test.d.ts.map +1 -1
  51. package/test/json-lower.test.ts +115 -0
  52. package/test/query.test.ts +261 -12
  53. package/test/sql-store.test.ts +233 -39
@@ -1,7 +1,246 @@
1
1
  import crypto from "crypto";
2
2
  import * as Effect from "effect-app/Effect";
3
3
  import * as Option from "effect-app/Option";
4
+ import * as S from "effect-app/Schema";
5
+ import * as SchemaAST from "effect-app/SchemaAST";
4
6
  import { OptimisticConcurrencyException } from "../errors.js";
7
+ const dateJson = S.toCodecJson(S.Date);
8
+ const isPlainObject = (value) => {
9
+ if (value === null || typeof value !== "object" || Array.isArray(value))
10
+ return false;
11
+ if (value instanceof Date || value instanceof Map || value instanceof Set)
12
+ return false;
13
+ const proto = Object.getPrototypeOf(value);
14
+ return proto === Object.prototype || proto === null;
15
+ };
16
+ const unwrapAst = (ast) => SchemaAST.isSuspend(ast) ? unwrapAst(ast.thunk()) : ast;
17
+ const unionAst = (hits) => {
18
+ if (hits.length === 0)
19
+ return undefined;
20
+ if (hits.length === 1)
21
+ return hits[0];
22
+ return S.Union(hits.map((hit) => S.make(hit))).ast;
23
+ };
24
+ const encodedObjects = (ast) => {
25
+ const current = unwrapAst(ast);
26
+ if (SchemaAST.isObjects(current))
27
+ return current;
28
+ if (SchemaAST.isDeclaration(current)) {
29
+ const encoded = unwrapAst(SchemaAST.toEncoded(current));
30
+ if (SchemaAST.isObjects(encoded))
31
+ return encoded;
32
+ }
33
+ return undefined;
34
+ };
35
+ const astAtPath = (ast, path) => {
36
+ if (ast === undefined)
37
+ return undefined;
38
+ if (path.length === 0)
39
+ return unwrapAst(ast);
40
+ const current = unwrapAst(ast);
41
+ const [head, ...tail] = path;
42
+ if (head === undefined)
43
+ return current;
44
+ if (SchemaAST.isUnion(current)) {
45
+ return unionAst(current.types.flatMap((member) => {
46
+ const hit = astAtPath(member, path);
47
+ return hit === undefined ? [] : [hit];
48
+ }));
49
+ }
50
+ if (head === "-1" || /^\d+$/.test(head)) {
51
+ if (SchemaAST.isArrays(current)) {
52
+ const element = current.rest[0] ?? current.elements[Number(head)] ?? current.elements[0];
53
+ return astAtPath(element, tail);
54
+ }
55
+ if (SchemaAST.isDeclaration(current) && current.typeParameters.length === 1) {
56
+ return astAtPath(current.typeParameters[0], tail);
57
+ }
58
+ return undefined;
59
+ }
60
+ const objects = encodedObjects(current);
61
+ if (objects !== undefined) {
62
+ const property = objects.propertySignatures.find((p) => p.name === head);
63
+ return property === undefined ? undefined : astAtPath(property.type, tail);
64
+ }
65
+ return undefined;
66
+ };
67
+ const elementAst = (ast) => {
68
+ if (ast === undefined)
69
+ return undefined;
70
+ const current = unwrapAst(ast);
71
+ if (SchemaAST.isUnion(current)) {
72
+ return unionAst(current.types.flatMap((member) => {
73
+ const hit = elementAst(member);
74
+ return hit === undefined ? [] : [hit];
75
+ }));
76
+ }
77
+ if (SchemaAST.isArrays(current))
78
+ return unwrapAst(current.rest[0] ?? current.elements[0] ?? current);
79
+ if (SchemaAST.isDeclaration(current) && current.typeParameters.length === 1) {
80
+ return unwrapAst(current.typeParameters[0]);
81
+ }
82
+ return current;
83
+ };
84
+ const mapKeyAst = (ast) => {
85
+ if (ast === undefined)
86
+ return undefined;
87
+ const current = unwrapAst(ast);
88
+ if (SchemaAST.isUnion(current)) {
89
+ return unionAst(current.types.flatMap((member) => {
90
+ const hit = mapKeyAst(member);
91
+ return hit === undefined ? [] : [hit];
92
+ }));
93
+ }
94
+ if (SchemaAST.isDeclaration(current) && current.typeParameters.length >= 2) {
95
+ return unwrapAst(current.typeParameters[0]);
96
+ }
97
+ return current;
98
+ };
99
+ const mapValueAst = (ast) => {
100
+ if (ast === undefined)
101
+ return undefined;
102
+ const current = unwrapAst(ast);
103
+ if (SchemaAST.isUnion(current)) {
104
+ return unionAst(current.types.flatMap((member) => {
105
+ const hit = mapValueAst(member);
106
+ return hit === undefined ? [] : [hit];
107
+ }));
108
+ }
109
+ if (SchemaAST.isDeclaration(current) && current.typeParameters.length >= 2) {
110
+ return unwrapAst(current.typeParameters[1]);
111
+ }
112
+ return current;
113
+ };
114
+ const asArray = (value) => Array.isArray(value) ? value : value instanceof Set ? [...value] : [value];
115
+ const encodeJson = (ast, value) => {
116
+ if (ast === undefined)
117
+ return toJsonQueryValue(value);
118
+ const current = unwrapAst(ast);
119
+ if (isPlainObject(value)) {
120
+ const out = {};
121
+ for (const [key, child] of Object.entries(value)) {
122
+ out[key] = encodeJson(astAtPath(current, [key]), child);
123
+ }
124
+ return out;
125
+ }
126
+ if (Array.isArray(value)) {
127
+ const element = SchemaAST.isArrays(current) || SchemaAST.isUnion(current)
128
+ ? elementAst(current)
129
+ : current;
130
+ return value.map((item) => encodeJson(element, item));
131
+ }
132
+ if (value instanceof Set) {
133
+ return [...value].map((item) => encodeJson(elementAst(current), item));
134
+ }
135
+ if (value instanceof Map) {
136
+ return [...value.entries()].map(([k, v]) => [
137
+ encodeJson(mapKeyAst(current), k),
138
+ encodeJson(mapValueAst(current), v)
139
+ ]);
140
+ }
141
+ return Effect.runSync(S.encodeUnknownEffect(S.toCodecJson(S.make(current)))(value));
142
+ };
143
+ const encodeFilterValue = (fieldAst, op, value) => {
144
+ if (fieldAst === undefined)
145
+ return toJsonQueryValue(value);
146
+ if (op === "in" || op === "notIn") {
147
+ return asArray(value).map((item) => encodeJson(fieldAst, item));
148
+ }
149
+ if (op === "includes"
150
+ || op === "notIncludes"
151
+ || op === "includes-any"
152
+ || op === "notIncludes-any"
153
+ || op === "includes-all"
154
+ || op === "notIncludes-all") {
155
+ const element = elementAst(fieldAst);
156
+ return op === "includes" || op === "notIncludes"
157
+ ? encodeJson(element, value)
158
+ : asArray(value).map((item) => encodeJson(element, item));
159
+ }
160
+ if (op === "hasKeyValue"
161
+ || op === "notHasKeyValue"
162
+ || op === "hasKeyValue-any"
163
+ || op === "notHasKeyValue-any"
164
+ || op === "hasKeyValue-all"
165
+ || op === "notHasKeyValue-all") {
166
+ const keyAst = mapKeyAst(fieldAst);
167
+ const valueAst = mapValueAst(fieldAst);
168
+ const pair = (item) => Array.isArray(item) && item.length >= 2
169
+ ? [encodeJson(keyAst, item[0]), encodeJson(valueAst, item[1])]
170
+ : toJsonQueryValue(item);
171
+ return op === "hasKeyValue" || op === "notHasKeyValue" ? pair(value) : asArray(value).map(pair);
172
+ }
173
+ if (op === "hasKey"
174
+ || op === "notHasKey"
175
+ || op === "hasKey-any"
176
+ || op === "notHasKey-any"
177
+ || op === "hasKey-all"
178
+ || op === "notHasKey-all") {
179
+ const keyAst = mapKeyAst(fieldAst);
180
+ return op === "hasKey" || op === "notHasKey"
181
+ ? encodeJson(keyAst, value)
182
+ : asArray(value).map((item) => encodeJson(keyAst, item));
183
+ }
184
+ if (op === "hasValue"
185
+ || op === "notHasValue"
186
+ || op === "hasValue-any"
187
+ || op === "notHasValue-any"
188
+ || op === "hasValue-all"
189
+ || op === "notHasValue-all") {
190
+ const valueAst = mapValueAst(fieldAst);
191
+ return op === "hasValue" || op === "notHasValue"
192
+ ? encodeJson(valueAst, value)
193
+ : asArray(value).map((item) => encodeJson(valueAst, item));
194
+ }
195
+ return encodeJson(fieldAst, value);
196
+ };
197
+ /**
198
+ * Lower Date / Map / Set to JSON when no field schema is available.
199
+ * Prefer {@link encodeWithSchema} / {@link jsonifyFilter} with the store schema.
200
+ */
201
+ export function toJsonQueryValue(value) {
202
+ if (value instanceof Date) {
203
+ return S.encodeSync(dateJson)(value);
204
+ }
205
+ if (value instanceof Map) {
206
+ return [...value.entries()].map(([k, v]) => [toJsonQueryValue(k), toJsonQueryValue(v)]);
207
+ }
208
+ if (value instanceof Set) {
209
+ return [...value].map((v) => toJsonQueryValue(v));
210
+ }
211
+ if (Array.isArray(value)) {
212
+ return value.map((v) => toJsonQueryValue(v));
213
+ }
214
+ if (isPlainObject(value)) {
215
+ const out = {};
216
+ for (const [k, v] of Object.entries(value)) {
217
+ out[k] = toJsonQueryValue(v);
218
+ }
219
+ return out;
220
+ }
221
+ if (value !== null && typeof value === "object") {
222
+ const toJSON = value.toJSON;
223
+ if (typeof toJSON === "function") {
224
+ return toJsonQueryValue(toJSON.call(value));
225
+ }
226
+ }
227
+ return value;
228
+ }
229
+ export function encodeWithSchema(schema, value) {
230
+ if (schema === undefined)
231
+ return toJsonQueryValue(value);
232
+ return encodeJson(SchemaAST.toEncoded(schema.ast), value);
233
+ }
234
+ export function jsonifyFilter(filter, schema) {
235
+ const ast = schema === undefined ? undefined : SchemaAST.toEncoded(schema.ast);
236
+ return filter.map((r) => r.t === "and-scope" || r.t === "or-scope" || r.t === "where-scope"
237
+ ? { ...r, result: jsonifyFilter(r.result, schema) }
238
+ : { ...r, value: encodeFilterValue(astAtPath(ast, r.path.split(".")), r.op, r.value) });
239
+ }
240
+ export const makeJsonLower = (config) => ({
241
+ toJson: (value) => encodeWithSchema(config?.schema, value),
242
+ jsonifyFilter: (filter) => jsonifyFilter(filter, config?.schema)
243
+ });
5
244
  /** Traverse an object by a dot-separated path string, e.g. `"a.b.c"`. */
6
245
  export function get(obj, path) {
7
246
  return path.split(".").reduce((res, key) => (res != null ? res[key] : res), obj);
@@ -41,18 +280,18 @@ export function lowercaseIfString(val) {
41
280
  return val;
42
281
  }
43
282
  export function compare(valA, valB) {
44
- return valA === valB;
283
+ return toJsonQueryValue(valA) === toJsonQueryValue(valB);
45
284
  }
46
285
  export function lowerThan(valA, valB) {
47
- return valA < valB;
286
+ return toJsonQueryValue(valA) < toJsonQueryValue(valB);
48
287
  }
49
288
  export function lowerThanExclusive(valA, valB) {
50
- return valA <= valB;
289
+ return toJsonQueryValue(valA) <= toJsonQueryValue(valB);
51
290
  }
52
291
  export function greaterThan(valA, valB) {
53
- return valA > valB;
292
+ return toJsonQueryValue(valA) > toJsonQueryValue(valB);
54
293
  }
55
294
  export function greaterThanExclusive(valA, valB) {
56
- return valA >= valB;
295
+ return toJsonQueryValue(valA) >= toJsonQueryValue(valB);
57
296
  }
58
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvU3RvcmUvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFBO0FBQzNCLE9BQU8sS0FBSyxNQUFNLE1BQU0sbUJBQW1CLENBQUE7QUFDM0MsT0FBTyxLQUFLLE1BQU0sTUFBTSxtQkFBbUIsQ0FBQTtBQUUzQyxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxjQUFjLENBQUE7QUFFN0QseUVBQXlFO0FBQ3pFLE1BQU0sVUFBVSxHQUFHLENBQUMsR0FBUSxFQUFFLElBQVk7SUFDeEMsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQVEsRUFBRSxHQUFXLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtBQUMvRixDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUFHLENBQ3RCLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFLLEVBQ2YsRUFBRSxDQUNMLENBQUM7SUFDQyxHQUFHLENBQUM7SUFDSix5R0FBeUc7SUFDekcsS0FBSyxFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDO0NBQzNFLENBQVEsQ0FBQTtBQUVYLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLElBQVksRUFBRSxFQUFFLENBQzdDLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQ3pCLENBQUksRUFDSixLQUFZLEVBQ1osT0FBeUI7SUFFekIsSUFBSSxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDWixJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUMzQixPQUFPLEtBQUssQ0FBQyxDQUFDLElBQUksOEJBQThCLENBQUM7Z0JBQy9DLElBQUk7Z0JBQ0osRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQVc7Z0JBQ3RCLE9BQU8sRUFBRSxFQUFFO2dCQUNYLEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSztnQkFDZCxJQUFJLEVBQUUsR0FBRzthQUNWLENBQUMsQ0FBQTtRQUNKLENBQUM7SUFDSCxDQUFDO0lBQ0QsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE9BQU8sQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUM5RCxPQUFPLEtBQUssQ0FBQyxDQUFDLElBQUksOEJBQThCLENBQUM7WUFDL0MsSUFBSTtZQUNKLEVBQUUsRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBVztZQUNsQyxPQUFPLEVBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLO1lBQzVCLEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSztZQUNkLElBQUksRUFBRSxHQUFHO1NBQ1YsQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUNELE9BQU8sUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBQ3BCLENBQUMsQ0FBQyxDQUFBO0FBRUosTUFBTSxVQUFVLGlCQUFpQixDQUFJLEdBQU07SUFDekMsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM1QixPQUFPLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUMxQixDQUFDO0lBQ0QsT0FBTyxHQUFHLENBQUE7QUFDWixDQUFDO0FBRUQsTUFBTSxVQUFVLE9BQU8sQ0FBQyxJQUFhLEVBQUUsSUFBYTtJQUNsRCxPQUFPLElBQUksS0FBSyxJQUFJLENBQUE7QUFDdEIsQ0FBQztBQUVELE1BQU0sVUFBVSxTQUFTLENBQUMsSUFBc0IsRUFBRSxJQUFzQjtJQUN0RSxPQUFPLElBQUksR0FBRyxJQUFJLENBQUE7QUFDcEIsQ0FBQztBQUVELE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxJQUFzQixFQUFFLElBQXNCO0lBQy9FLE9BQU8sSUFBSSxJQUFJLElBQUksQ0FBQTtBQUNyQixDQUFDO0FBRUQsTUFBTSxVQUFVLFdBQVcsQ0FBQyxJQUFzQixFQUFFLElBQXNCO0lBQ3hFLE9BQU8sSUFBSSxHQUFHLElBQUksQ0FBQTtBQUNwQixDQUFDO0FBRUQsTUFBTSxVQUFVLG9CQUFvQixDQUFDLElBQXNCLEVBQUUsSUFBc0I7SUFDakYsT0FBTyxJQUFJLElBQUksSUFBSSxDQUFBO0FBQ3JCLENBQUMifQ==
297
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvU3RvcmUvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFBO0FBQzNCLE9BQU8sS0FBSyxNQUFNLE1BQU0sbUJBQW1CLENBQUE7QUFFM0MsT0FBTyxLQUFLLE1BQU0sTUFBTSxtQkFBbUIsQ0FBQTtBQUMzQyxPQUFPLEtBQUssQ0FBQyxNQUFNLG1CQUFtQixDQUFBO0FBQ3RDLE9BQU8sS0FBSyxTQUFTLE1BQU0sc0JBQXNCLENBQUE7QUFFakQsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0sY0FBYyxDQUFBO0FBRTdELE1BQU0sUUFBUSxHQUFHLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFBO0FBRXRDLE1BQU0sYUFBYSxHQUFHLENBQUMsS0FBYyxFQUFvQyxFQUFFO0lBQ3pFLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQTtJQUNyRixJQUFJLEtBQUssWUFBWSxJQUFJLElBQUksS0FBSyxZQUFZLEdBQUcsSUFBSSxLQUFLLFlBQVksR0FBRztRQUFFLE9BQU8sS0FBSyxDQUFBO0lBQ3ZGLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDMUMsT0FBTyxLQUFLLEtBQUssTUFBTSxDQUFDLFNBQVMsSUFBSSxLQUFLLEtBQUssSUFBSSxDQUFBO0FBQ3JELENBQUMsQ0FBQTtBQUVELE1BQU0sU0FBUyxHQUFHLENBQUMsR0FBa0IsRUFBaUIsRUFBRSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxD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
package/dist/logger.d.ts CHANGED
@@ -2,7 +2,7 @@ export declare const InfraLogger: {
2
2
  logWarning: (...message: readonly any[]) => import("effect/Effect").Effect<void, never, never>;
3
3
  logError: (...message: readonly any[]) => import("effect/Effect").Effect<void, never, never>;
4
4
  logFatal: (...message: readonly any[]) => import("effect/Effect").Effect<void, never, never>;
5
- logInfo: (...message: readonly any[]) => import("effect/Effect").Effect<void, never, never>;
5
+ logInfo: (...message: ReadonlyArray<any>) => import("effect/Effect").Effect<void, never, never>;
6
6
  logDebug: (...message: ReadonlyArray<any>) => import("effect/Effect").Effect<void, never, never>;
7
7
  logWithLevel: (level: import("effect/LogLevel").Severity, ...message: readonly any[]) => import("effect/Effect").Effect<void, never, never>;
8
8
  };
package/examples/query.ts CHANGED
@@ -76,7 +76,7 @@ const program = Effect.gen(function*() {
76
76
  and("_tag", "Something"),
77
77
  or(
78
78
  where("displayName", "Riley"),
79
- and("n", "gt", "2021-01-01T00:00:00Z"), // TODO: work with To type translation, so Date?
79
+ and("n", "gt", new Date("2021-01-01T00:00:00Z")),
80
80
  and("_tag", "Something")
81
81
  ),
82
82
  order("displayName"),
@@ -90,7 +90,7 @@ const program = Effect.gen(function*() {
90
90
  and("_tag", "Something"),
91
91
  or(
92
92
  where("displayName", "Riley"),
93
- and("n", "gt", "2021-01-01T00:00:00Z"), // TODO: work with To type translation, so Date?
93
+ and("n", "gt", new Date("2021-01-01T00:00:00Z")),
94
94
  and("_tag", "Something")
95
95
  ),
96
96
  order("displayName"),
@@ -112,7 +112,7 @@ expectTypeOf(test1).toEqualTypeOf<
112
112
  readonly _tag: "Something"
113
113
  readonly id: string
114
114
  readonly displayName: string
115
- readonly n: string
115
+ readonly n: Date
116
116
  readonly union: {
117
117
  readonly _tag: "string"
118
118
  readonly value: string
@@ -129,7 +129,7 @@ expectTypeOf(testneq1).toEqualTypeOf<
129
129
  readonly _tag: "Something"
130
130
  readonly id: string
131
131
  readonly displayName: string
132
- readonly n: string
132
+ readonly n: Date
133
133
  readonly union: {
134
134
  readonly _tag: "number"
135
135
  readonly value: number
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/infra",
3
- "version": "4.0.0-beta.316",
3
+ "version": "4.0.0-beta.318",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -10,18 +10,18 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@faker-js/faker": "^8.4.1",
13
+ "@sentry/node": "10.55.0",
13
14
  "fast-check": "^4.9.0",
14
15
  "jose": "^6.2.3",
15
16
  "proper-lockfile": "^4.1.2",
16
17
  "pure-rand": "8.4.0",
17
18
  "query-string": "^9.4.0",
18
- "effect-app": "4.0.0-beta.316"
19
+ "effect-app": "4.0.0-beta.318"
19
20
  },
20
21
  "devDependencies": {
21
22
  "@azure/cosmos": "^4.9.3",
22
23
  "@azure/service-bus": "^7.9.5",
23
- "@effect/sql-sqlite-node": "4.0.0-beta.107",
24
- "@sentry/node": "10.55.0",
24
+ "@effect/sql-sqlite-node": "4.0.0-rc.112",
25
25
  "@sentry/opentelemetry": "10.55.0",
26
26
  "@types/better-sqlite3": "^7.6.13",
27
27
  "@types/node": "25.9.1",
@@ -39,12 +39,12 @@
39
39
  "peerDependencies": {
40
40
  "@azure/cosmos": "^4.9.3",
41
41
  "@azure/service-bus": "^7.9.5",
42
- "@effect/vitest": "^4.0.0-beta.107",
42
+ "@effect/vitest": "^4.0.0-rc.112",
43
43
  "@sendgrid/helpers": "^8.0.0",
44
44
  "@sendgrid/mail": "^8.1.6",
45
45
  "@sentry/node": "10.55.0",
46
46
  "@sentry/opentelemetry": "10.55.0",
47
- "effect": "^4.0.0-beta.107",
47
+ "effect": "^4.0.0-rc.112",
48
48
  "jwt-decode": "^4.0.0",
49
49
  "redis": "^3.1.2",
50
50
  "redlock": "^4.2.0"
@@ -624,21 +624,34 @@ export const makeMessageStorage = Effect.fnUntraced(function*(options?: {
624
624
  withTracerDisabled
625
625
  ),
626
626
 
627
- unprocessedMessages: (shardIds, now) =>
628
- queryMessages(
629
- "SELECT * FROM c WHERE c.type = 'message' AND ARRAY_CONTAINS(@shardIds, c.shardId) AND c.processed = false AND (NOT IS_DEFINED(c.lastRead) OR IS_NULL(c.lastRead) OR c.lastRead < @lastReadBefore) AND (NOT IS_DEFINED(c.deliverAt) OR IS_NULL(c.deliverAt) OR c.deliverAt <= @now) ORDER BY c.rowid",
630
- [
631
- { name: "@shardIds", value: Array.from(shardIds) },
632
- { name: "@lastReadBefore", value: now - tenMinutes },
633
- { name: "@now", value: now }
634
- ]
635
- )
627
+ unprocessedMessages: (shardIds, now, options) => {
628
+ if (options?.addresses !== undefined && options.addresses.length === 0) {
629
+ return Effect.succeed([])
630
+ }
631
+ const parameters: Array<CosmosParameter> = [
632
+ { name: "@shardIds", value: Array.from(shardIds) },
633
+ { name: "@lastReadBefore", value: now - tenMinutes },
634
+ { name: "@now", value: now }
635
+ ]
636
+ let query =
637
+ "SELECT * FROM c WHERE c.type = 'message' AND ARRAY_CONTAINS(@shardIds, c.shardId) AND c.processed = false AND (NOT IS_DEFINED(c.lastRead) OR IS_NULL(c.lastRead) OR c.lastRead < @lastReadBefore) AND (NOT IS_DEFINED(c.deliverAt) OR IS_NULL(c.deliverAt) OR c.deliverAt <= @now)"
638
+ if (options?.addresses !== undefined) {
639
+ const match = addressClauses(options.addresses, "a")
640
+ query += ` AND (${match.sql})`
641
+ parameters.push(...match.parameters)
642
+ }
643
+ query += " ORDER BY c.rowid"
644
+ if (options?.limit !== undefined) {
645
+ query += ` OFFSET 0 LIMIT ${Math.floor(options.limit)}`
646
+ }
647
+ return queryMessages(query, parameters)
636
648
  .pipe(
637
649
  Effect.flatMap((docs) => collectUnprocessed(docs, now, claimMessageRead, queryReplies)),
638
650
  annotate("unprocessedMessages"),
639
651
  refailPersistence,
640
652
  withTracerDisabled
641
- ),
653
+ )
654
+ },
642
655
 
643
656
  unprocessedMessagesById: (messageIds, now) =>
644
657
  queryMessages(
@@ -655,21 +668,20 @@ export const makeMessageStorage = Effect.fnUntraced(function*(options?: {
655
668
  withTracerDisabled
656
669
  ),
657
670
 
658
- resetAddress: (address) =>
659
- queryMessages(
660
- "SELECT * FROM c WHERE c.type = 'message' AND c.processed = false AND c.shardId = @shardId AND c.entityType = @entityType AND c.entityId = @entityId",
661
- [
662
- { name: "@shardId", value: ShardId.toString(address.shardId) },
663
- { name: "@entityType", value: address.entityType },
664
- { name: "@entityId", value: address.entityId }
665
- ]
671
+ resetAddresses: (addresses) => {
672
+ if (addresses.length === 0) return Effect.void
673
+ const match = addressClauses(addresses, "r")
674
+ return queryMessages(
675
+ `SELECT * FROM c WHERE c.type = 'message' AND c.processed = false AND (${match.sql})`,
676
+ match.parameters
666
677
  )
667
678
  .pipe(
668
679
  Effect.flatMap((docs) => patchDocs(docs, () => [{ op: "set", path: "/lastRead", value: null }])),
669
- annotate("resetAddress"),
680
+ annotate("resetAddresses"),
670
681
  refailPersistence,
671
682
  withTracerDisabled
672
- ),
683
+ )
684
+ },
673
685
 
674
686
  clearAddress: (address) =>
675
687
  queryMessages(
@@ -713,6 +725,30 @@ export const makeMessageStorage = Effect.fnUntraced(function*(options?: {
713
725
  })
714
726
  })
715
727
 
728
+ const addressClauses = (
729
+ addresses: ReadonlyArray<{
730
+ readonly shardId: Parameters<typeof ShardId.toString>[0]
731
+ readonly entityType: string
732
+ readonly entityId: string
733
+ }>,
734
+ prefix: string
735
+ ): { readonly sql: string; readonly parameters: Array<CosmosParameter> } => {
736
+ const parameters: Array<CosmosParameter> = []
737
+ const clauses: Array<string> = []
738
+ for (const [i, address] of addresses.entries()) {
739
+ const shard = `@${prefix}s${i}`
740
+ const entityType = `@${prefix}t${i}`
741
+ const entityId = `@${prefix}e${i}`
742
+ clauses.push(`(c.shardId = ${shard} AND c.entityType = ${entityType} AND c.entityId = ${entityId})`)
743
+ parameters.push(
744
+ { name: shard, value: ShardId.toString(address.shardId) },
745
+ { name: entityType, value: address.entityType },
746
+ { name: entityId, value: address.entityId }
747
+ )
748
+ }
749
+ return { sql: clauses.join(" OR "), parameters }
750
+ }
751
+
716
752
  const collectUnprocessed = <E>(
717
753
  docs: ReadonlyArray<MessageDoc>,
718
754
  now: number,
@@ -3,6 +3,7 @@ import * as Context from "effect-app/Context"
3
3
  import * as Effect from "effect-app/Effect"
4
4
  import * as Layer from "effect-app/Layer"
5
5
  import * as Data from "effect/Data"
6
+ import * as Schema from "effect/Schema"
6
7
  import * as Scope from "effect/Scope"
7
8
  import * as ClusterError from "effect/unstable/cluster/ClusterError"
8
9
  import { Persisted } from "effect/unstable/cluster/ClusterSchema"
@@ -121,6 +122,7 @@ export const makeRunners: (
121
122
  )
122
123
 
123
124
  return yield* Runners.make({
125
+ codecFor: Schema.toCodecJson,
124
126
  ping: (address) => Effect.fail(new ClusterError.RunnerUnavailable({ address })),
125
127
  send: ({ address, message }) => {
126
128
  const persisted = Context.get(message.rpc.annotations, Persisted)
@@ -9,6 +9,7 @@ import type { SupportedValues } from "effect-app/Store"
9
9
  import { assertUnreachable } from "effect-app/utils"
10
10
  import { InfraLogger } from "../../logger.ts"
11
11
  import { isRelationCheck } from "../codeFilter.ts"
12
+ import { jsonifyFilter, type JsonLower, toJsonQueryValue } from "../utils.ts"
12
13
 
13
14
  export function logQuery(q: {
14
15
  query: string
@@ -60,8 +61,12 @@ export function buildWhereCosmosQuery3(
60
61
  >,
61
62
  order?: NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }>,
62
63
  skip?: number,
63
- limit?: number
64
+ limit?: number,
65
+ json?: JsonLower
64
66
  ) {
67
+ const toJson = json?.toJson ?? toJsonQueryValue
68
+ filter = (json?.jsonifyFilter ?? jsonifyFilter)(filter)
69
+ defaultValues = toJson(defaultValues) as Record<string, unknown>
65
70
  const statement = (x: FilterR, i: number) => {
66
71
  if (x.path === idKey) {
67
72
  x = { ...x, path: "id" }
@@ -89,23 +94,56 @@ export function buildWhereCosmosQuery3(
89
94
  return `(NOT ARRAY_CONTAINS(${k}, ${v}))`
90
95
 
91
96
  case "includes-any":
92
- return `ARRAY_CONTAINS_ANY(${k}, ${
93
- (x.value as unknown as readonly unknown[]).map((_, i) => `${v}__${i}`).join(", ")
94
- })`
97
+ return `ARRAY_CONTAINS_ANY(${k}, ${(x.value as readonly unknown[]).map((_, i) => `${v}__${i}`).join(", ")})`
95
98
  case "notIncludes-any":
96
99
  return `(NOT ARRAY_CONTAINS_ANY(${k}, ${
97
- (x.value as unknown as readonly unknown[]).map((_, i) => `${v}__${i}`).join(", ")
100
+ (x.value as readonly unknown[]).map((_, i) => `${v}__${i}`).join(", ")
98
101
  }))`
99
102
 
100
103
  case "includes-all":
101
- return `ARRAY_CONTAINS_ALL(${k}, ${
102
- (x.value as unknown as readonly unknown[]).map((_, i) => `${v}__${i}`).join(", ")
103
- })`
104
+ return `ARRAY_CONTAINS_ALL(${k}, ${(x.value as readonly unknown[]).map((_, i) => `${v}__${i}`).join(", ")})`
104
105
  case "notIncludes-all":
105
106
  return `(NOT ARRAY_CONTAINS_ALL(${k}, ${
106
- (x.value as unknown as readonly unknown[]).map((_, i) => `${v}__${i}`).join(", ")
107
+ (x.value as readonly unknown[]).map((_, i) => `${v}__${i}`).join(", ")
107
108
  }))`
108
109
 
110
+ case "hasKey":
111
+ return `EXISTS(SELECT VALUE p FROM p IN ${k} WHERE p[0] = ${v})`
112
+ case "notHasKey":
113
+ return `(NOT EXISTS(SELECT VALUE p FROM p IN ${k} WHERE p[0] = ${v}))`
114
+ case "hasValue":
115
+ return `EXISTS(SELECT VALUE p FROM p IN ${k} WHERE p[1] = ${v})`
116
+ case "notHasValue":
117
+ return `(NOT EXISTS(SELECT VALUE p FROM p IN ${k} WHERE p[1] = ${v}))`
118
+ case "hasKeyValue":
119
+ return `ARRAY_CONTAINS(${k}, ${v})`
120
+ case "notHasKeyValue":
121
+ return `(NOT ARRAY_CONTAINS(${k}, ${v}))`
122
+ case "hasKey-any":
123
+ return `EXISTS(SELECT VALUE p FROM p IN ${k} WHERE ARRAY_CONTAINS(${v}, p[0]))`
124
+ case "notHasKey-any":
125
+ return `(NOT EXISTS(SELECT VALUE p FROM p IN ${k} WHERE ARRAY_CONTAINS(${v}, p[0])))`
126
+ case "hasKey-all":
127
+ return `(NOT EXISTS(SELECT VALUE key FROM key IN ${v} WHERE NOT EXISTS(SELECT VALUE p FROM p IN ${k} WHERE p[0] = key)))`
128
+ case "notHasKey-all":
129
+ return `EXISTS(SELECT VALUE key FROM key IN ${v} WHERE NOT EXISTS(SELECT VALUE p FROM p IN ${k} WHERE p[0] = key))`
130
+ case "hasValue-any":
131
+ return `EXISTS(SELECT VALUE p FROM p IN ${k} WHERE ARRAY_CONTAINS(${v}, p[1]))`
132
+ case "notHasValue-any":
133
+ return `(NOT EXISTS(SELECT VALUE p FROM p IN ${k} WHERE ARRAY_CONTAINS(${v}, p[1])))`
134
+ case "hasValue-all":
135
+ return `(NOT EXISTS(SELECT VALUE val FROM val IN ${v} WHERE NOT EXISTS(SELECT VALUE p FROM p IN ${k} WHERE p[1] = val)))`
136
+ case "notHasValue-all":
137
+ return `EXISTS(SELECT VALUE val FROM val IN ${v} WHERE NOT EXISTS(SELECT VALUE p FROM p IN ${k} WHERE p[1] = val))`
138
+ case "hasKeyValue-any":
139
+ return `EXISTS(SELECT VALUE pair FROM pair IN ${v} WHERE ARRAY_CONTAINS(${k}, pair))`
140
+ case "notHasKeyValue-any":
141
+ return `(NOT EXISTS(SELECT VALUE pair FROM pair IN ${v} WHERE ARRAY_CONTAINS(${k}, pair)))`
142
+ case "hasKeyValue-all":
143
+ return `(NOT EXISTS(SELECT VALUE pair FROM pair IN ${v} WHERE NOT ARRAY_CONTAINS(${k}, pair)))`
144
+ case "notHasKeyValue-all":
145
+ return `EXISTS(SELECT VALUE pair FROM pair IN ${v} WHERE NOT ARRAY_CONTAINS(${k}, pair))`
146
+
109
147
  case "contains":
110
148
  return `CONTAINS(${k}, ${v}, true)`
111
149
 
@@ -166,6 +204,24 @@ export function buildWhereCosmosQuery3(
166
204
  "notIncludes-any": "includes-any",
167
205
  "includes-all": "notIncludes-all",
168
206
  "notIncludes-all": "includes-all",
207
+ hasKey: "notHasKey",
208
+ notHasKey: "hasKey",
209
+ hasValue: "notHasValue",
210
+ notHasValue: "hasValue",
211
+ hasKeyValue: "notHasKeyValue",
212
+ notHasKeyValue: "hasKeyValue",
213
+ "hasKey-any": "notHasKey-any",
214
+ "notHasKey-any": "hasKey-any",
215
+ "hasKey-all": "notHasKey-all",
216
+ "notHasKey-all": "hasKey-all",
217
+ "hasValue-any": "notHasValue-any",
218
+ "notHasValue-any": "hasValue-any",
219
+ "hasValue-all": "notHasValue-all",
220
+ "notHasValue-all": "hasValue-all",
221
+ "hasKeyValue-any": "notHasKeyValue-any",
222
+ "notHasKeyValue-any": "hasKeyValue-any",
223
+ "hasKeyValue-all": "notHasKeyValue-all",
224
+ "notHasKeyValue-all": "hasKeyValue-all",
169
225
  in: "notIn",
170
226
  notIn: "in"
171
227
  } satisfies Record<Ops, Ops>