@effect-app/infra 0.200.3 → 0.201.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.
- package/CHANGELOG.md +19 -0
- package/_cjs/services/RepositoryBase.cjs +7 -3
- package/_cjs/services/RepositoryBase.cjs.map +1 -1
- package/_cjs/services/query/dsl.cjs +5 -5
- package/_cjs/services/query/dsl.cjs.map +1 -1
- package/_cjs/services/query/new-kid-interpreter.cjs +37 -32
- package/_cjs/services/query/new-kid-interpreter.cjs.map +1 -1
- package/_cjs/services/query.test.cjs +59 -22
- package/_cjs/services/query.test.cjs.map +1 -1
- package/dist/api/routing/match.d.ts +1 -1
- package/dist/services/RepositoryBase.d.ts +3 -3
- package/dist/services/RepositoryBase.d.ts.map +1 -1
- package/dist/services/RepositoryBase.js +11 -5
- package/dist/services/query/dsl.d.ts +3 -3
- package/dist/services/query/dsl.d.ts.map +1 -1
- package/dist/services/query/dsl.js +4 -4
- package/dist/services/query/new-kid-interpreter.d.ts +16 -12
- package/dist/services/query/new-kid-interpreter.d.ts.map +1 -1
- package/dist/services/query/new-kid-interpreter.js +33 -35
- package/dist/services/query.test.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/services/RepositoryBase.ts +49 -4
- package/src/services/query/dsl.ts +6 -6
- package/src/services/query/new-kid-interpreter.ts +58 -84
- package/src/services/query.test.ts +72 -26
|
@@ -26,13 +26,14 @@ import { makeFilters } from "@effect-app/infra/filter"
|
|
|
26
26
|
import type { ParseResult, Schema } from "@effect-app/schema"
|
|
27
27
|
import { NonNegativeInt } from "@effect-app/schema"
|
|
28
28
|
import type { Context, NonEmptyArray, NonEmptyReadonlyArray } from "effect-app"
|
|
29
|
-
import { Chunk, Effect, flow, Option, pipe, PubSub, ReadonlyArray, S } from "effect-app"
|
|
29
|
+
import { Chunk, Effect, flow, Option, pipe, PubSub, ReadonlyArray, S, Unify } from "effect-app"
|
|
30
30
|
import { runTerm } from "effect-app/Pure"
|
|
31
31
|
import type { FixEnv, PureEnv } from "effect-app/Pure"
|
|
32
32
|
import { assignTag } from "effect-app/service"
|
|
33
|
+
import type { NoInfer } from "effect/Types"
|
|
33
34
|
import { type InvalidStateError, NotFoundError, type OptimisticConcurrencyException } from "../errors.js"
|
|
34
35
|
import type { FieldValues } from "../filter/types.js"
|
|
35
|
-
import { make as makeQuery, page
|
|
36
|
+
import { make as makeQuery, page } from "./query.js"
|
|
36
37
|
import type { QAll, Query, QueryEnd, QueryProjection, QueryWhere } from "./query.js"
|
|
37
38
|
import * as Q2 from "./query.js"
|
|
38
39
|
import { ContextMapContainer } from "./Store/ContextMapContainer.js"
|
|
@@ -198,7 +199,7 @@ export class RepositoryBaseC3<
|
|
|
198
199
|
q: (q: Query<Omit<PM, "_etag">>) => Query<Omit<PM, "_etag">> | QueryEnd<Omit<PM, "_etag">>,
|
|
199
200
|
pure: Effect<A, E2, FixEnv<R2, Evt, T, T2>>
|
|
200
201
|
) =>
|
|
201
|
-
this.q2(flow(q, page({
|
|
202
|
+
this.q2(flow(q, page({ take: 1 }))).pipe(
|
|
202
203
|
Effect.map(ReadonlyArray.toNonEmptyArray),
|
|
203
204
|
Effect.flatMap(Effect.mapError(() => new NotFoundError({ type: this.itemType, id: q }))),
|
|
204
205
|
Effect.andThen((_) => saveWithPure_(this, _[0], pure))
|
|
@@ -209,7 +210,7 @@ export class RepositoryBaseC3<
|
|
|
209
210
|
pure: Effect<A, E2, FixEnv<R2, Evt, readonly T[], readonly T2[]>>,
|
|
210
211
|
batchSize?: number
|
|
211
212
|
) =>
|
|
212
|
-
this.q2(flow(q, page({
|
|
213
|
+
this.q2(flow(q, page({ take: 1 }))).pipe(
|
|
213
214
|
Effect.andThen((_) =>
|
|
214
215
|
batchSize === undefined
|
|
215
216
|
? saveManyWithPure_(this, _, pure)
|
|
@@ -785,6 +786,50 @@ export function makeRepo<
|
|
|
785
786
|
})
|
|
786
787
|
}
|
|
787
788
|
|
|
789
|
+
const query: {
|
|
790
|
+
<
|
|
791
|
+
T extends { id: unknown },
|
|
792
|
+
PM extends PersistenceModelType<string>,
|
|
793
|
+
Evt,
|
|
794
|
+
ItemType extends string,
|
|
795
|
+
A,
|
|
796
|
+
R,
|
|
797
|
+
From extends FieldValues
|
|
798
|
+
>(
|
|
799
|
+
repo: Repository<T, PM, Evt, ItemType>,
|
|
800
|
+
q: QueryProjection<PM extends From ? From : never, A, R>
|
|
801
|
+
): Effect.Effect<readonly A[], S.ParseResult.ParseError, R>
|
|
802
|
+
<
|
|
803
|
+
T extends { id: unknown },
|
|
804
|
+
PM extends PersistenceModelType<string>,
|
|
805
|
+
Evt,
|
|
806
|
+
ItemType extends string,
|
|
807
|
+
A,
|
|
808
|
+
R
|
|
809
|
+
>(
|
|
810
|
+
repo: Repository<T, PM, Evt, ItemType>,
|
|
811
|
+
q: QAll<NoInfer<PM>, A, R>
|
|
812
|
+
): Effect.Effect<readonly A[], never, R>
|
|
813
|
+
} = (<
|
|
814
|
+
T extends { id: unknown },
|
|
815
|
+
PM extends PersistenceModelType<string>,
|
|
816
|
+
Evt,
|
|
817
|
+
ItemType extends string,
|
|
818
|
+
A,
|
|
819
|
+
R
|
|
820
|
+
>(repo: Repository<T, PM, Evt, ItemType>, q: QAll<PM, A, R>) => {
|
|
821
|
+
const a = Q2.toFilter(q)
|
|
822
|
+
return Effect.flatMap(
|
|
823
|
+
repo.utils.filter(a),
|
|
824
|
+
(_) =>
|
|
825
|
+
Unify.unify(
|
|
826
|
+
a.schema
|
|
827
|
+
? repo.utils.parseMany2(_, a.schema as any)
|
|
828
|
+
: repo.utils.parseMany(_)
|
|
829
|
+
)
|
|
830
|
+
)
|
|
831
|
+
}) as any
|
|
832
|
+
|
|
788
833
|
const r: Repository<T, PM, Evt, ItemType> = {
|
|
789
834
|
/**
|
|
790
835
|
* @internal
|
|
@@ -84,7 +84,7 @@ export class Or<TFieldValues extends FieldValues> extends Data.TaggedClass("or")
|
|
|
84
84
|
|
|
85
85
|
export class Page<TFieldValues extends FieldValues> extends Data.TaggedClass("page")<{
|
|
86
86
|
current: Query<TFieldValues> | QueryWhere<TFieldValues> | QueryEnd<TFieldValues>
|
|
87
|
-
|
|
87
|
+
take?: number | undefined
|
|
88
88
|
skip?: number | undefined
|
|
89
89
|
}> implements QueryEnd<TFieldValues> {
|
|
90
90
|
readonly [QId]!: any
|
|
@@ -120,17 +120,17 @@ export const or: FilterContinuation = (...operation: any[]) => (current: any) =>
|
|
|
120
120
|
|
|
121
121
|
export const order: <TFieldValues extends FieldValues, TFieldName extends FieldPath<TFieldValues>>(
|
|
122
122
|
field: TFieldName,
|
|
123
|
-
|
|
123
|
+
direction?: "ASC" | "DESC"
|
|
124
124
|
) => (current: Query<TFieldValues> | QueryWhere<TFieldValues> | QueryEnd<TFieldValues>) => QueryEnd<TFieldValues> =
|
|
125
|
-
(field,
|
|
125
|
+
(field, direction = "ASC") => (current) => new Order({ current, field, direction })
|
|
126
126
|
|
|
127
127
|
export const page: <TFieldValues extends FieldValues>(
|
|
128
|
-
page: {
|
|
128
|
+
page: { skip?: number; take?: number }
|
|
129
129
|
) => (current: Query<TFieldValues> | QueryWhere<TFieldValues> | QueryEnd<TFieldValues>) => QueryEnd<TFieldValues> =
|
|
130
|
-
({
|
|
130
|
+
({ skip, take }) => (current) =>
|
|
131
131
|
new Page({
|
|
132
132
|
current,
|
|
133
|
-
|
|
133
|
+
take,
|
|
134
134
|
skip
|
|
135
135
|
})
|
|
136
136
|
|
|
@@ -1,41 +1,51 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
3
|
import { toNonEmptyArray } from "@effect-app/core/Array"
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { Match, Option, pipe, S } from "effect-app"
|
|
5
|
+
import { dropUndefinedT } from "effect-app/utils"
|
|
6
6
|
import type { FieldValues } from "../../filter/types.js"
|
|
7
7
|
import type { FieldPath } from "../../filter/types/path/eager.js"
|
|
8
|
-
import { make, type Q, type QAll
|
|
9
|
-
import type { Repository } from "../Repository.js"
|
|
10
|
-
import type { PersistenceModelType } from "../Store.js"
|
|
8
|
+
import { make, type Q, type QAll } from "../query.js"
|
|
11
9
|
import type { FilterResult, QueryBuilder } from "../Store/filterApi/query.js"
|
|
12
10
|
|
|
11
|
+
type Result<TFieldValues extends FieldValues, A = TFieldValues, R = never> = {
|
|
12
|
+
filter: FilterResult[]
|
|
13
|
+
schema: S.Schema<A, TFieldValues, R> | undefined
|
|
14
|
+
limit: number | undefined
|
|
15
|
+
skip: number | undefined
|
|
16
|
+
order: { key: FieldPath<TFieldValues>; direction: "ASC" | "DESC" }[]
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
const interpret = <TFieldValues extends FieldValues, A = TFieldValues, R = never>(_: QAll<TFieldValues, A, R>) => {
|
|
14
|
-
const values: FilterResult[] = []
|
|
15
20
|
const a = _ as Q<TFieldValues>
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
const data: Result<TFieldValues, any, any> = {
|
|
23
|
+
filter: [],
|
|
24
|
+
schema: undefined,
|
|
25
|
+
limit: undefined,
|
|
26
|
+
skip: undefined,
|
|
27
|
+
order: []
|
|
28
|
+
}
|
|
21
29
|
|
|
22
|
-
const upd = (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
const upd = (
|
|
31
|
+
v: Result<TFieldValues, any, any>
|
|
32
|
+
) => {
|
|
33
|
+
data.filter.push(...v.filter)
|
|
34
|
+
data.order.push(...v.order)
|
|
35
|
+
data.limit = v.limit
|
|
36
|
+
data.skip = v.skip
|
|
37
|
+
data.schema = v.schema
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
pipe(
|
|
31
41
|
a,
|
|
32
42
|
Match.valueTags({
|
|
33
43
|
value: () => {
|
|
34
|
-
//
|
|
44
|
+
// data.filter.push(value)
|
|
35
45
|
},
|
|
36
46
|
where: ({ current, operation }) => {
|
|
37
47
|
upd(interpret(current))
|
|
38
|
-
|
|
48
|
+
data.filter.push(
|
|
39
49
|
{
|
|
40
50
|
t: "where",
|
|
41
51
|
path: operation[0],
|
|
@@ -47,11 +57,11 @@ const interpret = <TFieldValues extends FieldValues, A = TFieldValues, R = never
|
|
|
47
57
|
and: ({ current, operation }) => {
|
|
48
58
|
upd(interpret(current))
|
|
49
59
|
if (typeof operation === "function") {
|
|
50
|
-
|
|
60
|
+
data.filter.push(
|
|
51
61
|
{ t: "and-scope", result: interpret(operation(make())).filter }
|
|
52
62
|
)
|
|
53
63
|
} else {
|
|
54
|
-
|
|
64
|
+
data.filter.push(
|
|
55
65
|
{
|
|
56
66
|
t: "and",
|
|
57
67
|
path: operation[0],
|
|
@@ -64,11 +74,11 @@ const interpret = <TFieldValues extends FieldValues, A = TFieldValues, R = never
|
|
|
64
74
|
or: ({ current, operation }) => {
|
|
65
75
|
upd(interpret(current))
|
|
66
76
|
if (typeof operation === "function") {
|
|
67
|
-
|
|
77
|
+
data.filter.push(
|
|
68
78
|
{ t: "or-scope", result: interpret(operation(make())).filter }
|
|
69
79
|
)
|
|
70
80
|
} else {
|
|
71
|
-
|
|
81
|
+
data.filter.push(
|
|
72
82
|
{
|
|
73
83
|
t: "or",
|
|
74
84
|
path: operation[0],
|
|
@@ -78,66 +88,36 @@ const interpret = <TFieldValues extends FieldValues, A = TFieldValues, R = never
|
|
|
78
88
|
)
|
|
79
89
|
}
|
|
80
90
|
},
|
|
81
|
-
order: ({ current }) => {
|
|
91
|
+
order: ({ current, direction, field }) => {
|
|
82
92
|
upd(interpret(current))
|
|
93
|
+
data.order.push({ key: field, direction })
|
|
83
94
|
},
|
|
84
95
|
page: (v) => {
|
|
85
96
|
upd(interpret(v.current))
|
|
86
|
-
limit = v.
|
|
87
|
-
skip = v.skip
|
|
97
|
+
data.limit = v.take
|
|
98
|
+
data.skip = v.skip
|
|
88
99
|
},
|
|
89
100
|
project: (v) => {
|
|
90
101
|
upd(interpret(v.current))
|
|
91
|
-
schema = v.schema
|
|
102
|
+
data.schema = v.schema
|
|
92
103
|
}
|
|
93
104
|
})
|
|
94
105
|
)
|
|
95
106
|
|
|
96
|
-
return
|
|
97
|
-
filter: values,
|
|
98
|
-
limit,
|
|
99
|
-
skip,
|
|
100
|
-
schema,
|
|
101
|
-
order
|
|
102
|
-
}
|
|
107
|
+
return data
|
|
103
108
|
}
|
|
104
109
|
|
|
105
|
-
export const
|
|
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,
|
|
110
|
+
export const toFilter = <
|
|
111
|
+
TFieldValues extends FieldValues,
|
|
134
112
|
A,
|
|
135
113
|
R
|
|
136
|
-
>(
|
|
114
|
+
>(
|
|
115
|
+
q: QAll<TFieldValues, A, R>
|
|
116
|
+
) => {
|
|
137
117
|
// TODO: Native interpreter for each db adapter, instead of the intermediate "new-kid" format
|
|
138
118
|
const a = interpret(q)
|
|
139
119
|
const schema = a.schema
|
|
140
|
-
let select: (keyof
|
|
120
|
+
let select: (keyof TFieldValues)[] = []
|
|
141
121
|
if (schema) {
|
|
142
122
|
let t = schema.ast
|
|
143
123
|
if (S.AST.isTransform(t)) {
|
|
@@ -147,23 +127,17 @@ export const query: {
|
|
|
147
127
|
select = t.propertySignatures.map((_) => _.name) as any
|
|
148
128
|
}
|
|
149
129
|
}
|
|
150
|
-
return
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
schema
|
|
165
|
-
? repo.utils.parseMany2(_, schema as any)
|
|
166
|
-
: repo.utils.parseMany(_)
|
|
167
|
-
)
|
|
168
|
-
)
|
|
169
|
-
}) as any
|
|
130
|
+
return dropUndefinedT({
|
|
131
|
+
limit: a.limit,
|
|
132
|
+
skip: a.skip,
|
|
133
|
+
select: Option.getOrUndefined(toNonEmptyArray(select)),
|
|
134
|
+
schema,
|
|
135
|
+
order: Option.getOrUndefined(toNonEmptyArray(a.order)),
|
|
136
|
+
filter: a.filter.length
|
|
137
|
+
? {
|
|
138
|
+
type: "new-kid" as const,
|
|
139
|
+
build: () => a.filter
|
|
140
|
+
} as QueryBuilder<any>
|
|
141
|
+
: undefined
|
|
142
|
+
})
|
|
143
|
+
}
|
|
@@ -1,37 +1,83 @@
|
|
|
1
1
|
import { Effect, flow, pipe, S } from "effect-app"
|
|
2
|
-
import {
|
|
2
|
+
import { TagClassMakeId } from "effect-app/service"
|
|
3
|
+
import { pick } from "effect-app/utils"
|
|
4
|
+
import { inspect } from "util"
|
|
5
|
+
import { and, make, or, order, page, project, toFilter, where } from "./query.js"
|
|
3
6
|
import { RepositoryDefaultImpl } from "./RepositoryBase.js"
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
import { memFilter } from "./Store/Memory.js"
|
|
8
|
+
|
|
9
|
+
export class s
|
|
10
|
+
extends S.Class<s>()({ id: S.StringId.withDefault, displayName: S.NonEmptyString255, n: S.Date.withDefault })
|
|
11
|
+
{}
|
|
12
|
+
export declare namespace s {
|
|
13
|
+
export type From = S.Schema.From<typeof s>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const MakeSomeService = Effect.succeed({ a: 1 })
|
|
17
|
+
export class SomeService extends TagClassMakeId("SomeService", MakeSomeService)<SomeService>() {}
|
|
18
|
+
|
|
19
|
+
const q = pipe(
|
|
20
|
+
make<s.From>(), // provided automatically inside Repo.q2()
|
|
16
21
|
where("displayName", "Verona"),
|
|
17
22
|
or(flow(
|
|
18
|
-
where("displayName", "Riley")
|
|
19
|
-
|
|
23
|
+
where("displayName", "Riley"),
|
|
24
|
+
and("n", "gt", "2021-01-01T00:00:00Z") // TODO: work with To type translation, so Date?
|
|
20
25
|
)),
|
|
21
|
-
order("displayName")
|
|
22
|
-
)
|
|
23
|
-
const q = pipe(
|
|
24
|
-
a,
|
|
25
|
-
// page(2, 1)
|
|
26
|
+
order("displayName"),
|
|
27
|
+
page({ take: 10 }),
|
|
26
28
|
project(
|
|
27
|
-
// User.struct.pipe(S.pick("displayName"))
|
|
28
29
|
S.transformOrFail(
|
|
29
|
-
S.struct({ displayName: S.string }), // for projection performance benefit, this should be limited to the fields interested
|
|
30
|
-
S.struct(
|
|
31
|
-
(_) => Effect.andThen(
|
|
30
|
+
S.struct({ displayName: S.string }), // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
|
|
31
|
+
S.struct(pick(s.fields, "displayName")),
|
|
32
|
+
(_) => Effect.andThen(SomeService, _),
|
|
32
33
|
() => Effect.die(new Error("not implemented"))
|
|
33
34
|
)
|
|
34
35
|
)
|
|
35
36
|
)
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
it("works", () => {
|
|
39
|
+
console.log("raw", inspect(q, undefined, 25))
|
|
40
|
+
const interpreted = toFilter(q)
|
|
41
|
+
console.log("interpreted", inspect(interpreted, undefined, 25))
|
|
42
|
+
const filtersBuilt = interpreted.filter.build()
|
|
43
|
+
console.log("filtersBuilt", inspect(filtersBuilt, undefined, 25))
|
|
44
|
+
const items = [
|
|
45
|
+
new s({ displayName: S.NonEmptyString255("Verona"), n: new Date("2020-01-01T00:00:00Z") }),
|
|
46
|
+
new s({ displayName: S.NonEmptyString255("Riley") }),
|
|
47
|
+
new s({ displayName: S.NonEmptyString255("Riley"), n: new Date("2020-01-01T00:00:00Z") })
|
|
48
|
+
]
|
|
49
|
+
.map((_) => S.encodeSync(s)(_))
|
|
50
|
+
|
|
51
|
+
const processed = memFilter(interpreted)(items)
|
|
52
|
+
|
|
53
|
+
expect(processed).toEqual(items.slice(0, 2).toReversed().map(({ displayName }) => ({ displayName })))
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it.skip("works with repo", () => {
|
|
57
|
+
class TestRepo extends RepositoryDefaultImpl<TestRepo>()<s.From & { _etag: string | undefined }, never>()(
|
|
58
|
+
"test",
|
|
59
|
+
s
|
|
60
|
+
) {}
|
|
61
|
+
const q1 = TestRepo.q2(() => q)
|
|
62
|
+
|
|
63
|
+
// same as above, but with the `flow` helper
|
|
64
|
+
const q2 = TestRepo.q2(flow(
|
|
65
|
+
where("displayName", "Verona"),
|
|
66
|
+
or(flow(
|
|
67
|
+
where("displayName", "Riley"),
|
|
68
|
+
and("n", "gt", "2021-01-01T00:00:00Z") // TODO: work with To type translation, so Date?
|
|
69
|
+
)),
|
|
70
|
+
order("displayName"),
|
|
71
|
+
page({ take: 10 }),
|
|
72
|
+
project(
|
|
73
|
+
S.transformOrFail(
|
|
74
|
+
S.struct({ displayName: S.string }), // for projection performance benefit, this should be limited to the fields interested, and leads to SELECT fields
|
|
75
|
+
S.struct(pick(s.fields, "displayName")),
|
|
76
|
+
(_) => Effect.andThen(SomeService, _),
|
|
77
|
+
() => Effect.die(new Error("not implemented"))
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
))
|
|
81
|
+
|
|
82
|
+
expect([q1, q2]).toEqual([q1, q1])
|
|
83
|
+
})
|