Repository navigation
Expand file tree
/
Copy pathoptimisticProxy.ts
More file actions
124 lines (111 loc) · 2.94 KB
/
Copy pathoptimisticProxy.ts
File metadata and controls
124 lines (111 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import type {
DataId,
IsographEnvironment,
IsographStore,
StoreRecord,
TypeName,
} from './IsographEnvironment';
function createLayerProxy<T>(
object: {
[key: string]: T | null;
},
optimisticObject: {
[key: string]: T | null;
},
getter: (
value: T | null | undefined,
optimisticValue: T | undefined,
p: string,
) => T | null | undefined,
): {
[key: string]: T | null;
} {
return new Proxy(optimisticObject, {
get(target, p: string) {
let optimisticValue = target[p];
if (optimisticValue === null) {
return optimisticValue;
}
const value = object[p];
if (optimisticValue === undefined && value == null) {
return value;
}
return getter(value, optimisticValue, p);
},
has(target, p) {
return Reflect.has(target, p) || Reflect.has(object, p);
},
ownKeys(target) {
const merged = {
...object,
...target,
};
return Reflect.ownKeys(merged);
},
set(target, p: string, value: any) {
return Reflect.set(target, p, value);
},
getOwnPropertyDescriptor(target, p: string) {
return (
Reflect.getOwnPropertyDescriptor(target, p) ??
Reflect.getOwnPropertyDescriptor(object, p)
);
},
});
}
export function createOptimisticProxy(
store: IsographStore,
optimisticLayer: OptimisticLayer,
): OptimisticLayer {
return createLayerProxy(
store,
optimisticLayer,
(recordsById, optimisticRecordsById, p) => {
optimisticRecordsById = optimisticLayer[p] ??= {};
return createLayerProxy(
recordsById ?? {},
optimisticRecordsById,
(storeRecord, optimisticStoreRecord, p) => {
optimisticStoreRecord = optimisticRecordsById[p] ??= {};
return createLayerProxy(
storeRecord ?? {},
optimisticStoreRecord,
(value, optimisticValue) =>
optimisticValue === undefined ? value : optimisticValue,
);
},
);
},
);
}
export type OptimisticLayer = {
[index: TypeName]: {
[index: DataId]: StoreRecord | null;
} | null;
};
export function mergeOptimisticLayer(environment: IsographEnvironment): void {
for (const [typeName, patchById] of Object.entries(
environment.optimisticLayer,
)) {
let recordById = environment.store[typeName];
if (patchById === null) {
environment.store[typeName] = null;
continue;
}
recordById = environment.store[typeName] ??= {};
for (const [recordId, patch] of Object.entries(patchById)) {
const data = recordById[recordId];
if (patch == null || data == null) {
recordById[recordId] = patch;
} else {
Object.assign(data, patch);
}
}
}
resetOptimisticLayer(environment);
}
export function resetOptimisticLayer(environment: IsographEnvironment) {
for (const key in environment.optimisticLayer) {
delete environment.optimisticLayer[key];
}
}