@jsonkit/db 2.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -86
- package/dist/cjs/index.cjs +140 -156
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +141 -155
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.ts +154 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -12
- package/dist/types/file/__tests__/multiEntryFileDb.test.d.ts +0 -1
- package/dist/types/file/__tests__/singleEntryFileDb.test.d.ts +0 -1
- package/dist/types/file/files.d.ts +0 -44
- package/dist/types/file/multiEntryFileDb.d.ts +0 -28
- package/dist/types/file/singleEntryFileDb.d.ts +0 -13
- package/dist/types/index.d.ts +0 -5
- package/dist/types/memory/__tests__/multiEntryMemDb.test.d.ts +0 -1
- package/dist/types/memory/__tests__/singleEntryMemDb.test.d.ts +0 -1
- package/dist/types/memory/multiEntryMemDb.d.ts +0 -19
- package/dist/types/memory/singleEntryMemDb.d.ts +0 -9
- package/dist/types/types.d.ts +0 -55
package/README.md
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
The package exposes two core concepts:
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
- **Single-entry databases** – manage exactly one JSON-serializable object.
|
|
8
|
+
- **Multi-entry databases** – manage collections of identifiable records keyed by an `id`.
|
|
9
9
|
|
|
10
10
|
Both concepts are available in **file-backed** and **in-memory** variants.
|
|
11
11
|
|
|
@@ -19,67 +19,28 @@ npm install @jsonkit/db
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
## Core Types
|
|
23
|
-
|
|
24
|
-
### `Identifiable`
|
|
25
|
-
|
|
26
|
-
```ts
|
|
27
|
-
type Identifiable = { id: string }
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
All multi-entry databases require entries to have a string `id`.
|
|
31
|
-
|
|
32
|
-
### `Promisable<T>`
|
|
33
|
-
|
|
34
|
-
A value or a promise of a value.
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
type Promisable<T> = T | Promise<T>
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### `PredicateFn<T>`
|
|
41
|
-
|
|
42
|
-
Used for filtering entries.
|
|
43
|
-
|
|
44
|
-
```ts
|
|
45
|
-
type PredicateFn<T extends Identifiable> = (entry: T) => boolean
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### `DeleteManyOutput`
|
|
49
|
-
|
|
50
|
-
Returned by bulk delete operations.
|
|
51
|
-
|
|
52
|
-
```ts
|
|
53
|
-
type DeleteManyOutput = {
|
|
54
|
-
deletedIds: string[]
|
|
55
|
-
ignoredIds: string[]
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
---
|
|
60
|
-
|
|
61
22
|
## Multi-entry Databases
|
|
62
23
|
|
|
63
24
|
Multi-entry databases manage collections of entries keyed by `id`.
|
|
64
25
|
|
|
65
26
|
### Common API (`MultiEntryDb<T>`)
|
|
66
27
|
|
|
67
|
-
All multi-entry implementations expose the same
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
28
|
+
All multi-entry implementations expose the same methods:
|
|
29
|
+
|
|
30
|
+
- `create(entry)`
|
|
31
|
+
- `getById(id)`
|
|
32
|
+
- `getByIdOrThrow(id)`
|
|
33
|
+
- `getWhere(predicate, pagination?)`
|
|
34
|
+
- `getAll(ids?)`
|
|
35
|
+
- `getAllIds()`
|
|
36
|
+
- `update(id, updater)`
|
|
37
|
+
- `deleteById(id)`
|
|
38
|
+
- `deleteByIds(ids)`
|
|
39
|
+
- `deleteWhere(predicate)`
|
|
40
|
+
- `exists(id)`
|
|
41
|
+
- `countAll()`
|
|
42
|
+
- `countWhere(predicate)`
|
|
43
|
+
- `destroy()`
|
|
83
44
|
|
|
84
45
|
Updates are **partial merges**, and changing an entry’s `id` during an update is supported.
|
|
85
46
|
|
|
@@ -97,9 +58,9 @@ const db = new MultiEntryFileDb<User>('./data/users')
|
|
|
97
58
|
|
|
98
59
|
#### Behavior
|
|
99
60
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
61
|
+
- Each entry is stored as `<id>.json` in the provided directory.
|
|
62
|
+
- The directory is created implicitly as files are written.
|
|
63
|
+
- IDs are validated to prevent path traversal by default.
|
|
103
64
|
|
|
104
65
|
#### Constructor
|
|
105
66
|
|
|
@@ -116,9 +77,9 @@ new MultiEntryFileDb<T>(dirpath, options?)
|
|
|
116
77
|
|
|
117
78
|
#### Notes
|
|
118
79
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
80
|
+
- Failed reads (missing file or invalid JSON) return `null`.
|
|
81
|
+
- `destroy()` deletes the entire directory.
|
|
82
|
+
- Intended for development, prototyping, and small datasets.
|
|
122
83
|
|
|
123
84
|
---
|
|
124
85
|
|
|
@@ -134,9 +95,9 @@ const db = new MultiEntryMemDb<User>()
|
|
|
134
95
|
|
|
135
96
|
#### Behavior
|
|
136
97
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
98
|
+
- Fast, ephemeral storage.
|
|
99
|
+
- Ideal for tests and short-lived processes.
|
|
100
|
+
- `destroy()` clears all entries.
|
|
140
101
|
|
|
141
102
|
---
|
|
142
103
|
|
|
@@ -146,10 +107,10 @@ Single-entry databases manage **exactly one value**, often used for configuratio
|
|
|
146
107
|
|
|
147
108
|
### Common API (`SingleEntryDb<T>`)
|
|
148
109
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
110
|
+
- `isInited()`
|
|
111
|
+
- `read()`
|
|
112
|
+
- `write(entry | updater)`
|
|
113
|
+
- `delete()`
|
|
153
114
|
|
|
154
115
|
`write` supports either replacing the entry or partially updating it via an updater function.
|
|
155
116
|
|
|
@@ -167,9 +128,9 @@ const db = new SingleEntryFileDb<AppConfig>('./config.json')
|
|
|
167
128
|
|
|
168
129
|
#### Behavior
|
|
169
130
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
131
|
+
- Reads and writes a single JSON file.
|
|
132
|
+
- `isInited()` checks file existence.
|
|
133
|
+
- `read()` throws if the file does not exist.
|
|
173
134
|
|
|
174
135
|
#### Constructor
|
|
175
136
|
|
|
@@ -177,7 +138,7 @@ const db = new SingleEntryFileDb<AppConfig>('./config.json')
|
|
|
177
138
|
new SingleEntryFileDb<T>(filepath, parser?)
|
|
178
139
|
```
|
|
179
140
|
|
|
180
|
-
|
|
141
|
+
- `parser` defaults to `JSON`.
|
|
181
142
|
|
|
182
143
|
---
|
|
183
144
|
|
|
@@ -193,9 +154,9 @@ const db = new SingleEntryMemDb<AppConfig>()
|
|
|
193
154
|
|
|
194
155
|
#### Behavior
|
|
195
156
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
157
|
+
- Optional initial value.
|
|
158
|
+
- `read()` throws if uninitialized.
|
|
159
|
+
- `delete()` resets the entry to `null`.
|
|
199
160
|
|
|
200
161
|
---
|
|
201
162
|
|
|
@@ -217,20 +178,67 @@ const allUsers = await users.getAll()
|
|
|
217
178
|
|
|
218
179
|
## Use Cases
|
|
219
180
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
181
|
+
- Rapid application prototyping
|
|
182
|
+
- CLI tools
|
|
183
|
+
- Small internal services
|
|
184
|
+
- Tests and mocks
|
|
185
|
+
- Configuration and state persistence
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Core Types
|
|
190
|
+
|
|
191
|
+
### `Identifiable`
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
type Identifiable = { id: string }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
All multi-entry databases require entries to have a string `id`.
|
|
198
|
+
|
|
199
|
+
### `Promisable<T>`
|
|
200
|
+
|
|
201
|
+
A value or a promise of a value.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
type Promisable<T> = T | Promise<T>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### `PredicateFn<T>`
|
|
208
|
+
|
|
209
|
+
Used for filtering entries.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
type PredicateFn<T extends Identifiable> = (entry: T) => boolean
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### `PaginationInput`
|
|
216
|
+
|
|
217
|
+
Used for filtering entries.
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
type PredicateFn<T extends Identifiable> = (entry: T) => boolean
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### `DeleteManyOutput`
|
|
224
|
+
|
|
225
|
+
Returned by bulk delete operations.
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
type DeleteManyOutput = {
|
|
229
|
+
deletedIds: string[]
|
|
230
|
+
ignoredIds: string[]
|
|
231
|
+
}
|
|
232
|
+
```
|
|
225
233
|
|
|
226
234
|
---
|
|
227
235
|
|
|
228
236
|
## Non-goals
|
|
229
237
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
238
|
+
- Concurrency control
|
|
239
|
+
- High-performance querying
|
|
240
|
+
- Large datasets
|
|
241
|
+
- ACID guarantees
|
|
234
242
|
|
|
235
243
|
For these, a dedicated database is recommended.
|
|
236
244
|
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -27,16 +27,112 @@ var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
|
27
27
|
var fsSync__namespace = /*#__PURE__*/_interopNamespaceDefault(fsSync);
|
|
28
28
|
var readline__namespace = /*#__PURE__*/_interopNamespaceDefault(readline);
|
|
29
29
|
|
|
30
|
+
class MultiEntryDb {
|
|
31
|
+
async getByIdOrThrow(id) {
|
|
32
|
+
const entry = await this.getById(id);
|
|
33
|
+
if (!entry)
|
|
34
|
+
throw new Error(`Entry with id '${id}' does not exist`);
|
|
35
|
+
return entry;
|
|
36
|
+
}
|
|
37
|
+
async getWhere(predicate, pagination) {
|
|
38
|
+
let totalMatched = 0;
|
|
39
|
+
const entries = [];
|
|
40
|
+
if (!pagination) {
|
|
41
|
+
for await (const entry of this.iterEntries()) {
|
|
42
|
+
const isMatch = predicate(entry);
|
|
43
|
+
if (isMatch)
|
|
44
|
+
entries.push(entry);
|
|
45
|
+
}
|
|
46
|
+
return entries;
|
|
47
|
+
}
|
|
48
|
+
const { take, page } = pagination;
|
|
49
|
+
const skip = pagination.skip ?? 0;
|
|
50
|
+
const startIndex = (page - 1) * take + skip;
|
|
51
|
+
const endIndex = startIndex + take;
|
|
52
|
+
for await (const entry of this.iterEntries()) {
|
|
53
|
+
const isMatch = predicate(entry);
|
|
54
|
+
if (isMatch) {
|
|
55
|
+
if (totalMatched >= startIndex && totalMatched < endIndex) {
|
|
56
|
+
entries.push(entry);
|
|
57
|
+
}
|
|
58
|
+
totalMatched++;
|
|
59
|
+
if (totalMatched >= endIndex)
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return entries;
|
|
64
|
+
}
|
|
65
|
+
getAll() {
|
|
66
|
+
return this.getWhere(() => true);
|
|
67
|
+
}
|
|
68
|
+
async getAllIds() {
|
|
69
|
+
const ids = [];
|
|
70
|
+
for await (const id of this.iterIds()) {
|
|
71
|
+
ids.push(id);
|
|
72
|
+
}
|
|
73
|
+
return ids;
|
|
74
|
+
}
|
|
75
|
+
deleteByIds(ids) {
|
|
76
|
+
return this.deleteWhere((entry) => ids.includes(entry.id));
|
|
77
|
+
}
|
|
78
|
+
async deleteWhere(predicate) {
|
|
79
|
+
const deletedIds = [];
|
|
80
|
+
const ignoredIds = [];
|
|
81
|
+
for await (const entry of this.iterEntries()) {
|
|
82
|
+
if (!predicate(entry))
|
|
83
|
+
continue;
|
|
84
|
+
const didDelete = await this.deleteById(entry.id);
|
|
85
|
+
if (didDelete) {
|
|
86
|
+
deletedIds.push(entry.id);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
ignoredIds.push(entry.id);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { deletedIds, ignoredIds };
|
|
93
|
+
}
|
|
94
|
+
async exists(id) {
|
|
95
|
+
const entry = await this.getById(id);
|
|
96
|
+
return entry !== null;
|
|
97
|
+
}
|
|
98
|
+
countAll() {
|
|
99
|
+
return this.countWhere(() => true);
|
|
100
|
+
}
|
|
101
|
+
async countWhere(predicate, pagination) {
|
|
102
|
+
let totalMatched = 0;
|
|
103
|
+
let count = 0;
|
|
104
|
+
if (!pagination) {
|
|
105
|
+
for await (const entry of this.iterEntries()) {
|
|
106
|
+
const isMatch = predicate(entry);
|
|
107
|
+
if (isMatch)
|
|
108
|
+
count++;
|
|
109
|
+
}
|
|
110
|
+
return count;
|
|
111
|
+
}
|
|
112
|
+
const { take, page } = pagination;
|
|
113
|
+
const skip = pagination.skip ?? 0;
|
|
114
|
+
const startIndex = (page - 1) * take + skip;
|
|
115
|
+
const endIndex = startIndex + take;
|
|
116
|
+
for await (const entry of this.iterEntries()) {
|
|
117
|
+
const isMatch = predicate(entry);
|
|
118
|
+
if (isMatch) {
|
|
119
|
+
if (totalMatched >= startIndex && totalMatched < endIndex)
|
|
120
|
+
count++;
|
|
121
|
+
totalMatched++;
|
|
122
|
+
if (totalMatched >= endIndex)
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return count;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
30
130
|
exports.FileType = void 0;
|
|
31
131
|
(function (FileType) {
|
|
32
132
|
FileType["File"] = "file";
|
|
33
133
|
FileType["Directory"] = "directory";
|
|
34
134
|
//Symlink: 'symlink'
|
|
35
135
|
})(exports.FileType || (exports.FileType = {}));
|
|
36
|
-
class SingleEntryDb {
|
|
37
|
-
}
|
|
38
|
-
class MultiEntryDb {
|
|
39
|
-
}
|
|
40
136
|
|
|
41
137
|
const DEFUALT_ENCODING = 'utf-8';
|
|
42
138
|
class Files {
|
|
@@ -260,53 +356,31 @@ class MultiEntryFileDb extends MultiEntryDb {
|
|
|
260
356
|
return entry;
|
|
261
357
|
}
|
|
262
358
|
async getById(id) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
async getByIdOrThrow(id) {
|
|
266
|
-
const entry = await this.readEntry(id);
|
|
267
|
-
if (!entry) {
|
|
268
|
-
throw new Error('Entry with id ' + id + ' does not exist');
|
|
269
|
-
}
|
|
270
|
-
return entry;
|
|
271
|
-
}
|
|
272
|
-
async getWhere(predicate, max) {
|
|
273
|
-
const entries = await this.getAll();
|
|
274
|
-
return entries.filter(predicate).slice(0, max);
|
|
275
|
-
}
|
|
276
|
-
async getAll(whereIds) {
|
|
277
|
-
const ids = whereIds === undefined ? await this.getAllIds() : whereIds;
|
|
278
|
-
const entries = [];
|
|
279
|
-
for (const id of ids) {
|
|
280
|
-
const entry = await this.readEntry(id);
|
|
281
|
-
if (entry)
|
|
282
|
-
entries.push(entry);
|
|
283
|
-
}
|
|
284
|
-
return entries;
|
|
285
|
-
}
|
|
286
|
-
async getAllIds() {
|
|
359
|
+
if (!this.isIdValid(id))
|
|
360
|
+
throw new Error(`Invalid id: ${id}`);
|
|
287
361
|
try {
|
|
288
|
-
const
|
|
289
|
-
|
|
362
|
+
const filepath = this.getFilePath(id);
|
|
363
|
+
const text = await this.files.read(filepath);
|
|
364
|
+
const entry = this.parser.parse(text);
|
|
365
|
+
return entry;
|
|
290
366
|
}
|
|
291
|
-
catch {
|
|
292
|
-
|
|
293
|
-
|
|
367
|
+
catch (error) {
|
|
368
|
+
console.error('Failed to read entry', error);
|
|
369
|
+
// File doesn't exist or invalid JSON
|
|
370
|
+
return null;
|
|
294
371
|
}
|
|
295
372
|
}
|
|
296
373
|
async update(id, updater) {
|
|
297
|
-
const entry = await this.
|
|
298
|
-
if (!entry) {
|
|
299
|
-
throw new Error('Entry with id ' + id + ' does not exist');
|
|
300
|
-
}
|
|
374
|
+
const entry = await this.getByIdOrThrow(id);
|
|
301
375
|
const updatedEntryFields = await updater(entry);
|
|
302
376
|
const updatedEntry = { ...entry, ...updatedEntryFields };
|
|
303
377
|
await this.writeEntry(updatedEntry);
|
|
304
378
|
if (updatedEntry.id !== id) {
|
|
305
|
-
await this.
|
|
379
|
+
await this.deleteById(id);
|
|
306
380
|
}
|
|
307
381
|
return updatedEntry;
|
|
308
382
|
}
|
|
309
|
-
async
|
|
383
|
+
async deleteById(id) {
|
|
310
384
|
try {
|
|
311
385
|
const filepath = this.getFilePath(id);
|
|
312
386
|
await this.files.delete(filepath, { force: false });
|
|
@@ -320,54 +394,12 @@ class MultiEntryFileDb extends MultiEntryDb {
|
|
|
320
394
|
async deleteByIds(ids) {
|
|
321
395
|
return this.deleteWhere((entry) => ids.includes(entry.id));
|
|
322
396
|
}
|
|
323
|
-
async deleteWhere(predicate) {
|
|
324
|
-
const deletedIds = [];
|
|
325
|
-
const ignoredIds = [];
|
|
326
|
-
for await (const entry of this.iterEntries()) {
|
|
327
|
-
if (!predicate(entry))
|
|
328
|
-
continue;
|
|
329
|
-
const didDelete = await this.delete(entry.id);
|
|
330
|
-
if (didDelete) {
|
|
331
|
-
deletedIds.push(entry.id);
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
ignoredIds.push(entry.id);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
return { deletedIds, ignoredIds };
|
|
338
|
-
}
|
|
339
397
|
async destroy() {
|
|
340
398
|
await this.files.delete(this.dirpath);
|
|
341
399
|
}
|
|
342
|
-
async exists(id) {
|
|
343
|
-
const entry = await this.readEntry(id);
|
|
344
|
-
return entry !== null;
|
|
345
|
-
}
|
|
346
|
-
async countAll() {
|
|
347
|
-
const ids = await this.getAllIds();
|
|
348
|
-
return ids.length;
|
|
349
|
-
}
|
|
350
|
-
async countWhere(predicate) {
|
|
351
|
-
return (await this.getWhere(predicate)).length;
|
|
352
|
-
}
|
|
353
400
|
getFilePath(id) {
|
|
354
401
|
return path__namespace.join(this.dirpath, `${id}.json`);
|
|
355
402
|
}
|
|
356
|
-
async readEntry(id) {
|
|
357
|
-
if (!this.isIdValid(id))
|
|
358
|
-
throw new Error(`Invalid id: ${id}`);
|
|
359
|
-
try {
|
|
360
|
-
const filepath = this.getFilePath(id);
|
|
361
|
-
const text = await this.files.read(filepath);
|
|
362
|
-
const entry = this.parser.parse(text);
|
|
363
|
-
return entry;
|
|
364
|
-
}
|
|
365
|
-
catch (error) {
|
|
366
|
-
console.error('Failed to read entry', error);
|
|
367
|
-
// File doesn't exist or invalid JSON
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
403
|
async writeEntry(entry) {
|
|
372
404
|
if (!this.isIdValid(entry.id))
|
|
373
405
|
throw new Error(`Invalid id: ${entry.id}`);
|
|
@@ -384,18 +416,26 @@ class MultiEntryFileDb extends MultiEntryDb {
|
|
|
384
416
|
return true;
|
|
385
417
|
}
|
|
386
418
|
async *iterEntries() {
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
const entry = await this.readEntry(id);
|
|
419
|
+
for await (const id of this.iterIds()) {
|
|
420
|
+
const entry = await this.getById(id);
|
|
390
421
|
if (entry)
|
|
391
422
|
yield entry;
|
|
392
423
|
}
|
|
393
424
|
}
|
|
425
|
+
async *iterIds() {
|
|
426
|
+
const filenames = await this.files.list(this.dirpath);
|
|
427
|
+
for (const filename of filenames) {
|
|
428
|
+
if (!filename.endsWith('.json'))
|
|
429
|
+
continue;
|
|
430
|
+
const id = filename.replace(/\.json$/, '');
|
|
431
|
+
if (this.isIdValid(id))
|
|
432
|
+
yield id;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
394
435
|
}
|
|
395
436
|
|
|
396
|
-
class SingleEntryFileDb
|
|
437
|
+
class SingleEntryFileDb {
|
|
397
438
|
constructor(filepath, parser = JSON) {
|
|
398
|
-
super();
|
|
399
439
|
this.filepath = filepath;
|
|
400
440
|
this.parser = parser;
|
|
401
441
|
this.files = new Files();
|
|
@@ -443,108 +483,54 @@ class MultiEntryMemDb extends MultiEntryDb {
|
|
|
443
483
|
async getById(id) {
|
|
444
484
|
return this.entries.get(id) ?? null;
|
|
445
485
|
}
|
|
446
|
-
async getByIdOrThrow(id) {
|
|
447
|
-
const entry = await this.getById(id);
|
|
448
|
-
if (!entry) {
|
|
449
|
-
throw new Error('Entry with id ' + id + ' does not exist');
|
|
450
|
-
}
|
|
451
|
-
return entry;
|
|
452
|
-
}
|
|
453
|
-
async getWhere(predicate, max) {
|
|
454
|
-
const entries = Array.from(this.entries.values()).filter(predicate);
|
|
455
|
-
return max !== undefined ? entries.slice(0, max) : entries;
|
|
456
|
-
}
|
|
457
|
-
async getAll(whereIds) {
|
|
458
|
-
if (whereIds === undefined) {
|
|
459
|
-
return Array.from(this.entries.values());
|
|
460
|
-
}
|
|
461
|
-
const entries = [];
|
|
462
|
-
for (const id of whereIds) {
|
|
463
|
-
const entry = this.entries.get(id);
|
|
464
|
-
if (entry)
|
|
465
|
-
entries.push(entry);
|
|
466
|
-
}
|
|
467
|
-
return entries;
|
|
468
|
-
}
|
|
469
|
-
async getAllIds() {
|
|
470
|
-
return Array.from(this.entries.keys());
|
|
471
|
-
}
|
|
472
486
|
async update(id, updater) {
|
|
473
|
-
const entry = this.
|
|
474
|
-
if (!entry) {
|
|
475
|
-
throw new Error('Entry with id ' + id + ' does not exist');
|
|
476
|
-
}
|
|
487
|
+
const entry = await this.getByIdOrThrow(id);
|
|
477
488
|
const updatedEntryFields = await updater(entry);
|
|
478
489
|
const updatedEntry = { ...entry, ...updatedEntryFields };
|
|
479
490
|
this.entries.set(updatedEntry.id, updatedEntry);
|
|
480
|
-
if (updatedEntry.id !== id)
|
|
491
|
+
if (updatedEntry.id !== id)
|
|
481
492
|
this.entries.delete(id);
|
|
482
|
-
}
|
|
483
493
|
return updatedEntry;
|
|
484
494
|
}
|
|
485
|
-
async
|
|
495
|
+
async deleteById(id) {
|
|
486
496
|
return this.entries.delete(id);
|
|
487
497
|
}
|
|
488
|
-
async deleteByIds(ids) {
|
|
489
|
-
return this.deleteWhere((entry) => ids.includes(entry.id));
|
|
490
|
-
}
|
|
491
|
-
async deleteWhere(predicate) {
|
|
492
|
-
const deletedIds = [];
|
|
493
|
-
const ignoredIds = [];
|
|
494
|
-
for (const [id, entry] of this.entries) {
|
|
495
|
-
if (!predicate(entry))
|
|
496
|
-
continue;
|
|
497
|
-
const didDelete = await this.delete(id);
|
|
498
|
-
if (didDelete) {
|
|
499
|
-
deletedIds.push(id);
|
|
500
|
-
}
|
|
501
|
-
else {
|
|
502
|
-
ignoredIds.push(id);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
return { deletedIds, ignoredIds };
|
|
506
|
-
}
|
|
507
498
|
async destroy() {
|
|
508
499
|
this.entries.clear();
|
|
509
500
|
}
|
|
510
|
-
async exists(id) {
|
|
511
|
-
return this.entries.has(id);
|
|
512
|
-
}
|
|
513
|
-
async countAll() {
|
|
514
|
-
return this.entries.size;
|
|
515
|
-
}
|
|
516
|
-
async countWhere(predicate) {
|
|
517
|
-
return Array.from(this.entries.values()).filter(predicate).length;
|
|
518
|
-
}
|
|
519
501
|
async *iterEntries() {
|
|
520
502
|
for (const entry of this.entries.values()) {
|
|
521
503
|
yield entry;
|
|
522
504
|
}
|
|
523
505
|
}
|
|
506
|
+
async *iterIds() {
|
|
507
|
+
for (const id of this.entries.keys()) {
|
|
508
|
+
yield id;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
524
511
|
}
|
|
525
512
|
|
|
526
|
-
class SingleEntryMemDb
|
|
513
|
+
class SingleEntryMemDb {
|
|
527
514
|
constructor(initialEntry = null) {
|
|
528
|
-
super();
|
|
529
515
|
this.entry = null;
|
|
530
516
|
this.entry = initialEntry;
|
|
531
517
|
}
|
|
532
|
-
|
|
518
|
+
isInited() {
|
|
533
519
|
return this.entry !== null;
|
|
534
520
|
}
|
|
535
|
-
|
|
521
|
+
read() {
|
|
536
522
|
if (this.entry === null)
|
|
537
523
|
throw new Error('Entry not initialized');
|
|
538
524
|
return this.entry;
|
|
539
525
|
}
|
|
540
|
-
|
|
526
|
+
write(updaterOrEntry) {
|
|
541
527
|
let entry;
|
|
542
528
|
if (typeof updaterOrEntry === 'function') {
|
|
543
529
|
const updater = updaterOrEntry;
|
|
544
530
|
if (this.entry === null) {
|
|
545
531
|
throw new Error('Cannot update uninitialized entry. Use write(entry) to initialize first.');
|
|
546
532
|
}
|
|
547
|
-
const updatedFields =
|
|
533
|
+
const updatedFields = updater(this.entry);
|
|
548
534
|
entry = { ...this.entry, ...updatedFields };
|
|
549
535
|
}
|
|
550
536
|
else {
|
|
@@ -553,15 +539,13 @@ class SingleEntryMemDb extends SingleEntryDb {
|
|
|
553
539
|
this.entry = entry;
|
|
554
540
|
return entry;
|
|
555
541
|
}
|
|
556
|
-
|
|
542
|
+
delete() {
|
|
557
543
|
this.entry = null;
|
|
558
544
|
}
|
|
559
545
|
}
|
|
560
546
|
|
|
561
|
-
exports.MultiEntryDb = MultiEntryDb;
|
|
562
547
|
exports.MultiEntryFileDb = MultiEntryFileDb;
|
|
563
548
|
exports.MultiEntryMemDb = MultiEntryMemDb;
|
|
564
|
-
exports.SingleEntryDb = SingleEntryDb;
|
|
565
549
|
exports.SingleEntryFileDb = SingleEntryFileDb;
|
|
566
550
|
exports.SingleEntryMemDb = SingleEntryMemDb;
|
|
567
551
|
//# sourceMappingURL=index.cjs.map
|