effect-app 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 +12 -0
- package/dist/DataDependencies.d.ts +221 -329
- package/dist/DataDependencies.d.ts.map +1 -1
- package/dist/DataDependencies.js +57 -9
- package/dist/Model/Repository/internal/internal.d.ts +5 -0
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +39 -10
- package/dist/Model/Repository/makeRepo.d.ts +9 -0
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/makeRepo.js +1 -1
- package/dist/rpc/Invalidation.d.ts +1796 -2660
- package/dist/rpc/Invalidation.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/DataDependencies.ts +66 -9
- package/src/Model/Repository/internal/internal.ts +64 -9
- package/src/Model/Repository/makeRepo.ts +11 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Invalidation.d.ts","sourceRoot":"","sources":["../../src/rpc/Invalidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AACzC,OAAO,EAAE,KAAK,gBAAgB,EAAgB,MAAM,wBAAwB,CAAA;AAC5E,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AACxC,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAA;AAC1D,OAAO,KAAK,MAAM,MAAM,cAAc,CAAA;AACtC,OAAO,KAAK,CAAC,MAAM,cAAc,CAAA;AAEjC;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAAA;AAmBjH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,uCAAS,CAAA;AAC5C,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAEjF,6GAA6G;AAC7G,eAAO,MAAM,eAAe;;;CAAkC,CAAA;AAC9D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,eAAe,CAAC,CAAA;AAEnE,oFAAoF;AACpF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;CAA2B,CAAA;AACxD,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAErE,wFAAwF;AACxF,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"Invalidation.d.ts","sourceRoot":"","sources":["../../src/rpc/Invalidation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/DataDependencies.ts
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
|
+
import type { NonEmptyReadonlyArray } from "effect/Array"
|
|
1
2
|
import * as Ref from "effect/Ref"
|
|
2
3
|
import * as Stream from "effect/Stream"
|
|
4
|
+
import * as Context from "./Context.ts"
|
|
3
5
|
import * as Effect from "./Effect.ts"
|
|
4
6
|
import * as RequestScopedDependencies from "./RequestScopedDependencies.ts"
|
|
5
7
|
import * as S from "./Schema.ts"
|
|
6
8
|
|
|
7
|
-
export const DataDependency = S.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
export const DataDependency = S.Union([
|
|
10
|
+
S.Struct({
|
|
11
|
+
type: S.Literal("repo"),
|
|
12
|
+
name: S.String,
|
|
13
|
+
ids: S.optional(S.NonEmptyArray(S.String))
|
|
14
|
+
}),
|
|
15
|
+
S.Struct({
|
|
16
|
+
type: S.Literal("signal"),
|
|
17
|
+
name: S.String,
|
|
18
|
+
ids: S.optional(S.NonEmptyArray(S.String))
|
|
19
|
+
})
|
|
20
|
+
])
|
|
11
21
|
export type DataDependency = S.Schema.Type<typeof DataDependency>
|
|
12
22
|
|
|
13
23
|
export const DataDependencies = S.ReadonlySet(DataDependency)
|
|
@@ -29,15 +39,45 @@ export interface DataDependencyRecorderService {
|
|
|
29
39
|
readonly drainWrites: Effect.Effect<DataDependencies>
|
|
30
40
|
}
|
|
31
41
|
|
|
42
|
+
const sameDomain = (a: DataDependency, b: DataDependency) => a.type === b.type && a.name === b.name
|
|
43
|
+
|
|
44
|
+
const dependenciesOverlap = (a: DataDependency, b: DataDependency) => {
|
|
45
|
+
if (!sameDomain(a, b)) return false
|
|
46
|
+
if (a.ids === undefined || b.ids === undefined) return true
|
|
47
|
+
return a.ids.some((id) => b.ids?.includes(id))
|
|
48
|
+
}
|
|
49
|
+
|
|
32
50
|
const containsDependency = (dependencies: ReadonlySet<DataDependency>, dependency: DataDependency) => {
|
|
33
51
|
for (const _ of dependencies) {
|
|
34
|
-
if (_
|
|
52
|
+
if (dependenciesOverlap(_, dependency)) return true
|
|
35
53
|
}
|
|
36
54
|
return false
|
|
37
55
|
}
|
|
38
56
|
|
|
39
|
-
const appendDependency = (dependency: DataDependency) => (dependencies: DataDependencies): DataDependencies =>
|
|
40
|
-
|
|
57
|
+
const appendDependency = (dependency: DataDependency) => (dependencies: DataDependencies): DataDependencies => {
|
|
58
|
+
const existing = [...dependencies].find((_) => sameDomain(_, dependency))
|
|
59
|
+
if (existing === undefined) return new Set([...dependencies, dependency])
|
|
60
|
+
if (existing.ids === undefined) return dependencies
|
|
61
|
+
if (dependency.ids === undefined) {
|
|
62
|
+
return new Set([...dependencies].filter((_) => _ !== existing).concat(dependency))
|
|
63
|
+
}
|
|
64
|
+
const first = existing.ids[0]
|
|
65
|
+
const ids: NonEmptyReadonlyArray<string> = [
|
|
66
|
+
first,
|
|
67
|
+
...new Set([...existing.ids.slice(1), ...dependency.ids].filter((id) => id !== first))
|
|
68
|
+
]
|
|
69
|
+
if (ids.length === existing.ids.length) return dependencies
|
|
70
|
+
const merged = existing.type === "repo" ? repo(existing.name, ids) : signal(existing.name, ids)
|
|
71
|
+
return new Set([...dependencies].filter((_) => _ !== existing).concat(merged))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const merge = (...groups: ReadonlyArray<DataDependencies>): DataDependencies => {
|
|
75
|
+
let merged = empty()
|
|
76
|
+
for (const group of groups) {
|
|
77
|
+
for (const dependency of group) merged = appendDependency(dependency)(merged)
|
|
78
|
+
}
|
|
79
|
+
return merged
|
|
80
|
+
}
|
|
41
81
|
|
|
42
82
|
export const DataDependencyRecorder = RequestScopedDependencies.make(
|
|
43
83
|
"effect-app/DataDependencyRecorder",
|
|
@@ -90,8 +130,25 @@ export const makeDataDependencyRecorder = (
|
|
|
90
130
|
drainWrites: Ref.getAndSet(writesRef, empty())
|
|
91
131
|
})
|
|
92
132
|
|
|
93
|
-
export const repo = (name: string): DataDependency =>
|
|
94
|
-
|
|
133
|
+
export const repo = (name: string, ids?: NonEmptyReadonlyArray<string>): DataDependency =>
|
|
134
|
+
ids === undefined ? { type: "repo", name } : { type: "repo", name, ids }
|
|
135
|
+
export const signal = (name: string, ids?: NonEmptyReadonlyArray<string>): DataDependency =>
|
|
136
|
+
ids === undefined ? { type: "signal", name } : { type: "signal", name, ids }
|
|
137
|
+
|
|
138
|
+
const RepoReadScope = Context.Reference<DataDependency | undefined>("effect-app/DataDependencies/RepoReadScope", {
|
|
139
|
+
defaultValue: () => undefined
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
export const readRepo = (name: string) =>
|
|
143
|
+
Effect.flatMap(
|
|
144
|
+
RepoReadScope,
|
|
145
|
+
(scope) => read(scope?.type === "repo" && scope.name === name ? scope : repo(name))
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
export const withRepoReadScope =
|
|
149
|
+
(name: string, ids: NonEmptyReadonlyArray<string>) =>
|
|
150
|
+
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
151
|
+
Effect.provideService(self, RepoReadScope, repo(name, ids))
|
|
95
152
|
|
|
96
153
|
export const QueryReadDependenciesMetaKey = "effect-app.query.readDependencies"
|
|
97
154
|
|
|
@@ -114,6 +114,8 @@ export function makeRepoInternal<
|
|
|
114
114
|
args: [Evt] extends [never] ? {
|
|
115
115
|
schemaContext?: Context.Context<RCtx>
|
|
116
116
|
makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
|
|
117
|
+
dependencyIds?: (item: T) => NonEmptyReadonlyArray<string>
|
|
118
|
+
additionalWriteDependencies?: (item: T) => ReadonlyArray<DataDependencies.DataDependency>
|
|
117
119
|
config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
|
|
118
120
|
partitionValue?: (e?: Encoded) => string
|
|
119
121
|
}
|
|
@@ -122,6 +124,8 @@ export function makeRepoInternal<
|
|
|
122
124
|
schemaContext?: Context.Context<RCtx>
|
|
123
125
|
publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect.Effect<void, never, RPublish>
|
|
124
126
|
makeInitial?: Effect.Effect<readonly T[], E, RInitial> | undefined
|
|
127
|
+
dependencyIds?: (item: T) => NonEmptyReadonlyArray<string>
|
|
128
|
+
additionalWriteDependencies?: (item: T) => ReadonlyArray<DataDependencies.DataDependency>
|
|
125
129
|
config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
|
|
126
130
|
partitionValue?: (e?: Encoded) => string
|
|
127
131
|
}
|
|
@@ -143,9 +147,31 @@ export function makeRepoInternal<
|
|
|
143
147
|
)
|
|
144
148
|
|
|
145
149
|
const store = yield* mkStore(args.makeInitial, args.config)
|
|
146
|
-
const
|
|
147
|
-
const
|
|
148
|
-
|
|
150
|
+
const recordRead = DataDependencies.readRepo(name)
|
|
151
|
+
const entityDependency = (ids: NonEmptyReadonlyArray<T[IdKey]>) =>
|
|
152
|
+
DataDependencies.repo(name, [String(ids[0]), ...ids.slice(1).map(String)])
|
|
153
|
+
const itemDependencies = (item: T) => {
|
|
154
|
+
const ids = args.dependencyIds?.(item) ?? [String(item[idKey])]
|
|
155
|
+
return [
|
|
156
|
+
DataDependencies.repo(name, ids),
|
|
157
|
+
...(args.additionalWriteDependencies?.(item) ?? [])
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
const recordEntityRead = (id: T[IdKey]) => DataDependencies.read(entityDependency([id]))
|
|
161
|
+
const recordEntityWrite = (ids: NonEmptyReadonlyArray<T[IdKey]>) =>
|
|
162
|
+
DataDependencies.write(entityDependency(ids))
|
|
163
|
+
const recordItemWrite = (items: NonEmptyReadonlyArray<T>) =>
|
|
164
|
+
Effect.forEach(
|
|
165
|
+
DataDependencies.merge(new Set(items.flatMap(itemDependencies))),
|
|
166
|
+
DataDependencies.write,
|
|
167
|
+
{ discard: true }
|
|
168
|
+
)
|
|
169
|
+
const recordAdditionalItemWrites = (items: ReadonlyArray<T>) =>
|
|
170
|
+
Effect.forEach(
|
|
171
|
+
DataDependencies.merge(new Set(items.flatMap((item) => args.additionalWriteDependencies?.(item) ?? []))),
|
|
172
|
+
DataDependencies.write,
|
|
173
|
+
{ discard: true }
|
|
174
|
+
)
|
|
149
175
|
const cms = Effect.map(getContextMap.pipe(Effect.orDie), (_) => ({
|
|
150
176
|
get: (id: string) => _.get(`${name}.${id}`),
|
|
151
177
|
set: (id: string, etag: string | undefined) => _.set(`${name}.${id}`, etag)
|
|
@@ -278,11 +304,25 @@ export function makeRepoInternal<
|
|
|
278
304
|
)
|
|
279
305
|
})
|
|
280
306
|
|
|
307
|
+
const loadExistingItems = (ids: ReadonlyArray<T[IdKey]>) =>
|
|
308
|
+
Effect
|
|
309
|
+
.forEach(
|
|
310
|
+
ids,
|
|
311
|
+
(id) =>
|
|
312
|
+
findE(id).pipe(
|
|
313
|
+
Effect.flatMap(Option.match({
|
|
314
|
+
onNone: () => Effect.succeed(Option.none<T>()),
|
|
315
|
+
onSome: (encoded) => decode(encoded).pipe(Effect.orDie, Effect.map(Option.some))
|
|
316
|
+
}))
|
|
317
|
+
)
|
|
318
|
+
)
|
|
319
|
+
.pipe(Effect.map(Array.getSomes))
|
|
320
|
+
|
|
281
321
|
const find = Effect.fn("Repository.find", {
|
|
282
322
|
kind: "client",
|
|
283
323
|
attributes: { "app.entity": name }
|
|
284
324
|
})(function*(id: T[IdKey]) {
|
|
285
|
-
yield*
|
|
325
|
+
yield* recordEntityRead(id)
|
|
286
326
|
yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
|
|
287
327
|
return yield* flatMapOption(findE(id), (_) => Effect.orDie(decode(_)))
|
|
288
328
|
})
|
|
@@ -310,8 +350,14 @@ export function makeRepoInternal<
|
|
|
310
350
|
|
|
311
351
|
const saveAndPublish = Effect.fn("Repository.saveAndPublish", { attributes: { "app.entity": name } })(
|
|
312
352
|
function*(items: Iterable<T>, events: Iterable<Evt> = []) {
|
|
313
|
-
yield* recordWrite
|
|
314
353
|
const it = Chunk.fromIterable(items)
|
|
354
|
+
if (Chunk.isNonEmpty(it)) {
|
|
355
|
+
const values = Chunk.toReadonlyArray(it)
|
|
356
|
+
const previous = args.additionalWriteDependencies
|
|
357
|
+
? yield* loadExistingItems(values.map((item) => item[idKey]))
|
|
358
|
+
: []
|
|
359
|
+
yield* recordItemWrite([values[0], ...values.slice(1), ...previous])
|
|
360
|
+
}
|
|
315
361
|
const evts = [...events]
|
|
316
362
|
yield* Effect.annotateCurrentSpan({
|
|
317
363
|
"app.entity.ids": Chunk.map(it, (_) => _[idKey]),
|
|
@@ -330,9 +376,11 @@ export function makeRepoInternal<
|
|
|
330
376
|
|
|
331
377
|
const removeAndPublish = Effect.fn("Repository.removeAndPublish", { attributes: { "app.entity": name } })(
|
|
332
378
|
function*(a: Iterable<T>, events: Iterable<Evt> = []) {
|
|
333
|
-
yield* recordWrite
|
|
334
379
|
const { set } = yield* cms
|
|
335
380
|
const it = [...a]
|
|
381
|
+
if (Array.isReadonlyArrayNonEmpty(it)) {
|
|
382
|
+
yield* recordItemWrite(it)
|
|
383
|
+
}
|
|
336
384
|
const evts = [...events]
|
|
337
385
|
yield* Effect.annotateCurrentSpan({
|
|
338
386
|
"app.entity.ids": it.map((_) => _[idKey]),
|
|
@@ -359,13 +407,16 @@ export function makeRepoInternal<
|
|
|
359
407
|
|
|
360
408
|
const removeById = Effect.fn("Repository.removeById", { attributes: { "app.entity": name } })(
|
|
361
409
|
function*(idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>) {
|
|
362
|
-
yield* recordWrite
|
|
363
410
|
const ids = globalThis.Array.isArray(idOrIds)
|
|
364
411
|
? idOrIds as readonly T[IdKey][]
|
|
365
412
|
: [idOrIds as T[IdKey]]
|
|
366
413
|
if (!Array.isReadonlyArrayNonEmpty(ids)) {
|
|
367
414
|
return
|
|
368
415
|
}
|
|
416
|
+
yield* recordEntityWrite(ids)
|
|
417
|
+
if (args.additionalWriteDependencies) {
|
|
418
|
+
yield* loadExistingItems(ids).pipe(Effect.flatMap(recordAdditionalItemWrites))
|
|
419
|
+
}
|
|
369
420
|
const { set } = yield* cms
|
|
370
421
|
const eids = yield* Effect.forEach(ids, (_) => encodeIdOnly(_ as any)).pipe(Effect.orDie)
|
|
371
422
|
yield* Effect.annotateCurrentSpan({ "app.entity.ids": eids })
|
|
@@ -640,7 +691,7 @@ export function makeRepoInternal<
|
|
|
640
691
|
),
|
|
641
692
|
find: (id: T[IdKey]) =>
|
|
642
693
|
flatMapOption(findE(id), dec).pipe(
|
|
643
|
-
Effect.tap(() =>
|
|
694
|
+
Effect.tap(() => recordEntityRead(id)),
|
|
644
695
|
Effect.withSpan("Repository.mapped.find", {
|
|
645
696
|
...spanAttrs,
|
|
646
697
|
attributes: { ...spanAttrs.attributes, "app.entity.id": id }
|
|
@@ -669,7 +720,11 @@ export function makeRepoInternal<
|
|
|
669
720
|
(_) => saveAllE(_)
|
|
670
721
|
)
|
|
671
722
|
.pipe(
|
|
672
|
-
Effect.tap(() =>
|
|
723
|
+
Effect.tap(() =>
|
|
724
|
+
Array.isReadonlyArrayNonEmpty(xes)
|
|
725
|
+
? recordEntityWrite([xes[0][idKey], ...xes.slice(1).map((_) => _[idKey])])
|
|
726
|
+
: Effect.void
|
|
727
|
+
),
|
|
673
728
|
Effect.withSpan("Repository.mapped.save", spanAttrs, { captureStackTrace: false })
|
|
674
729
|
)
|
|
675
730
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import type * as Scope from "effect/Scope"
|
|
10
10
|
import type { NonEmptyReadonlyArray } from "../../Array.ts"
|
|
11
11
|
import type * as Context from "../../Context.ts"
|
|
12
|
+
import type * as DataDependencies from "../../DataDependencies.ts"
|
|
12
13
|
import * as Effect from "../../Effect.ts"
|
|
13
14
|
import type * as S from "../../Schema.ts"
|
|
14
15
|
import type { StoreConfig, StoreMaker } from "../../Store.ts"
|
|
@@ -58,6 +59,16 @@ export interface RepositoryOptions<
|
|
|
58
59
|
*/
|
|
59
60
|
schemaContext?: Context.Context<RCtx>
|
|
60
61
|
|
|
62
|
+
/** IDs, including aliases, that identify an entity for dependency invalidation. */
|
|
63
|
+
dependencyIds?: (item: T) => NonEmptyReadonlyArray<string>
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Additional derived queries or resources affected by writing an item.
|
|
67
|
+
* Saves invalidate dependencies derived from both the previous and next item;
|
|
68
|
+
* removals derive them from the removed item.
|
|
69
|
+
*/
|
|
70
|
+
additionalWriteDependencies?: (item: T) => ReadonlyArray<DataDependencies.DataDependency>
|
|
71
|
+
|
|
61
72
|
overrides?: (
|
|
62
73
|
repo: Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>
|
|
63
74
|
) => Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>
|