Skip to content

Commit 918bddd

Browse files
authored
Merge pull request #82 from gadget-inc/fix-snapshot-references-in-maps
Ensure we properly snapshot reference types in maps/arrays
2 parents d23fa86 + 4bb5158 commit 918bddd

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

spec/getSnapshot.spec.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { IsExact } from "conditional-type-checks";
22
import { assert } from "conditional-type-checks";
3-
import type { SnapshotOut } from "../src";
3+
import type { IReferenceType, SnapshotOut } from "../src";
44
import { types } from "../src";
55
import { getSnapshot } from "../src/api";
66
import { TestClassModel } from "./fixtures/TestClassModel";
@@ -99,4 +99,35 @@ describe("getSnapshot", () => {
9999
verifySnapshot(snapshot);
100100
assert<IsExact<typeof snapshot.map.test_key, SnapshotOut<typeof NamedThing>>>(true);
101101
});
102+
103+
test("snapshots a reference type correctly in a map / array", () => {
104+
const RootType = types.model({
105+
things: types.map(NamedThing),
106+
refMap: types.map(types.reference(NamedThing)),
107+
refArray: types.array(types.reference(NamedThing)),
108+
});
109+
110+
const instance = RootType.createReadOnly({
111+
things: {
112+
a: { key: "a", name: "test a" },
113+
b: { key: "b", name: "test b" },
114+
},
115+
refMap: { a: "a", b: "b" },
116+
refArray: ["a", "b"],
117+
});
118+
119+
const snapshot = getSnapshot(instance);
120+
assert<IsExact<typeof snapshot.things.test_key, SnapshotOut<typeof NamedThing>>>(true);
121+
assert<IsExact<typeof snapshot.refMap.test_key, SnapshotOut<IReferenceType<typeof NamedThing>>>>(true);
122+
expect(snapshot.refMap.a).toEqual("a");
123+
expect(snapshot.refMap.b).toEqual("b");
124+
expect(snapshot.refArray[0]).toEqual("a");
125+
expect(snapshot.refArray[1]).toEqual("b");
126+
127+
const reconstructedInstance = RootType.createReadOnly(snapshot);
128+
expect(reconstructedInstance.refMap.get("a")?.name).toEqual("test a");
129+
expect(reconstructedInstance.refMap.get("b")?.name).toEqual("test b");
130+
expect(reconstructedInstance.refArray[0]?.name).toEqual("test a");
131+
expect(reconstructedInstance.refArray[1]?.name).toEqual("test b");
132+
});
102133
});

src/snapshot.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { IStateTreeNode as MSTStateTreeNode } from "mobx-state-tree";
22
import { getSnapshot as mstGetSnapshot, isStateTreeNode as mstIsStateTreeNode } from "mobx-state-tree";
33
import { getType, isModelType, isReferenceType, isStateTreeNode } from "./api";
4-
import { QuickArray } from "./array";
5-
import { QuickMap } from "./map";
4+
import { ArrayType, QuickArray } from "./array";
5+
import { MapType, QuickMap } from "./map";
66
import { $identifier } from "./symbols";
77
import type { IAnyType, IStateTreeNode, SnapshotOut } from "./types";
88

@@ -16,11 +16,21 @@ export function getSnapshot<T extends IAnyType>(value: IStateTreeNode<T>): Snaps
1616

1717
const snapshot = (value: any): unknown => {
1818
if (value instanceof QuickArray) {
19-
return Array.from(value.map((v) => snapshot(v)));
19+
const type = getType(value) as ArrayType<IAnyType>;
20+
const childrenAreReferences = isReferenceType(type.childrenType);
21+
22+
return Array.from(value.map((v) => (childrenAreReferences ? v[$identifier] : snapshot(v))));
2023
}
2124

2225
if (value instanceof QuickMap) {
23-
return Object.fromEntries(Array.from(value.entries()).map(([k, v]) => [k, snapshot(v)]));
26+
const type = getType(value) as MapType<IAnyType>;
27+
const childrenAreReferences = isReferenceType(type.childrenType);
28+
29+
return Object.fromEntries(
30+
Array.from(value.entries()).map(([k, v]) => {
31+
return [k, childrenAreReferences ? v[$identifier] : snapshot(v)];
32+
})
33+
);
2434
}
2535

2636
if (value instanceof Date) {

0 commit comments

Comments
 (0)