@fragno-dev/db 0.1.13 → 0.1.14
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 +48 -41
- package/CHANGELOG.md +6 -0
- package/dist/adapters/adapters.d.ts +13 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +2 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +6 -1
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +6 -4
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +49 -36
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
- package/dist/adapters/drizzle/shared.d.ts +14 -1
- package/dist/adapters/drizzle/shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +2 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +7 -2
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/kysely/kysely-query.js +5 -3
- package/dist/adapters/kysely/kysely-query.js.map +1 -1
- package/dist/adapters/kysely/kysely-shared.d.ts +11 -0
- package/dist/adapters/kysely/kysely-shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js +38 -9
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
- package/dist/bind-services.d.ts +7 -0
- package/dist/bind-services.d.ts.map +1 -0
- package/dist/bind-services.js +14 -0
- package/dist/bind-services.js.map +1 -0
- package/dist/fragment.d.ts +131 -12
- package/dist/fragment.d.ts.map +1 -1
- package/dist/fragment.js +107 -8
- package/dist/fragment.js.map +1 -1
- package/dist/mod.d.ts +4 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +3 -2
- package/dist/mod.js.map +1 -1
- package/dist/query/query.d.ts +2 -2
- package/dist/query/query.d.ts.map +1 -1
- package/dist/query/unit-of-work.d.ts +100 -15
- package/dist/query/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work.js +214 -7
- package/dist/query/unit-of-work.js.map +1 -1
- package/package.json +3 -3
- package/src/adapters/adapters.ts +14 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +6 -1
- package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +133 -5
- package/src/adapters/drizzle/drizzle-adapter.ts +16 -1
- package/src/adapters/drizzle/drizzle-query.ts +26 -15
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +57 -57
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +79 -39
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +2 -5
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +2 -2
- package/src/adapters/kysely/kysely-adapter.ts +16 -1
- package/src/adapters/kysely/kysely-query.ts +26 -15
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +43 -43
- package/src/adapters/kysely/kysely-uow-compiler.ts +50 -14
- package/src/adapters/kysely/kysely-uow-joins.test.ts +30 -30
- package/src/bind-services.test.ts +214 -0
- package/src/bind-services.ts +37 -0
- package/src/db-fragment.test.ts +800 -0
- package/src/fragment.ts +557 -28
- package/src/mod.ts +19 -0
- package/src/query/query.ts +2 -2
- package/src/query/unit-of-work-multi-schema.test.ts +64 -0
- package/src/query/unit-of-work-types.test.ts +13 -0
- package/src/query/unit-of-work.test.ts +5 -9
- package/src/query/unit-of-work.ts +511 -62
- package/src/uow-context-integration.test.ts +102 -0
- package/src/uow-context.test.ts +182 -0
- package/src/fragment.test.ts +0 -341
|
@@ -103,12 +103,12 @@ describe("kysely-uow-joins", () => {
|
|
|
103
103
|
|
|
104
104
|
// Helper to create UnitOfWork for testing
|
|
105
105
|
function createTestUOW(name?: string) {
|
|
106
|
-
const mockCompiler = createKyselyUOWCompiler(
|
|
106
|
+
const mockCompiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
107
107
|
const mockExecutor = {
|
|
108
108
|
executeRetrievalPhase: async () => [],
|
|
109
109
|
executeMutationPhase: async () => ({ success: true, createdInternalIds: [] }),
|
|
110
110
|
};
|
|
111
|
-
const mockDecoder: UOWDecoder
|
|
111
|
+
const mockDecoder: UOWDecoder = (rawResults, operations) => {
|
|
112
112
|
if (rawResults.length !== operations.length) {
|
|
113
113
|
throw new Error("rawResults and ops must have the same length");
|
|
114
114
|
}
|
|
@@ -127,7 +127,7 @@ describe("kysely-uow-joins", () => {
|
|
|
127
127
|
.join((jb) => jb.author()),
|
|
128
128
|
);
|
|
129
129
|
|
|
130
|
-
const compiler = createKyselyUOWCompiler(
|
|
130
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
131
131
|
const compiled = uow.compile(compiler);
|
|
132
132
|
|
|
133
133
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -147,7 +147,7 @@ describe("kysely-uow-joins", () => {
|
|
|
147
147
|
.join((jb) => jb.author((ab) => ab.select(["name", "email"]))),
|
|
148
148
|
);
|
|
149
149
|
|
|
150
|
-
const compiler = createKyselyUOWCompiler(
|
|
150
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
151
151
|
const compiled = uow.compile(compiler);
|
|
152
152
|
|
|
153
153
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -171,7 +171,7 @@ describe("kysely-uow-joins", () => {
|
|
|
171
171
|
),
|
|
172
172
|
);
|
|
173
173
|
|
|
174
|
-
const compiler = createKyselyUOWCompiler(
|
|
174
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
175
175
|
const compiled = uow.compile(compiler);
|
|
176
176
|
|
|
177
177
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -191,7 +191,7 @@ describe("kysely-uow-joins", () => {
|
|
|
191
191
|
.join((jb) => jb.inviter((ib) => ib.select(["name"]))),
|
|
192
192
|
);
|
|
193
193
|
|
|
194
|
-
const compiler = createKyselyUOWCompiler(
|
|
194
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
195
195
|
const compiled = uow.compile(compiler);
|
|
196
196
|
|
|
197
197
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -211,7 +211,7 @@ describe("kysely-uow-joins", () => {
|
|
|
211
211
|
.join((jb) => jb.post((pb) => pb.select(["title"])).author((ab) => ab.select(["name"]))),
|
|
212
212
|
);
|
|
213
213
|
|
|
214
|
-
const compiler = createKyselyUOWCompiler(
|
|
214
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
215
215
|
const compiled = uow.compile(compiler);
|
|
216
216
|
|
|
217
217
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -231,7 +231,7 @@ describe("kysely-uow-joins", () => {
|
|
|
231
231
|
.join((jb) => jb.post((pb) => pb.select(["title"])).tag((tb) => tb.select(["name"]))),
|
|
232
232
|
);
|
|
233
233
|
|
|
234
|
-
const compiler = createKyselyUOWCompiler(
|
|
234
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
235
235
|
const compiled = uow.compile(compiler);
|
|
236
236
|
|
|
237
237
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -261,7 +261,7 @@ describe("kysely-uow-joins", () => {
|
|
|
261
261
|
),
|
|
262
262
|
);
|
|
263
263
|
|
|
264
|
-
const compiler = createKyselyUOWCompiler(
|
|
264
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
265
265
|
const compiled = uow.compile(compiler);
|
|
266
266
|
|
|
267
267
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -281,7 +281,7 @@ describe("kysely-uow-joins", () => {
|
|
|
281
281
|
.join((jb) => jb.author((ab) => ab.select(["name"]).orderByIndex("idx_name", "asc"))),
|
|
282
282
|
);
|
|
283
283
|
|
|
284
|
-
const compiler = createKyselyUOWCompiler(
|
|
284
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
285
285
|
const compiled = uow.compile(compiler);
|
|
286
286
|
|
|
287
287
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -302,7 +302,7 @@ describe("kysely-uow-joins", () => {
|
|
|
302
302
|
.join((jb) => jb.author((ab) => ab.select(["name"]).pageSize(1))),
|
|
303
303
|
);
|
|
304
304
|
|
|
305
|
-
const compiler = createKyselyUOWCompiler(
|
|
305
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
306
306
|
const compiled = uow.compile(compiler);
|
|
307
307
|
|
|
308
308
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -330,7 +330,7 @@ describe("kysely-uow-joins", () => {
|
|
|
330
330
|
),
|
|
331
331
|
);
|
|
332
332
|
|
|
333
|
-
const compiler = createKyselyUOWCompiler(
|
|
333
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
334
334
|
const compiled = uow.compile(compiler);
|
|
335
335
|
|
|
336
336
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -353,7 +353,7 @@ describe("kysely-uow-joins", () => {
|
|
|
353
353
|
.join((jb) => jb.author((ab) => ab.select(["id", "name"]))),
|
|
354
354
|
);
|
|
355
355
|
|
|
356
|
-
const compiler = createKyselyUOWCompiler(
|
|
356
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
357
357
|
const compiled = uow.compile(compiler);
|
|
358
358
|
|
|
359
359
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -376,7 +376,7 @@ describe("kysely-uow-joins", () => {
|
|
|
376
376
|
.join((jb) => jb.author((ab) => ab.select(["id", "name"]))),
|
|
377
377
|
);
|
|
378
378
|
|
|
379
|
-
const compiler = createKyselyUOWCompiler(
|
|
379
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
380
380
|
const compiled = uow.compile(compiler);
|
|
381
381
|
|
|
382
382
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -401,7 +401,7 @@ describe("kysely-uow-joins", () => {
|
|
|
401
401
|
.join((jb) => jb.author((ab) => ab.select(["id"]))),
|
|
402
402
|
);
|
|
403
403
|
|
|
404
|
-
const compiler = createKyselyUOWCompiler(
|
|
404
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
405
405
|
const compiled = uow.compile(compiler);
|
|
406
406
|
|
|
407
407
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -423,7 +423,7 @@ describe("kysely-uow-joins", () => {
|
|
|
423
423
|
.join((jb) => jb.author((ab) => ab.select(["id", "name"]))),
|
|
424
424
|
);
|
|
425
425
|
|
|
426
|
-
const compiler = createKyselyUOWCompiler(
|
|
426
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
427
427
|
const compiled = uow.compile(compiler);
|
|
428
428
|
|
|
429
429
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -446,7 +446,7 @@ describe("kysely-uow-joins", () => {
|
|
|
446
446
|
.join((jb) => jb.author((ab) => ab.select(["name"]))),
|
|
447
447
|
);
|
|
448
448
|
|
|
449
|
-
const compiler = createKyselyUOWCompiler(
|
|
449
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
450
450
|
const compiled = uow.compile(compiler);
|
|
451
451
|
|
|
452
452
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -466,7 +466,7 @@ describe("kysely-uow-joins", () => {
|
|
|
466
466
|
const uow = createTestUOW();
|
|
467
467
|
uow.find("posts", (b) => b.whereIndex("primary").join((jb) => jb.author()));
|
|
468
468
|
|
|
469
|
-
const compiler = createKyselyUOWCompiler(
|
|
469
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
470
470
|
const compiled = uow.compile(compiler);
|
|
471
471
|
|
|
472
472
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -494,7 +494,7 @@ describe("kysely-uow-joins", () => {
|
|
|
494
494
|
),
|
|
495
495
|
);
|
|
496
496
|
|
|
497
|
-
const compiler = createKyselyUOWCompiler(
|
|
497
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
498
498
|
const compiled = uow.compile(compiler);
|
|
499
499
|
|
|
500
500
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -517,7 +517,7 @@ describe("kysely-uow-joins", () => {
|
|
|
517
517
|
),
|
|
518
518
|
);
|
|
519
519
|
|
|
520
|
-
const compiler = createKyselyUOWCompiler(
|
|
520
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
521
521
|
const compiled = uow.compile(compiler);
|
|
522
522
|
|
|
523
523
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -575,12 +575,12 @@ describe("kysely-uow-joins", () => {
|
|
|
575
575
|
});
|
|
576
576
|
|
|
577
577
|
function createCustomIdTestUOW() {
|
|
578
|
-
const mockCompiler = createKyselyUOWCompiler(
|
|
578
|
+
const mockCompiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
579
579
|
const mockExecutor = {
|
|
580
580
|
executeRetrievalPhase: async () => [],
|
|
581
581
|
executeMutationPhase: async () => ({ success: true, createdInternalIds: [] }),
|
|
582
582
|
};
|
|
583
|
-
const mockDecoder: UOWDecoder
|
|
583
|
+
const mockDecoder: UOWDecoder = (rawResults, operations) => {
|
|
584
584
|
if (rawResults.length !== operations.length) {
|
|
585
585
|
throw new Error("rawResults and ops must have the same length");
|
|
586
586
|
}
|
|
@@ -602,7 +602,7 @@ describe("kysely-uow-joins", () => {
|
|
|
602
602
|
),
|
|
603
603
|
);
|
|
604
604
|
|
|
605
|
-
const compiler = createKyselyUOWCompiler(
|
|
605
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
606
606
|
const compiled = uow.compile(compiler);
|
|
607
607
|
|
|
608
608
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -636,7 +636,7 @@ describe("kysely-uow-joins", () => {
|
|
|
636
636
|
),
|
|
637
637
|
);
|
|
638
638
|
|
|
639
|
-
const compiler = createKyselyUOWCompiler(
|
|
639
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
640
640
|
const compiled = uow.compile(compiler);
|
|
641
641
|
|
|
642
642
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -655,7 +655,7 @@ describe("kysely-uow-joins", () => {
|
|
|
655
655
|
const uow = createCustomIdTestUOW();
|
|
656
656
|
uow.find("product_categories", (b) => b.whereIndex("primary").join((jb) => jb.product()));
|
|
657
657
|
|
|
658
|
-
const compiler = createKyselyUOWCompiler(
|
|
658
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
659
659
|
const compiled = uow.compile(compiler);
|
|
660
660
|
|
|
661
661
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -685,7 +685,7 @@ describe("kysely-uow-joins", () => {
|
|
|
685
685
|
),
|
|
686
686
|
);
|
|
687
687
|
|
|
688
|
-
const compiler = createKyselyUOWCompiler(
|
|
688
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
689
689
|
const compiled = uow.compile(compiler);
|
|
690
690
|
|
|
691
691
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -717,7 +717,7 @@ describe("kysely-uow-joins", () => {
|
|
|
717
717
|
.join((jb) => jb.author((ab) => ab.select(["id"]))),
|
|
718
718
|
);
|
|
719
719
|
|
|
720
|
-
const compiler = createKyselyUOWCompiler(
|
|
720
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
721
721
|
const compiled = uow.compile(compiler);
|
|
722
722
|
|
|
723
723
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -741,7 +741,7 @@ describe("kysely-uow-joins", () => {
|
|
|
741
741
|
.join((jb) => jb.author((ab) => ab.select(["id", "name"]))),
|
|
742
742
|
);
|
|
743
743
|
|
|
744
|
-
const compiler = createKyselyUOWCompiler(
|
|
744
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
745
745
|
const compiled = uow.compile(compiler);
|
|
746
746
|
|
|
747
747
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -765,7 +765,7 @@ describe("kysely-uow-joins", () => {
|
|
|
765
765
|
.join((jb) => jb.post((pb) => pb.select(["id"])).author((ab) => ab.select(["id"]))),
|
|
766
766
|
);
|
|
767
767
|
|
|
768
|
-
const compiler = createKyselyUOWCompiler(
|
|
768
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
769
769
|
const compiled = uow.compile(compiler);
|
|
770
770
|
|
|
771
771
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -793,7 +793,7 @@ describe("kysely-uow-joins", () => {
|
|
|
793
793
|
.join((jb) => jb.inviter((ib) => ib.select(["id", "name"]))),
|
|
794
794
|
);
|
|
795
795
|
|
|
796
|
-
const compiler = createKyselyUOWCompiler(
|
|
796
|
+
const compiler = createKyselyUOWCompiler(pool, "postgresql");
|
|
797
797
|
const compiled = uow.compile(compiler);
|
|
798
798
|
|
|
799
799
|
expect(compiled.retrievalBatch).toHaveLength(1);
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { bindServicesToContext } from "./bind-services";
|
|
3
|
+
import { withUnitOfWork, type DatabaseRequestThisContext } from "./fragment";
|
|
4
|
+
import type { IUnitOfWorkBase } from "./query/unit-of-work";
|
|
5
|
+
import { schema, idColumn } from "./schema/create";
|
|
6
|
+
|
|
7
|
+
// Create a simple test schema for tests
|
|
8
|
+
const testSchema = schema((s) => {
|
|
9
|
+
return s.addTable("test", (t) => {
|
|
10
|
+
return t.addColumn("id", idColumn());
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe("bindServicesToContext", () => {
|
|
15
|
+
it("should bind simple function to context", async () => {
|
|
16
|
+
const mockSchemaView = { test: "schema-view" };
|
|
17
|
+
const mockUow = {
|
|
18
|
+
test: "uow",
|
|
19
|
+
forSchema: () => mockSchemaView,
|
|
20
|
+
} as unknown as IUnitOfWorkBase;
|
|
21
|
+
|
|
22
|
+
const services = {
|
|
23
|
+
testMethod: function (this: DatabaseRequestThisContext) {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
+
return this.getUnitOfWork(testSchema as any);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const bound = bindServicesToContext(services);
|
|
30
|
+
|
|
31
|
+
const result = await withUnitOfWork(mockUow, () => bound.testMethod());
|
|
32
|
+
|
|
33
|
+
expect(result).toBe(mockSchemaView);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should bind multiple functions", async () => {
|
|
37
|
+
const mockSchemaView = { test: "schema-view" };
|
|
38
|
+
const mockUow = {
|
|
39
|
+
test: "uow",
|
|
40
|
+
forSchema: () => mockSchemaView,
|
|
41
|
+
} as unknown as IUnitOfWorkBase;
|
|
42
|
+
|
|
43
|
+
const services = {
|
|
44
|
+
method1: function (this: DatabaseRequestThisContext) {
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
+
return this.getUnitOfWork(testSchema as any);
|
|
47
|
+
},
|
|
48
|
+
method2: function (this: DatabaseRequestThisContext) {
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
return this.getUnitOfWork(testSchema as any);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const bound = bindServicesToContext(services);
|
|
55
|
+
|
|
56
|
+
await withUnitOfWork(mockUow, () => {
|
|
57
|
+
expect(bound.method1()).toBe(mockSchemaView);
|
|
58
|
+
expect(bound.method2()).toBe(mockSchemaView);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should bind nested service objects", async () => {
|
|
63
|
+
const mockSchemaView = { test: "schema-view" };
|
|
64
|
+
const mockUow = {
|
|
65
|
+
test: "uow",
|
|
66
|
+
forSchema: () => mockSchemaView,
|
|
67
|
+
} as unknown as IUnitOfWorkBase;
|
|
68
|
+
|
|
69
|
+
const services = {
|
|
70
|
+
nested: {
|
|
71
|
+
method: function (this: DatabaseRequestThisContext) {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
return this.getUnitOfWork(testSchema as any);
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const bound = bindServicesToContext(services);
|
|
79
|
+
|
|
80
|
+
const result = await withUnitOfWork(mockUow, () => bound.nested.method());
|
|
81
|
+
|
|
82
|
+
expect(result).toBe(mockSchemaView);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should preserve non-function properties", () => {
|
|
86
|
+
const services = {
|
|
87
|
+
method: function () {
|
|
88
|
+
return "test";
|
|
89
|
+
},
|
|
90
|
+
constant: "value",
|
|
91
|
+
number: 42,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const bound = bindServicesToContext(services);
|
|
95
|
+
|
|
96
|
+
expect(bound.constant).toBe("value");
|
|
97
|
+
expect(bound.number).toBe(42);
|
|
98
|
+
expect(bound.method()).toBe("test");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should handle functions with parameters", async () => {
|
|
102
|
+
const mockSchemaView = { test: "schema-view" };
|
|
103
|
+
const mockUow = {
|
|
104
|
+
test: "uow",
|
|
105
|
+
forSchema: () => mockSchemaView,
|
|
106
|
+
} as unknown as IUnitOfWorkBase;
|
|
107
|
+
|
|
108
|
+
const services = {
|
|
109
|
+
testMethod: function (this: DatabaseRequestThisContext, param1: string, param2: number) {
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
|
+
const uow = this.getUnitOfWork(testSchema as any);
|
|
112
|
+
return { uow, param1, param2 };
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const bound = bindServicesToContext(services);
|
|
117
|
+
|
|
118
|
+
const result = await withUnitOfWork(mockUow, () => bound.testMethod("hello", 123));
|
|
119
|
+
|
|
120
|
+
expect(result.uow).toBe(mockSchemaView);
|
|
121
|
+
expect(result.param1).toBe("hello");
|
|
122
|
+
expect(result.param2).toBe(123);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should handle async functions", async () => {
|
|
126
|
+
const mockSchemaView = { test: "schema-view" };
|
|
127
|
+
const mockUow = {
|
|
128
|
+
test: "uow",
|
|
129
|
+
forSchema: () => mockSchemaView,
|
|
130
|
+
} as unknown as IUnitOfWorkBase;
|
|
131
|
+
|
|
132
|
+
const services = {
|
|
133
|
+
asyncMethod: async function (this: DatabaseRequestThisContext) {
|
|
134
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
136
|
+
return this.getUnitOfWork(testSchema as any);
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const bound = bindServicesToContext(services);
|
|
141
|
+
|
|
142
|
+
const result = await withUnitOfWork(mockUow, async () => await bound.asyncMethod());
|
|
143
|
+
|
|
144
|
+
expect(result).toBe(mockSchemaView);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should not bind arrays", () => {
|
|
148
|
+
const services = {
|
|
149
|
+
array: [1, 2, 3],
|
|
150
|
+
method: function () {
|
|
151
|
+
return "test";
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const bound = bindServicesToContext(services);
|
|
156
|
+
|
|
157
|
+
expect(bound.array).toEqual([1, 2, 3]);
|
|
158
|
+
expect(Array.isArray(bound.array)).toBe(true);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("should handle deeply nested objects", async () => {
|
|
162
|
+
const mockSchemaView = { test: "schema-view" };
|
|
163
|
+
const mockUow = {
|
|
164
|
+
test: "uow",
|
|
165
|
+
forSchema: () => mockSchemaView,
|
|
166
|
+
} as unknown as IUnitOfWorkBase;
|
|
167
|
+
|
|
168
|
+
const services = {
|
|
169
|
+
level1: {
|
|
170
|
+
level2: {
|
|
171
|
+
level3: {
|
|
172
|
+
method: function (this: DatabaseRequestThisContext) {
|
|
173
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
174
|
+
return this.getUnitOfWork(testSchema as any);
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const bound = bindServicesToContext(services);
|
|
182
|
+
|
|
183
|
+
const result = await withUnitOfWork(mockUow, () => bound.level1.level2.level3.method());
|
|
184
|
+
|
|
185
|
+
expect(result).toBe(mockSchemaView);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("should allow bound services to access UOW independently", async () => {
|
|
189
|
+
const mockSchemaView = { test: "schema-view" };
|
|
190
|
+
const mockUow = {
|
|
191
|
+
test: "uow",
|
|
192
|
+
forSchema: () => mockSchemaView,
|
|
193
|
+
} as unknown as IUnitOfWorkBase;
|
|
194
|
+
|
|
195
|
+
const services = {
|
|
196
|
+
getUow: function (this: DatabaseRequestThisContext) {
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
198
|
+
return this.getUnitOfWork(testSchema as any);
|
|
199
|
+
},
|
|
200
|
+
callOther: function (this: DatabaseRequestThisContext) {
|
|
201
|
+
// Both methods can access UOW via their own `this` context
|
|
202
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
203
|
+
return this.getUnitOfWork(testSchema as any);
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const bound = bindServicesToContext(services);
|
|
208
|
+
|
|
209
|
+
await withUnitOfWork(mockUow, () => {
|
|
210
|
+
expect(bound.getUow()).toBe(mockSchemaView);
|
|
211
|
+
expect(bound.callOther()).toBe(mockSchemaView);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { serviceContext } from "./fragment";
|
|
2
|
+
|
|
3
|
+
// Type helper to remove 'this' parameter from functions
|
|
4
|
+
type OmitThisParameter<T> = T extends (this: infer _This, ...args: infer A) => infer R
|
|
5
|
+
? (...args: A) => R
|
|
6
|
+
: T;
|
|
7
|
+
|
|
8
|
+
// Recursively remove 'this' parameter from all functions in an object
|
|
9
|
+
export type BoundServices<T> = {
|
|
10
|
+
[K in keyof T]: T[K] extends (...args: never[]) => unknown
|
|
11
|
+
? OmitThisParameter<T[K]>
|
|
12
|
+
: T[K] extends Record<string, unknown>
|
|
13
|
+
? BoundServices<T[K]>
|
|
14
|
+
: T[K];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function bindServicesToContext<T extends Record<string, unknown>>(
|
|
18
|
+
services: T,
|
|
19
|
+
): BoundServices<T> {
|
|
20
|
+
const bound = {} as BoundServices<T>;
|
|
21
|
+
|
|
22
|
+
for (const [key, value] of Object.entries(services)) {
|
|
23
|
+
if (typeof value === "function") {
|
|
24
|
+
// Bind function to serviceContext
|
|
25
|
+
bound[key as keyof T] = value.bind(serviceContext) as BoundServices<T>[keyof T];
|
|
26
|
+
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
27
|
+
// Recursively bind nested service objects
|
|
28
|
+
bound[key as keyof T] = bindServicesToContext(
|
|
29
|
+
value as Record<string, unknown>,
|
|
30
|
+
) as BoundServices<T>[keyof T];
|
|
31
|
+
} else {
|
|
32
|
+
bound[key as keyof T] = value as BoundServices<T>[keyof T];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return bound;
|
|
37
|
+
}
|