@effect-app/infra 4.0.0-beta.21 → 4.0.0-beta.210
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 +1548 -0
- package/_check.sh +1 -1
- package/dist/CUPS.d.ts +7 -7
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +10 -12
- package/dist/Emailer/Sendgrid.d.ts +14 -14
- package/dist/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/Emailer/Sendgrid.js +16 -15
- package/dist/Emailer/fake.d.ts +1 -1
- package/dist/Emailer/service.d.ts +10 -4
- package/dist/Emailer/service.d.ts.map +1 -1
- package/dist/Emailer/service.js +3 -3
- package/dist/Emailer.d.ts +1 -1
- package/dist/MainFiberSet.d.ts +9 -9
- 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/ext.d.ts +33 -15
- package/dist/Model/Repository/ext.d.ts.map +1 -1
- package/dist/Model/Repository/ext.js +54 -2
- package/dist/Model/Repository/internal/internal.d.ts +6 -6
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +59 -41
- package/dist/Model/Repository/legacy.d.ts +1 -1
- package/dist/Model/Repository/makeRepo.d.ts +7 -6
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/makeRepo.js +5 -1
- package/dist/Model/Repository/service.d.ts +28 -23
- package/dist/Model/Repository/service.d.ts.map +1 -1
- package/dist/Model/Repository/validation.d.ts +46 -17
- package/dist/Model/Repository/validation.d.ts.map +1 -1
- package/dist/Model/Repository/validation.js +5 -5
- package/dist/Model/Repository.d.ts +2 -1
- package/dist/Model/Repository.d.ts.map +1 -1
- package/dist/Model/Repository.js +2 -1
- package/dist/Model/dsl.d.ts +4 -4
- package/dist/Model/dsl.d.ts.map +1 -1
- package/dist/Model/filter/filterApi.d.ts +5 -5
- package/dist/Model/filter/filterApi.d.ts.map +1 -1
- package/dist/Model/filter/types/errors.d.ts +1 -1
- package/dist/Model/filter/types/fields.d.ts +1 -1
- package/dist/Model/filter/types/path/common.d.ts +1 -1
- package/dist/Model/filter/types/path/eager.d.ts +1 -1
- package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
- package/dist/Model/filter/types/path/eager.js +1 -1
- package/dist/Model/filter/types/path/index.d.ts +1 -1
- package/dist/Model/filter/types/utils.d.ts +1 -1
- package/dist/Model/filter/types/validator.d.ts +1 -1
- package/dist/Model/filter/types.d.ts +1 -1
- package/dist/Model/query/dsl.d.ts +16 -16
- package/dist/Model/query/dsl.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.d.ts +6 -6
- package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.js +3 -3
- package/dist/Model/query.d.ts +1 -1
- package/dist/Model.d.ts +2 -1
- package/dist/Model.d.ts.map +1 -1
- package/dist/Model.js +2 -1
- package/dist/QueueMaker/SQLQueue.d.ts +5 -7
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +130 -116
- package/dist/QueueMaker/errors.d.ts +2 -2
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.d.ts +7 -4
- package/dist/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +75 -63
- package/dist/QueueMaker/sbqueue.d.ts +6 -3
- package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/QueueMaker/sbqueue.js +52 -53
- package/dist/QueueMaker/service.d.ts +1 -1
- package/dist/RequestContext.d.ts +74 -35
- package/dist/RequestContext.d.ts.map +1 -1
- package/dist/RequestContext.js +13 -14
- package/dist/RequestFiberSet.d.ts +7 -7
- package/dist/RequestFiberSet.d.ts.map +1 -1
- package/dist/RequestFiberSet.js +3 -3
- 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/query.d.ts +1 -1
- package/dist/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/Store/Cosmos/query.js +10 -12
- package/dist/Store/Cosmos.d.ts +1 -1
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +335 -243
- package/dist/Store/Disk.d.ts +2 -2
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +72 -35
- package/dist/Store/Memory.d.ts +6 -4
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +90 -57
- 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 +231 -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 +464 -0
- package/dist/Store/codeFilter.d.ts +1 -1
- package/dist/Store/codeFilter.d.ts.map +1 -1
- package/dist/Store/codeFilter.js +4 -2
- package/dist/Store/index.d.ts +5 -2
- package/dist/Store/index.d.ts.map +1 -1
- package/dist/Store/index.js +15 -3
- package/dist/Store/service.d.ts +18 -7
- package/dist/Store/service.d.ts.map +1 -1
- package/dist/Store/service.js +24 -6
- package/dist/Store/utils.d.ts +1 -1
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +3 -4
- package/dist/Store.d.ts +1 -1
- package/dist/adapters/SQL/Model.d.ts +31 -42
- package/dist/adapters/SQL/Model.d.ts.map +1 -1
- package/dist/adapters/SQL/Model.js +29 -38
- package/dist/adapters/SQL.d.ts +1 -1
- package/dist/adapters/ServiceBus.d.ts +11 -11
- package/dist/adapters/ServiceBus.d.ts.map +1 -1
- package/dist/adapters/ServiceBus.js +13 -15
- package/dist/adapters/cosmos-client.d.ts +3 -3
- package/dist/adapters/cosmos-client.d.ts.map +1 -1
- package/dist/adapters/cosmos-client.js +3 -3
- package/dist/adapters/index.d.ts +8 -2
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +8 -2
- package/dist/adapters/logger.d.ts +2 -2
- package/dist/adapters/logger.d.ts.map +1 -1
- package/dist/adapters/memQueue.d.ts +3 -3
- package/dist/adapters/memQueue.d.ts.map +1 -1
- package/dist/adapters/memQueue.js +3 -3
- package/dist/adapters/mongo-client.d.ts +3 -3
- 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 +8 -8
- package/dist/api/ContextProvider.d.ts.map +1 -1
- package/dist/api/ContextProvider.js +6 -6
- package/dist/api/codec.d.ts +1 -1
- package/dist/api/internal/RequestContextMiddleware.d.ts +2 -2
- package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
- package/dist/api/internal/RequestContextMiddleware.js +2 -2
- package/dist/api/internal/auth.d.ts +44 -6
- package/dist/api/internal/auth.d.ts.map +1 -1
- package/dist/api/internal/auth.js +160 -29
- package/dist/api/internal/events.d.ts +3 -3
- package/dist/api/internal/events.d.ts.map +1 -1
- package/dist/api/internal/events.js +10 -8
- package/dist/api/internal/health.d.ts +1 -1
- package/dist/api/layerUtils.d.ts +6 -6
- package/dist/api/layerUtils.d.ts.map +1 -1
- package/dist/api/layerUtils.js +5 -5
- package/dist/api/middlewares.d.ts +1 -1
- package/dist/api/reportError.d.ts +1 -1
- package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.d.ts +39 -3
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +48 -16
- package/dist/api/routing/middleware.d.ts +1 -2
- package/dist/api/routing/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware.js +1 -2
- package/dist/api/routing/schema/jwt.d.ts +1 -1
- package/dist/api/routing/schema/jwt.d.ts.map +1 -1
- package/dist/api/routing/tsort.d.ts +1 -1
- package/dist/api/routing/tsort.d.ts.map +1 -1
- package/dist/api/routing/utils.d.ts +3 -3
- package/dist/api/routing/utils.d.ts.map +1 -1
- package/dist/api/routing.d.ts +80 -37
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +112 -40
- package/dist/api/setupRequest.d.ts +8 -5
- package/dist/api/setupRequest.d.ts.map +1 -1
- package/dist/api/setupRequest.js +12 -7
- package/dist/api/util.d.ts +1 -1
- package/dist/arbs.d.ts +1 -1
- package/dist/arbs.d.ts.map +1 -1
- package/dist/arbs.js +5 -3
- package/dist/errorReporter.d.ts +4 -4
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +20 -25
- package/dist/errors.d.ts +1 -1
- package/dist/fileUtil.d.ts +1 -1
- package/dist/fileUtil.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/logger/jsonLogger.d.ts +1 -1
- package/dist/logger/logFmtLogger.d.ts +1 -1
- package/dist/logger/shared.d.ts +1 -1
- package/dist/logger/shared.js +2 -2
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/otel.d.ts +66 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +56 -0
- package/dist/rateLimit.d.ts +9 -3
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +5 -11
- package/dist/test.d.ts +2 -2
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +1 -1
- package/dist/vitest.d.ts +1 -1
- package/examples/query.ts +39 -35
- package/package.json +45 -37
- package/src/CUPS.ts +9 -11
- package/src/Emailer/Sendgrid.ts +17 -14
- package/src/Emailer/service.ts +9 -3
- package/src/MainFiberSet.ts +5 -6
- package/src/Model/Repository/Registry.ts +33 -0
- package/src/Model/Repository/ext.ts +96 -10
- package/src/Model/Repository/internal/internal.ts +159 -139
- package/src/Model/Repository/makeRepo.ts +12 -10
- package/src/Model/Repository/service.ts +31 -22
- package/src/Model/Repository/validation.ts +4 -4
- package/src/Model/Repository.ts +1 -0
- package/src/Model/dsl.ts +3 -3
- package/src/Model/filter/types/path/eager.ts +1 -2
- package/src/Model/query/dsl.ts +18 -18
- package/src/Model/query/new-kid-interpreter.ts +2 -2
- package/src/Model.ts +1 -0
- package/src/QueueMaker/SQLQueue.ts +144 -152
- package/src/QueueMaker/memQueue.ts +104 -103
- package/src/QueueMaker/sbqueue.ts +70 -86
- package/src/RequestContext.ts +14 -16
- package/src/RequestFiberSet.ts +2 -2
- package/src/Store/ContextMapContainer.ts +41 -2
- package/src/Store/Cosmos/query.ts +16 -20
- package/src/Store/Cosmos.ts +473 -348
- package/src/Store/Disk.ts +102 -65
- package/src/Store/Memory.ts +118 -83
- package/src/Store/SQL/Pg.ts +352 -0
- package/src/Store/SQL/query.ts +409 -0
- package/src/Store/SQL.ts +734 -0
- package/src/Store/codeFilter.ts +3 -1
- package/src/Store/index.ts +17 -2
- package/src/Store/service.ts +32 -8
- package/src/Store/utils.ts +23 -22
- package/src/adapters/SQL/Model.ts +41 -40
- package/src/adapters/ServiceBus.ts +112 -116
- package/src/adapters/cosmos-client.ts +2 -2
- package/src/adapters/index.ts +7 -0
- 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 +12 -13
- package/src/api/internal/RequestContextMiddleware.ts +1 -1
- package/src/api/internal/auth.ts +246 -44
- package/src/api/internal/events.ts +13 -9
- package/src/api/layerUtils.ts +8 -8
- package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
- package/src/api/routing/middleware/middleware.ts +55 -14
- package/src/api/routing/middleware.ts +0 -2
- package/src/api/routing.ts +298 -128
- package/src/api/setupRequest.ts +28 -8
- package/src/arbs.ts +4 -2
- package/src/errorReporter.ts +62 -74
- package/src/logger/shared.ts +1 -1
- package/src/otel.ts +141 -0
- package/src/rateLimit.ts +30 -22
- package/src/test.ts +1 -1
- package/test/auth.test.ts +101 -0
- package/test/contextProvider.test.ts +11 -11
- package/test/controller.test.ts +21 -30
- package/test/dist/auth.test.d.ts.map +1 -0
- 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 +26 -12
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +12 -10
- package/test/dist/query.test.d.ts.map +1 -1
- package/test/dist/rawQuery.test.d.ts.map +1 -1
- package/test/dist/repository-ext.test.d.ts.map +1 -0
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/dist/router-generator.test.d.ts.map +1 -0
- package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
- package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
- package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
- package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
- package/test/dist/sql-store.test.d.ts.map +1 -0
- package/test/fixtures.ts +11 -9
- package/test/query.test.ts +216 -34
- package/test/rawQuery.test.ts +23 -19
- package/test/repository-ext.test.ts +60 -0
- package/test/requires.test.ts +6 -6
- package/test/router-generator.test.ts +183 -0
- package/test/routing-interruptibility.test.ts +63 -0
- package/test/rpc-e2e-invalidation.test.ts +251 -0
- package/test/rpc-multi-middleware.test.ts +78 -9
- package/test/rpc-stream-fullstack.test.ts +300 -0
- package/test/sql-store.test.ts +1064 -0
- package/test/validateSample.test.ts +15 -12
- package/tsconfig.examples.json +1 -1
- package/tsconfig.json +0 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +35 -35
- package/tsconfig.test.json +2 -2
- package/dist/Operations.d.ts +0 -55
- package/dist/Operations.d.ts.map +0 -1
- package/dist/Operations.js +0 -102
- package/dist/OperationsRepo.d.ts +0 -41
- package/dist/OperationsRepo.d.ts.map +0 -1
- package/dist/OperationsRepo.js +0 -14
- package/eslint.config.mjs +0 -24
- package/src/Operations.ts +0 -235
- package/src/OperationsRepo.ts +0 -16
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
|
|
3
|
-
import type
|
|
4
|
-
import { Array, Chunk, Effect, Equivalence, flow, type NonEmptyReadonlyArray, Option, pipe, Pipeable, PubSub, Result, S, SchemaAST, ServiceMap, Unify } from "effect-app"
|
|
2
|
+
|
|
3
|
+
import { Array, Chunk, Context, Effect, Equivalence, flow, type NonEmptyReadonlyArray, Option, pipe, Pipeable, PubSub, Result, S, SchemaAST, Unify } from "effect-app"
|
|
5
4
|
import { toNonEmptyArray } from "effect-app/Array"
|
|
6
5
|
import { NotFoundError } from "effect-app/client/errors"
|
|
7
6
|
import { flatMapOption } from "effect-app/Effect"
|
|
@@ -55,14 +54,14 @@ export function makeRepoInternal<
|
|
|
55
54
|
|
|
56
55
|
function make<RInitial = never, E = never, RPublish = never, RCtx = never>(
|
|
57
56
|
args: [Evt] extends [never] ? {
|
|
58
|
-
schemaContext?:
|
|
57
|
+
schemaContext?: Context.Context<RCtx>
|
|
59
58
|
makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
|
|
60
59
|
config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
|
|
61
60
|
partitionValue?: (e?: Encoded) => string
|
|
62
61
|
}
|
|
63
62
|
}
|
|
64
63
|
: {
|
|
65
|
-
schemaContext?:
|
|
64
|
+
schemaContext?: Context.Context<RCtx>
|
|
66
65
|
publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect.Effect<void, never, RPublish>
|
|
67
66
|
makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
|
|
68
67
|
config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
|
|
@@ -72,16 +71,16 @@ export function makeRepoInternal<
|
|
|
72
71
|
) {
|
|
73
72
|
return Effect
|
|
74
73
|
.gen(function*() {
|
|
75
|
-
const rctx:
|
|
74
|
+
const rctx: Context.Context<RCtx> = args.schemaContext ?? Context.empty() as any
|
|
76
75
|
const provideRctx = Effect.provide(rctx)
|
|
77
76
|
const encodeMany = flow(
|
|
78
77
|
S.encodeEffect(S.Array(schema)),
|
|
79
78
|
provideRctx,
|
|
80
|
-
Effect.withSpan("encodeMany", {}, { captureStackTrace: false })
|
|
79
|
+
Effect.withSpan("encodeMany", { attributes: { "app.entity": name } }, { captureStackTrace: false })
|
|
81
80
|
)
|
|
82
|
-
const decode = flow(S.
|
|
81
|
+
const decode = flow(S.decodeEffectConcurrently(schema), provideRctx)
|
|
83
82
|
const decodeMany = flow(
|
|
84
|
-
S.
|
|
83
|
+
S.decodeEffectConcurrently(S.Array(schema)),
|
|
85
84
|
provideRctx
|
|
86
85
|
)
|
|
87
86
|
|
|
@@ -113,11 +112,14 @@ export function makeRepoInternal<
|
|
|
113
112
|
let ast = _.ast
|
|
114
113
|
if (ast._tag === "Declaration") ast = ast.typeParameters[0]!
|
|
115
114
|
|
|
116
|
-
// In v4, to get the encoded (from) side of a schema, use SchemaAST.toEncoded
|
|
117
115
|
const pickIdFromAst = (a: SchemaAST.AST) => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
// Unwrap Declaration (e.g. TaggedClass) to get the underlying Objects AST
|
|
117
|
+
let inner = a
|
|
118
|
+
if (inner._tag === "Declaration") inner = inner.typeParameters[0]!
|
|
119
|
+
// Pick from the original AST to preserve the full encoding chain (e.g. decodeTo transformations).
|
|
120
|
+
// Using toEncoded would lose transformation info needed to encode Type -> Encoded.
|
|
121
|
+
if (SchemaAST.isObjects(inner)) {
|
|
122
|
+
const field = inner.propertySignatures.find((_) => _.name === idKey)
|
|
121
123
|
if (field) {
|
|
122
124
|
return S.Struct({ [idKey]: S.make(field.type) }) as unknown as Codec<T, Encoded>
|
|
123
125
|
}
|
|
@@ -138,7 +140,7 @@ export function makeRepoInternal<
|
|
|
138
140
|
Effect.map((_: Record<string, unknown>) => _[idKey as string] as Encoded[IdKey])
|
|
139
141
|
)
|
|
140
142
|
const findEId = Effect.fnUntraced(function*(id: Encoded[IdKey]) {
|
|
141
|
-
yield* Effect.annotateCurrentSpan({
|
|
143
|
+
yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
|
|
142
144
|
|
|
143
145
|
return yield* Effect.flatMap(
|
|
144
146
|
store.find(id),
|
|
@@ -151,7 +153,7 @@ export function makeRepoInternal<
|
|
|
151
153
|
})
|
|
152
154
|
// TODO: select the particular field, instead of as struct
|
|
153
155
|
const findE = Effect.fnUntraced(function*(id: T[IdKey]) {
|
|
154
|
-
yield* Effect.annotateCurrentSpan({
|
|
156
|
+
yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
|
|
155
157
|
|
|
156
158
|
return yield* pipe(
|
|
157
159
|
encodeId({ [idKey]: id } as any),
|
|
@@ -161,8 +163,8 @@ export function makeRepoInternal<
|
|
|
161
163
|
)
|
|
162
164
|
})
|
|
163
165
|
|
|
164
|
-
const find = Effect.fn("find")(function*(id: T[IdKey]) {
|
|
165
|
-
yield* Effect.annotateCurrentSpan({
|
|
166
|
+
const find = Effect.fn("find", { attributes: { "app.entity": name } })(function*(id: T[IdKey]) {
|
|
167
|
+
yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
|
|
166
168
|
|
|
167
169
|
return yield* flatMapOption(findE(id), (_) => Effect.orDie(decode(_)))
|
|
168
170
|
})
|
|
@@ -188,73 +190,86 @@ export function makeRepoInternal<
|
|
|
188
190
|
Effect.andThen(saveAllE)
|
|
189
191
|
)
|
|
190
192
|
|
|
191
|
-
const saveAndPublish = Effect.fn("saveAndPublish"
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
193
|
+
const saveAndPublish = Effect.fn("saveAndPublish", { attributes: { "app.entity": name } })(
|
|
194
|
+
function*(items: Iterable<T>, events: Iterable<Evt> = []) {
|
|
195
|
+
const it = Chunk.fromIterable(items)
|
|
196
|
+
const evts = [...events]
|
|
197
|
+
yield* Effect.annotateCurrentSpan({
|
|
198
|
+
"app.entity.ids": Chunk.map(it, (_) => _[idKey]),
|
|
199
|
+
"app.event.count": evts.length
|
|
200
|
+
})
|
|
201
|
+
return yield* saveAll(it)
|
|
202
|
+
.pipe(
|
|
203
|
+
Effect.andThen(Effect.sync(() => toNonEmptyArray(evts))),
|
|
204
|
+
// TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
|
|
205
|
+
(_) => flatMapOption(_, pub),
|
|
206
|
+
Effect.andThen(PubSub.publish(changeFeed, [Chunk.toArray(it), "save"] as [T[], "save" | "remove"])),
|
|
207
|
+
Effect.asVoid
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
)
|
|
204
211
|
|
|
205
|
-
const removeAndPublish = Effect.fn("removeAndPublish"
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
|
|
212
|
+
const removeAndPublish = Effect.fn("removeAndPublish", { attributes: { "app.entity": name } })(
|
|
213
|
+
function*(a: Iterable<T>, events: Iterable<Evt> = []) {
|
|
214
|
+
const { set } = yield* cms
|
|
215
|
+
const it = [...a]
|
|
216
|
+
const evts = [...events]
|
|
217
|
+
yield* Effect.annotateCurrentSpan({
|
|
218
|
+
"app.entity.ids": it.map((_) => _[idKey]),
|
|
219
|
+
"app.event.count": evts.length
|
|
220
|
+
})
|
|
221
|
+
const items = yield* encodeMany(it).pipe(Effect.orDie)
|
|
222
|
+
if (Array.isReadonlyArrayNonEmpty(items)) {
|
|
223
|
+
yield* store.batchRemove(
|
|
224
|
+
items.map((_) => (_[idKey])),
|
|
225
|
+
args.config?.partitionValue?.(items[0])
|
|
226
|
+
)
|
|
227
|
+
for (const e of items) {
|
|
228
|
+
set(e[idKey], undefined)
|
|
229
|
+
}
|
|
230
|
+
yield* Effect
|
|
231
|
+
.sync(() => toNonEmptyArray(evts))
|
|
232
|
+
// TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
|
|
233
|
+
.pipe((_) => flatMapOption(_, pub))
|
|
234
|
+
|
|
235
|
+
yield* PubSub.publish(changeFeed, [it, "remove"] as [T[], "save" | "remove"])
|
|
218
236
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
|
|
222
|
-
.pipe((_) => flatMapOption(_, pub))
|
|
237
|
+
}
|
|
238
|
+
)
|
|
223
239
|
|
|
224
|
-
|
|
240
|
+
const removeById = Effect.fn("removeById", { attributes: { "app.entity": name } })(
|
|
241
|
+
function*(idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>) {
|
|
242
|
+
const ids = globalThis.Array.isArray(idOrIds)
|
|
243
|
+
? idOrIds as readonly T[IdKey][]
|
|
244
|
+
: [idOrIds as T[IdKey]]
|
|
245
|
+
if (!Array.isReadonlyArrayNonEmpty(ids)) {
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
const { set } = yield* cms
|
|
249
|
+
const eids = yield* Effect.forEach(ids, (_) => encodeIdOnly(_ as any)).pipe(Effect.orDie)
|
|
250
|
+
yield* Effect.annotateCurrentSpan({ "app.entity.ids": eids })
|
|
251
|
+
yield* store.batchRemove(eids)
|
|
252
|
+
for (const id of eids) {
|
|
253
|
+
set(id, undefined)
|
|
254
|
+
}
|
|
255
|
+
yield* PubSub.publish(changeFeed, [[], "remove"] as [T[], "save" | "remove"])
|
|
225
256
|
}
|
|
226
|
-
|
|
257
|
+
)
|
|
227
258
|
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
259
|
+
const parseMany = Effect.fn("parseMany", { attributes: { "app.entity": name } })(
|
|
260
|
+
function*(items: readonly PM[]) {
|
|
261
|
+
const cm = yield* cms
|
|
262
|
+
return yield* decodeMany(items.map((_) => mapReverse(_, cm.set))).pipe(Effect.orDie)
|
|
231
263
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
264
|
+
)
|
|
265
|
+
const parseMany2 = Effect.fn("parseMany2", { attributes: { "app.entity": name } })(
|
|
266
|
+
function*<A, R>(items: readonly PM[], schema: S.Codec<A, Encoded, R>) {
|
|
267
|
+
const cm = yield* cms
|
|
268
|
+
return yield* S.decodeEffectConcurrently(S.Array(schema))(items.map((_) => mapReverse(_, cm.set))).pipe(
|
|
269
|
+
Effect.orDie
|
|
270
|
+
)
|
|
238
271
|
}
|
|
239
|
-
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
const parseMany = (items: readonly PM[]) =>
|
|
243
|
-
Effect
|
|
244
|
-
.flatMap(cms, (cm) =>
|
|
245
|
-
decodeMany(items.map((_) => mapReverse(_, cm.set)))
|
|
246
|
-
.pipe(Effect.orDie, Effect.withSpan("parseMany", {}, { captureStackTrace: false })))
|
|
247
|
-
const parseMany2 = <A, R>(
|
|
248
|
-
items: readonly PM[],
|
|
249
|
-
schema: S.Codec<A, Encoded, R>
|
|
250
|
-
) =>
|
|
251
|
-
Effect
|
|
252
|
-
.flatMap(cms, (cm) =>
|
|
253
|
-
S
|
|
254
|
-
.decodeEffect(S.Array(schema))(
|
|
255
|
-
items.map((_) => mapReverse(_, cm.set))
|
|
256
|
-
)
|
|
257
|
-
.pipe(Effect.orDie, Effect.withSpan("parseMany2", {}, { captureStackTrace: false })))
|
|
272
|
+
)
|
|
258
273
|
const filter = <U extends keyof Encoded = keyof Encoded>(args: FilterArgs<Encoded, U>) =>
|
|
259
274
|
store
|
|
260
275
|
.filter(
|
|
@@ -276,24 +291,24 @@ export function makeRepoInternal<
|
|
|
276
291
|
const query: {
|
|
277
292
|
<A, R, From extends FieldValues>(
|
|
278
293
|
q: Q.QueryProjection<Encoded extends From ? From : never, A, R>
|
|
279
|
-
): Effect.Effect<readonly A[], S.SchemaError, R
|
|
294
|
+
): Effect.Effect<readonly A[], S.SchemaError, Exclude<R, RCtx>>
|
|
280
295
|
<A, R, EncodedRefined extends Encoded = Encoded>(
|
|
281
296
|
q: Q.QAll<NoInfer<Encoded>, NoInfer<EncodedRefined>, A, R>
|
|
282
|
-
): Effect.Effect<readonly A[], never, R
|
|
297
|
+
): Effect.Effect<readonly A[], never, Exclude<R, RCtx>>
|
|
283
298
|
} = (<A, R, EncodedRefined extends Encoded = Encoded>(q: Q.QAll<Encoded, EncodedRefined, A, R>) => {
|
|
284
299
|
const a = Q.toFilter(q)
|
|
285
300
|
const eff = a.mode === "project"
|
|
286
301
|
? filter(a)
|
|
287
302
|
// TODO: mapFrom but need to support per field and dependencies
|
|
288
303
|
.pipe(
|
|
289
|
-
Effect.andThen(flow(S.
|
|
304
|
+
Effect.andThen(flow(S.decodeEffectConcurrently(S.Array(a.schema ?? schema)), provideRctx))
|
|
290
305
|
)
|
|
291
306
|
: a.mode === "collect"
|
|
292
307
|
? filter(a)
|
|
293
308
|
// TODO: mapFrom but need to support per field and dependencies
|
|
294
309
|
.pipe(
|
|
295
310
|
Effect.flatMap(flow(
|
|
296
|
-
S.
|
|
311
|
+
S.decodeEffectConcurrently(S.Array(a.schema)),
|
|
297
312
|
Effect.map(Array.getSomes),
|
|
298
313
|
provideRctx
|
|
299
314
|
))
|
|
@@ -325,72 +340,76 @@ export function makeRepoInternal<
|
|
|
325
340
|
.map(eff, (_) => NonNegativeInt(_.length))
|
|
326
341
|
.pipe(Effect.catchTag("SchemaError", (e) => Effect.die(e)))
|
|
327
342
|
: eff,
|
|
328
|
-
Effect.withSpan(
|
|
343
|
+
Effect.withSpan(`query ${name}`, {
|
|
344
|
+
kind: "client",
|
|
329
345
|
attributes: {
|
|
330
|
-
"
|
|
331
|
-
|
|
346
|
+
"app.entity": name,
|
|
347
|
+
"db.operation.name": "query",
|
|
348
|
+
"db.collection.name": name
|
|
332
349
|
}
|
|
333
350
|
}, { captureStackTrace: false })
|
|
334
351
|
)
|
|
335
352
|
}) as any
|
|
336
353
|
|
|
337
|
-
const validateSample = Effect.fn("validateSample")(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
// 3. validate each item
|
|
359
|
-
const errors: ValidationError[] = []
|
|
354
|
+
const validateSample = Effect.fn("validateSample", { attributes: { "app.entity": name } })(
|
|
355
|
+
function*(options?: {
|
|
356
|
+
percentage?: number
|
|
357
|
+
maxItems?: number
|
|
358
|
+
}) {
|
|
359
|
+
const percentage = options?.percentage ?? 0.1 // default 10%
|
|
360
|
+
const maxItems = options?.maxItems
|
|
361
|
+
|
|
362
|
+
// 1. get all IDs with projection (bypasses main schema decode)
|
|
363
|
+
const allIds = yield* store.filter({
|
|
364
|
+
t: null as unknown as Encoded,
|
|
365
|
+
select: [idKey as keyof Encoded]
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
// 2. random subset
|
|
369
|
+
const shuffled = [...allIds].sort(() => Math.random() - 0.5)
|
|
370
|
+
const sampleSize = Math.min(
|
|
371
|
+
maxItems ?? Infinity,
|
|
372
|
+
Math.ceil(allIds.length * percentage)
|
|
373
|
+
)
|
|
374
|
+
const sample = shuffled.slice(0, sampleSize)
|
|
360
375
|
|
|
361
|
-
|
|
362
|
-
const
|
|
363
|
-
const rawResult = yield* store.find(id)
|
|
376
|
+
// 3. validate each item
|
|
377
|
+
const errors: ValidationError[] = []
|
|
364
378
|
|
|
365
|
-
|
|
379
|
+
for (const item of sample) {
|
|
380
|
+
const id = item[idKey]
|
|
381
|
+
const rawResult = yield* store.find(id)
|
|
366
382
|
|
|
367
|
-
|
|
368
|
-
const jitMResult = mapFrom(rawData) // apply jitM
|
|
383
|
+
if (Option.isNone(rawResult)) continue
|
|
369
384
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
provideRctx
|
|
373
|
-
)
|
|
385
|
+
const rawData = rawResult.value as Encoded
|
|
386
|
+
const jitMResult = mapFrom(rawData) // apply jitM
|
|
374
387
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
id,
|
|
379
|
-
rawData,
|
|
380
|
-
jitMResult,
|
|
381
|
-
error: decodeResult.failure
|
|
382
|
-
})
|
|
388
|
+
const decodeResult = yield* S.decodeEffectConcurrently(schema)(jitMResult).pipe(
|
|
389
|
+
Effect.result,
|
|
390
|
+
provideRctx
|
|
383
391
|
)
|
|
392
|
+
|
|
393
|
+
if (Result.isFailure(decodeResult)) {
|
|
394
|
+
errors.push(
|
|
395
|
+
ValidationError.make({
|
|
396
|
+
id,
|
|
397
|
+
rawData,
|
|
398
|
+
jitMResult,
|
|
399
|
+
error: decodeResult.failure
|
|
400
|
+
})
|
|
401
|
+
)
|
|
402
|
+
}
|
|
384
403
|
}
|
|
385
|
-
}
|
|
386
404
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
405
|
+
return ValidationResult.make({
|
|
406
|
+
total: NonNegativeInt(allIds.length),
|
|
407
|
+
sampled: NonNegativeInt(sample.length),
|
|
408
|
+
valid: NonNegativeInt(sample.length - errors.length),
|
|
409
|
+
errors
|
|
410
|
+
})
|
|
411
|
+
}
|
|
412
|
+
)
|
|
394
413
|
|
|
395
414
|
const r = {
|
|
396
415
|
changeFeed,
|
|
@@ -401,9 +420,10 @@ export function makeRepoInternal<
|
|
|
401
420
|
saveAndPublish,
|
|
402
421
|
removeAndPublish,
|
|
403
422
|
removeById,
|
|
423
|
+
seedNamespace: (namespace: string) => store.seedNamespace(namespace),
|
|
404
424
|
validateSample,
|
|
405
425
|
queryRaw<A, Out, QR>(schema: S.Codec<A, Out, QR>, q: Q.RawQuery<Encoded, Out>) {
|
|
406
|
-
const dec = S.
|
|
426
|
+
const dec = S.decodeEffectConcurrently(S.Array(schema))
|
|
407
427
|
return store.queryRaw(q).pipe(Effect.flatMap(dec))
|
|
408
428
|
},
|
|
409
429
|
query(q: any) {
|
|
@@ -414,9 +434,9 @@ export function makeRepoInternal<
|
|
|
414
434
|
* @internal
|
|
415
435
|
*/
|
|
416
436
|
mapped: <A, R>(schema: S.Codec<A, any, R>) => {
|
|
417
|
-
const dec = S.
|
|
437
|
+
const dec = S.decodeEffectConcurrently(schema)
|
|
418
438
|
const encMany = S.encodeEffect(S.Array(schema))
|
|
419
|
-
const decMany = S.
|
|
439
|
+
const decMany = S.decodeEffectConcurrently(S.Array(schema))
|
|
420
440
|
return {
|
|
421
441
|
all: allE.pipe(
|
|
422
442
|
Effect.flatMap(decMany),
|
|
@@ -441,12 +461,12 @@ export function makeRepoInternal<
|
|
|
441
461
|
// },
|
|
442
462
|
save: (...xes: any[]) =>
|
|
443
463
|
Effect.flatMap(encMany(xes), (_) => saveAllE(_)).pipe(
|
|
444
|
-
Effect.withSpan("mapped.save", {}, { captureStackTrace: false })
|
|
464
|
+
Effect.withSpan("mapped.save", { attributes: { "app.entity": name } }, { captureStackTrace: false })
|
|
445
465
|
)
|
|
446
466
|
}
|
|
447
467
|
}
|
|
448
468
|
}
|
|
449
|
-
return r as Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<R, RCtx>, RPublish>
|
|
469
|
+
return r as Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<R, RCtx>, RPublish, RCtx>
|
|
450
470
|
})
|
|
451
471
|
.pipe(Effect
|
|
452
472
|
// .withSpan("Repository.make [effect-app/infra]", { attributes: { "repository.model_name": name } })
|
|
@@ -513,7 +533,7 @@ export function makeStore<Encoded extends FieldValues>() {
|
|
|
513
533
|
.pipe(
|
|
514
534
|
Effect.flatMap(Effect.forEach(encodeToEncoded())),
|
|
515
535
|
setupRequestContextFromCurrent("Repository.makeInitial [effect-app/infra]", {
|
|
516
|
-
attributes: { "
|
|
536
|
+
attributes: { "app.entity": name }
|
|
517
537
|
})
|
|
518
538
|
)
|
|
519
539
|
: undefined,
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
6
6
|
|
|
7
7
|
// import type { ParserEnv } from "effect-app/Schema/custom/Parser"
|
|
8
|
-
|
|
9
|
-
import type
|
|
10
|
-
import { Effect, type NonEmptyReadonlyArray, type S, type ServiceMap } from "effect-app"
|
|
8
|
+
|
|
9
|
+
import { type Context, Effect, type NonEmptyReadonlyArray, type S } from "effect-app"
|
|
11
10
|
import type { StoreConfig, StoreMaker } from "../../Store.js"
|
|
12
11
|
import type { FieldValues } from "../filter/types.js"
|
|
13
12
|
import { type ExtendedRepository, extendRepo } from "./ext.js"
|
|
14
13
|
import { makeRepoInternal } from "./internal/internal.js"
|
|
14
|
+
import { RepositoryRegistry } from "./Registry.js"
|
|
15
15
|
import type { Repository } from "./service.js"
|
|
16
16
|
|
|
17
17
|
export interface RepositoryOptions<
|
|
@@ -52,11 +52,11 @@ export interface RepositoryOptions<
|
|
|
52
52
|
* Optional context to be provided to Schema decode/encode.
|
|
53
53
|
* Useful for effectful transformations like XWithItems, where items is a transformation retrieving elements from another database table or other source.
|
|
54
54
|
*/
|
|
55
|
-
schemaContext?:
|
|
55
|
+
schemaContext?: Context.Context<RCtx>
|
|
56
56
|
|
|
57
57
|
overrides?: (
|
|
58
|
-
repo: Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>
|
|
59
|
-
) => Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>
|
|
58
|
+
repo: Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>
|
|
59
|
+
) => Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -83,9 +83,9 @@ export const makeRepo: {
|
|
|
83
83
|
schema: S.Codec<T, Encoded, RSchema>,
|
|
84
84
|
options: RepositoryOptions<IdKey, Encoded, T, ItemType, Evt, RPublish, E, RInitial, RCtx, RSchema>
|
|
85
85
|
): Effect.Effect<
|
|
86
|
-
ExtendedRepository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>,
|
|
86
|
+
ExtendedRepository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>,
|
|
87
87
|
E,
|
|
88
|
-
RInitial | StoreMaker
|
|
88
|
+
RInitial | StoreMaker | RepositoryRegistry
|
|
89
89
|
>
|
|
90
90
|
<
|
|
91
91
|
ItemType extends string,
|
|
@@ -102,9 +102,9 @@ export const makeRepo: {
|
|
|
102
102
|
schema: S.Codec<T, Encoded, RSchema>,
|
|
103
103
|
options: Omit<RepositoryOptions<"id", Encoded, T, ItemType, Evt, RPublish, E, RInitial, RCtx, RSchema>, "idKey">
|
|
104
104
|
): Effect.Effect<
|
|
105
|
-
ExtendedRepository<T, Encoded, Evt, ItemType, "id", Exclude<RSchema, RCtx>, RPublish>,
|
|
105
|
+
ExtendedRepository<T, Encoded, Evt, ItemType, "id", Exclude<RSchema, RCtx>, RPublish, RCtx>,
|
|
106
106
|
E,
|
|
107
|
-
RInitial | StoreMaker
|
|
107
|
+
RInitial | StoreMaker | RepositoryRegistry
|
|
108
108
|
>
|
|
109
109
|
} = <
|
|
110
110
|
ItemType extends string,
|
|
@@ -135,5 +135,7 @@ export const makeRepo: {
|
|
|
135
135
|
let r = yield* mkRepo.make<RInitial, E, RPublish, RCtx>(options as any)
|
|
136
136
|
if (options.overrides) r = options.overrides(r)
|
|
137
137
|
const repo = extendRepo(r)
|
|
138
|
+
const registry = yield* RepositoryRegistry
|
|
139
|
+
registry.register(itemType, repo)
|
|
138
140
|
return repo
|
|
139
141
|
})
|