@effect-app/infra 4.0.0-beta.303 → 4.0.0-beta.305
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 +15 -0
- package/dist/logger.d.ts +4 -4
- package/package.json +2 -2
- package/test/repository-ext.test.ts +144 -1
- package/test/rpc-e2e-invalidation.test.ts +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @effect-app/infra
|
|
2
2
|
|
|
3
|
+
## 4.0.0-beta.305
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8bd9a11: Support ID-scoped signal dependencies and additive repository dependencies derived from previous and current entities.
|
|
8
|
+
- Updated dependencies [8bd9a11]
|
|
9
|
+
- effect-app@4.0.0-beta.305
|
|
10
|
+
|
|
11
|
+
## 4.0.0-beta.304
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [412f08b]
|
|
16
|
+
- effect-app@4.0.0-beta.304
|
|
17
|
+
|
|
3
18
|
## 4.0.0-beta.303
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/dist/logger.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare const InfraLogger: {
|
|
2
|
-
logWarning: (...message:
|
|
3
|
-
logError: (...message:
|
|
4
|
-
logFatal: (...message:
|
|
2
|
+
logWarning: (...message: ReadonlyArray<any>) => import("effect/Effect").Effect<void, never, never>;
|
|
3
|
+
logError: (...message: ReadonlyArray<any>) => import("effect/Effect").Effect<void, never, never>;
|
|
4
|
+
logFatal: (...message: ReadonlyArray<any>) => import("effect/Effect").Effect<void, never, never>;
|
|
5
5
|
logInfo: (...message: ReadonlyArray<any>) => import("effect/Effect").Effect<void, never, never>;
|
|
6
6
|
logDebug: (...message: ReadonlyArray<any>) => import("effect/Effect").Effect<void, never, never>;
|
|
7
|
-
logWithLevel: (level: import("effect/LogLevel").Severity, ...message:
|
|
7
|
+
logWithLevel: (level: import("effect/LogLevel").Severity, ...message: ReadonlyArray<any>) => import("effect/Effect").Effect<void, never, never>;
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=logger.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.305",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"proper-lockfile": "^4.1.2",
|
|
16
16
|
"pure-rand": "8.4.0",
|
|
17
17
|
"query-string": "^9.4.0",
|
|
18
|
-
"effect-app": "4.0.0-beta.
|
|
18
|
+
"effect-app": "4.0.0-beta.305"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@azure/cosmos": "^4.9.3",
|
|
@@ -170,7 +170,150 @@ describe("repository ext save/remove batching", () => {
|
|
|
170
170
|
.pipe(Effect.provideService(DataDependencies.DataDependencyRecorder, recorder))
|
|
171
171
|
|
|
172
172
|
expect(yield* Ref.get(readsRef)).toEqual(new Set([DataDependencies.repo("DependencyItem")]))
|
|
173
|
-
expect(yield* Ref.get(writesRef)).toEqual(new Set([DataDependencies.repo("DependencyItem")]))
|
|
173
|
+
expect(yield* Ref.get(writesRef)).toEqual(new Set([DataDependencies.repo("DependencyItem", ["1"])]))
|
|
174
|
+
})
|
|
175
|
+
.pipe(
|
|
176
|
+
setupRequestContextFromCurrent(),
|
|
177
|
+
Effect.provide(TestStoreLive)
|
|
178
|
+
))
|
|
179
|
+
|
|
180
|
+
it.effect("narrows direct repository reads to the requested entity", () =>
|
|
181
|
+
Effect
|
|
182
|
+
.gen(function*() {
|
|
183
|
+
const readsRef = yield* Ref.make(DataDependencies.empty())
|
|
184
|
+
const writesRef = yield* Ref.make(DataDependencies.empty())
|
|
185
|
+
const recorder = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
|
|
186
|
+
|
|
187
|
+
yield* Effect
|
|
188
|
+
.gen(function*() {
|
|
189
|
+
const repo = yield* makeRepo("DependencyItem", BatchItem, {})
|
|
190
|
+
yield* repo.find("1")
|
|
191
|
+
})
|
|
192
|
+
.pipe(Effect.provideService(DataDependencies.DataDependencyRecorder, recorder))
|
|
193
|
+
|
|
194
|
+
expect(yield* Ref.get(readsRef)).toEqual(new Set([DataDependencies.repo("DependencyItem", ["1"])]))
|
|
195
|
+
})
|
|
196
|
+
.pipe(
|
|
197
|
+
setupRequestContextFromCurrent(),
|
|
198
|
+
Effect.provide(TestStoreLive)
|
|
199
|
+
))
|
|
200
|
+
|
|
201
|
+
it("matches entity dependencies by overlapping ids with a coarse fallback", () => {
|
|
202
|
+
const item1 = new Set([DataDependencies.repo("DependencyItem", ["1"])])
|
|
203
|
+
const item2 = new Set([DataDependencies.repo("DependencyItem", ["2"])])
|
|
204
|
+
const collection = new Set([DataDependencies.repo("DependencyItem")])
|
|
205
|
+
|
|
206
|
+
expect(DataDependencies.intersects(item1, item2)).toBe(false)
|
|
207
|
+
expect(DataDependencies.intersects(item1, item1)).toBe(true)
|
|
208
|
+
expect(DataDependencies.intersects(collection, item2)).toBe(true)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it("decodes repository dependencies produced before entity ids were added", () => {
|
|
212
|
+
expect(
|
|
213
|
+
S.decodeUnknownSync(DataDependencies.DataDependency)({
|
|
214
|
+
type: "repo",
|
|
215
|
+
name: "DependencyItem"
|
|
216
|
+
})
|
|
217
|
+
)
|
|
218
|
+
.toEqual(DataDependencies.repo("DependencyItem"))
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it.effect("matches an explicit query scope to a write alias", () =>
|
|
222
|
+
Effect
|
|
223
|
+
.gen(function*() {
|
|
224
|
+
const readsRef = yield* Ref.make(DataDependencies.empty())
|
|
225
|
+
const writesRef = yield* Ref.make(DataDependencies.empty())
|
|
226
|
+
const recorder = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
|
|
227
|
+
|
|
228
|
+
yield* Effect
|
|
229
|
+
.gen(function*() {
|
|
230
|
+
const repo = yield* makeRepo("DependencyItem", BatchItem, {
|
|
231
|
+
dependencyIds: (item) => [item.id, `alias-${item.id}`]
|
|
232
|
+
})
|
|
233
|
+
yield* repo.save(new BatchItem({ id: "1", label: "one" }))
|
|
234
|
+
yield* repo.all.pipe(DataDependencies.withRepoReadScope("DependencyItem", ["alias-1"]))
|
|
235
|
+
})
|
|
236
|
+
.pipe(Effect.provideService(DataDependencies.DataDependencyRecorder, recorder))
|
|
237
|
+
|
|
238
|
+
expect(yield* Ref.get(readsRef)).toEqual(new Set([DataDependencies.repo("DependencyItem", ["alias-1"])]))
|
|
239
|
+
expect(yield* Ref.get(writesRef)).toEqual(
|
|
240
|
+
new Set([DataDependencies.repo("DependencyItem", ["1", "alias-1"])])
|
|
241
|
+
)
|
|
242
|
+
})
|
|
243
|
+
.pipe(
|
|
244
|
+
setupRequestContextFromCurrent(),
|
|
245
|
+
Effect.provide(TestStoreLive)
|
|
246
|
+
))
|
|
247
|
+
|
|
248
|
+
it.effect("records repository and affected-query write dependencies", () =>
|
|
249
|
+
Effect
|
|
250
|
+
.gen(function*() {
|
|
251
|
+
const readsRef = yield* Ref.make(DataDependencies.empty())
|
|
252
|
+
const writesRef = yield* Ref.make(DataDependencies.empty())
|
|
253
|
+
const recorder = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
|
|
254
|
+
|
|
255
|
+
yield* Effect
|
|
256
|
+
.gen(function*() {
|
|
257
|
+
const repo = yield* makeRepo("DependencyItem", BatchItem, {
|
|
258
|
+
dependencyIds: (item) => [item.id, `alias-${item.id}`],
|
|
259
|
+
additionalWriteDependencies: (item) => [
|
|
260
|
+
DataDependencies.signal("DependencyItem.List", [item.label])
|
|
261
|
+
]
|
|
262
|
+
})
|
|
263
|
+
yield* repo.save(new BatchItem({ id: "1", label: "one" }))
|
|
264
|
+
yield* DataDependencies.read(DataDependencies.signal("DependencyItem.List", ["one"]))
|
|
265
|
+
})
|
|
266
|
+
.pipe(Effect.provideService(DataDependencies.DataDependencyRecorder, recorder))
|
|
267
|
+
|
|
268
|
+
expect(yield* Ref.get(readsRef)).toEqual(
|
|
269
|
+
new Set([DataDependencies.signal("DependencyItem.List", ["one"])])
|
|
270
|
+
)
|
|
271
|
+
expect(yield* Ref.get(writesRef)).toEqual(
|
|
272
|
+
new Set([
|
|
273
|
+
DataDependencies.repo("DependencyItem", ["1", "alias-1"]),
|
|
274
|
+
DataDependencies.signal("DependencyItem.List", ["one"])
|
|
275
|
+
])
|
|
276
|
+
)
|
|
277
|
+
})
|
|
278
|
+
.pipe(
|
|
279
|
+
setupRequestContextFromCurrent(),
|
|
280
|
+
Effect.provide(TestStoreLive)
|
|
281
|
+
))
|
|
282
|
+
|
|
283
|
+
it.effect("invalidates derived dependencies from previous saves and removeById", () =>
|
|
284
|
+
Effect
|
|
285
|
+
.gen(function*() {
|
|
286
|
+
const readsRef = yield* Ref.make(DataDependencies.empty())
|
|
287
|
+
const writesRef = yield* Ref.make(DataDependencies.empty())
|
|
288
|
+
const recorder = DataDependencies.makeDataDependencyRecorder(readsRef, writesRef)
|
|
289
|
+
|
|
290
|
+
yield* Effect
|
|
291
|
+
.gen(function*() {
|
|
292
|
+
const repo = yield* makeRepo("DerivedDependencyItem", BatchItem, {
|
|
293
|
+
additionalWriteDependencies: (item) => [
|
|
294
|
+
DataDependencies.signal("DerivedDependencyItem.List", [item.label])
|
|
295
|
+
]
|
|
296
|
+
})
|
|
297
|
+
yield* repo.save(new BatchItem({ id: "1", label: "old" }))
|
|
298
|
+
yield* recorder.drainWrites
|
|
299
|
+
|
|
300
|
+
yield* repo.save(new BatchItem({ id: "1", label: "new" }))
|
|
301
|
+
expect(yield* recorder.drainWrites).toEqual(
|
|
302
|
+
new Set([
|
|
303
|
+
DataDependencies.repo("DerivedDependencyItem", ["1"]),
|
|
304
|
+
DataDependencies.signal("DerivedDependencyItem.List", ["new", "old"])
|
|
305
|
+
])
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
yield* repo.removeById("1")
|
|
309
|
+
expect(yield* recorder.drainWrites).toEqual(
|
|
310
|
+
new Set([
|
|
311
|
+
DataDependencies.repo("DerivedDependencyItem", ["1"]),
|
|
312
|
+
DataDependencies.signal("DerivedDependencyItem.List", ["new"])
|
|
313
|
+
])
|
|
314
|
+
)
|
|
315
|
+
})
|
|
316
|
+
.pipe(Effect.provideService(DataDependencies.DataDependencyRecorder, recorder))
|
|
174
317
|
})
|
|
175
318
|
.pipe(
|
|
176
319
|
setupRequestContextFromCurrent(),
|
|
@@ -358,8 +358,8 @@ it.live(
|
|
|
358
358
|
const writes = yield* Ref.get(writesRef)
|
|
359
359
|
expect(values).toStrictEqual([1, 2, 3])
|
|
360
360
|
// Each emitted value writes to RepoItem; routing drains the writes per chunk and the client
|
|
361
|
-
// accumulates
|
|
362
|
-
expect(writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem")]))
|
|
361
|
+
// accumulates their entity ids into one dependency.
|
|
362
|
+
expect(writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem", ["1", "2", "3"])]))
|
|
363
363
|
}, Effect.provide(TestLayer)),
|
|
364
364
|
{ timeout: 10_000 }
|
|
365
365
|
)
|
|
@@ -377,7 +377,7 @@ it.live(
|
|
|
377
377
|
const command = yield* withDependencyCapture(client.SaveRepoItem.handler({ id: "1", label: "one" }))
|
|
378
378
|
expect(Exit.isSuccess(command.result)).toBe(true)
|
|
379
379
|
expect(command.dependencies.reads).toStrictEqual(DataDependencies.empty())
|
|
380
|
-
expect(command.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem")]))
|
|
380
|
+
expect(command.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("RepoItem", ["1"])]))
|
|
381
381
|
}, Effect.provide(TestLayer)),
|
|
382
382
|
{ timeout: 10_000 }
|
|
383
383
|
)
|
|
@@ -411,7 +411,7 @@ it.live(
|
|
|
411
411
|
// A command writing an UNRELATED repo => the query is NOT invalidated (negative control).
|
|
412
412
|
const saveOther = yield* withDependencyCapture(client.SaveOtherItem.handler({ id: "2", label: "two" }))
|
|
413
413
|
expect(Exit.isSuccess(saveOther.result)).toBe(true)
|
|
414
|
-
expect(saveOther.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("OtherItem")]))
|
|
414
|
+
expect(saveOther.dependencies.writes).toStrictEqual(new Set([DataDependencies.repo("OtherItem", ["2"])]))
|
|
415
415
|
expect(invalidatedBy(saveOther.dependencies.writes)).toStrictEqual([])
|
|
416
416
|
}, Effect.provide(TestLayer)),
|
|
417
417
|
{ timeout: 10_000 }
|