@effect-app/infra 0.200.2 → 0.200.3
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 +6 -0
- package/_cjs/services/RepositoryBase.cjs +3 -0
- package/_cjs/services/RepositoryBase.cjs.map +1 -1
- package/_cjs/services/query/dsl.cjs +79 -0
- package/_cjs/services/query/dsl.cjs.map +1 -0
- package/_cjs/services/query/new-kid-interpreter.cjs +129 -0
- package/_cjs/services/query/new-kid-interpreter.cjs.map +1 -0
- package/_cjs/services/query.cjs +20 -200
- package/_cjs/services/query.cjs.map +1 -1
- package/_cjs/services/query.test.cjs +34 -0
- package/_cjs/services/query.test.cjs.map +1 -0
- package/dist/services/QueueMaker/memQueue.d.ts +1 -1
- package/dist/services/QueueMaker/sbqueue.d.ts +1 -1
- package/dist/services/RepositoryBase.d.ts +9 -9
- package/dist/services/RepositoryBase.d.ts.map +1 -1
- package/dist/services/RepositoryBase.js +4 -1
- package/dist/services/query/dsl.d.ts +127 -0
- package/dist/services/query/dsl.d.ts.map +1 -0
- package/dist/services/query/dsl.js +38 -0
- package/dist/services/query/new-kid-interpreter.d.ts +15 -0
- package/dist/services/query/new-kid-interpreter.d.ts.map +1 -0
- package/dist/services/query/new-kid-interpreter.js +110 -0
- package/dist/services/query.d.ts +2 -163
- package/dist/services/query.d.ts.map +1 -1
- package/dist/services/query.js +3 -157
- package/dist/services/query.test.d.ts.map +1 -0
- package/package.json +23 -3
- package/src/services/RepositoryBase.ts +11 -8
- package/src/services/query/dsl.ts +290 -0
- package/src/services/query/new-kid-interpreter.ts +169 -0
- package/src/services/query.test.ts +37 -0
- package/src/services/query.ts +2 -462
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
import type { FieldValues } from "@effect-app/infra/filter/types"
|
|
5
|
+
import type { FieldPath, FieldPathValue } from "@effect-app/infra/filter/types/path/eager"
|
|
6
|
+
import type { Ops } from "@effect-app/infra/services/Store/filterApi/proxy"
|
|
7
|
+
import type { S } from "effect-app"
|
|
8
|
+
import { Data } from "effect-app"
|
|
9
|
+
import type { Covariant } 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 const QId = Symbol()
|
|
18
|
+
export type QId = typeof QId
|
|
19
|
+
|
|
20
|
+
export interface QueryTogether<
|
|
21
|
+
out TFieldValues extends FieldValues,
|
|
22
|
+
out T extends "initial" | "where" | "end" | "projection" = "initial",
|
|
23
|
+
out A = TFieldValues,
|
|
24
|
+
out R = never
|
|
25
|
+
> {
|
|
26
|
+
readonly [QId]: {
|
|
27
|
+
readonly _TFieldValues: Covariant<TFieldValues>
|
|
28
|
+
readonly _T: Covariant<T>
|
|
29
|
+
readonly _A: Covariant<A>
|
|
30
|
+
readonly _R: Covariant<R>
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type Query<TFieldValues extends FieldValues> = QueryTogether<TFieldValues, "initial">
|
|
35
|
+
export type QueryWhere<TFieldValues extends FieldValues> = QueryTogether<TFieldValues, "where">
|
|
36
|
+
|
|
37
|
+
export type QueryEnd<TFieldValues extends FieldValues> = QueryTogether<TFieldValues, "end">
|
|
38
|
+
|
|
39
|
+
export type QueryProjection<TFieldValues extends FieldValues, A = TFieldValues, R = never> = QueryTogether<
|
|
40
|
+
TFieldValues,
|
|
41
|
+
"projection",
|
|
42
|
+
A,
|
|
43
|
+
R
|
|
44
|
+
>
|
|
45
|
+
|
|
46
|
+
export type Q<TFieldValues extends FieldValues> =
|
|
47
|
+
| Initial<TFieldValues>
|
|
48
|
+
| Where<TFieldValues>
|
|
49
|
+
| And<TFieldValues>
|
|
50
|
+
| Or<TFieldValues>
|
|
51
|
+
| Order<TFieldValues, any>
|
|
52
|
+
| Page<TFieldValues>
|
|
53
|
+
| Project<any, TFieldValues, any>
|
|
54
|
+
|
|
55
|
+
export class Initial<TFieldValues extends FieldValues> extends Data.TaggedClass("value")<{ value: "initial" }>
|
|
56
|
+
implements Query<TFieldValues>
|
|
57
|
+
{
|
|
58
|
+
readonly [QId]!: any
|
|
59
|
+
constructor() {
|
|
60
|
+
super({ value: "initial" as const })
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class Where<TFieldValues extends FieldValues> extends Data.TaggedClass("where")<{
|
|
65
|
+
current: Query<TFieldValues>
|
|
66
|
+
operation: [string, Ops, any] | [string, any]
|
|
67
|
+
}> implements QueryWhere<TFieldValues> {
|
|
68
|
+
readonly [QId]!: any
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class And<TFieldValues extends FieldValues> extends Data.TaggedClass("and")<{
|
|
72
|
+
current: Query<TFieldValues>
|
|
73
|
+
operation: [string, Ops, any] | [string, any] | ((q: Query<TFieldValues>) => QueryWhere<TFieldValues>)
|
|
74
|
+
}> implements QueryWhere<TFieldValues> {
|
|
75
|
+
readonly [QId]!: any
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class Or<TFieldValues extends FieldValues> extends Data.TaggedClass("or")<{
|
|
79
|
+
current: Query<TFieldValues>
|
|
80
|
+
operation: [string, Ops, any] | [string, any] | ((q: Query<TFieldValues>) => QueryWhere<TFieldValues>)
|
|
81
|
+
}> implements QueryWhere<TFieldValues> {
|
|
82
|
+
readonly [QId]!: any
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class Page<TFieldValues extends FieldValues> extends Data.TaggedClass("page")<{
|
|
86
|
+
current: Query<TFieldValues> | QueryWhere<TFieldValues> | QueryEnd<TFieldValues>
|
|
87
|
+
limit?: number | undefined
|
|
88
|
+
skip?: number | undefined
|
|
89
|
+
}> implements QueryEnd<TFieldValues> {
|
|
90
|
+
readonly [QId]!: any
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class Order<TFieldValues extends FieldValues, TFieldName extends FieldPath<TFieldValues>>
|
|
94
|
+
extends Data.TaggedClass("order")<{
|
|
95
|
+
current: Query<TFieldValues> | QueryWhere<TFieldValues> | QueryEnd<TFieldValues>
|
|
96
|
+
field: TFieldName
|
|
97
|
+
direction: "ASC" | "DESC"
|
|
98
|
+
}>
|
|
99
|
+
implements QueryEnd<TFieldValues>
|
|
100
|
+
{
|
|
101
|
+
readonly [QId]!: any
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export class Project<A, TFieldValues extends FieldValues, R> extends Data.TaggedClass("project")<{
|
|
105
|
+
current: Query<TFieldValues> | QueryWhere<TFieldValues> | QueryEnd<TFieldValues>
|
|
106
|
+
schema: S.Schema<A, TFieldValues, R>
|
|
107
|
+
}> implements QueryProjection<TFieldValues, A, R> {
|
|
108
|
+
readonly [QId]!: any
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const make: <TFieldValues extends FieldValues>() => Query<TFieldValues> = () => new Initial()
|
|
112
|
+
|
|
113
|
+
export const where: FilterWhere = (...operation: any[]) => (current: any) => new Where({ current, operation } as any)
|
|
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> | QueryWhere<TFieldValues> | QueryEnd<TFieldValues>) => QueryEnd<TFieldValues> =
|
|
125
|
+
(field, desc) => (current) => new Order({ current, field, direction: desc ? "DESC" : "ASC" })
|
|
126
|
+
|
|
127
|
+
export const page: <TFieldValues extends FieldValues>(
|
|
128
|
+
page: { limit?: number; skip?: number }
|
|
129
|
+
) => (current: Query<TFieldValues> | QueryWhere<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 = FieldValues, R = never>(
|
|
138
|
+
schema: S.Schema<A, TFieldValues, R>
|
|
139
|
+
) => (
|
|
140
|
+
current: Query<TFieldValues> | QueryWhere<TFieldValues> | QueryEnd<TFieldValues>
|
|
141
|
+
) => QueryProjection<TFieldValues, A, R> = (schema) => (current) => new Project({ current, schema })
|
|
142
|
+
|
|
143
|
+
export type FilterWheres = {
|
|
144
|
+
<
|
|
145
|
+
TFieldValues extends FieldValues,
|
|
146
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
147
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
148
|
+
>(
|
|
149
|
+
path: TFieldName,
|
|
150
|
+
value: V
|
|
151
|
+
): (
|
|
152
|
+
current: Query<TFieldValues>
|
|
153
|
+
) => QueryWhere<TFieldValues>
|
|
154
|
+
<
|
|
155
|
+
TFieldValues extends FieldValues,
|
|
156
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
157
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
158
|
+
>(
|
|
159
|
+
path: TFieldName,
|
|
160
|
+
op: "neq",
|
|
161
|
+
value: V
|
|
162
|
+
): (
|
|
163
|
+
current: Query<TFieldValues>
|
|
164
|
+
) => QueryWhere<TFieldValues>
|
|
165
|
+
<
|
|
166
|
+
TFieldValues extends FieldValues,
|
|
167
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
168
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
169
|
+
>(
|
|
170
|
+
path: TFieldName,
|
|
171
|
+
op: "gt" | "gte" | "lt" | "lte",
|
|
172
|
+
value: V // only numbers?
|
|
173
|
+
): (
|
|
174
|
+
current: Query<TFieldValues>
|
|
175
|
+
) => QueryWhere<TFieldValues>
|
|
176
|
+
<
|
|
177
|
+
TFieldValues extends FieldValues,
|
|
178
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
179
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
180
|
+
>(
|
|
181
|
+
path: TFieldName,
|
|
182
|
+
op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith",
|
|
183
|
+
value: V // only strings?
|
|
184
|
+
): (
|
|
185
|
+
current: Query<TFieldValues>
|
|
186
|
+
) => QueryWhere<TFieldValues>
|
|
187
|
+
<
|
|
188
|
+
TFieldValues extends FieldValues,
|
|
189
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
190
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
191
|
+
>(
|
|
192
|
+
path: TFieldName,
|
|
193
|
+
op: "in" | "notIn",
|
|
194
|
+
value: readonly V[]
|
|
195
|
+
): (
|
|
196
|
+
current: Query<TFieldValues>
|
|
197
|
+
) => QueryWhere<TFieldValues>
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export type FilterWhere = {
|
|
201
|
+
<
|
|
202
|
+
TFieldValues extends FieldValues,
|
|
203
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
204
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
205
|
+
>(f: {
|
|
206
|
+
path: TFieldName
|
|
207
|
+
op: Ops
|
|
208
|
+
value: V
|
|
209
|
+
}): (
|
|
210
|
+
current: Query<TFieldValues>
|
|
211
|
+
) => QueryWhere<TFieldValues>
|
|
212
|
+
} & FilterWheres
|
|
213
|
+
|
|
214
|
+
export type FilterContinuations = {
|
|
215
|
+
<
|
|
216
|
+
TFieldValues extends FieldValues,
|
|
217
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
218
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
219
|
+
>(
|
|
220
|
+
path: TFieldName,
|
|
221
|
+
value: V
|
|
222
|
+
): (
|
|
223
|
+
current: QueryWhere<TFieldValues>
|
|
224
|
+
) => QueryWhere<TFieldValues>
|
|
225
|
+
<
|
|
226
|
+
TFieldValues extends FieldValues,
|
|
227
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
228
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
229
|
+
>(
|
|
230
|
+
path: TFieldName,
|
|
231
|
+
op: "neq",
|
|
232
|
+
value: V
|
|
233
|
+
): (
|
|
234
|
+
current: QueryWhere<TFieldValues>
|
|
235
|
+
) => QueryWhere<TFieldValues>
|
|
236
|
+
<
|
|
237
|
+
TFieldValues extends FieldValues,
|
|
238
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
239
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
240
|
+
>(
|
|
241
|
+
path: TFieldName,
|
|
242
|
+
op: "gt" | "gte" | "lt" | "lte",
|
|
243
|
+
value: V // only numbers?
|
|
244
|
+
): (
|
|
245
|
+
current: QueryWhere<TFieldValues>
|
|
246
|
+
) => QueryWhere<TFieldValues>
|
|
247
|
+
<
|
|
248
|
+
TFieldValues extends FieldValues,
|
|
249
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
250
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
251
|
+
>(
|
|
252
|
+
path: TFieldName,
|
|
253
|
+
op: "startsWith" | "endsWith" | "contains" | "notContains" | "notStartsWith" | "notEndsWith",
|
|
254
|
+
value: V // only strings?
|
|
255
|
+
): (
|
|
256
|
+
current: QueryWhere<TFieldValues>
|
|
257
|
+
) => QueryWhere<TFieldValues>
|
|
258
|
+
<
|
|
259
|
+
TFieldValues extends FieldValues,
|
|
260
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
261
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
262
|
+
>(
|
|
263
|
+
path: TFieldName,
|
|
264
|
+
op: "in" | "notIn",
|
|
265
|
+
value: readonly V[]
|
|
266
|
+
): (
|
|
267
|
+
current: QueryWhere<TFieldValues>
|
|
268
|
+
) => QueryWhere<TFieldValues>
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export type FilterContinuation = {
|
|
272
|
+
<TFieldValues extends FieldValues>(
|
|
273
|
+
fb: (
|
|
274
|
+
current: Query<TFieldValues>
|
|
275
|
+
) => QueryWhere<TFieldValues>
|
|
276
|
+
): (
|
|
277
|
+
current: QueryWhere<TFieldValues>
|
|
278
|
+
) => QueryWhere<TFieldValues>
|
|
279
|
+
<
|
|
280
|
+
TFieldValues extends FieldValues,
|
|
281
|
+
TFieldName extends FieldPath<TFieldValues>,
|
|
282
|
+
V extends FieldPathValue<TFieldValues, TFieldName>
|
|
283
|
+
>(f: {
|
|
284
|
+
path: TFieldName
|
|
285
|
+
op: Ops
|
|
286
|
+
value: V
|
|
287
|
+
}): (
|
|
288
|
+
current: QueryWhere<TFieldValues>
|
|
289
|
+
) => QueryWhere<TFieldValues>
|
|
290
|
+
} & FilterContinuations
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
|
+
import { toNonEmptyArray } from "@effect-app/core/Array"
|
|
4
|
+
import { Effect, Match, Option, pipe, S, Unify } from "effect-app"
|
|
5
|
+
import type { NoInfer } from "effect/Types"
|
|
6
|
+
import type { FieldValues } from "../../filter/types.js"
|
|
7
|
+
import type { FieldPath } from "../../filter/types/path/eager.js"
|
|
8
|
+
import { make, type Q, type QAll, type QueryProjection } from "../query.js"
|
|
9
|
+
import type { Repository } from "../Repository.js"
|
|
10
|
+
import type { PersistenceModelType } from "../Store.js"
|
|
11
|
+
import type { FilterResult, QueryBuilder } from "../Store/filterApi/query.js"
|
|
12
|
+
|
|
13
|
+
const interpret = <TFieldValues extends FieldValues, A = TFieldValues, R = never>(_: QAll<TFieldValues, A, R>) => {
|
|
14
|
+
const values: FilterResult[] = []
|
|
15
|
+
const a = _ as Q<TFieldValues>
|
|
16
|
+
|
|
17
|
+
let schema: S.Schema<A, TFieldValues, R> | undefined = undefined as any
|
|
18
|
+
let limit: number | undefined = undefined as any
|
|
19
|
+
let skip: number | undefined = undefined as any
|
|
20
|
+
const order: { field: FieldPath<TFieldValues>; direction: "ASC" | "DESC" }[] = []
|
|
21
|
+
|
|
22
|
+
const upd = (v: { schema: any; limit: any; skip: any; filter: readonly FilterResult[]; order: any[] }) => {
|
|
23
|
+
values.push(...v.filter)
|
|
24
|
+
order.push(...v.order)
|
|
25
|
+
limit = v.limit
|
|
26
|
+
skip = v.skip
|
|
27
|
+
schema = v.schema
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pipe(
|
|
31
|
+
a,
|
|
32
|
+
Match.valueTags({
|
|
33
|
+
value: () => {
|
|
34
|
+
// values.push(value)
|
|
35
|
+
},
|
|
36
|
+
where: ({ current, operation }) => {
|
|
37
|
+
upd(interpret(current))
|
|
38
|
+
values.push(
|
|
39
|
+
{
|
|
40
|
+
t: "where",
|
|
41
|
+
path: operation[0],
|
|
42
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
43
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
},
|
|
47
|
+
and: ({ current, operation }) => {
|
|
48
|
+
upd(interpret(current))
|
|
49
|
+
if (typeof operation === "function") {
|
|
50
|
+
values.push(
|
|
51
|
+
{ t: "and-scope", result: interpret(operation(make())).filter }
|
|
52
|
+
)
|
|
53
|
+
} else {
|
|
54
|
+
values.push(
|
|
55
|
+
{
|
|
56
|
+
t: "and",
|
|
57
|
+
path: operation[0],
|
|
58
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
59
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
or: ({ current, operation }) => {
|
|
65
|
+
upd(interpret(current))
|
|
66
|
+
if (typeof operation === "function") {
|
|
67
|
+
values.push(
|
|
68
|
+
{ t: "or-scope", result: interpret(operation(make())).filter }
|
|
69
|
+
)
|
|
70
|
+
} else {
|
|
71
|
+
values.push(
|
|
72
|
+
{
|
|
73
|
+
t: "or",
|
|
74
|
+
path: operation[0],
|
|
75
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
76
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
order: ({ current }) => {
|
|
82
|
+
upd(interpret(current))
|
|
83
|
+
},
|
|
84
|
+
page: (v) => {
|
|
85
|
+
upd(interpret(v.current))
|
|
86
|
+
limit = v.limit
|
|
87
|
+
skip = v.skip
|
|
88
|
+
},
|
|
89
|
+
project: (v) => {
|
|
90
|
+
upd(interpret(v.current))
|
|
91
|
+
schema = v.schema
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
filter: values,
|
|
98
|
+
limit,
|
|
99
|
+
skip,
|
|
100
|
+
schema,
|
|
101
|
+
order
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const query: {
|
|
106
|
+
<
|
|
107
|
+
T extends { id: unknown },
|
|
108
|
+
PM extends PersistenceModelType<string>,
|
|
109
|
+
Evt,
|
|
110
|
+
ItemType extends string,
|
|
111
|
+
A,
|
|
112
|
+
R,
|
|
113
|
+
From extends FieldValues
|
|
114
|
+
>(
|
|
115
|
+
repo: Repository<T, PM, Evt, ItemType>,
|
|
116
|
+
q: QueryProjection<PM extends From ? From : never, A, R>
|
|
117
|
+
): Effect.Effect<readonly A[], S.ParseResult.ParseError, R>
|
|
118
|
+
<
|
|
119
|
+
T extends { id: unknown },
|
|
120
|
+
PM extends PersistenceModelType<string>,
|
|
121
|
+
Evt,
|
|
122
|
+
ItemType extends string,
|
|
123
|
+
A,
|
|
124
|
+
R
|
|
125
|
+
>(
|
|
126
|
+
repo: Repository<T, PM, Evt, ItemType>,
|
|
127
|
+
q: QAll<NoInfer<PM>, A, R>
|
|
128
|
+
): Effect.Effect<readonly T[], never, R>
|
|
129
|
+
} = (<
|
|
130
|
+
T extends { id: unknown },
|
|
131
|
+
PM extends PersistenceModelType<string>,
|
|
132
|
+
Evt,
|
|
133
|
+
ItemType extends string,
|
|
134
|
+
A,
|
|
135
|
+
R
|
|
136
|
+
>(repo: Repository<T, PM, Evt, ItemType>, q: QAll<PM, A, R>) => {
|
|
137
|
+
// TODO: Native interpreter for each db adapter, instead of the intermediate "new-kid" format
|
|
138
|
+
const a = interpret(q)
|
|
139
|
+
const schema = a.schema
|
|
140
|
+
let select: (keyof PM)[] = []
|
|
141
|
+
if (schema) {
|
|
142
|
+
let t = schema.ast
|
|
143
|
+
if (S.AST.isTransform(t)) {
|
|
144
|
+
t = t.from
|
|
145
|
+
}
|
|
146
|
+
if (S.AST.isTypeLiteral(t)) {
|
|
147
|
+
select = t.propertySignatures.map((_) => _.name) as any
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return Effect.flatMap(
|
|
151
|
+
repo.utils.filter({
|
|
152
|
+
limit: a.limit,
|
|
153
|
+
skip: a.skip,
|
|
154
|
+
select: Option.getOrUndefined(toNonEmptyArray(select)),
|
|
155
|
+
filter: a.filter.length
|
|
156
|
+
? {
|
|
157
|
+
type: "new-kid" as const,
|
|
158
|
+
build: () => a.filter
|
|
159
|
+
} as QueryBuilder<any>
|
|
160
|
+
: undefined
|
|
161
|
+
}),
|
|
162
|
+
(_) =>
|
|
163
|
+
Unify.unify(
|
|
164
|
+
schema
|
|
165
|
+
? repo.utils.parseMany2(_, schema as any)
|
|
166
|
+
: repo.utils.parseMany(_)
|
|
167
|
+
)
|
|
168
|
+
)
|
|
169
|
+
}) as any
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Effect, flow, pipe, S } from "effect-app"
|
|
2
|
+
import { make, or, order, project, where } from "./query.js"
|
|
3
|
+
import { RepositoryDefaultImpl } from "./RepositoryBase.js"
|
|
4
|
+
import { RequestContextContainer } from "./RequestContextContainer.js"
|
|
5
|
+
|
|
6
|
+
const s = S.struct({ id: S.string, displayName: S.string, n: S.Date })
|
|
7
|
+
type s = S.Schema.To<typeof s>
|
|
8
|
+
type sfrom = S.Schema.From<typeof s>
|
|
9
|
+
export class TestRepo extends RepositoryDefaultImpl<TestRepo>()<sfrom & { _etag: string | undefined }, never>()(
|
|
10
|
+
"test",
|
|
11
|
+
s
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
const a = pipe(
|
|
15
|
+
make<{ id: string; displayName: string; n: Date }>(),
|
|
16
|
+
where("displayName", "Verona"),
|
|
17
|
+
or(flow(
|
|
18
|
+
where("displayName", "Riley")
|
|
19
|
+
// and("resource._tag", "Printer")
|
|
20
|
+
)),
|
|
21
|
+
order("displayName")
|
|
22
|
+
)
|
|
23
|
+
const q = pipe(
|
|
24
|
+
a,
|
|
25
|
+
// page(2, 1)
|
|
26
|
+
project(
|
|
27
|
+
// User.struct.pipe(S.pick("displayName"))
|
|
28
|
+
S.transformOrFail(
|
|
29
|
+
S.struct({ displayName: S.string }), // for projection performance benefit, this should be limited to the fields interested
|
|
30
|
+
S.struct({ displayName: S.string }),
|
|
31
|
+
(_) => Effect.andThen(RequestContextContainer, _),
|
|
32
|
+
() => Effect.die(new Error("not implemented"))
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
console.log(q)
|
|
37
|
+
console.log(TestRepo.q2(() => q))
|