@roc-db/test-utils 0.2.0-pre.102 → 0.2.0-pre.103
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/dist/index.js +497 -117
- package/dist/types/entities/BlockParagraph.d.ts +1 -0
- package/dist/types/entities/index.d.ts +1 -0
- package/dist/types/operations/deleteUnmentionedBlockParagraph.d.ts +5 -0
- package/dist/types/operations/duplicateBlockParagraph.d.ts +4 -0
- package/dist/types/operations/updateBlockParagraphMentions.d.ts +9 -0
- package/dist/types/schemas/BlockParagraphSchema.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,7 +21,8 @@ import { entitySchemaGenerator as entitySchemaGenerator2 } from "roc-db";
|
|
|
21
21
|
import { z as z2 } from "zod";
|
|
22
22
|
var BlockParagraphSchema = entitySchemaGenerator2("BlockParagraph", {
|
|
23
23
|
data: z2.object({
|
|
24
|
-
content: z2.string().optional()
|
|
24
|
+
content: z2.string().optional(),
|
|
25
|
+
mentions: z2.array(z2.string()).optional()
|
|
25
26
|
}),
|
|
26
27
|
parents: z2.object({
|
|
27
28
|
parent: PostRefSchema
|
|
@@ -168,7 +169,8 @@ var BlockRefSchema = z13.union([
|
|
|
168
169
|
// src/entities/BlockParagraph.ts
|
|
169
170
|
var BlockParagraph = new Entity4("BlockParagraph", {
|
|
170
171
|
data: z14.object({
|
|
171
|
-
content: z14.string().optional()
|
|
172
|
+
content: z14.string().optional(),
|
|
173
|
+
mentions: z14.array(z14.string()).optional()
|
|
172
174
|
}),
|
|
173
175
|
parents: z14.object({
|
|
174
176
|
parent: z14.union([PostEntity.refSchema, BlockRefSchema])
|
|
@@ -440,29 +442,62 @@ var deleteDraft = writeOperation13("deleteDraft", DraftRefSchema, (txn) => {
|
|
|
440
442
|
return QueryChain6(Query13(() => txn.deleteEntity(ref, true)), Query13(() => txn.deleteChangeSet(ref)));
|
|
441
443
|
});
|
|
442
444
|
|
|
443
|
-
// src/operations/
|
|
444
|
-
import { Query as Query14, writeOperation as writeOperation14 } from "roc-db";
|
|
445
|
+
// src/operations/deleteUnmentionedBlockParagraph.ts
|
|
446
|
+
import { BadRequestError, Query as Query14, QueryChain as QueryChain7, writeOperation as writeOperation14 } from "roc-db";
|
|
445
447
|
import { z as z30 } from "zod";
|
|
446
|
-
var
|
|
448
|
+
var deleteUnmentionedBlockParagraph = writeOperation14("deleteUnmentionedBlockParagraph", z30.object({
|
|
449
|
+
ref: BlockParagraphRefSchema,
|
|
450
|
+
mentionedByRef: BlockParagraphRefSchema
|
|
451
|
+
}).strict(), (txn) => {
|
|
452
|
+
const { ref, mentionedByRef } = txn.payload;
|
|
453
|
+
return QueryChain7(Query14(() => txn.readEntity(mentionedByRef)), Query14((mentionedBy) => {
|
|
454
|
+
if (mentionedBy.data.mentions?.includes(ref)) {
|
|
455
|
+
throw new BadRequestError("Delete not allowed. Paragraph is mentioned");
|
|
456
|
+
}
|
|
457
|
+
return txn.readEntity(ref);
|
|
458
|
+
}), Query14((block) => txn.readEntity(block.parents.parent)), Query14((parent) => txn.patchEntity(parent.ref, {
|
|
459
|
+
children: {
|
|
460
|
+
blocks: parent.children.blocks.filter((blockRef) => blockRef !== ref)
|
|
461
|
+
}
|
|
462
|
+
})), Query14(() => txn.deleteEntity(ref)));
|
|
463
|
+
}, { changeSetOnly: true });
|
|
464
|
+
|
|
465
|
+
// src/operations/duplicateBlockParagraph.ts
|
|
466
|
+
import { Query as Query15, QueryChain as QueryChain8, writeOperation as writeOperation15 } from "roc-db";
|
|
467
|
+
import { z as z31 } from "zod";
|
|
468
|
+
var duplicateBlockParagraph = writeOperation15("duplicateBlockParagraph", z31.object({ ref: BlockParagraphRefSchema }).strict(), (txn) => {
|
|
469
|
+
const copyRef = txn.createRef("BlockParagraph");
|
|
470
|
+
return QueryChain8(Query15(() => txn.readEntity(txn.payload.ref)), Query15((source) => txn.readEntity(source.parents.parent)), Query15((parent) => txn.patchEntity(parent.ref, {
|
|
471
|
+
children: { blocks: [...parent.children.blocks, copyRef] }
|
|
472
|
+
})), Query15((_parent, _readParent, source) => txn.createEntity(copyRef, {
|
|
473
|
+
parents: source.parents,
|
|
474
|
+
data: source.data
|
|
475
|
+
})));
|
|
476
|
+
}, { changeSetOnly: true, outputSchema: BlockParagraphSchema });
|
|
477
|
+
|
|
478
|
+
// src/operations/deleteOrgSettings.ts
|
|
479
|
+
import { Query as Query16, writeOperation as writeOperation16 } from "roc-db";
|
|
480
|
+
import { z as z32 } from "zod";
|
|
481
|
+
var deleteOrgSettings = writeOperation16("deleteOrgSettings", z32.object({}).optional(), (txn) => Query16(() => txn.deleteEntity("OrgSettings")));
|
|
447
482
|
|
|
448
483
|
// src/operations/deletePost.ts
|
|
449
|
-
import { Query as
|
|
450
|
-
var deletePost =
|
|
484
|
+
import { Query as Query17, writeOperation as writeOperation17 } from "roc-db";
|
|
485
|
+
var deletePost = writeOperation17("deletePost", PostRefSchema, (txn) => {
|
|
451
486
|
const ref = txn.payload;
|
|
452
|
-
return
|
|
487
|
+
return Query17(() => txn.deleteEntity(ref, true));
|
|
453
488
|
});
|
|
454
489
|
|
|
455
490
|
// src/operations/duplicateDraft.ts
|
|
456
491
|
import {
|
|
457
|
-
Query as
|
|
458
|
-
QueryChain as
|
|
459
|
-
writeOperation as
|
|
492
|
+
Query as Query18,
|
|
493
|
+
QueryChain as QueryChain9,
|
|
494
|
+
writeOperation as writeOperation18
|
|
460
495
|
} from "roc-db";
|
|
461
|
-
import { z as
|
|
462
|
-
var duplicateDraft =
|
|
496
|
+
import { z as z33 } from "zod";
|
|
497
|
+
var duplicateDraft = writeOperation18("duplicateDraft", z33.object({ sourceRef: DraftRefSchema, postRef: PostRefSchema }).strict(), (txn) => {
|
|
463
498
|
const newDraftRef = txn.createRef("Draft");
|
|
464
499
|
const { sourceRef, postRef } = txn.payload;
|
|
465
|
-
return
|
|
500
|
+
return QueryChain9(Query18(() => txn.createEntity(newDraftRef, { parents: { post: postRef } })), Query18(() => txn.duplicateChangeSetMutations(sourceRef, newDraftRef)), Query18((dup) => {
|
|
466
501
|
const result = dup;
|
|
467
502
|
return {
|
|
468
503
|
draftRef: newDraftRef,
|
|
@@ -473,28 +508,28 @@ var duplicateDraft = writeOperation16("duplicateDraft", z31.object({ sourceRef:
|
|
|
473
508
|
});
|
|
474
509
|
|
|
475
510
|
// src/operations/moveBlocks.ts
|
|
476
|
-
import { Query as
|
|
477
|
-
import { z as
|
|
478
|
-
var PayloadSchema3 =
|
|
479
|
-
refs:
|
|
480
|
-
targetPosition:
|
|
511
|
+
import { Query as Query19, QueryChain as QueryChain10, writeOperation as writeOperation19 } from "roc-db";
|
|
512
|
+
import { z as z34 } from "zod";
|
|
513
|
+
var PayloadSchema3 = z34.object({
|
|
514
|
+
refs: z34.array(z34.union([BlockParagraphRefSchema, BlockRowRefSchema])),
|
|
515
|
+
targetPosition: z34.number().min(0)
|
|
481
516
|
}).strict();
|
|
482
|
-
var moveBlocks =
|
|
517
|
+
var moveBlocks = writeOperation19("moveBlocks", PayloadSchema3, (txn) => {
|
|
483
518
|
const { refs } = txn.payload;
|
|
484
|
-
return
|
|
519
|
+
return QueryChain10(Query19(() => txn.batchReadEntities(refs)), Query19((items) => {
|
|
485
520
|
return "todo";
|
|
486
521
|
}));
|
|
487
522
|
});
|
|
488
523
|
|
|
489
524
|
// src/operations/pageBlocks.ts
|
|
490
|
-
import { Query as
|
|
491
|
-
import { z as
|
|
492
|
-
var pageBlocks = readOperation("pageBlocks",
|
|
493
|
-
size:
|
|
494
|
-
parentRef:
|
|
525
|
+
import { Query as Query20, readOperation } from "roc-db";
|
|
526
|
+
import { z as z35 } from "zod";
|
|
527
|
+
var pageBlocks = readOperation("pageBlocks", z35.object({
|
|
528
|
+
size: z35.number().default(100),
|
|
529
|
+
parentRef: z35.string().optional()
|
|
495
530
|
}), (txn) => {
|
|
496
531
|
const { size, parentRef } = txn.payload;
|
|
497
|
-
return
|
|
532
|
+
return Query20(() => txn.pageEntities({
|
|
498
533
|
entities: ["BlockImage", "BlockParagraph"],
|
|
499
534
|
size,
|
|
500
535
|
childrenOf: parentRef ? [parentRef] : []
|
|
@@ -502,50 +537,50 @@ var pageBlocks = readOperation("pageBlocks", z33.object({
|
|
|
502
537
|
});
|
|
503
538
|
|
|
504
539
|
// src/operations/pageEmptyEntitiesArray.ts
|
|
505
|
-
import { Query as
|
|
506
|
-
import { z as
|
|
507
|
-
var pageEmptyEntitiesArray = readOperation2("pageEmptyEntitiesArray",
|
|
540
|
+
import { Query as Query21, readOperation as readOperation2 } from "roc-db";
|
|
541
|
+
import { z as z36 } from "zod";
|
|
542
|
+
var pageEmptyEntitiesArray = readOperation2("pageEmptyEntitiesArray", z36.object({ size: z36.number().default(100) }), (txn) => {
|
|
508
543
|
const { size } = txn.payload;
|
|
509
|
-
return
|
|
544
|
+
return Query21(() => txn.pageEntities({ entities: [], size }));
|
|
510
545
|
});
|
|
511
546
|
|
|
512
547
|
// src/operations/pagePosts.ts
|
|
513
|
-
import { Query as
|
|
514
|
-
import { z as
|
|
515
|
-
var pagePosts = readOperation3("pagePosts",
|
|
548
|
+
import { Query as Query22, readOperation as readOperation3 } from "roc-db";
|
|
549
|
+
import { z as z37 } from "zod";
|
|
550
|
+
var pagePosts = readOperation3("pagePosts", z37.object({ size: z37.number().default(100) }).default({}), (txn) => {
|
|
516
551
|
const { size } = txn.payload;
|
|
517
|
-
return
|
|
552
|
+
return Query22(() => txn.pageEntities({ entities: ["Post"], size }));
|
|
518
553
|
});
|
|
519
554
|
|
|
520
555
|
// src/operations/pageSplat.ts
|
|
521
|
-
import { Query as
|
|
522
|
-
import { z as
|
|
523
|
-
var pageSplat = readOperation4("pageSplat",
|
|
556
|
+
import { Query as Query23, readOperation as readOperation4 } from "roc-db";
|
|
557
|
+
import { z as z38 } from "zod";
|
|
558
|
+
var pageSplat = readOperation4("pageSplat", z38.object({ size: z38.number().default(100) }), (txn) => {
|
|
524
559
|
const { size } = txn.payload;
|
|
525
|
-
return
|
|
560
|
+
return Query23(() => txn.pageEntities({ entities: "*", size }));
|
|
526
561
|
});
|
|
527
562
|
|
|
528
563
|
// src/operations/pagePostsByTag.ts
|
|
529
|
-
import { Query as
|
|
530
|
-
import { z as
|
|
531
|
-
var pagePostsByTag = readOperation5("pagePostsByTag",
|
|
564
|
+
import { Query as Query24, readOperation as readOperation5 } from "roc-db";
|
|
565
|
+
import { z as z39 } from "zod";
|
|
566
|
+
var pagePostsByTag = readOperation5("pagePostsByTag", z39.string(), (txn) => {
|
|
532
567
|
const tag = txn.payload;
|
|
533
|
-
return
|
|
568
|
+
return Query24(() => txn.pageEntitiesByIndex("Post", "tags", tag));
|
|
534
569
|
});
|
|
535
570
|
|
|
536
571
|
// src/operations/readEntity.ts
|
|
537
|
-
import { NotFoundError, Query as
|
|
538
|
-
import { z as
|
|
539
|
-
var readEntity = readOperation6("readEntity",
|
|
572
|
+
import { NotFoundError, Query as Query25, QueryChain as QueryChain11, readOperation as readOperation6 } from "roc-db";
|
|
573
|
+
import { z as z40 } from "zod";
|
|
574
|
+
var readEntity = readOperation6("readEntity", z40.string(), (txn) => {
|
|
540
575
|
const ref = txn.payload;
|
|
541
|
-
return
|
|
576
|
+
return QueryChain11(Query25(() => txn.readEntity(ref)), Query25((entity) => {
|
|
542
577
|
if (!entity) {
|
|
543
578
|
throw new NotFoundError(ref);
|
|
544
579
|
}
|
|
545
580
|
return entity;
|
|
546
581
|
}));
|
|
547
582
|
}, {
|
|
548
|
-
outputSchema:
|
|
583
|
+
outputSchema: z40.union([
|
|
549
584
|
PostSchema,
|
|
550
585
|
BlockImageSchema,
|
|
551
586
|
BlockParagraphSchema
|
|
@@ -553,11 +588,11 @@ var readEntity = readOperation6("readEntity", z38.string(), (txn) => {
|
|
|
553
588
|
});
|
|
554
589
|
|
|
555
590
|
// src/operations/readMutation.ts
|
|
556
|
-
import { NotFoundError as NotFoundError2, Query as
|
|
557
|
-
import { z as
|
|
558
|
-
var readMutation = readOperation7("readMutation",
|
|
591
|
+
import { NotFoundError as NotFoundError2, Query as Query26, QueryChain as QueryChain12, readOperation as readOperation7 } from "roc-db";
|
|
592
|
+
import { z as z41 } from "zod";
|
|
593
|
+
var readMutation = readOperation7("readMutation", z41.string(), (txn) => {
|
|
559
594
|
const ref = txn.payload;
|
|
560
|
-
return
|
|
595
|
+
return QueryChain12(Query26(() => txn.readMutation(ref)), Query26((entity) => {
|
|
561
596
|
if (!entity) {
|
|
562
597
|
throw new NotFoundError2(ref);
|
|
563
598
|
}
|
|
@@ -566,57 +601,57 @@ var readMutation = readOperation7("readMutation", z39.string(), (txn) => {
|
|
|
566
601
|
});
|
|
567
602
|
|
|
568
603
|
// src/operations/readOrgSettings.ts
|
|
569
|
-
import { Query as
|
|
570
|
-
import { z as
|
|
571
|
-
var readOrgSettings = readOperation8("readOrgSettings",
|
|
604
|
+
import { Query as Query27, readOperation as readOperation8 } from "roc-db";
|
|
605
|
+
import { z as z42 } from "zod";
|
|
606
|
+
var readOrgSettings = readOperation8("readOrgSettings", z42.object({}).optional(), (txn) => Query27(() => txn.readEntity("OrgSettings", true)));
|
|
572
607
|
|
|
573
608
|
// src/operations/readPost.ts
|
|
574
|
-
import { Query as
|
|
609
|
+
import { Query as Query28, readOperation as readOperation9 } from "roc-db";
|
|
575
610
|
var readPost = readOperation9("readPost", PostRefSchema, (txn) => {
|
|
576
611
|
const ref = txn.payload;
|
|
577
|
-
return
|
|
612
|
+
return Query28(() => txn.readEntity(ref, true));
|
|
578
613
|
}, { outputSchema: PostSchema });
|
|
579
614
|
|
|
580
615
|
// src/operations/readPostBySlug.ts
|
|
581
|
-
import { Query as
|
|
582
|
-
import { z as
|
|
583
|
-
var readPostBySlug = readOperation10("readPostBySlug",
|
|
616
|
+
import { Query as Query29, readOperation as readOperation10 } from "roc-db";
|
|
617
|
+
import { z as z43 } from "zod";
|
|
618
|
+
var readPostBySlug = readOperation10("readPostBySlug", z43.string(), (txn) => {
|
|
584
619
|
const slug = txn.payload;
|
|
585
|
-
return
|
|
620
|
+
return Query29(() => txn.readEntityByUniqueField("Post", "slug", slug));
|
|
586
621
|
}, { outputSchema: PostSchema });
|
|
587
622
|
|
|
588
623
|
// src/operations/testTransactionalEdits.ts
|
|
589
624
|
import { expect } from "bun:test";
|
|
590
|
-
import { Query as
|
|
591
|
-
import { z as
|
|
625
|
+
import { Query as Query30, QueryChain as QueryChain13, writeOperation as writeOperation20 } from "roc-db";
|
|
626
|
+
import { z as z44 } from "zod";
|
|
592
627
|
var TestCreatePatchDeleteInSameTransaction = (txn, title) => {
|
|
593
628
|
const postRef = txn.createRef("Post");
|
|
594
|
-
return
|
|
629
|
+
return QueryChain13(Query30(() => txn.createEntity(postRef, {
|
|
595
630
|
data: { title, tags: [] },
|
|
596
631
|
children: { blocks: [] }
|
|
597
|
-
})),
|
|
632
|
+
})), Query30(() => txn.patchEntity(postRef, { data: { foo: "bar" } })), Query30((post) => {
|
|
598
633
|
expect(post.data.title).toBe(title);
|
|
599
634
|
expect(post.data.foo).toBe("bar");
|
|
600
|
-
}),
|
|
635
|
+
}), Query30(() => txn.patchEntity(postRef, { data: { foo: null, bar: "foo" } })), Query30((post) => {
|
|
601
636
|
expect(post.data.title).toBe(title);
|
|
602
637
|
expect(post.data.foo).toBeUndefined();
|
|
603
638
|
expect(post.data.bar).toBe("foo");
|
|
604
639
|
expect(txn.log).toHaveLength(1);
|
|
605
640
|
expect(txn.log.get(postRef)?.[0]).toBe("create");
|
|
606
|
-
}),
|
|
641
|
+
}), Query30((post) => txn.deleteEntity(postRef)), Query30((res) => {
|
|
607
642
|
expect(res).toBe(1);
|
|
608
643
|
expect(txn.log).toHaveLength(0);
|
|
609
644
|
}));
|
|
610
645
|
};
|
|
611
646
|
var TestUpdateAndDeleteInSameTransaction = (txn, ref) => {
|
|
612
|
-
return
|
|
647
|
+
return QueryChain13(Query30(() => txn.patchEntity(ref, { data: { foo: "bar" } })), Query30((post) => {
|
|
613
648
|
expect(post.data.foo).toBe("bar");
|
|
614
|
-
}),
|
|
649
|
+
}), Query30(() => txn.patchEntity(ref, { data: { foo: null, bar: "foo" } })), Query30((post) => {
|
|
615
650
|
expect(post.data.foo).toBeUndefined();
|
|
616
651
|
expect(post.data.bar).toBe("foo");
|
|
617
652
|
expect(txn.log).toHaveLength(1);
|
|
618
653
|
expect(txn.log.get(ref)?.[0]).toBe("update");
|
|
619
|
-
}),
|
|
654
|
+
}), Query30((post) => txn.deleteEntity(ref)), Query30((res) => {
|
|
620
655
|
expect(res).toBe(1);
|
|
621
656
|
expect(txn.log).toHaveLength(1);
|
|
622
657
|
expect(txn.log.get(ref)?.[0]).toBe("delete");
|
|
@@ -624,14 +659,14 @@ var TestUpdateAndDeleteInSameTransaction = (txn, ref) => {
|
|
|
624
659
|
};
|
|
625
660
|
var TestCreateOnExistingRef = (txn) => {
|
|
626
661
|
const ref = txn.createRef("Post");
|
|
627
|
-
return
|
|
662
|
+
return QueryChain13(Query30(() => txn.createEntity(ref, { data: { foo: "bar" } })), Query30(() => txn.createEntity(ref, { data: { foo: "bar" } })));
|
|
628
663
|
};
|
|
629
|
-
var PayloadSchema4 =
|
|
630
|
-
name:
|
|
664
|
+
var PayloadSchema4 = z44.object({
|
|
665
|
+
name: z44.string().optional(),
|
|
631
666
|
post1ref: PostRefSchema.optional(),
|
|
632
667
|
post2ref: PostRefSchema.optional()
|
|
633
668
|
}).strict();
|
|
634
|
-
var testTransactionalEdits =
|
|
669
|
+
var testTransactionalEdits = writeOperation20("testTransactionalEdits", PayloadSchema4, (txn) => {
|
|
635
670
|
const { name, post1ref, post2ref } = txn.payload;
|
|
636
671
|
if (name)
|
|
637
672
|
return TestCreatePatchDeleteInSameTransaction(txn, name);
|
|
@@ -642,38 +677,56 @@ var testTransactionalEdits = writeOperation18("testTransactionalEdits", PayloadS
|
|
|
642
677
|
}, {});
|
|
643
678
|
|
|
644
679
|
// src/operations/updateBlockParagraph.ts
|
|
645
|
-
import { Query as
|
|
646
|
-
import { z as
|
|
647
|
-
var updateBlockParagraph =
|
|
680
|
+
import { Query as Query31, writeOperation as writeOperation21 } from "roc-db";
|
|
681
|
+
import { z as z45 } from "zod";
|
|
682
|
+
var updateBlockParagraph = writeOperation21("updateBlockParagraph", z45.object({
|
|
648
683
|
ref: BlockParagraphRefSchema,
|
|
649
|
-
content:
|
|
684
|
+
content: z45.string()
|
|
650
685
|
}), (txn) => {
|
|
651
686
|
const { ref, content } = txn.payload;
|
|
652
|
-
return
|
|
687
|
+
return Query31(() => txn.patchEntity(ref, {
|
|
653
688
|
data: { content }
|
|
654
689
|
}));
|
|
655
690
|
}, { outputSchema: BlockParagraphSchema });
|
|
656
691
|
|
|
692
|
+
// src/operations/updateBlockParagraphMentions.ts
|
|
693
|
+
import {
|
|
694
|
+
Query as Query32,
|
|
695
|
+
QueryChain as QueryChain14,
|
|
696
|
+
writeOperation as writeOperation22
|
|
697
|
+
} from "roc-db";
|
|
698
|
+
import { z as z46 } from "zod";
|
|
699
|
+
var PayloadSchema5 = z46.object({
|
|
700
|
+
ref: BlockParagraphRefSchema,
|
|
701
|
+
mentions: z46.array(BlockParagraphRefSchema)
|
|
702
|
+
}).strict();
|
|
703
|
+
var setMentions = (txn) => {
|
|
704
|
+
const { ref, mentions } = txn.payload;
|
|
705
|
+
return QueryChain14(...mentions.map((mention) => Query32(() => txn.readEntity(mention))), Query32(() => txn.patchEntity(ref, { data: { mentions } })));
|
|
706
|
+
};
|
|
707
|
+
var updateBlockParagraphMentions = writeOperation22("updateBlockParagraphMentions", PayloadSchema5, setMentions, { debounce: 10, changeSetOnly: true, outputSchema: BlockParagraphSchema });
|
|
708
|
+
var setBlockParagraphMentions = writeOperation22("setBlockParagraphMentions", PayloadSchema5, setMentions, { changeSetOnly: true, outputSchema: BlockParagraphSchema });
|
|
709
|
+
|
|
657
710
|
// src/operations/updateOrgSettingsName.ts
|
|
658
|
-
import { Query as
|
|
659
|
-
import { z as
|
|
660
|
-
var updateOrgSettingsName =
|
|
711
|
+
import { Query as Query33, writeOperation as writeOperation23 } from "roc-db";
|
|
712
|
+
import { z as z47 } from "zod";
|
|
713
|
+
var updateOrgSettingsName = writeOperation23("updateOrgSettingsName", z47.object({ name: z47.string() }), (txn) => {
|
|
661
714
|
const { name } = txn.payload;
|
|
662
|
-
return
|
|
715
|
+
return Query33(() => txn.patchEntity("OrgSettings", { data: { name } }));
|
|
663
716
|
}, { debounce: 10 });
|
|
664
717
|
|
|
665
718
|
// src/operations/updatePost.ts
|
|
666
|
-
import { Query as
|
|
667
|
-
import { z as
|
|
668
|
-
var
|
|
719
|
+
import { Query as Query34, writeOperation as writeOperation24 } from "roc-db";
|
|
720
|
+
import { z as z48 } from "zod";
|
|
721
|
+
var PayloadSchema6 = z48.object({
|
|
669
722
|
ref: PostRefSchema,
|
|
670
|
-
title:
|
|
671
|
-
tags:
|
|
723
|
+
title: z48.string().optional(),
|
|
724
|
+
tags: z48.array(z48.string()).optional().default([]),
|
|
672
725
|
authorRef: UserRefSchema.optional()
|
|
673
726
|
});
|
|
674
|
-
var updatePost =
|
|
727
|
+
var updatePost = writeOperation24("updatePost", PayloadSchema6, (txn) => {
|
|
675
728
|
const { ref, authorRef, ...data } = txn.payload;
|
|
676
|
-
return
|
|
729
|
+
return Query34(() => txn.updateEntity(ref, {
|
|
677
730
|
data,
|
|
678
731
|
parents: { author: authorRef },
|
|
679
732
|
children: { blocks: [] }
|
|
@@ -681,43 +734,43 @@ var updatePost = writeOperation21("updatePost", PayloadSchema5, (txn) => {
|
|
|
681
734
|
}, { outputSchema: PostSchema });
|
|
682
735
|
|
|
683
736
|
// src/operations/updatePostDescription.ts
|
|
684
|
-
import { Query as
|
|
685
|
-
import { z as
|
|
686
|
-
var updatePostDescription =
|
|
737
|
+
import { Query as Query35, writeOperation as writeOperation25 } from "roc-db";
|
|
738
|
+
import { z as z49 } from "zod";
|
|
739
|
+
var updatePostDescription = writeOperation25("updatePostDescription", z49.object({ ref: PostRefSchema, description: z49.string() }), (txn) => {
|
|
687
740
|
const { ref, description } = txn.payload;
|
|
688
|
-
return
|
|
741
|
+
return Query35(() => txn.patchEntity(ref, { data: { description } }));
|
|
689
742
|
}, { debounce: 10, changeSetOnly: true, outputSchema: PostSchema });
|
|
690
743
|
|
|
691
744
|
// src/operations/updatePostSlug.ts
|
|
692
|
-
import { Query as
|
|
693
|
-
import { z as
|
|
694
|
-
var updatePostSlug =
|
|
745
|
+
import { Query as Query36, writeOperation as writeOperation26 } from "roc-db";
|
|
746
|
+
import { z as z50 } from "zod";
|
|
747
|
+
var updatePostSlug = writeOperation26("updatePostSlug", z50.object({ ref: PostRefSchema, slug: z50.string() }), (txn) => {
|
|
695
748
|
const { ref, slug } = txn.payload;
|
|
696
|
-
return
|
|
749
|
+
return Query36(() => txn.patchEntity(ref, { data: { slug } }));
|
|
697
750
|
}, { debounce: 10, outputSchema: PostSchema });
|
|
698
751
|
|
|
699
752
|
// src/operations/updatePostTags.ts
|
|
700
|
-
import { Query as
|
|
701
|
-
import { z as
|
|
702
|
-
var updatePostTags =
|
|
753
|
+
import { Query as Query37, writeOperation as writeOperation27 } from "roc-db";
|
|
754
|
+
import { z as z51 } from "zod";
|
|
755
|
+
var updatePostTags = writeOperation27("updatePostTags", z51.object({ ref: PostRefSchema, tags: z51.array(z51.string()) }), (txn) => {
|
|
703
756
|
const { ref, tags } = txn.payload;
|
|
704
|
-
return
|
|
757
|
+
return Query37(() => txn.patchEntity(ref, { data: { tags } }));
|
|
705
758
|
}, { debounce: 10, outputSchema: PostSchema });
|
|
706
759
|
|
|
707
760
|
// src/operations/updatePostTitle.ts
|
|
708
|
-
import { Query as
|
|
709
|
-
import { z as
|
|
710
|
-
var updatePostTitle =
|
|
761
|
+
import { Query as Query38, writeOperation as writeOperation28 } from "roc-db";
|
|
762
|
+
import { z as z52 } from "zod";
|
|
763
|
+
var updatePostTitle = writeOperation28("updatePostTitle", z52.object({ ref: PostRefSchema, title: z52.string() }), (txn) => {
|
|
711
764
|
const { ref, title } = txn.payload;
|
|
712
|
-
return
|
|
765
|
+
return Query38(() => txn.patchEntity(ref, { data: { title } }));
|
|
713
766
|
}, { debounce: 10, outputSchema: PostSchema });
|
|
714
767
|
|
|
715
768
|
// src/operations/crudBySlug.ts
|
|
716
|
-
import { Query as
|
|
717
|
-
import { z as
|
|
718
|
-
var crudBySlug =
|
|
769
|
+
import { Query as Query39, QueryChain as QueryChain15, writeOperation as writeOperation29 } from "roc-db";
|
|
770
|
+
import { z as z53 } from "zod";
|
|
771
|
+
var crudBySlug = writeOperation29("crudBySlug", z53.object({ slug: z53.string(), newSlug: z53.string() }), (txn) => {
|
|
719
772
|
const { slug, newSlug } = txn.payload;
|
|
720
|
-
return
|
|
773
|
+
return QueryChain15(Query39(() => txn.readEntityByUniqueField("Post", "slug", slug)), Query39((post) => txn.patchEntity(post.ref, { data: { slug: newSlug } })), Query39(() => txn.readEntityByUniqueField("Post", "slug", newSlug)), Query39((post) => txn.deleteEntity(post.ref)), Query39(() => {
|
|
721
774
|
return [
|
|
722
775
|
txn.readEntityByUniqueField("Post", "slug", slug, false),
|
|
723
776
|
txn.readEntityByUniqueField("Post", "slug", newSlug, false)
|
|
@@ -745,6 +798,8 @@ var operations = [
|
|
|
745
798
|
crudBySlug,
|
|
746
799
|
deleteBlocks,
|
|
747
800
|
deleteDraft,
|
|
801
|
+
deleteUnmentionedBlockParagraph,
|
|
802
|
+
duplicateBlockParagraph,
|
|
748
803
|
deleteOrgSettings,
|
|
749
804
|
deletePost,
|
|
750
805
|
duplicateDraft,
|
|
@@ -761,6 +816,8 @@ var operations = [
|
|
|
761
816
|
pageSplat,
|
|
762
817
|
testTransactionalEdits,
|
|
763
818
|
updateBlockParagraph,
|
|
819
|
+
updateBlockParagraphMentions,
|
|
820
|
+
setBlockParagraphMentions,
|
|
764
821
|
updateOrgSettingsName,
|
|
765
822
|
updatePost,
|
|
766
823
|
updatePostDescription,
|
|
@@ -771,13 +828,13 @@ var operations = [
|
|
|
771
828
|
// src/testAdapterImplementation.ts
|
|
772
829
|
import { beforeAll, describe, expect as expect2, test } from "bun:test";
|
|
773
830
|
import {
|
|
774
|
-
BadRequestError,
|
|
831
|
+
BadRequestError as BadRequestError2,
|
|
775
832
|
ConflictError,
|
|
776
833
|
Entity as Entity9,
|
|
777
834
|
NotFoundError as NotFoundError3,
|
|
778
835
|
Snowflake
|
|
779
836
|
} from "roc-db";
|
|
780
|
-
import { z as
|
|
837
|
+
import { z as z54 } from "zod";
|
|
781
838
|
import { faker } from "@faker-js/faker";
|
|
782
839
|
var snowflake = new Snowflake(10, 10);
|
|
783
840
|
var prepareChangeSetTest = async (adapter, adapter2) => {
|
|
@@ -968,7 +1025,7 @@ var testAdapterImplementation = async (adapterConstructor, generateArgs) => {
|
|
|
968
1025
|
expect2(() => adapter1.updatePostDescription({
|
|
969
1026
|
ref: postRef,
|
|
970
1027
|
description: "Description 1"
|
|
971
|
-
})).toThrow(
|
|
1028
|
+
})).toThrow(BadRequestError2);
|
|
972
1029
|
});
|
|
973
1030
|
test("delete (deleteEntity function)", async () => {
|
|
974
1031
|
const currentPost = await adapter1.readPost(postRef);
|
|
@@ -1025,7 +1082,7 @@ var testAdapterImplementation = async (adapterConstructor, generateArgs) => {
|
|
|
1025
1082
|
expect2(mutation2.log[0][1]).toBe("delete");
|
|
1026
1083
|
expect2(() => adapter1.testTransactionalEdits({
|
|
1027
1084
|
post2ref: post2.ref
|
|
1028
|
-
})).toThrow(
|
|
1085
|
+
})).toThrow(BadRequestError2);
|
|
1029
1086
|
});
|
|
1030
1087
|
});
|
|
1031
1088
|
describe("OrgSettings singleton", () => {
|
|
@@ -1101,12 +1158,12 @@ var testAdapterImplementation = async (adapterConstructor, generateArgs) => {
|
|
|
1101
1158
|
test("constructor rejects singleton + uniqueDataKeys", () => {
|
|
1102
1159
|
expect2(() => new Entity9("Bad", {
|
|
1103
1160
|
singleton: true,
|
|
1104
|
-
data:
|
|
1161
|
+
data: z54.object({ name: z54.string() }),
|
|
1105
1162
|
uniqueDataKeys: ["name"]
|
|
1106
1163
|
})).toThrow(/singleton/);
|
|
1107
1164
|
});
|
|
1108
1165
|
test("createRef throws on unregistered entity", async () => {
|
|
1109
|
-
expect2(() => adapter.createUnknownRef()).toThrow(
|
|
1166
|
+
expect2(() => adapter.createUnknownRef()).toThrow(BadRequestError2);
|
|
1110
1167
|
});
|
|
1111
1168
|
});
|
|
1112
1169
|
describe("paging", () => {
|
|
@@ -1239,7 +1296,7 @@ var testAdapterImplementation = async (adapterConstructor, generateArgs) => {
|
|
|
1239
1296
|
});
|
|
1240
1297
|
test("invalid changeSetRef throws error", async () => {
|
|
1241
1298
|
const changeSetAdapter2 = adapter1.changeSet("Draft/123");
|
|
1242
|
-
expect2(() => changeSetAdapter2.createPost({ title: "Title 1" })).toThrow(
|
|
1299
|
+
expect2(() => changeSetAdapter2.createPost({ title: "Title 1" })).toThrow(BadRequestError2);
|
|
1243
1300
|
});
|
|
1244
1301
|
test("duplicateDraft (txn.duplicateChangeSetMutations) produces an independent copy with remapped refs", async () => {
|
|
1245
1302
|
const [post2] = await adapter1.createPost({
|
|
@@ -1431,6 +1488,329 @@ var testAdapterImplementation = async (adapterConstructor, generateArgs) => {
|
|
|
1431
1488
|
});
|
|
1432
1489
|
});
|
|
1433
1490
|
});
|
|
1491
|
+
describe("debounce ordering", () => {
|
|
1492
|
+
const tick = () => Bun.sleep(2);
|
|
1493
|
+
const createSyncQueue = (server) => {
|
|
1494
|
+
const queue = [];
|
|
1495
|
+
return {
|
|
1496
|
+
add: ([result, mutation]) => {
|
|
1497
|
+
const index = queue.findIndex((m) => m.ref === mutation.ref);
|
|
1498
|
+
if (index === -1)
|
|
1499
|
+
queue.push(mutation);
|
|
1500
|
+
else
|
|
1501
|
+
queue[index] = mutation;
|
|
1502
|
+
return result;
|
|
1503
|
+
},
|
|
1504
|
+
flush: async () => {
|
|
1505
|
+
while (queue.length) {
|
|
1506
|
+
await tick();
|
|
1507
|
+
await server.persistOptimisticMutations([queue[0]]);
|
|
1508
|
+
queue.shift();
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
};
|
|
1512
|
+
};
|
|
1513
|
+
const replay = async (source) => {
|
|
1514
|
+
const mutations = await source.pageMutations({ size: 1000 });
|
|
1515
|
+
const replayed = await createAdapter({ optimistic: true });
|
|
1516
|
+
await replayed.loadMutations(mutations);
|
|
1517
|
+
return replayed;
|
|
1518
|
+
};
|
|
1519
|
+
const setupClient = async () => {
|
|
1520
|
+
const server = await createAdapter();
|
|
1521
|
+
const client = await createAdapter({ optimistic: true });
|
|
1522
|
+
const queue = createSyncQueue(server);
|
|
1523
|
+
const post = queue.add(await client.createPost({ title: "Post", tags: [] }));
|
|
1524
|
+
const draft = queue.add(await client.createDraft({ postRef: post.ref }));
|
|
1525
|
+
const changeSet = client.changeSet(draft.ref);
|
|
1526
|
+
const createParagraph = async () => queue.add(await changeSet.createBlockParagraph({
|
|
1527
|
+
parentRef: post.ref
|
|
1528
|
+
})).block;
|
|
1529
|
+
const holder = await createParagraph();
|
|
1530
|
+
await queue.flush();
|
|
1531
|
+
return {
|
|
1532
|
+
server,
|
|
1533
|
+
queue,
|
|
1534
|
+
post,
|
|
1535
|
+
draft,
|
|
1536
|
+
changeSet,
|
|
1537
|
+
createParagraph,
|
|
1538
|
+
holder
|
|
1539
|
+
};
|
|
1540
|
+
};
|
|
1541
|
+
test("forward: a version that reads an entity created after the previous version syncs", async () => {
|
|
1542
|
+
const { server, queue, draft, changeSet, createParagraph, holder } = await setupClient();
|
|
1543
|
+
queue.add(await changeSet.updateBlockParagraphMentions({
|
|
1544
|
+
ref: holder.ref,
|
|
1545
|
+
mentions: []
|
|
1546
|
+
}));
|
|
1547
|
+
const mentioned = await createParagraph();
|
|
1548
|
+
queue.add(await changeSet.updateBlockParagraphMentions({
|
|
1549
|
+
ref: holder.ref,
|
|
1550
|
+
mentions: [mentioned.ref]
|
|
1551
|
+
}));
|
|
1552
|
+
await queue.flush();
|
|
1553
|
+
const replayed = (await replay(server)).changeSet(draft.ref);
|
|
1554
|
+
const replayedHolder = await replayed.readEntity(holder.ref);
|
|
1555
|
+
expect2(replayedHolder.data.mentions).toEqual([mentioned.ref]);
|
|
1556
|
+
});
|
|
1557
|
+
test("reverse: a version that frees an entity before it is deleted replays", async () => {
|
|
1558
|
+
const {
|
|
1559
|
+
server,
|
|
1560
|
+
queue,
|
|
1561
|
+
post,
|
|
1562
|
+
draft,
|
|
1563
|
+
changeSet,
|
|
1564
|
+
createParagraph,
|
|
1565
|
+
holder
|
|
1566
|
+
} = await setupClient();
|
|
1567
|
+
const first = await createParagraph();
|
|
1568
|
+
const second = await createParagraph();
|
|
1569
|
+
const third = await createParagraph();
|
|
1570
|
+
queue.add(await changeSet.setBlockParagraphMentions({
|
|
1571
|
+
ref: holder.ref,
|
|
1572
|
+
mentions: [first.ref]
|
|
1573
|
+
}));
|
|
1574
|
+
await queue.flush();
|
|
1575
|
+
queue.add(await changeSet.updateBlockParagraphMentions({
|
|
1576
|
+
ref: holder.ref,
|
|
1577
|
+
mentions: [second.ref]
|
|
1578
|
+
}));
|
|
1579
|
+
await queue.flush();
|
|
1580
|
+
queue.add(await changeSet.deleteUnmentionedBlockParagraph({
|
|
1581
|
+
ref: first.ref,
|
|
1582
|
+
mentionedByRef: holder.ref
|
|
1583
|
+
}));
|
|
1584
|
+
await queue.flush();
|
|
1585
|
+
queue.add(await changeSet.updateBlockParagraphMentions({
|
|
1586
|
+
ref: holder.ref,
|
|
1587
|
+
mentions: [third.ref]
|
|
1588
|
+
}));
|
|
1589
|
+
await queue.flush();
|
|
1590
|
+
const replayed = (await replay(server)).changeSet(draft.ref);
|
|
1591
|
+
const replayedHolder = await replayed.readEntity(holder.ref);
|
|
1592
|
+
expect2(replayedHolder.data.mentions).toEqual([third.ref]);
|
|
1593
|
+
const replayedPost = await replayed.readEntity(post.ref);
|
|
1594
|
+
expect2(replayedPost.children.blocks).not.toContain(first.ref);
|
|
1595
|
+
});
|
|
1596
|
+
test("copy: an entity copied between two versions keeps the version it copied", async () => {
|
|
1597
|
+
const { server, queue, draft, changeSet, createParagraph, holder } = await setupClient();
|
|
1598
|
+
const first = await createParagraph();
|
|
1599
|
+
const second = await createParagraph();
|
|
1600
|
+
queue.add(await changeSet.updateBlockParagraphMentions({
|
|
1601
|
+
ref: holder.ref,
|
|
1602
|
+
mentions: [first.ref]
|
|
1603
|
+
}));
|
|
1604
|
+
await queue.flush();
|
|
1605
|
+
const copy = queue.add(await changeSet.duplicateBlockParagraph({ ref: holder.ref }));
|
|
1606
|
+
await queue.flush();
|
|
1607
|
+
queue.add(await changeSet.updateBlockParagraphMentions({
|
|
1608
|
+
ref: holder.ref,
|
|
1609
|
+
mentions: [second.ref]
|
|
1610
|
+
}));
|
|
1611
|
+
await queue.flush();
|
|
1612
|
+
expect2(copy.data.mentions).toEqual([first.ref]);
|
|
1613
|
+
const replayed = (await replay(server)).changeSet(draft.ref);
|
|
1614
|
+
const replayedCopy = await replayed.readEntity(copy.ref);
|
|
1615
|
+
expect2(replayedCopy.data.mentions).toEqual([first.ref]);
|
|
1616
|
+
const replayedHolder = await replayed.readEntity(holder.ref);
|
|
1617
|
+
expect2(replayedHolder.data.mentions).toEqual([second.ref]);
|
|
1618
|
+
});
|
|
1619
|
+
test("server-side: non-optimistic versions around another write replay", async () => {
|
|
1620
|
+
const server = await createAdapter();
|
|
1621
|
+
const [post] = await server.createPost({ title: "Post", tags: [] });
|
|
1622
|
+
const [draft] = await server.createDraft({ postRef: post.ref });
|
|
1623
|
+
const changeSet = server.changeSet(draft.ref);
|
|
1624
|
+
const [{ block: holder }] = await changeSet.createBlockParagraph({
|
|
1625
|
+
parentRef: post.ref
|
|
1626
|
+
});
|
|
1627
|
+
await changeSet.updateBlockParagraphMentions({
|
|
1628
|
+
ref: holder.ref,
|
|
1629
|
+
mentions: []
|
|
1630
|
+
});
|
|
1631
|
+
await tick();
|
|
1632
|
+
const [{ block: mentioned }] = await changeSet.createBlockParagraph({ parentRef: post.ref });
|
|
1633
|
+
await tick();
|
|
1634
|
+
await changeSet.updateBlockParagraphMentions({
|
|
1635
|
+
ref: holder.ref,
|
|
1636
|
+
mentions: [mentioned.ref]
|
|
1637
|
+
});
|
|
1638
|
+
await changeSet.createBlockParagraph({ parentRef: post.ref });
|
|
1639
|
+
const replayed = (await replay(server)).changeSet(draft.ref);
|
|
1640
|
+
const replayedHolder = await replayed.readEntity(holder.ref);
|
|
1641
|
+
expect2(replayedHolder.data.mentions).toEqual([mentioned.ref]);
|
|
1642
|
+
});
|
|
1643
|
+
test("old client: merged versions whose row is no longer last persist once and replay", async () => {
|
|
1644
|
+
const {
|
|
1645
|
+
server,
|
|
1646
|
+
queue,
|
|
1647
|
+
post,
|
|
1648
|
+
draft,
|
|
1649
|
+
changeSet,
|
|
1650
|
+
createParagraph,
|
|
1651
|
+
holder
|
|
1652
|
+
} = await setupClient();
|
|
1653
|
+
const first = await createParagraph();
|
|
1654
|
+
const second = await createParagraph();
|
|
1655
|
+
const third = await createParagraph();
|
|
1656
|
+
queue.add(await changeSet.setBlockParagraphMentions({
|
|
1657
|
+
ref: holder.ref,
|
|
1658
|
+
mentions: [first.ref]
|
|
1659
|
+
}));
|
|
1660
|
+
const [, versionMutation] = await changeSet.updateBlockParagraphMentions({
|
|
1661
|
+
ref: holder.ref,
|
|
1662
|
+
mentions: [second.ref]
|
|
1663
|
+
});
|
|
1664
|
+
queue.add([undefined, versionMutation]);
|
|
1665
|
+
queue.add(await changeSet.deleteUnmentionedBlockParagraph({
|
|
1666
|
+
ref: first.ref,
|
|
1667
|
+
mentionedByRef: holder.ref
|
|
1668
|
+
}));
|
|
1669
|
+
await queue.flush();
|
|
1670
|
+
const mergedPayload = { ref: holder.ref, mentions: [third.ref] };
|
|
1671
|
+
await tick();
|
|
1672
|
+
const resentTimestamp = new Date().toISOString();
|
|
1673
|
+
await server.persistOptimisticMutations([
|
|
1674
|
+
{
|
|
1675
|
+
...versionMutation,
|
|
1676
|
+
payload: mergedPayload,
|
|
1677
|
+
debounceCount: versionMutation.debounceCount + 1,
|
|
1678
|
+
timestamp: resentTimestamp
|
|
1679
|
+
}
|
|
1680
|
+
]);
|
|
1681
|
+
await expect2((async () => server.persistOptimisticMutations([
|
|
1682
|
+
{
|
|
1683
|
+
...versionMutation,
|
|
1684
|
+
payload: mergedPayload,
|
|
1685
|
+
debounceCount: versionMutation.debounceCount + 1,
|
|
1686
|
+
timestamp: resentTimestamp
|
|
1687
|
+
}
|
|
1688
|
+
]))()).rejects.toThrow("Mutation already synced");
|
|
1689
|
+
await tick();
|
|
1690
|
+
const finalPayload = { ref: holder.ref, mentions: [] };
|
|
1691
|
+
await server.persistOptimisticMutations([
|
|
1692
|
+
{
|
|
1693
|
+
...versionMutation,
|
|
1694
|
+
payload: finalPayload,
|
|
1695
|
+
debounceCount: versionMutation.debounceCount + 2,
|
|
1696
|
+
timestamp: new Date().toISOString()
|
|
1697
|
+
}
|
|
1698
|
+
]);
|
|
1699
|
+
const stored = await server.pageMutations({ size: 1000 });
|
|
1700
|
+
const versions = stored.filter((m) => m.operation.name === "updateBlockParagraphMentions");
|
|
1701
|
+
expect2(versions).toHaveLength(2);
|
|
1702
|
+
expect2(versions.map((m) => m.payload)).toContainEqual({
|
|
1703
|
+
ref: holder.ref,
|
|
1704
|
+
mentions: [second.ref]
|
|
1705
|
+
});
|
|
1706
|
+
expect2(versions.map((m) => m.payload)).toContainEqual(finalPayload);
|
|
1707
|
+
const replayed = (await replay(server)).changeSet(draft.ref);
|
|
1708
|
+
const replayedHolder = await replayed.readEntity(holder.ref);
|
|
1709
|
+
expect2(replayedHolder.data.mentions).toEqual([]);
|
|
1710
|
+
const replayedPost = await replayed.readEntity(post.ref);
|
|
1711
|
+
expect2(replayedPost.children.blocks).not.toContain(first.ref);
|
|
1712
|
+
});
|
|
1713
|
+
test("old client: a merged version and a write depending on it in one batch replay in order", async () => {
|
|
1714
|
+
const { server, queue, draft, changeSet, createParagraph, holder } = await setupClient();
|
|
1715
|
+
const first = await createParagraph();
|
|
1716
|
+
const second = await createParagraph();
|
|
1717
|
+
const [, versionMutation] = await changeSet.updateBlockParagraphMentions({
|
|
1718
|
+
ref: holder.ref,
|
|
1719
|
+
mentions: [first.ref]
|
|
1720
|
+
});
|
|
1721
|
+
queue.add([undefined, versionMutation]);
|
|
1722
|
+
await queue.flush();
|
|
1723
|
+
await createParagraph();
|
|
1724
|
+
await queue.flush();
|
|
1725
|
+
await tick();
|
|
1726
|
+
const [, version] = await changeSet.updateBlockParagraphMentions({
|
|
1727
|
+
ref: holder.ref,
|
|
1728
|
+
mentions: [second.ref]
|
|
1729
|
+
});
|
|
1730
|
+
const mergedVersion = {
|
|
1731
|
+
...versionMutation,
|
|
1732
|
+
payload: version.payload,
|
|
1733
|
+
debounceCount: versionMutation.debounceCount + 1,
|
|
1734
|
+
timestamp: version.timestamp
|
|
1735
|
+
};
|
|
1736
|
+
await tick();
|
|
1737
|
+
const [, deleteMutation] = await changeSet.deleteUnmentionedBlockParagraph({
|
|
1738
|
+
ref: first.ref,
|
|
1739
|
+
mentionedByRef: holder.ref
|
|
1740
|
+
});
|
|
1741
|
+
await tick();
|
|
1742
|
+
await server.persistOptimisticMutations([
|
|
1743
|
+
mergedVersion,
|
|
1744
|
+
deleteMutation
|
|
1745
|
+
]);
|
|
1746
|
+
const replayed = (await replay(server)).changeSet(draft.ref);
|
|
1747
|
+
const replayedHolder = await replayed.readEntity(holder.ref);
|
|
1748
|
+
expect2(replayedHolder.data.mentions).toEqual([second.ref]);
|
|
1749
|
+
});
|
|
1750
|
+
test("consecutive versions coalesce into the row after an intervening write", async () => {
|
|
1751
|
+
const { changeSet, createParagraph, holder } = await setupClient();
|
|
1752
|
+
const [, version1] = await changeSet.updateBlockParagraphMentions({
|
|
1753
|
+
ref: holder.ref,
|
|
1754
|
+
mentions: []
|
|
1755
|
+
});
|
|
1756
|
+
await tick();
|
|
1757
|
+
const mentioned = await createParagraph();
|
|
1758
|
+
await tick();
|
|
1759
|
+
const [, version2] = await changeSet.updateBlockParagraphMentions({
|
|
1760
|
+
ref: holder.ref,
|
|
1761
|
+
mentions: [mentioned.ref]
|
|
1762
|
+
});
|
|
1763
|
+
const [, version3] = await changeSet.updateBlockParagraphMentions({
|
|
1764
|
+
ref: holder.ref,
|
|
1765
|
+
mentions: []
|
|
1766
|
+
});
|
|
1767
|
+
expect2(version2.ref).not.toBe(version1.ref);
|
|
1768
|
+
expect2(version3.ref).toBe(version2.ref);
|
|
1769
|
+
expect2(version3.debounceCount).toBe(version2.debounceCount + 1);
|
|
1770
|
+
});
|
|
1771
|
+
test("another identity's write in the changeSet, or the identity's own write elsewhere, ends coalescing", async () => {
|
|
1772
|
+
const engineArgs = await generateArgs();
|
|
1773
|
+
const adapterA = await createAdapter({
|
|
1774
|
+
session: { identityRef: "User/A" },
|
|
1775
|
+
engineArgs
|
|
1776
|
+
});
|
|
1777
|
+
const adapterB = await createAdapter({
|
|
1778
|
+
session: { identityRef: "User/B" },
|
|
1779
|
+
engineArgs
|
|
1780
|
+
});
|
|
1781
|
+
const [post] = await adapterA.createPost({
|
|
1782
|
+
title: "Post",
|
|
1783
|
+
tags: []
|
|
1784
|
+
});
|
|
1785
|
+
const [draft] = await adapterA.createDraft({ postRef: post.ref });
|
|
1786
|
+
const changeSetA = adapterA.changeSet(draft.ref);
|
|
1787
|
+
const changeSetB = adapterB.changeSet(draft.ref);
|
|
1788
|
+
const [{ block: holder }] = await changeSetA.createBlockParagraph({
|
|
1789
|
+
parentRef: post.ref
|
|
1790
|
+
});
|
|
1791
|
+
const update = async () => {
|
|
1792
|
+
await tick();
|
|
1793
|
+
const [, mutation] = await changeSetA.updateBlockParagraphMentions({
|
|
1794
|
+
ref: holder.ref,
|
|
1795
|
+
mentions: []
|
|
1796
|
+
});
|
|
1797
|
+
return mutation;
|
|
1798
|
+
};
|
|
1799
|
+
const version1 = await update();
|
|
1800
|
+
await tick();
|
|
1801
|
+
await changeSetB.createBlockParagraph({ parentRef: post.ref });
|
|
1802
|
+
const version2 = await update();
|
|
1803
|
+
await tick();
|
|
1804
|
+
await adapterA.createPost({ title: "Elsewhere", tags: [] });
|
|
1805
|
+
const version3 = await update();
|
|
1806
|
+
await tick();
|
|
1807
|
+
await adapterB.createPost({ title: "Not A", tags: [] });
|
|
1808
|
+
const version4 = await update();
|
|
1809
|
+
expect2(version2.ref).not.toBe(version1.ref);
|
|
1810
|
+
expect2(version3.ref).not.toBe(version2.ref);
|
|
1811
|
+
expect2(version4.ref).toBe(version3.ref);
|
|
1812
|
+
});
|
|
1813
|
+
});
|
|
1434
1814
|
};
|
|
1435
1815
|
// src/inMemoryAdapter.ts
|
|
1436
1816
|
import { createInMemoryAdapter } from "@roc-db/in-memory";
|
|
@@ -2,6 +2,7 @@ import { Entity } from "roc-db";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
export declare const BlockParagraph: Entity<"BlockParagraph", z.ZodObject<{
|
|
4
4
|
content: z.ZodOptional<z.ZodString>;
|
|
5
|
+
mentions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
5
6
|
}, z.core.$strip>, z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
6
7
|
parent: z.ZodUnion<readonly [z.ZodType<`Post/${number}`, `Post/${number}`, z.core.$ZodTypeInternals<`Post/${number}`, `Post/${number}`>>, z.ZodUnion<readonly [z.ZodTemplateLiteral<`BlockParagraph/${number}`>, z.ZodTemplateLiteral<`BlockRow/${number}`>]>]>;
|
|
7
8
|
}, z.core.$strip>, z.ZodObject<{}, z.core.$strip>, false>;
|
|
@@ -18,6 +18,7 @@ export declare const entities: (import("roc-db").Entity<"Draft", import("zod").Z
|
|
|
18
18
|
author: import("zod").ZodOptional<import("zod").ZodTemplateLiteral<`User/${number}`>>;
|
|
19
19
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{}, import("zod/v4/core").$strip>, false> | import("roc-db").Entity<"BlockParagraph", import("zod").ZodObject<{
|
|
20
20
|
content: import("zod").ZodOptional<import("zod").ZodString>;
|
|
21
|
+
mentions: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
21
22
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
22
23
|
parent: import("zod").ZodUnion<readonly [import("zod").ZodType<`Post/${number}`, `Post/${number}`, import("zod/v4/core").$ZodTypeInternals<`Post/${number}`, `Post/${number}`>>, import("zod").ZodUnion<readonly [import("zod").ZodTemplateLiteral<`BlockParagraph/${number}`>, import("zod").ZodTemplateLiteral<`BlockRow/${number}`>]>]>;
|
|
23
24
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{}, import("zod/v4/core").$strip>, false> | import("roc-db").Entity<"BlockRow", import("zod").ZodObject<{}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const deleteUnmentionedBlockParagraph: import("roc-db").WriteOperation<"deleteUnmentionedBlockParagraph", z.ZodObject<{
|
|
3
|
+
ref: z.ZodTemplateLiteral<`BlockParagraph/${number}`>;
|
|
4
|
+
mentionedByRef: z.ZodTemplateLiteral<`BlockParagraph/${number}`>;
|
|
5
|
+
}, z.core.$strict>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const updateBlockParagraphMentions: import("roc-db").WriteOperation<"updateBlockParagraphMentions", z.ZodObject<{
|
|
3
|
+
ref: z.ZodTemplateLiteral<`BlockParagraph/${number}`>;
|
|
4
|
+
mentions: z.ZodArray<z.ZodTemplateLiteral<`BlockParagraph/${number}`>>;
|
|
5
|
+
}, z.core.$strict>>;
|
|
6
|
+
export declare const setBlockParagraphMentions: import("roc-db").WriteOperation<"setBlockParagraphMentions", z.ZodObject<{
|
|
7
|
+
ref: z.ZodTemplateLiteral<`BlockParagraph/${number}`>;
|
|
8
|
+
mentions: z.ZodArray<z.ZodTemplateLiteral<`BlockParagraph/${number}`>>;
|
|
9
|
+
}, z.core.$strict>>;
|
|
@@ -12,6 +12,7 @@ export declare const BlockParagraphSchema: z.ZodObject<{
|
|
|
12
12
|
}, z.core.$strict>>;
|
|
13
13
|
data: z.ZodNonOptional<z.ZodObject<{
|
|
14
14
|
content: z.ZodOptional<z.ZodString>;
|
|
15
|
+
mentions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
15
16
|
}, z.core.$strip>>;
|
|
16
17
|
children: z.ZodNonOptional<z.ZodObject<{}, z.core.$strip>>;
|
|
17
18
|
parents: z.ZodNonOptional<z.ZodObject<{
|