@effect-app/infra 0.196.3 → 0.196.5

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.
@@ -17,7 +17,7 @@ export interface RecordCache extends ReturnType<typeof makeLiveRecordCache> {
17
17
  }
18
18
  export declare const RecordCache: import("effect/Context").Tag<RecordCache, RecordCache>;
19
19
  export declare const LiveRecordCache: import("effect/Layer").Layer<RecordCache, never, never>;
20
- export declare function find<R, RDecode, EDecode, E, EA, A>(tryRead: (id: string) => Effect<Option<CachedRecord<EA>>, E, R>, decode: (d: EA) => Effect<A, EDecode, RDecode>, type: string): (id: string) => import("effect/Effect").Effect<import("effect/Option").Option<A>, InvalidStateError | E, RecordCache | R | RDecode>;
20
+ export declare function find<R, RDecode, EDecode, E, EA, A>(tryRead: (id: string) => Effect<Option<CachedRecord<EA>>, E, R>, decode: (d: EA) => Effect<A, EDecode, RDecode>, type: string): (id: string) => import("effect/Effect").Effect<import("effect/Option").Option<A>, E | InvalidStateError, R | RDecode | RecordCache>;
21
21
  export declare function storeDirectly<R, E, TKey extends string, A extends DBRecord<TKey>>(save: (r: A, version: Option<Version>) => Effect<CachedRecord<A>, E, R>, type: string): (record: A) => import("effect/Effect").Effect<A, E, RecordCache | R>;
22
- export declare function store<R, E, R2, E2, TKey extends string, EA, A extends DBRecord<TKey>>(tryRead: (id: string) => Effect<Option<CachedRecord<EA>>, E, R>, save: (r: A, version: Option<Version>) => Effect<CachedRecord<A>, E, R>, lock: (id: string) => Effect<unknown, E2, R2 | Scope>, type: string): (record: A) => import("effect/Effect").Effect<A, OptimisticLockException | InvalidStateError | E | E2, RecordCache | R | Exclude<R2, import("effect/Scope").Scope>>;
22
+ export declare function store<R, E, R2, E2, TKey extends string, EA, A extends DBRecord<TKey>>(tryRead: (id: string) => Effect<Option<CachedRecord<EA>>, E, R>, save: (r: A, version: Option<Version>) => Effect<CachedRecord<A>, E, R>, lock: (id: string) => Effect<unknown, E2, R2 | Scope>, type: string): (record: A) => import("effect/Effect").Effect<A, E | E2 | InvalidStateError | OptimisticLockException, R | RecordCache | Exclude<R2, import("effect/Scope").Scope>>;
23
23
  //# sourceMappingURL=simpledb.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/infra",
3
- "version": "0.196.3",
3
+ "version": "0.196.5",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -18,10 +18,10 @@
18
18
  "proper-lockfile": "^4.1.2",
19
19
  "pure-rand": "6.0.4",
20
20
  "redlock": "^4.2.0",
21
- "@effect-app/infra-adapters": "0.133.2",
21
+ "@effect-app/infra-adapters": "0.133.3",
22
22
  "@effect-app/core": "0.146.1",
23
+ "effect-app": "0.173.3",
23
24
  "@effect-app/fluent-extensions": "0.139.0",
24
- "effect-app": "0.173.2",
25
25
  "@effect-app/schema": "0.197.1"
26
26
  },
27
27
  "devDependencies": {
@@ -696,6 +696,16 @@
696
696
  "default": "./_cjs/services/Store/utils.cjs"
697
697
  }
698
698
  },
699
+ "./services/query": {
700
+ "import": {
701
+ "types": "./dist/services/query.d.ts",
702
+ "default": "./dist/services/query.js"
703
+ },
704
+ "require": {
705
+ "types": "./dist/services/query.d.ts",
706
+ "default": "./_cjs/services/query.cjs"
707
+ }
708
+ },
699
709
  "./services/simpledb/cosmosdb": {
700
710
  "import": {
701
711
  "types": "./dist/services/simpledb/cosmosdb.d.ts",
@@ -23,6 +23,8 @@ import { makeFilters } from "@effect-app/infra/filter"
23
23
  import { Effect, S } from "effect-app"
24
24
  import { type FixEnv, runTerm } from "effect-app/Pure"
25
25
  import { type InvalidStateError, NotFoundError, type OptimisticConcurrencyException } from "../errors.js"
26
+ import type { FieldValues } from "../filter/types.js"
27
+ import { make as makeQuery, type QAll, type Query, query, type QueryProjection } from "./query.js"
26
28
  import { ContextMapContainer } from "./Store/ContextMapContainer.js"
27
29
  import * as Q from "./Store/filterApi/query.js"
28
30
 
@@ -88,6 +90,19 @@ export abstract class RepositoryBaseC<
88
90
  ) => Effect<void>
89
91
 
90
92
  abstract readonly mapped: Mapped<PM, Omit<PM, "_etag">>
93
+ abstract readonly q2: {
94
+ <A, R, From extends FieldValues>(
95
+ q: (initial: Query<Omit<PM, "_etag">>) => QueryProjection<Omit<PM, "_etag"> extends From ? From : never, A, R>
96
+ ): Effect.Effect<readonly A[], S.ParseResult.ParseError, R>
97
+ <R = never>(
98
+ q: (initial: Query<Omit<PM, "_etag">>) => QAll<Omit<PM, "_etag">, T, R>
99
+ ): Effect.Effect<readonly T[], never, R>
100
+
101
+ <A, R, From extends FieldValues>(
102
+ q: QueryProjection<Omit<PM, "_etag"> extends From ? From : never, A, R>
103
+ ): Effect.Effect<readonly A[], S.ParseResult.ParseError, R>
104
+ <R = never>(q: QAll<Omit<PM, "_etag">, T, R>): Effect.Effect<readonly T[], never, R>
105
+ }
91
106
  }
92
107
 
93
108
  export abstract class RepositoryBaseC1<
@@ -121,6 +136,7 @@ export class RepositoryBaseC2<
121
136
  this.utils = this.impl.utils
122
137
  this.changeFeed = this.impl.changeFeed
123
138
  this.mapped = this.impl.mapped
139
+ this.q2 = this.impl.q2
124
140
  }
125
141
  // makes super calls a compiler error, as it should
126
142
  override saveAndPublish
@@ -130,6 +146,7 @@ export class RepositoryBaseC2<
130
146
  override utils
131
147
  override changeFeed
132
148
  override mapped
149
+ override q2
133
150
  }
134
151
 
135
152
  const anyQb = Q.QueryBuilder.make<any>()
@@ -782,7 +799,8 @@ export function makeRepo<
782
799
  find,
783
800
  all,
784
801
  saveAndPublish,
785
- removeAndPublish
802
+ removeAndPublish,
803
+ q2: (q: any) => query(r, typeof q === "function" ? q(makeQuery()) : q) as any
786
804
  }
787
805
  return r
788
806
  })
@@ -970,26 +988,27 @@ export interface RepoFunctions<T extends { id: unknown }, PM extends { id: strin
970
988
  save: (...items: T[]) => Effect<void, InvalidStateError | OptimisticConcurrencyException, Service>
971
989
  get: (id: T["id"]) => Effect<T, NotFoundError<ItemType>, Service>
972
990
 
973
- query: (b: (fn: Q.FilterTest<PM>, fields: Q.Filter<PM, never>) => Q.QueryBuilder<PM>) => Effect<T[], never, never>
991
+ query: (b: (fn: Q.FilterTest<PM>, fields: Q.Filter<PM, never>) => Q.QueryBuilder<PM>) => Effect<T[], never, Service>
974
992
  queryLegacy: <S = T>(map: {
975
993
  filter?: Filter<PM>
976
994
  collect?: (t: T) => Option<S>
977
995
  limit?: number
978
996
  skip?: number
979
- }) => Effect<S[], never, never>
997
+ }) => Effect<S[], never, Service>
980
998
 
981
999
  mapped: MM<Service, PM, Omit<PM, "_etag">>
982
1000
  }
983
1001
 
984
1002
  const makeRepoFunctions = (tag: any) => {
985
1003
  const { all } = Effect.serviceConstants(tag) as any
986
- const { find, get, query, queryLegacy, removeAndPublish, removeById, save, saveAndPublish } = Effect.serviceFunctions(
987
- tag
988
- ) as any
1004
+ const { find, get, q2, query, queryLegacy, removeAndPublish, removeById, save, saveAndPublish } = Effect
1005
+ .serviceFunctions(
1006
+ tag
1007
+ ) as any
989
1008
 
990
1009
  const mapped = (s: any) => tag.map((_: any) => _.mapped(s))
991
1010
 
992
- return { all, find, removeById, saveAndPublish, removeAndPublish, save, get, query, queryLegacy, mapped }
1011
+ return { all, find, removeById, saveAndPublish, removeAndPublish, save, get, query, queryLegacy, q2, mapped }
993
1012
  }
994
1013
 
995
1014
  export const RepositoryBaseImpl = <Service>() => {
@@ -0,0 +1,458 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import type { FieldValues } from "@effect-app/infra/filter/types"
3
+ import type { FieldPath, FieldPathValue } from "@effect-app/infra/filter/types/path/eager"
4
+ import type { Repository } from "@effect-app/infra/services/Repository"
5
+ import type { PersistenceModelType } from "@effect-app/infra/services/Store"
6
+ import type { Ops } from "@effect-app/infra/services/Store/filterApi/proxy"
7
+ import type { FilterResult, QueryBuilder } from "@effect-app/infra/services/Store/filterApi/query"
8
+ import { Data, Effect, Match, pipe, S, Unify } from "effect-app"
9
+ import type { NoInfer } from "effect/Types"
10
+
11
+ export type QAll<TFieldValues extends FieldValues, A = TFieldValues, R = never> =
12
+ | Query<TFieldValues>
13
+ | QueryWhere<TFieldValues>
14
+ | QueryEnd<TFieldValues>
15
+ | QueryProjection<TFieldValues, A, R>
16
+
17
+ export interface Query<TFieldValues extends FieldValues> {
18
+ readonly args: { TFieldValues: TFieldValues }
19
+ readonly _id: unique symbol
20
+ }
21
+ export interface QueryWhere<TFieldValues extends FieldValues> extends Query<TFieldValues> {
22
+ readonly args: { TFieldValues: TFieldValues }
23
+ readonly _id2: unique symbol
24
+ }
25
+
26
+ export interface QueryEnd<TFieldValues extends FieldValues> {
27
+ readonly args: { TFieldValues: TFieldValues }
28
+ readonly _id3: unique symbol
29
+ }
30
+
31
+ export interface QueryProjection<TFieldValues extends FieldValues, A = TFieldValues, R = never> {
32
+ readonly args: { TFieldValues: TFieldValues; A: A; R: R }
33
+ readonly _id4: unique symbol
34
+ }
35
+
36
+ // Impl, later
37
+ export type Q<TFieldValues extends FieldValues> =
38
+ | Initial<TFieldValues>
39
+ | Where<TFieldValues>
40
+ | And<TFieldValues>
41
+ | Or<TFieldValues>
42
+ | Order<TFieldValues, any>
43
+ | Page<TFieldValues>
44
+ | Project<any, TFieldValues, any>
45
+
46
+ export class Initial<TFieldValues extends FieldValues> extends Data.TaggedClass("value")<{ value: "initial" }>
47
+ implements Query<TFieldValues>
48
+ {
49
+ readonly _id: any
50
+ readonly args: any
51
+ constructor() {
52
+ super({ value: "initial" as const })
53
+ }
54
+ }
55
+
56
+ export class Where<TFieldValues extends FieldValues> extends Data.TaggedClass("where")<{
57
+ current: Query<TFieldValues>
58
+ operation: [string, Ops, any] | [string, any]
59
+ }> implements QueryWhere<TFieldValues> {
60
+ _id2!: any
61
+ _id: any
62
+ readonly args: any
63
+ }
64
+
65
+ export class And<TFieldValues extends FieldValues> extends Data.TaggedClass("and")<{
66
+ current: Query<TFieldValues>
67
+ operation: [string, Ops, any] | [string, any] | ((q: Query<TFieldValues>) => QueryWhere<TFieldValues>)
68
+ }> implements QueryWhere<TFieldValues> {
69
+ _id2!: any
70
+ _id: any
71
+ readonly args: any
72
+ }
73
+
74
+ export class Or<TFieldValues extends FieldValues> extends Data.TaggedClass("or")<{
75
+ current: Query<TFieldValues>
76
+ operation: [string, Ops, any] | [string, any] | ((q: Query<TFieldValues>) => QueryWhere<TFieldValues>)
77
+ }> implements QueryWhere<TFieldValues> {
78
+ _id2!: any
79
+ _id: any
80
+ readonly args: any
81
+ }
82
+
83
+ export class Page<TFieldValues extends FieldValues> extends Data.TaggedClass("page")<{
84
+ current: Query<TFieldValues> | QueryEnd<TFieldValues>
85
+ limit?: number | undefined
86
+ skip?: number | undefined
87
+ }> implements QueryEnd<TFieldValues> {
88
+ _id3!: any
89
+ readonly args: any
90
+ }
91
+
92
+ export class Order<TFieldValues extends FieldValues, TFieldName extends FieldPath<TFieldValues>>
93
+ extends Data.TaggedClass("order")<{
94
+ current: Query<TFieldValues> | QueryEnd<TFieldValues>
95
+ field: TFieldName
96
+ desc?: boolean | undefined
97
+ }>
98
+ implements QueryEnd<TFieldValues>
99
+ {
100
+ _id3!: any
101
+ readonly args: any
102
+ }
103
+
104
+ export class Project<A, TFieldValues extends FieldValues, R> extends Data.TaggedClass("project")<{
105
+ current: Query<TFieldValues> | QueryEnd<TFieldValues>
106
+ schema: S.Schema<A, TFieldValues, R>
107
+ }> implements QueryProjection<TFieldValues, A, R> {
108
+ _id4!: any
109
+ readonly args: any
110
+ }
111
+
112
+ const wh: any = (...operation: any[]) => (current: any[]) => new Where({ current, operation } as any)
113
+ export const where: FilterWhere = wh
114
+
115
+ export const and: FilterContinuation = (...operation: any[]) => (current: any) =>
116
+ new And({ current, operation: typeof operation[0] === "function" ? operation[0] : operation } as any)
117
+
118
+ export const or: FilterContinuation = (...operation: any[]) => (current: any) =>
119
+ new Or({ current, operation: typeof operation[0] === "function" ? operation[0] : operation } as any)
120
+
121
+ export const order: <TFieldValues extends FieldValues, TFieldName extends FieldPath<TFieldValues>>(
122
+ field: TFieldName,
123
+ desc?: boolean
124
+ ) => (current: Query<TFieldValues> | QueryEnd<TFieldValues>) => QueryEnd<TFieldValues> = (field, desc) => (current) =>
125
+ new Order({ current, field, desc })
126
+
127
+ export const page: <TFieldValues extends FieldValues>(
128
+ page: { limit?: number; skip?: number }
129
+ ) => (current: Query<TFieldValues> | QueryEnd<TFieldValues>) => QueryEnd<TFieldValues> =
130
+ ({ limit, skip }) => (current) =>
131
+ new Page({
132
+ current,
133
+ limit,
134
+ skip
135
+ })
136
+
137
+ export const project: <TFieldValues extends FieldValues, A, R>(
138
+ schema: S.Schema<A, TFieldValues, R>
139
+ // TODO: should be able to use a subset of FieldValues and use select
140
+ ) => (current: Query<TFieldValues> | QueryEnd<TFieldValues>) => QueryProjection<TFieldValues, A, R> =
141
+ (schema) => (current) => new Project({ current, schema })
142
+
143
+ // TODO: able to switch to Order and Limit/Take, which are "enders"
144
+ export type FilterWheres = {
145
+ <
146
+ TFieldValues extends FieldValues,
147
+ TFieldName extends FieldPath<TFieldValues>,
148
+ V extends FieldPathValue<TFieldValues, TFieldName>
149
+ >(
150
+ path: TFieldName,
151
+ value: V
152
+ ): (
153
+ current: Query<TFieldValues>
154
+ ) => QueryWhere<TFieldValues>
155
+ <
156
+ TFieldValues extends FieldValues,
157
+ TFieldName extends FieldPath<TFieldValues>,
158
+ V extends FieldPathValue<TFieldValues, TFieldName>
159
+ >(
160
+ path: TFieldName,
161
+ op: "neq",
162
+ value: V
163
+ ): (
164
+ current: Query<TFieldValues>
165
+ ) => QueryWhere<TFieldValues>
166
+ <
167
+ TFieldValues extends FieldValues,
168
+ TFieldName extends FieldPath<TFieldValues>,
169
+ V extends FieldPathValue<TFieldValues, TFieldName>
170
+ >(
171
+ path: TFieldName,
172
+ op: "gt" | "gte" | "lt" | "lte",
173
+ value: V // only numbers?
174
+ ): (
175
+ current: Query<TFieldValues>
176
+ ) => QueryWhere<TFieldValues>
177
+ <
178
+ TFieldValues extends FieldValues,
179
+ TFieldName extends FieldPath<TFieldValues>,
180
+ V extends FieldPathValue<TFieldValues, TFieldName>
181
+ >(
182
+ path: TFieldName,
183
+ op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith",
184
+ value: V // only strings?
185
+ ): (
186
+ current: Query<TFieldValues>
187
+ ) => QueryWhere<TFieldValues>
188
+ <
189
+ TFieldValues extends FieldValues,
190
+ TFieldName extends FieldPath<TFieldValues>,
191
+ V extends FieldPathValue<TFieldValues, TFieldName>
192
+ >(
193
+ path: TFieldName,
194
+ op: "in" | "notIn",
195
+ value: readonly V[]
196
+ ): (
197
+ current: Query<TFieldValues>
198
+ ) => QueryWhere<TFieldValues>
199
+ }
200
+
201
+ export type FilterWhere = {
202
+ <
203
+ TFieldValues extends FieldValues,
204
+ TFieldName extends FieldPath<TFieldValues>,
205
+ V extends FieldPathValue<TFieldValues, TFieldName>
206
+ >(f: {
207
+ path: TFieldName
208
+ op: Ops
209
+ value: V
210
+ }): (
211
+ current: Query<TFieldValues>
212
+ ) => QueryWhere<TFieldValues>
213
+ } & FilterWheres
214
+
215
+ export type FilterContinuations = {
216
+ <
217
+ TFieldValues extends FieldValues,
218
+ TFieldName extends FieldPath<TFieldValues>,
219
+ V extends FieldPathValue<TFieldValues, TFieldName>
220
+ >(
221
+ path: TFieldName,
222
+ value: V
223
+ ): (
224
+ current: QueryWhere<TFieldValues>
225
+ ) => QueryWhere<TFieldValues>
226
+ <
227
+ TFieldValues extends FieldValues,
228
+ TFieldName extends FieldPath<TFieldValues>,
229
+ V extends FieldPathValue<TFieldValues, TFieldName>
230
+ >(
231
+ path: TFieldName,
232
+ op: "neq",
233
+ value: V
234
+ ): (
235
+ current: QueryWhere<TFieldValues>
236
+ ) => QueryWhere<TFieldValues>
237
+ <
238
+ TFieldValues extends FieldValues,
239
+ TFieldName extends FieldPath<TFieldValues>,
240
+ V extends FieldPathValue<TFieldValues, TFieldName>
241
+ >(
242
+ path: TFieldName,
243
+ op: "gt" | "gte" | "lt" | "lte",
244
+ value: V // only numbers?
245
+ ): (
246
+ current: QueryWhere<TFieldValues>
247
+ ) => QueryWhere<TFieldValues>
248
+ <
249
+ TFieldValues extends FieldValues,
250
+ TFieldName extends FieldPath<TFieldValues>,
251
+ V extends FieldPathValue<TFieldValues, TFieldName>
252
+ >(
253
+ path: TFieldName,
254
+ op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith",
255
+ value: V // only strings?
256
+ ): (
257
+ current: QueryWhere<TFieldValues>
258
+ ) => QueryWhere<TFieldValues>
259
+ <
260
+ TFieldValues extends FieldValues,
261
+ TFieldName extends FieldPath<TFieldValues>,
262
+ V extends FieldPathValue<TFieldValues, TFieldName>
263
+ >(
264
+ path: TFieldName,
265
+ op: "in" | "notIn",
266
+ value: readonly V[]
267
+ ): (
268
+ current: QueryWhere<TFieldValues>
269
+ ) => QueryWhere<TFieldValues>
270
+ }
271
+
272
+ export type FilterContinuation = {
273
+ <TFieldValues extends FieldValues>(
274
+ fb: (
275
+ current: Query<TFieldValues>
276
+ ) => QueryWhere<TFieldValues>
277
+ ): (
278
+ current: QueryWhere<TFieldValues>
279
+ ) => QueryWhere<TFieldValues>
280
+ <
281
+ TFieldValues extends FieldValues,
282
+ TFieldName extends FieldPath<TFieldValues>,
283
+ V extends FieldPathValue<TFieldValues, TFieldName>
284
+ >(f: {
285
+ path: TFieldName
286
+ op: Ops
287
+ value: V
288
+ }): (
289
+ current: QueryWhere<TFieldValues>
290
+ ) => QueryWhere<TFieldValues>
291
+ } & FilterContinuations
292
+
293
+ export const make: <TFieldValues extends FieldValues>() => Query<TFieldValues> = () => new Initial()
294
+ export interface A {
295
+ a: string
296
+ b: number
297
+ c: boolean
298
+ }
299
+
300
+ const interpret = <TFieldValues extends FieldValues, A = TFieldValues, R = never>(_: QAll<TFieldValues, A, R>) => {
301
+ const values: FilterResult[] = []
302
+ const a = _ as Q<TFieldValues>
303
+
304
+ let schema: S.Schema<A, TFieldValues, R> | undefined = undefined as any
305
+ let limit: number | undefined = undefined as any
306
+ let skip: number | undefined = undefined as any
307
+
308
+ const upd = (v: { schema: any; limit: any; skip: any; filter: readonly FilterResult[] }) => {
309
+ values.push(...v.filter)
310
+ limit = v.limit
311
+ skip = v.skip
312
+ schema = v.schema
313
+ }
314
+
315
+ pipe(
316
+ a,
317
+ Match.valueTags({
318
+ value: () => {
319
+ // values.push(value)
320
+ },
321
+ where: ({ current, operation }) => {
322
+ upd(interpret(current))
323
+ values.push(
324
+ {
325
+ t: "where",
326
+ path: operation[0],
327
+ op: operation.length === 2 ? "eq" : operation[1],
328
+ value: operation.length === 2 ? operation[1] : operation[2]
329
+ }
330
+ )
331
+ },
332
+ and: ({ current, operation }) => {
333
+ upd(interpret(current))
334
+ if (typeof operation === "function") {
335
+ values.push(
336
+ { t: "and-scope", result: interpret(operation(make())).filter }
337
+ )
338
+ } else {
339
+ values.push(
340
+ {
341
+ t: "and",
342
+ path: operation[0],
343
+ op: operation.length === 2 ? "eq" : operation[1],
344
+ value: operation.length === 2 ? operation[1] : operation[2]
345
+ }
346
+ )
347
+ }
348
+ },
349
+ or: ({ current, operation }) => {
350
+ upd(interpret(current))
351
+ if (typeof operation === "function") {
352
+ values.push(
353
+ { t: "or-scope", result: interpret(operation(make())).filter }
354
+ )
355
+ } else {
356
+ values.push(
357
+ {
358
+ t: "or",
359
+ path: operation[0],
360
+ op: operation.length === 2 ? "eq" : operation[1],
361
+ value: operation.length === 2 ? operation[1] : operation[2]
362
+ }
363
+ )
364
+ }
365
+ },
366
+ order: ({ current }) => {
367
+ upd(interpret(current))
368
+ console.log("missing order implementation")
369
+ },
370
+ page: (v) => {
371
+ upd(interpret(v.current))
372
+ limit = v.limit
373
+ skip = v.skip
374
+ },
375
+ project: (v) => {
376
+ upd(interpret(v.current))
377
+ schema = v.schema
378
+ }
379
+ })
380
+ )
381
+
382
+ // TODO
383
+ return {
384
+ filter: values,
385
+ limit,
386
+ skip,
387
+ schema
388
+ }
389
+ }
390
+
391
+ export const query: {
392
+ <
393
+ T extends { id: unknown },
394
+ PM extends PersistenceModelType<string>,
395
+ Evt,
396
+ ItemType extends string,
397
+ A,
398
+ R,
399
+ From extends FieldValues
400
+ >(
401
+ repo: Repository<T, PM, Evt, ItemType>,
402
+ q: QueryProjection<PM extends From ? From : never, A, R>
403
+ ): Effect.Effect<readonly A[], S.ParseResult.ParseError, R>
404
+ <
405
+ T extends { id: unknown },
406
+ PM extends PersistenceModelType<string>,
407
+ Evt,
408
+ ItemType extends string,
409
+ A,
410
+ R
411
+ >(
412
+ repo: Repository<T, PM, Evt, ItemType>,
413
+ q: QAll<NoInfer<PM>, A, R>
414
+ ): Effect.Effect<readonly T[], never, R>
415
+ } = (<
416
+ T extends { id: unknown },
417
+ PM extends PersistenceModelType<string>,
418
+ Evt,
419
+ ItemType extends string,
420
+ A,
421
+ R
422
+ >(repo: Repository<T, PM, Evt, ItemType>, q: QAll<PM, A, R>) => {
423
+ // TODO: Native interpreter for each db adapter, instead of the intermediate "new-kid" format
424
+ const a = interpret(q)
425
+ const schema = a.schema
426
+ let select: (keyof PM)[] = []
427
+ if (schema) {
428
+ let t = schema.ast
429
+ if (S.AST.isTransform(t)) {
430
+ t = t.from
431
+ }
432
+ if (S.AST.isTypeLiteral(t)) {
433
+ select = t.propertySignatures.map((_) => _.name) as any
434
+ }
435
+ }
436
+ return pipe(
437
+ a.filter.length === 0
438
+ ? repo.utils.all
439
+ : repo.utils.filter({
440
+ limit: a.limit,
441
+ skip: a.skip,
442
+ select: select.toNonEmpty.value ?? undefined,
443
+ filter: a.filter.length
444
+ ? {
445
+ type: "new-kid" as const,
446
+ build: () => a.filter
447
+ } as any as QueryBuilder<any>
448
+ : undefined
449
+ }),
450
+ Effect.flatMap((_) =>
451
+ Unify.unify(
452
+ schema
453
+ ? repo.utils.parseMany2(_, schema as any)
454
+ : repo.utils.parseMany(_)
455
+ )
456
+ )
457
+ )
458
+ }) as any