Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/@adiwajshing/keyed-db/lib/KeyedDB.js
1126 views
1
"use strict";
2
var __importDefault = (this && this.__importDefault) || function (mod) {
3
return (mod && mod.__esModule) ? mod : { "default": mod };
4
};
5
Object.defineProperty(exports, "__esModule", { value: true });
6
const BinarySearch_1 = __importDefault(require("./BinarySearch"));
7
class KeyedDB {
8
/**
9
* @param key Return the unique key used to sort items
10
* @param id The unique ID for the items
11
*/
12
constructor(key, id) {
13
this.key = key;
14
this.idGetter = id || (v => this.key.key(v).toString());
15
this.dict = {};
16
this.array = [];
17
}
18
get length() {
19
return this.array.length;
20
}
21
get first() {
22
return this.array[0];
23
}
24
get last() {
25
return this.array[this.array.length - 1];
26
}
27
toJSON() {
28
return this.array;
29
}
30
/**
31
* Inserts items into the DB in klogN time.
32
* Where k is the number of items being inserted.
33
* @param values
34
*/
35
insert(...values) {
36
values.forEach(v => this._insertSingle(v));
37
}
38
/**
39
* Upserts items into the DB in 2klogN time.
40
* Where k is the number of items being inserted.
41
*
42
* If a duplicate is found, it is deleted first and then the new one is inserted
43
* @param values
44
* @returns list of updated values
45
*/
46
upsert(...values) {
47
const updates = [];
48
values.forEach(v => {
49
if (!v)
50
return;
51
const deleted = this.deleteById(this.idGetter(v), false);
52
this._insertSingle(v);
53
// add to updates
54
deleted && updates.push(v);
55
});
56
return updates;
57
}
58
/**
59
* Inserts items only if they are not present in the DB
60
* @param values
61
* @returns list of all the inserted values
62
*/
63
insertIfAbsent(...values) {
64
const insertions = [];
65
values.forEach(v => {
66
if (!v)
67
return;
68
// if ID is present
69
const presentValue = this.get(this.idGetter(v));
70
if (presentValue)
71
return;
72
// if key is present
73
const presentKey = this.firstIndex(v);
74
if (this.array[presentKey] && this.key.key(this.array[presentKey]) === this.key.key(v))
75
return;
76
this.insert(v);
77
insertions.push(v);
78
});
79
return insertions;
80
}
81
/**
82
* Deletes an item indexed by the ID
83
* @param id
84
* @param assertPresent
85
*/
86
deleteById(id, assertPresent = true) {
87
const value = this.get(id);
88
if (!value) {
89
if (assertPresent)
90
throw new Error(`Value not found`);
91
else
92
return;
93
}
94
return this.delete(value);
95
}
96
delete(value) {
97
const index = this.firstIndex(value);
98
if (index < 0 || index >= this.array.length || this.key.key(value) !== this.key.key(this.array[index])) {
99
return null;
100
}
101
delete this.dict[this.idGetter(value)];
102
return this.array.splice(index, 1)[0];
103
}
104
slice(start, end) {
105
const db = new KeyedDB(this.key, this.idGetter);
106
db.array = this.array.slice(start, end);
107
db.array.forEach(item => db.dict[this.idGetter(item)] = item);
108
return db;
109
}
110
/** Clears the DB */
111
clear() {
112
this.array = [];
113
this.dict = {};
114
}
115
get(id) {
116
return this.dict[id];
117
}
118
all() {
119
return this.array;
120
}
121
/**
122
* Updates a value specified by the ID
123
* and adjusts its position in the DB after an update if required
124
* @param id
125
* @param update
126
*/
127
update(id, update) {
128
const value = this.get(id);
129
if (value) {
130
const idx = this.firstIndex(value);
131
if (idx >= 0 && idx < this.array.length && this.idGetter(this.array[idx]) === id) {
132
const oldKey = this.key.key(value);
133
update(value);
134
const newKey = this.key.key(value);
135
if (newKey !== oldKey) {
136
delete this.dict[id];
137
this.array.splice(idx, 1);
138
this._insertSingle(value);
139
return 2;
140
}
141
return 1;
142
}
143
}
144
}
145
/**
146
* @deprecated see `update`
147
*/
148
updateKey(value, update) {
149
return this.update(this.idGetter(value), update);
150
}
151
filter(predicate) {
152
const db = new KeyedDB(this.key, this.idGetter);
153
db.array = this.array.filter((value, index) => {
154
if (predicate(value, index)) {
155
db.dict[this.idGetter(value)] = value;
156
return true;
157
}
158
});
159
return db;
160
}
161
/**
162
* Get the values of the data in a paginated manner
163
* @param value the value itself beyond which the content is to be retreived
164
* @param limit max number of items to retreive
165
* @param predicate optional filter
166
* @param mode whether to get the content `before` the cursor or `after` the cursor; default=`after`
167
*/
168
paginatedByValue(value, limit, predicate, mode = 'after') {
169
return this.paginated(value && this.key.key(value), limit, predicate, mode);
170
}
171
/**
172
* Get the values of the data in a paginated manner
173
* @param value the cursor beyond which the content is to be retreived
174
* @param limit max number of items to retreive
175
* @param predicate optional filter
176
* @param mode whether to get the content `before` the cursor or `after` the cursor; default=`after`
177
*/
178
paginated(cursor, limit, predicate, mode = 'after') {
179
let index = mode === 'after' ? 0 : this.array.length;
180
if (cursor !== null && typeof cursor !== 'undefined') {
181
index = BinarySearch_1.default(this.array, v => this.key.compare(cursor, this.key.key(v)));
182
if (index < 0)
183
index = 0;
184
if (this.key.key(this.array[index]) === cursor)
185
index += (mode === 'after' ? 1 : 0);
186
}
187
return this.filtered(index, limit, mode, predicate);
188
}
189
_insertSingle(value) {
190
if (!value)
191
throw new Error('falsey value');
192
const valueID = this.idGetter(value);
193
if (this.get(valueID)) {
194
throw new Error('duplicate ID being inserted: ' + valueID);
195
}
196
if (this.array.length > 0) {
197
const index = this.firstIndex(value);
198
if (index >= this.array.length)
199
this.array.push(value);
200
else if (index < 0)
201
this.array.unshift(value);
202
else if (this.key.key(value) !== this.key.key(this.array[index]))
203
this.array.splice(index, 0, value);
204
else
205
throw new Error(`duplicate key: ${this.key.key(value)}, of inserting: ${valueID}, present: ${this.idGetter(this.array[index])}`);
206
}
207
else {
208
this.array.push(value);
209
}
210
this.dict[valueID] = value;
211
}
212
filtered(start, count, mode, predicate) {
213
let arr;
214
if (mode === 'after') {
215
if (predicate) {
216
arr = [];
217
for (let item of this.array.slice(start)) {
218
predicate(item, start + arr.length) && arr.push(item);
219
if (arr.length >= count)
220
break;
221
}
222
}
223
else
224
arr = this.array.slice(start, start + count);
225
}
226
else if (mode === 'before') {
227
if (predicate) {
228
arr = [];
229
for (let i = start - 1; i >= 0; i--) {
230
let item = this.array[i];
231
predicate(item, start + arr.length) && arr.unshift(item);
232
if (arr.length >= count)
233
break;
234
}
235
}
236
else
237
arr = this.array.slice(Math.max(start - count, 0), start);
238
}
239
return arr;
240
}
241
firstIndex(value) {
242
const valueKey = this.key.key(value);
243
return BinarySearch_1.default(this.array, v => this.key.compare(valueKey, this.key.key(v)));
244
}
245
}
246
exports.default = KeyedDB;
247
248