@fragno-dev/db 0.2.0 → 0.2.2
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/.turbo/turbo-build.log +34 -30
- package/CHANGELOG.md +49 -0
- package/dist/adapters/generic-sql/query/where-builder.js +1 -1
- package/dist/db-fragment-definition-builder.d.ts +31 -39
- package/dist/db-fragment-definition-builder.d.ts.map +1 -1
- package/dist/db-fragment-definition-builder.js +20 -16
- package/dist/db-fragment-definition-builder.js.map +1 -1
- package/dist/fragments/internal-fragment.d.ts +94 -8
- package/dist/fragments/internal-fragment.d.ts.map +1 -1
- package/dist/fragments/internal-fragment.js +56 -55
- package/dist/fragments/internal-fragment.js.map +1 -1
- package/dist/hooks/hooks.d.ts +5 -3
- package/dist/hooks/hooks.d.ts.map +1 -1
- package/dist/hooks/hooks.js +38 -37
- package/dist/hooks/hooks.js.map +1 -1
- package/dist/mod.d.ts +3 -3
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +4 -4
- package/dist/mod.js.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts +367 -80
- package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/execute-unit-of-work.js +448 -148
- package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.d.ts +35 -11
- package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work/unit-of-work.js +49 -19
- package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
- package/dist/query/value-decoding.js +1 -1
- package/dist/schema/create.d.ts +2 -3
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +2 -5
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/generate-id.d.ts +20 -0
- package/dist/schema/generate-id.d.ts.map +1 -0
- package/dist/schema/generate-id.js +28 -0
- package/dist/schema/generate-id.js.map +1 -0
- package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +1 -0
- package/src/adapters/drizzle/drizzle-adapter-sqlite3.test.ts +41 -25
- package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +39 -25
- package/src/db-fragment-definition-builder.test.ts +58 -42
- package/src/db-fragment-definition-builder.ts +78 -88
- package/src/db-fragment-instantiator.test.ts +64 -88
- package/src/db-fragment-integration.test.ts +292 -142
- package/src/fragments/internal-fragment.test.ts +272 -266
- package/src/fragments/internal-fragment.ts +155 -122
- package/src/hooks/hooks.test.ts +268 -264
- package/src/hooks/hooks.ts +74 -63
- package/src/mod.ts +14 -4
- package/src/query/unit-of-work/execute-unit-of-work.test.ts +1582 -998
- package/src/query/unit-of-work/execute-unit-of-work.ts +1746 -343
- package/src/query/unit-of-work/tx-builder.test.ts +1041 -0
- package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +269 -21
- package/src/query/unit-of-work/unit-of-work.test.ts +64 -0
- package/src/query/unit-of-work/unit-of-work.ts +65 -30
- package/src/schema/create.ts +2 -5
- package/src/schema/generate-id.test.ts +57 -0
- package/src/schema/generate-id.ts +38 -0
- package/src/shared/config.ts +0 -10
- package/src/shared/connection-pool.ts +0 -24
- package/src/shared/prisma.ts +0 -45
|
@@ -0,0 +1,1041 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test suite for ServiceTxBuilder and HandlerTxBuilder type inference.
|
|
3
|
+
* These tests verify that the builder pattern correctly infers types based on
|
|
4
|
+
* which callbacks are set.
|
|
5
|
+
*
|
|
6
|
+
* NOTE: These are TYPE tests only. We test that the type inference is correct,
|
|
7
|
+
* not the runtime behavior (which is covered by execute-unit-of-work.test.ts).
|
|
8
|
+
*/
|
|
9
|
+
import { describe, expectTypeOf, it } from "vitest";
|
|
10
|
+
import type { AnySchema } from "../../schema/create";
|
|
11
|
+
import type { TypedUnitOfWork } from "./unit-of-work";
|
|
12
|
+
import {
|
|
13
|
+
ServiceTxBuilder,
|
|
14
|
+
HandlerTxBuilder,
|
|
15
|
+
type TxResult,
|
|
16
|
+
type ServiceBuilderMutateContext,
|
|
17
|
+
type HandlerBuilderMutateContext,
|
|
18
|
+
type BuilderTransformContextWithMutate,
|
|
19
|
+
type BuilderTransformContextWithoutMutate,
|
|
20
|
+
type ExtractServiceRetrieveResults,
|
|
21
|
+
type ExtractServiceFinalResults,
|
|
22
|
+
type AwaitedPromisesInObject,
|
|
23
|
+
} from "./execute-unit-of-work";
|
|
24
|
+
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Helper types for extracting TxResult type parameters
|
|
27
|
+
// =============================================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Extract the final result type (TResult) from a TxResult
|
|
31
|
+
*/
|
|
32
|
+
type TxResultFinalType<T> = T extends TxResult<infer R, infer _> ? R : never;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Extract the retrieve success result type from a TxResult
|
|
36
|
+
*/
|
|
37
|
+
type TxResultRetrieveType<T> = T extends TxResult<infer _, infer R> ? R : never;
|
|
38
|
+
|
|
39
|
+
// =============================================================================
|
|
40
|
+
// Test Schema
|
|
41
|
+
// =============================================================================
|
|
42
|
+
|
|
43
|
+
type TestSchema = AnySchema & {
|
|
44
|
+
version: 1;
|
|
45
|
+
entities: {
|
|
46
|
+
users: { id: string; name: string; email: string };
|
|
47
|
+
orders: { id: string; userId: string; total: number };
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// =============================================================================
|
|
52
|
+
// ServiceTxBuilder Type Tests
|
|
53
|
+
// =============================================================================
|
|
54
|
+
|
|
55
|
+
describe("ServiceTxBuilder type inference", () => {
|
|
56
|
+
// We're testing types only, not runtime behavior
|
|
57
|
+
// Using `as` casts to create builders without runtime dependencies
|
|
58
|
+
|
|
59
|
+
describe("return type priority", () => {
|
|
60
|
+
it("returns empty array when no callbacks are set", () => {
|
|
61
|
+
// Create a builder type directly to test type inference
|
|
62
|
+
type Builder = ServiceTxBuilder<
|
|
63
|
+
TestSchema,
|
|
64
|
+
readonly [],
|
|
65
|
+
[],
|
|
66
|
+
[],
|
|
67
|
+
unknown,
|
|
68
|
+
unknown,
|
|
69
|
+
false,
|
|
70
|
+
false,
|
|
71
|
+
false,
|
|
72
|
+
false,
|
|
73
|
+
{}
|
|
74
|
+
>;
|
|
75
|
+
|
|
76
|
+
// The build() return type should be TxResult<[], []>
|
|
77
|
+
type BuildResult = ReturnType<Builder["build"]>;
|
|
78
|
+
// Extract just the type parameters to avoid complex internal type matching
|
|
79
|
+
// Check length property to verify empty tuple without array method comparison issues
|
|
80
|
+
expectTypeOf<TxResultFinalType<BuildResult>["length"]>().toEqualTypeOf<0>();
|
|
81
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>["length"]>().toEqualTypeOf<0>();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("returns retrieve results when only retrieve is set", () => {
|
|
85
|
+
type Builder = ServiceTxBuilder<
|
|
86
|
+
TestSchema,
|
|
87
|
+
readonly [],
|
|
88
|
+
[{ id: string; name: string }[]],
|
|
89
|
+
[{ id: string; name: string }[]], // same as retrieve since no transformRetrieve
|
|
90
|
+
unknown,
|
|
91
|
+
unknown,
|
|
92
|
+
true, // HasRetrieve
|
|
93
|
+
false,
|
|
94
|
+
false,
|
|
95
|
+
false,
|
|
96
|
+
{}
|
|
97
|
+
>;
|
|
98
|
+
|
|
99
|
+
type BuildResult = ReturnType<Builder["build"]>;
|
|
100
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<
|
|
101
|
+
[{ id: string; name: string }[]]
|
|
102
|
+
>();
|
|
103
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<
|
|
104
|
+
[{ id: string; name: string }[]]
|
|
105
|
+
>();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("returns transformRetrieve result when transformRetrieve is set", () => {
|
|
109
|
+
type Builder = ServiceTxBuilder<
|
|
110
|
+
TestSchema,
|
|
111
|
+
readonly [],
|
|
112
|
+
[{ id: string; name: string }[]],
|
|
113
|
+
{ id: string; name: string } | null, // transformed result
|
|
114
|
+
unknown,
|
|
115
|
+
unknown,
|
|
116
|
+
true, // HasRetrieve
|
|
117
|
+
true, // HasTransformRetrieve
|
|
118
|
+
false,
|
|
119
|
+
false,
|
|
120
|
+
{}
|
|
121
|
+
>;
|
|
122
|
+
|
|
123
|
+
type BuildResult = ReturnType<Builder["build"]>;
|
|
124
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<{
|
|
125
|
+
id: string;
|
|
126
|
+
name: string;
|
|
127
|
+
} | null>();
|
|
128
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<{
|
|
129
|
+
id: string;
|
|
130
|
+
name: string;
|
|
131
|
+
} | null>();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("returns mutate result when mutate is set (no transformRetrieve)", () => {
|
|
135
|
+
type Builder = ServiceTxBuilder<
|
|
136
|
+
TestSchema,
|
|
137
|
+
readonly [],
|
|
138
|
+
[{ id: string; name: string }[]],
|
|
139
|
+
[{ id: string; name: string }[]], // raw retrieve results since no transformRetrieve
|
|
140
|
+
{ created: true; id: string }, // mutate result
|
|
141
|
+
unknown,
|
|
142
|
+
true, // HasRetrieve
|
|
143
|
+
false, // NO transformRetrieve
|
|
144
|
+
true, // HasMutate
|
|
145
|
+
false,
|
|
146
|
+
{}
|
|
147
|
+
>;
|
|
148
|
+
|
|
149
|
+
type BuildResult = ReturnType<Builder["build"]>;
|
|
150
|
+
// Final result type is the mutate return type
|
|
151
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<{
|
|
152
|
+
created: true;
|
|
153
|
+
id: string;
|
|
154
|
+
}>();
|
|
155
|
+
// Retrieve success result is the raw retrieve results (no transformRetrieve)
|
|
156
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<
|
|
157
|
+
[{ id: string; name: string }[]]
|
|
158
|
+
>();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("returns mutate result when mutate is set (with transformRetrieve)", () => {
|
|
162
|
+
type Builder = ServiceTxBuilder<
|
|
163
|
+
TestSchema,
|
|
164
|
+
readonly [],
|
|
165
|
+
[{ id: string; name: string }[]],
|
|
166
|
+
{ id: string; name: string } | null, // transformed
|
|
167
|
+
{ orderId: string }, // mutate result
|
|
168
|
+
unknown,
|
|
169
|
+
true, // HasRetrieve
|
|
170
|
+
true, // HasTransformRetrieve
|
|
171
|
+
true, // HasMutate
|
|
172
|
+
false,
|
|
173
|
+
{}
|
|
174
|
+
>;
|
|
175
|
+
|
|
176
|
+
type BuildResult = ReturnType<Builder["build"]>;
|
|
177
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<{ orderId: string }>();
|
|
178
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<{
|
|
179
|
+
id: string;
|
|
180
|
+
name: string;
|
|
181
|
+
} | null>();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("returns transform result when transform is set", () => {
|
|
185
|
+
type Builder = ServiceTxBuilder<
|
|
186
|
+
TestSchema,
|
|
187
|
+
readonly [],
|
|
188
|
+
[{ id: string; name: string }[]],
|
|
189
|
+
{ id: string; name: string } | null,
|
|
190
|
+
{ orderId: string },
|
|
191
|
+
{ success: true; data: string }, // transform result
|
|
192
|
+
true, // HasRetrieve
|
|
193
|
+
true, // HasTransformRetrieve
|
|
194
|
+
true, // HasMutate
|
|
195
|
+
true, // HasTransform
|
|
196
|
+
{}
|
|
197
|
+
>;
|
|
198
|
+
|
|
199
|
+
type BuildResult = ReturnType<Builder["build"]>;
|
|
200
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<{
|
|
201
|
+
success: true;
|
|
202
|
+
data: string;
|
|
203
|
+
}>();
|
|
204
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<{
|
|
205
|
+
id: string;
|
|
206
|
+
name: string;
|
|
207
|
+
} | null>();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe("withServiceCalls type inference", () => {
|
|
212
|
+
it("infers service call result types in mutate context", () => {
|
|
213
|
+
type ServiceCall1 = TxResult<{ userId: string }, { userId: string }>;
|
|
214
|
+
type ServiceCall2 = TxResult<number, number>;
|
|
215
|
+
type ServiceCalls = readonly [ServiceCall1, ServiceCall2];
|
|
216
|
+
|
|
217
|
+
type Builder = ServiceTxBuilder<
|
|
218
|
+
TestSchema,
|
|
219
|
+
ServiceCalls,
|
|
220
|
+
[],
|
|
221
|
+
[],
|
|
222
|
+
string, // mutate result
|
|
223
|
+
unknown,
|
|
224
|
+
false,
|
|
225
|
+
false,
|
|
226
|
+
true, // HasMutate
|
|
227
|
+
false,
|
|
228
|
+
{}
|
|
229
|
+
>;
|
|
230
|
+
|
|
231
|
+
// Get the mutate method's parameter type
|
|
232
|
+
type MutateParam = Parameters<Builder["mutate"]>[0];
|
|
233
|
+
type MutateCtx = Parameters<MutateParam>[0];
|
|
234
|
+
|
|
235
|
+
// serviceIntermediateResult should be a tuple with the retrieve success results
|
|
236
|
+
expectTypeOf<MutateCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
237
|
+
readonly [{ userId: string }, number]
|
|
238
|
+
>();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("handles optional service calls (undefined in tuple)", () => {
|
|
242
|
+
type ServiceCall = TxResult<{ userId: string }, { userId: string }>;
|
|
243
|
+
type ServiceCalls = readonly [ServiceCall, undefined];
|
|
244
|
+
|
|
245
|
+
type Extracted = ExtractServiceRetrieveResults<ServiceCalls>;
|
|
246
|
+
|
|
247
|
+
// Second element should be undefined
|
|
248
|
+
expectTypeOf<Extracted>().toEqualTypeOf<readonly [{ userId: string }, undefined]>();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("provides serviceIntermediateResult in transform with final results", () => {
|
|
252
|
+
type ServiceCall = TxResult<{ finalData: string }, { retrieveData: string }>;
|
|
253
|
+
type ServiceCalls = readonly [ServiceCall];
|
|
254
|
+
|
|
255
|
+
type Builder = ServiceTxBuilder<
|
|
256
|
+
TestSchema,
|
|
257
|
+
ServiceCalls,
|
|
258
|
+
[],
|
|
259
|
+
[],
|
|
260
|
+
{ created: boolean },
|
|
261
|
+
unknown,
|
|
262
|
+
false,
|
|
263
|
+
false,
|
|
264
|
+
true, // HasMutate
|
|
265
|
+
true, // HasTransform (we'll check its param type)
|
|
266
|
+
{}
|
|
267
|
+
>;
|
|
268
|
+
|
|
269
|
+
// Get the transform method's parameter type
|
|
270
|
+
type TransformParam = Parameters<Builder["transform"]>[0];
|
|
271
|
+
type TransformCtx = Parameters<TransformParam>[0];
|
|
272
|
+
|
|
273
|
+
// serviceResult contains final results
|
|
274
|
+
expectTypeOf<TransformCtx["serviceResult"]>().toEqualTypeOf<
|
|
275
|
+
readonly [{ finalData: string }]
|
|
276
|
+
>();
|
|
277
|
+
// serviceIntermediateResult contains retrieve success results
|
|
278
|
+
expectTypeOf<TransformCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
279
|
+
readonly [{ retrieveData: string }]
|
|
280
|
+
>();
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe("context types", () => {
|
|
285
|
+
it("ServiceBuilderMutateContext has correct shape", () => {
|
|
286
|
+
type Ctx = ServiceBuilderMutateContext<TestSchema, string, readonly [], {}>;
|
|
287
|
+
|
|
288
|
+
expectTypeOf<Ctx["uow"]>().toExtend<TypedUnitOfWork<TestSchema, [], unknown, {}>>();
|
|
289
|
+
expectTypeOf<Ctx["retrieveResult"]>().toEqualTypeOf<string>();
|
|
290
|
+
expectTypeOf<Ctx["serviceIntermediateResult"]>().toEqualTypeOf<readonly []>();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("BuilderTransformContextWithMutate has mutateResult defined", () => {
|
|
294
|
+
type Ctx = BuilderTransformContextWithMutate<
|
|
295
|
+
string,
|
|
296
|
+
{ id: string },
|
|
297
|
+
readonly [],
|
|
298
|
+
readonly []
|
|
299
|
+
>;
|
|
300
|
+
|
|
301
|
+
expectTypeOf<Ctx["retrieveResult"]>().toEqualTypeOf<string>();
|
|
302
|
+
expectTypeOf<Ctx["mutateResult"]>().toEqualTypeOf<{ id: string }>();
|
|
303
|
+
expectTypeOf<Ctx["serviceIntermediateResult"]>().toEqualTypeOf<readonly []>();
|
|
304
|
+
expectTypeOf<Ctx["serviceIntermediateResult"]>().toEqualTypeOf<readonly []>();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it("BuilderTransformContextWithoutMutate has mutateResult as undefined", () => {
|
|
308
|
+
type Ctx = BuilderTransformContextWithoutMutate<string, readonly [], readonly []>;
|
|
309
|
+
|
|
310
|
+
expectTypeOf<Ctx["retrieveResult"]>().toEqualTypeOf<string>();
|
|
311
|
+
expectTypeOf<Ctx["mutateResult"]>().toEqualTypeOf<undefined>();
|
|
312
|
+
expectTypeOf<Ctx["serviceIntermediateResult"]>().toEqualTypeOf<readonly []>();
|
|
313
|
+
expectTypeOf<Ctx["serviceIntermediateResult"]>().toEqualTypeOf<readonly []>();
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe("builder state tracking via type parameters", () => {
|
|
318
|
+
it("builder with HasRetrieve=true returns retrieve results when no other callbacks", () => {
|
|
319
|
+
type BuilderWithRetrieve = ServiceTxBuilder<
|
|
320
|
+
TestSchema,
|
|
321
|
+
readonly [],
|
|
322
|
+
[{ id: string }[]],
|
|
323
|
+
[{ id: string }[]], // same as retrieve since no transformRetrieve
|
|
324
|
+
unknown,
|
|
325
|
+
unknown,
|
|
326
|
+
true, // HasRetrieve = true
|
|
327
|
+
false,
|
|
328
|
+
false,
|
|
329
|
+
false,
|
|
330
|
+
{}
|
|
331
|
+
>;
|
|
332
|
+
|
|
333
|
+
type BuildResult = ReturnType<BuilderWithRetrieve["build"]>;
|
|
334
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<[{ id: string }[]]>();
|
|
335
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<[{ id: string }[]]>();
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it("builder with HasTransformRetrieve=true returns transformed result", () => {
|
|
339
|
+
type BuilderWithTransformRetrieve = ServiceTxBuilder<
|
|
340
|
+
TestSchema,
|
|
341
|
+
readonly [],
|
|
342
|
+
[{ id: string }[]],
|
|
343
|
+
{ id: string } | null, // transformed
|
|
344
|
+
unknown,
|
|
345
|
+
unknown,
|
|
346
|
+
true, // HasRetrieve
|
|
347
|
+
true, // HasTransformRetrieve = true
|
|
348
|
+
false,
|
|
349
|
+
false,
|
|
350
|
+
{}
|
|
351
|
+
>;
|
|
352
|
+
|
|
353
|
+
type BuildResult = ReturnType<BuilderWithTransformRetrieve["build"]>;
|
|
354
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<{ id: string } | null>();
|
|
355
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<{ id: string } | null>();
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it("builder with HasMutate=true returns mutate result", () => {
|
|
359
|
+
type BuilderWithMutate = ServiceTxBuilder<
|
|
360
|
+
TestSchema,
|
|
361
|
+
readonly [],
|
|
362
|
+
[{ id: string }[]],
|
|
363
|
+
[{ id: string }[]],
|
|
364
|
+
{ created: boolean }, // mutate result
|
|
365
|
+
unknown,
|
|
366
|
+
true,
|
|
367
|
+
false,
|
|
368
|
+
true, // HasMutate = true
|
|
369
|
+
false,
|
|
370
|
+
{}
|
|
371
|
+
>;
|
|
372
|
+
|
|
373
|
+
type BuildResult = ReturnType<BuilderWithMutate["build"]>;
|
|
374
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<{ created: boolean }>();
|
|
375
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<[{ id: string }[]]>();
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("builder with HasTransform=true returns transform result", () => {
|
|
379
|
+
type BuilderWithTransform = ServiceTxBuilder<
|
|
380
|
+
TestSchema,
|
|
381
|
+
readonly [],
|
|
382
|
+
[],
|
|
383
|
+
[],
|
|
384
|
+
{ orderId: string },
|
|
385
|
+
{ success: boolean }, // transform result
|
|
386
|
+
false,
|
|
387
|
+
false,
|
|
388
|
+
true,
|
|
389
|
+
true, // HasTransform = true
|
|
390
|
+
{}
|
|
391
|
+
>;
|
|
392
|
+
|
|
393
|
+
type BuildResult = ReturnType<BuilderWithTransform["build"]>;
|
|
394
|
+
expectTypeOf<TxResultFinalType<BuildResult>>().toEqualTypeOf<{ success: boolean }>();
|
|
395
|
+
// When HasMutate=true but no retrieve, the mutate result becomes the retrieve success result for dependents
|
|
396
|
+
expectTypeOf<TxResultRetrieveType<BuildResult>>().toEqualTypeOf<{ orderId: string }>();
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// =============================================================================
|
|
402
|
+
// HandlerTxBuilder Type Tests
|
|
403
|
+
// =============================================================================
|
|
404
|
+
|
|
405
|
+
describe("HandlerTxBuilder type inference", () => {
|
|
406
|
+
describe("return type priority", () => {
|
|
407
|
+
it("returns service final results when only withServiceCalls is set", () => {
|
|
408
|
+
type ServiceCall = TxResult<{ data: string }, { data: string }>;
|
|
409
|
+
|
|
410
|
+
type Builder = HandlerTxBuilder<
|
|
411
|
+
readonly [ServiceCall],
|
|
412
|
+
[],
|
|
413
|
+
[],
|
|
414
|
+
unknown,
|
|
415
|
+
unknown,
|
|
416
|
+
false,
|
|
417
|
+
false,
|
|
418
|
+
false,
|
|
419
|
+
false,
|
|
420
|
+
{}
|
|
421
|
+
>;
|
|
422
|
+
|
|
423
|
+
type ExecuteResult = ReturnType<Builder["execute"]>;
|
|
424
|
+
// execute() returns a Promise of the service final results
|
|
425
|
+
expectTypeOf<ExecuteResult>().toExtend<
|
|
426
|
+
Promise<AwaitedPromisesInObject<readonly [{ data: string }]>>
|
|
427
|
+
>();
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("returns mutate result when mutate is set", () => {
|
|
431
|
+
type Builder = HandlerTxBuilder<
|
|
432
|
+
readonly [],
|
|
433
|
+
[],
|
|
434
|
+
[],
|
|
435
|
+
{ orderId: string }, // mutate result
|
|
436
|
+
unknown,
|
|
437
|
+
false,
|
|
438
|
+
false,
|
|
439
|
+
true, // HasMutate
|
|
440
|
+
false,
|
|
441
|
+
{}
|
|
442
|
+
>;
|
|
443
|
+
|
|
444
|
+
type ExecuteResult = ReturnType<Builder["execute"]>;
|
|
445
|
+
expectTypeOf<ExecuteResult>().toExtend<Promise<{ orderId: string }>>();
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it("returns transform result when transform is set", () => {
|
|
449
|
+
type Builder = HandlerTxBuilder<
|
|
450
|
+
readonly [],
|
|
451
|
+
[],
|
|
452
|
+
[],
|
|
453
|
+
{ orderId: string },
|
|
454
|
+
{ success: true; orderId: string }, // transform result
|
|
455
|
+
false,
|
|
456
|
+
false,
|
|
457
|
+
true, // HasMutate
|
|
458
|
+
true, // HasTransform
|
|
459
|
+
{}
|
|
460
|
+
>;
|
|
461
|
+
|
|
462
|
+
type ExecuteResult = ReturnType<Builder["execute"]>;
|
|
463
|
+
expectTypeOf<ExecuteResult>().toExtend<Promise<{ success: true; orderId: string }>>();
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
describe("context field names", () => {
|
|
468
|
+
it("HandlerBuilderMutateContext has idempotencyKey and currentAttempt", () => {
|
|
469
|
+
type Ctx = HandlerBuilderMutateContext<[], readonly [], {}>;
|
|
470
|
+
|
|
471
|
+
expectTypeOf<Ctx["idempotencyKey"]>().toEqualTypeOf<string>();
|
|
472
|
+
expectTypeOf<Ctx["currentAttempt"]>().toEqualTypeOf<number>();
|
|
473
|
+
expectTypeOf<Ctx["forSchema"]>().toBeFunction();
|
|
474
|
+
// Check length property to verify empty tuple without array method comparison issues
|
|
475
|
+
expectTypeOf<Ctx["retrieveResult"]["length"]>().toEqualTypeOf<0>();
|
|
476
|
+
expectTypeOf<Ctx["serviceIntermediateResult"]["length"]>().toEqualTypeOf<0>();
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it("retrieve context in HandlerTxBuilder has correct type", () => {
|
|
480
|
+
type Builder = HandlerTxBuilder<
|
|
481
|
+
readonly [],
|
|
482
|
+
[],
|
|
483
|
+
[],
|
|
484
|
+
unknown,
|
|
485
|
+
unknown,
|
|
486
|
+
false,
|
|
487
|
+
false,
|
|
488
|
+
false,
|
|
489
|
+
false,
|
|
490
|
+
{}
|
|
491
|
+
>;
|
|
492
|
+
|
|
493
|
+
// Get the retrieve parameter type
|
|
494
|
+
type RetrieveParam = Parameters<Builder["retrieve"]>[0];
|
|
495
|
+
type RetrieveCtx = Parameters<RetrieveParam>[0];
|
|
496
|
+
|
|
497
|
+
expectTypeOf<RetrieveCtx["idempotencyKey"]>().toEqualTypeOf<string>();
|
|
498
|
+
expectTypeOf<RetrieveCtx["currentAttempt"]>().toEqualTypeOf<number>();
|
|
499
|
+
expectTypeOf<RetrieveCtx["forSchema"]>().toBeFunction();
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
it("transform context has serviceResult and serviceIntermediateResult", () => {
|
|
503
|
+
type ServiceCall = TxResult<{ finalData: string }, { retrieveData: string }>;
|
|
504
|
+
|
|
505
|
+
type Builder = HandlerTxBuilder<
|
|
506
|
+
readonly [ServiceCall],
|
|
507
|
+
[],
|
|
508
|
+
[],
|
|
509
|
+
unknown,
|
|
510
|
+
unknown,
|
|
511
|
+
false,
|
|
512
|
+
false,
|
|
513
|
+
false,
|
|
514
|
+
true, // HasTransform
|
|
515
|
+
{}
|
|
516
|
+
>;
|
|
517
|
+
|
|
518
|
+
type TransformParam = Parameters<Builder["transform"]>[0];
|
|
519
|
+
type TransformCtx = Parameters<TransformParam>[0];
|
|
520
|
+
|
|
521
|
+
expectTypeOf<TransformCtx["serviceResult"]>().toEqualTypeOf<
|
|
522
|
+
readonly [{ finalData: string }]
|
|
523
|
+
>();
|
|
524
|
+
expectTypeOf<TransformCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
525
|
+
readonly [{ retrieveData: string }]
|
|
526
|
+
>();
|
|
527
|
+
expectTypeOf<TransformCtx["mutateResult"]>().toEqualTypeOf<undefined>();
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
describe("withServiceCalls + mutate flow", () => {
|
|
532
|
+
it("serviceIntermediateResult is available in mutate", () => {
|
|
533
|
+
type ServiceCall = TxResult<number, { user: { id: string } }>;
|
|
534
|
+
|
|
535
|
+
type Builder = HandlerTxBuilder<
|
|
536
|
+
readonly [ServiceCall],
|
|
537
|
+
[],
|
|
538
|
+
[],
|
|
539
|
+
unknown,
|
|
540
|
+
unknown,
|
|
541
|
+
false,
|
|
542
|
+
false,
|
|
543
|
+
true, // HasMutate
|
|
544
|
+
false,
|
|
545
|
+
{}
|
|
546
|
+
>;
|
|
547
|
+
|
|
548
|
+
type MutateParam = Parameters<Builder["mutate"]>[0];
|
|
549
|
+
type MutateCtx = Parameters<MutateParam>[0];
|
|
550
|
+
|
|
551
|
+
expectTypeOf<MutateCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
552
|
+
readonly [{ user: { id: string } }]
|
|
553
|
+
>();
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
describe("retrieve + transformRetrieve flow", () => {
|
|
558
|
+
it("transformRetrieve receives raw retrieve results", () => {
|
|
559
|
+
type Builder = HandlerTxBuilder<
|
|
560
|
+
readonly [],
|
|
561
|
+
[{ id: string }, { id: string }], // retrieve results
|
|
562
|
+
[{ id: string }, { id: string }],
|
|
563
|
+
unknown,
|
|
564
|
+
unknown,
|
|
565
|
+
true, // HasRetrieve
|
|
566
|
+
false,
|
|
567
|
+
false,
|
|
568
|
+
false,
|
|
569
|
+
{}
|
|
570
|
+
>;
|
|
571
|
+
|
|
572
|
+
type TransformRetrieveParam = Parameters<Builder["transformRetrieve"]>[0];
|
|
573
|
+
|
|
574
|
+
// First param is the raw retrieve results
|
|
575
|
+
expectTypeOf<Parameters<TransformRetrieveParam>[0]>().toEqualTypeOf<
|
|
576
|
+
[{ id: string }, { id: string }]
|
|
577
|
+
>();
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
it("mutate receives transformed retrieve result when transformRetrieve is set", () => {
|
|
581
|
+
type Builder = HandlerTxBuilder<
|
|
582
|
+
readonly [],
|
|
583
|
+
[{ id: string }[]],
|
|
584
|
+
{ id: string } | null, // transformed
|
|
585
|
+
unknown,
|
|
586
|
+
unknown,
|
|
587
|
+
true, // HasRetrieve
|
|
588
|
+
true, // HasTransformRetrieve
|
|
589
|
+
true, // HasMutate
|
|
590
|
+
false,
|
|
591
|
+
{}
|
|
592
|
+
>;
|
|
593
|
+
|
|
594
|
+
type MutateParam = Parameters<Builder["mutate"]>[0];
|
|
595
|
+
type MutateCtx = Parameters<MutateParam>[0];
|
|
596
|
+
|
|
597
|
+
// retrieveResult is the transformed type
|
|
598
|
+
expectTypeOf<MutateCtx["retrieveResult"]>().toEqualTypeOf<{ id: string } | null>();
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
// =============================================================================
|
|
604
|
+
// Helper Type Tests
|
|
605
|
+
// =============================================================================
|
|
606
|
+
|
|
607
|
+
describe("Helper type utilities", () => {
|
|
608
|
+
describe("ExtractServiceRetrieveResults", () => {
|
|
609
|
+
it("extracts retrieve success results from TxResult tuple", () => {
|
|
610
|
+
type ServiceCalls = readonly [TxResult<number, string>, TxResult<boolean, { data: number }>];
|
|
611
|
+
|
|
612
|
+
type Result = ExtractServiceRetrieveResults<ServiceCalls>;
|
|
613
|
+
|
|
614
|
+
// Should extract the second type parameter (retrieve success result)
|
|
615
|
+
expectTypeOf<Result>().toEqualTypeOf<readonly [string, { data: number }]>();
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
it("handles undefined in service calls", () => {
|
|
619
|
+
type ServiceCalls = readonly [TxResult<number, string>, undefined];
|
|
620
|
+
|
|
621
|
+
type Result = ExtractServiceRetrieveResults<ServiceCalls>;
|
|
622
|
+
|
|
623
|
+
expectTypeOf<Result>().toEqualTypeOf<readonly [string, undefined]>();
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
it("handles empty service calls array", () => {
|
|
627
|
+
type ServiceCalls = readonly [];
|
|
628
|
+
|
|
629
|
+
type Result = ExtractServiceRetrieveResults<ServiceCalls>;
|
|
630
|
+
|
|
631
|
+
expectTypeOf<Result>().toEqualTypeOf<readonly []>();
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
describe("ExtractServiceFinalResults", () => {
|
|
636
|
+
it("extracts final results from TxResult tuple", () => {
|
|
637
|
+
type ServiceCalls = readonly [
|
|
638
|
+
TxResult<{ id: number }, string>,
|
|
639
|
+
TxResult<boolean, { data: number }>,
|
|
640
|
+
];
|
|
641
|
+
|
|
642
|
+
type Result = ExtractServiceFinalResults<ServiceCalls>;
|
|
643
|
+
|
|
644
|
+
// Should extract the first type parameter (final result)
|
|
645
|
+
expectTypeOf<Result>().toEqualTypeOf<readonly [{ id: number }, boolean]>();
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
it("handles undefined in service calls", () => {
|
|
649
|
+
type ServiceCalls = readonly [TxResult<number, string>, undefined];
|
|
650
|
+
|
|
651
|
+
type Result = ExtractServiceFinalResults<ServiceCalls>;
|
|
652
|
+
|
|
653
|
+
expectTypeOf<Result>().toEqualTypeOf<readonly [number, undefined]>();
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it("handles empty service calls array", () => {
|
|
657
|
+
type ServiceCalls = readonly [];
|
|
658
|
+
|
|
659
|
+
type Result = ExtractServiceFinalResults<ServiceCalls>;
|
|
660
|
+
|
|
661
|
+
expectTypeOf<Result>().toEqualTypeOf<readonly []>();
|
|
662
|
+
});
|
|
663
|
+
});
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
// =============================================================================
|
|
667
|
+
// Builder Method Parameter Type Tests
|
|
668
|
+
// =============================================================================
|
|
669
|
+
|
|
670
|
+
describe("ServiceTxBuilder method parameter types", () => {
|
|
671
|
+
// Test with an initial builder type
|
|
672
|
+
type InitialBuilder = ServiceTxBuilder<
|
|
673
|
+
TestSchema,
|
|
674
|
+
readonly [],
|
|
675
|
+
[],
|
|
676
|
+
[],
|
|
677
|
+
unknown,
|
|
678
|
+
unknown,
|
|
679
|
+
false,
|
|
680
|
+
false,
|
|
681
|
+
false,
|
|
682
|
+
false,
|
|
683
|
+
{}
|
|
684
|
+
>;
|
|
685
|
+
|
|
686
|
+
describe("retrieve() callback parameter", () => {
|
|
687
|
+
it("receives TypedUnitOfWork with correct schema", () => {
|
|
688
|
+
type RetrieveCallback = Parameters<InitialBuilder["retrieve"]>[0];
|
|
689
|
+
type UowParam = Parameters<RetrieveCallback>[0];
|
|
690
|
+
|
|
691
|
+
// The UoW should be typed for TestSchema
|
|
692
|
+
expectTypeOf<UowParam>().toExtend<TypedUnitOfWork<TestSchema, [], unknown, {}>>();
|
|
693
|
+
});
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
describe("transformRetrieve() callback parameters", () => {
|
|
697
|
+
// Builder with retrieve results set
|
|
698
|
+
type BuilderWithRetrieve = ServiceTxBuilder<
|
|
699
|
+
TestSchema,
|
|
700
|
+
readonly [],
|
|
701
|
+
[{ id: string; name: string }[]], // retrieve results
|
|
702
|
+
[{ id: string; name: string }[]], // same since no transformRetrieve yet
|
|
703
|
+
unknown,
|
|
704
|
+
unknown,
|
|
705
|
+
true, // HasRetrieve
|
|
706
|
+
false,
|
|
707
|
+
false,
|
|
708
|
+
false,
|
|
709
|
+
{}
|
|
710
|
+
>;
|
|
711
|
+
|
|
712
|
+
it("first param is raw retrieve results", () => {
|
|
713
|
+
type TransformRetrieveCallback = Parameters<BuilderWithRetrieve["transformRetrieve"]>[0];
|
|
714
|
+
type FirstParam = Parameters<TransformRetrieveCallback>[0];
|
|
715
|
+
|
|
716
|
+
expectTypeOf<FirstParam>().toEqualTypeOf<[{ id: string; name: string }[]]>();
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
it("second param is service retrieve results", () => {
|
|
720
|
+
// Builder with service calls
|
|
721
|
+
type BuilderWithServices = ServiceTxBuilder<
|
|
722
|
+
TestSchema,
|
|
723
|
+
readonly [TxResult<number, { userId: string }>, TxResult<boolean, { count: number }>],
|
|
724
|
+
[{ id: string }[]],
|
|
725
|
+
[{ id: string }[]],
|
|
726
|
+
unknown,
|
|
727
|
+
unknown,
|
|
728
|
+
true,
|
|
729
|
+
false,
|
|
730
|
+
false,
|
|
731
|
+
false,
|
|
732
|
+
{}
|
|
733
|
+
>;
|
|
734
|
+
|
|
735
|
+
type TransformRetrieveCallback = Parameters<BuilderWithServices["transformRetrieve"]>[0];
|
|
736
|
+
type SecondParam = Parameters<TransformRetrieveCallback>[1];
|
|
737
|
+
|
|
738
|
+
expectTypeOf<SecondParam>().toEqualTypeOf<readonly [{ userId: string }, { count: number }]>();
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
describe("mutate() context parameter", () => {
|
|
743
|
+
it("has uow typed for schema", () => {
|
|
744
|
+
type MutateCallback = Parameters<InitialBuilder["mutate"]>[0];
|
|
745
|
+
type MutateCtx = Parameters<MutateCallback>[0];
|
|
746
|
+
|
|
747
|
+
expectTypeOf<MutateCtx["uow"]>().toExtend<TypedUnitOfWork<TestSchema, [], unknown, {}>>();
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
it("has retrieveResult from retrieve results when no transformRetrieve", () => {
|
|
751
|
+
type BuilderWithRetrieve = ServiceTxBuilder<
|
|
752
|
+
TestSchema,
|
|
753
|
+
readonly [],
|
|
754
|
+
[{ id: string; name: string }[]],
|
|
755
|
+
[{ id: string; name: string }[]], // same as TRetrieveResults
|
|
756
|
+
unknown,
|
|
757
|
+
unknown,
|
|
758
|
+
true,
|
|
759
|
+
false, // no transformRetrieve
|
|
760
|
+
false,
|
|
761
|
+
false,
|
|
762
|
+
{}
|
|
763
|
+
>;
|
|
764
|
+
|
|
765
|
+
type MutateCallback = Parameters<BuilderWithRetrieve["mutate"]>[0];
|
|
766
|
+
type MutateCtx = Parameters<MutateCallback>[0];
|
|
767
|
+
|
|
768
|
+
expectTypeOf<MutateCtx["retrieveResult"]>().toEqualTypeOf<[{ id: string; name: string }[]]>();
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
it("has retrieveResult from transformRetrieve when set", () => {
|
|
772
|
+
type BuilderWithTransformRetrieve = ServiceTxBuilder<
|
|
773
|
+
TestSchema,
|
|
774
|
+
readonly [],
|
|
775
|
+
[{ id: string; name: string }[]],
|
|
776
|
+
{ user: { id: string } } | null, // transformed
|
|
777
|
+
unknown,
|
|
778
|
+
unknown,
|
|
779
|
+
true,
|
|
780
|
+
true, // has transformRetrieve
|
|
781
|
+
false,
|
|
782
|
+
false,
|
|
783
|
+
{}
|
|
784
|
+
>;
|
|
785
|
+
|
|
786
|
+
type MutateCallback = Parameters<BuilderWithTransformRetrieve["mutate"]>[0];
|
|
787
|
+
type MutateCtx = Parameters<MutateCallback>[0];
|
|
788
|
+
|
|
789
|
+
expectTypeOf<MutateCtx["retrieveResult"]>().toEqualTypeOf<{ user: { id: string } } | null>();
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
it("has serviceResult from service calls", () => {
|
|
793
|
+
type BuilderWithServices = ServiceTxBuilder<
|
|
794
|
+
TestSchema,
|
|
795
|
+
readonly [TxResult<string, { data: number[] }>],
|
|
796
|
+
[],
|
|
797
|
+
[],
|
|
798
|
+
unknown,
|
|
799
|
+
unknown,
|
|
800
|
+
false,
|
|
801
|
+
false,
|
|
802
|
+
false,
|
|
803
|
+
false,
|
|
804
|
+
{}
|
|
805
|
+
>;
|
|
806
|
+
|
|
807
|
+
type MutateCallback = Parameters<BuilderWithServices["mutate"]>[0];
|
|
808
|
+
type MutateCtx = Parameters<MutateCallback>[0];
|
|
809
|
+
|
|
810
|
+
expectTypeOf<MutateCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
811
|
+
readonly [{ data: number[] }]
|
|
812
|
+
>();
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
describe("transform() context parameter", () => {
|
|
817
|
+
it("has mutateResult when HasMutate=true", () => {
|
|
818
|
+
type BuilderWithMutate = ServiceTxBuilder<
|
|
819
|
+
TestSchema,
|
|
820
|
+
readonly [],
|
|
821
|
+
[{ id: string }[]],
|
|
822
|
+
[{ id: string }[]],
|
|
823
|
+
{ created: boolean }, // mutate result
|
|
824
|
+
unknown,
|
|
825
|
+
true,
|
|
826
|
+
false,
|
|
827
|
+
true, // HasMutate
|
|
828
|
+
false,
|
|
829
|
+
{}
|
|
830
|
+
>;
|
|
831
|
+
|
|
832
|
+
type TransformCallback = Parameters<BuilderWithMutate["transform"]>[0];
|
|
833
|
+
type TransformCtx = Parameters<TransformCallback>[0];
|
|
834
|
+
|
|
835
|
+
expectTypeOf<TransformCtx["mutateResult"]>().toEqualTypeOf<{ created: boolean }>();
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
it("has mutateResult as undefined when HasMutate=false", () => {
|
|
839
|
+
type BuilderWithoutMutate = ServiceTxBuilder<
|
|
840
|
+
TestSchema,
|
|
841
|
+
readonly [],
|
|
842
|
+
[{ id: string }[]],
|
|
843
|
+
[{ id: string }[]],
|
|
844
|
+
unknown,
|
|
845
|
+
unknown,
|
|
846
|
+
true,
|
|
847
|
+
false,
|
|
848
|
+
false, // HasMutate = false
|
|
849
|
+
false,
|
|
850
|
+
{}
|
|
851
|
+
>;
|
|
852
|
+
|
|
853
|
+
type TransformCallback = Parameters<BuilderWithoutMutate["transform"]>[0];
|
|
854
|
+
type TransformCtx = Parameters<TransformCallback>[0];
|
|
855
|
+
|
|
856
|
+
expectTypeOf<TransformCtx["mutateResult"]>().toEqualTypeOf<undefined>();
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
it("has serviceResult with final results and serviceIntermediateResult with retrieve results", () => {
|
|
860
|
+
type BuilderWithServices = ServiceTxBuilder<
|
|
861
|
+
TestSchema,
|
|
862
|
+
readonly [TxResult<{ finalValue: number }, { retrieveValue: string }>],
|
|
863
|
+
[],
|
|
864
|
+
[],
|
|
865
|
+
{ id: string },
|
|
866
|
+
unknown,
|
|
867
|
+
false,
|
|
868
|
+
false,
|
|
869
|
+
true,
|
|
870
|
+
false,
|
|
871
|
+
{}
|
|
872
|
+
>;
|
|
873
|
+
|
|
874
|
+
type TransformCallback = Parameters<BuilderWithServices["transform"]>[0];
|
|
875
|
+
type TransformCtx = Parameters<TransformCallback>[0];
|
|
876
|
+
|
|
877
|
+
// serviceResult has FINAL results
|
|
878
|
+
expectTypeOf<TransformCtx["serviceResult"]>().toEqualTypeOf<
|
|
879
|
+
readonly [{ finalValue: number }]
|
|
880
|
+
>();
|
|
881
|
+
// serviceIntermediateResult has RETRIEVE results
|
|
882
|
+
expectTypeOf<TransformCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
883
|
+
readonly [{ retrieveValue: string }]
|
|
884
|
+
>();
|
|
885
|
+
});
|
|
886
|
+
});
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
describe("HandlerTxBuilder method parameter types", () => {
|
|
890
|
+
type InitialBuilder = HandlerTxBuilder<
|
|
891
|
+
readonly [],
|
|
892
|
+
[],
|
|
893
|
+
[],
|
|
894
|
+
unknown,
|
|
895
|
+
unknown,
|
|
896
|
+
false,
|
|
897
|
+
false,
|
|
898
|
+
false,
|
|
899
|
+
false,
|
|
900
|
+
{}
|
|
901
|
+
>;
|
|
902
|
+
|
|
903
|
+
describe("retrieve() callback parameter", () => {
|
|
904
|
+
it("receives context with idempotencyKey and currentAttempt", () => {
|
|
905
|
+
type RetrieveCallback = Parameters<InitialBuilder["retrieve"]>[0];
|
|
906
|
+
type CtxParam = Parameters<RetrieveCallback>[0];
|
|
907
|
+
|
|
908
|
+
expectTypeOf<CtxParam["idempotencyKey"]>().toEqualTypeOf<string>();
|
|
909
|
+
expectTypeOf<CtxParam["currentAttempt"]>().toEqualTypeOf<number>();
|
|
910
|
+
expectTypeOf<CtxParam["forSchema"]>().toBeFunction();
|
|
911
|
+
});
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
describe("mutate() context parameter", () => {
|
|
915
|
+
it("has idempotencyKey, currentAttempt, and forSchema", () => {
|
|
916
|
+
type BuilderWithRetrieve = HandlerTxBuilder<
|
|
917
|
+
readonly [],
|
|
918
|
+
[{ id: string }[]],
|
|
919
|
+
[{ id: string }[]],
|
|
920
|
+
unknown,
|
|
921
|
+
unknown,
|
|
922
|
+
true,
|
|
923
|
+
false,
|
|
924
|
+
false,
|
|
925
|
+
false,
|
|
926
|
+
{}
|
|
927
|
+
>;
|
|
928
|
+
|
|
929
|
+
type MutateCallback = Parameters<BuilderWithRetrieve["mutate"]>[0];
|
|
930
|
+
type MutateCtx = Parameters<MutateCallback>[0];
|
|
931
|
+
|
|
932
|
+
expectTypeOf<MutateCtx["idempotencyKey"]>().toEqualTypeOf<string>();
|
|
933
|
+
expectTypeOf<MutateCtx["currentAttempt"]>().toEqualTypeOf<number>();
|
|
934
|
+
expectTypeOf<MutateCtx["forSchema"]>().toBeFunction();
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
it("has retrieveResult from retrieve", () => {
|
|
938
|
+
type BuilderWithRetrieve = HandlerTxBuilder<
|
|
939
|
+
readonly [],
|
|
940
|
+
[{ id: string }[]],
|
|
941
|
+
[{ id: string }[]],
|
|
942
|
+
unknown,
|
|
943
|
+
unknown,
|
|
944
|
+
true,
|
|
945
|
+
false,
|
|
946
|
+
false,
|
|
947
|
+
false,
|
|
948
|
+
{}
|
|
949
|
+
>;
|
|
950
|
+
|
|
951
|
+
type MutateCallback = Parameters<BuilderWithRetrieve["mutate"]>[0];
|
|
952
|
+
type MutateCtx = Parameters<MutateCallback>[0];
|
|
953
|
+
|
|
954
|
+
expectTypeOf<MutateCtx["retrieveResult"]>().toEqualTypeOf<[{ id: string }[]]>();
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
it("has serviceResult from service calls", () => {
|
|
958
|
+
type BuilderWithServices = HandlerTxBuilder<
|
|
959
|
+
readonly [TxResult<number, { user: { id: string } }>],
|
|
960
|
+
[],
|
|
961
|
+
[],
|
|
962
|
+
unknown,
|
|
963
|
+
unknown,
|
|
964
|
+
false,
|
|
965
|
+
false,
|
|
966
|
+
false,
|
|
967
|
+
false,
|
|
968
|
+
{}
|
|
969
|
+
>;
|
|
970
|
+
|
|
971
|
+
type MutateCallback = Parameters<BuilderWithServices["mutate"]>[0];
|
|
972
|
+
type MutateCtx = Parameters<MutateCallback>[0];
|
|
973
|
+
|
|
974
|
+
expectTypeOf<MutateCtx["serviceIntermediateResult"]>().toEqualTypeOf<
|
|
975
|
+
readonly [{ user: { id: string } }]
|
|
976
|
+
>();
|
|
977
|
+
});
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
describe("execute() return type", () => {
|
|
981
|
+
it("returns Promise of mutate result when HasMutate=true", () => {
|
|
982
|
+
type BuilderWithMutate = HandlerTxBuilder<
|
|
983
|
+
readonly [],
|
|
984
|
+
[],
|
|
985
|
+
[],
|
|
986
|
+
{ orderId: string; success: boolean }, // mutate result
|
|
987
|
+
unknown,
|
|
988
|
+
false,
|
|
989
|
+
false,
|
|
990
|
+
true, // HasMutate
|
|
991
|
+
false,
|
|
992
|
+
{}
|
|
993
|
+
>;
|
|
994
|
+
|
|
995
|
+
type ExecuteResult = ReturnType<BuilderWithMutate["execute"]>;
|
|
996
|
+
|
|
997
|
+
expectTypeOf<ExecuteResult>().toEqualTypeOf<Promise<{ orderId: string; success: boolean }>>();
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
it("returns Promise of transform result when HasTransform=true", () => {
|
|
1001
|
+
type BuilderWithTransform = HandlerTxBuilder<
|
|
1002
|
+
readonly [],
|
|
1003
|
+
[],
|
|
1004
|
+
[],
|
|
1005
|
+
{ orderId: string },
|
|
1006
|
+
{ success: true; order: { id: string } }, // transform result
|
|
1007
|
+
false,
|
|
1008
|
+
false,
|
|
1009
|
+
true,
|
|
1010
|
+
true, // HasTransform
|
|
1011
|
+
{}
|
|
1012
|
+
>;
|
|
1013
|
+
|
|
1014
|
+
type ExecuteResult = ReturnType<BuilderWithTransform["execute"]>;
|
|
1015
|
+
|
|
1016
|
+
expectTypeOf<ExecuteResult>().toEqualTypeOf<
|
|
1017
|
+
Promise<{ success: true; order: { id: string } }>
|
|
1018
|
+
>();
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
it("returns Promise of service final results when only withServiceCalls is set", () => {
|
|
1022
|
+
type BuilderWithServices = HandlerTxBuilder<
|
|
1023
|
+
readonly [TxResult<{ data: string }, unknown>, TxResult<number, unknown>],
|
|
1024
|
+
[],
|
|
1025
|
+
[],
|
|
1026
|
+
unknown,
|
|
1027
|
+
unknown,
|
|
1028
|
+
false,
|
|
1029
|
+
false,
|
|
1030
|
+
false,
|
|
1031
|
+
false,
|
|
1032
|
+
{}
|
|
1033
|
+
>;
|
|
1034
|
+
|
|
1035
|
+
type ExecuteResult = ReturnType<BuilderWithServices["execute"]>;
|
|
1036
|
+
|
|
1037
|
+
// Result is the awaited service final results tuple
|
|
1038
|
+
expectTypeOf<ExecuteResult>().toExtend<Promise<readonly [{ data: string }, number]>>();
|
|
1039
|
+
});
|
|
1040
|
+
});
|
|
1041
|
+
});
|