effect-app 4.0.0-beta.247 → 4.0.0-beta.249
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 +16 -0
- package/dist/Emailer.d.ts +51 -0
- package/dist/Emailer.d.ts.map +1 -0
- package/dist/Emailer.js +7 -0
- package/dist/Model/Repository/Registry.d.ts +21 -0
- package/dist/Model/Repository/Registry.d.ts.map +1 -0
- package/dist/Model/Repository/Registry.js +18 -0
- package/dist/Model/Repository/ext.d.ts +60 -0
- package/dist/Model/Repository/ext.d.ts.map +1 -0
- package/dist/Model/Repository/ext.js +122 -0
- package/dist/Model/Repository/internal/internal.d.ts +62 -0
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
- package/dist/Model/Repository/internal/internal.js +413 -0
- package/dist/Model/Repository/legacy.d.ts +21 -0
- package/dist/Model/Repository/legacy.d.ts.map +1 -0
- package/dist/Model/Repository/legacy.js +2 -0
- package/dist/Model/Repository/makeRepo.d.ts +53 -0
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -0
- package/dist/Model/Repository/makeRepo.js +27 -0
- package/dist/Model/Repository/service.d.ts +97 -0
- package/dist/Model/Repository/service.d.ts.map +1 -0
- package/dist/Model/Repository/service.js +2 -0
- package/dist/Model/Repository/validation.d.ts +71 -0
- package/dist/Model/Repository/validation.d.ts.map +1 -0
- package/dist/Model/Repository/validation.js +32 -0
- package/dist/Model/Repository.d.ts +7 -0
- package/dist/Model/Repository.d.ts.map +1 -0
- package/dist/Model/Repository.js +7 -0
- package/dist/Model/dsl.d.ts +33 -0
- package/dist/Model/dsl.d.ts.map +1 -0
- package/dist/Model/dsl.js +43 -0
- package/dist/Model/filter/filterApi.d.ts +30 -0
- package/dist/Model/filter/filterApi.d.ts.map +1 -0
- package/dist/Model/filter/filterApi.js +2 -0
- package/dist/Model/filter/types/errors.d.ts +29 -0
- package/dist/Model/filter/types/errors.d.ts.map +1 -0
- package/dist/Model/filter/types/errors.js +2 -0
- package/dist/Model/filter/types/fields.d.ts +15 -0
- package/dist/Model/filter/types/fields.d.ts.map +1 -0
- package/dist/Model/filter/types/fields.js +2 -0
- package/dist/Model/filter/types/path/common.d.ts +316 -0
- package/dist/Model/filter/types/path/common.d.ts.map +1 -0
- package/dist/Model/filter/types/path/common.js +2 -0
- package/dist/Model/filter/types/path/eager.d.ts +95 -0
- package/dist/Model/filter/types/path/eager.d.ts.map +1 -0
- package/dist/Model/filter/types/path/eager.js +31 -0
- package/dist/Model/filter/types/path/index.d.ts +4 -0
- package/dist/Model/filter/types/path/index.d.ts.map +1 -0
- package/dist/Model/filter/types/path/index.js +3 -0
- package/dist/Model/filter/types/utils.d.ts +79 -0
- package/dist/Model/filter/types/utils.d.ts.map +1 -0
- package/dist/Model/filter/types/utils.js +2 -0
- package/dist/Model/filter/types/validator.d.ts +30 -0
- package/dist/Model/filter/types/validator.d.ts.map +1 -0
- package/dist/Model/filter/types/validator.js +2 -0
- package/dist/Model/filter/types.d.ts +5 -0
- package/dist/Model/filter/types.d.ts.map +1 -0
- package/dist/Model/filter/types.js +7 -0
- package/dist/Model/query/dsl.d.ts +446 -0
- package/dist/Model/query/dsl.d.ts.map +1 -0
- package/dist/Model/query/dsl.js +342 -0
- package/dist/Model/query/new-kid-interpreter.d.ts +136 -0
- package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -0
- package/dist/Model/query/new-kid-interpreter.js +336 -0
- package/dist/Model/query.d.ts +15 -0
- package/dist/Model/query.d.ts.map +1 -0
- package/dist/Model/query.js +3 -0
- package/dist/Model.d.ts +5 -0
- package/dist/Model.d.ts.map +1 -0
- package/dist/Model.js +5 -0
- package/dist/QueueMaker.d.ts +13 -0
- package/dist/QueueMaker.d.ts.map +1 -0
- package/dist/QueueMaker.js +4 -0
- package/dist/RequestContext.d.ts +103 -0
- package/dist/RequestContext.d.ts.map +1 -0
- package/dist/RequestContext.js +49 -0
- package/dist/Schema/ext.d.ts +9 -9
- package/dist/Schema/ext.d.ts.map +1 -1
- package/dist/Schema/ext.js +1 -1
- package/dist/Store.d.ts +147 -0
- package/dist/Store.d.ts.map +1 -0
- package/dist/Store.js +95 -0
- package/dist/client/apiClientFactory.d.ts +1 -1
- package/dist/client/clientFor.d.ts +5 -5
- package/dist/client/clientFor.d.ts.map +1 -1
- package/dist/client/makeClient.d.ts +36 -36
- package/dist/client/makeClient.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/rpc/MiddlewareMaker.d.ts +2 -2
- package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
- package/dist/rpc/RpcMiddleware.d.ts +2 -2
- package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +40 -0
- package/dist/toast.d.ts +51 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +34 -0
- package/dist/withToast.d.ts +30 -0
- package/dist/withToast.d.ts.map +1 -0
- package/dist/withToast.js +64 -0
- package/package.json +113 -1
- package/src/Emailer.ts +51 -0
- package/src/Model/Repository/Registry.ts +34 -0
- package/src/Model/Repository/ext.ts +375 -0
- package/src/Model/Repository/internal/internal.ts +708 -0
- package/src/Model/Repository/legacy.ts +29 -0
- package/src/Model/Repository/makeRepo.ts +144 -0
- package/src/Model/Repository/service.ts +639 -0
- package/src/Model/Repository/validation.ts +31 -0
- package/src/Model/Repository.ts +6 -0
- package/src/Model/dsl.ts +129 -0
- package/src/Model/filter/filterApi.ts +60 -0
- package/src/Model/filter/types/errors.ts +47 -0
- package/src/Model/filter/types/fields.ts +50 -0
- package/src/Model/filter/types/path/common.ts +404 -0
- package/src/Model/filter/types/path/eager.ts +297 -0
- package/src/Model/filter/types/path/index.ts +4 -0
- package/src/Model/filter/types/utils.ts +128 -0
- package/src/Model/filter/types/validator.ts +46 -0
- package/src/Model/filter/types.ts +6 -0
- package/src/Model/query/dsl.ts +2546 -0
- package/src/Model/query/new-kid-interpreter.ts +484 -0
- package/src/Model/query.ts +13 -0
- package/src/Model.ts +4 -0
- package/src/QueueMaker.ts +19 -0
- package/src/RequestContext.ts +62 -0
- package/src/Schema/ext.ts +6 -6
- package/src/Store.ts +243 -0
- package/src/client/clientFor.ts +8 -8
- package/src/client/makeClient.ts +11 -11
- package/src/index.ts +2 -0
- package/src/rpc/MiddlewareMaker.ts +1 -1
- package/src/rpc/RpcMiddleware.ts +1 -1
- package/src/runtime.ts +56 -0
- package/src/toast.ts +54 -0
- package/src/withToast.ts +133 -0
- package/test/dist/rpc-dynamic-middleware.test.d.ts.map +1 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
|
+
import { identity, pipe } from "effect/Function"
|
|
4
|
+
import * as Match from "effect/Match"
|
|
5
|
+
import * as SchemaAST from "effect/SchemaAST"
|
|
6
|
+
import * as Array from "../../Array.js"
|
|
7
|
+
import { toNonEmptyArray } from "../../Array.js"
|
|
8
|
+
import * as Option from "../../Option.js"
|
|
9
|
+
import * as S from "../../Schema.js"
|
|
10
|
+
import { dropUndefinedT } from "../../utils.js"
|
|
11
|
+
import type { FilterResult } from "../filter/filterApi.js"
|
|
12
|
+
import type { FieldValues } from "../filter/types.js"
|
|
13
|
+
import type { FieldPath } from "../filter/types/path/eager.js"
|
|
14
|
+
import { make, type Q, type QAll } from "../query/dsl.js"
|
|
15
|
+
|
|
16
|
+
export type AggregateIrExpression =
|
|
17
|
+
| { readonly _tag: "agg-count" }
|
|
18
|
+
| { readonly _tag: "agg-count-when"; readonly filter: readonly FilterResult[] }
|
|
19
|
+
| { readonly _tag: "agg-sum"; readonly field: string }
|
|
20
|
+
| { readonly _tag: "agg-min"; readonly field: string }
|
|
21
|
+
| { readonly _tag: "agg-max"; readonly field: string }
|
|
22
|
+
|
|
23
|
+
export type AggregateIrItem =
|
|
24
|
+
| AggregateIrExpression
|
|
25
|
+
| { readonly _tag: "agg-field"; readonly path: string }
|
|
26
|
+
|
|
27
|
+
export type ComputedProjectionMathIrExpression =
|
|
28
|
+
| {
|
|
29
|
+
readonly _tag: "field"
|
|
30
|
+
readonly field: string
|
|
31
|
+
}
|
|
32
|
+
| {
|
|
33
|
+
readonly _tag: "mul"
|
|
34
|
+
readonly left: ComputedProjectionMathIrExpression
|
|
35
|
+
readonly right: ComputedProjectionMathIrExpression
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type ComputedProjectionIrExpression =
|
|
39
|
+
| {
|
|
40
|
+
readonly _tag: "relation-count"
|
|
41
|
+
readonly path: string
|
|
42
|
+
readonly filter: readonly FilterResult[]
|
|
43
|
+
}
|
|
44
|
+
| {
|
|
45
|
+
readonly _tag: "relation-any"
|
|
46
|
+
readonly path: string
|
|
47
|
+
readonly filter: readonly FilterResult[]
|
|
48
|
+
}
|
|
49
|
+
| {
|
|
50
|
+
readonly _tag: "relation-every"
|
|
51
|
+
readonly path: string
|
|
52
|
+
readonly filter: readonly FilterResult[]
|
|
53
|
+
}
|
|
54
|
+
| {
|
|
55
|
+
readonly _tag: "relation-distinct-count"
|
|
56
|
+
readonly path: string
|
|
57
|
+
readonly field: string
|
|
58
|
+
readonly filter: readonly FilterResult[]
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
readonly _tag: "relation-sum"
|
|
62
|
+
readonly path: string
|
|
63
|
+
readonly field: string
|
|
64
|
+
readonly filter: readonly FilterResult[]
|
|
65
|
+
}
|
|
66
|
+
| {
|
|
67
|
+
readonly _tag: "relation-sum-expr"
|
|
68
|
+
readonly path: string
|
|
69
|
+
readonly expression: ComputedProjectionMathIrExpression
|
|
70
|
+
readonly filter: readonly FilterResult[]
|
|
71
|
+
}
|
|
72
|
+
| {
|
|
73
|
+
readonly _tag: "relation-sum-expr-by"
|
|
74
|
+
readonly path: string
|
|
75
|
+
readonly expression: ComputedProjectionMathIrExpression
|
|
76
|
+
readonly unit: string
|
|
77
|
+
readonly filter: readonly FilterResult[]
|
|
78
|
+
}
|
|
79
|
+
| {
|
|
80
|
+
readonly _tag: "relation-sum-expr-normalized"
|
|
81
|
+
readonly path: string
|
|
82
|
+
readonly expression: ComputedProjectionMathIrExpression
|
|
83
|
+
readonly unit: string
|
|
84
|
+
readonly toBase: string
|
|
85
|
+
readonly factors: Readonly<Record<string, number>>
|
|
86
|
+
readonly filter: readonly FilterResult[]
|
|
87
|
+
}
|
|
88
|
+
| {
|
|
89
|
+
readonly _tag: "relation-collect"
|
|
90
|
+
readonly path: string
|
|
91
|
+
readonly field: string
|
|
92
|
+
readonly distinct: boolean
|
|
93
|
+
readonly filter: readonly FilterResult[]
|
|
94
|
+
}
|
|
95
|
+
| {
|
|
96
|
+
readonly _tag: "relation-collect-fields"
|
|
97
|
+
readonly path: string
|
|
98
|
+
readonly fields: readonly string[]
|
|
99
|
+
readonly distinct: boolean
|
|
100
|
+
readonly filter: readonly FilterResult[]
|
|
101
|
+
}
|
|
102
|
+
| {
|
|
103
|
+
readonly _tag: "relation-length"
|
|
104
|
+
readonly path: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type Result<TFieldValues extends FieldValues, A = TFieldValues, R = never> = {
|
|
108
|
+
filter: FilterResult[]
|
|
109
|
+
schema: S.Codec<A, TFieldValues, R> | undefined
|
|
110
|
+
limit: number | undefined
|
|
111
|
+
skip: number | undefined
|
|
112
|
+
order: { key: FieldPath<TFieldValues>; direction: "ASC" | "DESC" }[]
|
|
113
|
+
ttype: "one" | "many" | "count" | undefined
|
|
114
|
+
mode: "collect" | "project" | "transform" | "aggregate" | undefined
|
|
115
|
+
computed: Record<string, ComputedProjectionIrExpression> | undefined
|
|
116
|
+
aggregateMap: Record<string, AggregateIrItem> | undefined
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const interpret = <
|
|
120
|
+
TFieldValues extends FieldValues,
|
|
121
|
+
TFieldValuesRefined extends TFieldValues = TFieldValues,
|
|
122
|
+
A = TFieldValues,
|
|
123
|
+
R = never
|
|
124
|
+
>(_: QAll<TFieldValues, TFieldValuesRefined, A, R>) => {
|
|
125
|
+
const a = _ as Q<TFieldValues>
|
|
126
|
+
|
|
127
|
+
const data: Result<TFieldValues, any, any> = {
|
|
128
|
+
filter: [],
|
|
129
|
+
schema: undefined,
|
|
130
|
+
limit: undefined,
|
|
131
|
+
skip: undefined,
|
|
132
|
+
order: [],
|
|
133
|
+
ttype: undefined,
|
|
134
|
+
mode: undefined,
|
|
135
|
+
computed: undefined,
|
|
136
|
+
aggregateMap: undefined
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const upd = (
|
|
140
|
+
v: Result<TFieldValues, any, any>
|
|
141
|
+
) => {
|
|
142
|
+
data.filter.push(...v.filter)
|
|
143
|
+
data.order.push(...v.order)
|
|
144
|
+
if (v.limit !== undefined) data.limit = v.limit
|
|
145
|
+
if (v.skip !== undefined) data.skip = v.skip
|
|
146
|
+
if (v.ttype !== undefined) data.ttype = v.ttype
|
|
147
|
+
if (v.schema !== undefined) data.schema = v.schema
|
|
148
|
+
if (v.mode !== undefined) data.mode = v.mode
|
|
149
|
+
if (v.computed !== undefined) data.computed = v.computed
|
|
150
|
+
if (v.aggregateMap !== undefined) data.aggregateMap = v.aggregateMap
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const applyPath = (path: string) => (_: FilterResult): FilterResult =>
|
|
154
|
+
_.t === "where" || _.t === "and" || _.t === "or"
|
|
155
|
+
? { ..._, path: `${path}.-1.${_.path}` }
|
|
156
|
+
: { ..._, result: _.result.map(applyPath(path)) }
|
|
157
|
+
|
|
158
|
+
pipe(
|
|
159
|
+
a,
|
|
160
|
+
Match.valueTags({
|
|
161
|
+
value: () => {
|
|
162
|
+
// data.filter.push(value)
|
|
163
|
+
},
|
|
164
|
+
where: ({ current, operation, relation, subPath }) => {
|
|
165
|
+
upd(interpret(current))
|
|
166
|
+
if (typeof operation === "function") {
|
|
167
|
+
data.filter.push(
|
|
168
|
+
{
|
|
169
|
+
t: "where-scope",
|
|
170
|
+
result: interpret(operation(make())).filter.map(subPath ? applyPath(subPath) : identity),
|
|
171
|
+
relation
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
} else {
|
|
175
|
+
data.filter.push(
|
|
176
|
+
{
|
|
177
|
+
t: "where",
|
|
178
|
+
path: operation[0],
|
|
179
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
180
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
and: ({ current, operation, relation }) => {
|
|
186
|
+
upd(interpret(current))
|
|
187
|
+
if (typeof operation === "function") {
|
|
188
|
+
data.filter.push(
|
|
189
|
+
{ t: "and-scope", result: interpret(operation(make())).filter, relation }
|
|
190
|
+
)
|
|
191
|
+
} else {
|
|
192
|
+
data.filter.push(
|
|
193
|
+
{
|
|
194
|
+
t: "and",
|
|
195
|
+
path: operation[0],
|
|
196
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
197
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
or: ({ current, operation, relation }) => {
|
|
203
|
+
upd(interpret(current))
|
|
204
|
+
if (typeof operation === "function") {
|
|
205
|
+
data.filter.push(
|
|
206
|
+
{ t: "or-scope", result: interpret(operation(make())).filter, relation }
|
|
207
|
+
)
|
|
208
|
+
} else {
|
|
209
|
+
data.filter.push(
|
|
210
|
+
{
|
|
211
|
+
t: "or",
|
|
212
|
+
path: operation[0],
|
|
213
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
214
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
one: ({ current }) => {
|
|
220
|
+
upd(interpret(current))
|
|
221
|
+
data.limit = 1
|
|
222
|
+
data.ttype = "one"
|
|
223
|
+
},
|
|
224
|
+
count: ({ current }) => {
|
|
225
|
+
upd(interpret(current))
|
|
226
|
+
data.ttype = "count"
|
|
227
|
+
data.schema = S.Struct({ id: S.String }) as any
|
|
228
|
+
},
|
|
229
|
+
order: ({ current, direction, field }) => {
|
|
230
|
+
upd(interpret(current))
|
|
231
|
+
data.order.push({ key: field, direction })
|
|
232
|
+
},
|
|
233
|
+
page: (v) => {
|
|
234
|
+
upd(interpret(v.current))
|
|
235
|
+
data.limit = v.take
|
|
236
|
+
data.skip = v.skip
|
|
237
|
+
},
|
|
238
|
+
project: (v) => {
|
|
239
|
+
upd(interpret(v.current))
|
|
240
|
+
if (v.mode === "aggregate" && v.aggregateMap) {
|
|
241
|
+
data.schema = v.schema
|
|
242
|
+
data.mode = "aggregate"
|
|
243
|
+
data.aggregateMap = Object.fromEntries(
|
|
244
|
+
Object.entries(v.aggregateMap).map(([key, expression]) => {
|
|
245
|
+
switch (expression._tag) {
|
|
246
|
+
case "agg-field":
|
|
247
|
+
return [key, { _tag: "agg-field" as const, path: expression.path }]
|
|
248
|
+
case "agg-count":
|
|
249
|
+
return [key, { _tag: "agg-count" as const }]
|
|
250
|
+
case "agg-count-when": {
|
|
251
|
+
const filter = interpret(expression.operation(make())).filter
|
|
252
|
+
return [key, { _tag: "agg-count-when" as const, filter }]
|
|
253
|
+
}
|
|
254
|
+
case "agg-sum":
|
|
255
|
+
return [key, { _tag: "agg-sum" as const, field: expression.field }]
|
|
256
|
+
case "agg-min":
|
|
257
|
+
return [key, { _tag: "agg-min" as const, field: expression.field }]
|
|
258
|
+
case "agg-max":
|
|
259
|
+
return [key, { _tag: "agg-max" as const, field: expression.field }]
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
)
|
|
263
|
+
return
|
|
264
|
+
}
|
|
265
|
+
if (v.computed && v.mode === "transform") {
|
|
266
|
+
throw new Error("Computed projections require mode 'project' or 'collect', not 'transform'")
|
|
267
|
+
}
|
|
268
|
+
data.schema = v.schema
|
|
269
|
+
data.mode = v.computed
|
|
270
|
+
? v.mode === "collect" ? "collect" : "project"
|
|
271
|
+
: v.mode
|
|
272
|
+
data.computed = v.computed
|
|
273
|
+
? Object.fromEntries(
|
|
274
|
+
Object.entries(v.computed).map(([key, expression]) => {
|
|
275
|
+
const e = expression
|
|
276
|
+
const op = "operation" in e ? e.operation : undefined
|
|
277
|
+
const filter = op ? interpret(op(make())).filter.map(applyPath(e.path)) : []
|
|
278
|
+
switch (e._tag) {
|
|
279
|
+
case "relation-count":
|
|
280
|
+
case "relation-any":
|
|
281
|
+
case "relation-every":
|
|
282
|
+
return [key, { _tag: e._tag, path: e.path, filter } as ComputedProjectionIrExpression]
|
|
283
|
+
case "relation-distinct-count":
|
|
284
|
+
case "relation-sum":
|
|
285
|
+
return [
|
|
286
|
+
key,
|
|
287
|
+
{ _tag: e._tag, path: e.path, field: e.field, filter } as ComputedProjectionIrExpression
|
|
288
|
+
]
|
|
289
|
+
case "relation-sum-expr":
|
|
290
|
+
return [
|
|
291
|
+
key,
|
|
292
|
+
{ _tag: e._tag, path: e.path, expression: e.expression, filter } as ComputedProjectionIrExpression
|
|
293
|
+
]
|
|
294
|
+
case "relation-sum-expr-by":
|
|
295
|
+
return [
|
|
296
|
+
key,
|
|
297
|
+
{
|
|
298
|
+
_tag: e._tag,
|
|
299
|
+
path: e.path,
|
|
300
|
+
expression: e.expression,
|
|
301
|
+
unit: e.unit,
|
|
302
|
+
filter
|
|
303
|
+
} as ComputedProjectionIrExpression
|
|
304
|
+
]
|
|
305
|
+
case "relation-sum-expr-normalized":
|
|
306
|
+
return [
|
|
307
|
+
key,
|
|
308
|
+
{
|
|
309
|
+
_tag: e._tag,
|
|
310
|
+
path: e.path,
|
|
311
|
+
expression: e.expression,
|
|
312
|
+
unit: e.unit,
|
|
313
|
+
toBase: e.toBase,
|
|
314
|
+
factors: e.factors,
|
|
315
|
+
filter
|
|
316
|
+
} as ComputedProjectionIrExpression
|
|
317
|
+
]
|
|
318
|
+
case "relation-collect":
|
|
319
|
+
return [
|
|
320
|
+
key,
|
|
321
|
+
{
|
|
322
|
+
_tag: e._tag,
|
|
323
|
+
path: e.path,
|
|
324
|
+
field: e.field,
|
|
325
|
+
distinct: e.distinct,
|
|
326
|
+
filter
|
|
327
|
+
} as ComputedProjectionIrExpression
|
|
328
|
+
]
|
|
329
|
+
case "relation-collect-fields":
|
|
330
|
+
return [
|
|
331
|
+
key,
|
|
332
|
+
{
|
|
333
|
+
_tag: e._tag,
|
|
334
|
+
path: e.path,
|
|
335
|
+
fields: e.fields,
|
|
336
|
+
distinct: e.distinct,
|
|
337
|
+
filter
|
|
338
|
+
} as ComputedProjectionIrExpression
|
|
339
|
+
]
|
|
340
|
+
case "relation-length":
|
|
341
|
+
return [key, { _tag: e._tag, path: e.path } as ComputedProjectionIrExpression]
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
)
|
|
345
|
+
: undefined
|
|
346
|
+
}
|
|
347
|
+
})
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
return data
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const walkTransformation = (t: S.AST.AST): S.AST.AST => {
|
|
354
|
+
if (S.AST.isDeclaration(t) && t.typeParameters.length > 0) {
|
|
355
|
+
return walkTransformation(t.typeParameters[0]!)
|
|
356
|
+
}
|
|
357
|
+
return t
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export const toFilter = <
|
|
361
|
+
TFieldValues extends FieldValues,
|
|
362
|
+
A,
|
|
363
|
+
R,
|
|
364
|
+
TFieldValuesRefined extends TFieldValues = TFieldValues
|
|
365
|
+
>(
|
|
366
|
+
q: QAll<TFieldValues, TFieldValuesRefined, A, R>,
|
|
367
|
+
baseSchema?: S.Schema<unknown>
|
|
368
|
+
) => {
|
|
369
|
+
// TODO: Native interpreter for each db adapter, instead of the intermediate "new-kid" format
|
|
370
|
+
const a = interpret(q)
|
|
371
|
+
|
|
372
|
+
// Aggregate mode: build select entirely from aggregateMap (no schema-driven field list)
|
|
373
|
+
if (a.mode === "aggregate" && a.aggregateMap) {
|
|
374
|
+
const aggSelect = Object.entries(a.aggregateMap).map(([key, item]) => {
|
|
375
|
+
if (item._tag === "agg-field") {
|
|
376
|
+
return { key, path: item.path }
|
|
377
|
+
}
|
|
378
|
+
return { key, aggregate: item }
|
|
379
|
+
})
|
|
380
|
+
return dropUndefinedT({
|
|
381
|
+
t: null as unknown as TFieldValues,
|
|
382
|
+
limit: a.limit,
|
|
383
|
+
skip: a.skip,
|
|
384
|
+
select: Option.getOrUndefined(toNonEmptyArray(aggSelect)) as any,
|
|
385
|
+
schema: a.schema,
|
|
386
|
+
computed: undefined,
|
|
387
|
+
order: Option.getOrUndefined(toNonEmptyArray(a.order)),
|
|
388
|
+
ttype: a.ttype,
|
|
389
|
+
mode: "aggregate" as const,
|
|
390
|
+
filter: a.filter.length ? a.filter : undefined
|
|
391
|
+
})
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const schema = a.schema
|
|
395
|
+
let select: (keyof TFieldValues | { key: string; subKeys: string[] } | {
|
|
396
|
+
key: string
|
|
397
|
+
computed: ComputedProjectionIrExpression
|
|
398
|
+
})[] = []
|
|
399
|
+
// TODO: support more complex (nested) schemas?
|
|
400
|
+
if (schema) {
|
|
401
|
+
const t = walkTransformation(SchemaAST.toEncoded(schema.ast))
|
|
402
|
+
if (S.AST.isObjects(t)) {
|
|
403
|
+
select = t.propertySignatures.map((_) => _.name as string)
|
|
404
|
+
for (const prop of t.propertySignatures) {
|
|
405
|
+
if (S.AST.isArrays(prop.type)) {
|
|
406
|
+
// make sure we only select when there are actually type literals in the tuple...
|
|
407
|
+
// otherwise we might be dealing with strings etc.
|
|
408
|
+
// TODO; be more strict, can't support arrays with unions that have non TypeLiteral members etc..
|
|
409
|
+
const arraySelect = {
|
|
410
|
+
key: prop.name as string,
|
|
411
|
+
subKeys: Array.flatMap(
|
|
412
|
+
prop.type.rest,
|
|
413
|
+
(x) => {
|
|
414
|
+
const t = walkTransformation(x)
|
|
415
|
+
return S.AST.isObjects(t) ? t.propertySignatures.map((y) => y.name as string) : []
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
if (arraySelect.subKeys.length > 0) {
|
|
420
|
+
select.push(arraySelect)
|
|
421
|
+
// make sure we don't double select?
|
|
422
|
+
if (select.includes(prop.name as string)) {
|
|
423
|
+
select.splice(select.indexOf(prop.name as string), 1)
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const computed = a.computed
|
|
431
|
+
const getSelectKey = (_: (typeof select)[number]) => {
|
|
432
|
+
if (typeof _ === "string") {
|
|
433
|
+
return _
|
|
434
|
+
}
|
|
435
|
+
if (typeof _ === "object" && _ !== null && "key" in _) {
|
|
436
|
+
return _.key
|
|
437
|
+
}
|
|
438
|
+
return String(_)
|
|
439
|
+
}
|
|
440
|
+
const schemaKeys = select.map(getSelectKey)
|
|
441
|
+
const nonEncodedSchemaKeys = (() => {
|
|
442
|
+
if (!baseSchema) {
|
|
443
|
+
return [] as string[]
|
|
444
|
+
}
|
|
445
|
+
const encoded = walkTransformation(SchemaAST.toEncoded(baseSchema.ast))
|
|
446
|
+
if (!S.AST.isObjects(encoded)) {
|
|
447
|
+
return [] as string[]
|
|
448
|
+
}
|
|
449
|
+
const encodedKeys = encoded.propertySignatures.map((_) => _.name as string)
|
|
450
|
+
return schemaKeys.filter((key) => !encodedKeys.includes(key))
|
|
451
|
+
})()
|
|
452
|
+
const missingComputedKeys = nonEncodedSchemaKeys.filter((key) => !(computed && key in computed))
|
|
453
|
+
|
|
454
|
+
if (Array.isArrayNonEmpty(missingComputedKeys)) {
|
|
455
|
+
throw new Error(`Missing computed projections for schema keys: ${missingComputedKeys.join(", ")}`)
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (computed) {
|
|
459
|
+
const computedKeys = Object.keys(computed)
|
|
460
|
+
const extraComputedKeys = computedKeys.filter((key) => !schemaKeys.includes(key))
|
|
461
|
+
if (Array.isArrayNonEmpty(extraComputedKeys)) {
|
|
462
|
+
throw new Error(`Computed projection keys must exist in projection schema: ${extraComputedKeys.join(", ")}`)
|
|
463
|
+
}
|
|
464
|
+
select = select.filter((_) => {
|
|
465
|
+
const key = getSelectKey(_)
|
|
466
|
+
return !(key in computed)
|
|
467
|
+
})
|
|
468
|
+
select.push(...Object.entries(computed).map(([key, expression]) => ({ key, computed: expression })))
|
|
469
|
+
}
|
|
470
|
+
return dropUndefinedT({
|
|
471
|
+
t: null as unknown as TFieldValues,
|
|
472
|
+
limit: a.limit,
|
|
473
|
+
skip: a.skip,
|
|
474
|
+
select: Option.getOrUndefined(toNonEmptyArray(select)),
|
|
475
|
+
schema,
|
|
476
|
+
computed,
|
|
477
|
+
order: Option.getOrUndefined(toNonEmptyArray(a.order)),
|
|
478
|
+
ttype: a.ttype,
|
|
479
|
+
mode: a.mode ?? "transform",
|
|
480
|
+
filter: a.filter.length
|
|
481
|
+
? a.filter
|
|
482
|
+
: undefined
|
|
483
|
+
})
|
|
484
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./query/dsl.js"
|
|
2
|
+
export * from "./query/new-kid-interpreter.js"
|
|
3
|
+
|
|
4
|
+
export interface RawQuery<Encoded, Out> {
|
|
5
|
+
cosmos: (vals: { name: string }) => {
|
|
6
|
+
query: string
|
|
7
|
+
parameters: {
|
|
8
|
+
name: string
|
|
9
|
+
value: any
|
|
10
|
+
}[]
|
|
11
|
+
}
|
|
12
|
+
memory: (t: readonly Encoded[]) => readonly Out[]
|
|
13
|
+
}
|
package/src/Model.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as Scope from "effect/Scope"
|
|
2
|
+
import type { NonEmptyReadonlyArray } from "./Array.js"
|
|
3
|
+
import type * as Effect from "./Effect.js"
|
|
4
|
+
import { RequestContext } from "./RequestContext.js"
|
|
5
|
+
|
|
6
|
+
export interface QueueBase<Evt, DrainEvt> {
|
|
7
|
+
drain: <DrainE, DrainR>(
|
|
8
|
+
makeHandleEvent: (ks: DrainEvt) => Effect.Effect<void, DrainE, DrainR>,
|
|
9
|
+
sessionId?: string
|
|
10
|
+
) => Effect.Effect<never, never, Scope.Scope | DrainR>
|
|
11
|
+
publish: (
|
|
12
|
+
...messages: NonEmptyReadonlyArray<Evt>
|
|
13
|
+
) => Effect.Effect<void>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface QueueMakerOps {}
|
|
17
|
+
export const QueueMaker: QueueMakerOps = {}
|
|
18
|
+
|
|
19
|
+
export const QueueMeta = RequestContext
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as Context from "./Context.js"
|
|
2
|
+
import { UserProfileId } from "./ids.js"
|
|
3
|
+
import * as S from "./Schema.js"
|
|
4
|
+
import { NonEmptyString255 } from "./Schema.js"
|
|
5
|
+
|
|
6
|
+
export const Locale = S.Literals(["en", "de"])
|
|
7
|
+
export type Locale = typeof Locale.Type
|
|
8
|
+
|
|
9
|
+
export class LocaleRef extends Context.Reference("Locale", { defaultValue: (): Locale => "en" }) {}
|
|
10
|
+
|
|
11
|
+
export class RequestContext extends S.Opaque<
|
|
12
|
+
RequestContext,
|
|
13
|
+
RequestContext.Encoded
|
|
14
|
+
>()(S.Struct({
|
|
15
|
+
span: S.Struct({
|
|
16
|
+
traceId: S.String,
|
|
17
|
+
spanId: S.String,
|
|
18
|
+
sampled: S.Boolean
|
|
19
|
+
}),
|
|
20
|
+
name: NonEmptyString255,
|
|
21
|
+
locale: Locale,
|
|
22
|
+
sourceId: S.optional(NonEmptyString255), // TODO?
|
|
23
|
+
namespace: NonEmptyString255,
|
|
24
|
+
/** @deprecated */
|
|
25
|
+
userProfile: S.optional(S.Struct({ sub: UserProfileId })) //
|
|
26
|
+
})) {
|
|
27
|
+
// static Tag = Context.Tag<RequestContext>()
|
|
28
|
+
|
|
29
|
+
static toMonitoring(this: void, self: RequestContext) {
|
|
30
|
+
return {
|
|
31
|
+
operationName: self.name,
|
|
32
|
+
locale: self.locale
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const spanAttributes = (ctx: Pick<RequestContext, "locale" | "namespace"> & Partial<RequestContext>) => ({
|
|
38
|
+
"code.function.name": ctx.name,
|
|
39
|
+
"app.locale": ctx.locale,
|
|
40
|
+
"app.tenant.id": ctx.namespace,
|
|
41
|
+
...ctx.sourceId ? { "client.id": ctx.sourceId } : {},
|
|
42
|
+
...(ctx.userProfile?.sub
|
|
43
|
+
? {
|
|
44
|
+
"user.id": ctx
|
|
45
|
+
.userProfile
|
|
46
|
+
.sub,
|
|
47
|
+
"user.roles": "roles" in ctx
|
|
48
|
+
.userProfile
|
|
49
|
+
? ctx.userProfile.roles
|
|
50
|
+
: undefined
|
|
51
|
+
}
|
|
52
|
+
: {})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// codegen:start {preset: model}
|
|
56
|
+
//
|
|
57
|
+
export namespace RequestContext {
|
|
58
|
+
export interface Encoded extends S.StructNestedEncoded<typeof RequestContext> {}
|
|
59
|
+
}
|
|
60
|
+
//
|
|
61
|
+
// codegen:end
|
|
62
|
+
//
|
package/src/Schema/ext.ts
CHANGED
|
@@ -292,12 +292,12 @@ export const ReadonlySetFromArray = <ValueSchema extends S.Top>(value: ValueSche
|
|
|
292
292
|
const from = S
|
|
293
293
|
.Array(value)
|
|
294
294
|
.annotate({ ...concurrencyUnbounded, expected: "an array of unique items that will be decoded as a ReadonlySet" })
|
|
295
|
-
const to = S.instanceOf(Set) as S.instanceOf<ReadonlySet<
|
|
295
|
+
const to = S.instanceOf(Set) as S.instanceOf<ReadonlySet<ValueSchema["Type"]>>
|
|
296
296
|
const schema = from.pipe(
|
|
297
297
|
S.decodeTo(
|
|
298
298
|
to,
|
|
299
299
|
SchemaTransformation.transform({
|
|
300
|
-
decode: (arr) => new Set(arr) as ReadonlySet<
|
|
300
|
+
decode: (arr) => new Set(arr) as ReadonlySet<ValueSchema["Type"]>,
|
|
301
301
|
encode: (set) => [...set]
|
|
302
302
|
})
|
|
303
303
|
)
|
|
@@ -319,7 +319,7 @@ export const ReadonlyMapFromArray = <KeySchema extends S.Top, ValueSchema extend
|
|
|
319
319
|
expected: "an array of key-value tuples that will be decoded as a ReadonlyMap"
|
|
320
320
|
})
|
|
321
321
|
const to = S.instanceOf(Map) as S.instanceOf<
|
|
322
|
-
ReadonlyMap<
|
|
322
|
+
ReadonlyMap<KeySchema["Type"], ValueSchema["Type"]>
|
|
323
323
|
>
|
|
324
324
|
const schema = from.pipe(
|
|
325
325
|
S.decodeTo(
|
|
@@ -327,7 +327,7 @@ export const ReadonlyMapFromArray = <KeySchema extends S.Top, ValueSchema extend
|
|
|
327
327
|
SchemaTransformation.transform({
|
|
328
328
|
decode: (
|
|
329
329
|
arr
|
|
330
|
-
) => new Map(arr) as ReadonlyMap<
|
|
330
|
+
) => new Map(arr) as ReadonlyMap<KeySchema["Type"], ValueSchema["Type"]>,
|
|
331
331
|
encode: (
|
|
332
332
|
map
|
|
333
333
|
) => [...map.entries()] as any // fu
|
|
@@ -350,7 +350,7 @@ export const ReadonlySet = <ValueSchema extends S.Top>(value: ValueSchema) =>
|
|
|
350
350
|
* note.
|
|
351
351
|
*/
|
|
352
352
|
withConstructorDefault: s.pipe(
|
|
353
|
-
S.withConstructorDefault(Effect.sync(() => new Set<
|
|
353
|
+
S.withConstructorDefault(Effect.sync(() => new Set<ValueSchema["Type"]>()))
|
|
354
354
|
),
|
|
355
355
|
/**
|
|
356
356
|
* Decode-time default `new Set()`. **Discouraged for persisted
|
|
@@ -360,7 +360,7 @@ export const ReadonlySet = <ValueSchema extends S.Top>(value: ValueSchema) =>
|
|
|
360
360
|
* decode-time fallback. See file-level note.
|
|
361
361
|
*/
|
|
362
362
|
withDecodingDefaultType: s.pipe(
|
|
363
|
-
S.withDecodingDefaultType(Effect.sync(() => new Set<
|
|
363
|
+
S.withDecodingDefaultType(Effect.sync(() => new Set<ValueSchema["Type"]>()))
|
|
364
364
|
)
|
|
365
365
|
})
|
|
366
366
|
)
|