@effect-app/infra 0.210.11 → 0.211.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/_cjs/services/RepositoryBase.cjs +2 -23
  3. package/_cjs/services/RepositoryBase.cjs.map +1 -1
  4. package/_cjs/services/Store/Cosmos/query.cjs +0 -137
  5. package/_cjs/services/Store/Cosmos/query.cjs.map +1 -1
  6. package/_cjs/services/Store/Cosmos.cjs +5 -35
  7. package/_cjs/services/Store/Cosmos.cjs.map +1 -1
  8. package/_cjs/services/Store/Disk.cjs +0 -1
  9. package/_cjs/services/Store/Disk.cjs.map +1 -1
  10. package/_cjs/services/Store/Memory.cjs +0 -6
  11. package/_cjs/services/Store/Memory.cjs.map +1 -1
  12. package/_cjs/services/Store/service.cjs.map +1 -1
  13. package/_cjs/services/Store/utils.cjs +1 -106
  14. package/_cjs/services/Store/utils.cjs.map +1 -1
  15. package/dist/api/routing/match.d.ts +1 -1
  16. package/dist/api/setupRequest.d.ts +1 -1
  17. package/dist/services/QueueMaker/memQueue.d.ts +1 -1
  18. package/dist/services/QueueMaker/sbqueue.d.ts +1 -1
  19. package/dist/services/RepositoryBase.d.ts +3 -60
  20. package/dist/services/RepositoryBase.d.ts.map +1 -1
  21. package/dist/services/RepositoryBase.js +3 -23
  22. package/dist/services/Store/Cosmos/query.d.ts +1 -45
  23. package/dist/services/Store/Cosmos/query.d.ts.map +1 -1
  24. package/dist/services/Store/Cosmos/query.js +1 -145
  25. package/dist/services/Store/Cosmos.d.ts.map +1 -1
  26. package/dist/services/Store/Cosmos.js +18 -61
  27. package/dist/services/Store/Disk.d.ts.map +1 -1
  28. package/dist/services/Store/Disk.js +1 -2
  29. package/dist/services/Store/Memory.d.ts.map +1 -1
  30. package/dist/services/Store/Memory.js +2 -10
  31. package/dist/services/Store/filterApi/query.d.ts +1 -1
  32. package/dist/services/Store/filterApi/query.d.ts.map +1 -1
  33. package/dist/services/Store/service.d.ts +1 -38
  34. package/dist/services/Store/service.d.ts.map +1 -1
  35. package/dist/services/Store/service.js +1 -1
  36. package/dist/services/Store/utils.d.ts +1 -6
  37. package/dist/services/Store/utils.d.ts.map +1 -1
  38. package/dist/services/Store/utils.js +3 -140
  39. package/dist/services/query/dsl.d.ts +2 -2
  40. package/dist/services/query/dsl.d.ts.map +1 -1
  41. package/package.json +2 -12
  42. package/src/services/RepositoryBase.ts +3 -35
  43. package/src/services/Store/Cosmos/query.ts +1 -203
  44. package/src/services/Store/Cosmos.ts +38 -135
  45. package/src/services/Store/Disk.ts +0 -1
  46. package/src/services/Store/Memory.ts +2 -17
  47. package/src/services/Store/Redis.ts.bak +2 -4
  48. package/src/services/Store/filterApi/query.ts +2 -2
  49. package/src/services/Store/service.ts +1 -35
  50. package/src/services/Store/utils.ts +3 -152
  51. package/src/services/query/dsl.ts +4 -4
  52. package/_cjs/filter.cjs +0 -363
  53. package/_cjs/filter.cjs.map +0 -1
  54. package/_cjs/services/Store/Cosmos.test.cjs +0 -55
  55. package/_cjs/services/Store/Cosmos.test.cjs.map +0 -1
  56. package/_cjs/services/Store/codeFilter.test.cjs +0 -63
  57. package/_cjs/services/Store/codeFilter.test.cjs.map +0 -1
  58. package/dist/filter.d.ts +0 -142
  59. package/dist/filter.d.ts.map +0 -1
  60. package/dist/filter.js +0 -248
  61. package/dist/services/Store/Cosmos.test.d.ts.map +0 -1
  62. package/dist/services/Store/codeFilter.test.d.ts.map +0 -1
  63. package/src/filter.ts +0 -420
  64. package/src/services/Store/Cosmos.test.ts +0 -94
  65. package/src/services/Store/codeFilter.test.ts +0 -166
@@ -4,24 +4,11 @@ import { toNonEmptyArray } from "@effect-app/core/Array"
4
4
  import { CosmosClient, CosmosClientLayer } from "@effect-app/infra-adapters/cosmos-client"
5
5
  import { Chunk, Duration, Effect, Layer, Option, ReadonlyArray, Secret } from "effect-app"
6
6
  import type { NonEmptyReadonlyArray } from "effect-app"
7
- import { dropUndefinedT, omit, pick, spread } from "effect-app/utils"
7
+ import { dropUndefinedT, omit, pick } from "effect-app/utils"
8
8
  import { OptimisticConcurrencyException } from "../../errors.js"
9
- import {
10
- buildCosmosQuery,
11
- buildFilterJoinSelectCosmosQuery,
12
- buildFindJoinCosmosQuery,
13
- buildWhereCosmosQuery3,
14
- logQuery
15
- } from "./Cosmos/query.js"
9
+ import { buildWhereCosmosQuery3, logQuery } from "./Cosmos/query.js"
16
10
  import { StoreMaker } from "./service.js"
17
- import type {
18
- FilterArgs,
19
- FilterJoinSelect,
20
- PersistenceModelType,
21
- StorageConfig,
22
- Store,
23
- StoreConfig
24
- } from "./service.js"
11
+ import type { FilterArgs, PersistenceModelType, StorageConfig, Store, StoreConfig } from "./service.js"
25
12
 
26
13
  class CosmosDbOperationError {
27
14
  constructor(readonly message: string) {}
@@ -213,15 +200,14 @@ function makeCosmosStore({ prefix }: StorageConfig) {
213
200
  parameters: [{ name: "@id", value: importedMarkerId }]
214
201
  }))
215
202
  .pipe(
216
- Effect
217
- .tap((q) => logQuery(q)),
203
+ Effect.tap((q) => logQuery(q)),
218
204
  Effect.flatMap((q) =>
219
205
  Effect.promise(() =>
220
206
  container
221
207
  .items
222
208
  .query<PM>(q)
223
209
  .fetchAll()
224
- .then(({ resources }) => resources)
210
+ .then(({ resources }) => resources.map((_) => ({ ...defaultValues, ..._ })))
225
211
  )
226
212
  ),
227
213
  Effect
@@ -229,48 +215,6 @@ function makeCosmosStore({ prefix }: StorageConfig) {
229
215
  attributes: { "repository.container_id": containerId, "repository.model_name": name }
230
216
  })
231
217
  ),
232
- filterJoinSelect: <T extends object>(
233
- filter: FilterJoinSelect,
234
- cursor?: { skip?: number; limit?: number }
235
- ) =>
236
- Effect
237
- .forEach(
238
- filter
239
- .keys,
240
- (k) =>
241
- Effect
242
- .sync(() => buildFilterJoinSelectCosmosQuery(filter, k, name, cursor?.skip, cursor?.limit))
243
- .pipe(
244
- Effect
245
- .tap((q) => logQuery(q)),
246
- Effect.flatMap((q) =>
247
- Effect.promise(() =>
248
- container
249
- .items
250
- .query<T>(q)
251
- .fetchAll()
252
- .then(({ resources }) => resources.map((_) => ({ ...defaultValues, ..._ })))
253
- )
254
- )
255
- )
256
- )
257
- .pipe(
258
- Effect.map((a) => {
259
- const v = a
260
- .flatMap((_) => _)
261
- .map((x) =>
262
- spread(
263
- x,
264
- ({ r, ...rest }: any) => ({ ...rest, ...r } as T & { _rootId: string })
265
- )
266
- )
267
- return v
268
- }),
269
- Effect
270
- .withSpan("Cosmos.filterJoinSelect [effect-app/infra/Store]", {
271
- attributes: { "repository.container_id": containerId, "repository.model_name": name }
272
- })
273
- ),
274
218
  /**
275
219
  * May return duplicate results for "join_find", when matching more than once.
276
220
  */
@@ -281,82 +225,40 @@ function makeCosmosStore({ prefix }: StorageConfig) {
281
225
  const limit = f?.limit
282
226
  const filter = f.filter ?? { type: "new-kid", build: () => [] }
283
227
  type M = U extends undefined ? PM : Pick<PM, U>
284
- return (filter.type === "join_find"
285
- // This is a problem if one of the multiple joined arrays can be empty!
286
- // https://stackoverflow.com/questions/60320780/azure-cosmosdb-sql-join-not-returning-results-when-the-child-contains-empty-arra
287
- // so we use multiple queries instead.
288
- ? Effect
289
- .forEach(
290
- filter
291
- .keys,
292
- (k) =>
293
- Effect
294
- .sync(() => buildFindJoinCosmosQuery(filter, k, name, skip, limit))
295
- .pipe(
296
- Effect.tap((q) => logQuery(q)),
297
- Effect
298
- .flatMap((q) =>
299
- Effect.promise(() =>
300
- container
301
- .items
302
- .query<M>(q)
303
- .fetchAll()
304
- .then(({ resources }) => resources.map((_) => ({ ...defaultValues, ..._ })))
305
- )
306
- )
307
- )
228
+ return Effect
229
+ .sync(() =>
230
+ buildWhereCosmosQuery3(
231
+ filter.build(),
232
+ name,
233
+ importedMarkerId,
234
+ defaultValues,
235
+ f.select as NonEmptyReadonlyArray<string> | undefined,
236
+ f.order as NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }> | undefined,
237
+ skip,
238
+ limit
308
239
  )
309
- .pipe(Effect.map((_) => _.flatMap((_) => _)))
310
- : (filter.type === "new-kid"
311
- ? Effect
312
- .sync(() =>
313
- buildWhereCosmosQuery3(
314
- filter.build(),
315
- name,
316
- importedMarkerId,
317
- defaultValues,
318
- f.select as NonEmptyReadonlyArray<string> | undefined,
319
- f.order as NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }> | undefined,
320
- skip,
321
- limit
240
+ )
241
+ .pipe(
242
+ Effect.tap((q) => logQuery(q)),
243
+ Effect
244
+ .flatMap((q) =>
245
+ Effect.promise(() =>
246
+ f.select
247
+ ? container
248
+ .items
249
+ .query<M>(q)
250
+ .fetchAll()
251
+ .then(({ resources }) =>
252
+ resources.map((_) => ({ ...pick(defaultValues, f.select!), ..._ }))
253
+ )
254
+ : container
255
+ .items
256
+ .query<{ f: M }>(q)
257
+ .fetchAll()
258
+ .then(({ resources }) => resources.map((_) => ({ ...defaultValues, ..._.f })))
322
259
  )
323
260
  )
324
- .pipe(
325
- Effect.tap((q) => logQuery(q)),
326
- Effect
327
- .flatMap((q) =>
328
- Effect.promise(() =>
329
- f.select
330
- ? container
331
- .items
332
- .query<M>(q)
333
- .fetchAll()
334
- .then(({ resources }) =>
335
- resources.map((_) => ({ ...pick(defaultValues, f.select!), ..._ }))
336
- )
337
- : container
338
- .items
339
- .query<{ f: M }>(q)
340
- .fetchAll()
341
- .then(({ resources }) => resources.map((_) => ({ ...defaultValues, ..._.f })))
342
- )
343
- )
344
- )
345
- : Effect
346
- .sync(() => buildCosmosQuery(filter, name, importedMarkerId, defaultValues, skip, limit))
347
- .pipe(
348
- Effect.tap((q) => logQuery(q)),
349
- Effect
350
- .flatMap((q) =>
351
- Effect.promise(() =>
352
- container
353
- .items
354
- .query<{ f: M }>(q)
355
- .fetchAll()
356
- .then(({ resources }) => resources.map((_) => ({ ...defaultValues, ..._.f })))
357
- )
358
- )
359
- )))
261
+ )
360
262
  .pipe(Effect.withSpan("Cosmos.filter [effect-app/infra/Store]", {
361
263
  attributes: { "repository.container_id": containerId, "repository.model_name": name }
362
264
  }))
@@ -468,7 +370,8 @@ function makeCosmosStore({ prefix }: StorageConfig) {
468
370
  Effect.promise(() =>
469
371
  container.items.create({
470
372
  _partitionKey: importedMarkerId,
471
- id: importedMarkerId
373
+ id: importedMarkerId,
374
+ ttl: -1
472
375
  })
473
376
  )
474
377
  )
@@ -150,7 +150,6 @@ export function makeDiskStore({ prefix }: StorageConfig, dir: string) {
150
150
  all: Effect.flatMap(getStore, (_) => _.all),
151
151
  find: (...args) => Effect.flatMap(getStore, (_) => _.find(...args)),
152
152
  filter: (...args) => Effect.flatMap(getStore, (_) => _.filter(...args)),
153
- filterJoinSelect: (...args) => Effect.flatMap(getStore, (_) => _.filterJoinSelect(...args)),
154
153
  set: (...args) => Effect.flatMap(getStore, (_) => _.set(...args)),
155
154
  batchSet: (...args) => Effect.flatMap(getStore, (_) => _.batchSet(...args)),
156
155
  bulkSet: (...args) => Effect.flatMap(getStore, (_) => _.bulkSet(...args)),
@@ -4,9 +4,9 @@ import { Effect, FiberRef, flow, Option, Order, pipe, ReadonlyArray, Ref } from
4
4
  import type { NonEmptyArray, NonEmptyReadonlyArray } from "effect-app"
5
5
  import { get, pick } from "effect-app/utils"
6
6
  import type { RequestContext } from "../../RequestContext.js"
7
- import type { FilterArgs, FilterJoinSelect, PersistenceModelType, Store, StoreConfig } from "./service.js"
7
+ import type { FilterArgs, PersistenceModelType, Store, StoreConfig } from "./service.js"
8
8
  import { StoreMaker } from "./service.js"
9
- import { codeFilter, codeFilterJoinSelect, makeUpdateETag } from "./utils.js"
9
+ import { codeFilter, makeUpdateETag } from "./utils.js"
10
10
 
11
11
  export function memFilter<T extends PersistenceModelType<string>, U extends keyof T = never>(f: FilterArgs<T, U>) {
12
12
  type M = U extends undefined ? T : Pick<T, U>
@@ -149,20 +149,6 @@ export function makeMemoryStoreInt<Id extends string, PM extends PersistenceMode
149
149
  attributes: { "repository.model_name": modelName, "repository.namespace": namespace }
150
150
  })
151
151
  ),
152
- filterJoinSelect: <T extends object>(filter: FilterJoinSelect) =>
153
- all
154
- .pipe(
155
- Effect.map((c) => c.flatMap(codeFilterJoinSelect<PM, T>(filter))),
156
- Effect
157
- .withSpan(
158
- "Memory.filterJoinSelect [effect-app/infra/Store]",
159
- {
160
- attributes: {
161
- modelName
162
- }
163
- }
164
- )
165
- ),
166
152
  set: (e) =>
167
153
  s
168
154
  .find(e.id)
@@ -257,7 +243,6 @@ export const makeMemoryStore = () => ({
257
243
  all: Effect.flatMap(getStore, (_) => _.all),
258
244
  find: (...args) => Effect.flatMap(getStore, (_) => _.find(...args)),
259
245
  filter: (...args) => Effect.flatMap(getStore, (_) => _.filter(...args)),
260
- filterJoinSelect: (...args) => Effect.flatMap(getStore, (_) => _.filterJoinSelect(...args)),
261
246
  set: (...args) => Effect.flatMap(getStore, (_) => _.set(...args)),
262
247
  batchSet: (...args) => Effect.flatMap(getStore, (_) => _.batchSet(...args)),
263
248
  bulkSet: (...args) => Effect.flatMap(getStore, (_) => _.bulkSet(...args)),
@@ -4,9 +4,9 @@ import { Effect, Layer, Option, ReadonlyArray, Secret } from "effect-app"
4
4
  import type { NonEmptyArray, NonEmptyReadonlyArray } from "effect-app"
5
5
  import { NotFoundError } from "../../errors.js"
6
6
  import { memFilter } from "./Memory.js"
7
- import type { FilterJoinSelect, PersistenceModelType, StorageConfig, Store, StoreConfig } from "./service.js"
7
+ import type { PersistenceModelType, StorageConfig, Store, StoreConfig } from "./service.js"
8
8
  import { StoreMaker } from "./service.js"
9
- import { codeFilterJoinSelect, makeETag, makeUpdateETag } from "./utils.js"
9
+ import { makeETag, makeUpdateETag } from "./utils.js"
10
10
 
11
11
  function makeRedisStore({ prefix }: StorageConfig) {
12
12
  return Effect.gen(function*($) {
@@ -61,8 +61,6 @@ function makeRedisStore({ prefix }: StorageConfig) {
61
61
  const s: Store<PM, Id> = {
62
62
  all,
63
63
  filter: (f) => all.map(memFilter(f)),
64
- filterJoinSelect: <T extends object>(filter: FilterJoinSelect) =>
65
- all.map((c) => c.flatMap(codeFilterJoinSelect<PM, T>(filter))),
66
64
  find: (id) => asMap.map((_) => Option.fromNullable(_.get(id))),
67
65
  set: (e) =>
68
66
  s
@@ -210,11 +210,11 @@ export type Filts<TFieldValues extends FieldValues> = {
210
210
  ): QueryBuilder<TFieldValues>
211
211
  <
212
212
  TFieldName extends FieldPath<TFieldValues>,
213
- V extends FieldPathValue<TFieldValues, TFieldName>
213
+ V extends string
214
214
  >(
215
215
  path: TFieldName,
216
216
  op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith",
217
- value: V // only strings?
217
+ value: V
218
218
  ): QueryBuilder<TFieldValues>
219
219
  <
220
220
  TFieldName extends FieldPath<TFieldValues>,
@@ -34,37 +34,7 @@ export type Where =
34
34
  value: readonly (SupportedValues)[]
35
35
  }
36
36
 
37
- // default is where
38
- export type StoreWhereFilter = {
39
- type?: "where" | undefined
40
- mode?: "and" | "or" | undefined // default is and
41
- where: readonly [
42
- Where,
43
- ...(Where[])
44
- ]
45
- }
46
- export type LegacyFilter<E> =
47
- | { by: keyof E; type: "startsWith"; value: any }
48
- | { by: keyof E; type: "endsWith"; value: any }
49
- | { by: keyof E; type: "contains"; value: any }
50
- export type JoinFindFilter = {
51
- type: "join_find"
52
- keys: readonly string[] /* value paths of E */
53
- valueKey: string /* value paths of E[keys][valueKey] */
54
- value: any /* value path[valueKey] of E */
55
- }
56
- export type Filter<E extends FieldValues> =
57
- | JoinFindFilter
58
- | StoreWhereFilter
59
- | LegacyFilter<E>
60
- | QueryBuilder<E>
61
-
62
- export type FilterJoinSelect = {
63
- type: "filter_join_select"
64
- keys: readonly string[] /* value paths of E */
65
- valueKey: string /* value paths of E[keys][valueKey] */
66
- value: any /* value path[valueKey] of E */
67
- }
37
+ export type Filter<E extends FieldValues> = QueryBuilder<E>
68
38
 
69
39
  export interface O<PM extends PersistenceModelType<unknown>> {
70
40
  key: keyof PM
@@ -86,10 +56,6 @@ export type FilterFunc<PM extends PersistenceModelType<unknown>> = <U extends ke
86
56
  export interface Store<PM extends PersistenceModelType<Id>, Id> {
87
57
  all: Effect<PM[]>
88
58
  filter: FilterFunc<PM>
89
- /** @deprecated */
90
- filterJoinSelect: <T extends object>(
91
- filter: FilterJoinSelect
92
- ) => Effect<(T & { _rootId: string })[]>
93
59
  find: (id: Id) => Effect<Option<PM>>
94
60
  set: (e: PM) => Effect<PM, OptimisticConcurrencyException>
95
61
  batchSet: (
@@ -1,9 +1,8 @@
1
- import { Effect, Option, ReadonlyArray } from "effect-app"
2
- import { get } from "effect-app/utils"
1
+ import { Effect, Option } from "effect-app"
3
2
  import objectHash from "object-hash"
4
3
  import { OptimisticConcurrencyException } from "../../errors.js"
5
4
  import { codeFilter3_ } from "./codeFilter.js"
6
- import type { Filter, FilterJoinSelect, PersistenceModelType, SupportedValues2 } from "./service.js"
5
+ import type { Filter, PersistenceModelType, SupportedValues2 } from "./service.js"
7
6
 
8
7
  export const makeETag = <E extends PersistenceModelType<Id>, Id extends string>(
9
8
  { _etag, ...e }: E
@@ -37,155 +36,7 @@ export const makeUpdateETag =
37
36
  })
38
37
 
39
38
  export function codeFilter<E extends { id: string }, NE extends E>(filter: Filter<NE>) {
40
- return (x: E) =>
41
- filter.type === "new-kid"
42
- ? codeFilter3_(filter.build(), x) ? Option.some(x as unknown as NE) : Option.none()
43
- : filter.type === "startsWith"
44
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
- ? lowercaseIfString((x as any)[filter.by]).startsWith(filter.value.toLowerCase())
46
- ? Option.some(x as unknown as NE)
47
- : Option.none()
48
- : filter.type === "endsWith"
49
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
- ? lowercaseIfString((x as any)[filter.by]).endsWith(filter.value.toLowerCase())
51
- ? Option.some(x as unknown as NE)
52
- : Option.none()
53
- : filter.type === "contains"
54
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
56
- ? lowercaseIfString((x as any)[filter.by]).includes(filter.value.toLowerCase())
57
- ? Option.some(x as unknown as NE)
58
- : Option.none()
59
- : filter.type === "join_find"
60
- ? filter.keys.some((k) => {
61
- const value = get(x, k) as Record<string, unknown>[]
62
- // we mimic the behavior of cosmosdb; if the shape in db does not match what we're looking for, we imagine false hit
63
- return (
64
- value
65
- && value.some((v) => compare(v[filter.valueKey], filter.value))
66
- )
67
- })
68
- ? Option.some(x as unknown as NE)
69
- : Option.none()
70
- // TODO: support mixed or/and
71
- : filter.mode === "or"
72
- ? filter
73
- .where
74
- .some((p) => {
75
- const k = get(x, p.key)
76
- switch (p.t) {
77
- case "in":
78
- return p.value.includes(k)
79
- case "not-in":
80
- return !p.value.includes(k)
81
- case "lt":
82
- return lowerThan(k, p.value)
83
- case "lte":
84
- return lowerThanExclusive(k, p.value)
85
- case "gt":
86
- return greaterThan(k, p.value)
87
- case "gte":
88
- return greaterThanExclusive(k, p.value)
89
- case "includes":
90
- return (k as Array<string>).includes(p.value)
91
- case "not-includes":
92
- return !(k as Array<string>).includes(p.value)
93
- case "contains":
94
- return (k as string).toLowerCase().includes(p.value.toLowerCase())
95
- case "ends-with":
96
- return (k as string).toLowerCase().endsWith(p.value.toLowerCase())
97
- case "starts-with":
98
- return (k as string).toLowerCase().startsWith(p.value.toLowerCase())
99
- case "not-contains":
100
- return !(k as string).toLowerCase().includes(p.value.toLowerCase())
101
- case "not-ends-with":
102
- return !(k as string).toLowerCase().endsWith(p.value.toLowerCase())
103
- case "not-starts-with":
104
- return !(k as string).toLowerCase().startsWith(p.value.toLowerCase())
105
- case "not-eq":
106
- return !compare(k, p.value)
107
- case "eq":
108
- case undefined:
109
- return compare(k, p.value)
110
- }
111
- })
112
- ? Option.some(x as unknown as NE)
113
- : Option.none()
114
- : filter
115
- .where
116
- .every((p) => {
117
- const k = get(x, p.key)
118
- switch (p.t) {
119
- case "in":
120
- return p.value.includes(k)
121
- case "not-in":
122
- return !p.value.includes(k)
123
- case "lt":
124
- return lowerThan(k, p.value)
125
- case "lte":
126
- return lowerThanExclusive(k, p.value)
127
- case "gt":
128
- return greaterThan(k, p.value)
129
- case "gte":
130
- return greaterThanExclusive(k, p.value)
131
- case "includes":
132
- return (k as Array<string>).includes(p.value)
133
- case "not-includes":
134
- return !(k as Array<string>).includes(p.value)
135
- case "contains":
136
- return (k as string).toLowerCase().includes(p.value.toLowerCase())
137
- case "ends-with":
138
- return (k as string).toLowerCase().endsWith(p.value.toLowerCase())
139
- case "starts-with":
140
- return (k as string).toLowerCase().startsWith(p.value.toLowerCase())
141
- case "not-contains":
142
- return !(k as string).toLowerCase().includes(p.value.toLowerCase())
143
- case "not-ends-with":
144
- return !(k as string).toLowerCase().endsWith(p.value.toLowerCase())
145
- case "not-starts-with":
146
- return !(k as string).toLowerCase().startsWith(p.value.toLowerCase())
147
- case "not-eq":
148
- return p.key.includes(".-1.")
149
- ? (get(x, p.key.split(".-1.")[0]) as any[])
150
- // TODO: or vs and
151
- .every((_) => !compare(get(_, p.key.split(".-1.")[1]!), p.value))
152
- : !compare(k, p.value)
153
- case "eq":
154
- case undefined:
155
- return p.key.includes(".-1.")
156
- ? (get(x, p.key.split(".-1.")[0]) as any[])
157
- // TODO: or vs and
158
- .some((_) => compare(get(_, p.key.split(".-1.")[1]!), p.value))
159
- : compare(k, p.value)
160
- }
161
- })
162
- ? Option.some(x as unknown as NE)
163
- : Option.none()
164
- }
165
-
166
- export function codeFilterJoinSelect<E extends { id: string }, NE>(
167
- filter: FilterJoinSelect
168
- ) {
169
- return (x: E) =>
170
- ReadonlyArray
171
- .filterMap(
172
- filter
173
- .keys,
174
- (k) => {
175
- const value = get(x, k)
176
- // we mimic the behavior of cosmosdb; if the shape in db does not match what we're looking for, we imagine false hit
177
- return value
178
- ? Option.some(
179
- ReadonlyArray.filterMap(value as readonly NE[], (v) =>
180
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
181
- compare((v as any)[filter.valueKey], filter.value)
182
- ? Option.some({ ...v, _rootId: x.id })
183
- : Option.none())
184
- )
185
- : Option.none()
186
- }
187
- )
188
- .flatMap((_) => _)
39
+ return (x: E) => codeFilter3_(filter.build(), x) ? Option.some(x as unknown as NE) : Option.none()
189
40
  }
190
41
 
191
42
  export function lowercaseIfString<T>(val: T) {
@@ -251,11 +251,11 @@ export type FilterWheres = {
251
251
  <
252
252
  TFieldValues extends FieldValues,
253
253
  TFieldName extends FieldPath<TFieldValues>,
254
- V extends FieldPathValue<TFieldValues, TFieldName>
254
+ V extends string
255
255
  >(
256
256
  path: TFieldName,
257
257
  op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith",
258
- value: V // only strings?
258
+ value: V
259
259
  ): (
260
260
  current: Query<TFieldValues>
261
261
  ) => QueryWhere<TFieldValues>
@@ -322,11 +322,11 @@ export type FilterContinuations = {
322
322
  <
323
323
  TFieldValues extends FieldValues,
324
324
  TFieldName extends FieldPath<TFieldValues>,
325
- V extends FieldPathValue<TFieldValues, TFieldName>
325
+ V extends string
326
326
  >(
327
327
  path: TFieldName,
328
328
  op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith",
329
- value: V // only strings?
329
+ value: V
330
330
  ): (
331
331
  current: QueryWhere<TFieldValues>
332
332
  ) => QueryWhere<TFieldValues>