@effect-app/infra 2.61.8 → 2.63.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.
- package/CHANGELOG.md +12 -0
- package/dist/Model/filter/filterApi.d.ts +4 -0
- package/dist/Model/filter/filterApi.d.ts.map +1 -1
- package/dist/Model/query/dsl.d.ts +14 -1
- package/dist/Model/query/dsl.d.ts.map +1 -1
- package/dist/Model/query/dsl.js +3 -1
- package/dist/Model/query/new-kid-interpreter.d.ts +1 -1
- package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.js +16 -8
- package/dist/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/Store/Cosmos/query.js +57 -12
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +4 -2
- package/dist/Store/codeFilter.d.ts.map +1 -1
- package/dist/Store/codeFilter.js +18 -12
- package/package.json +1 -1
- package/src/Model/filter/filterApi.ts +5 -0
- package/src/Model/query/dsl.ts +34 -6
- package/src/Model/query/new-kid-interpreter.ts +17 -7
- package/src/Store/Cosmos/query.ts +70 -15
- package/src/Store/Cosmos.ts +3 -1
- package/src/Store/codeFilter.ts +21 -17
- package/test/dist/rawQuery.test.d.ts.map +1 -1
- package/test/rawQuery.test.ts +106 -48
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { Array, Effect, type NonEmptyReadonlyArray } from "effect-app"
|
|
4
4
|
import { assertUnreachable } from "effect-app/utils"
|
|
5
5
|
import { InfraLogger } from "../../logger.js"
|
|
6
|
-
import type { FilterR, FilterResult } from "../../Model/filter/filterApi.js"
|
|
6
|
+
import type { FilterR, FilterResult, Ops } from "../../Model/filter/filterApi.js"
|
|
7
7
|
import { isRelationCheck } from "../codeFilter.js"
|
|
8
8
|
import type { SupportedValues } from "../service.js"
|
|
9
9
|
|
|
@@ -125,7 +125,48 @@ export function buildWhereCosmosQuery3(
|
|
|
125
125
|
|
|
126
126
|
let i = 0
|
|
127
127
|
|
|
128
|
-
const
|
|
128
|
+
const flipOps = {
|
|
129
|
+
gt: "lt",
|
|
130
|
+
lt: "gt",
|
|
131
|
+
gte: "lte",
|
|
132
|
+
lte: "gte",
|
|
133
|
+
contains: "notContains",
|
|
134
|
+
notContains: "contains",
|
|
135
|
+
startsWith: "notStartsWith",
|
|
136
|
+
notStartsWith: "startsWith",
|
|
137
|
+
endsWith: "notEndsWith",
|
|
138
|
+
notEndsWith: "endsWith",
|
|
139
|
+
eq: "neq",
|
|
140
|
+
neq: "eq",
|
|
141
|
+
includes: "notIncludes",
|
|
142
|
+
notIncludes: "includes",
|
|
143
|
+
"includes-any": "notIncludes-any",
|
|
144
|
+
"notIncludes-any": "includes-any",
|
|
145
|
+
"includes-all": "notIncludes-all",
|
|
146
|
+
"notIncludes-all": "includes-all",
|
|
147
|
+
in: "notIn",
|
|
148
|
+
notIn: "in"
|
|
149
|
+
} satisfies Record<Ops, Ops>
|
|
150
|
+
|
|
151
|
+
const flippies = {
|
|
152
|
+
and: "or",
|
|
153
|
+
or: "and"
|
|
154
|
+
} satisfies Record<"and" | "or", "and" | "or">
|
|
155
|
+
|
|
156
|
+
const flip = (every: boolean) => (_: FilterResult): FilterResult =>
|
|
157
|
+
every
|
|
158
|
+
? _.t === "where" || _.t === "or" || _.t === "and"
|
|
159
|
+
? {
|
|
160
|
+
..._,
|
|
161
|
+
t: _.t === "where"
|
|
162
|
+
? _.t
|
|
163
|
+
: flippies[_.t],
|
|
164
|
+
op: flipOps[_.op]
|
|
165
|
+
}
|
|
166
|
+
: _
|
|
167
|
+
: _
|
|
168
|
+
|
|
169
|
+
const print = (state: readonly FilterResult[], values: any[], isRelation: string | null, every: boolean) => {
|
|
129
170
|
let s = ""
|
|
130
171
|
let l = 0
|
|
131
172
|
const printN = (n: number) => {
|
|
@@ -144,48 +185,62 @@ export function buildWhereCosmosQuery3(
|
|
|
144
185
|
break
|
|
145
186
|
case "or-scope": {
|
|
146
187
|
++l
|
|
188
|
+
if (!every) every = e.relation === "every"
|
|
147
189
|
const rel = isRelationCheck(e.result, isRelation)
|
|
148
190
|
if (rel) {
|
|
149
191
|
const rel = (e.result[0]! as { path: string }).path.split(".-1.")[0]
|
|
150
192
|
s += isRelation
|
|
151
|
-
? ` OR (\n${printN(l + 1)}${print(e.result, values)}\n${printN(l)})`
|
|
152
|
-
: ` OR (\n${printN(l + 1)}
|
|
153
|
-
|
|
193
|
+
? ` OR (\n${printN(l + 1)}${print(e.result, values, rel, every)}\n${printN(l)})`
|
|
194
|
+
: ` OR (\n${printN(l + 1)}${
|
|
195
|
+
every ? "NOT " : ""
|
|
196
|
+
}EXISTS(SELECT VALUE ${rel} FROM ${rel} IN f.${rel} WHERE ${
|
|
197
|
+
print(
|
|
198
|
+
e
|
|
199
|
+
.result
|
|
200
|
+
.map(flip(every)),
|
|
201
|
+
values,
|
|
202
|
+
rel,
|
|
203
|
+
every
|
|
204
|
+
)
|
|
154
205
|
}))`
|
|
155
206
|
} else {
|
|
156
|
-
s += ` OR (\n${printN(l + 1)}${print(e.result, values)}\n${printN(l)})`
|
|
207
|
+
s += ` OR (\n${printN(l + 1)}${print(e.result, values, null, every)}\n${printN(l)})`
|
|
157
208
|
}
|
|
158
209
|
--l
|
|
159
210
|
break
|
|
160
211
|
}
|
|
161
212
|
case "and-scope": {
|
|
162
213
|
++l
|
|
214
|
+
if (!every) every = e.relation === "every"
|
|
163
215
|
const rel = isRelationCheck(e.result, isRelation)
|
|
164
216
|
if (rel) {
|
|
165
217
|
const rel = (e.result[0]! as { path: string }).path.split(".-1.")[0]
|
|
166
218
|
s += isRelation
|
|
167
|
-
? ` AND (\n${printN(l + 1)}${print(e.result, values)}\n${printN(l)})`
|
|
168
|
-
: ` AND (\n${printN(l + 1)}
|
|
169
|
-
|
|
219
|
+
? ` AND (\n${printN(l + 1)}${print(e.result, values, rel, every)}\n${printN(l)})`
|
|
220
|
+
: ` AND (\n${printN(l + 1)}${
|
|
221
|
+
every ? "NOT " : ""
|
|
222
|
+
}EXISTS(SELECT VALUE ${rel} FROM ${rel} IN f.${rel} WHERE ${
|
|
223
|
+
print(e.result.map(flip(every)), values, rel, every)
|
|
170
224
|
}))`
|
|
171
225
|
} else {
|
|
172
|
-
s += ` AND (\n${printN(l + 1)}${print(e.result, values)}\n${printN(l)})`
|
|
226
|
+
s += ` AND (\n${printN(l + 1)}${print(e.result, values, null, every)}\n${printN(l)})`
|
|
173
227
|
}
|
|
174
228
|
--l
|
|
175
229
|
break
|
|
176
230
|
}
|
|
177
231
|
case "where-scope": {
|
|
178
232
|
// ;++l
|
|
233
|
+
if (!every) every = e.relation === "every"
|
|
179
234
|
const rel = isRelationCheck(e.result, isRelation)
|
|
180
235
|
if (rel) {
|
|
181
236
|
const rel = (e.result[0]! as { path: string }).path.split(".-1.")[0]
|
|
182
237
|
s += isRelation
|
|
183
|
-
? `(\n${printN(l + 1)}${print(e.result, values)}\n${printN(l)})`
|
|
184
|
-
: `(\n${printN(l + 1)}EXISTS(SELECT VALUE ${rel} FROM ${rel} IN f.${rel} WHERE ${
|
|
185
|
-
print(e.result, values, rel)
|
|
238
|
+
? `(\n${printN(l + 1)}${print(e.result, values, rel, every)}\n${printN(l)})`
|
|
239
|
+
: `(\n${printN(l + 1)}${every ? "NOT " : ""}EXISTS(SELECT VALUE ${rel} FROM ${rel} IN f.${rel} WHERE ${
|
|
240
|
+
print(e.result.map(flip(every)), values, rel, every)
|
|
186
241
|
}))`
|
|
187
242
|
} else {
|
|
188
|
-
s += `(\n${printN(l + 1)}${print(e.result, values)}\n${printN(l)})`
|
|
243
|
+
s += `(\n${printN(l + 1)}${print(e.result, values, null, every)}\n${printN(l)})`
|
|
189
244
|
}
|
|
190
245
|
// ;--l
|
|
191
246
|
break
|
|
@@ -239,7 +294,7 @@ export function buildWhereCosmosQuery3(
|
|
|
239
294
|
}
|
|
240
295
|
FROM ${name} f
|
|
241
296
|
|
|
242
|
-
WHERE f.id != @id ${filter.length ? `AND (${print(filter, values.map((_) => _.value))})` : ""}
|
|
297
|
+
WHERE f.id != @id ${filter.length ? `AND (${print(filter, values.map((_) => _.value), null, false)})` : ""}
|
|
243
298
|
${order ? `ORDER BY ${order.map((_) => `${dottedToAccess(`f.${_.key}`)} ${_.direction}`).join(", ")}` : ""}
|
|
244
299
|
${skip !== undefined || limit !== undefined ? `OFFSET ${skip ?? 0} LIMIT ${limit ?? 999999}` : ""}`,
|
|
245
300
|
parameters: [
|
package/src/Store/Cosmos.ts
CHANGED
|
@@ -54,6 +54,8 @@ function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
54
54
|
const container = db.container(containerId)
|
|
55
55
|
const bulk = container.items.bulk.bind(container.items)
|
|
56
56
|
const execBatch = container.items.batch.bind(container.items)
|
|
57
|
+
// TODO: move the marker to a separate container and get rid of the checks on every query
|
|
58
|
+
// then need to clean up the actual data.. perhaps first do with a config toggle to prescribe to it.
|
|
57
59
|
const importedMarkerId = containerId
|
|
58
60
|
|
|
59
61
|
const bulkSet = (items: NonEmptyReadonlyArray<PM>) =>
|
|
@@ -288,7 +290,7 @@ function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
288
290
|
.sync(() =>
|
|
289
291
|
buildWhereCosmosQuery3(
|
|
290
292
|
idKey,
|
|
291
|
-
filter ? [{ t: "where-scope", result: filter }] : [],
|
|
293
|
+
filter ? [{ t: "where-scope", result: filter, relation: "some" }] : [],
|
|
292
294
|
name,
|
|
293
295
|
importedMarkerId,
|
|
294
296
|
defaultValues,
|
package/src/Store/codeFilter.ts
CHANGED
|
@@ -93,7 +93,8 @@ const codeFilter3__ = <E>(
|
|
|
93
93
|
state: readonly FilterResult[],
|
|
94
94
|
sut: E,
|
|
95
95
|
statements: any[],
|
|
96
|
-
isRelation: string | null
|
|
96
|
+
isRelation: string | null,
|
|
97
|
+
every: boolean
|
|
97
98
|
): string => {
|
|
98
99
|
let s = ""
|
|
99
100
|
let l = 0
|
|
@@ -126,32 +127,34 @@ const codeFilter3__ = <E>(
|
|
|
126
127
|
break
|
|
127
128
|
case "or-scope": {
|
|
128
129
|
++l
|
|
130
|
+
if (!every) every = e.relation === "every"
|
|
129
131
|
const rel = isRelationCheck(e.result, isRelation)
|
|
130
132
|
if (rel) {
|
|
131
133
|
const rel = (e.result[0]! as { path: string }).path.split(".-1.")[0]
|
|
132
134
|
s += isRelation
|
|
133
|
-
? ` || (\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, rel)}\n${printN(l)})`
|
|
134
|
-
: ` || (\n${printN(l + 1)}sut.${rel}
|
|
135
|
-
|
|
136
|
-
})`
|
|
135
|
+
? ` || (\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, rel, every)}\n${printN(l)})`
|
|
136
|
+
: ` || (\n${printN(l + 1)}sut.${rel}.${every ? "every" : "some"}(el => ${
|
|
137
|
+
codeFilter3__(e.result, sut, statements, rel, every)
|
|
138
|
+
})\n${printN(l)})`
|
|
137
139
|
} else {
|
|
138
|
-
s += ` || (\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements)}\n${printN(l)})`
|
|
140
|
+
s += ` || (\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, null, every)}\n${printN(l)})`
|
|
139
141
|
}
|
|
140
142
|
--l
|
|
141
143
|
break
|
|
142
144
|
}
|
|
143
145
|
case "and-scope": {
|
|
144
146
|
++l
|
|
147
|
+
if (!every) every = e.relation === "every"
|
|
145
148
|
const rel = isRelationCheck(e.result, isRelation)
|
|
146
149
|
if (rel) {
|
|
147
150
|
const rel = (e.result[0]! as { path: string }).path.split(".-1.")[0]
|
|
148
151
|
s += isRelation
|
|
149
|
-
? ` && (\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, rel)}\n${printN(l)})`
|
|
150
|
-
: ` && (\n${printN(l + 1)}sut.${rel}
|
|
151
|
-
|
|
152
|
-
})`
|
|
152
|
+
? ` && (\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, rel, every)}\n${printN(l)})`
|
|
153
|
+
: ` && (\n${printN(l + 1)}sut.${rel}.${every ? "every" : "some"}(el => ${
|
|
154
|
+
codeFilter3__(e.result, sut, statements, rel, every)
|
|
155
|
+
})\n${printN(l)})`
|
|
153
156
|
} else {
|
|
154
|
-
s += ` && (\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements)}\n${printN(l)})`
|
|
157
|
+
s += ` && (\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, null, every)}\n${printN(l)})`
|
|
155
158
|
}
|
|
156
159
|
--l
|
|
157
160
|
|
|
@@ -159,16 +162,17 @@ const codeFilter3__ = <E>(
|
|
|
159
162
|
}
|
|
160
163
|
case "where-scope": {
|
|
161
164
|
// ;++l
|
|
165
|
+
if (!every) every = e.relation === "every"
|
|
162
166
|
const rel = isRelationCheck(e.result, isRelation)
|
|
163
167
|
if (rel) {
|
|
164
168
|
const rel = (e.result[0]! as { path: string }).path.split(".-1.")[0]
|
|
165
169
|
s += isRelation
|
|
166
|
-
? `(\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, rel)}\n${printN(l)})`
|
|
167
|
-
: `(\n${printN(l + 1)}sut.${rel}
|
|
168
|
-
|
|
169
|
-
})`
|
|
170
|
+
? `(\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, rel, every)}\n${printN(l)})`
|
|
171
|
+
: `(\n${printN(l + 1)}sut.${rel}.${every ? "every" : "some"}(el => ${
|
|
172
|
+
codeFilter3__(e.result, sut, statements, rel, every)
|
|
173
|
+
})\n${printN(l)})`
|
|
170
174
|
} else {
|
|
171
|
-
s += `(\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements)}\n${printN(l)})`
|
|
175
|
+
s += `(\n${printN(l + 1)}${codeFilter3__(e.result, sut, statements, null, every)}\n${printN(l)})`
|
|
172
176
|
}
|
|
173
177
|
// ;--l
|
|
174
178
|
break
|
|
@@ -181,7 +185,7 @@ const codeFilter3__ = <E>(
|
|
|
181
185
|
export const codeFilter3_ = <E>(state: readonly FilterResult[], sut: E): boolean => {
|
|
182
186
|
const statements: any[] = [] // must be defined here to be used by eval.
|
|
183
187
|
// always put everything inside a root scope.
|
|
184
|
-
const s = codeFilter3__([{ t: "where-scope", result: state }], sut, statements)
|
|
188
|
+
const s = codeFilter3__([{ t: "where-scope", result: state, relation: "some" }], sut, statements, null, false)
|
|
185
189
|
return eval(s)
|
|
186
190
|
}
|
|
187
191
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rawQuery.test.d.ts","sourceRoot":"","sources":["../rawQuery.test.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"rawQuery.test.d.ts","sourceRoot":"","sources":["../rawQuery.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAwD,cAAc,EAAuB,MAAM,YAAY,CAAA;AACtH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAO5C,eAAO,MAAM,EAAE,iDAUb,CAAA"}
|
package/test/rawQuery.test.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from "@effect/vitest"
|
|
2
|
-
import { Array, Config, Effect, Layer, Logger, LogLevel, ManagedRuntime, Option, Redacted, S } from "effect-app"
|
|
2
|
+
import { Array, Config, Effect, flow, Layer, Logger, LogLevel, ManagedRuntime, Option, Redacted, S } from "effect-app"
|
|
3
3
|
import { LogLevels } from "effect-app/utils"
|
|
4
4
|
import { setupRequestContextFromCurrent } from "../src/api/setupRequest.js"
|
|
5
|
-
import { and, or, project, where } from "../src/Model/query.js"
|
|
5
|
+
import { and, or, project, where, whereEvery, whereSome } from "../src/Model/query.js"
|
|
6
6
|
import { makeRepo } from "../src/Model/Repository/makeRepo.js"
|
|
7
7
|
import { CosmosStoreLayer } from "../src/Store/Cosmos.js"
|
|
8
8
|
import { MemoryStoreLive } from "../src/Store/Memory.js"
|
|
@@ -146,6 +146,35 @@ describe("select first-level array fields", () => {
|
|
|
146
146
|
.pipe(Effect.provide(SomethingRepo.Test), rt.runPromise))
|
|
147
147
|
})
|
|
148
148
|
|
|
149
|
+
const projected = S.Struct({ name: S.String, items: S.Array(S.Struct({ id: S.String, value: S.Number })) })
|
|
150
|
+
|
|
151
|
+
const expected = [
|
|
152
|
+
{
|
|
153
|
+
name: "Item 2",
|
|
154
|
+
items: [
|
|
155
|
+
{ id: "2-1", value: 30 },
|
|
156
|
+
{ id: "2-2", value: 40 }
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
const both = [
|
|
162
|
+
{
|
|
163
|
+
name: "Item 1",
|
|
164
|
+
items: [
|
|
165
|
+
{ id: "1-1", value: 10 },
|
|
166
|
+
{ id: "1-2", value: 20 }
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: "Item 2",
|
|
171
|
+
items: [
|
|
172
|
+
{ id: "2-1", value: 30 },
|
|
173
|
+
{ id: "2-2", value: 40 }
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
]
|
|
177
|
+
|
|
149
178
|
// NOTE: right now we cannot specify if all/"every" items must match the filter, or if at least one item (any/"some") must match the filter.
|
|
150
179
|
// the current implementation is any/some, so we can always filter down in the code to narrow further..
|
|
151
180
|
describe("filter first-level array fields as groups", () => {
|
|
@@ -153,8 +182,6 @@ describe("filter first-level array fields as groups", () => {
|
|
|
153
182
|
.gen(function*() {
|
|
154
183
|
const repo = yield* SomethingRepo
|
|
155
184
|
|
|
156
|
-
const projected = S.Struct({ name: S.String, items: S.Array(S.Struct({ id: S.String, value: S.Number })) })
|
|
157
|
-
|
|
158
185
|
// ok crazy lol, "value" is a reserved word in CosmosDB, so we have to use t["value"] as a field name instead of t.value
|
|
159
186
|
// deprecated; joins should be avoided because they're very expensive, and require DISTINCT to avoid duplicates
|
|
160
187
|
// which might affect results in unexpected ways?
|
|
@@ -200,73 +227,104 @@ describe("filter first-level array fields as groups", () => {
|
|
|
200
227
|
)
|
|
201
228
|
})
|
|
202
229
|
|
|
230
|
+
expect(items).toStrictEqual(expected)
|
|
231
|
+
expect(itemsExists).toStrictEqual(expected)
|
|
232
|
+
})
|
|
233
|
+
.pipe(setupRequestContextFromCurrent())
|
|
234
|
+
|
|
235
|
+
it("works well in CosmosDB", () =>
|
|
236
|
+
test
|
|
237
|
+
.pipe(Effect.provide(SomethingRepo.TestCosmos), rt.runPromise))
|
|
238
|
+
|
|
239
|
+
it("works well in Memory", () =>
|
|
240
|
+
test
|
|
241
|
+
.pipe(Effect.provide(SomethingRepo.Test), rt.runPromise))
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
describe("1", () => {
|
|
245
|
+
const test = Effect
|
|
246
|
+
.gen(function*() {
|
|
247
|
+
const repo = yield* SomethingRepo
|
|
203
248
|
const items2 = yield* repo.query(
|
|
204
|
-
|
|
205
|
-
|
|
249
|
+
whereSome(
|
|
250
|
+
"items",
|
|
251
|
+
flow(
|
|
252
|
+
where("value", "gt", 20),
|
|
253
|
+
and("description", "contains", "d item")
|
|
254
|
+
)
|
|
255
|
+
),
|
|
206
256
|
project(projected)
|
|
207
257
|
)
|
|
258
|
+
expect(items2).toStrictEqual(expected)
|
|
208
259
|
|
|
209
260
|
const items2Or = yield* repo.query(
|
|
210
|
-
|
|
211
|
-
|
|
261
|
+
whereSome(
|
|
262
|
+
"items",
|
|
263
|
+
flow(
|
|
264
|
+
where("value", "gt", 20),
|
|
265
|
+
or("description", "contains", "d item")
|
|
266
|
+
)
|
|
267
|
+
),
|
|
212
268
|
project(projected)
|
|
213
269
|
)
|
|
214
270
|
|
|
271
|
+
expect(items2Or).toStrictEqual(both)
|
|
215
272
|
// mixing relation check with scoped relationcheck
|
|
216
273
|
const items3 = yield* repo.query(
|
|
217
|
-
|
|
218
|
-
|
|
274
|
+
whereSome(
|
|
275
|
+
"items",
|
|
276
|
+
flow(where("value", "gt", 20), and(where("description", "contains", "d item")))
|
|
277
|
+
),
|
|
219
278
|
project(projected)
|
|
220
279
|
)
|
|
221
280
|
|
|
281
|
+
expect(items3).toStrictEqual(expected)
|
|
222
282
|
const items3Or = yield* repo.query(
|
|
223
|
-
|
|
224
|
-
|
|
283
|
+
whereSome(
|
|
284
|
+
"items",
|
|
285
|
+
flow(
|
|
286
|
+
where("value", "gt", 20),
|
|
287
|
+
or(where("description", "contains", "d item"))
|
|
288
|
+
)
|
|
289
|
+
),
|
|
225
290
|
project(projected)
|
|
226
291
|
)
|
|
227
292
|
|
|
228
|
-
|
|
229
|
-
// need to use DISTINCT..
|
|
230
|
-
// https://stackoverflow.com/questions/51855660/cosmos-db-joins-give-duplicate-results
|
|
293
|
+
expect(items3Or).toStrictEqual(both)
|
|
231
294
|
const items4 = yield* repo.query(
|
|
232
|
-
where("
|
|
295
|
+
whereSome("items", where("value", "gt", 10)),
|
|
233
296
|
project(projected)
|
|
234
297
|
)
|
|
235
298
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
items: [
|
|
240
|
-
{ id: "2-1", value: 30 },
|
|
241
|
-
{ id: "2-2", value: 40 }
|
|
242
|
-
]
|
|
243
|
-
}
|
|
244
|
-
]
|
|
299
|
+
expect(items4).toStrictEqual(both)
|
|
300
|
+
})
|
|
301
|
+
.pipe(setupRequestContextFromCurrent())
|
|
245
302
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
items: [
|
|
250
|
-
{ id: "1-1", value: 10 },
|
|
251
|
-
{ id: "1-2", value: 20 }
|
|
252
|
-
]
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
name: "Item 2",
|
|
256
|
-
items: [
|
|
257
|
-
{ id: "2-1", value: 30 },
|
|
258
|
-
{ id: "2-2", value: 40 }
|
|
259
|
-
]
|
|
260
|
-
}
|
|
261
|
-
]
|
|
303
|
+
it("works well in CosmosDB", () =>
|
|
304
|
+
test
|
|
305
|
+
.pipe(Effect.provide(SomethingRepo.TestCosmos), rt.runPromise))
|
|
262
306
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
307
|
+
it("works well in Memory", () =>
|
|
308
|
+
test
|
|
309
|
+
.pipe(Effect.provide(SomethingRepo.Test), rt.runPromise))
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
describe("multi-level", () => {
|
|
313
|
+
const test = Effect
|
|
314
|
+
.gen(function*() {
|
|
315
|
+
const repo = yield* SomethingRepo
|
|
316
|
+
const itemsCheckWithEvery = yield* repo.query(
|
|
317
|
+
whereEvery(
|
|
318
|
+
"items",
|
|
319
|
+
flow(
|
|
320
|
+
where("value", "gt", 20),
|
|
321
|
+
and("description", "contains", "d item")
|
|
322
|
+
)
|
|
323
|
+
),
|
|
324
|
+
project(projected)
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
expect(itemsCheckWithEvery).toStrictEqual([])
|
|
270
328
|
})
|
|
271
329
|
.pipe(setupRequestContextFromCurrent())
|
|
272
330
|
|