-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
154 lines (135 loc) · 4.35 KB
/
index.ts
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import {
applyPatches,
enableMapSet,
enablePatches,
immerable,
Patch,
produceWithPatches,
Immutable,
Draft,
} from 'immer';
enablePatches();
enableMapSet();
export type Items<T> = ReadonlyMap<string, Immutable<T>>;
type OpReturnType<T> = {
itemsDraft: Items<Immutable<T>>;
patches: Patch[];
inversePatches: Patch[];
confirm: () => Items<T>;
};
export interface BatchUpdate<T> {
id: string;
itemProps: Partial<T>;
}
export class ItemStore<T> {
[immerable] = true;
public items: Items<T> = new Map();
/**
* Returned on add/update/remove/batchUpdate operations and allows to save the changes to the store
* @param patches - patches array
* @returns updated items map
*/
private confirm = (patches: Patch[]): Items<T> => {
this.applyPatches(patches);
return this.items;
};
// Operation methods
/**
* Gets an item by id
* @param id - string
* @returns item or null
*/
public get(id: string): Immutable<T> | null {
return this.items.get(id) || null;
}
/**
* Creates a draft of adding a new item to the store
* @param id - string
* @param item - your predefined item type
* @returns itemsDraft (the draft), patches (describes what changed), inversePatches (describes inverse changes), confirm (saves items draft by appling patches)
*/
public add(id: string, item: Draft<Immutable<T>>): OpReturnType<T> {
const [items, patches, inversePatches] = produceWithPatches(this.items, draft => {
draft.set(id, item);
});
return {
itemsDraft: items,
patches,
inversePatches,
confirm: () => this.confirm(patches),
};
}
/**
* Creates a draft of updating an item with new values
* @param id - string
* @param itemProps - your predefined item type (could be partial)
* @returns itemsDraft (the draft), patches (describes what changed), inversePatches (describes inverse changes), confirm (saves items draft by appling patches)
*/
public update(id: string, itemProps: Partial<T>): OpReturnType<T> {
const [items, patches, inversePatches] = produceWithPatches(this.items, draft => {
const client = draft.get(id);
if (client) {
Object.assign(client, itemProps);
}
});
return {
itemsDraft: items,
patches,
inversePatches,
confirm: () => this.confirm(patches),
};
}
/**
* Creates a draft of removing an item from the store
* @param id - string
* @returns itemsDraft (the draft), patches (describes what changed), inversePatches (describes inverse changes), confirm (saves items draft by appling patches)
*/
public remove(id: string): OpReturnType<T> {
const [items, patches, inversePatches] = produceWithPatches(this.items, draft => {
draft.delete(id);
});
return {
itemsDraft: items,
patches,
inversePatches,
confirm: () => this.confirm(patches),
};
}
/**
* Creates a draft of batch updating items with new values
* @param updates - id: strings, itemProps: item type (partial)
* @returns itemsDraft (the draft), patches (describes what changed), inversePatches (describes inverse changes), confirm (saves items draft by appling patches)
*/
public batchUpdate(updates: BatchUpdate<T>[]): OpReturnType<T> {
const [items, patches, inversePatches] = produceWithPatches(this.items, draft => {
updates.forEach(({ id, itemProps }) => {
const client = draft.get(id);
if (client) {
Object.assign(client, itemProps);
}
});
});
return {
itemsDraft: items,
patches,
inversePatches,
confirm: () => this.confirm(patches),
};
}
/**
* Applies patches to the store items
* @param patches - patches array
* @returns updated items map
*/
public applyPatches(patches: Patch[]): Items<T> {
this.items = applyPatches(this.items, patches);
return this.items;
}
/**
* Transforms map of items to an array when required
* @returns array of items
*/
public get itemsArray(): Immutable<T>[] {
return Array.from(this.items.values());
}
}