@microphi/json-db 2.3.0 → 2.5.1
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 +9 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -3
- package/lib/lib/storage/json-storage.d.ts +1 -1
- package/lib/lib/storage/json-storage.d.ts.map +1 -1
- package/lib/lib/storage/json-storage.js +44 -41
- package/package.json +4 -3
- package/lib/index.js.map +0 -1
- package/lib/lib/list/list.d.ts +0 -28
- package/lib/lib/list/list.d.ts.map +0 -1
- package/lib/lib/list/list.js +0 -94
- package/lib/lib/list/list.js.map +0 -1
- package/lib/lib/storage/json-storage.js.map +0 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> Small, fast and simple file based json-db super powered by [minisearch](https://github.com/lucaong/minisearch)
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
|
-
With your
|
|
6
|
+
With your preferred package manager install
|
|
7
7
|
```
|
|
8
8
|
@microphi/json-db
|
|
9
9
|
```
|
|
@@ -51,3 +51,11 @@ const storage = new JsonStorage<User>('users', '.data', {
|
|
|
51
51
|
The third object in the JsonStorage constructor is the `Options` object of minisearch which documentation can be found [here](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html#constructor)
|
|
52
52
|
|
|
53
53
|
JsonStorage uses internally rxjs to queue the operations on the index and so to avoid too many read/write to occur simultaneously. By default `index.json` is written on disk after 3 second of inactivity. This can be changed using the fourth argument of the constructor specifying the time in milliseconds. Also a fifth argument can be passed to change the default rxjs scheduler (asapScheduler).
|
|
54
|
+
|
|
55
|
+
#### Minisearch
|
|
56
|
+
minisearch functionalities are available through the `search` field.
|
|
57
|
+
```typescript
|
|
58
|
+
storage.search.search('batman', { fields: ['name'] });
|
|
59
|
+
```
|
|
60
|
+
Remember documents are added/updated/removed to minisearch automatically.
|
|
61
|
+
For more info on minisearch please consult their [repo](https://github.com/lucaong/minisearch).
|
package/lib/index.d.ts
CHANGED
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./lib/storage/json-storage"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-storage.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/json-storage.ts"],"names":[],"mappings":"AACA,OAAO,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAgD,MAAM,MAAM,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"json-storage.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/json-storage.ts"],"names":[],"mappings":"AACA,OAAO,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAgD,MAAM,MAAM,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAA;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,GAAG;IACzC,EAAE,EAAE,MAAM,CAAC;CACZ,CAAA;AAED,qBAAa,WAAW,CAAC,CAAC,SAAS,MAAM;;IAwBrC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,QAAQ;IAGhB,OAAO,CAAC,SAAS,CAAC;IAxBpB,YAAY,mBAA0B;IAEtC,KAAK;YAAgC,MAAM;cAAQ,MAAM;QAAgB;IAEzE,IAAI,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,CAM1B;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAE9B;IAED,OAAO,CAAC,OAAO,CAAiB;gBAItB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EACxB,kBAAkB,CAAC,EAAE,OAAO,EAC5B,QAAQ,CAAC,EAAE,MAAM,EACT,SAAS,CAAC,uBAAW;IAgEzB,SAAS;IAMf,GAAG,CAAC,EAAE,EAAE,MAAM;IAIR,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;IA+B7B,MAAM,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE;IAqC7B,QAAQ;IAIR,SAAS;IAqBT,MAAM;YAMQ,WAAW;IAuBzB,OAAO,CAAC,SAAS;IAIX,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAC,SAAS,CAAC;YAsB7B,QAAQ;YAKR,OAAO;CAKtB"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var _JsonStorage_l;
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.JsonStorage = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const debug_1 = require("@microphi/debug");
|
|
7
|
+
const minisearch_1 = require("minisearch");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const rxjs_1 = require("rxjs");
|
|
11
|
+
const list_1 = require("@microphi/list");
|
|
12
|
+
class JsonStorage {
|
|
10
13
|
get search() {
|
|
11
14
|
if (!this._search) {
|
|
12
15
|
throw Error(`Need to enable search by passing Minisearch Options to constructor. ${this.entity}`);
|
|
@@ -20,30 +23,30 @@ export class JsonStorage {
|
|
|
20
23
|
this.entity = entity;
|
|
21
24
|
this.basePath = basePath;
|
|
22
25
|
this.scheduler = scheduler;
|
|
23
|
-
_JsonStorage_l.set(this, getDebugger(`JsonStorage:${this.entity}`));
|
|
24
|
-
this.syncPending$ = new Subject();
|
|
25
|
-
this.index = new List('id', []);
|
|
26
|
-
this.index.operations$.pipe(debounceTime(debounce || 3000, this.scheduler || asapScheduler), switchMap(() => {
|
|
27
|
-
return from(this.saveIndex());
|
|
26
|
+
_JsonStorage_l.set(this, (0, debug_1.getDebugger)(`JsonStorage:${this.entity}`));
|
|
27
|
+
this.syncPending$ = new rxjs_1.Subject();
|
|
28
|
+
this.index = new list_1.List('id', []);
|
|
29
|
+
this.index.operations$.pipe((0, rxjs_1.debounceTime)(debounce || 3000, this.scheduler || rxjs_1.asapScheduler), (0, rxjs_1.switchMap)(() => {
|
|
30
|
+
return (0, rxjs_1.from)(this.saveIndex());
|
|
28
31
|
})).subscribe(() => {
|
|
29
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `index has been quiet for ${debounce}ms. Updated`);
|
|
32
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `index has been quiet for ${debounce}ms. Updated`);
|
|
30
33
|
});
|
|
31
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'creating service');
|
|
34
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'creating service');
|
|
32
35
|
if (searchIndexOptions) {
|
|
33
|
-
this._search = new
|
|
36
|
+
this._search = new minisearch_1.default(searchIndexOptions);
|
|
34
37
|
}
|
|
35
38
|
this.getIndex().then((data) => {
|
|
36
39
|
this.index.upsert(...data);
|
|
37
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `loaded index for ${data.length} items`);
|
|
38
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'getting documents');
|
|
40
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `loaded index for ${data.length} items`);
|
|
41
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'getting documents');
|
|
39
42
|
const documents = [...this.index].map(({ id }) => {
|
|
40
43
|
return this.get(id);
|
|
41
44
|
});
|
|
42
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `got ${documents.length} documents`);
|
|
45
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `got ${documents.length} documents`);
|
|
43
46
|
if (searchIndexOptions) {
|
|
44
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'reading files to generate search index');
|
|
47
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'reading files to generate search index');
|
|
45
48
|
Promise.all(documents).then((actualDocs) => {
|
|
46
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'rebuilding search index with', actualDocs.length);
|
|
49
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'rebuilding search index with', actualDocs.length);
|
|
47
50
|
actualDocs.forEach((doc) => {
|
|
48
51
|
try {
|
|
49
52
|
if (doc && doc['id']) {
|
|
@@ -53,20 +56,20 @@ export class JsonStorage {
|
|
|
53
56
|
}
|
|
54
57
|
catch (err) {
|
|
55
58
|
console.error('Error while loading entity into search index');
|
|
56
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, doc);
|
|
59
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, doc);
|
|
57
60
|
// console.error(actualDocs);
|
|
58
61
|
console.error(err);
|
|
59
62
|
}
|
|
60
63
|
});
|
|
61
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'search index rebuilt');
|
|
62
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `handling ${this._search.documentCount} documents for free search`);
|
|
64
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'search index rebuilt');
|
|
65
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `handling ${this._search.documentCount} documents for free search`);
|
|
63
66
|
});
|
|
64
67
|
}
|
|
65
68
|
});
|
|
66
69
|
}
|
|
67
70
|
async saveIndex() {
|
|
68
71
|
const path = await this.storageFile('index');
|
|
69
|
-
writeFileSync(path, JSON.stringify([...this.index]));
|
|
72
|
+
(0, node_fs_1.writeFileSync)(path, JSON.stringify([...this.index]));
|
|
70
73
|
return Promise.resolve('ok');
|
|
71
74
|
}
|
|
72
75
|
has(id) {
|
|
@@ -113,7 +116,7 @@ export class JsonStorage {
|
|
|
113
116
|
this._search?.remove(doc);
|
|
114
117
|
}
|
|
115
118
|
// finally remove json file
|
|
116
|
-
unlink(entry.path, (err) => {
|
|
119
|
+
(0, node_fs_1.unlink)(entry.path, (err) => {
|
|
117
120
|
if (err)
|
|
118
121
|
reject(err);
|
|
119
122
|
resolve('ok');
|
|
@@ -132,9 +135,9 @@ export class JsonStorage {
|
|
|
132
135
|
this._search.removeAll();
|
|
133
136
|
}
|
|
134
137
|
return new Promise((resolve) => {
|
|
135
|
-
exists(`${this.basePath}/${this.entity}`, (exists) => {
|
|
138
|
+
(0, node_fs_1.exists)(`${this.basePath}/${this.entity}`, (exists) => {
|
|
136
139
|
if (exists) {
|
|
137
|
-
rmSync(`${this.basePath}/${this.entity}`, { recursive: true });
|
|
140
|
+
(0, node_fs_1.rmSync)(`${this.basePath}/${this.entity}`, { recursive: true });
|
|
138
141
|
}
|
|
139
142
|
resolve('ok');
|
|
140
143
|
});
|
|
@@ -146,16 +149,16 @@ export class JsonStorage {
|
|
|
146
149
|
}
|
|
147
150
|
async storageFile(key) {
|
|
148
151
|
const path = this.buildPath(key);
|
|
149
|
-
const folder = dirname(path);
|
|
150
|
-
if (existsSync(path)) {
|
|
152
|
+
const folder = (0, node_path_1.dirname)(path);
|
|
153
|
+
if ((0, node_fs_1.existsSync)(path)) {
|
|
151
154
|
return Promise.resolve(path);
|
|
152
155
|
}
|
|
153
156
|
return new Promise((resolve, reject) => {
|
|
154
|
-
mkdir(folder, { recursive: true }, (err) => {
|
|
157
|
+
(0, node_fs_1.mkdir)(folder, { recursive: true }, (err) => {
|
|
155
158
|
if (err)
|
|
156
159
|
reject(err);
|
|
157
|
-
const fd = openSync(path, 'w');
|
|
158
|
-
close(fd, (err) => {
|
|
160
|
+
const fd = (0, node_fs_1.openSync)(path, 'w');
|
|
161
|
+
(0, node_fs_1.close)(fd, (err) => {
|
|
159
162
|
if (err)
|
|
160
163
|
reject(err);
|
|
161
164
|
resolve(path);
|
|
@@ -164,11 +167,11 @@ export class JsonStorage {
|
|
|
164
167
|
});
|
|
165
168
|
}
|
|
166
169
|
buildPath(id) {
|
|
167
|
-
return join(this.basePath, this.entity, `${id}.json`);
|
|
170
|
+
return (0, node_path_1.join)(this.basePath, this.entity, `${id}.json`);
|
|
168
171
|
}
|
|
169
172
|
async get(id) {
|
|
170
173
|
const path = await this.storageFile(id);
|
|
171
|
-
const data = readFileSync(path, { encoding: 'utf8' });
|
|
174
|
+
const data = (0, node_fs_1.readFileSync)(path, { encoding: 'utf8' });
|
|
172
175
|
let entity;
|
|
173
176
|
try {
|
|
174
177
|
entity = JSON.parse(data);
|
|
@@ -176,22 +179,22 @@ export class JsonStorage {
|
|
|
176
179
|
}
|
|
177
180
|
catch (e) {
|
|
178
181
|
// console.log(e);
|
|
179
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `error while trying to load data for item with id ${id}`);
|
|
180
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'item does not exists');
|
|
181
|
-
__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'clearing index');
|
|
182
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `error while trying to load data for item with id ${id}`);
|
|
183
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'item does not exists');
|
|
184
|
+
tslib_1.__classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'clearing index');
|
|
182
185
|
this.index.delete({ id, path });
|
|
183
186
|
}
|
|
184
187
|
return Promise.resolve(undefined);
|
|
185
188
|
}
|
|
186
189
|
async getIndex() {
|
|
187
|
-
const index = readFileSync(await this.storageFile('index'), { encoding: 'utf8' });
|
|
190
|
+
const index = (0, node_fs_1.readFileSync)(await this.storageFile('index'), { encoding: 'utf8' });
|
|
188
191
|
return JSON.parse(index || '[]');
|
|
189
192
|
}
|
|
190
193
|
async setItem(id, doc) {
|
|
191
|
-
writeFileSync(join(this.basePath, this.entity, `${id}.json`), JSON.stringify({ id, ...doc }));
|
|
194
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(this.basePath, this.entity, `${id}.json`), JSON.stringify({ id, ...doc }));
|
|
192
195
|
// this.l('wrote doc to disk', id, doc);
|
|
193
196
|
return Promise.resolve('ok');
|
|
194
197
|
}
|
|
195
198
|
}
|
|
199
|
+
exports.JsonStorage = JsonStorage;
|
|
196
200
|
_JsonStorage_l = new WeakMap();
|
|
197
|
-
//# sourceMappingURL=json-storage.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microphi/json-db",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "Small, fast and simple file based json-db",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"lint": "eslint ./src"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@microphi/debug": "^2.
|
|
32
|
+
"@microphi/debug": "^2.5.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@babel/plugin-transform-modules-commonjs": "^7.23.3",
|
|
@@ -39,8 +39,9 @@
|
|
|
39
39
|
"utility-types": "^3.10.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
+
"@microphi/list": "^2.3.0",
|
|
42
43
|
"minisearch": "^6.3.0",
|
|
43
44
|
"rxjs": "~7.8.0"
|
|
44
45
|
},
|
|
45
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "85be3ad7bf34a32e5b386d817b71ef3f6703b397"
|
|
46
47
|
}
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC","sourcesContent":["export * from './lib/list/list';\nexport * from './lib/storage/json-storage';\n"]}
|
package/lib/lib/list/list.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Subject } from 'rxjs';
|
|
2
|
-
import { $Keys, FunctionKeys } from 'utility-types';
|
|
3
|
-
export interface Operation {
|
|
4
|
-
op: FunctionKeys<List<any>>;
|
|
5
|
-
payload?: unknown;
|
|
6
|
-
timestamp: Date;
|
|
7
|
-
}
|
|
8
|
-
export declare class List<EntityType extends object> implements Iterable<EntityType> {
|
|
9
|
-
private IDField;
|
|
10
|
-
operations$: Subject<Operation>;
|
|
11
|
-
readonly entities: Map<string, EntityType>;
|
|
12
|
-
/**
|
|
13
|
-
* maps entities position from the original array to their ids
|
|
14
|
-
*/
|
|
15
|
-
private readonly ids;
|
|
16
|
-
get size(): number;
|
|
17
|
-
has(id: string): boolean;
|
|
18
|
-
get(id: string): EntityType | undefined;
|
|
19
|
-
private getId;
|
|
20
|
-
constructor(IDField: $Keys<EntityType>, entities?: EntityType[]);
|
|
21
|
-
[Symbol.iterator](): IterableIterator<EntityType>;
|
|
22
|
-
upsert(...entities: EntityType[]): void;
|
|
23
|
-
prepend(...entities: EntityType[]): void;
|
|
24
|
-
clear(): void;
|
|
25
|
-
delete(...entities: EntityType[]): void;
|
|
26
|
-
append(...entities: EntityType[]): void;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=list.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/lib/list/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGpD,MAAM,WAAW,SAAS;IAExB,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,qBAAa,IAAI,CAAC,UAAU,SAAS,MAAM,CAAE,YAAW,QAAQ,CAAC,UAAU,CAAC;IAgC9D,OAAO,CAAC,OAAO;IA9BpB,WAAW,qBAA4B;IAE9C,SAAgB,QAAQ,0BAAiC;IAEzD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IAEpC,IAAW,IAAI,WAOd;IAEM,GAAG,CAAC,EAAE,EAAE,MAAM;IAId,GAAG,CAAC,EAAE,EAAE,MAAM;IAIrB,OAAO,CAAC,KAAK;gBAIO,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,QAAQ,GAAE,UAAU,EAAO;IAW1E,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAa3C,MAAM,CAAC,GAAG,QAAQ,EAAE,UAAU,EAAE;IAehC,OAAO,CAAC,GAAG,QAAQ,EAAE,UAAU,EAAE;IAgBjC,KAAK;IAQL,MAAM,CAAC,GAAG,QAAQ,EAAE,UAAU,EAAE;IAehC,MAAM,CAAC,GAAG,QAAQ,EAAE,UAAU,EAAE;CAgBxC"}
|
package/lib/lib/list/list.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { Subject } from 'rxjs';
|
|
2
|
-
export class List {
|
|
3
|
-
get size() {
|
|
4
|
-
if (this.ids.length !== this.entities.size) {
|
|
5
|
-
throw new Error(`Size Mismatch ${this.ids.length} !== ${this.entities.size}`);
|
|
6
|
-
}
|
|
7
|
-
return this.entities.size;
|
|
8
|
-
}
|
|
9
|
-
has(id) {
|
|
10
|
-
return this.entities.has(id);
|
|
11
|
-
}
|
|
12
|
-
get(id) {
|
|
13
|
-
return this.entities.get(id);
|
|
14
|
-
}
|
|
15
|
-
getId(entity) {
|
|
16
|
-
return entity[this.IDField];
|
|
17
|
-
}
|
|
18
|
-
constructor(IDField, entities = []) {
|
|
19
|
-
this.IDField = IDField;
|
|
20
|
-
this.operations$ = new Subject();
|
|
21
|
-
this.entities = new Map();
|
|
22
|
-
/**
|
|
23
|
-
* maps entities position from the original array to their ids
|
|
24
|
-
*/
|
|
25
|
-
this.ids = [];
|
|
26
|
-
this.ids = entities.map((e) => this.getId(e));
|
|
27
|
-
entities
|
|
28
|
-
.forEach((item) => {
|
|
29
|
-
const id = this.getId(item);
|
|
30
|
-
this.entities.set(id, item);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
*[Symbol.iterator]() {
|
|
34
|
-
for (const idx in this.ids) {
|
|
35
|
-
const id = this.ids[idx];
|
|
36
|
-
const entity = this.entities.get(id);
|
|
37
|
-
if (entity) {
|
|
38
|
-
yield entity;
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
throw new Error(`Cannot get entity with id ${id}`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
upsert(...entities) {
|
|
46
|
-
entities.forEach((e) => {
|
|
47
|
-
const id = this.getId(e);
|
|
48
|
-
if (!this.entities.has(id)) {
|
|
49
|
-
this.ids.push(id);
|
|
50
|
-
}
|
|
51
|
-
this.entities.set(id, e);
|
|
52
|
-
});
|
|
53
|
-
this.operations$.next({ op: 'upsert', payload: entities, timestamp: new Date() });
|
|
54
|
-
}
|
|
55
|
-
prepend(...entities) {
|
|
56
|
-
entities.reverse().forEach((e) => {
|
|
57
|
-
const id = this.getId(e);
|
|
58
|
-
if (this.entities.has(id)) {
|
|
59
|
-
this.delete(e);
|
|
60
|
-
}
|
|
61
|
-
this.ids.unshift(id);
|
|
62
|
-
this.entities.set(id, e);
|
|
63
|
-
});
|
|
64
|
-
this.operations$.next({ op: 'prepend', payload: entities, timestamp: new Date() });
|
|
65
|
-
}
|
|
66
|
-
clear() {
|
|
67
|
-
this.ids.length = 0;
|
|
68
|
-
this.entities.clear();
|
|
69
|
-
this.operations$.next({ op: 'clear', timestamp: new Date() });
|
|
70
|
-
}
|
|
71
|
-
delete(...entities) {
|
|
72
|
-
entities.forEach((e) => {
|
|
73
|
-
const id = this.getId(e);
|
|
74
|
-
const indexOfId = this.ids.findIndex((_id) => _id === id);
|
|
75
|
-
if (indexOfId >= 0) {
|
|
76
|
-
this.ids.splice(indexOfId, 1);
|
|
77
|
-
this.entities.delete(id);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
this.operations$.next({ op: 'delete', payload: entities, timestamp: new Date() });
|
|
81
|
-
}
|
|
82
|
-
append(...entities) {
|
|
83
|
-
entities.forEach((e) => {
|
|
84
|
-
const id = this.getId(e);
|
|
85
|
-
if (this.entities.has(id)) {
|
|
86
|
-
this.delete(e);
|
|
87
|
-
}
|
|
88
|
-
this.ids.push(id);
|
|
89
|
-
this.entities.set(id, e);
|
|
90
|
-
});
|
|
91
|
-
this.operations$.next({ op: 'append', payload: entities, timestamp: new Date() });
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
//# sourceMappingURL=list.js.map
|
package/lib/lib/list/list.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/lib/list/list.ts"],"names":[],"mappings":"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","sourcesContent":["import { Subject } from 'rxjs';\nimport { $Keys, FunctionKeys } from 'utility-types';\n\n\nexport interface Operation {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n op: FunctionKeys<List<any>>;\n payload?: unknown;\n timestamp: Date;\n}\n\nexport class List<EntityType extends object> implements Iterable<EntityType> {\n\n public operations$ = new Subject<Operation>();\n\n public readonly entities = new Map<string, EntityType>();\n\n /**\n * maps entities position from the original array to their ids\n */\n private readonly ids: string[] = [];\n\n public get size() {\n if (this.ids.length !== this.entities.size) {\n\n throw new Error(`Size Mismatch ${this.ids.length} !== ${this.entities.size}`);\n }\n\n return this.entities.size;\n }\n\n public has(id: string) {\n return this.entities.has(id);\n }\n\n public get(id: string) {\n return this.entities.get(id);\n }\n\n private getId(entity: EntityType): string {\n return entity[this.IDField] as string;\n }\n\n constructor(private IDField: $Keys<EntityType>, entities: EntityType[] = []) {\n\n this.ids = entities.map((e) => this.getId(e));\n\n entities\n .forEach((item) => {\n const id = this.getId(item);\n this.entities.set(id, item);\n });\n }\n\n *[Symbol.iterator](): IterableIterator<EntityType> {\n for (const idx in this.ids) {\n const id = this.ids[idx];\n\n const entity = this.entities.get(id);\n if (entity) {\n yield entity;\n } else {\n throw new Error(`Cannot get entity with id ${id}`);\n }\n }\n }\n\n public upsert(...entities: EntityType[]) {\n entities.forEach((e) => {\n const id = this.getId(e);\n\n if (!this.entities.has(id)) {\n this.ids.push(id);\n }\n\n this.entities.set(id, e);\n\n });\n\n this.operations$.next({ op: 'upsert', payload: entities, timestamp: new Date() });\n }\n\n public prepend(...entities: EntityType[]) {\n entities.reverse().forEach((e) => {\n const id = this.getId(e);\n\n if (this.entities.has(id)) {\n this.delete(e);\n }\n\n this.ids.unshift(id);\n\n this.entities.set(id, e);\n\n });\n this.operations$.next({ op: 'prepend', payload: entities, timestamp: new Date() });\n }\n\n public clear() {\n\n this.ids.length = 0;\n this.entities.clear();\n this.operations$.next({ op: 'clear', timestamp: new Date() });\n\n }\n\n public delete(...entities: EntityType[]) {\n\n entities.forEach((e) => {\n const id = this.getId(e);\n const indexOfId = this.ids.findIndex((_id) => _id === id);\n\n if (indexOfId >= 0) {\n this.ids.splice(indexOfId, 1);\n this.entities.delete(id);\n }\n });\n\n this.operations$.next({ op: 'delete', payload: entities, timestamp: new Date() });\n }\n\n public append(...entities: EntityType[]) {\n entities.forEach((e) => {\n const id = this.getId(e);\n\n if (this.entities.has(id)) {\n this.delete(e);\n }\n\n this.ids.push(id);\n this.entities.set(id, e);\n });\n\n this.operations$.next({ op: 'append', payload: entities, timestamp: new Date() });\n }\n\n\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"json-storage.js","sourceRoot":"","sources":["../../../src/lib/storage/json-storage.ts"],"names":[],"mappings":"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","sourcesContent":["import { getDebugger } from '@microphi/debug';\nimport MiniSearch, { Options } from 'minisearch';\nimport { close, exists, existsSync, mkdir, openSync, readFileSync, rmSync, unlink, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { Scheduler, Subject, asapScheduler, debounceTime, from, switchMap } from 'rxjs';\nimport { List } from '../list/list';\n\n/**\n * Mark T as having auto trailing attributes\n *\n * `modified` and `created` iso string date;\n */\nexport type withAutoTrail<T> = T & {\n modified?: string;\n created?: string;\n}\n\nexport type withId<T extends object> = T & {\n id: string;\n}\n\nexport class JsonStorage<T extends object> {\n\n #l = getDebugger(`JsonStorage:${this.entity}`);\n\n syncPending$ = new Subject<boolean>();\n\n index = new List<withAutoTrail<{ id: string; path: string; }>>('id', []);\n\n get search(): MiniSearch<T> {\n if (!this._search) {\n throw Error(`Need to enable search by passing Minisearch Options to constructor. ${this.entity}`);\n }\n\n return this._search;\n }\n\n set search(value: MiniSearch<T>) {\n this._search = value;\n }\n\n private _search!: MiniSearch<T>;\n\n\n constructor(\n private entity: string,\n private basePath: string,\n searchIndexOptions?: Options,\n debounce?: number,\n private scheduler?: Scheduler,\n ) {\n\n this.index.operations$.pipe(\n debounceTime(debounce || 3_000, this.scheduler || asapScheduler),\n switchMap(() => {\n return from(this.saveIndex());\n })\n ).subscribe(() => {\n this.#l(`index has been quiet for ${debounce}ms. Updated`);\n });\n\n this.#l('creating service');\n\n if (searchIndexOptions) {\n this._search = new MiniSearch(searchIndexOptions);\n }\n\n this.getIndex().then((data) => {\n\n this.index.upsert(...data);\n\n this.#l(`loaded index for ${data.length} items`);\n this.#l('getting documents');\n\n const documents = [...this.index].map(({ id }) => {\n return this.get(id);\n });\n this.#l(`got ${documents.length} documents`);\n\n if (searchIndexOptions) {\n this.#l('reading files to generate search index');\n Promise.all(documents).then((actualDocs) => {\n\n this.#l('rebuilding search index with', actualDocs.length);\n\n actualDocs.forEach((doc) => {\n\n try {\n\n if (doc && doc['id']) {\n // this.l(`adding document with id ${doc['id']}`);\n\n this._search.add(doc);\n }\n\n } catch (err) {\n console.error('Error while loading entity into search index');\n this.#l(doc);\n // console.error(actualDocs);\n console.error(err);\n }\n\n });\n\n this.#l('search index rebuilt');\n this.#l(`handling ${this._search.documentCount} documents for free search`);\n\n });\n }\n });\n\n }\n\n async saveIndex() {\n const path = await this.storageFile('index');\n writeFileSync(path, JSON.stringify([...this.index]));\n return Promise.resolve('ok');\n }\n\n has(id: string) {\n return this.index.has(id);\n }\n\n async upsert(...docs: (withId<T>)[]) {\n\n for (const {id, ...doc} of docs) {\n const timestamp = new Date().toISOString();\n const updateTime = this.index.has(id) ? {\n modified: timestamp,\n } : {\n modified: timestamp,\n created: timestamp,\n };\n\n this.index.upsert({\n id: id,\n path: await this.storageFile(id),\n ...updateTime\n });\n\n await this.setItem(id, doc as T);\n\n if (this._search) {\n if (this._search.has(id)) {\n this._search.replace({id, ...doc} as T);\n } else {\n this._search.add({id, ...doc} as T);\n }\n }\n }\n\n return Promise.resolve();\n }\n\n async remove(...ids: string[]) {\n return new Promise((resolve, reject) => {\n\n for (const id of ids) {\n\n const entry = this.index.get(id);\n\n if (!entry) {\n resolve('ok');\n }\n\n this.get(id).then((doc) => {\n\n if (entry) {\n\n // remove index and search entry\n this.index.delete(entry);\n\n if (doc) {\n this._search?.remove(doc);\n }\n\n // finally remove json file\n unlink(entry.path, (err) => {\n if (err) reject(err);\n\n resolve('ok');\n });\n }\n\n\n });\n }\n\n });\n }\n\n getCount() {\n return this.index.size;\n }\n\n deleteAll() {\n this.index.clear();\n\n if (this._search) {\n this._search.removeAll();\n }\n\n return new Promise((resolve) => {\n exists(`${this.basePath}/${this.entity}`, (exists) => {\n if (exists) {\n\n rmSync(`${this.basePath}/${this.entity}`, { recursive: true });\n\n }\n\n resolve('ok');\n\n });\n });\n }\n\n getAll() {\n const items$ = [...this.index].map(({ id }) => this.get(id));\n\n return Promise.all(items$);\n }\n\n private async storageFile(key: string): Promise<string> {\n const path = this.buildPath(key);\n const folder = dirname(path);\n\n if (existsSync(path)) {\n return Promise.resolve(path);\n }\n\n return new Promise((resolve, reject) => {\n mkdir(folder, { recursive: true }, (err) => {\n if (err) reject(err);\n\n const fd = openSync(path, 'w');\n close(fd, (err) => {\n if (err) reject(err);\n\n resolve(path);\n });\n\n });\n });\n }\n\n private buildPath(id: string) {\n return join(this.basePath, this.entity, `${id}.json`);\n }\n\n async get(id: string): Promise<T|undefined> {\n const path = await this.storageFile(id);\n const data = readFileSync(path, {encoding: 'utf8'});\n let entity: T;\n\n try {\n\n entity = JSON.parse(data);\n\n return entity;\n } catch (e) {\n // console.log(e);\n this.#l(`error while trying to load data for item with id ${id}`);\n this.#l('item does not exists');\n this.#l('clearing index');\n this.index.delete({id, path});\n }\n\n return Promise.resolve(undefined);\n }\n\n\n private async getIndex(): Promise<{id: string; path: string;}[]> {\n const index = readFileSync(await this.storageFile('index'), {encoding: 'utf8'});\n return JSON.parse(index || '[]');\n }\n\n private async setItem(id: string, doc: T) {\n writeFileSync(join(this.basePath, this.entity, `${id}.json`), JSON.stringify({id, ...doc}));\n // this.l('wrote doc to disk', id, doc);\n return Promise.resolve('ok');\n }\n}\n"]}
|