Suite of AT Protocol TypeScript libraries built on web standards
1import type { Cid } from "@atp/lex/data";
2import { BlockMap } from "./block-map.ts";
3import { CidSet } from "./cid-set.ts";
4import { type MST, mstDiff, type NodeEntry } from "./mst/index.ts";
5
6export class DataDiff {
7 adds: Record<string, DataAdd> = {};
8 updates: Record<string, DataUpdate> = {};
9 deletes: Record<string, DataDelete> = {};
10
11 newMstBlocks: BlockMap = new BlockMap();
12 newLeafCids: CidSet = new CidSet();
13 removedCids: CidSet = new CidSet();
14
15 static of(curr: MST, prev: MST | null): Promise<DataDiff> {
16 return mstDiff(curr, prev);
17 }
18
19 async nodeAdd(node: NodeEntry) {
20 if (node.isLeaf()) {
21 this.leafAdd(node.key, node.value);
22 } else {
23 const data = await node.serialize();
24 this.treeAdd(data.cid, data.bytes);
25 }
26 }
27
28 async nodeDelete(node: NodeEntry) {
29 if (node.isLeaf()) {
30 const key = node.key;
31 const cid = node.value;
32 this.deletes[key] = { key, cid };
33 this.removedCids.add(cid);
34 } else {
35 const cid = await node.getPointer();
36 this.treeDelete(cid);
37 }
38 }
39
40 leafAdd(key: string, cid: Cid) {
41 this.adds[key] = { key, cid };
42 if (this.removedCids.has(cid)) {
43 this.removedCids.delete(cid);
44 } else {
45 this.newLeafCids.add(cid);
46 }
47 }
48
49 leafUpdate(key: string, prev: Cid, cid: Cid) {
50 if (prev.equals(cid)) return;
51 this.updates[key] = { key, prev, cid };
52 this.removedCids.add(prev);
53 this.newLeafCids.add(cid);
54 }
55
56 leafDelete(key: string, cid: Cid) {
57 this.deletes[key] = { key, cid };
58 if (this.newLeafCids.has(cid)) {
59 this.newLeafCids.delete(cid);
60 } else {
61 this.removedCids.add(cid);
62 }
63 }
64
65 treeAdd(cid: Cid, bytes: Uint8Array) {
66 if (this.removedCids.has(cid)) {
67 this.removedCids.delete(cid);
68 } else {
69 this.newMstBlocks.set(cid, bytes);
70 }
71 }
72
73 treeDelete(cid: Cid) {
74 if (this.newMstBlocks.has(cid)) {
75 this.newMstBlocks.delete(cid);
76 } else {
77 this.removedCids.add(cid);
78 }
79 }
80
81 addList(): DataAdd[] {
82 return Object.values(this.adds);
83 }
84
85 updateList(): DataUpdate[] {
86 return Object.values(this.updates);
87 }
88
89 deleteList(): DataDelete[] {
90 return Object.values(this.deletes);
91 }
92
93 updatedKeys(): string[] {
94 const keys = [
95 ...Object.keys(this.adds),
96 ...Object.keys(this.updates),
97 ...Object.keys(this.deletes),
98 ];
99 return [...new Set(keys)];
100 }
101}
102
103export type DataAdd = {
104 key: string;
105 cid: Cid;
106};
107
108export type DataUpdate = {
109 key: string;
110 prev: Cid;
111 cid: Cid;
112};
113
114export type DataDelete = {
115 key: string;
116 cid: Cid;
117};