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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-app",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.249",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -66,6 +66,10 @@
|
|
|
66
66
|
"types": "./dist/Effect.d.ts",
|
|
67
67
|
"default": "./dist/Effect.js"
|
|
68
68
|
},
|
|
69
|
+
"./Emailer": {
|
|
70
|
+
"types": "./dist/Emailer.d.ts",
|
|
71
|
+
"default": "./dist/Emailer.js"
|
|
72
|
+
},
|
|
69
73
|
"./Function": {
|
|
70
74
|
"types": "./dist/Function.d.ts",
|
|
71
75
|
"default": "./dist/Function.js"
|
|
@@ -78,6 +82,90 @@
|
|
|
78
82
|
"types": "./dist/Layer.d.ts",
|
|
79
83
|
"default": "./dist/Layer.js"
|
|
80
84
|
},
|
|
85
|
+
"./Model": {
|
|
86
|
+
"types": "./dist/Model.d.ts",
|
|
87
|
+
"default": "./dist/Model.js"
|
|
88
|
+
},
|
|
89
|
+
"./Model/Repository": {
|
|
90
|
+
"types": "./dist/Model/Repository.d.ts",
|
|
91
|
+
"default": "./dist/Model/Repository.js"
|
|
92
|
+
},
|
|
93
|
+
"./Model/Repository/Registry": {
|
|
94
|
+
"types": "./dist/Model/Repository/Registry.d.ts",
|
|
95
|
+
"default": "./dist/Model/Repository/Registry.js"
|
|
96
|
+
},
|
|
97
|
+
"./Model/Repository/ext": {
|
|
98
|
+
"types": "./dist/Model/Repository/ext.d.ts",
|
|
99
|
+
"default": "./dist/Model/Repository/ext.js"
|
|
100
|
+
},
|
|
101
|
+
"./Model/Repository/legacy": {
|
|
102
|
+
"types": "./dist/Model/Repository/legacy.d.ts",
|
|
103
|
+
"default": "./dist/Model/Repository/legacy.js"
|
|
104
|
+
},
|
|
105
|
+
"./Model/Repository/makeRepo": {
|
|
106
|
+
"types": "./dist/Model/Repository/makeRepo.d.ts",
|
|
107
|
+
"default": "./dist/Model/Repository/makeRepo.js"
|
|
108
|
+
},
|
|
109
|
+
"./Model/Repository/service": {
|
|
110
|
+
"types": "./dist/Model/Repository/service.d.ts",
|
|
111
|
+
"default": "./dist/Model/Repository/service.js"
|
|
112
|
+
},
|
|
113
|
+
"./Model/Repository/validation": {
|
|
114
|
+
"types": "./dist/Model/Repository/validation.d.ts",
|
|
115
|
+
"default": "./dist/Model/Repository/validation.js"
|
|
116
|
+
},
|
|
117
|
+
"./Model/dsl": {
|
|
118
|
+
"types": "./dist/Model/dsl.d.ts",
|
|
119
|
+
"default": "./dist/Model/dsl.js"
|
|
120
|
+
},
|
|
121
|
+
"./Model/filter/filterApi": {
|
|
122
|
+
"types": "./dist/Model/filter/filterApi.d.ts",
|
|
123
|
+
"default": "./dist/Model/filter/filterApi.js"
|
|
124
|
+
},
|
|
125
|
+
"./Model/filter/types": {
|
|
126
|
+
"types": "./dist/Model/filter/types.d.ts",
|
|
127
|
+
"default": "./dist/Model/filter/types.js"
|
|
128
|
+
},
|
|
129
|
+
"./Model/filter/types/errors": {
|
|
130
|
+
"types": "./dist/Model/filter/types/errors.d.ts",
|
|
131
|
+
"default": "./dist/Model/filter/types/errors.js"
|
|
132
|
+
},
|
|
133
|
+
"./Model/filter/types/fields": {
|
|
134
|
+
"types": "./dist/Model/filter/types/fields.d.ts",
|
|
135
|
+
"default": "./dist/Model/filter/types/fields.js"
|
|
136
|
+
},
|
|
137
|
+
"./Model/filter/types/path/common": {
|
|
138
|
+
"types": "./dist/Model/filter/types/path/common.d.ts",
|
|
139
|
+
"default": "./dist/Model/filter/types/path/common.js"
|
|
140
|
+
},
|
|
141
|
+
"./Model/filter/types/path/eager": {
|
|
142
|
+
"types": "./dist/Model/filter/types/path/eager.d.ts",
|
|
143
|
+
"default": "./dist/Model/filter/types/path/eager.js"
|
|
144
|
+
},
|
|
145
|
+
"./Model/filter/types/path/index": {
|
|
146
|
+
"types": "./dist/Model/filter/types/path/index.d.ts",
|
|
147
|
+
"default": "./dist/Model/filter/types/path/index.js"
|
|
148
|
+
},
|
|
149
|
+
"./Model/filter/types/utils": {
|
|
150
|
+
"types": "./dist/Model/filter/types/utils.d.ts",
|
|
151
|
+
"default": "./dist/Model/filter/types/utils.js"
|
|
152
|
+
},
|
|
153
|
+
"./Model/filter/types/validator": {
|
|
154
|
+
"types": "./dist/Model/filter/types/validator.d.ts",
|
|
155
|
+
"default": "./dist/Model/filter/types/validator.js"
|
|
156
|
+
},
|
|
157
|
+
"./Model/query": {
|
|
158
|
+
"types": "./dist/Model/query.d.ts",
|
|
159
|
+
"default": "./dist/Model/query.js"
|
|
160
|
+
},
|
|
161
|
+
"./Model/query/dsl": {
|
|
162
|
+
"types": "./dist/Model/query/dsl.d.ts",
|
|
163
|
+
"default": "./dist/Model/query/dsl.js"
|
|
164
|
+
},
|
|
165
|
+
"./Model/query/new-kid-interpreter": {
|
|
166
|
+
"types": "./dist/Model/query/new-kid-interpreter.d.ts",
|
|
167
|
+
"default": "./dist/Model/query/new-kid-interpreter.js"
|
|
168
|
+
},
|
|
81
169
|
"./NonEmptySet": {
|
|
82
170
|
"types": "./dist/NonEmptySet.d.ts",
|
|
83
171
|
"default": "./dist/NonEmptySet.js"
|
|
@@ -90,6 +178,14 @@
|
|
|
90
178
|
"types": "./dist/Pure.d.ts",
|
|
91
179
|
"default": "./dist/Pure.js"
|
|
92
180
|
},
|
|
181
|
+
"./QueueMaker": {
|
|
182
|
+
"types": "./dist/QueueMaker.d.ts",
|
|
183
|
+
"default": "./dist/QueueMaker.js"
|
|
184
|
+
},
|
|
185
|
+
"./RequestContext": {
|
|
186
|
+
"types": "./dist/RequestContext.d.ts",
|
|
187
|
+
"default": "./dist/RequestContext.js"
|
|
188
|
+
},
|
|
93
189
|
"./Schema": {
|
|
94
190
|
"types": "./dist/Schema.d.ts",
|
|
95
191
|
"default": "./dist/Schema.js"
|
|
@@ -154,6 +250,10 @@
|
|
|
154
250
|
"types": "./dist/Set.d.ts",
|
|
155
251
|
"default": "./dist/Set.js"
|
|
156
252
|
},
|
|
253
|
+
"./Store": {
|
|
254
|
+
"types": "./dist/Store.d.ts",
|
|
255
|
+
"default": "./dist/Store.js"
|
|
256
|
+
},
|
|
157
257
|
"./TypeTest": {
|
|
158
258
|
"types": "./dist/TypeTest.d.ts",
|
|
159
259
|
"default": "./dist/TypeTest.js"
|
|
@@ -254,6 +354,14 @@
|
|
|
254
354
|
"types": "./dist/rpc/RpcMiddleware.d.ts",
|
|
255
355
|
"default": "./dist/rpc/RpcMiddleware.js"
|
|
256
356
|
},
|
|
357
|
+
"./runtime": {
|
|
358
|
+
"types": "./dist/runtime.d.ts",
|
|
359
|
+
"default": "./dist/runtime.js"
|
|
360
|
+
},
|
|
361
|
+
"./toast": {
|
|
362
|
+
"types": "./dist/toast.d.ts",
|
|
363
|
+
"default": "./dist/toast.js"
|
|
364
|
+
},
|
|
257
365
|
"./transform": {
|
|
258
366
|
"types": "./dist/transform.d.ts",
|
|
259
367
|
"default": "./dist/transform.js"
|
|
@@ -289,6 +397,10 @@
|
|
|
289
397
|
"./validation/validators": {
|
|
290
398
|
"types": "./dist/validation/validators.d.ts",
|
|
291
399
|
"default": "./dist/validation/validators.js"
|
|
400
|
+
},
|
|
401
|
+
"./withToast": {
|
|
402
|
+
"types": "./dist/withToast.d.ts",
|
|
403
|
+
"default": "./dist/withToast.js"
|
|
292
404
|
}
|
|
293
405
|
},
|
|
294
406
|
"gitHead": "bd8e27eea3eff97db8739d577d67e7336c078d28",
|
package/src/Emailer.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as Data from "effect/Data"
|
|
2
|
+
import type { NonEmptyReadonlyArray } from "./Array.js"
|
|
3
|
+
import * as Context from "./Context.js"
|
|
4
|
+
import type * as Effect from "./Effect.js"
|
|
5
|
+
import type { Email } from "./Schema.js"
|
|
6
|
+
|
|
7
|
+
export class SendMailError extends Data.TaggedError("SendMailError")<{
|
|
8
|
+
readonly raw: Error
|
|
9
|
+
}> {}
|
|
10
|
+
|
|
11
|
+
export class Emailer extends Context.Opaque<Emailer, {
|
|
12
|
+
sendMail: (msg: EmailMsgOptionalFrom) => Effect.Effect<void, SendMailError>
|
|
13
|
+
}>()("effect-app/Emailer") {}
|
|
14
|
+
|
|
15
|
+
export type EmailData = Email | {
|
|
16
|
+
name?: string
|
|
17
|
+
email: Email
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface EmailContentPart {
|
|
21
|
+
type: string
|
|
22
|
+
value: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type EmailRecipients = EmailData | NonEmptyReadonlyArray<EmailData>
|
|
26
|
+
|
|
27
|
+
export interface EmailMsgBase {
|
|
28
|
+
readonly to: EmailRecipients
|
|
29
|
+
readonly cc?: EmailRecipients
|
|
30
|
+
readonly bcc?: EmailRecipients
|
|
31
|
+
readonly from: EmailData
|
|
32
|
+
readonly replyTo?: EmailData
|
|
33
|
+
readonly subject?: string
|
|
34
|
+
/**
|
|
35
|
+
* should multiple `to` addresess be considered multiple emails?
|
|
36
|
+
* defaults to `true`, not to leak email addresses
|
|
37
|
+
*/
|
|
38
|
+
readonly isMultiple?: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type EmailContent =
|
|
42
|
+
| { text: string }
|
|
43
|
+
| { html: string }
|
|
44
|
+
| { templateId: string }
|
|
45
|
+
| { content: NonEmptyReadonlyArray<EmailContentPart> }
|
|
46
|
+
|
|
47
|
+
export type EmailMsg =
|
|
48
|
+
& EmailMsgBase
|
|
49
|
+
& EmailContent
|
|
50
|
+
|
|
51
|
+
export type EmailMsgOptionalFrom = Omit<EmailMsgBase, "from"> & Partial<Pick<EmailMsg, "from">> & EmailContent
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as Context from "../../Context.js"
|
|
2
|
+
import * as Effect from "../../Effect.js"
|
|
3
|
+
|
|
4
|
+
export interface RegisteredRepository {
|
|
5
|
+
readonly seedNamespace: (namespace: string) => Effect.Effect<void>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const make = Effect.sync(() => {
|
|
9
|
+
const repos = new Map<string, RegisteredRepository>()
|
|
10
|
+
return {
|
|
11
|
+
register(modelName: string, repo: RegisteredRepository) {
|
|
12
|
+
repos.set(modelName, repo)
|
|
13
|
+
},
|
|
14
|
+
seedNamespace: (namespace: string) =>
|
|
15
|
+
Effect.suspend(() =>
|
|
16
|
+
Effect.forEach(
|
|
17
|
+
repos.values(),
|
|
18
|
+
(r) => r.seedNamespace(namespace),
|
|
19
|
+
{ concurrency: "unbounded", discard: true }
|
|
20
|
+
)
|
|
21
|
+
),
|
|
22
|
+
get entries(): ReadonlyMap<string, RegisteredRepository> {
|
|
23
|
+
return repos
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
export class RepositoryRegistry extends Context.Opaque<RepositoryRegistry, {
|
|
29
|
+
readonly register: (modelName: string, repo: RegisteredRepository) => void
|
|
30
|
+
readonly seedNamespace: (namespace: string) => Effect.Effect<void>
|
|
31
|
+
readonly entries: ReadonlyMap<string, RegisteredRepository>
|
|
32
|
+
}>()("effect-app/RepositoryRegistry", { make }) {}
|
|
33
|
+
|
|
34
|
+
export const RepositoryRegistryLive = RepositoryRegistry.toLayer(RepositoryRegistry.make)
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
|
+
import * as Exit from "effect/Exit"
|
|
4
|
+
import * as Request from "effect/Request"
|
|
5
|
+
import * as RequestResolver from "effect/RequestResolver"
|
|
6
|
+
import * as Array from "../../Array.js"
|
|
7
|
+
import type { NonEmptyArray } from "../../Array.js"
|
|
8
|
+
import { type InvalidStateError, NotFoundError, type OptimisticConcurrencyException } from "../../client/errors.js"
|
|
9
|
+
import * as Effect from "../../Effect.js"
|
|
10
|
+
import * as Option from "../../Option.js"
|
|
11
|
+
import { type FixEnv, type PureEnv, runTerm } from "../../Pure.js"
|
|
12
|
+
import { AnyPureDSL } from "../dsl.js"
|
|
13
|
+
import type { FieldValues } from "../filter/types.js"
|
|
14
|
+
import type { Query, QueryEnd, QueryWhere } from "../query.js"
|
|
15
|
+
import * as Q from "../query.js"
|
|
16
|
+
import type { Repository } from "./service.js"
|
|
17
|
+
|
|
18
|
+
interface BatchOptions {
|
|
19
|
+
readonly batch?: true | number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const asReadonlyArray = <T>(itemOrItems: T | ReadonlyArray<T>): ReadonlyArray<T> =>
|
|
23
|
+
globalThis.Array.isArray(itemOrItems)
|
|
24
|
+
? itemOrItems as ReadonlyArray<T>
|
|
25
|
+
: [itemOrItems as T]
|
|
26
|
+
|
|
27
|
+
const getBatchSize = (batch?: true | number) =>
|
|
28
|
+
batch === true
|
|
29
|
+
? 100
|
|
30
|
+
: typeof batch === "number" && Number.isFinite(batch) && batch > 0
|
|
31
|
+
? Math.floor(batch)
|
|
32
|
+
: undefined
|
|
33
|
+
|
|
34
|
+
export const extendRepo = <
|
|
35
|
+
T,
|
|
36
|
+
Encoded extends FieldValues,
|
|
37
|
+
Evt,
|
|
38
|
+
ItemType extends string,
|
|
39
|
+
IdKey extends keyof T & keyof Encoded,
|
|
40
|
+
RSchema,
|
|
41
|
+
RPublish,
|
|
42
|
+
RProvided = never
|
|
43
|
+
>(
|
|
44
|
+
repo: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided>
|
|
45
|
+
) => {
|
|
46
|
+
const get = (id: T[IdKey]) =>
|
|
47
|
+
repo.find(id).pipe(
|
|
48
|
+
Effect.flatMap(Option.match({
|
|
49
|
+
onNone: () => Effect.fail(new NotFoundError<ItemType>({ type: repo.itemType, id })),
|
|
50
|
+
onSome: Effect.succeed
|
|
51
|
+
}))
|
|
52
|
+
)
|
|
53
|
+
function saveManyWithPure_<
|
|
54
|
+
R,
|
|
55
|
+
A,
|
|
56
|
+
E,
|
|
57
|
+
S1 extends T,
|
|
58
|
+
S2 extends T
|
|
59
|
+
>(
|
|
60
|
+
items: Iterable<S1>,
|
|
61
|
+
pure: Effect.Effect<A, E, FixEnv<R, Evt, readonly S1[], readonly S2[]>>
|
|
62
|
+
) {
|
|
63
|
+
return saveAllWithEffectInt(
|
|
64
|
+
runTerm(pure, [...items])
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function saveWithPure_<
|
|
69
|
+
R,
|
|
70
|
+
A,
|
|
71
|
+
E,
|
|
72
|
+
S1 extends T,
|
|
73
|
+
S2 extends T
|
|
74
|
+
>(
|
|
75
|
+
item: S1,
|
|
76
|
+
pure: Effect.Effect<A, E, FixEnv<R, Evt, S1, S2>>
|
|
77
|
+
) {
|
|
78
|
+
return saveAllWithEffectInt(
|
|
79
|
+
runTerm(pure, item)
|
|
80
|
+
.pipe(Effect
|
|
81
|
+
.map(([item, events, a]) => [[item], events, a]))
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function saveAllWithEffectInt<
|
|
86
|
+
P extends T,
|
|
87
|
+
R,
|
|
88
|
+
E,
|
|
89
|
+
A
|
|
90
|
+
>(
|
|
91
|
+
gen: Effect.Effect<readonly [Iterable<P>, Iterable<Evt>, A], E, R>
|
|
92
|
+
) {
|
|
93
|
+
return Effect.flatMap(gen, ([items, events, a]) => repo.saveAndPublish(items, events).pipe(Effect.map(() => a)))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function saveManyWithPureBatched_<
|
|
97
|
+
R,
|
|
98
|
+
A,
|
|
99
|
+
E,
|
|
100
|
+
S1 extends T,
|
|
101
|
+
S2 extends T
|
|
102
|
+
>(
|
|
103
|
+
items: Iterable<S1>,
|
|
104
|
+
pure: Effect.Effect<A, E, FixEnv<R, Evt, readonly S1[], readonly S2[]>>,
|
|
105
|
+
batchSize = 100
|
|
106
|
+
) {
|
|
107
|
+
return Effect.forEach(
|
|
108
|
+
Array.chunksOf(items, batchSize),
|
|
109
|
+
(batch) =>
|
|
110
|
+
saveAllWithEffectInt(
|
|
111
|
+
runTerm(pure, batch)
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const queryAndSavePure: {
|
|
117
|
+
<A, E2, R2, T2 extends T>(
|
|
118
|
+
q: (
|
|
119
|
+
q: Query<Encoded>
|
|
120
|
+
) => QueryEnd<Encoded, "one">,
|
|
121
|
+
pure: Effect.Effect<A, E2, FixEnv<R2, Evt, T, T2>>
|
|
122
|
+
): Effect.Effect<
|
|
123
|
+
A,
|
|
124
|
+
InvalidStateError | OptimisticConcurrencyException | NotFoundError<ItemType> | E2,
|
|
125
|
+
Exclude<R2, {
|
|
126
|
+
env: PureEnv<Evt, T, T2>
|
|
127
|
+
}>
|
|
128
|
+
>
|
|
129
|
+
<A, E2, R2, T2 extends T>(
|
|
130
|
+
q: (
|
|
131
|
+
q: Query<Encoded>
|
|
132
|
+
) =>
|
|
133
|
+
| Query<Encoded>
|
|
134
|
+
| QueryWhere<Encoded>
|
|
135
|
+
| QueryEnd<Encoded>,
|
|
136
|
+
pure: Effect.Effect<A, E2, FixEnv<R2, Evt, readonly T[], readonly T2[]>>
|
|
137
|
+
): Effect.Effect<
|
|
138
|
+
A,
|
|
139
|
+
InvalidStateError | OptimisticConcurrencyException | E2,
|
|
140
|
+
| RSchema
|
|
141
|
+
| RPublish
|
|
142
|
+
| Exclude<R2, {
|
|
143
|
+
env: PureEnv<Evt, readonly T[], readonly T2[]>
|
|
144
|
+
}>
|
|
145
|
+
>
|
|
146
|
+
<A, E2, R2, T2 extends T>(
|
|
147
|
+
q: (
|
|
148
|
+
q: Query<Encoded>
|
|
149
|
+
) =>
|
|
150
|
+
| Query<Encoded>
|
|
151
|
+
| QueryWhere<Encoded>
|
|
152
|
+
| QueryEnd<Encoded>,
|
|
153
|
+
pure: Effect.Effect<A, E2, FixEnv<R2, Evt, readonly T[], readonly T2[]>>,
|
|
154
|
+
batch: "batched" | number
|
|
155
|
+
): Effect.Effect<
|
|
156
|
+
A[],
|
|
157
|
+
InvalidStateError | OptimisticConcurrencyException | E2,
|
|
158
|
+
| RSchema
|
|
159
|
+
| RPublish
|
|
160
|
+
| Exclude<R2, {
|
|
161
|
+
env: PureEnv<Evt, readonly T[], readonly T2[]>
|
|
162
|
+
}>
|
|
163
|
+
>
|
|
164
|
+
} = (q, pure, batch?: "batched" | number) =>
|
|
165
|
+
repo.query(q).pipe(
|
|
166
|
+
Effect.andThen((_) =>
|
|
167
|
+
Array.isArray(_)
|
|
168
|
+
? batch === undefined
|
|
169
|
+
? saveManyWithPure_(_ as any, pure as any)
|
|
170
|
+
: saveManyWithPureBatched_(_ as any, pure as any, batch === "batched" ? 100 : batch)
|
|
171
|
+
: saveWithPure_(_ as any, pure as any)
|
|
172
|
+
)
|
|
173
|
+
) as any
|
|
174
|
+
|
|
175
|
+
const saveManyWithPure: {
|
|
176
|
+
<R, A, E, S1 extends T, S2 extends T>(
|
|
177
|
+
items: Iterable<S1>,
|
|
178
|
+
pure: Effect.Effect<A, E, FixEnv<R, Evt, readonly S1[], readonly S2[]>>
|
|
179
|
+
): Effect.Effect<
|
|
180
|
+
A,
|
|
181
|
+
InvalidStateError | OptimisticConcurrencyException | E,
|
|
182
|
+
| RSchema
|
|
183
|
+
| RPublish
|
|
184
|
+
| Exclude<R, {
|
|
185
|
+
env: PureEnv<Evt, readonly S1[], readonly S2[]>
|
|
186
|
+
}>
|
|
187
|
+
>
|
|
188
|
+
<R, A, E, S1 extends T, S2 extends T>(
|
|
189
|
+
items: Iterable<S1>,
|
|
190
|
+
pure: Effect.Effect<A, E, FixEnv<R, Evt, readonly S1[], readonly S2[]>>,
|
|
191
|
+
batch: "batched" | number
|
|
192
|
+
): Effect.Effect<
|
|
193
|
+
A[],
|
|
194
|
+
InvalidStateError | OptimisticConcurrencyException | E,
|
|
195
|
+
| RSchema
|
|
196
|
+
| RPublish
|
|
197
|
+
| Exclude<R, {
|
|
198
|
+
env: PureEnv<Evt, readonly S1[], readonly S2[]>
|
|
199
|
+
}>
|
|
200
|
+
>
|
|
201
|
+
} = (items, pure, batch?: "batched" | number) =>
|
|
202
|
+
batch
|
|
203
|
+
? Effect.forEach(
|
|
204
|
+
Array.chunksOf(items, batch === "batched" ? 100 : batch),
|
|
205
|
+
(batch) =>
|
|
206
|
+
saveAllWithEffectInt(
|
|
207
|
+
runTerm(pure, batch)
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
: saveAllWithEffectInt(
|
|
211
|
+
runTerm(pure, [...items])
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
const byIdAndSaveWithPure: {
|
|
215
|
+
<R, A, E, S2 extends T>(
|
|
216
|
+
id: T[IdKey],
|
|
217
|
+
pure: Effect.Effect<A, E, FixEnv<R, Evt, T, S2>>
|
|
218
|
+
): Effect.Effect<
|
|
219
|
+
A,
|
|
220
|
+
InvalidStateError | OptimisticConcurrencyException | NotFoundError<ItemType> | E,
|
|
221
|
+
| RSchema
|
|
222
|
+
| RPublish
|
|
223
|
+
| Exclude<R, {
|
|
224
|
+
env: PureEnv<Evt, T, S2>
|
|
225
|
+
}>
|
|
226
|
+
>
|
|
227
|
+
} = (id, pure): any => get(id).pipe(Effect.flatMap((item) => saveWithPure_(item, pure)))
|
|
228
|
+
|
|
229
|
+
type Req =
|
|
230
|
+
& Request.Request<T, NotFoundError<ItemType>>
|
|
231
|
+
& { _tag: `Get${ItemType}`; id: T[IdKey] }
|
|
232
|
+
const _request = Request.tagged<Req>(`Get${repo.itemType}`)
|
|
233
|
+
|
|
234
|
+
const requestResolver = RequestResolver
|
|
235
|
+
.make((
|
|
236
|
+
entries: NonEmptyArray<Request.Entry<Req>>,
|
|
237
|
+
_key: unknown
|
|
238
|
+
) =>
|
|
239
|
+
(repo.query(Q.where(repo.idKey as any, "in" as any, entries.map((_) => _.request.id)) as any) as Effect.Effect<
|
|
240
|
+
readonly T[]
|
|
241
|
+
>)
|
|
242
|
+
// TODO
|
|
243
|
+
.pipe(
|
|
244
|
+
Effect.andThen((items) =>
|
|
245
|
+
Effect.forEach(entries, (entry) =>
|
|
246
|
+
Request.complete(
|
|
247
|
+
Array
|
|
248
|
+
.findFirst(items, (_) => _[repo.idKey] === entry.request.id)
|
|
249
|
+
.pipe(Option.match({
|
|
250
|
+
onNone: () => Exit.fail(new NotFoundError({ type: repo.itemType, id: entry.request.id })),
|
|
251
|
+
onSome: Exit.succeed
|
|
252
|
+
}))
|
|
253
|
+
)(entry), { discard: true })
|
|
254
|
+
),
|
|
255
|
+
Effect
|
|
256
|
+
.catchCause((cause) =>
|
|
257
|
+
Effect.forEach(entries, (entry) => Request.complete(Exit.failCause(cause))(entry), { discard: true })
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
)
|
|
261
|
+
.pipe(
|
|
262
|
+
RequestResolver.batchN(20)
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
const exts = {
|
|
266
|
+
request: (id: T[IdKey]) => Effect.request(_request({ id }), requestResolver),
|
|
267
|
+
get,
|
|
268
|
+
log: (evt: Evt) => AnyPureDSL.log(evt),
|
|
269
|
+
/**
|
|
270
|
+
* Enables chunked writes for large batches via `options.batch`.
|
|
271
|
+
* Note: batching breaks transactional properties because chunks are saved independently.
|
|
272
|
+
*/
|
|
273
|
+
save: ((itemOrItems: T | ReadonlyArray<T>, options?: BatchOptions) => {
|
|
274
|
+
const items = asReadonlyArray(itemOrItems)
|
|
275
|
+
if (!Array.isReadonlyArrayNonEmpty(items)) {
|
|
276
|
+
return Effect.void
|
|
277
|
+
}
|
|
278
|
+
const batchSize = getBatchSize(options?.batch)
|
|
279
|
+
if (batchSize === undefined) {
|
|
280
|
+
return repo.saveAndPublish(items)
|
|
281
|
+
}
|
|
282
|
+
return Effect.forEach(
|
|
283
|
+
Array.chunksOf(items, batchSize),
|
|
284
|
+
(batch) => repo.saveAndPublish(batch),
|
|
285
|
+
{ discard: true }
|
|
286
|
+
)
|
|
287
|
+
}) as (
|
|
288
|
+
itemOrItems: T | ReadonlyArray<T>,
|
|
289
|
+
options?: BatchOptions
|
|
290
|
+
) => Effect.Effect<
|
|
291
|
+
void,
|
|
292
|
+
InvalidStateError | OptimisticConcurrencyException,
|
|
293
|
+
RSchema | RPublish
|
|
294
|
+
>,
|
|
295
|
+
saveWithEvents: (events: Iterable<Evt>) => (...items: NonEmptyArray<T>) => repo.saveAndPublish(items, events),
|
|
296
|
+
/**
|
|
297
|
+
* Enables chunked deletes for large batches via `options.batch`.
|
|
298
|
+
* Note: batching breaks transactional properties because chunks are removed independently.
|
|
299
|
+
*/
|
|
300
|
+
remove: ((itemOrItems: T | ReadonlyArray<T>, options?: BatchOptions) => {
|
|
301
|
+
const items = asReadonlyArray(itemOrItems)
|
|
302
|
+
if (!Array.isReadonlyArrayNonEmpty(items)) {
|
|
303
|
+
return Effect.void
|
|
304
|
+
}
|
|
305
|
+
const batchSize = getBatchSize(options?.batch)
|
|
306
|
+
if (batchSize === undefined) {
|
|
307
|
+
return repo.removeAndPublish(items)
|
|
308
|
+
}
|
|
309
|
+
return Effect.forEach(
|
|
310
|
+
Array.chunksOf(items, batchSize),
|
|
311
|
+
(batch) => repo.removeAndPublish(batch),
|
|
312
|
+
{ discard: true }
|
|
313
|
+
)
|
|
314
|
+
}) as (
|
|
315
|
+
itemOrItems: T | ReadonlyArray<T>,
|
|
316
|
+
options?: BatchOptions
|
|
317
|
+
) => Effect.Effect<void, never, RSchema | RPublish>,
|
|
318
|
+
/**
|
|
319
|
+
* Enables chunked deletes for large batches via `options.batch`.
|
|
320
|
+
* Note: batching breaks transactional properties because chunks are removed independently.
|
|
321
|
+
*/
|
|
322
|
+
removeById: ((idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>, options?: BatchOptions) => {
|
|
323
|
+
const ids = asReadonlyArray(idOrIds)
|
|
324
|
+
if (!Array.isReadonlyArrayNonEmpty(ids)) {
|
|
325
|
+
return Effect.void
|
|
326
|
+
}
|
|
327
|
+
const batchSize = getBatchSize(options?.batch)
|
|
328
|
+
if (batchSize === undefined) {
|
|
329
|
+
return repo.removeById(ids)
|
|
330
|
+
}
|
|
331
|
+
return Effect.forEach(
|
|
332
|
+
Array.chunksOf(ids, batchSize),
|
|
333
|
+
(batch) => repo.removeById(batch),
|
|
334
|
+
{ discard: true }
|
|
335
|
+
)
|
|
336
|
+
}) as (
|
|
337
|
+
idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>,
|
|
338
|
+
options?: BatchOptions
|
|
339
|
+
) => Effect.Effect<void, never, RSchema>,
|
|
340
|
+
queryAndSavePure,
|
|
341
|
+
saveManyWithPure,
|
|
342
|
+
byIdAndSaveWithPure,
|
|
343
|
+
saveWithPure: <
|
|
344
|
+
R,
|
|
345
|
+
A,
|
|
346
|
+
E,
|
|
347
|
+
S1 extends T,
|
|
348
|
+
S2 extends T
|
|
349
|
+
>(
|
|
350
|
+
item: S1,
|
|
351
|
+
pure: Effect.Effect<A, E, FixEnv<R, Evt, S1, S2>>
|
|
352
|
+
) =>
|
|
353
|
+
saveAllWithEffectInt(
|
|
354
|
+
runTerm(pure, item)
|
|
355
|
+
.pipe(Effect.map(([item, events, a]) => [[item], events, a]))
|
|
356
|
+
)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
...repo,
|
|
361
|
+
...exts
|
|
362
|
+
} as Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided> & typeof exts
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
366
|
+
export interface ExtendedRepository<
|
|
367
|
+
T,
|
|
368
|
+
Encoded extends FieldValues,
|
|
369
|
+
Evt,
|
|
370
|
+
ItemType extends string,
|
|
371
|
+
IdKey extends keyof T & keyof Encoded,
|
|
372
|
+
RSchema,
|
|
373
|
+
RPublish,
|
|
374
|
+
RProvided = never
|
|
375
|
+
> extends ReturnType<typeof extendRepo<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided>> {}
|