@effect-app/infra 4.0.0-beta.12 → 4.0.0-beta.120
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 +794 -0
- package/dist/CUPS.d.ts +3 -3
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +3 -3
- package/dist/Emailer/service.d.ts +3 -3
- package/dist/Emailer/service.d.ts.map +1 -1
- package/dist/Emailer/service.js +3 -3
- package/dist/MainFiberSet.d.ts +2 -2
- package/dist/MainFiberSet.d.ts.map +1 -1
- package/dist/MainFiberSet.js +3 -3
- package/dist/Model/Repository/Registry.d.ts +20 -0
- package/dist/Model/Repository/Registry.d.ts.map +1 -0
- package/dist/Model/Repository/Registry.js +17 -0
- package/dist/Model/Repository/internal/internal.d.ts +3 -3
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +22 -16
- package/dist/Model/Repository/makeRepo.d.ts +5 -4
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/makeRepo.js +4 -1
- package/dist/Model/Repository/service.d.ts +5 -0
- package/dist/Model/Repository/service.d.ts.map +1 -1
- package/dist/Model/Repository/validation.d.ts +7 -6
- package/dist/Model/Repository/validation.d.ts.map +1 -1
- package/dist/Model/Repository.d.ts +1 -0
- package/dist/Model/Repository.d.ts.map +1 -1
- package/dist/Model/Repository.js +2 -1
- package/dist/Model/query/dsl.d.ts +9 -9
- package/dist/Model.d.ts +1 -0
- package/dist/Model.d.ts.map +1 -1
- package/dist/Model.js +2 -1
- package/dist/Operations.d.ts +2 -2
- package/dist/Operations.d.ts.map +1 -1
- package/dist/Operations.js +3 -3
- package/dist/OperationsRepo.d.ts +3 -3
- package/dist/OperationsRepo.d.ts.map +1 -1
- package/dist/OperationsRepo.js +3 -3
- package/dist/QueueMaker/SQLQueue.d.ts +2 -4
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +8 -6
- package/dist/QueueMaker/errors.d.ts +1 -1
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +3 -3
- package/dist/QueueMaker/sbqueue.js +3 -3
- package/dist/RequestContext.d.ts +22 -17
- package/dist/RequestContext.d.ts.map +1 -1
- package/dist/RequestContext.js +5 -5
- package/dist/RequestFiberSet.d.ts +2 -2
- package/dist/RequestFiberSet.d.ts.map +1 -1
- package/dist/RequestFiberSet.js +5 -5
- package/dist/Store/ContextMapContainer.d.ts +19 -3
- package/dist/Store/ContextMapContainer.d.ts.map +1 -1
- package/dist/Store/ContextMapContainer.js +13 -3
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +136 -68
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +24 -21
- package/dist/Store/Memory.d.ts +2 -2
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +26 -21
- package/dist/Store/SQL/Pg.d.ts +4 -0
- package/dist/Store/SQL/Pg.d.ts.map +1 -0
- package/dist/Store/SQL/Pg.js +191 -0
- package/dist/Store/SQL/query.d.ts +38 -0
- package/dist/Store/SQL/query.d.ts.map +1 -0
- package/dist/Store/SQL/query.js +367 -0
- package/dist/Store/SQL.d.ts +20 -0
- package/dist/Store/SQL.d.ts.map +1 -0
- package/dist/Store/SQL.js +381 -0
- package/dist/Store/index.d.ts +4 -1
- package/dist/Store/index.d.ts.map +1 -1
- package/dist/Store/index.js +15 -3
- package/dist/Store/service.d.ts +16 -5
- package/dist/Store/service.d.ts.map +1 -1
- package/dist/Store/service.js +24 -6
- package/dist/adapters/ServiceBus.d.ts +6 -6
- package/dist/adapters/ServiceBus.d.ts.map +1 -1
- package/dist/adapters/ServiceBus.js +9 -9
- package/dist/adapters/cosmos-client.d.ts +2 -2
- package/dist/adapters/cosmos-client.d.ts.map +1 -1
- package/dist/adapters/cosmos-client.js +3 -3
- package/dist/adapters/logger.d.ts.map +1 -1
- package/dist/adapters/memQueue.d.ts +2 -2
- package/dist/adapters/memQueue.d.ts.map +1 -1
- package/dist/adapters/memQueue.js +3 -3
- package/dist/adapters/mongo-client.d.ts +2 -2
- package/dist/adapters/mongo-client.d.ts.map +1 -1
- package/dist/adapters/mongo-client.js +3 -3
- package/dist/adapters/redis-client.d.ts +3 -3
- package/dist/adapters/redis-client.d.ts.map +1 -1
- package/dist/adapters/redis-client.js +3 -3
- package/dist/api/ContextProvider.d.ts +6 -6
- package/dist/api/ContextProvider.d.ts.map +1 -1
- package/dist/api/ContextProvider.js +6 -6
- package/dist/api/internal/auth.d.ts +1 -1
- package/dist/api/internal/events.d.ts +2 -2
- package/dist/api/internal/events.d.ts.map +1 -1
- package/dist/api/internal/events.js +11 -7
- package/dist/api/layerUtils.d.ts +5 -5
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +5 -5
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +3 -3
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.d.ts +35 -1
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +39 -1
- package/dist/api/routing.d.ts +1 -5
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +3 -2
- package/dist/api/setupRequest.d.ts +6 -3
- package/dist/api/setupRequest.d.ts.map +1 -1
- package/dist/api/setupRequest.js +11 -6
- package/dist/logger.d.ts.map +1 -1
- package/examples/query.ts +30 -26
- package/package.json +36 -18
- package/src/CUPS.ts +2 -2
- package/src/Emailer/service.ts +2 -2
- package/src/MainFiberSet.ts +2 -2
- package/src/Model/Repository/Registry.ts +33 -0
- package/src/Model/Repository/internal/internal.ts +76 -59
- package/src/Model/Repository/makeRepo.ts +7 -4
- package/src/Model/Repository/service.ts +6 -0
- package/src/Model/Repository.ts +1 -0
- package/src/Model.ts +1 -0
- package/src/Operations.ts +2 -2
- package/src/OperationsRepo.ts +2 -2
- package/src/QueueMaker/SQLQueue.ts +8 -7
- package/src/QueueMaker/memQueue.ts +2 -2
- package/src/QueueMaker/sbqueue.ts +2 -2
- package/src/RequestContext.ts +4 -4
- package/src/RequestFiberSet.ts +4 -4
- package/src/Store/ContextMapContainer.ts +41 -2
- package/src/Store/Cosmos.ts +350 -255
- package/src/Store/Disk.ts +37 -33
- package/src/Store/Memory.ts +29 -22
- package/src/Store/SQL/Pg.ts +321 -0
- package/src/Store/SQL/query.ts +409 -0
- package/src/Store/SQL.ts +674 -0
- package/src/Store/index.ts +17 -2
- package/src/Store/service.ts +31 -7
- package/src/adapters/ServiceBus.ts +8 -8
- package/src/adapters/cosmos-client.ts +2 -2
- package/src/adapters/memQueue.ts +2 -2
- package/src/adapters/mongo-client.ts +2 -2
- package/src/adapters/redis-client.ts +2 -2
- package/src/api/ContextProvider.ts +11 -11
- package/src/api/internal/events.ts +14 -9
- package/src/api/layerUtils.ts +8 -8
- package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
- package/src/api/routing/middleware/middleware.ts +43 -0
- package/src/api/routing.ts +3 -3
- package/src/api/setupRequest.ts +27 -7
- package/test/contextProvider.test.ts +11 -11
- package/test/controller.test.ts +12 -9
- package/test/dist/contextProvider.test.d.ts.map +1 -1
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/date-query.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +19 -9
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +11 -9
- package/test/dist/query.test.d.ts.map +1 -1
- package/test/dist/rawQuery.test.d.ts.map +1 -1
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
- package/test/dist/sql-store.test.d.ts.map +1 -0
- package/test/fixtures.ts +10 -8
- package/test/query.test.ts +182 -33
- package/test/rawQuery.test.ts +22 -18
- package/test/requires.test.ts +6 -5
- package/test/rpc-multi-middleware.test.ts +72 -3
- package/test/sql-store.test.ts +1064 -0
- package/test/validateSample.test.ts +12 -9
- package/tsconfig.json +0 -1
package/test/query.test.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
/* eslint-disable unused-imports/no-unused-vars */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
-
import {
|
|
4
|
+
import { SchemaTransformation } from "effect"
|
|
5
|
+
import { Context, Effect, flow, Layer, Option, pipe, S, Struct } from "effect-app"
|
|
5
6
|
import { inspect } from "util"
|
|
6
7
|
import { expect, expectTypeOf, it } from "vitest"
|
|
7
8
|
import { setupRequestContextFromCurrent } from "../src/api/setupRequest.js"
|
|
8
9
|
import { and, count, make, one, or, order, page, project, type QueryEnd, type QueryProjection, type QueryWhere, toFilter, where } from "../src/Model/query.js"
|
|
9
10
|
import { makeRepo } from "../src/Model/Repository.js"
|
|
11
|
+
import { RepositoryRegistryLive } from "../src/Model/Repository/Registry.js"
|
|
10
12
|
import { memFilter, MemoryStoreLive } from "../src/Store/Memory.js"
|
|
11
13
|
import { SomeService } from "./fixtures.js"
|
|
12
14
|
|
|
15
|
+
const TestStoreLive = Layer.merge(MemoryStoreLive, RepositoryRegistryLive)
|
|
16
|
+
|
|
13
17
|
const str = S.Struct({ _tag: S.Literal("string"), value: S.String })
|
|
14
|
-
const num = S.Struct({ _tag: S.Literal("number"), value: S.
|
|
18
|
+
const num = S.Struct({ _tag: S.Literal("number"), value: S.Finite })
|
|
15
19
|
const someUnion = S.Union([str, num])
|
|
16
20
|
|
|
17
21
|
export class Something extends S.Class<Something>("Something")({
|
|
@@ -19,7 +23,7 @@ export class Something extends S.Class<Something>("Something")({
|
|
|
19
23
|
displayName: S.NonEmptyString255,
|
|
20
24
|
name: S.NullOr(S.NonEmptyString255).withDefault,
|
|
21
25
|
n: S.Date.withDefault,
|
|
22
|
-
union: someUnion.pipe(S.
|
|
26
|
+
union: someUnion.pipe(S.withConstructorDefault(Effect.succeed({ _tag: "string" as const, value: "hi" })))
|
|
23
27
|
}) {}
|
|
24
28
|
export declare namespace Something {
|
|
25
29
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
@@ -90,8 +94,8 @@ it("works", () => {
|
|
|
90
94
|
|
|
91
95
|
const processed = memFilter(interpreted)(items.map((_) =>
|
|
92
96
|
S.encodeUnknownSync(S.Struct({
|
|
93
|
-
...
|
|
94
|
-
displayName: S.
|
|
97
|
+
...Struct.omit(Something.fields, ["displayName"]),
|
|
98
|
+
displayName: S.Literals(["Verona", "Riley"])
|
|
95
99
|
}))(_)
|
|
96
100
|
))
|
|
97
101
|
|
|
@@ -99,7 +103,7 @@ it("works", () => {
|
|
|
99
103
|
})
|
|
100
104
|
|
|
101
105
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
102
|
-
class SomethingRepo extends
|
|
106
|
+
class SomethingRepo extends Context.Service<SomethingRepo>()("SomethingRepo", {
|
|
103
107
|
make: Effect.gen(function*() {
|
|
104
108
|
return yield* makeRepo("Something", Something, {})
|
|
105
109
|
})
|
|
@@ -112,7 +116,7 @@ class SomethingRepo extends ServiceMap.Service<SomethingRepo>()("SomethingRepo",
|
|
|
112
116
|
})
|
|
113
117
|
)
|
|
114
118
|
.pipe(
|
|
115
|
-
Layer.provide(
|
|
119
|
+
Layer.provide(TestStoreLive)
|
|
116
120
|
)
|
|
117
121
|
}
|
|
118
122
|
|
|
@@ -156,8 +160,6 @@ it("works with repo", () =>
|
|
|
156
160
|
|
|
157
161
|
expectTypeOf(smtArr).toEqualTypeOf<readonly Something[]>()
|
|
158
162
|
|
|
159
|
-
console.log(" $$$$$$")
|
|
160
|
-
console.log(Struct.pick(["id", "displayName"]))
|
|
161
163
|
expect(q1).toEqual(items.slice(0, 2).toReversed().map(Struct.pick(["id", "displayName"])))
|
|
162
164
|
expect(q2).toEqual(items.slice(0, 2).toReversed().map(Struct.pick(["displayName"])))
|
|
163
165
|
})
|
|
@@ -281,7 +283,7 @@ it(
|
|
|
281
283
|
expect(result).toEqual([])
|
|
282
284
|
expect(result2).toEqual([])
|
|
283
285
|
})
|
|
284
|
-
.pipe(Effect.provide(
|
|
286
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
|
|
285
287
|
)
|
|
286
288
|
|
|
287
289
|
it(
|
|
@@ -467,7 +469,7 @@ it(
|
|
|
467
469
|
|
|
468
470
|
expect([]).toEqual([])
|
|
469
471
|
})
|
|
470
|
-
.pipe(Effect.provide(
|
|
472
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
|
|
471
473
|
)
|
|
472
474
|
|
|
473
475
|
it(
|
|
@@ -510,7 +512,7 @@ it(
|
|
|
510
512
|
|
|
511
513
|
expect([]).toEqual([])
|
|
512
514
|
})
|
|
513
|
-
.pipe(Effect.provide(
|
|
515
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
|
|
514
516
|
)
|
|
515
517
|
|
|
516
518
|
it(
|
|
@@ -521,8 +523,8 @@ it(
|
|
|
521
523
|
const schema = S.Struct({
|
|
522
524
|
id: S.String,
|
|
523
525
|
createdAt: S.Date.pipe(
|
|
524
|
-
S.withDecodingDefault(() => new Date().toISOString()),
|
|
525
|
-
S.withConstructorDefault(() =>
|
|
526
|
+
S.withDecodingDefault(Effect.sync(() => new Date().toISOString())),
|
|
527
|
+
S.withConstructorDefault(Effect.sync(() => new Date()))
|
|
526
528
|
)
|
|
527
529
|
})
|
|
528
530
|
const repo = yield* makeRepo(
|
|
@@ -534,8 +536,8 @@ it(
|
|
|
534
536
|
const outputSchema = S.Struct({
|
|
535
537
|
id: S.Literal("123"),
|
|
536
538
|
createdAt: S.Date.pipe(
|
|
537
|
-
S.withDecodingDefault(() => new Date().toISOString()),
|
|
538
|
-
S.withConstructorDefault(() =>
|
|
539
|
+
S.withDecodingDefault(Effect.sync(() => new Date().toISOString())),
|
|
540
|
+
S.withConstructorDefault(Effect.sync(() => new Date()))
|
|
539
541
|
)
|
|
540
542
|
})
|
|
541
543
|
|
|
@@ -543,7 +545,7 @@ it(
|
|
|
543
545
|
|
|
544
546
|
expect(result).toEqual([])
|
|
545
547
|
})
|
|
546
|
-
.pipe(Effect.provide(
|
|
548
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
|
|
547
549
|
)
|
|
548
550
|
|
|
549
551
|
it(
|
|
@@ -553,7 +555,7 @@ it(
|
|
|
553
555
|
.gen(function*() {
|
|
554
556
|
const schema = S.Struct({
|
|
555
557
|
id: S.String,
|
|
556
|
-
literals: S.
|
|
558
|
+
literals: S.Literals(["a", "b", "c"])
|
|
557
559
|
})
|
|
558
560
|
|
|
559
561
|
type Schema = typeof schema.Type
|
|
@@ -573,7 +575,7 @@ it(
|
|
|
573
575
|
|
|
574
576
|
expect(result).toEqual([])
|
|
575
577
|
})
|
|
576
|
-
.pipe(Effect.provide(
|
|
578
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
|
|
577
579
|
)
|
|
578
580
|
|
|
579
581
|
it(
|
|
@@ -583,7 +585,7 @@ it(
|
|
|
583
585
|
.gen(function*() {
|
|
584
586
|
const schema = S.Struct({
|
|
585
587
|
id: S.String,
|
|
586
|
-
literals: S.Union([S.
|
|
588
|
+
literals: S.Union([S.Literals(["a", "b", "c"]), S.Null])
|
|
587
589
|
})
|
|
588
590
|
|
|
589
591
|
type Schema = typeof schema.Type
|
|
@@ -617,7 +619,7 @@ it(
|
|
|
617
619
|
|
|
618
620
|
expect(result).toEqual([])
|
|
619
621
|
})
|
|
620
|
-
.pipe(Effect.provide(
|
|
622
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
|
|
621
623
|
)
|
|
622
624
|
|
|
623
625
|
it(
|
|
@@ -661,7 +663,7 @@ it(
|
|
|
661
663
|
|
|
662
664
|
expect(result).toEqual([])
|
|
663
665
|
})
|
|
664
|
-
.pipe(Effect.provide(
|
|
666
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise)
|
|
665
667
|
)
|
|
666
668
|
|
|
667
669
|
it("remove null from one constituent of a tagged union", () =>
|
|
@@ -674,7 +676,7 @@ it("remove null from one constituent of a tagged union", () =>
|
|
|
674
676
|
|
|
675
677
|
class BB extends S.Class<BB>("BB")({
|
|
676
678
|
id: S.Literal("BB"),
|
|
677
|
-
b: S.NullOr(S.
|
|
679
|
+
b: S.NullOr(S.Finite)
|
|
678
680
|
}) {}
|
|
679
681
|
|
|
680
682
|
type Union = AA | BB
|
|
@@ -710,7 +712,7 @@ it("remove null from one constituent of a tagged union", () =>
|
|
|
710
712
|
})[]
|
|
711
713
|
>()
|
|
712
714
|
})
|
|
713
|
-
.pipe(Effect.provide(
|
|
715
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
714
716
|
|
|
715
717
|
it("refine 3", () =>
|
|
716
718
|
Effect
|
|
@@ -748,7 +750,7 @@ it("refine 3", () =>
|
|
|
748
750
|
const resQuer1 = yield* repo.query(where("id", "AA"))
|
|
749
751
|
expectTypeOf(resQuer1).toEqualTypeOf<readonly AA[]>()
|
|
750
752
|
})
|
|
751
|
-
.pipe(Effect.provide(
|
|
753
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
752
754
|
|
|
753
755
|
it("my test", () =>
|
|
754
756
|
Effect
|
|
@@ -766,7 +768,7 @@ it("my test", () =>
|
|
|
766
768
|
)
|
|
767
769
|
expectTypeOf(resQuer1).toEqualTypeOf<readonly AA[]>()
|
|
768
770
|
})
|
|
769
|
-
.pipe(Effect.provide(
|
|
771
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
770
772
|
|
|
771
773
|
it("refine inner without imposing a projection", () =>
|
|
772
774
|
Effect
|
|
@@ -810,7 +812,7 @@ it("refine inner without imposing a projection", () =>
|
|
|
810
812
|
where("union._tag", "AA"),
|
|
811
813
|
// But if I wanna the whole Data as output ignoring the inner refinement
|
|
812
814
|
// I wanna be able to do so
|
|
813
|
-
project(
|
|
815
|
+
project(Data.mapFields(Struct.pick(["union"])))
|
|
814
816
|
)
|
|
815
817
|
|
|
816
818
|
expectTypeOf(query2).toEqualTypeOf<
|
|
@@ -841,7 +843,7 @@ it("refine inner without imposing a projection", () =>
|
|
|
841
843
|
}[]
|
|
842
844
|
>()
|
|
843
845
|
})
|
|
844
|
-
.pipe(Effect.provide(
|
|
846
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
845
847
|
|
|
846
848
|
it("does not allow string queries on arrays", () =>
|
|
847
849
|
Effect
|
|
@@ -876,7 +878,7 @@ it("does not allow string queries on arrays", () =>
|
|
|
876
878
|
expectTypeOf(good3).toEqualTypeOf<QueryWhere<Some, Some>>()
|
|
877
879
|
expectTypeOf(good4).toEqualTypeOf<QueryWhere<Some, Some>>()
|
|
878
880
|
})
|
|
879
|
-
.pipe(Effect.provide(
|
|
881
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
880
882
|
|
|
881
883
|
it("test array.length", () =>
|
|
882
884
|
Effect
|
|
@@ -917,7 +919,7 @@ it("test array.length", () =>
|
|
|
917
919
|
QueryWhere<Something, Something>
|
|
918
920
|
>()
|
|
919
921
|
})
|
|
920
|
-
.pipe(Effect.provide(
|
|
922
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
921
923
|
|
|
922
924
|
it("distribution over union", () =>
|
|
923
925
|
Effect
|
|
@@ -941,7 +943,7 @@ it("distribution over union", () =>
|
|
|
941
943
|
})[]
|
|
942
944
|
>()
|
|
943
945
|
})
|
|
944
|
-
.pipe(Effect.provide(
|
|
946
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
945
947
|
|
|
946
948
|
it("refine nested union", () =>
|
|
947
949
|
Effect
|
|
@@ -982,7 +984,154 @@ it("refine nested union", () =>
|
|
|
982
984
|
}[]
|
|
983
985
|
>()
|
|
984
986
|
})
|
|
985
|
-
.pipe(Effect.provide(
|
|
987
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
988
|
+
|
|
989
|
+
it("find with transformed id", () =>
|
|
990
|
+
Effect
|
|
991
|
+
.gen(function*() {
|
|
992
|
+
const ConfiguratorId = S.NonEmptyString255
|
|
993
|
+
|
|
994
|
+
class PreconfigurationId extends S.Class<PreconfigurationId>("PreconfigurationId")({
|
|
995
|
+
configuratorId: ConfiguratorId,
|
|
996
|
+
label: S.NonEmptyString50
|
|
997
|
+
}) {}
|
|
998
|
+
|
|
999
|
+
const PreconfigurationIdFromString = S.NonEmptyString255.pipe(
|
|
1000
|
+
S.decodeTo(
|
|
1001
|
+
S.toType(PreconfigurationId),
|
|
1002
|
+
SchemaTransformation.transformOrFail({
|
|
1003
|
+
decode: Effect.fnUntraced(function*(value) {
|
|
1004
|
+
const values = value.split("_")
|
|
1005
|
+
const label = yield* S.SchemaParser.decodeUnknownEffect(S.NonEmptyString50)(values.pop())
|
|
1006
|
+
const configuratorId = yield* S.SchemaParser.decodeUnknownEffect(ConfiguratorId)(values.join("_"))
|
|
1007
|
+
return new PreconfigurationId({ configuratorId, label })
|
|
1008
|
+
}),
|
|
1009
|
+
encode: (id) => Effect.succeed(S.NonEmptyString255(`${id.configuratorId}_${id.label}`))
|
|
1010
|
+
})
|
|
1011
|
+
),
|
|
1012
|
+
S.revealCodec
|
|
1013
|
+
)
|
|
1014
|
+
|
|
1015
|
+
const Preconfiguration = S.Struct({
|
|
1016
|
+
id: PreconfigurationIdFromString,
|
|
1017
|
+
name: S.String
|
|
1018
|
+
})
|
|
1019
|
+
|
|
1020
|
+
const repo = yield* makeRepo("Preconfiguration", Preconfiguration, { idKey: "id" as const })
|
|
1021
|
+
|
|
1022
|
+
const id = new PreconfigurationId({
|
|
1023
|
+
configuratorId: S.NonEmptyString255("myConfigurator"),
|
|
1024
|
+
label: S.NonEmptyString50("myLabel")
|
|
1025
|
+
})
|
|
1026
|
+
const item = { id, name: "test preconfig" }
|
|
1027
|
+
|
|
1028
|
+
yield* repo.saveAndPublish([item])
|
|
1029
|
+
|
|
1030
|
+
const found = yield* repo.find(id)
|
|
1031
|
+
expect(Option.isSome(found)).toBe(true)
|
|
1032
|
+
expect(Option.getOrThrow(found).name).toBe("test preconfig")
|
|
1033
|
+
expect(Option.getOrThrow(found).id).toEqual(id)
|
|
1034
|
+
|
|
1035
|
+
const notFound = yield* repo.find(
|
|
1036
|
+
new PreconfigurationId({
|
|
1037
|
+
configuratorId: S.NonEmptyString255("other"),
|
|
1038
|
+
label: S.NonEmptyString50("nope")
|
|
1039
|
+
})
|
|
1040
|
+
)
|
|
1041
|
+
expect(Option.isNone(notFound)).toBe(true)
|
|
1042
|
+
})
|
|
1043
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
1044
|
+
|
|
1045
|
+
it("find with transformed id in tagged union", () =>
|
|
1046
|
+
Effect
|
|
1047
|
+
.gen(function*() {
|
|
1048
|
+
const ConfiguratorId = S.NonEmptyString255
|
|
1049
|
+
|
|
1050
|
+
class PreconfigurationId extends S.Class<PreconfigurationId>("PreconfigurationId")({
|
|
1051
|
+
configuratorId: ConfiguratorId,
|
|
1052
|
+
label: S.NonEmptyString50
|
|
1053
|
+
}) {}
|
|
1054
|
+
|
|
1055
|
+
const PreconfigurationIdFromString = S.NonEmptyString255.pipe(
|
|
1056
|
+
S.decodeTo(
|
|
1057
|
+
S.toType(PreconfigurationId),
|
|
1058
|
+
SchemaTransformation.transformOrFail({
|
|
1059
|
+
decode: Effect.fnUntraced(function*(value) {
|
|
1060
|
+
const values = value.split("_")
|
|
1061
|
+
const label = yield* S.SchemaParser.decodeUnknownEffect(S.NonEmptyString50)(values.pop())
|
|
1062
|
+
const configuratorId = yield* S.SchemaParser.decodeUnknownEffect(ConfiguratorId)(values.join("_"))
|
|
1063
|
+
return new PreconfigurationId({ configuratorId, label })
|
|
1064
|
+
}),
|
|
1065
|
+
encode: (id) => Effect.succeed(S.NonEmptyString255(`${id.configuratorId}_${id.label}`))
|
|
1066
|
+
})
|
|
1067
|
+
),
|
|
1068
|
+
S.revealCodec
|
|
1069
|
+
)
|
|
1070
|
+
|
|
1071
|
+
class Draft extends S.TaggedClass<Draft>()("Draft", {
|
|
1072
|
+
id: PreconfigurationIdFromString,
|
|
1073
|
+
name: S.String
|
|
1074
|
+
}) {}
|
|
1075
|
+
|
|
1076
|
+
class Published extends S.TaggedClass<Published>()("Published", {
|
|
1077
|
+
id: PreconfigurationIdFromString,
|
|
1078
|
+
name: S.String,
|
|
1079
|
+
publishedAt: S.String
|
|
1080
|
+
}) {}
|
|
1081
|
+
|
|
1082
|
+
class Archived extends S.TaggedClass<Archived>()("Archived", {
|
|
1083
|
+
id: PreconfigurationIdFromString,
|
|
1084
|
+
name: S.String,
|
|
1085
|
+
archivedAt: S.String
|
|
1086
|
+
}) {}
|
|
1087
|
+
|
|
1088
|
+
const Preconfiguration = S.Union([Draft, Published, Archived])
|
|
1089
|
+
|
|
1090
|
+
const repo = yield* makeRepo("Preconfiguration", Preconfiguration, {})
|
|
1091
|
+
|
|
1092
|
+
const id1 = new PreconfigurationId({
|
|
1093
|
+
configuratorId: S.NonEmptyString255("conf1"),
|
|
1094
|
+
label: S.NonEmptyString50("draft1")
|
|
1095
|
+
})
|
|
1096
|
+
const id2 = new PreconfigurationId({
|
|
1097
|
+
configuratorId: S.NonEmptyString255("conf2"),
|
|
1098
|
+
label: S.NonEmptyString50("pub1")
|
|
1099
|
+
})
|
|
1100
|
+
const id3 = new PreconfigurationId({
|
|
1101
|
+
configuratorId: S.NonEmptyString255("conf3"),
|
|
1102
|
+
label: S.NonEmptyString50("arch1")
|
|
1103
|
+
})
|
|
1104
|
+
|
|
1105
|
+
const draft = new Draft({ id: id1, name: "my draft" })
|
|
1106
|
+
const published = new Published({ id: id2, name: "my published", publishedAt: "2024-01-01" })
|
|
1107
|
+
const archived = new Archived({ id: id3, name: "my archived", archivedAt: "2024-06-01" })
|
|
1108
|
+
|
|
1109
|
+
yield* repo.saveAndPublish([draft, published, archived])
|
|
1110
|
+
|
|
1111
|
+
// find each by their PreconfigurationId instance
|
|
1112
|
+
const foundDraft = yield* repo.find(id1)
|
|
1113
|
+
expect(Option.isSome(foundDraft)).toBe(true)
|
|
1114
|
+
expect(Option.getOrThrow(foundDraft)._tag).toBe("Draft")
|
|
1115
|
+
expect(Option.getOrThrow(foundDraft).name).toBe("my draft")
|
|
1116
|
+
|
|
1117
|
+
const foundPublished = yield* repo.find(id2)
|
|
1118
|
+
expect(Option.isSome(foundPublished)).toBe(true)
|
|
1119
|
+
expect(Option.getOrThrow(foundPublished)._tag).toBe("Published")
|
|
1120
|
+
|
|
1121
|
+
const foundArchived = yield* repo.find(id3)
|
|
1122
|
+
expect(Option.isSome(foundArchived)).toBe(true)
|
|
1123
|
+
expect(Option.getOrThrow(foundArchived)._tag).toBe("Archived")
|
|
1124
|
+
|
|
1125
|
+
// not found
|
|
1126
|
+
const notFound = yield* repo.find(
|
|
1127
|
+
new PreconfigurationId({
|
|
1128
|
+
configuratorId: S.NonEmptyString255("nope"),
|
|
1129
|
+
label: S.NonEmptyString50("nope")
|
|
1130
|
+
})
|
|
1131
|
+
)
|
|
1132
|
+
expect(Option.isNone(notFound)).toBe(true)
|
|
1133
|
+
})
|
|
1134
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
|
986
1135
|
|
|
987
1136
|
it("refine union with nested union", () =>
|
|
988
1137
|
Effect
|
|
@@ -1097,4 +1246,4 @@ it("refine union with nested union", () =>
|
|
|
1097
1246
|
})[]
|
|
1098
1247
|
>()
|
|
1099
1248
|
})
|
|
1100
|
-
.pipe(Effect.provide(
|
|
1249
|
+
.pipe(Effect.provide(TestStoreLive), setupRequestContextFromCurrent(), Effect.runPromise))
|
package/test/rawQuery.test.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it } from "@effect/vitest"
|
|
2
|
-
import { Array, Config, Effect, flow, Layer, ManagedRuntime, Redacted, References, Result, S
|
|
2
|
+
import { Array, Config, Context, Effect, flow, Layer, ManagedRuntime, Redacted, References, Result, S } from "effect-app"
|
|
3
3
|
import { LogLevels } from "effect-app/utils"
|
|
4
4
|
import { setupRequestContextFromCurrent } from "../src/api/setupRequest.js"
|
|
5
5
|
import { and, or, project, where, whereEvery, whereSome } from "../src/Model/query.js"
|
|
6
6
|
import { makeRepo } from "../src/Model/Repository/makeRepo.js"
|
|
7
|
+
import { RepositoryRegistryLive } from "../src/Model/Repository/Registry.js"
|
|
7
8
|
import { CosmosStoreLayer } from "../src/Store/Cosmos.js"
|
|
8
9
|
import { MemoryStoreLive } from "../src/Store/Memory.js"
|
|
9
10
|
|
|
@@ -24,7 +25,7 @@ class Something extends S.Class<Something>("Something")({
|
|
|
24
25
|
id: S.String,
|
|
25
26
|
name: S.String,
|
|
26
27
|
description: S.String,
|
|
27
|
-
items: S.Array(S.Struct({ id: S.String, value: S.
|
|
28
|
+
items: S.Array(S.Struct({ id: S.String, value: S.Finite, description: S.String }))
|
|
28
29
|
}) {}
|
|
29
30
|
|
|
30
31
|
const items = [
|
|
@@ -49,7 +50,7 @@ const items = [
|
|
|
49
50
|
]
|
|
50
51
|
|
|
51
52
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
52
|
-
class SomethingRepo extends
|
|
53
|
+
class SomethingRepo extends Context.Service<SomethingRepo>()(
|
|
53
54
|
"SomethingRepo",
|
|
54
55
|
{
|
|
55
56
|
make: Effect.gen(function*() {
|
|
@@ -76,28 +77,31 @@ class SomethingRepo extends ServiceMap.Service<SomethingRepo>()(
|
|
|
76
77
|
static readonly Test = this
|
|
77
78
|
.layer
|
|
78
79
|
.pipe(
|
|
79
|
-
Layer.provide(MemoryStoreLive)
|
|
80
|
+
Layer.provide(Layer.merge(MemoryStoreLive, RepositoryRegistryLive))
|
|
80
81
|
)
|
|
81
82
|
|
|
82
83
|
static readonly TestCosmos = this
|
|
83
84
|
.layer
|
|
84
85
|
.pipe(
|
|
85
86
|
Layer.provide(
|
|
86
|
-
Effect
|
|
87
|
-
|
|
88
|
-
Config.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
Effect
|
|
88
|
+
.gen(function*() {
|
|
89
|
+
const url = yield* Config.redacted("STORAGE_URL").pipe(
|
|
90
|
+
Config.withDefault(
|
|
91
|
+
Redacted.make(
|
|
92
|
+
// the emulator doesn't implement array projections :/ so you need an actual cloud instance!
|
|
93
|
+
"AccountEndpoint=http://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
|
|
94
|
+
)
|
|
92
95
|
)
|
|
93
96
|
)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
return CosmosStoreLayer({
|
|
98
|
+
dbName: "test",
|
|
99
|
+
prefix: "",
|
|
100
|
+
url
|
|
101
|
+
})
|
|
102
|
+
.pipe(Layer.merge(RepositoryRegistryLive))
|
|
99
103
|
})
|
|
100
|
-
|
|
104
|
+
.pipe(Layer.unwrap)
|
|
101
105
|
)
|
|
102
106
|
)
|
|
103
107
|
}
|
|
@@ -107,7 +111,7 @@ describe("select first-level array fields", () => {
|
|
|
107
111
|
.gen(function*() {
|
|
108
112
|
const repo = yield* SomethingRepo
|
|
109
113
|
|
|
110
|
-
const projected = S.Struct({ name: S.String, items: S.Array(S.Struct({ id: S.String, value: S.
|
|
114
|
+
const projected = S.Struct({ name: S.String, items: S.Array(S.Struct({ id: S.String, value: S.Finite })) })
|
|
111
115
|
|
|
112
116
|
// ok crazy lol, "value" is a reserved word in CosmosDB, so we have to use t["value"] as a field name instead of t.value
|
|
113
117
|
const items = yield* repo.queryRaw(projected, {
|
|
@@ -159,7 +163,7 @@ describe("select first-level array fields", () => {
|
|
|
159
163
|
.pipe(Effect.provide(SomethingRepo.Test), rt.runPromise))
|
|
160
164
|
})
|
|
161
165
|
|
|
162
|
-
const projected = S.Struct({ name: S.String, items: S.Array(S.Struct({ id: S.String, value: S.
|
|
166
|
+
const projected = S.Struct({ name: S.String, items: S.Array(S.Struct({ id: S.String, value: S.Finite })) })
|
|
163
167
|
|
|
164
168
|
const expected = [
|
|
165
169
|
{
|
package/test/requires.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, expectTypeOf, it } from "@effect/vitest"
|
|
2
|
-
import { Effect, Layer, Result, S
|
|
2
|
+
import { Context, Effect, Layer, Result, S } from "effect-app"
|
|
3
3
|
import { NotLoggedInError, UnauthorizedError } from "effect-app/client"
|
|
4
4
|
import { HttpHeaders } from "effect-app/http"
|
|
5
5
|
import * as RpcX from "effect-app/rpc"
|
|
@@ -63,11 +63,12 @@ const testSuite = (_mw: typeof middleware3) =>
|
|
|
63
63
|
"works",
|
|
64
64
|
Effect.fn(function*() {
|
|
65
65
|
const defaultOpts = {
|
|
66
|
+
client: null as any, // TODO?
|
|
66
67
|
headers: HttpHeaders.fromRecordUnsafe({}),
|
|
67
68
|
payload: { _tag: "Test" },
|
|
68
69
|
clientId: 0,
|
|
69
70
|
requestId: "test-id" as any,
|
|
70
|
-
rpc: { ...TestRpc, annotations:
|
|
71
|
+
rpc: { ...TestRpc, annotations: Context.make(_mw.requestContext, {}) }
|
|
71
72
|
}
|
|
72
73
|
const next = Effect.void as unknown as Effect.Effect<SuccessValue, unhandled, never>
|
|
73
74
|
const layer = _mw.layer.pipe(
|
|
@@ -89,7 +90,7 @@ const testSuite = (_mw: typeof middleware3) =>
|
|
|
89
90
|
headers: HttpHeaders.fromRecordUnsafe({ "x-user": "test-user", "x-is-manager": "true" }),
|
|
90
91
|
rpc: {
|
|
91
92
|
...defaultOpts.rpc,
|
|
92
|
-
annotations:
|
|
93
|
+
annotations: Context.make(_mw.requestContext, { requireRoles: ["manager"] })
|
|
93
94
|
}
|
|
94
95
|
})
|
|
95
96
|
)
|
|
@@ -127,7 +128,7 @@ const testSuite = (_mw: typeof middleware3) =>
|
|
|
127
128
|
Object.assign({ ...defaultOpts }, {
|
|
128
129
|
rpc: {
|
|
129
130
|
...defaultOpts.rpc,
|
|
130
|
-
annotations:
|
|
131
|
+
annotations: Context.make(_mw.requestContext, { requireRoles: ["manager"] })
|
|
131
132
|
}
|
|
132
133
|
})
|
|
133
134
|
)
|
|
@@ -153,7 +154,7 @@ const testSuite = (_mw: typeof middleware3) =>
|
|
|
153
154
|
{
|
|
154
155
|
rpc: {
|
|
155
156
|
...defaultOpts.rpc,
|
|
156
|
-
annotations:
|
|
157
|
+
annotations: Context.make(_mw.requestContext, { requireRoles: ["manager"] })
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { NodeHttpServer } from "@effect/platform-node"
|
|
2
2
|
import { expect, expectTypeOf, it } from "@effect/vitest"
|
|
3
|
-
import { Console, Effect, Layer, Result } from "effect"
|
|
4
|
-
import { S } from "effect-app"
|
|
3
|
+
import { Console, Effect, Layer, Ref, Result } from "effect"
|
|
4
|
+
import { Context, S } from "effect-app"
|
|
5
5
|
import { NotLoggedInError } from "effect-app/client"
|
|
6
6
|
import { HttpRouter } from "effect-app/http"
|
|
7
7
|
import { DefaultGenericMiddlewares } from "effect-app/middleware"
|
|
8
8
|
import { MiddlewareMaker } from "effect-app/rpc"
|
|
9
9
|
import { middlewareGroup } from "effect-app/rpc/MiddlewareMaker"
|
|
10
10
|
import { FetchHttpClient } from "effect/unstable/http"
|
|
11
|
-
import { RpcClient, RpcGroup, RpcSerialization, RpcServer, RpcTest } from "effect/unstable/rpc"
|
|
11
|
+
import { Rpc, RpcClient, RpcGroup, RpcSerialization, RpcServer, RpcTest } from "effect/unstable/rpc"
|
|
12
12
|
import { createServer } from "http"
|
|
13
13
|
import { DefaultGenericMiddlewaresLive } from "../src/api/routing.js"
|
|
14
14
|
import { AllowAnonymous, AllowAnonymousLive, RequestContextMap, RequireRoles, RequireRolesLive, Some, SomeElseMiddleware, SomeElseMiddlewareLive, SomeMiddleware, SomeMiddlewareLive, SomeService, Test, TestLive, UserProfile } from "./fixtures.js"
|
|
@@ -136,3 +136,72 @@ it.live(
|
|
|
136
136
|
Effect.provide(RpcTestLayer)
|
|
137
137
|
)
|
|
138
138
|
)
|
|
139
|
+
|
|
140
|
+
// Per-request service isolation test
|
|
141
|
+
|
|
142
|
+
class PerRequestCounter extends Context.Service<PerRequestCounter>()(
|
|
143
|
+
"PerRequestCounter",
|
|
144
|
+
{ make: Effect.sync(() => ({ a: 0 })) }
|
|
145
|
+
) {
|
|
146
|
+
static Default = Layer.effect(this, this.make)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
class GlobalCounter extends Context.Service<GlobalCounter, {
|
|
150
|
+
readonly ref: Ref.Ref<number>
|
|
151
|
+
}>()("GlobalCounter") {}
|
|
152
|
+
|
|
153
|
+
const CounterRpcs = RpcGroup.make(
|
|
154
|
+
Rpc.make("incrementA", {
|
|
155
|
+
success: S.Number
|
|
156
|
+
}),
|
|
157
|
+
Rpc.make("incrementB", {
|
|
158
|
+
success: S.Number
|
|
159
|
+
})
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
const counterImpl = CounterRpcs
|
|
163
|
+
.toLayer({
|
|
164
|
+
incrementA: Effect.fn(function*() {
|
|
165
|
+
const counter = yield* PerRequestCounter
|
|
166
|
+
counter.a++
|
|
167
|
+
const global = yield* GlobalCounter
|
|
168
|
+
yield* Ref.update(global.ref, (n) => n + 1)
|
|
169
|
+
return counter.a
|
|
170
|
+
}, Effect.provide(PerRequestCounter.Default)),
|
|
171
|
+
incrementB: Effect.fn(function*() {
|
|
172
|
+
const counter = yield* PerRequestCounter
|
|
173
|
+
counter.a++
|
|
174
|
+
const global = yield* GlobalCounter
|
|
175
|
+
yield* Ref.update(global.ref, (n) => n + 1)
|
|
176
|
+
return counter.a
|
|
177
|
+
}, Effect.provide(PerRequestCounter.Default))
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
const GlobalCounterLive = Layer.effect(
|
|
181
|
+
GlobalCounter,
|
|
182
|
+
Ref.make(0).pipe(Effect.map((ref) => ({ ref })))
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
const CounterTestLayer = counterImpl.pipe(Layer.provideMerge(GlobalCounterLive))
|
|
186
|
+
|
|
187
|
+
it.live(
|
|
188
|
+
"per-request service isolation with shared global counter",
|
|
189
|
+
Effect.fnUntraced(
|
|
190
|
+
function*() {
|
|
191
|
+
const client = yield* RpcTest.makeClient(CounterRpcs)
|
|
192
|
+
const global = yield* GlobalCounter
|
|
193
|
+
|
|
194
|
+
const r1 = yield* client.incrementA()
|
|
195
|
+
const r2 = yield* client.incrementB()
|
|
196
|
+
|
|
197
|
+
// per-request counter is fresh each time → both return 1
|
|
198
|
+
expect(r1).toBe(1)
|
|
199
|
+
expect(r2).toBe(1)
|
|
200
|
+
|
|
201
|
+
// global counter is shared across requests → accumulates to 2
|
|
202
|
+
const globalCount = yield* Ref.get(global.ref)
|
|
203
|
+
expect(globalCount).toBe(2)
|
|
204
|
+
},
|
|
205
|
+
Effect.provide(CounterTestLayer)
|
|
206
|
+
)
|
|
207
|
+
)
|