@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.
Files changed (62) hide show
  1. package/.turbo/turbo-build.log +34 -30
  2. package/CHANGELOG.md +49 -0
  3. package/dist/adapters/generic-sql/query/where-builder.js +1 -1
  4. package/dist/db-fragment-definition-builder.d.ts +31 -39
  5. package/dist/db-fragment-definition-builder.d.ts.map +1 -1
  6. package/dist/db-fragment-definition-builder.js +20 -16
  7. package/dist/db-fragment-definition-builder.js.map +1 -1
  8. package/dist/fragments/internal-fragment.d.ts +94 -8
  9. package/dist/fragments/internal-fragment.d.ts.map +1 -1
  10. package/dist/fragments/internal-fragment.js +56 -55
  11. package/dist/fragments/internal-fragment.js.map +1 -1
  12. package/dist/hooks/hooks.d.ts +5 -3
  13. package/dist/hooks/hooks.d.ts.map +1 -1
  14. package/dist/hooks/hooks.js +38 -37
  15. package/dist/hooks/hooks.js.map +1 -1
  16. package/dist/mod.d.ts +3 -3
  17. package/dist/mod.d.ts.map +1 -1
  18. package/dist/mod.js +4 -4
  19. package/dist/mod.js.map +1 -1
  20. package/dist/query/unit-of-work/execute-unit-of-work.d.ts +367 -80
  21. package/dist/query/unit-of-work/execute-unit-of-work.d.ts.map +1 -1
  22. package/dist/query/unit-of-work/execute-unit-of-work.js +448 -148
  23. package/dist/query/unit-of-work/execute-unit-of-work.js.map +1 -1
  24. package/dist/query/unit-of-work/unit-of-work.d.ts +35 -11
  25. package/dist/query/unit-of-work/unit-of-work.d.ts.map +1 -1
  26. package/dist/query/unit-of-work/unit-of-work.js +49 -19
  27. package/dist/query/unit-of-work/unit-of-work.js.map +1 -1
  28. package/dist/query/value-decoding.js +1 -1
  29. package/dist/schema/create.d.ts +2 -3
  30. package/dist/schema/create.d.ts.map +1 -1
  31. package/dist/schema/create.js +2 -5
  32. package/dist/schema/create.js.map +1 -1
  33. package/dist/schema/generate-id.d.ts +20 -0
  34. package/dist/schema/generate-id.d.ts.map +1 -0
  35. package/dist/schema/generate-id.js +28 -0
  36. package/dist/schema/generate-id.js.map +1 -0
  37. package/dist/sql-driver/dialects/durable-object-dialect.d.ts.map +1 -1
  38. package/package.json +3 -3
  39. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +1 -0
  40. package/src/adapters/drizzle/drizzle-adapter-sqlite3.test.ts +41 -25
  41. package/src/adapters/generic-sql/test/generic-drizzle-adapter-sqlite3.test.ts +39 -25
  42. package/src/db-fragment-definition-builder.test.ts +58 -42
  43. package/src/db-fragment-definition-builder.ts +78 -88
  44. package/src/db-fragment-instantiator.test.ts +64 -88
  45. package/src/db-fragment-integration.test.ts +292 -142
  46. package/src/fragments/internal-fragment.test.ts +272 -266
  47. package/src/fragments/internal-fragment.ts +155 -122
  48. package/src/hooks/hooks.test.ts +268 -264
  49. package/src/hooks/hooks.ts +74 -63
  50. package/src/mod.ts +14 -4
  51. package/src/query/unit-of-work/execute-unit-of-work.test.ts +1582 -998
  52. package/src/query/unit-of-work/execute-unit-of-work.ts +1746 -343
  53. package/src/query/unit-of-work/tx-builder.test.ts +1041 -0
  54. package/src/query/unit-of-work/unit-of-work-coordinator.test.ts +269 -21
  55. package/src/query/unit-of-work/unit-of-work.test.ts +64 -0
  56. package/src/query/unit-of-work/unit-of-work.ts +65 -30
  57. package/src/schema/create.ts +2 -5
  58. package/src/schema/generate-id.test.ts +57 -0
  59. package/src/schema/generate-id.ts +38 -0
  60. package/src/shared/config.ts +0 -10
  61. package/src/shared/connection-pool.ts +0 -24
  62. package/src/shared/prisma.ts +0 -45
@@ -53,33 +53,43 @@ describe("Hook System", () => {
53
53
  const hooks: HooksMap = {
54
54
  onTest: vi.fn(),
55
55
  };
56
+ const onSuccess = vi.fn();
57
+ const onBeforeMutate = vi.fn();
56
58
 
57
59
  await internalFragment.inContext(async function () {
58
- await this.uow(async ({ forSchema, executeMutate }) => {
59
- const uow = forSchema(internalSchema, hooks);
60
-
61
- // Trigger a hook
62
- uow.triggerHook("onTest", { data: "test" });
63
-
64
- // Prepare hook mutations
65
- prepareHookMutations(uow, {
66
- hooks,
67
- namespace,
68
- internalFragment,
69
- defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 5 }),
70
- });
71
-
72
- await executeMutate();
73
- });
60
+ await this.handlerTx({
61
+ onAfterMutate: onSuccess,
62
+ onBeforeMutate,
63
+ })
64
+ .mutate(({ forSchema }) => {
65
+ const uow = forSchema(internalSchema, hooks);
66
+
67
+ // Trigger a hook
68
+ uow.triggerHook("onTest", { data: "test" });
69
+
70
+ // Prepare hook mutations
71
+ prepareHookMutations(uow, {
72
+ hooks,
73
+ namespace,
74
+ internalFragment,
75
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 5 }),
76
+ });
77
+ })
78
+ .execute();
74
79
  });
75
80
 
81
+ // Verify callbacks were executed
82
+ expect(onSuccess).toHaveBeenCalledOnce();
83
+ expect(onBeforeMutate).toHaveBeenCalledOnce();
84
+
76
85
  // Verify hook was created
77
86
  const events = await internalFragment.inContext(async function () {
78
- return await this.uow(async ({ executeRetrieve }) => {
79
- const result = internalFragment.services.hookService.getPendingHookEvents(namespace);
80
- await executeRetrieve();
81
- return result;
82
- });
87
+ return await this.handlerTx()
88
+ .withServiceCalls(
89
+ () => [internalFragment.services.hookService.getPendingHookEvents(namespace)] as const,
90
+ )
91
+ .transform(({ serviceResult: [result] }) => result)
92
+ .execute();
83
93
  });
84
94
 
85
95
  expect(events).toHaveLength(1);
@@ -98,28 +108,29 @@ describe("Hook System", () => {
98
108
  };
99
109
 
100
110
  await internalFragment.inContext(async function () {
101
- await this.uow(async ({ forSchema, executeMutate }) => {
102
- const uow = forSchema(internalSchema, hooks);
103
-
104
- uow.triggerHook("onNoRetry", { data: "test" });
105
-
106
- prepareHookMutations(uow, {
107
- hooks,
108
- namespace,
109
- internalFragment,
110
- defaultRetryPolicy: new NoRetryPolicy(),
111
- });
112
-
113
- await executeMutate();
114
- });
111
+ await this.handlerTx()
112
+ .mutate(({ forSchema }) => {
113
+ const uow = forSchema(internalSchema, hooks);
114
+
115
+ uow.triggerHook("onNoRetry", { data: "test" });
116
+
117
+ prepareHookMutations(uow, {
118
+ hooks,
119
+ namespace,
120
+ internalFragment,
121
+ defaultRetryPolicy: new NoRetryPolicy(),
122
+ });
123
+ })
124
+ .execute();
115
125
  });
116
126
 
117
127
  const events = await internalFragment.inContext(async function () {
118
- return await this.uow(async ({ executeRetrieve }) => {
119
- const result = internalFragment.services.hookService.getPendingHookEvents(namespace);
120
- await executeRetrieve();
121
- return result;
122
- });
128
+ return await this.handlerTx()
129
+ .withServiceCalls(
130
+ () => [internalFragment.services.hookService.getPendingHookEvents(namespace)] as const,
131
+ )
132
+ .transform(({ serviceResult: [result] }) => result)
133
+ .execute();
123
134
  });
124
135
 
125
136
  expect(events).toHaveLength(1);
@@ -133,34 +144,35 @@ describe("Hook System", () => {
133
144
  };
134
145
 
135
146
  await internalFragment.inContext(async function () {
136
- await this.uow(async ({ forSchema, executeMutate }) => {
137
- const uow = forSchema(internalSchema, hooks);
138
-
139
- uow.triggerHook(
140
- "onCustomRetry",
141
- { data: "test" },
142
- {
143
- retryPolicy: new NoRetryPolicy(),
144
- },
145
- );
146
-
147
- prepareHookMutations(uow, {
148
- hooks,
149
- namespace,
150
- internalFragment,
151
- defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 10 }),
152
- });
153
-
154
- await executeMutate();
155
- });
147
+ await this.handlerTx()
148
+ .mutate(({ forSchema }) => {
149
+ const uow = forSchema(internalSchema, hooks);
150
+
151
+ uow.triggerHook(
152
+ "onCustomRetry",
153
+ { data: "test" },
154
+ {
155
+ retryPolicy: new NoRetryPolicy(),
156
+ },
157
+ );
158
+
159
+ prepareHookMutations(uow, {
160
+ hooks,
161
+ namespace,
162
+ internalFragment,
163
+ defaultRetryPolicy: new ExponentialBackoffRetryPolicy({ maxRetries: 10 }),
164
+ });
165
+ })
166
+ .execute();
156
167
  });
157
168
 
158
169
  const events = await internalFragment.inContext(async function () {
159
- return await this.uow(async ({ executeRetrieve }) => {
160
- const result = internalFragment.services.hookService.getPendingHookEvents(namespace);
161
- await executeRetrieve();
162
- return result;
163
- });
170
+ return await this.handlerTx()
171
+ .withServiceCalls(
172
+ () => [internalFragment.services.hookService.getPendingHookEvents(namespace)] as const,
173
+ )
174
+ .transform(({ serviceResult: [result] }) => result)
175
+ .execute();
164
176
  });
165
177
 
166
178
  expect(events[0]?.maxAttempts).toBe(1);
@@ -179,22 +191,24 @@ describe("Hook System", () => {
179
191
 
180
192
  // Create a pending hook event
181
193
  await internalFragment.inContext(async function () {
182
- await this.uow(async ({ forSchema, executeMutate }) => {
183
- const uow = forSchema(internalSchema);
184
- eventId = uow.create("fragno_hooks", {
185
- namespace,
186
- hookName: "onSuccess",
187
- payload: { email: "test@example.com" },
188
- status: "pending",
189
- attempts: 0,
190
- maxAttempts: 5,
191
- lastAttemptAt: null,
192
- nextRetryAt: null,
193
- error: null,
194
- nonce: "test-nonce",
195
- });
196
- await executeMutate();
197
- });
194
+ const createdId = await this.handlerTx()
195
+ .mutate(({ forSchema }) => {
196
+ const uow = forSchema(internalSchema);
197
+ return uow.create("fragno_hooks", {
198
+ namespace,
199
+ hookName: "onSuccess",
200
+ payload: { email: "test@example.com" },
201
+ status: "pending",
202
+ attempts: 0,
203
+ maxAttempts: 5,
204
+ lastAttemptAt: null,
205
+ nextRetryAt: null,
206
+ error: null,
207
+ nonce: "test-nonce",
208
+ });
209
+ })
210
+ .execute();
211
+ eventId = createdId;
198
212
  });
199
213
 
200
214
  // Process hooks
@@ -211,19 +225,16 @@ describe("Hook System", () => {
211
225
 
212
226
  // Verify hook context (this)
213
227
  const hookContext = hookFn.mock.contexts[0] as HookContext;
214
- expect(hookContext.nonce).toBe("test-nonce");
228
+ expect(hookContext.idempotencyKey).toBe("test-nonce");
215
229
 
216
230
  // Verify event was marked as completed
217
231
  const result = await internalFragment.inContext(async function () {
218
- return await this.uow(async ({ forSchema, executeRetrieve }) => {
219
- const uow = forSchema(internalSchema);
220
- const findUow = uow.find("fragno_hooks", (b) =>
221
- b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
222
- );
223
- await executeRetrieve();
224
- const [events] = await findUow.retrievalPhase;
225
- return events?.[0];
226
- });
232
+ return await this.handlerTx()
233
+ .withServiceCalls(
234
+ () => [internalFragment.services.hookService.getHookById(eventId)] as const,
235
+ )
236
+ .transform(({ serviceResult: [event] }) => event)
237
+ .execute();
227
238
  });
228
239
 
229
240
  expect(result?.status).toBe("completed");
@@ -240,22 +251,24 @@ describe("Hook System", () => {
240
251
  let eventId: FragnoId;
241
252
 
242
253
  await internalFragment.inContext(async function () {
243
- await this.uow(async ({ forSchema, executeMutate }) => {
244
- const uow = forSchema(internalSchema);
245
- eventId = uow.create("fragno_hooks", {
246
- namespace,
247
- hookName: "onFailure",
248
- payload: { data: "test" },
249
- status: "pending",
250
- attempts: 0,
251
- maxAttempts: 5,
252
- lastAttemptAt: null,
253
- nextRetryAt: null,
254
- error: null,
255
- nonce: "test-nonce",
256
- });
257
- await executeMutate();
258
- });
254
+ const createdId = await this.handlerTx()
255
+ .mutate(({ forSchema }) => {
256
+ const uow = forSchema(internalSchema);
257
+ return uow.create("fragno_hooks", {
258
+ namespace,
259
+ hookName: "onFailure",
260
+ payload: { data: "test" },
261
+ status: "pending",
262
+ attempts: 0,
263
+ maxAttempts: 5,
264
+ lastAttemptAt: null,
265
+ nextRetryAt: null,
266
+ error: null,
267
+ nonce: "test-nonce",
268
+ });
269
+ })
270
+ .execute();
271
+ eventId = createdId;
259
272
  });
260
273
 
261
274
  await processHooks({
@@ -268,15 +281,12 @@ describe("Hook System", () => {
268
281
  expect(hookFn).toHaveBeenCalledOnce();
269
282
 
270
283
  const result = await internalFragment.inContext(async function () {
271
- return await this.uow(async ({ forSchema, executeRetrieve }) => {
272
- const uow = forSchema(internalSchema);
273
- const findUow = uow.find("fragno_hooks", (b) =>
274
- b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
275
- );
276
- await executeRetrieve();
277
- const [events] = await findUow.retrievalPhase;
278
- return events?.[0];
279
- });
284
+ return await this.handlerTx()
285
+ .withServiceCalls(
286
+ () => [internalFragment.services.hookService.getHookById(eventId)] as const,
287
+ )
288
+ .transform(({ serviceResult: [event] }) => event)
289
+ .execute();
280
290
  });
281
291
 
282
292
  expect(result?.status).toBe("pending");
@@ -295,22 +305,24 @@ describe("Hook System", () => {
295
305
  let eventId: FragnoId;
296
306
 
297
307
  await internalFragment.inContext(async function () {
298
- await this.uow(async ({ forSchema, executeMutate }) => {
299
- const uow = forSchema(internalSchema);
300
- eventId = uow.create("fragno_hooks", {
301
- namespace,
302
- hookName: "onMaxRetries",
303
- payload: { data: "test" },
304
- status: "pending",
305
- attempts: 0,
306
- maxAttempts: 1,
307
- lastAttemptAt: null,
308
- nextRetryAt: null,
309
- error: null,
310
- nonce: "test-nonce",
311
- });
312
- await executeMutate();
313
- });
308
+ const createdId = await this.handlerTx()
309
+ .mutate(({ forSchema }) => {
310
+ const uow = forSchema(internalSchema);
311
+ return uow.create("fragno_hooks", {
312
+ namespace,
313
+ hookName: "onMaxRetries",
314
+ payload: { data: "test" },
315
+ status: "pending",
316
+ attempts: 0,
317
+ maxAttempts: 1,
318
+ lastAttemptAt: null,
319
+ nextRetryAt: null,
320
+ error: null,
321
+ nonce: "test-nonce",
322
+ });
323
+ })
324
+ .execute();
325
+ eventId = createdId;
314
326
  });
315
327
 
316
328
  await processHooks({
@@ -321,15 +333,12 @@ describe("Hook System", () => {
321
333
  });
322
334
 
323
335
  const result = await internalFragment.inContext(async function () {
324
- return await this.uow(async ({ forSchema, executeRetrieve }) => {
325
- const uow = forSchema(internalSchema);
326
- const findUow = uow.find("fragno_hooks", (b) =>
327
- b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
328
- );
329
- await executeRetrieve();
330
- const [events] = await findUow.retrievalPhase;
331
- return events?.[0];
332
- });
336
+ return await this.handlerTx()
337
+ .withServiceCalls(
338
+ () => [internalFragment.services.hookService.getHookById(eventId)] as const,
339
+ )
340
+ .transform(({ serviceResult: [event] }) => event)
341
+ .execute();
333
342
  });
334
343
 
335
344
  expect(result?.status).toBe("failed");
@@ -346,22 +355,24 @@ describe("Hook System", () => {
346
355
  let eventId: FragnoId;
347
356
 
348
357
  await internalFragment.inContext(async function () {
349
- await this.uow(async ({ forSchema, executeMutate }) => {
350
- const uow = forSchema(internalSchema);
351
- eventId = uow.create("fragno_hooks", {
352
- namespace,
353
- hookName: "onMissing",
354
- payload: { data: "test" },
355
- status: "pending",
356
- attempts: 0,
357
- maxAttempts: 1,
358
- lastAttemptAt: null,
359
- nextRetryAt: null,
360
- error: null,
361
- nonce: "test-nonce",
362
- });
363
- await executeMutate();
364
- });
358
+ const createdId = await this.handlerTx()
359
+ .mutate(({ forSchema }) => {
360
+ const uow = forSchema(internalSchema);
361
+ return uow.create("fragno_hooks", {
362
+ namespace,
363
+ hookName: "onMissing",
364
+ payload: { data: "test" },
365
+ status: "pending",
366
+ attempts: 0,
367
+ maxAttempts: 1,
368
+ lastAttemptAt: null,
369
+ nextRetryAt: null,
370
+ error: null,
371
+ nonce: "test-nonce",
372
+ });
373
+ })
374
+ .execute();
375
+ eventId = createdId;
365
376
  });
366
377
 
367
378
  await processHooks({
@@ -372,15 +383,12 @@ describe("Hook System", () => {
372
383
  });
373
384
 
374
385
  const result = await internalFragment.inContext(async function () {
375
- return await this.uow(async ({ forSchema, executeRetrieve }) => {
376
- const uow = forSchema(internalSchema);
377
- const findUow = uow.find("fragno_hooks", (b) =>
378
- b.whereIndex("primary", (eb) => eb("id", "=", eventId)),
379
- );
380
- await executeRetrieve();
381
- const [events] = await findUow.retrievalPhase;
382
- return events?.[0];
383
- });
386
+ return await this.handlerTx()
387
+ .withServiceCalls(
388
+ () => [internalFragment.services.hookService.getHookById(eventId)] as const,
389
+ )
390
+ .transform(({ serviceResult: [event] }) => event)
391
+ .execute();
384
392
  });
385
393
 
386
394
  expect(result?.status).toBe("failed");
@@ -399,46 +407,47 @@ describe("Hook System", () => {
399
407
  };
400
408
 
401
409
  await internalFragment.inContext(async function () {
402
- await this.uow(async ({ forSchema, executeMutate }) => {
403
- const uow = forSchema(internalSchema);
404
- uow.create("fragno_hooks", {
405
- namespace,
406
- hookName: "onHook1",
407
- payload: { id: 1 },
408
- status: "pending",
409
- attempts: 0,
410
- maxAttempts: 5,
411
- lastAttemptAt: null,
412
- nextRetryAt: null,
413
- error: null,
414
- nonce: "nonce-1",
415
- });
416
- uow.create("fragno_hooks", {
417
- namespace,
418
- hookName: "onHook2",
419
- payload: { id: 2 },
420
- status: "pending",
421
- attempts: 0,
422
- maxAttempts: 5,
423
- lastAttemptAt: null,
424
- nextRetryAt: null,
425
- error: null,
426
- nonce: "nonce-2",
427
- });
428
- uow.create("fragno_hooks", {
429
- namespace,
430
- hookName: "onHook3",
431
- payload: { id: 3 },
432
- status: "pending",
433
- attempts: 0,
434
- maxAttempts: 5,
435
- lastAttemptAt: null,
436
- nextRetryAt: null,
437
- error: null,
438
- nonce: "nonce-3",
439
- });
440
- await executeMutate();
441
- });
410
+ await this.handlerTx()
411
+ .mutate(({ forSchema }) => {
412
+ const uow = forSchema(internalSchema);
413
+ uow.create("fragno_hooks", {
414
+ namespace,
415
+ hookName: "onHook1",
416
+ payload: { id: 1 },
417
+ status: "pending",
418
+ attempts: 0,
419
+ maxAttempts: 5,
420
+ lastAttemptAt: null,
421
+ nextRetryAt: null,
422
+ error: null,
423
+ nonce: "nonce-1",
424
+ });
425
+ uow.create("fragno_hooks", {
426
+ namespace,
427
+ hookName: "onHook2",
428
+ payload: { id: 2 },
429
+ status: "pending",
430
+ attempts: 0,
431
+ maxAttempts: 5,
432
+ lastAttemptAt: null,
433
+ nextRetryAt: null,
434
+ error: null,
435
+ nonce: "nonce-2",
436
+ });
437
+ uow.create("fragno_hooks", {
438
+ namespace,
439
+ hookName: "onHook3",
440
+ payload: { id: 3 },
441
+ status: "pending",
442
+ attempts: 0,
443
+ maxAttempts: 5,
444
+ lastAttemptAt: null,
445
+ nextRetryAt: null,
446
+ error: null,
447
+ nonce: "nonce-3",
448
+ });
449
+ })
450
+ .execute();
442
451
  });
443
452
 
444
453
  await processHooks({
@@ -454,15 +463,12 @@ describe("Hook System", () => {
454
463
 
455
464
  // Verify all were marked as completed
456
465
  const events = await internalFragment.inContext(async function () {
457
- return await this.uow(async ({ forSchema, executeRetrieve }) => {
458
- const uow = forSchema(internalSchema);
459
- const findUow = uow.find("fragno_hooks", (b) =>
460
- b.whereIndex("idx_namespace_status_retry", (eb) => eb("namespace", "=", namespace)),
461
- );
462
- await executeRetrieve();
463
- const [results] = await findUow.retrievalPhase;
464
- return results;
465
- });
466
+ return await this.handlerTx()
467
+ .withServiceCalls(
468
+ () => [internalFragment.services.hookService.getHooksByNamespace(namespace)] as const,
469
+ )
470
+ .transform(({ serviceResult: [result] }) => result)
471
+ .execute();
466
472
  });
467
473
 
468
474
  const completed = events.filter((e) => e.status === "completed");
@@ -481,46 +487,47 @@ describe("Hook System", () => {
481
487
  };
482
488
 
483
489
  await internalFragment.inContext(async function () {
484
- await this.uow(async ({ forSchema, executeMutate }) => {
485
- const uow = forSchema(internalSchema);
486
- uow.create("fragno_hooks", {
487
- namespace,
488
- hookName: "onHook1",
489
- payload: { id: 1 },
490
- status: "pending",
491
- attempts: 0,
492
- maxAttempts: 5,
493
- lastAttemptAt: null,
494
- nextRetryAt: null,
495
- error: null,
496
- nonce: "nonce-1",
497
- });
498
- uow.create("fragno_hooks", {
499
- namespace,
500
- hookName: "onHook2",
501
- payload: { id: 2 },
502
- status: "pending",
503
- attempts: 0,
504
- maxAttempts: 5,
505
- lastAttemptAt: null,
506
- nextRetryAt: null,
507
- error: null,
508
- nonce: "nonce-2",
509
- });
510
- uow.create("fragno_hooks", {
511
- namespace,
512
- hookName: "onHook3",
513
- payload: { id: 3 },
514
- status: "pending",
515
- attempts: 0,
516
- maxAttempts: 5,
517
- lastAttemptAt: null,
518
- nextRetryAt: null,
519
- error: null,
520
- nonce: "nonce-3",
521
- });
522
- await executeMutate();
523
- });
490
+ await this.handlerTx()
491
+ .mutate(({ forSchema }) => {
492
+ const uow = forSchema(internalSchema);
493
+ uow.create("fragno_hooks", {
494
+ namespace,
495
+ hookName: "onHook1",
496
+ payload: { id: 1 },
497
+ status: "pending",
498
+ attempts: 0,
499
+ maxAttempts: 5,
500
+ lastAttemptAt: null,
501
+ nextRetryAt: null,
502
+ error: null,
503
+ nonce: "nonce-1",
504
+ });
505
+ uow.create("fragno_hooks", {
506
+ namespace,
507
+ hookName: "onHook2",
508
+ payload: { id: 2 },
509
+ status: "pending",
510
+ attempts: 0,
511
+ maxAttempts: 5,
512
+ lastAttemptAt: null,
513
+ nextRetryAt: null,
514
+ error: null,
515
+ nonce: "nonce-2",
516
+ });
517
+ uow.create("fragno_hooks", {
518
+ namespace,
519
+ hookName: "onHook3",
520
+ payload: { id: 3 },
521
+ status: "pending",
522
+ attempts: 0,
523
+ maxAttempts: 5,
524
+ lastAttemptAt: null,
525
+ nextRetryAt: null,
526
+ error: null,
527
+ nonce: "nonce-3",
528
+ });
529
+ })
530
+ .execute();
524
531
  });
525
532
 
526
533
  await processHooks({
@@ -536,15 +543,12 @@ describe("Hook System", () => {
536
543
 
537
544
  // Verify hook1 and hook3 were completed, hook2 was marked for retry
538
545
  const events = await internalFragment.inContext(async function () {
539
- return await this.uow(async ({ forSchema, executeRetrieve }) => {
540
- const uow = forSchema(internalSchema);
541
- const findUow = uow.find("fragno_hooks", (b) =>
542
- b.whereIndex("idx_namespace_status_retry", (eb) => eb("namespace", "=", namespace)),
543
- );
544
- await executeRetrieve();
545
- const [results] = await findUow.retrievalPhase;
546
- return results;
547
- });
546
+ return await this.handlerTx()
547
+ .withServiceCalls(
548
+ () => [internalFragment.services.hookService.getHooksByNamespace(namespace)] as const,
549
+ )
550
+ .transform(({ serviceResult: [result] }) => result)
551
+ .execute();
548
552
  });
549
553
 
550
554
  const completed = events.filter((e) => e.status === "completed");