@effect-app/infra 0.117.0 → 0.119.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 (85) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/_cjs/filter.cjs +13 -13
  3. package/_cjs/filter.cjs.map +1 -1
  4. package/_cjs/services/Repository.cjs +4 -38
  5. package/_cjs/services/Repository.cjs.map +1 -1
  6. package/_cjs/services/RepositoryBase.cjs +39 -36
  7. package/_cjs/services/RepositoryBase.cjs.map +1 -1
  8. package/_cjs/services/Store/Cosmos/query.cjs +291 -0
  9. package/_cjs/services/Store/Cosmos/query.cjs.map +1 -0
  10. package/_cjs/services/Store/Cosmos.cjs +38 -183
  11. package/_cjs/services/Store/Cosmos.cjs.map +1 -1
  12. package/_cjs/services/Store/Cosmos.test.cjs +7 -7
  13. package/_cjs/services/Store/Cosmos.test.cjs.map +1 -1
  14. package/_cjs/services/Store/Memory.cjs +20 -17
  15. package/_cjs/services/Store/Memory.cjs.map +1 -1
  16. package/_cjs/services/Store/Redis.cjs +1 -1
  17. package/_cjs/services/Store/Redis.cjs.map +1 -1
  18. package/_cjs/services/Store/codeFilter.cjs +151 -0
  19. package/_cjs/services/Store/codeFilter.cjs.map +1 -0
  20. package/_cjs/services/Store/codeFilter.test.cjs +8 -8
  21. package/_cjs/services/Store/codeFilter.test.cjs.map +1 -1
  22. package/_cjs/services/Store/filterApi/proxy.cjs +40 -0
  23. package/_cjs/services/Store/filterApi/proxy.cjs.map +1 -0
  24. package/_cjs/services/Store/filterApi/query.cjs +173 -0
  25. package/_cjs/services/Store/filterApi/query.cjs.map +1 -0
  26. package/_cjs/services/Store/filterApi.test.cjs +164 -0
  27. package/_cjs/services/Store/filterApi.test.cjs.map +1 -0
  28. package/_cjs/services/Store/service.cjs.map +1 -1
  29. package/_cjs/services/Store/utils.cjs +8 -1
  30. package/_cjs/services/Store/utils.cjs.map +1 -1
  31. package/_src/filter.ts +13 -13
  32. package/_src/services/Repository.ts +124 -70
  33. package/_src/services/RepositoryBase.ts +26 -12
  34. package/_src/services/Store/Cosmos/query.ts +390 -0
  35. package/_src/services/Store/Cosmos.test.ts +6 -6
  36. package/_src/services/Store/Cosmos.ts +39 -245
  37. package/_src/services/Store/Memory.ts +21 -18
  38. package/_src/services/Store/Redis.ts +2 -3
  39. package/_src/services/Store/codeFilter.test.ts +8 -8
  40. package/_src/services/Store/codeFilter.ts +150 -0
  41. package/_src/services/Store/filterApi/proxy.ts +109 -0
  42. package/_src/services/Store/filterApi/query.ts +256 -0
  43. package/_src/services/Store/filterApi.test.ts +263 -0
  44. package/_src/services/Store/service.ts +17 -5
  45. package/_src/services/Store/utils.ts +10 -7
  46. package/dist/filter.d.ts +13 -13
  47. package/dist/filter.js +14 -14
  48. package/dist/services/Repository.d.ts +44 -104
  49. package/dist/services/Repository.d.ts.map +1 -1
  50. package/dist/services/Repository.js +6 -30
  51. package/dist/services/RepositoryBase.d.ts +11 -21
  52. package/dist/services/RepositoryBase.d.ts.map +1 -1
  53. package/dist/services/RepositoryBase.js +41 -37
  54. package/dist/services/Store/Cosmos/query.d.ts +61 -0
  55. package/dist/services/Store/Cosmos/query.d.ts.map +1 -0
  56. package/dist/services/Store/Cosmos/query.js +302 -0
  57. package/dist/services/Store/Cosmos.d.ts +3 -47
  58. package/dist/services/Store/Cosmos.d.ts.map +1 -1
  59. package/dist/services/Store/Cosmos.js +39 -193
  60. package/dist/services/Store/Memory.d.ts +2 -7
  61. package/dist/services/Store/Memory.d.ts.map +1 -1
  62. package/dist/services/Store/Memory.js +17 -15
  63. package/dist/services/Store/Redis.d.ts.map +1 -1
  64. package/dist/services/Store/Redis.js +2 -2
  65. package/dist/services/Store/codeFilter.d.ts +5 -0
  66. package/dist/services/Store/codeFilter.d.ts.map +1 -0
  67. package/dist/services/Store/codeFilter.js +140 -0
  68. package/dist/services/Store/filterApi/proxy.d.ts +41 -0
  69. package/dist/services/Store/filterApi/proxy.d.ts.map +1 -0
  70. package/dist/services/Store/filterApi/proxy.js +41 -0
  71. package/dist/services/Store/filterApi/query.d.ts +64 -0
  72. package/dist/services/Store/filterApi/query.d.ts.map +1 -0
  73. package/dist/services/Store/filterApi/query.js +134 -0
  74. package/dist/services/Store/filterApi.test.d.ts.map +1 -0
  75. package/dist/services/Store/service.d.ts +12 -5
  76. package/dist/services/Store/service.d.ts.map +1 -1
  77. package/dist/services/Store/service.js +1 -1
  78. package/dist/services/Store/utils.d.ts +7 -1
  79. package/dist/services/Store/utils.d.ts.map +1 -1
  80. package/dist/services/Store/utils.js +118 -115
  81. package/dist/services/simpledb/cosmosdb.d.ts +2 -2
  82. package/dist/services/simpledb/diskdb.d.ts +1 -1
  83. package/dist/services/simpledb/redisdb.d.ts +2 -2
  84. package/dist/services/simpledb/simpledb.d.ts +2 -2
  85. package/package.json +44 -4
@@ -0,0 +1,390 @@
1
+ import { assertUnreachable } from "@effect-app/prelude/utils"
2
+ import type { FilterR, FilterResult } from "../filterApi/query.js"
3
+ import type { FilterJoinSelect, JoinFindFilter, LegacyFilter, StoreWhereFilter, SupportedValues } from "../service.js"
4
+
5
+ export function logQuery(q: {
6
+ query: string
7
+ parameters: {
8
+ name: string
9
+ value: SupportedValues | readonly SupportedValues[]
10
+ }[]
11
+ }) {
12
+ return Effect
13
+ .logDebug("cosmos query")
14
+ .pipe(Effect.annotateLogs({
15
+ query: q.query,
16
+ parameters: JSON.stringify(
17
+ q.parameters.reduce((acc, v) => {
18
+ acc[v.name] = v.value
19
+ return acc
20
+ }, {} as Record<string, SupportedValues | readonly SupportedValues[]>),
21
+ undefined,
22
+ 2
23
+ )
24
+ }))
25
+ }
26
+
27
+ /**
28
+ * @deprecated: should build Select into Where query
29
+ */
30
+ export function buildFilterJoinSelectCosmosQuery(
31
+ filter: FilterJoinSelect,
32
+ k: string,
33
+ name: string,
34
+ skip?: number,
35
+ limit?: number
36
+ ) {
37
+ const lm = skip !== undefined || limit !== undefined ? `OFFSET ${skip ?? 0} LIMIT ${limit ?? 999999}` : ""
38
+ return {
39
+ query: `
40
+ SELECT r, f.id as _rootId
41
+ FROM ${name} f
42
+ JOIN r IN f.${k}
43
+ WHERE LOWER(r.${filter.valueKey}) = LOWER(@value)
44
+ ${lm}
45
+ `,
46
+ parameters: [{ name: "@value", value: filter.value }]
47
+ }
48
+ }
49
+
50
+ /**
51
+ * @deprecated: is now part of Where query as k.-1.valueKey
52
+ */
53
+ export function buildFindJoinCosmosQuery(
54
+ filter: JoinFindFilter,
55
+ k: string,
56
+ name: string,
57
+ skip?: number,
58
+ limit?: number
59
+ ) {
60
+ const lm = skip !== undefined || limit !== undefined ? `OFFSET ${skip ?? 0} LIMIT ${limit ?? 999999}` : ""
61
+ return {
62
+ query: `
63
+ SELECT DISTINCT VALUE f
64
+ FROM ${name} f
65
+ JOIN r IN f.${k}
66
+ WHERE LOWER(r.${filter.valueKey}) = LOWER(@value)
67
+ ${lm}`,
68
+ parameters: [{ name: "@value", value: filter.value }]
69
+ }
70
+ }
71
+
72
+ /**
73
+ * @deprecated: should build into Where query
74
+ */
75
+ export function buildLegacyCosmosQuery<PM>(
76
+ filter: LegacyFilter<PM>,
77
+ name: string,
78
+ importedMarkerId: string,
79
+ skip?: number,
80
+ limit?: number
81
+ ) {
82
+ const lm = skip !== undefined || limit !== undefined ? `OFFSET ${skip ?? 0} LIMIT ${limit ?? 999999}` : ""
83
+ return {
84
+ query: `
85
+ SELECT *
86
+ FROM ${name} f
87
+ WHERE f.id != @id AND f.${
88
+ String(
89
+ filter.by
90
+ )
91
+ } LIKE @filter
92
+ ${lm}`,
93
+ parameters: [
94
+ { name: "@id", value: importedMarkerId },
95
+ {
96
+ name: "@filter",
97
+ value: filter.type === "endsWith"
98
+ ? `%${filter.value}`
99
+ : filter.type === "contains"
100
+ ? `%${filter.value}%`
101
+ : `${filter.value}%`
102
+ }
103
+ ]
104
+ }
105
+ }
106
+
107
+ export function buildWhereCosmosQuery(
108
+ filter: StoreWhereFilter,
109
+ name: string,
110
+ importedMarkerId: string,
111
+ skip?: number,
112
+ limit?: number
113
+ ) {
114
+ const lm = skip !== undefined || limit !== undefined ? `OFFSET ${skip ?? 0} LIMIT ${limit ?? 999999}` : ""
115
+ return {
116
+ query: `
117
+ SELECT *
118
+ FROM ${name} f
119
+ ${
120
+ filter
121
+ .where
122
+ .filter((_) => _.key.includes(".-1."))
123
+ .map((_) => _.key.split(".-1.")[0])
124
+ .map((_) => `JOIN ${_} IN f.${_}`)
125
+ .uniq(Equivalence.string)
126
+ .join("\n")
127
+ }
128
+ WHERE f.id != @id AND ${
129
+ filter
130
+ .where
131
+ .map((_) =>
132
+ _.key.includes(".-1.")
133
+ ? { ..._, f: _.key.split(".-1.")[0], key: _.key.split(".-1.")[1]! }
134
+ : { ..._, f: "f" }
135
+ )
136
+ .map(
137
+ (x, i) => {
138
+ const k = `${x.f}.${x.key}`
139
+ const v = `@v${i}`
140
+
141
+ switch (x.t) {
142
+ case "in":
143
+ return `ARRAY_CONTAINS(${v}, ${k})`
144
+ case "not-in":
145
+ return `(NOT ARRAY_CONTAINS(${v}, ${k}))`
146
+
147
+ case "includes":
148
+ return `ARRAY_CONTAINS(${k}, ${v})`
149
+ case "not-includes":
150
+ return `(NOT ARRAY_CONTAINS(${k}, ${v}))`
151
+ case "contains":
152
+ return `CONTAINS(${k}, ${v}, true)`
153
+ case "starts-with":
154
+ return `STARTSWITH(${k}, ${v}, true)`
155
+ case "ends-with":
156
+ return `ENDSWITH(${k}, ${v}, true)`
157
+ case "not-contains":
158
+ return `NOT(CONTAINS(${k}, ${v}, true))`
159
+ case "not-starts-with":
160
+ return `NOT(STARTSWITH(${k}, ${v}, true))`
161
+ case "not-ends-with":
162
+ return `NOT(ENDSWITH(${k}, ${v}, true))`
163
+ }
164
+
165
+ const lk = lowerIfNeeded(k, x.value)
166
+ const lv = lowerIfNeeded(v, x.value)
167
+
168
+ switch (x.t) {
169
+ case "lt":
170
+ return `${lk} < ${lv}`
171
+ case "lte":
172
+ return `${lk} <= ${lv}`
173
+ case "gt":
174
+ return `${lk} > ${lv}`
175
+ case "gte":
176
+ return `${lk} >= ${lv}`
177
+ case "not-eq":
178
+ return x.value === null
179
+ ? `IS_NULL(${k}) = false`
180
+ : `${lk} <> ${lv}`
181
+ case undefined:
182
+ case "eq":
183
+ return x.value === null
184
+ ? `IS_NULL(${k}) = true`
185
+ : `${lk} = ${lv}`
186
+ }
187
+ }
188
+ )
189
+ .join(filter.mode === "or" ? " OR " : " AND ")
190
+ }
191
+ ${lm}`,
192
+ parameters: [
193
+ { name: "@id", value: importedMarkerId },
194
+ ...filter
195
+ .where
196
+ .map((x, i) => ({
197
+ name: `@v${i}`,
198
+ value: x.value
199
+ }))
200
+ ]
201
+ }
202
+ }
203
+
204
+ // function isArray(t: SupportedValues | readonly SupportedValues[]): t is readonly SupportedValues[] {
205
+ // return Array.isArray(t)
206
+ // }
207
+
208
+ function lowerIfNeeded(key: unknown, value: unknown) {
209
+ return typeof value === "string" ? `LOWER(${key})` : `${key}`
210
+ }
211
+
212
+ export function buildCosmosQuery<PM>(
213
+ filter: LegacyFilter<PM> | StoreWhereFilter,
214
+ name: string,
215
+ importedMarkerId: string,
216
+ skip?: number,
217
+ limit?: number
218
+ ) {
219
+ return filter.type === "startsWith"
220
+ || filter.type === "endsWith"
221
+ || filter.type === "contains"
222
+ ? buildLegacyCosmosQuery(filter, name, importedMarkerId, skip, limit)
223
+ : buildWhereCosmosQuery(filter, name, importedMarkerId, skip, limit)
224
+ }
225
+
226
+ export function buildWhereCosmosQuery3(
227
+ filter: readonly FilterResult[],
228
+ name: string,
229
+ importedMarkerId: string,
230
+ select?: readonly string[],
231
+ skip?: number,
232
+ limit?: number
233
+ ) {
234
+ const lm = skip !== undefined || limit !== undefined ? `OFFSET ${skip ?? 0} LIMIT ${limit ?? 999999}` : ""
235
+
236
+ const statement = (x: FilterR, i: number) => {
237
+ const k = x.path.includes(".-1.")
238
+ ? `${x.path.split(".-1.")[0]}.${x.path.split(".-1.")[1]!}`
239
+ : `f.${x.path}`
240
+
241
+ const v = "@v" + i
242
+
243
+ switch (x.op) {
244
+ case "in":
245
+ return `ARRAY_CONTAINS(${v}, ${k})`
246
+ case "notIn":
247
+ return `(NOT ARRAY_CONTAINS(${v}, ${k}))`
248
+
249
+ case "includes":
250
+ return `ARRAY_CONTAINS(${k}, ${v})`
251
+ case "notIncludes":
252
+ return `(NOT ARRAY_CONTAINS(${k}, ${v}))`
253
+ case "contains":
254
+ return `CONTAINS(${k}, ${v}, true)`
255
+
256
+ case "startsWith":
257
+ return `STARTSWITH(${k}, ${v}, true)`
258
+ case "endsWith":
259
+ return `ENDSWITH(${k}, ${v}, true)`
260
+ case "notContains":
261
+ return `NOT(CONTAINS(${k}, ${v}, true))`
262
+ case "notStartsWith":
263
+ return `NOT(STARTSWITH(${k}, ${v}, true))`
264
+ case "notEndsWith":
265
+ return `NOT(ENDSWITH(${k}, ${v}, true))`
266
+ }
267
+
268
+ const lk = lowerIfNeeded(k, x.value)
269
+ const lv = lowerIfNeeded(v, x.value)
270
+
271
+ switch (x.op) {
272
+ case "lt":
273
+ return `${lk} < ${lv}`
274
+ case "lte":
275
+ return `${lk} <= ${lv}`
276
+ case "gt":
277
+ return `${lk} > ${lv}`
278
+ case "gte":
279
+ return `${lk} >= ${lv}`
280
+ case "neq":
281
+ return x.value === null
282
+ ? `IS_NULL(${k}) = false`
283
+ : `${lk} <> ${lv}`
284
+ case undefined:
285
+ case "eq":
286
+ return x.value === null
287
+ ? `IS_NULL(${k}) = true`
288
+ : `${lk} = ${lv}`
289
+ default: {
290
+ return assertUnreachable(x.op)
291
+ }
292
+ }
293
+ }
294
+
295
+ let i = 0
296
+
297
+ const print = (state: readonly FilterResult[]) => {
298
+ let s = ""
299
+ let l = 0
300
+ const printN = (n: number) => {
301
+ return n === 0 ? "" : ReadonlyArray.range(1, n).map(() => " ").join("")
302
+ }
303
+ for (const e of state) {
304
+ switch (e.t) {
305
+ case "where":
306
+ s += statement(e, i++)
307
+ break
308
+ case "or":
309
+ s += ` OR ${statement(e, i++)}`
310
+ break
311
+ case "and":
312
+ s += ` AND ${statement(e, i++)}`
313
+ break
314
+ case "or-scope": {
315
+ ;++l
316
+ s += ` OR (\n${printN(l + 1)}${print(e.result)}\n${printN(l)})`
317
+ ;--l
318
+ break
319
+ }
320
+ case "and-scope": {
321
+ ;++l
322
+ s += ` AND (\n${printN(l + 1)}${print(e.result)}\n${printN(l)})`
323
+ ;--l
324
+ break
325
+ }
326
+ case "where-scope": {
327
+ // ;++l
328
+ s += `(\n${printN(l + 1)}${print(e.result)}\n)`
329
+ // ;--l
330
+ break
331
+ }
332
+ }
333
+ }
334
+ return s
335
+ }
336
+
337
+ // const fff = (filter: readonly FilterR[], mode: "AND" | "OR") =>
338
+ // "(" + filter
339
+ // .map((_) =>
340
+ // _.path.includes(".-1.")
341
+ // ? { ..._, f: _.path.split(".-1.")[0], key: _.path.split(".-1.")[1]! }
342
+ // : { ..._, f: "f" }
343
+ // )
344
+ // .map(
345
+ // (x, i) => {
346
+ // const k = `${x.f}.${x.path}`
347
+ // const v = `@v${i}`
348
+
349
+ // return statement(x, k, v)
350
+ // }
351
+ // )
352
+ // .join(mode === "OR" ? " OR " : " AND ") + ")"
353
+ const getValues = (filter: readonly FilterResult[]): FilterR[] =>
354
+ filter
355
+ .flatMap((_) =>
356
+ _.t === "and-scope" || _.t === "or-scope" || _.t === "where-scope"
357
+ ? getValues(_.result)
358
+ : [_]
359
+ )
360
+ const values = getValues(filter)
361
+ return {
362
+ query: `
363
+ SELECT ${
364
+ select
365
+ ? `VALUE {\n${select.map((_) => `${_}: f.${_}`).join(",\n")}\n}`
366
+ : "*"
367
+ }
368
+ FROM ${name} f
369
+
370
+ ${
371
+ values
372
+ .filter((_) => _.path.includes(".-1."))
373
+ .map((_) => _.path.split(".-1.")[0])
374
+ .map((_) => `JOIN ${_} IN f.${_}`)
375
+ .uniq(Equivalence.string)
376
+ .join("\n")
377
+ }
378
+
379
+ WHERE f.id != @id ${filter.length ? `AND ${print(filter)}` : ""}
380
+ ${lm}`,
381
+ parameters: [
382
+ { name: "@id", value: importedMarkerId },
383
+ ...values
384
+ .map((x, i) => ({
385
+ name: `@v${i}`,
386
+ value: x.value
387
+ }))
388
+ ]
389
+ }
390
+ }
@@ -1,6 +1,6 @@
1
1
  import type { StoreWhereFilter, Where } from "@effect-app/infra/services/Store"
2
2
  import { Filters, makeFilters } from "../../filter.js"
3
- import { buildWhereCosmosQuery } from "./Cosmos.js"
3
+ import { buildWhereCosmosQuery } from "./Cosmos/query.js"
4
4
 
5
5
  const f_ = makeFilters<Something>()
6
6
  export type SomethingWhereFilter = typeof f_
@@ -57,15 +57,15 @@ test("works", () => {
57
57
  }
58
58
  ],
59
59
  "query": `
60
- SELECT f
61
- FROM Somethings AS f
60
+ SELECT *
61
+ FROM Somethings f
62
62
 
63
63
  WHERE f.id != @id AND LOWER(f.b) = LOWER(@v0)
64
64
  OFFSET 0 LIMIT 10`
65
65
  })
66
66
 
67
67
  expect(buildWhereCosmosQuery(
68
- somethingsWhere((_) => _("d.-1.a", Filters.$isnt("a2"))),
68
+ somethingsWhere((_) => _("d.-1.a", Filters.isnt("a2"))),
69
69
  "Somethings",
70
70
  "importedMarkerId",
71
71
  undefined,
@@ -83,8 +83,8 @@ test("works", () => {
83
83
  }
84
84
  ],
85
85
  "query": `
86
- SELECT f
87
- FROM Somethings AS f
86
+ SELECT *
87
+ FROM Somethings f
88
88
  JOIN d IN f.d
89
89
  WHERE f.id != @id AND LOWER(d.a) <> LOWER(@v0)
90
90
  OFFSET 0 LIMIT 10`