effect-app 4.0.0-beta.282 → 4.0.0-beta.283
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/DataDependencies.d.ts +159 -0
- package/dist/DataDependencies.d.ts.map +1 -0
- package/dist/DataDependencies.js +44 -0
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +15 -7
- package/dist/client/apiClientFactory.d.ts.map +1 -1
- package/dist/client/apiClientFactory.js +44 -7
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/rpc/Invalidation.d.ts +992 -0
- package/dist/rpc/Invalidation.d.ts.map +1 -1
- package/dist/rpc/Invalidation.js +10 -3
- package/package.json +1 -1
- package/src/DataDependencies.ts +78 -0
- package/src/Model/Repository/internal/internal.ts +14 -0
- package/src/client/apiClientFactory.ts +64 -16
- package/src/client.ts +1 -0
- package/src/rpc/Invalidation.ts +16 -2
|
@@ -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,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/dist/rpc/Invalidation.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as Ref from "effect/Ref";
|
|
|
2
2
|
import { Rpc } from "effect/unstable/rpc";
|
|
3
3
|
import { makeQueryKey } from "../client/clientFor.js";
|
|
4
4
|
import * as Context from "../Context.js";
|
|
5
|
+
import * as DataDependencies from "../DataDependencies.js";
|
|
5
6
|
import * as Effect from "../Effect.js";
|
|
6
7
|
import * as S from "../Schema.js";
|
|
7
8
|
const normalizeKey = (input) => {
|
|
@@ -12,7 +13,7 @@ const normalizeKey = (input) => {
|
|
|
12
13
|
};
|
|
13
14
|
// Disambiguates `add` overloads: a `string[]` means a single key; an array
|
|
14
15
|
// containing arrays-or-objects means a batch of inputs.
|
|
15
|
-
const isBatch = (input) => Array.isArray(input) && input
|
|
16
|
+
const isBatch = (input) => Array.isArray(input) && input[0] !== undefined && typeof input[0] !== "string";
|
|
16
17
|
const normalizeInputs = (input) => isBatch(input) ? input.map(normalizeKey) : [normalizeKey(input)];
|
|
17
18
|
/**
|
|
18
19
|
* A single segment within an `InvalidationKey` array.
|
|
@@ -25,7 +26,13 @@ export const InvalidationKey = S.Array(InvalidationKeySegment);
|
|
|
25
26
|
/** Schema for the full set of invalidation keys – an array of `InvalidationKey`. */
|
|
26
27
|
export const InvalidationKeys = S.Array(InvalidationKey);
|
|
27
28
|
/** Metadata included in every command response for server-driven cache invalidation. */
|
|
28
|
-
export const CommandMetaData = S.Struct({
|
|
29
|
+
export const CommandMetaData = S.Struct({
|
|
30
|
+
invalidateQueries: InvalidationKeys,
|
|
31
|
+
dataDependencies: DataDependencies.DataDependencySet
|
|
32
|
+
});
|
|
33
|
+
export const emptyDataDependencies = { reads: [], writes: [] };
|
|
34
|
+
export const makeMetaData = (invalidateQueries, dataDependencies = emptyDataDependencies) => ({ invalidateQueries, dataDependencies });
|
|
35
|
+
export const QueryResponseWithMetaData = (success) => S.Struct({ payload: success, metadata: S.Struct({ dataDependencies: DataDependencies.DataDependencySet }) });
|
|
29
36
|
/**
|
|
30
37
|
* Wraps a command's success schema so that the wire format carries both the `payload`
|
|
31
38
|
* (the handler's actual return value) and `metadata` (server-driven cache invalidation keys).
|
|
@@ -165,4 +172,4 @@ export const makeStreamRpc = Rpc.custom(({ defect, error, success }) => ({
|
|
|
165
172
|
error: StreamFailureChunk(error),
|
|
166
173
|
defect
|
|
167
174
|
}));
|
|
168
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
175
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW52YWxpZGF0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3JwYy9JbnZhbGlkYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEdBQUcsTUFBTSxZQUFZLENBQUE7QUFDakMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ3pDLE9BQU8sRUFBeUIsWUFBWSxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFDNUUsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUE7QUFDeEMsT0FBTyxLQUFLLGdCQUFnQixNQUFNLHdCQUF3QixDQUFBO0FBQzFELE9BQU8sS0FBSyxNQUFNLE1BQU0sY0FBYyxDQUFBO0FBQ3RDLE9BQU8sS0FBSyxDQUFDLE1BQU0sY0FBYyxDQUFBO0FBU2pDLE1BQU0sWUFBWSxHQUFHLENBQUMsS0FBMkIsRUFBbUIsRUFBRTtJQUNwRSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQUUsT0FBTyxLQUFLLENBQUE7SUFDdEMsTUFBTSxPQUFPLEdBQUcsS0FBbUQsQ0FBQTtJQUNuRSxPQUFPLFlBQVksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO0FBQzFHLENBQUMsQ0FBQTtBQUVELDJFQUEyRTtBQUMzRSx3REFBd0Q7QUFDeEQsTUFBTSxPQUFPLEdBQUcsQ0FDZCxLQUFpRSxFQUNuQixFQUFFLENBQ2hELEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLFNBQVMsSUFBSSxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLENB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
|
package/package.json
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as Ref from "effect/Ref"
|
|
2
|
+
import * as Context from "./Context.ts"
|
|
3
|
+
import * as Effect from "./Effect.ts"
|
|
4
|
+
import * as S from "./Schema.ts"
|
|
5
|
+
|
|
6
|
+
export const DataDependency = S.Struct({
|
|
7
|
+
type: S.Literals(["repo", "signal"]),
|
|
8
|
+
name: S.String
|
|
9
|
+
})
|
|
10
|
+
export type DataDependency = S.Schema.Type<typeof DataDependency>
|
|
11
|
+
|
|
12
|
+
export const DataDependencies = S.Array(DataDependency)
|
|
13
|
+
export type DataDependencies = S.Schema.Type<typeof DataDependencies>
|
|
14
|
+
|
|
15
|
+
export const DataDependencySet = S.Struct({
|
|
16
|
+
reads: DataDependencies,
|
|
17
|
+
writes: DataDependencies
|
|
18
|
+
})
|
|
19
|
+
export type DataDependencySet = S.Schema.Type<typeof DataDependencySet>
|
|
20
|
+
|
|
21
|
+
export interface DataDependencyRecorderService {
|
|
22
|
+
readonly read: (dependency: DataDependency) => Effect.Effect<void>
|
|
23
|
+
readonly write: (dependency: DataDependency) => Effect.Effect<void>
|
|
24
|
+
readonly get: Effect.Effect<DataDependencySet>
|
|
25
|
+
readonly drain: Effect.Effect<DataDependencySet>
|
|
26
|
+
readonly drainWrites: Effect.Effect<DataDependencies>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const containsDependency = (dependencies: ReadonlyArray<DataDependency>, dependency: DataDependency) =>
|
|
30
|
+
dependencies.some((_) => _.type === dependency.type && _.name === dependency.name)
|
|
31
|
+
|
|
32
|
+
const appendDependency = (dependency: DataDependency) => (dependencies: DataDependencies): DataDependencies =>
|
|
33
|
+
containsDependency(dependencies, dependency) ? dependencies : [...dependencies, dependency]
|
|
34
|
+
|
|
35
|
+
export const DataDependencyRecorder = Context.Reference<DataDependencyRecorderService>(
|
|
36
|
+
"effect-app/DataDependencyRecorder",
|
|
37
|
+
{
|
|
38
|
+
defaultValue: () => ({
|
|
39
|
+
read: (_dependency) => Effect.void,
|
|
40
|
+
write: (_dependency) => Effect.void,
|
|
41
|
+
get: Effect.succeed({ reads: [], writes: [] }),
|
|
42
|
+
drain: Effect.succeed({ reads: [], writes: [] }),
|
|
43
|
+
drainWrites: Effect.succeed([])
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
export type DataDependencyRecorder = typeof DataDependencyRecorder
|
|
48
|
+
|
|
49
|
+
export const makeDataDependencyRecorder = (
|
|
50
|
+
readsRef: Ref.Ref<DataDependencies>,
|
|
51
|
+
writesRef: Ref.Ref<DataDependencies>
|
|
52
|
+
): DataDependencyRecorderService => ({
|
|
53
|
+
read: (dependency) => Ref.update(readsRef, appendDependency(dependency)),
|
|
54
|
+
write: (dependency) => Ref.update(writesRef, appendDependency(dependency)),
|
|
55
|
+
get: Effect.all({
|
|
56
|
+
reads: Ref.get(readsRef),
|
|
57
|
+
writes: Ref.get(writesRef)
|
|
58
|
+
}),
|
|
59
|
+
drain: Effect.all({
|
|
60
|
+
reads: Ref.getAndSet(readsRef, []),
|
|
61
|
+
writes: Ref.getAndSet(writesRef, [])
|
|
62
|
+
}),
|
|
63
|
+
drainWrites: Ref.getAndSet(writesRef, [])
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
export const repo = (name: string): DataDependency => ({ type: "repo", name })
|
|
67
|
+
export const signal = (name: string): DataDependency => ({ type: "signal", name })
|
|
68
|
+
|
|
69
|
+
export const QueryReadDependenciesMetaKey = "effect-app.query.readDependencies"
|
|
70
|
+
|
|
71
|
+
export const read = (dependency: DataDependency) => DataDependencyRecorder.use((_) => _.read(dependency))
|
|
72
|
+
|
|
73
|
+
export const write = (dependency: DataDependency) => DataDependencyRecorder.use((_) => _.write(dependency))
|
|
74
|
+
|
|
75
|
+
export const intersects = (
|
|
76
|
+
a: ReadonlyArray<DataDependency>,
|
|
77
|
+
b: ReadonlyArray<DataDependency>
|
|
78
|
+
) => a.some((dependency) => containsDependency(b, dependency))
|
|
@@ -16,6 +16,7 @@ import { toNonEmptyArray } from "../../../Array.ts"
|
|
|
16
16
|
import * as Chunk from "../../../Chunk.ts"
|
|
17
17
|
import { NotFoundError } from "../../../client/errors.ts"
|
|
18
18
|
import * as Context from "../../../Context.ts"
|
|
19
|
+
import * as DataDependencies from "../../../DataDependencies.ts"
|
|
19
20
|
import * as Effect from "../../../Effect.ts"
|
|
20
21
|
import { flatMapOption } from "../../../Effect.ts"
|
|
21
22
|
import * as Option from "../../../Option.ts"
|
|
@@ -100,6 +101,9 @@ export function makeRepoInternal<
|
|
|
100
101
|
)
|
|
101
102
|
|
|
102
103
|
const store = yield* mkStore(args.makeInitial, args.config)
|
|
104
|
+
const repoDependency = DataDependencies.repo(name)
|
|
105
|
+
const recordRead = DataDependencies.read(repoDependency)
|
|
106
|
+
const recordWrite = DataDependencies.write(repoDependency)
|
|
103
107
|
const cms = Effect.map(getContextMap.pipe(Effect.orDie), (_) => ({
|
|
104
108
|
get: (id: string) => _.get(`${name}.${id}`),
|
|
105
109
|
set: (id: string, etag: string | undefined) => _.set(`${name}.${id}`, etag)
|
|
@@ -162,6 +166,7 @@ export function makeRepoInternal<
|
|
|
162
166
|
(_) => decodeMany(_).pipe(Effect.orDie)
|
|
163
167
|
)
|
|
164
168
|
.pipe(
|
|
169
|
+
Effect.tap(() => recordRead),
|
|
165
170
|
Effect.map((_) => _ as T[]),
|
|
166
171
|
Effect.withSpan("Repository.all", {
|
|
167
172
|
kind: "client",
|
|
@@ -231,6 +236,7 @@ export function makeRepoInternal<
|
|
|
231
236
|
kind: "client",
|
|
232
237
|
attributes: { "app.entity": name }
|
|
233
238
|
})(function*(id: T[IdKey]) {
|
|
239
|
+
yield* recordRead
|
|
234
240
|
yield* Effect.annotateCurrentSpan({ "app.entity.id": id })
|
|
235
241
|
return yield* flatMapOption(findE(id), (_) => Effect.orDie(decode(_)))
|
|
236
242
|
})
|
|
@@ -258,6 +264,7 @@ export function makeRepoInternal<
|
|
|
258
264
|
|
|
259
265
|
const saveAndPublish = Effect.fn("Repository.saveAndPublish", { attributes: { "app.entity": name } })(
|
|
260
266
|
function*(items: Iterable<T>, events: Iterable<Evt> = []) {
|
|
267
|
+
yield* recordWrite
|
|
261
268
|
const it = Chunk.fromIterable(items)
|
|
262
269
|
const evts = [...events]
|
|
263
270
|
yield* Effect.annotateCurrentSpan({
|
|
@@ -277,6 +284,7 @@ export function makeRepoInternal<
|
|
|
277
284
|
|
|
278
285
|
const removeAndPublish = Effect.fn("Repository.removeAndPublish", { attributes: { "app.entity": name } })(
|
|
279
286
|
function*(a: Iterable<T>, events: Iterable<Evt> = []) {
|
|
287
|
+
yield* recordWrite
|
|
280
288
|
const { set } = yield* cms
|
|
281
289
|
const it = [...a]
|
|
282
290
|
const evts = [...events]
|
|
@@ -305,6 +313,7 @@ export function makeRepoInternal<
|
|
|
305
313
|
|
|
306
314
|
const removeById = Effect.fn("Repository.removeById", { attributes: { "app.entity": name } })(
|
|
307
315
|
function*(idOrIds: T[IdKey] | ReadonlyArray<T[IdKey]>) {
|
|
316
|
+
yield* recordWrite
|
|
308
317
|
const ids = globalThis.Array.isArray(idOrIds)
|
|
309
318
|
? idOrIds as readonly T[IdKey][]
|
|
310
319
|
: [idOrIds as T[IdKey]]
|
|
@@ -460,6 +469,7 @@ export function makeRepoInternal<
|
|
|
460
469
|
"db.response.returned_rows": Array.isArray(r) ? r.length : 1
|
|
461
470
|
})
|
|
462
471
|
),
|
|
472
|
+
Effect.tap(() => recordRead),
|
|
463
473
|
Effect.withSpan("Repository.query", {
|
|
464
474
|
kind: "client",
|
|
465
475
|
attributes: { "app.entity": name }
|
|
@@ -552,6 +562,7 @@ export function makeRepoInternal<
|
|
|
552
562
|
const dec = S.decodeEffectConcurrently(S.Array(schema))
|
|
553
563
|
return store.queryRaw(q).pipe(
|
|
554
564
|
Effect.flatMap(dec),
|
|
565
|
+
Effect.tap(() => recordRead),
|
|
555
566
|
Effect.withSpan("Repository.queryRaw", {
|
|
556
567
|
kind: "client",
|
|
557
568
|
attributes: { "app.entity": name }
|
|
@@ -573,11 +584,13 @@ export function makeRepoInternal<
|
|
|
573
584
|
return {
|
|
574
585
|
all: allE.pipe(
|
|
575
586
|
Effect.flatMap(decMany),
|
|
587
|
+
Effect.tap(() => recordRead),
|
|
576
588
|
Effect.map((_) => _ as any[]),
|
|
577
589
|
Effect.withSpan("Repository.mapped.all", spanAttrs, { captureStackTrace: false })
|
|
578
590
|
),
|
|
579
591
|
find: (id: T[IdKey]) =>
|
|
580
592
|
flatMapOption(findE(id), dec).pipe(
|
|
593
|
+
Effect.tap(() => recordRead),
|
|
581
594
|
Effect.withSpan("Repository.mapped.find", {
|
|
582
595
|
...spanAttrs,
|
|
583
596
|
attributes: { ...spanAttrs.attributes, "app.entity.id": id }
|
|
@@ -601,6 +614,7 @@ export function makeRepoInternal<
|
|
|
601
614
|
// },
|
|
602
615
|
save: (...xes: any[]) =>
|
|
603
616
|
Effect.flatMap(encMany(xes), (_) => saveAllE(_)).pipe(
|
|
617
|
+
Effect.tap(() => recordWrite),
|
|
604
618
|
Effect.withSpan("Repository.mapped.save", spanAttrs, { captureStackTrace: false })
|
|
605
619
|
)
|
|
606
620
|
}
|
|
@@ -10,6 +10,7 @@ import * as Struct from "effect/Struct"
|
|
|
10
10
|
import { Rpc, RpcClient, RpcGroup, RpcSerialization } from "effect/unstable/rpc"
|
|
11
11
|
import * as Config from "../Config.ts"
|
|
12
12
|
import * as Context from "../Context.ts"
|
|
13
|
+
import * as DataDependencies from "../DataDependencies.ts"
|
|
13
14
|
import * as Effect from "../Effect.ts"
|
|
14
15
|
import { HttpClient, HttpClientRequest } from "../http.ts"
|
|
15
16
|
import { Invalidation } from "../rpc.ts"
|
|
@@ -142,7 +143,12 @@ export const makeRpcGroupFromRequestsAndModuleName = <M extends RequestsAny, con
|
|
|
142
143
|
stream: true as const
|
|
143
144
|
})
|
|
144
145
|
: Invalidation.makeCommandRpc(r._tag, { payload: r, success: r.success, error: r.error })
|
|
145
|
-
: Rpc.make(r._tag, {
|
|
146
|
+
: Rpc.make(r._tag, {
|
|
147
|
+
payload: r,
|
|
148
|
+
success: isStream ? r.success : Invalidation.QueryResponseWithMetaData(r.success),
|
|
149
|
+
error: r.error,
|
|
150
|
+
stream: isStream
|
|
151
|
+
})) as any
|
|
146
152
|
})
|
|
147
153
|
)
|
|
148
154
|
.prefix(`${moduleName}.`)
|
|
@@ -211,6 +217,20 @@ const makeApiClientFactory = Effect
|
|
|
211
217
|
// `InvalidationKeysFromServer` and yield the raw payload / re-fail with the raw
|
|
212
218
|
// error. Middleware-thrown failures arrive raw on the Cause already (no wrap to
|
|
213
219
|
// strip) — the `else` branch passes them through.
|
|
220
|
+
const forwardDependencies = (
|
|
221
|
+
dependencies: DataDependencies.DataDependencySet | undefined,
|
|
222
|
+
options?: { readonly reads?: boolean }
|
|
223
|
+
) =>
|
|
224
|
+
dependencies === undefined
|
|
225
|
+
? Effect.void
|
|
226
|
+
: Effect.gen(function*() {
|
|
227
|
+
const dependencyRecorder = yield* DataDependencies.DataDependencyRecorder
|
|
228
|
+
if (options?.reads) {
|
|
229
|
+
yield* Effect.forEach(dependencies.reads, dependencyRecorder.read, { discard: true })
|
|
230
|
+
}
|
|
231
|
+
yield* Effect.forEach(dependencies.writes, dependencyRecorder.write, { discard: true })
|
|
232
|
+
})
|
|
233
|
+
|
|
214
234
|
const unwrapCommand = (eff: Effect.Effect<any, any, any>): Effect.Effect<any, any, any> =>
|
|
215
235
|
eff.pipe(
|
|
216
236
|
Effect.flatMap((result: any) =>
|
|
@@ -218,6 +238,7 @@ const makeApiClientFactory = Effect
|
|
|
218
238
|
const keys: ReadonlyArray<Invalidation.InvalidationKey> = result?.metadata?.invalidateQueries ?? []
|
|
219
239
|
const invalidationKeys = yield* InvalidationKeysFromServer
|
|
220
240
|
yield* Effect.forEach(keys, (key) => invalidationKeys.add(key), { discard: true })
|
|
241
|
+
yield* forwardDependencies(result?.metadata?.dataDependencies)
|
|
221
242
|
return result.payload
|
|
222
243
|
})
|
|
223
244
|
),
|
|
@@ -227,12 +248,23 @@ const makeApiClientFactory = Effect
|
|
|
227
248
|
const keys: ReadonlyArray<Invalidation.InvalidationKey> = result.metadata?.invalidateQueries ?? []
|
|
228
249
|
const invalidationKeys = yield* InvalidationKeysFromServer
|
|
229
250
|
yield* Effect.forEach(keys, (key) => invalidationKeys.add(key), { discard: true })
|
|
251
|
+
yield* forwardDependencies(result.metadata?.dataDependencies)
|
|
230
252
|
return yield* Effect.fail(result.error)
|
|
231
253
|
})
|
|
232
254
|
: Effect.fail(result)
|
|
233
255
|
)
|
|
234
256
|
)
|
|
235
257
|
|
|
258
|
+
const unwrapQuery = (eff: Effect.Effect<any, any, any>): Effect.Effect<any, any, any> =>
|
|
259
|
+
eff.pipe(
|
|
260
|
+
Effect.flatMap((result: any) =>
|
|
261
|
+
Effect.gen(function*() {
|
|
262
|
+
yield* forwardDependencies(result?.metadata?.dataDependencies, { reads: true })
|
|
263
|
+
return result.payload
|
|
264
|
+
})
|
|
265
|
+
)
|
|
266
|
+
)
|
|
267
|
+
|
|
236
268
|
return {
|
|
237
269
|
mr,
|
|
238
270
|
client: typedKeysOf(filtered)
|
|
@@ -275,7 +307,7 @@ const makeApiClientFactory = Effect
|
|
|
275
307
|
Effect.provide(layers, { local: true }),
|
|
276
308
|
Effect.provide(svcs)
|
|
277
309
|
)
|
|
278
|
-
return isCommand ? unwrapCommand(rpcEffect) : rpcEffect
|
|
310
|
+
return isCommand ? unwrapCommand(rpcEffect) : isStream ? rpcEffect : unwrapQuery(rpcEffect)
|
|
279
311
|
})
|
|
280
312
|
)
|
|
281
313
|
|
|
@@ -292,13 +324,24 @@ const makeApiClientFactory = Effect
|
|
|
292
324
|
// Collect server invalidation keys from the "done" chunk, then discard it.
|
|
293
325
|
Stream.tap((item: any) =>
|
|
294
326
|
item._tag === "done" || item._tag === "metadata"
|
|
295
|
-
?
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
327
|
+
? Effect.gen(function*() {
|
|
328
|
+
const metadata = item.metadata as Invalidation.CommandMetaData
|
|
329
|
+
const invalidationKeys = yield* InvalidationKeysFromServer
|
|
330
|
+
yield* Effect.forEach(metadata.invalidateQueries, invalidationKeys.add, {
|
|
331
|
+
discard: true
|
|
332
|
+
})
|
|
333
|
+
const dependencyRecorder = yield* DataDependencies.DataDependencyRecorder
|
|
334
|
+
yield* Effect.forEach(
|
|
335
|
+
metadata.dataDependencies.reads,
|
|
336
|
+
dependencyRecorder.read,
|
|
299
337
|
{ discard: true }
|
|
300
338
|
)
|
|
301
|
-
|
|
339
|
+
yield* Effect.forEach(
|
|
340
|
+
metadata.dataDependencies.writes,
|
|
341
|
+
dependencyRecorder.write,
|
|
342
|
+
{ discard: true }
|
|
343
|
+
)
|
|
344
|
+
})
|
|
302
345
|
: Effect.void
|
|
303
346
|
),
|
|
304
347
|
Stream.filter((item: any) => item._tag === "value"),
|
|
@@ -309,15 +352,20 @@ const makeApiClientFactory = Effect
|
|
|
309
352
|
Stream.catch((err: any) =>
|
|
310
353
|
err?._tag === "error" && err?.metadata
|
|
311
354
|
? Stream.fromEffect(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
355
|
+
Effect.gen(function*() {
|
|
356
|
+
const metadata = err.metadata as Invalidation.CommandMetaData
|
|
357
|
+
const invalidationKeys = yield* InvalidationKeysFromServer
|
|
358
|
+
yield* Effect.forEach(metadata.invalidateQueries, invalidationKeys.add, {
|
|
359
|
+
discard: true
|
|
360
|
+
})
|
|
361
|
+
const dependencyRecorder = yield* DataDependencies.DataDependencyRecorder
|
|
362
|
+
yield* Effect.forEach(
|
|
363
|
+
metadata.dataDependencies.writes,
|
|
364
|
+
dependencyRecorder.write,
|
|
365
|
+
{ discard: true }
|
|
366
|
+
)
|
|
367
|
+
return yield* Effect.fail(err.error)
|
|
368
|
+
})
|
|
321
369
|
)
|
|
322
370
|
: Stream.fail(err)
|
|
323
371
|
),
|
package/src/client.ts
CHANGED
package/src/rpc/Invalidation.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as Ref from "effect/Ref"
|
|
|
2
2
|
import { Rpc } from "effect/unstable/rpc"
|
|
3
3
|
import { type ClientForOptions, makeQueryKey } from "../client/clientFor.ts"
|
|
4
4
|
import * as Context from "../Context.ts"
|
|
5
|
+
import * as DataDependencies from "../DataDependencies.ts"
|
|
5
6
|
import * as Effect from "../Effect.ts"
|
|
6
7
|
import * as S from "../Schema.ts"
|
|
7
8
|
|
|
@@ -23,7 +24,7 @@ const normalizeKey = (input: InvalidationKeyInput): InvalidationKey => {
|
|
|
23
24
|
const isBatch = (
|
|
24
25
|
input: InvalidationKeyInput | ReadonlyArray<InvalidationKeyInput>
|
|
25
26
|
): input is ReadonlyArray<InvalidationKeyInput> =>
|
|
26
|
-
Array.isArray(input) && input
|
|
27
|
+
Array.isArray(input) && input[0] !== undefined && typeof input[0] !== "string"
|
|
27
28
|
|
|
28
29
|
const normalizeInputs = (
|
|
29
30
|
input: InvalidationKeyInput | ReadonlyArray<InvalidationKeyInput>
|
|
@@ -46,9 +47,22 @@ export const InvalidationKeys = S.Array(InvalidationKey)
|
|
|
46
47
|
export type InvalidationKeys = S.Schema.Type<typeof InvalidationKeys>
|
|
47
48
|
|
|
48
49
|
/** Metadata included in every command response for server-driven cache invalidation. */
|
|
49
|
-
export const CommandMetaData = S.Struct({
|
|
50
|
+
export const CommandMetaData = S.Struct({
|
|
51
|
+
invalidateQueries: InvalidationKeys,
|
|
52
|
+
dataDependencies: DataDependencies.DataDependencySet
|
|
53
|
+
})
|
|
50
54
|
export type CommandMetaData = S.Schema.Type<typeof CommandMetaData>
|
|
51
55
|
|
|
56
|
+
export const emptyDataDependencies: DataDependencies.DataDependencySet = { reads: [], writes: [] }
|
|
57
|
+
|
|
58
|
+
export const makeMetaData = (
|
|
59
|
+
invalidateQueries: InvalidationKeys,
|
|
60
|
+
dataDependencies: DataDependencies.DataDependencySet = emptyDataDependencies
|
|
61
|
+
): CommandMetaData => ({ invalidateQueries, dataDependencies })
|
|
62
|
+
|
|
63
|
+
export const QueryResponseWithMetaData = <S extends S.Top>(success: S) =>
|
|
64
|
+
S.Struct({ payload: success, metadata: S.Struct({ dataDependencies: DataDependencies.DataDependencySet }) })
|
|
65
|
+
|
|
52
66
|
/**
|
|
53
67
|
* Wraps a command's success schema so that the wire format carries both the `payload`
|
|
54
68
|
* (the handler's actual return value) and `metadata` (server-driven cache invalidation keys).
|