@effect-app/infra 4.0.0-beta.256 → 4.0.0-beta.257
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 +7 -0
- package/dist/WorkflowEngineCosmos.d.ts +29 -0
- package/dist/WorkflowEngineCosmos.d.ts.map +1 -0
- package/dist/WorkflowEngineCosmos.js +521 -0
- package/package.json +2 -2
- package/test/dist/_check-agg-infer.test-d.d.ts +2 -0
- package/test/dist/_check-agg-infer.test-d.d.ts.map +1 -0
- package/test/dist/_check-agg-infer.test-d.js +19 -0
- package/test/dist/_check-proj-infer.test-d.d.ts +2 -0
- package/test/dist/_check-proj-infer.test-d.d.ts.map +1 -0
- package/test/dist/_check-proj-infer.test-d.js +16 -0
- package/test/dist/_check-tighten.test-d.d.ts +2 -0
- package/test/dist/_check-tighten.test-d.d.ts.map +1 -0
- package/test/dist/_check-tighten.test-d.js +21 -0
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as Layer from "effect-app/Layer";
|
|
2
|
+
import * as Duration from "effect/Duration";
|
|
3
|
+
import * as Redacted from "effect/Redacted";
|
|
4
|
+
import { WorkflowEngine } from "effect/unstable/workflow/WorkflowEngine";
|
|
5
|
+
export interface WorkflowEngineCosmosConfig {
|
|
6
|
+
readonly url: Redacted.Redacted<string>;
|
|
7
|
+
readonly dbName: string;
|
|
8
|
+
readonly prefix?: string;
|
|
9
|
+
/** Lease duration before claim considered stale. Default 30s. */
|
|
10
|
+
readonly leaseTtl?: Duration.Duration;
|
|
11
|
+
/** Renewal cadence — should be < leaseTtl. Default 10s. */
|
|
12
|
+
readonly heartbeatInterval?: Duration.Duration;
|
|
13
|
+
/** Cadence for scanning stale leases. Default 15s. Set to `Duration.zero` to disable. */
|
|
14
|
+
readonly recoveryInterval?: Duration.Duration;
|
|
15
|
+
/** Cadence for scanning due clocks. Default 5s. Set to `Duration.zero` to disable. */
|
|
16
|
+
readonly clockPollInterval?: Duration.Duration;
|
|
17
|
+
/** Stable worker identity; defaults to a random UUID per process. */
|
|
18
|
+
readonly workerId?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Cosmos DB backed `WorkflowEngine` layer.
|
|
22
|
+
*
|
|
23
|
+
* Per-execution writes share a partition key (TransactionalBatch-eligible) and
|
|
24
|
+
* use OCC via `_etag`/IfMatch, giving first-writer-wins semantics for activity
|
|
25
|
+
* results, durable-deferred completions, and exec-state transitions. All
|
|
26
|
+
* persisted payloads/results/exits are round-tripped through schema codecs.
|
|
27
|
+
*/
|
|
28
|
+
export declare const layerCosmos: (cfg: WorkflowEngineCosmosConfig) => Layer.Layer<WorkflowEngine>;
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV29ya2Zsb3dFbmdpbmVDb3Ntb3MuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9Xb3JrZmxvd0VuZ2luZUNvc21vcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFpQ0EsT0FBTyxLQUFLLEtBQUssTUFBTSxrQkFBa0IsQ0FBQTtBQUd6QyxPQUFPLEtBQUssUUFBUSxNQUFNLGlCQUFpQixDQUFBO0FBSTNDLE9BQU8sS0FBSyxRQUFRLE1BQU0saUJBQWlCLENBQUE7QUFJM0MsT0FBTyxFQUE0QixjQUFjLEVBQW9CLE1BQU0seUNBQXlDLENBQUE7QUFNcEgsTUFBTSxXQUFXLDBCQUEwQjtJQUN6QyxRQUFRLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDdkMsUUFBUSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUE7SUFDdkIsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLE1BQU0sQ0FBQTtJQUN4QixpRUFBaUU7SUFDakUsUUFBUSxDQUFDLFFBQVEsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUE7SUFDckMsMkRBQTJEO0lBQzNELFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUE7SUFDOUMseUZBQXlGO0lBQ3pGLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUE7SUFDN0Msc0ZBQXNGO0lBQ3RGLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUE7SUFDOUMscUVBQXFFO0lBQ3JFLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRSxNQUFNLENBQUE7Q0FDM0I7QUFtb0JEOzs7Ozs7O0dBT0c7QUFDSCxlQUFPLE1BQU0sV0FBVyxRQUFTLDBCQUEwQixLQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUdSLENBQUEifQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowEngineCosmos.d.ts","sourceRoot":"","sources":["../src/WorkflowEngineCosmos.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAA;AAGzC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAI3C,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAI3C,OAAO,EAA4B,cAAc,EAAoB,MAAM,yCAAyC,CAAA;AAMpH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IACrC,2DAA2D;IAC3D,QAAQ,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IAC9C,yFAAyF;IACzF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IAC7C,sFAAsF;IACtF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;IAC9C,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B;AAmoBD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,QAAS,0BAA0B,KAAG,KAAK,CAAC,KAAK,CAAC,cAAc,CAGR,CAAA"}
|
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cosmos DB backed {@link WorkflowEngine} implementation.
|
|
3
|
+
*
|
|
4
|
+
* Persists workflow state in a single container partitioned by `executionId`
|
|
5
|
+
* so per-execution writes share a partition key (eligible for Cosmos
|
|
6
|
+
* TransactionalBatch). Optimistic concurrency is enforced with `_etag` +
|
|
7
|
+
* `IfMatch` on Replace, and create-only batch ops give first-writer-wins
|
|
8
|
+
* semantics for activity results and durable-deferred completions.
|
|
9
|
+
*
|
|
10
|
+
* Durability — everything that crosses the storage boundary is round-tripped
|
|
11
|
+
* through schema codecs (`S.fromJsonString(S.toCodecJson(...))`), exactly like
|
|
12
|
+
* the cluster engine, instead of dumping live runtime objects as JSON:
|
|
13
|
+
*
|
|
14
|
+
* - The workflow payload and the top-level workflow result are encoded with the
|
|
15
|
+
* workflow's own `payloadSchema` / `successSchema` / `errorSchema`, so typed
|
|
16
|
+
* values (dates, branded ids, schema classes) survive a restart.
|
|
17
|
+
* - Activity results flow through the engine already encoded, so they are
|
|
18
|
+
* persisted with an opaque `Workflow.Result({ success: AnyOrVoid, error:
|
|
19
|
+
* AnyOrVoid })` codec — same trick the cluster `ActivityRpc` uses.
|
|
20
|
+
* - Durable-deferred exits and clock completions use an opaque `Exit` codec.
|
|
21
|
+
*
|
|
22
|
+
* Crash recovery: each driver holds a time-bound lease (`worker` +
|
|
23
|
+
* `leaseExpiresAt`) on the exec doc and renews it via a heartbeat fiber. A
|
|
24
|
+
* scope-bound recovery poller queries for exec docs whose lease has lapsed and
|
|
25
|
+
* re-drives them in the local process, decoding the persisted payload and
|
|
26
|
+
* picking up persisted activity results from where the crashed driver left off.
|
|
27
|
+
*
|
|
28
|
+
* Durable clocks: `scheduleClock` writes a clock doc (`fireAt`, `deferredName`)
|
|
29
|
+
* and arms an in-process timer. A cross-partition clock poller fires any clock
|
|
30
|
+
* whose `fireAt` is due, completing the deferred idempotently (create-only) and
|
|
31
|
+
* deleting the doc. Survives restarts.
|
|
32
|
+
*/
|
|
33
|
+
import * as Effect from "effect-app/Effect";
|
|
34
|
+
import * as Layer from "effect-app/Layer";
|
|
35
|
+
import * as Option from "effect-app/Option";
|
|
36
|
+
import * as S from "effect-app/Schema";
|
|
37
|
+
import * as Duration from "effect/Duration";
|
|
38
|
+
import * as Exit from "effect/Exit";
|
|
39
|
+
import * as Fiber from "effect/Fiber";
|
|
40
|
+
import * as FiberMap from "effect/FiberMap";
|
|
41
|
+
import * as Redacted from "effect/Redacted";
|
|
42
|
+
import * as Schedule from "effect/Schedule";
|
|
43
|
+
import * as Workflow from "effect/unstable/workflow/Workflow";
|
|
44
|
+
import { makeUnsafe, WorkflowEngine, WorkflowInstance } from "effect/unstable/workflow/WorkflowEngine";
|
|
45
|
+
import { randomUUID } from "node:crypto";
|
|
46
|
+
import { CosmosClient, CosmosClientLayer } from "./cosmos-client.js";
|
|
47
|
+
import { OptimisticConcurrencyException } from "./errors.js";
|
|
48
|
+
import { annotateCosmosResponse, annotateDb } from "./otel.js";
|
|
49
|
+
const execId = "exec";
|
|
50
|
+
const activityKey = (name, attempt) => `activity::${name}::${attempt}`;
|
|
51
|
+
const deferredKey = (name) => `deferred::${name}`;
|
|
52
|
+
const clockKey = (name) => `clock::${name}`;
|
|
53
|
+
const isOptimisticStatus = (code) => code === 409 || code === 412 || code === 404;
|
|
54
|
+
// --- Storage codecs ----------------------------------------------------------
|
|
55
|
+
// Values flowing through the engine's activity / deferred boundary are already
|
|
56
|
+
// schema-encoded, so the structure is round-tripped while the payload stays
|
|
57
|
+
// opaque (mirrors the cluster engine's `AnyOrVoid` usage).
|
|
58
|
+
const AnyOrVoid = S.Union([S.Any, S.Void]);
|
|
59
|
+
const ActivityResultCodec = S.fromJsonString(S.toCodecJson(Workflow.Result({ success: AnyOrVoid, error: AnyOrVoid })));
|
|
60
|
+
const DeferredExitCodec = S.fromJsonString(S.toCodecJson(S.Exit(AnyOrVoid, AnyOrVoid, S.Defect)));
|
|
61
|
+
const encodeActivityResult = (r) => Effect.orDie(S.encodeEffect(ActivityResultCodec)(r));
|
|
62
|
+
const decodeActivityResult = (s) => Effect.orDie(S.decodeEffect(ActivityResultCodec)(s));
|
|
63
|
+
const encodeDeferredExit = (e) => Effect.orDie(S.encodeEffect(DeferredExitCodec)(e));
|
|
64
|
+
const decodeDeferredExit = (s) => Effect.orDie(S.decodeEffect(DeferredExitCodec)(s));
|
|
65
|
+
const makeCosmosWorkflowEngine = Effect.fnUntraced(function* (cfg) {
|
|
66
|
+
const { db } = yield* CosmosClient;
|
|
67
|
+
const containerId = `${cfg.prefix ?? ""}workflow-engine`;
|
|
68
|
+
yield* Effect.promise(() => db.containers.createIfNotExists({
|
|
69
|
+
id: containerId,
|
|
70
|
+
partitionKey: { paths: ["/_partitionKey"], version: 2 }
|
|
71
|
+
}));
|
|
72
|
+
const container = db.container(containerId);
|
|
73
|
+
const scope = yield* Effect.scope;
|
|
74
|
+
const workerId = cfg.workerId ?? randomUUID();
|
|
75
|
+
const leaseTtl = cfg.leaseTtl ?? Duration.seconds(30);
|
|
76
|
+
const heartbeatInterval = cfg.heartbeatInterval ?? Duration.seconds(10);
|
|
77
|
+
const recoveryInterval = cfg.recoveryInterval ?? Duration.seconds(15);
|
|
78
|
+
const clockPollInterval = cfg.clockPollInterval ?? Duration.seconds(5);
|
|
79
|
+
const annotate = (operation, executionId) => annotateDb({
|
|
80
|
+
operation,
|
|
81
|
+
system: "cosmosdb",
|
|
82
|
+
collection: containerId,
|
|
83
|
+
entity: "workflow",
|
|
84
|
+
extra: executionId !== undefined
|
|
85
|
+
? { "azure.cosmosdb.operation.partition_key": executionId, "app.entity.id": executionId }
|
|
86
|
+
: undefined
|
|
87
|
+
});
|
|
88
|
+
const workflows = new Map();
|
|
89
|
+
const locals = new Map();
|
|
90
|
+
const clocks = yield* FiberMap.make();
|
|
91
|
+
// Per-workflow codecs for the typed payload + top-level result. Cached by
|
|
92
|
+
// workflow name; derived from the workflow's own schemas so typed values
|
|
93
|
+
// (dates, branded ids, schema classes) survive the storage round-trip.
|
|
94
|
+
const makePayloadCodec = (workflow) => S.fromJsonString(S.toCodecJson(workflow.payloadSchema));
|
|
95
|
+
const payloadCodecCache = new Map();
|
|
96
|
+
const payloadCodecFor = (workflow) => {
|
|
97
|
+
let c = payloadCodecCache.get(workflow.name);
|
|
98
|
+
if (!c) {
|
|
99
|
+
c = makePayloadCodec(workflow);
|
|
100
|
+
payloadCodecCache.set(workflow.name, c);
|
|
101
|
+
}
|
|
102
|
+
return c;
|
|
103
|
+
};
|
|
104
|
+
const makeResultCodec = (workflow) => S.fromJsonString(S.toCodecJson(Workflow.Result({ success: workflow.successSchema, error: workflow.errorSchema })));
|
|
105
|
+
const resultCodecCache = new Map();
|
|
106
|
+
const resultCodecFor = (workflow) => {
|
|
107
|
+
let c = resultCodecCache.get(workflow.name);
|
|
108
|
+
if (!c) {
|
|
109
|
+
c = makeResultCodec(workflow);
|
|
110
|
+
resultCodecCache.set(workflow.name, c);
|
|
111
|
+
}
|
|
112
|
+
return c;
|
|
113
|
+
};
|
|
114
|
+
const encodePayload = (workflow, payload) => Effect.orDie(S.encodeEffect(payloadCodecFor(workflow))(payload));
|
|
115
|
+
const decodePayload = (workflow, s) => Effect.orDie(S.decodeEffect(payloadCodecFor(workflow))(s));
|
|
116
|
+
const encodeResult = (workflow, r) => Effect.orDie(S.encodeEffect(resultCodecFor(workflow))(r));
|
|
117
|
+
const decodeResult = (workflow, s) => Effect.orDie(S.decodeEffect(resultCodecFor(workflow))(s));
|
|
118
|
+
// --- Cosmos primitives -------------------------------------------------
|
|
119
|
+
const readExec = (executionId) => Effect
|
|
120
|
+
.gen(function* () {
|
|
121
|
+
const resp = yield* Effect.promise(() => container.item(execId, executionId).read());
|
|
122
|
+
yield* annotateCosmosResponse({ requestCharge: resp.requestCharge, statusCode: resp.statusCode });
|
|
123
|
+
return Option.fromNullishOr(resp.resource).pipe(Option.map((r) => ({ ...r, _etag: resp.etag })));
|
|
124
|
+
})
|
|
125
|
+
.pipe(annotate("readExec", executionId));
|
|
126
|
+
const replaceExec = (doc) => Effect
|
|
127
|
+
.gen(function* () {
|
|
128
|
+
const resp = yield* Effect.promise(() => container.item(execId, doc._partitionKey).replace(doc, {
|
|
129
|
+
accessCondition: { type: "IfMatch", condition: doc._etag ?? "" }
|
|
130
|
+
}));
|
|
131
|
+
yield* annotateCosmosResponse({ requestCharge: resp.requestCharge, statusCode: resp.statusCode });
|
|
132
|
+
if (isOptimisticStatus(resp.statusCode)) {
|
|
133
|
+
return yield* new OptimisticConcurrencyException({
|
|
134
|
+
type: "workflow.exec",
|
|
135
|
+
id: doc._partitionKey,
|
|
136
|
+
code: resp.statusCode
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return { ...doc, _etag: resp.etag };
|
|
140
|
+
})
|
|
141
|
+
.pipe(annotate("replaceExec", doc._partitionKey));
|
|
142
|
+
// Atomic create-or-noop using a single-op batch — returns true if created.
|
|
143
|
+
const createIfMissing = (body) => Effect.gen(function* () {
|
|
144
|
+
const resp = yield* Effect.promise(() => container.items.batch([{ operationType: "Create", resourceBody: body }], body._partitionKey));
|
|
145
|
+
const r = resp.result?.[0];
|
|
146
|
+
const code = r?.statusCode ?? 0;
|
|
147
|
+
if (code === 201)
|
|
148
|
+
return true;
|
|
149
|
+
if (code === 409)
|
|
150
|
+
return false;
|
|
151
|
+
return yield* Effect.die(new Error(`workflow-engine cosmos createIfMissing for ${body.id} failed: ${code}`));
|
|
152
|
+
});
|
|
153
|
+
// Last-writer-wins upsert — used to overwrite a persisted *suspended* activity
|
|
154
|
+
// result once it finally completes (create-only ops can't transition it).
|
|
155
|
+
const upsert = (body) => Effect.gen(function* () {
|
|
156
|
+
const resp = yield* Effect.promise(() => container.items.upsert(body));
|
|
157
|
+
yield* annotateCosmosResponse({ requestCharge: resp.requestCharge, statusCode: resp.statusCode });
|
|
158
|
+
});
|
|
159
|
+
const readPoint = (id, executionId) => Effect.promise(() => container.item(id, executionId).read()).pipe(Effect.map((r) => Option.fromNullishOr(r.resource)));
|
|
160
|
+
// --- Workflow result helpers ------------------------------------------
|
|
161
|
+
const completeResult = (workflow, state) => state.status === "complete" && state.completedResult
|
|
162
|
+
? Effect.map(decodeResult(workflow, state.completedResult), Option.some)
|
|
163
|
+
: Effect.succeedNone;
|
|
164
|
+
// --- Lease / claim ----------------------------------------------------
|
|
165
|
+
const leaseActive = (state, now) => state.worker !== undefined
|
|
166
|
+
&& state.worker !== workerId
|
|
167
|
+
&& state.leaseExpiresAt !== undefined
|
|
168
|
+
&& Date.parse(state.leaseExpiresAt) > now;
|
|
169
|
+
/**
|
|
170
|
+
* Try to claim a lease on `state`. Returns the updated doc on success, `None`
|
|
171
|
+
* if another worker holds an active lease, or on OCC conflict (caller may
|
|
172
|
+
* retry by re-reading).
|
|
173
|
+
*/
|
|
174
|
+
const tryClaim = (state) => Effect.gen(function* () {
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
if (leaseActive(state, now))
|
|
177
|
+
return Option.none();
|
|
178
|
+
const updated = {
|
|
179
|
+
...state,
|
|
180
|
+
worker: workerId,
|
|
181
|
+
leaseExpiresAt: new Date(now + Duration.toMillis(leaseTtl)).toISOString()
|
|
182
|
+
};
|
|
183
|
+
return yield* replaceExec(updated).pipe(Effect.map(Option.some), Effect.catchTag("OptimisticConcurrencyException", () => Effect.succeed(Option.none())));
|
|
184
|
+
});
|
|
185
|
+
/**
|
|
186
|
+
* Renew lease until the local fiber stops or another worker takes the claim.
|
|
187
|
+
* Best-effort: failures are swallowed; loop simply retries on next tick.
|
|
188
|
+
*/
|
|
189
|
+
const heartbeat = (executionId) => Effect.gen(function* () {
|
|
190
|
+
while (true) {
|
|
191
|
+
yield* Effect.sleep(heartbeatInterval);
|
|
192
|
+
const local = locals.get(executionId);
|
|
193
|
+
const polled = local?.fiber?.pollUnsafe();
|
|
194
|
+
if (!local?.fiber || polled)
|
|
195
|
+
return;
|
|
196
|
+
const cur = yield* readExec(executionId).pipe(Effect.catchCause(() => Effect.succeed(Option.none())));
|
|
197
|
+
if (Option.isNone(cur))
|
|
198
|
+
continue;
|
|
199
|
+
const state = cur.value;
|
|
200
|
+
if (state.status === "complete" || state.worker !== workerId)
|
|
201
|
+
return;
|
|
202
|
+
yield* replaceExec({
|
|
203
|
+
...state,
|
|
204
|
+
leaseExpiresAt: new Date(Date.now() + Duration.toMillis(leaseTtl)).toISOString()
|
|
205
|
+
})
|
|
206
|
+
.pipe(Effect.catchTag("OptimisticConcurrencyException", () => Effect.void), Effect.catchCause(() => Effect.void));
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
// --- Drive logic -------------------------------------------------------
|
|
210
|
+
const drive = (executionId, payload, parent, entry) => Effect.gen(function* () {
|
|
211
|
+
let local = locals.get(executionId);
|
|
212
|
+
if (local?.fiber) {
|
|
213
|
+
const polled = local.fiber.pollUnsafe();
|
|
214
|
+
const stillRunning = !polled;
|
|
215
|
+
const completedNotResume = polled && polled._tag === "Success" && polled.value._tag === "Complete";
|
|
216
|
+
if (stillRunning || completedNotResume)
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const stateOpt = yield* readExec(executionId);
|
|
220
|
+
if (Option.isNone(stateOpt) || stateOpt.value.status === "complete")
|
|
221
|
+
return;
|
|
222
|
+
// Best-effort claim: takes lease so recovery poller leaves us alone.
|
|
223
|
+
// Failure is tolerated — local fiber still drives; OCC guards persisted
|
|
224
|
+
// state so split-brain stays correct.
|
|
225
|
+
const claimed = yield* tryClaim(stateOpt.value);
|
|
226
|
+
const state = Option.isSome(claimed) ? claimed.value : stateOpt.value;
|
|
227
|
+
const instance = WorkflowInstance.initial(entry.workflow, executionId);
|
|
228
|
+
instance.interrupted = state.interrupted;
|
|
229
|
+
if (!local) {
|
|
230
|
+
local = { instance, fiber: undefined, parent };
|
|
231
|
+
locals.set(executionId, local);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
local.instance = instance;
|
|
235
|
+
}
|
|
236
|
+
const onComplete = Effect.fnUntraced(function* (result) {
|
|
237
|
+
const current = yield* readExec(executionId);
|
|
238
|
+
if (Option.isNone(current) || current.value.status === "complete")
|
|
239
|
+
return;
|
|
240
|
+
const isComplete = result._tag === "Complete";
|
|
241
|
+
const completedResult = isComplete ? yield* encodeResult(entry.workflow, result) : undefined;
|
|
242
|
+
yield* replaceExec({
|
|
243
|
+
...current.value,
|
|
244
|
+
status: isComplete ? "complete" : current.value.status,
|
|
245
|
+
suspended: result._tag === "Suspended",
|
|
246
|
+
interrupted: instance.interrupted,
|
|
247
|
+
completedResult,
|
|
248
|
+
// Release lease on completion so the doc isn't seen as orphaned.
|
|
249
|
+
worker: isComplete ? undefined : current.value.worker,
|
|
250
|
+
leaseExpiresAt: isComplete ? undefined : current.value.leaseExpiresAt
|
|
251
|
+
})
|
|
252
|
+
.pipe(Effect.catchTag("OptimisticConcurrencyException", () => Effect.void));
|
|
253
|
+
if (parent && isComplete) {
|
|
254
|
+
yield* Effect.forkIn(driveById(parent), scope);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
local.fiber = yield* entry.execute(payload, executionId).pipe(Effect.onExit(() => {
|
|
258
|
+
if (!instance.interrupted)
|
|
259
|
+
return Effect.void;
|
|
260
|
+
instance.suspended = false;
|
|
261
|
+
return Effect.withFiber((fiber) => Effect.interruptible(Fiber.interrupt(fiber)));
|
|
262
|
+
}), Workflow.intoResult, Effect.provideService(WorkflowInstance, instance), Effect.provideService(WorkflowEngine, engine), Effect.tap(onComplete), Effect.forkIn(entry.scope));
|
|
263
|
+
if (Option.isSome(claimed)) {
|
|
264
|
+
yield* Effect.forkIn(heartbeat(executionId), scope);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
const driveById = (executionId) => Effect.gen(function* () {
|
|
268
|
+
const stateOpt = yield* readExec(executionId);
|
|
269
|
+
if (Option.isNone(stateOpt))
|
|
270
|
+
return;
|
|
271
|
+
const state = stateOpt.value;
|
|
272
|
+
const entry = workflows.get(state.workflowName);
|
|
273
|
+
if (!entry)
|
|
274
|
+
return;
|
|
275
|
+
const payload = yield* decodePayload(entry.workflow, state.payload);
|
|
276
|
+
yield* drive(executionId, payload, state.parent, entry);
|
|
277
|
+
});
|
|
278
|
+
// --- Clock firing -----------------------------------------------------
|
|
279
|
+
// Persist deferred completion (first-writer-wins via createIfMissing),
|
|
280
|
+
// resume the workflow, then clean up the clock doc.
|
|
281
|
+
const fireClock = (doc) => Effect.gen(function* () {
|
|
282
|
+
const created = yield* createIfMissing({
|
|
283
|
+
id: deferredKey(doc.deferredName),
|
|
284
|
+
_partitionKey: doc._partitionKey,
|
|
285
|
+
type: "deferred",
|
|
286
|
+
exit: yield* encodeDeferredExit(Exit.void)
|
|
287
|
+
})
|
|
288
|
+
.pipe(annotate("clockFire", doc._partitionKey));
|
|
289
|
+
if (created)
|
|
290
|
+
yield* driveById(doc._partitionKey);
|
|
291
|
+
yield* Effect.promise(() => container.item(doc.id, doc._partitionKey).delete()).pipe(Effect.catchCause(() => Effect.void));
|
|
292
|
+
});
|
|
293
|
+
// --- Encoded engine ----------------------------------------------------
|
|
294
|
+
const encoded = {
|
|
295
|
+
register: Effect.fnUntraced(function* (workflow, execute) {
|
|
296
|
+
workflows.set(workflow.name, {
|
|
297
|
+
workflow,
|
|
298
|
+
execute,
|
|
299
|
+
scope: yield* Effect.scope
|
|
300
|
+
});
|
|
301
|
+
}),
|
|
302
|
+
execute: Effect.fnUntraced(function* (workflow, options) {
|
|
303
|
+
const entry = workflows.get(workflow.name);
|
|
304
|
+
if (!entry) {
|
|
305
|
+
return yield* Effect.orDie(Effect.fail(`Workflow ${workflow.name} is not registered`));
|
|
306
|
+
}
|
|
307
|
+
const initial = {
|
|
308
|
+
id: execId,
|
|
309
|
+
_partitionKey: options.executionId,
|
|
310
|
+
type: "exec",
|
|
311
|
+
workflowName: workflow.name,
|
|
312
|
+
payload: yield* encodePayload(workflow, options.payload),
|
|
313
|
+
parent: options.parent?.executionId,
|
|
314
|
+
status: "running",
|
|
315
|
+
suspended: false,
|
|
316
|
+
interrupted: false
|
|
317
|
+
};
|
|
318
|
+
const created = yield* createIfMissing(initial).pipe(annotate("execute.claim", options.executionId));
|
|
319
|
+
if (created || !locals.has(options.executionId)) {
|
|
320
|
+
yield* drive(options.executionId, options.payload, options.parent?.executionId, entry);
|
|
321
|
+
}
|
|
322
|
+
if (options.discard)
|
|
323
|
+
return undefined;
|
|
324
|
+
const local = locals.get(options.executionId);
|
|
325
|
+
if (local?.fiber) {
|
|
326
|
+
return (yield* Fiber.join(local.fiber));
|
|
327
|
+
}
|
|
328
|
+
// Foreign-owned execution: poll until exec doc reports complete.
|
|
329
|
+
while (true) {
|
|
330
|
+
const cur = yield* readExec(options.executionId);
|
|
331
|
+
if (Option.isSome(cur)) {
|
|
332
|
+
const c = yield* completeResult(workflow, cur.value);
|
|
333
|
+
if (Option.isSome(c))
|
|
334
|
+
return c.value;
|
|
335
|
+
}
|
|
336
|
+
yield* Effect.sleep(Duration.millis(500));
|
|
337
|
+
}
|
|
338
|
+
}),
|
|
339
|
+
poll: (workflow, executionId) => Effect.gen(function* () {
|
|
340
|
+
const local = locals.get(executionId);
|
|
341
|
+
if (local?.fiber) {
|
|
342
|
+
const exit = local.fiber.pollUnsafe();
|
|
343
|
+
if (!exit)
|
|
344
|
+
return Option.none();
|
|
345
|
+
if (exit._tag !== "Success")
|
|
346
|
+
return yield* Effect.die(exit.cause);
|
|
347
|
+
return Option.some(exit.value);
|
|
348
|
+
}
|
|
349
|
+
const state = yield* readExec(executionId);
|
|
350
|
+
if (Option.isNone(state))
|
|
351
|
+
return Option.none();
|
|
352
|
+
return yield* completeResult(workflow, state.value);
|
|
353
|
+
}),
|
|
354
|
+
interrupt: Effect.fnUntraced(function* (_workflow, executionId) {
|
|
355
|
+
const local = locals.get(executionId);
|
|
356
|
+
if (local)
|
|
357
|
+
local.instance.interrupted = true;
|
|
358
|
+
const current = yield* readExec(executionId);
|
|
359
|
+
if (Option.isNone(current) || current.value.status === "complete")
|
|
360
|
+
return;
|
|
361
|
+
yield* replaceExec({ ...current.value, interrupted: true }).pipe(Effect.catchTag("OptimisticConcurrencyException", () => Effect.void));
|
|
362
|
+
yield* driveById(executionId);
|
|
363
|
+
}),
|
|
364
|
+
interruptUnsafe: Effect.fnUntraced(function* (_workflow, executionId) {
|
|
365
|
+
const local = locals.get(executionId);
|
|
366
|
+
if (local)
|
|
367
|
+
local.instance.interrupted = true;
|
|
368
|
+
const current = yield* readExec(executionId);
|
|
369
|
+
if (Option.isSome(current) && current.value.status !== "complete") {
|
|
370
|
+
yield* replaceExec({ ...current.value, interrupted: true }).pipe(Effect.catchTag("OptimisticConcurrencyException", () => Effect.void));
|
|
371
|
+
}
|
|
372
|
+
if (local?.fiber)
|
|
373
|
+
yield* Fiber.interrupt(local.fiber);
|
|
374
|
+
}),
|
|
375
|
+
resume: (_workflow, executionId) => driveById(executionId),
|
|
376
|
+
activityExecute: Effect.fnUntraced(function* (activity, attempt) {
|
|
377
|
+
const instance = yield* WorkflowInstance;
|
|
378
|
+
const id = activityKey(activity.name, attempt);
|
|
379
|
+
const existing = yield* readPoint(id, instance.executionId).pipe(annotate("activityRead", instance.executionId));
|
|
380
|
+
if (Option.isSome(existing)) {
|
|
381
|
+
const prev = yield* decodeActivityResult(existing.value.result);
|
|
382
|
+
// A completed activity is replayed from its persisted result; a
|
|
383
|
+
// suspended one must re-run (it parked on a clock/deferred).
|
|
384
|
+
if (prev._tag === "Complete")
|
|
385
|
+
return prev;
|
|
386
|
+
}
|
|
387
|
+
const activityInstance = WorkflowInstance.initial(instance.workflow, instance.executionId);
|
|
388
|
+
activityInstance.interrupted = instance.interrupted;
|
|
389
|
+
const result = yield* activity.executeEncoded.pipe(Workflow.intoResult, Effect.provideService(WorkflowInstance, activityInstance));
|
|
390
|
+
const doc = {
|
|
391
|
+
id,
|
|
392
|
+
_partitionKey: instance.executionId,
|
|
393
|
+
type: "activity",
|
|
394
|
+
result: yield* encodeActivityResult(result)
|
|
395
|
+
};
|
|
396
|
+
if (Option.isSome(existing)) {
|
|
397
|
+
// Overwrite the previously persisted *suspended* doc with the new result.
|
|
398
|
+
yield* upsert(doc).pipe(annotate("activityPersist", instance.executionId));
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
// First-writer-wins: if persistence loses the race, use the persisted result.
|
|
402
|
+
const persisted = yield* createIfMissing(doc).pipe(annotate("activityPersist", instance.executionId));
|
|
403
|
+
if (persisted)
|
|
404
|
+
return result;
|
|
405
|
+
const winner = yield* readPoint(id, instance.executionId);
|
|
406
|
+
if (Option.isSome(winner)) {
|
|
407
|
+
const w = yield* decodeActivityResult(winner.value.result);
|
|
408
|
+
if (w._tag === "Complete")
|
|
409
|
+
return w;
|
|
410
|
+
}
|
|
411
|
+
return result;
|
|
412
|
+
}),
|
|
413
|
+
deferredResult: Effect.fnUntraced(function* (deferred) {
|
|
414
|
+
const instance = yield* WorkflowInstance;
|
|
415
|
+
const got = yield* readPoint(deferredKey(deferred.name), instance.executionId).pipe(annotate("deferredRead", instance.executionId));
|
|
416
|
+
if (Option.isNone(got))
|
|
417
|
+
return Option.none();
|
|
418
|
+
return Option.some(yield* decodeDeferredExit(got.value.exit));
|
|
419
|
+
}),
|
|
420
|
+
deferredDone: Effect.fnUntraced(function* (options) {
|
|
421
|
+
const created = yield* createIfMissing({
|
|
422
|
+
id: deferredKey(options.deferredName),
|
|
423
|
+
_partitionKey: options.executionId,
|
|
424
|
+
type: "deferred",
|
|
425
|
+
exit: yield* encodeDeferredExit(options.exit)
|
|
426
|
+
})
|
|
427
|
+
.pipe(annotate("deferredPersist", options.executionId));
|
|
428
|
+
if (!created)
|
|
429
|
+
return;
|
|
430
|
+
yield* driveById(options.executionId);
|
|
431
|
+
}),
|
|
432
|
+
scheduleClock: (workflow, options) => {
|
|
433
|
+
const fireAt = new Date(Date.now() + Duration.toMillis(options.clock.duration)).toISOString();
|
|
434
|
+
const clockDoc = {
|
|
435
|
+
id: clockKey(options.clock.name),
|
|
436
|
+
_partitionKey: options.executionId,
|
|
437
|
+
type: "clock",
|
|
438
|
+
workflowName: workflow.name,
|
|
439
|
+
deferredName: options.clock.deferred.name,
|
|
440
|
+
fireAt
|
|
441
|
+
};
|
|
442
|
+
return Effect.gen(function* () {
|
|
443
|
+
yield* createIfMissing(clockDoc).pipe(annotate("clockPersist", options.executionId));
|
|
444
|
+
// Fast-path in-process timer. If this process dies, the clock poller
|
|
445
|
+
// picks up the persisted doc and fires the deferred.
|
|
446
|
+
yield* fireClock(clockDoc).pipe(Effect.delay(options.clock.duration), FiberMap.run(clocks, `${options.executionId}/${options.clock.name}`, { onlyIfMissing: true }), Effect.asVoid);
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
const engine = makeUnsafe(encoded);
|
|
451
|
+
// --- Recovery poller --------------------------------------------------
|
|
452
|
+
// Scan for executions whose lease has lapsed (or was never set) and
|
|
453
|
+
// re-drive them locally. driveById will go through claim → fork fiber,
|
|
454
|
+
// resuming activities from persisted results.
|
|
455
|
+
if (Duration.toMillis(recoveryInterval) > 0) {
|
|
456
|
+
const recoverStep = Effect
|
|
457
|
+
.gen(function* () {
|
|
458
|
+
const nowIso = new Date().toISOString();
|
|
459
|
+
const stale = yield* Effect.promise(() => container
|
|
460
|
+
.items
|
|
461
|
+
.query({
|
|
462
|
+
query: "SELECT c._partitionKey, c.workflowName FROM c WHERE c.type = 'exec' AND c.status = 'running' AND (NOT IS_DEFINED(c.leaseExpiresAt) OR c.leaseExpiresAt <= @now)",
|
|
463
|
+
parameters: [{ name: "@now", value: nowIso }]
|
|
464
|
+
})
|
|
465
|
+
.fetchAll());
|
|
466
|
+
for (const row of stale.resources) {
|
|
467
|
+
if (!workflows.has(row.workflowName))
|
|
468
|
+
continue;
|
|
469
|
+
const local = locals.get(row._partitionKey);
|
|
470
|
+
if (local?.fiber && !local.fiber.pollUnsafe())
|
|
471
|
+
continue;
|
|
472
|
+
yield* Effect.forkIn(driveById(row._partitionKey), scope);
|
|
473
|
+
}
|
|
474
|
+
})
|
|
475
|
+
.pipe(annotate("recoveryScan"), Effect.catchCause(() => Effect.void));
|
|
476
|
+
yield* recoverStep.pipe(Effect.repeat(Schedule.spaced(recoveryInterval)), Effect.forkIn(scope));
|
|
477
|
+
}
|
|
478
|
+
// --- Clock poller -----------------------------------------------------
|
|
479
|
+
// Cross-partition scan for clocks whose fireAt is due. Fires the deferred
|
|
480
|
+
// via createIfMissing (idempotent) so multiple pollers across processes
|
|
481
|
+
// converge. Also acts as the restart recovery path for clocks scheduled
|
|
482
|
+
// before a crash.
|
|
483
|
+
if (Duration.toMillis(clockPollInterval) > 0) {
|
|
484
|
+
const clockStep = Effect
|
|
485
|
+
.gen(function* () {
|
|
486
|
+
const nowIso = new Date().toISOString();
|
|
487
|
+
const due = yield* Effect.promise(() => container
|
|
488
|
+
.items
|
|
489
|
+
.query({
|
|
490
|
+
query: "SELECT c.id, c._partitionKey, c.workflowName, c.deferredName FROM c WHERE c.type = 'clock' AND c.fireAt <= @now",
|
|
491
|
+
parameters: [{ name: "@now", value: nowIso }]
|
|
492
|
+
})
|
|
493
|
+
.fetchAll());
|
|
494
|
+
for (const row of due.resources) {
|
|
495
|
+
yield* Effect.forkIn(fireClock({
|
|
496
|
+
id: row.id,
|
|
497
|
+
_partitionKey: row._partitionKey,
|
|
498
|
+
type: "clock",
|
|
499
|
+
workflowName: row.workflowName,
|
|
500
|
+
deferredName: row.deferredName,
|
|
501
|
+
fireAt: nowIso
|
|
502
|
+
}), scope);
|
|
503
|
+
}
|
|
504
|
+
})
|
|
505
|
+
.pipe(annotate("clockScan"), Effect.catchCause(() => Effect.void));
|
|
506
|
+
yield* clockStep.pipe(Effect.repeat(Schedule.spaced(clockPollInterval)), Effect.forkIn(scope));
|
|
507
|
+
}
|
|
508
|
+
return engine;
|
|
509
|
+
});
|
|
510
|
+
/**
|
|
511
|
+
* Cosmos DB backed `WorkflowEngine` layer.
|
|
512
|
+
*
|
|
513
|
+
* Per-execution writes share a partition key (TransactionalBatch-eligible) and
|
|
514
|
+
* use OCC via `_etag`/IfMatch, giving first-writer-wins semantics for activity
|
|
515
|
+
* results, durable-deferred completions, and exec-state transitions. All
|
|
516
|
+
* persisted payloads/results/exits are round-tripped through schema codecs.
|
|
517
|
+
*/
|
|
518
|
+
export const layerCosmos = (cfg) => Layer
|
|
519
|
+
.effect(WorkflowEngine)(makeCosmosWorkflowEngine(cfg))
|
|
520
|
+
.pipe(Layer.provide(CosmosClientLayer(Redacted.value(cfg.url), cfg.dbName)));
|
|
521
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV29ya2Zsb3dFbmdpbmVDb3Ntb3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvV29ya2Zsb3dFbmdpbmVDb3Ntb3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0ErQkc7QUFDSCxPQUFPLEtBQUssTUFBTSxNQUFNLG1CQUFtQixDQUFBO0FBQzNDLE9BQU8sS0FBSyxLQUFLLE1BQU0sa0JBQWtCLENBQUE7QUFDekMsT0FBTyxLQUFLLE1BQU0sTUFBTSxtQkFBbUIsQ0FBQTtBQUMzQyxPQUFPLEtBQUssQ0FBQyxNQUFNLG1CQUFtQixDQUFBO0FBQ3RDLE9BQU8sS0FBSyxRQUFRLE1BQU0saUJBQWlCLENBQUE7QUFDM0MsT0FBTyxLQUFLLElBQUksTUFBTSxhQUFhLENBQUE7QUFDbkMsT0FBTyxLQUFLLEtBQUssTUFBTSxjQUFjLENBQUE7QUFDckMsT0FBTyxLQUFLLFFBQVEsTUFBTSxpQkFBaUIsQ0FBQTtBQUMzQyxPQUFPLEtBQUssUUFBUSxNQUFNLGlCQUFpQixDQUFBO0FBQzNDLE9BQU8sS0FBSyxRQUFRLE1BQU0saUJBQWlCLENBQUE7QUFFM0MsT0FBTyxLQUFLLFFBQVEsTUFBTSxtQ0FBbUMsQ0FBQTtBQUM3RCxPQUFPLEVBQWdCLFVBQVUsRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQTtBQUNwSCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3hDLE9BQU8sRUFBRSxZQUFZLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQTtBQUNwRSxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDNUQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLFVBQVUsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQStEOUQsTUFBTSxNQUFNLEdBQUcsTUFBZSxDQUFBO0FBQzlCLE1BQU0sV0FBVyxHQUFHLENBQUMs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
|
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.257",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"proper-lockfile": "^4.1.2",
|
|
14
14
|
"pure-rand": "8.4.0",
|
|
15
15
|
"query-string": "^9.3.1",
|
|
16
|
-
"effect-app": "4.0.0-beta.
|
|
16
|
+
"effect-app": "4.0.0-beta.257"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@azure/cosmos": "^4.9.3",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_check-agg-infer.test-d.d.ts","sourceRoot":"","sources":["../_check-agg-infer.test-d.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as S from "effect-app/Schema";
|
|
2
|
+
import { aggregate, make, where } from "effect-app/Model/query";
|
|
3
|
+
const baseSchema = S.Struct({
|
|
4
|
+
id: S.String,
|
|
5
|
+
address: S.Struct({ city: S.String }),
|
|
6
|
+
active: S.Boolean,
|
|
7
|
+
qty: S.Number
|
|
8
|
+
});
|
|
9
|
+
// Should compile — Row inferred from pipe
|
|
10
|
+
const _ok = make().pipe(aggregate(S.Struct({ city: S.String, count: S.NonNegativeInt, total: S.Number }), ($) => ({
|
|
11
|
+
city: $.field("address.city"),
|
|
12
|
+
count: $.countWhen((q) => q.pipe(where("active", true))),
|
|
13
|
+
total: $.sum("qty")
|
|
14
|
+
})));
|
|
15
|
+
// Should ERROR — bad path
|
|
16
|
+
const _bad = make().pipe(aggregate(S.Struct({ a: S.String }), ($) => ({
|
|
17
|
+
a: $.field("nonexistent")
|
|
18
|
+
})));
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2NoZWNrLWFnZy1pbmZlci50ZXN0LWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9fY2hlY2stYWdnLWluZmVyLnRlc3QtZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssQ0FBQyxNQUFNLG1CQUFtQixDQUFBO0FBQ3RDLE9BQU8sRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxNQUFNLHdCQUF3QixDQUFBO0FBRS9ELE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDMUIsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNO0lBQ1osT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ3JDLE1BQU0sRUFBRSxDQUFDLENBQUMsT0FBTztJQUNqQixHQUFHLEVBQUUsQ0FBQyxDQUFDLE1BQU07Q0FDZCxDQUFDLENBQUE7QUFHRiwwQ0FBMEM7QUFDMUMsTUFBTSxHQUFHLEdBQUcsSUFBSSxFQUFPLENBQUMsSUFBSSxDQUMxQixTQUFTLENBQ1AsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsY0FBYyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsRUFDdEUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDTixJQUFJLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUM7SUFDN0IsS0FBSyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3hELEtBQUssRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQztDQUNwQixDQUFDLENBQ0gsQ0FDRixDQUFBO0FBRUQsMEJBQTBCO0FBQzFCLE1BQU0sSUFBSSxHQUFHLElBQUksRUFBTyxDQUFDLElBQUksQ0FDM0IsU0FBUyxDQUNQLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQ3pCLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ04sQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDO0NBQzFCLENBQUMsQ0FDSCxDQUNGLENBQUEifQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_check-proj-infer.test-d.d.ts","sourceRoot":"","sources":["../_check-proj-infer.test-d.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as S from "effect-app/Schema";
|
|
2
|
+
import { make, projectComputed, where } from "effect-app/Model/query";
|
|
3
|
+
const baseSchema = S.Struct({
|
|
4
|
+
id: S.String,
|
|
5
|
+
items: S.Array(S.Struct({ articleId: S.String, qty: S.Number, note: S.String }))
|
|
6
|
+
});
|
|
7
|
+
// Should compile — Row inferred from pipe
|
|
8
|
+
const _ok = make().pipe(projectComputed(S.Struct({ id: S.String, total: S.Number, distinctArticles: S.NonNegativeInt }), ({ relation }) => ({
|
|
9
|
+
total: relation("items").sum("qty"),
|
|
10
|
+
distinctArticles: relation("items").distinctCount("articleId", where("qty", "gte", 0))
|
|
11
|
+
})));
|
|
12
|
+
// Should ERROR — bad path on relation element
|
|
13
|
+
const _bad = make().pipe(projectComputed(S.Struct({ a: S.Number }), ({ relation }) => ({
|
|
14
|
+
a: relation("items").sum("nonexistent")
|
|
15
|
+
})));
|
|
16
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2NoZWNrLXByb2otaW5mZXIudGVzdC1kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vX2NoZWNrLXByb2otaW5mZXIudGVzdC1kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxDQUFDLE1BQU0sbUJBQW1CLENBQUE7QUFDdEMsT0FBTyxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFFckUsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUMxQixFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU07SUFDWixLQUFLLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0NBQ2pGLENBQUMsQ0FBQTtBQUdGLDBDQUEwQztBQUMxQyxNQUFNLEdBQUcsR0FBRyxJQUFJLEVBQU8sQ0FBQyxJQUFJLENBQzFCLGVBQWUsQ0FDYixDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDLEVBQy9FLENBQUMsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNqQixLQUFLLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUM7SUFDbkMsZ0JBQWdCLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLGFBQWEsQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7Q0FDdkYsQ0FBQyxDQUNILENBQ0YsQ0FBQTtBQUVELDhDQUE4QztBQUM5QyxNQUFNLElBQUksR0FBRyxJQUFJLEVBQU8sQ0FBQyxJQUFJLENBQzNCLGVBQWUsQ0FDYixDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUN6QixDQUFDLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDakIsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDO0NBQ3hDLENBQUMsQ0FDSCxDQUNGLENBQUEifQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_check-tighten.test-d.d.ts","sourceRoot":"","sources":["../_check-tighten.test-d.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as S from "effect-app/Schema";
|
|
2
|
+
import { computed, relation } from "effect-app/Model/query";
|
|
3
|
+
const baseSchema = S.Struct({
|
|
4
|
+
id: S.String,
|
|
5
|
+
items: S.Array(S.Struct({ articleId: S.String, qty: S.Number }))
|
|
6
|
+
});
|
|
7
|
+
// Should compile:
|
|
8
|
+
const _ok = computed({
|
|
9
|
+
a: relation("items").sum("qty"),
|
|
10
|
+
b: relation("items").distinctCount("articleId"),
|
|
11
|
+
c: relation("items").collect("articleId"),
|
|
12
|
+
d: relation("items").collectFields(["articleId", "qty"])
|
|
13
|
+
});
|
|
14
|
+
// Should ERROR — invalid field paths
|
|
15
|
+
const _bad = computed({
|
|
16
|
+
a: relation("items").sum("nonexistent"),
|
|
17
|
+
b: relation("items").distinctCount("not_a_field"),
|
|
18
|
+
c: relation("items").collect("zzz"),
|
|
19
|
+
d: relation("items").collectFields(["zzz"])
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2NoZWNrLXRpZ2h0ZW4udGVzdC1kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vX2NoZWNrLXRpZ2h0ZW4udGVzdC1kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxDQUFDLE1BQU0sbUJBQW1CLENBQUE7QUFDdEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQTtBQUUzRCxNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQzFCLEVBQUUsRUFBRSxDQUFDLENBQUMsTUFBTTtJQUNaLEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7Q0FDakUsQ0FBQyxDQUFBO0FBR0Ysa0JBQWtCO0FBQ2xCLE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQztJQUNuQixDQUFDLEVBQUUsUUFBUSxDQUFNLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUM7SUFDcEMsQ0FBQyxFQUFFLFFBQVEsQ0FBTSxPQUFPLENBQUMsQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDO0lBQ3BELENBQUMsRUFBRSxRQUFRLENBQU0sT0FBTyxDQUFDLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQztJQUM5QyxDQUFDLEVBQUUsUUFBUSxDQUFNLE9BQU8sQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLFdBQVcsRUFBRSxLQUFLLENBQUMsQ0FBQztDQUM5RCxDQUFDLENBQUE7QUFFRixxQ0FBcUM7QUFDckMsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDO0lBQ3BCLENBQUMsRUFBRSxRQUFRLENBQU0sT0FBTyxDQUFDLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQztJQUM1QyxDQUFDLEVBQUUsUUFBUSxDQUFNLE9BQU8sQ0FBQyxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUM7SUFDdEQsQ0FBQyxFQUFFLFFBQVEsQ0FBTSxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDO0lBQ3hDLENBQUMsRUFBRSxRQUFRLENBQU0sT0FBTyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7Q0FDakQsQ0FBQyxDQUFBIn0=
|