@microphi/json-db 2.2.0 → 2.3.0

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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +43 -2
  3. package/lib/index.d.ts +1 -0
  4. package/lib/index.d.ts.map +1 -1
  5. package/lib/index.js +1 -0
  6. package/lib/index.js.map +1 -1
  7. package/lib/lib/storage/json-storage.d.ts +43 -0
  8. package/lib/lib/storage/json-storage.d.ts.map +1 -0
  9. package/lib/lib/storage/json-storage.js +197 -0
  10. package/lib/lib/storage/json-storage.js.map +1 -0
  11. package/package.json +13 -4
  12. package/lib/lib/aspects/after.decorator.d.ts +0 -35
  13. package/lib/lib/aspects/after.decorator.d.ts.map +0 -1
  14. package/lib/lib/aspects/after.decorator.js +0 -45
  15. package/lib/lib/aspects/after.decorator.js.map +0 -1
  16. package/lib/lib/aspects/before.decorator.d.ts +0 -28
  17. package/lib/lib/aspects/before.decorator.d.ts.map +0 -1
  18. package/lib/lib/aspects/before.decorator.js +0 -46
  19. package/lib/lib/aspects/before.decorator.js.map +0 -1
  20. package/lib/lib/container/bootstrap.d.ts +0 -3
  21. package/lib/lib/container/bootstrap.d.ts.map +0 -1
  22. package/lib/lib/container/bootstrap.js +0 -15
  23. package/lib/lib/container/bootstrap.js.map +0 -1
  24. package/lib/lib/container/di.decorator.d.ts +0 -10
  25. package/lib/lib/container/di.decorator.d.ts.map +0 -1
  26. package/lib/lib/container/di.decorator.js +0 -15
  27. package/lib/lib/container/di.decorator.js.map +0 -1
  28. package/lib/lib/container/graph.d.ts +0 -171
  29. package/lib/lib/container/graph.d.ts.map +0 -1
  30. package/lib/lib/container/graph.js +0 -429
  31. package/lib/lib/container/graph.js.map +0 -1
  32. package/lib/lib/injctable/inject.decorator.d.ts +0 -7
  33. package/lib/lib/injctable/inject.decorator.d.ts.map +0 -1
  34. package/lib/lib/injctable/inject.decorator.js +0 -31
  35. package/lib/lib/injctable/inject.decorator.js.map +0 -1
  36. package/lib/lib/injctable/injectable.decorator.d.ts +0 -16
  37. package/lib/lib/injctable/injectable.decorator.d.ts.map +0 -1
  38. package/lib/lib/injctable/injectable.decorator.js +0 -52
  39. package/lib/lib/injctable/injectable.decorator.js.map +0 -1
  40. package/lib/lib/injctable/injector.d.ts +0 -4
  41. package/lib/lib/injctable/injector.d.ts.map +0 -1
  42. package/lib/lib/injctable/injector.js +0 -25
  43. package/lib/lib/injctable/injector.js.map +0 -1
  44. package/lib/lib/provider/providers.d.ts +0 -15
  45. package/lib/lib/provider/providers.d.ts.map +0 -1
  46. package/lib/lib/provider/providers.js +0 -80
  47. package/lib/lib/provider/providers.js.map +0 -1
  48. package/lib/lib/scan.d.ts +0 -3
  49. package/lib/lib/scan.d.ts.map +0 -1
  50. package/lib/lib/scan.js +0 -19
  51. package/lib/lib/scan.js.map +0 -1
  52. package/lib/lib/testing/mocked.d.ts +0 -9
  53. package/lib/lib/testing/mocked.d.ts.map +0 -1
  54. package/lib/lib/testing/mocked.js +0 -58
  55. package/lib/lib/testing/mocked.js.map +0 -1
  56. package/lib/lib/testing/test-bed.d.ts +0 -7
  57. package/lib/lib/testing/test-bed.d.ts.map +0 -1
  58. package/lib/lib/testing/test-bed.js +0 -20
  59. package/lib/lib/testing/test-bed.js.map +0 -1
  60. package/lib/lib/types.d.ts +0 -10
  61. package/lib/lib/types.d.ts.map +0 -1
  62. package/lib/lib/types.js +0 -4
  63. package/lib/lib/types.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Davide Cavaliere
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @microphi/json-db [![npm version](https://badge.fury.io/js/%40microphi%2Fjsob-db.svg)](https://badge.fury.io/js/%40microphi%2Fjson-db)
2
2
 
3
- > Small, fast and simple file based json-db
3
+ > Small, fast and simple file based json-db super powered by [minisearch](https://github.com/lucaong/minisearch)
4
4
 
5
5
  ## Install
6
6
  With your preferend package manager install
@@ -9,4 +9,45 @@ With your preferend package manager install
9
9
  ```
10
10
 
11
11
  ## How to use
12
- > TBD
12
+ ### Basic usage:
13
+ ```typescript
14
+ interface User {
15
+ id: string;
16
+ name: string;
17
+ }
18
+
19
+ // create a new storage for User
20
+ const storage = new JsonStorage<User>('users', '.data');
21
+
22
+ await storage.upsert({id: '1', name:'superman'});
23
+ await storage.upsert({id: '2', name:'batman'});
24
+
25
+ // getting a document by id
26
+ const batman = await storage.get('2');
27
+ // updating a document
28
+ await storage.upsert({id: '2', name: 'super-batman'});
29
+
30
+ // get all documents
31
+ const docs = await storage.getAll();
32
+
33
+ // remove a document
34
+ await storage.remove('1');
35
+
36
+ // remove all documents
37
+ await storage.deleteAll();
38
+
39
+ ```
40
+ A directory with the name provided (in this case `.data`) will be created and inside there another folder with the entity name.
41
+ Data is save in `json` files as in `${id}.json` and an `index.json` will collect all stored documents metadata such as modified date and create date.
42
+
43
+ ### Enable minisearch
44
+ To enable minisearch create instantiate a storage class such as
45
+ ```typescript
46
+ const storage = new JsonStorage<User>('users', '.data', {
47
+ fields: ['name'],
48
+ idField: 'id',
49
+ });
50
+ ```
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
+
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).
package/lib/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './lib/list/list';
2
+ export * from './lib/storage/json-storage';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC"}
package/lib/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './lib/list/list';
2
+ export * from './lib/storage/json-storage';
2
3
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC","sourcesContent":["export * from './lib/list/list';\n"]}
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"]}
@@ -0,0 +1,43 @@
1
+ import MiniSearch, { Options } from 'minisearch';
2
+ import { Scheduler, Subject } from 'rxjs';
3
+ import { List } from '../list/list';
4
+ /**
5
+ * Mark T as having auto trailing attributes
6
+ *
7
+ * `modified` and `created` iso string date;
8
+ */
9
+ export type withAutoTrail<T> = T & {
10
+ modified?: string;
11
+ created?: string;
12
+ };
13
+ export type withId<T extends object> = T & {
14
+ id: string;
15
+ };
16
+ export declare class JsonStorage<T extends object> {
17
+ #private;
18
+ private entity;
19
+ private basePath;
20
+ private scheduler?;
21
+ syncPending$: Subject<boolean>;
22
+ index: List<withAutoTrail<{
23
+ id: string;
24
+ path: string;
25
+ }>>;
26
+ get search(): MiniSearch<T>;
27
+ set search(value: MiniSearch<T>);
28
+ private _search;
29
+ constructor(entity: string, basePath: string, searchIndexOptions?: Options, debounce?: number, scheduler?: Scheduler | undefined);
30
+ saveIndex(): Promise<string>;
31
+ has(id: string): boolean;
32
+ upsert(...docs: (withId<T>)[]): Promise<void>;
33
+ remove(...ids: string[]): Promise<unknown>;
34
+ getCount(): number;
35
+ deleteAll(): Promise<unknown>;
36
+ getAll(): Promise<(Awaited<T> | undefined)[]>;
37
+ private storageFile;
38
+ private buildPath;
39
+ get(id: string): Promise<T | undefined>;
40
+ private getIndex;
41
+ private setItem;
42
+ }
43
+ //# sourceMappingURL=json-storage.d.ts.map
@@ -0,0 +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,cAAc,CAAC;AAEpC;;;;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"}
@@ -0,0 +1,197 @@
1
+ var _JsonStorage_l;
2
+ import { __classPrivateFieldGet } from "tslib";
3
+ import { getDebugger } from '@microphi/debug';
4
+ import MiniSearch from 'minisearch';
5
+ import { close, exists, existsSync, mkdir, openSync, readFileSync, rmSync, unlink, writeFileSync } from 'node:fs';
6
+ import { dirname, join } from 'node:path';
7
+ import { Subject, asapScheduler, debounceTime, from, switchMap } from 'rxjs';
8
+ import { List } from '../list/list';
9
+ export class JsonStorage {
10
+ get search() {
11
+ if (!this._search) {
12
+ throw Error(`Need to enable search by passing Minisearch Options to constructor. ${this.entity}`);
13
+ }
14
+ return this._search;
15
+ }
16
+ set search(value) {
17
+ this._search = value;
18
+ }
19
+ constructor(entity, basePath, searchIndexOptions, debounce, scheduler) {
20
+ this.entity = entity;
21
+ this.basePath = basePath;
22
+ 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());
28
+ })).subscribe(() => {
29
+ __classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `index has been quiet for ${debounce}ms. Updated`);
30
+ });
31
+ __classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'creating service');
32
+ if (searchIndexOptions) {
33
+ this._search = new MiniSearch(searchIndexOptions);
34
+ }
35
+ this.getIndex().then((data) => {
36
+ 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');
39
+ const documents = [...this.index].map(({ id }) => {
40
+ return this.get(id);
41
+ });
42
+ __classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, `got ${documents.length} documents`);
43
+ if (searchIndexOptions) {
44
+ __classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'reading files to generate search index');
45
+ Promise.all(documents).then((actualDocs) => {
46
+ __classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, 'rebuilding search index with', actualDocs.length);
47
+ actualDocs.forEach((doc) => {
48
+ try {
49
+ if (doc && doc['id']) {
50
+ // this.l(`adding document with id ${doc['id']}`);
51
+ this._search.add(doc);
52
+ }
53
+ }
54
+ catch (err) {
55
+ console.error('Error while loading entity into search index');
56
+ __classPrivateFieldGet(this, _JsonStorage_l, "f").call(this, doc);
57
+ // console.error(actualDocs);
58
+ console.error(err);
59
+ }
60
+ });
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`);
63
+ });
64
+ }
65
+ });
66
+ }
67
+ async saveIndex() {
68
+ const path = await this.storageFile('index');
69
+ writeFileSync(path, JSON.stringify([...this.index]));
70
+ return Promise.resolve('ok');
71
+ }
72
+ has(id) {
73
+ return this.index.has(id);
74
+ }
75
+ async upsert(...docs) {
76
+ for (const { id, ...doc } of docs) {
77
+ const timestamp = new Date().toISOString();
78
+ const updateTime = this.index.has(id) ? {
79
+ modified: timestamp,
80
+ } : {
81
+ modified: timestamp,
82
+ created: timestamp,
83
+ };
84
+ this.index.upsert({
85
+ id: id,
86
+ path: await this.storageFile(id),
87
+ ...updateTime
88
+ });
89
+ await this.setItem(id, doc);
90
+ if (this._search) {
91
+ if (this._search.has(id)) {
92
+ this._search.replace({ id, ...doc });
93
+ }
94
+ else {
95
+ this._search.add({ id, ...doc });
96
+ }
97
+ }
98
+ }
99
+ return Promise.resolve();
100
+ }
101
+ async remove(...ids) {
102
+ return new Promise((resolve, reject) => {
103
+ for (const id of ids) {
104
+ const entry = this.index.get(id);
105
+ if (!entry) {
106
+ resolve('ok');
107
+ }
108
+ this.get(id).then((doc) => {
109
+ if (entry) {
110
+ // remove index and search entry
111
+ this.index.delete(entry);
112
+ if (doc) {
113
+ this._search?.remove(doc);
114
+ }
115
+ // finally remove json file
116
+ unlink(entry.path, (err) => {
117
+ if (err)
118
+ reject(err);
119
+ resolve('ok');
120
+ });
121
+ }
122
+ });
123
+ }
124
+ });
125
+ }
126
+ getCount() {
127
+ return this.index.size;
128
+ }
129
+ deleteAll() {
130
+ this.index.clear();
131
+ if (this._search) {
132
+ this._search.removeAll();
133
+ }
134
+ return new Promise((resolve) => {
135
+ exists(`${this.basePath}/${this.entity}`, (exists) => {
136
+ if (exists) {
137
+ rmSync(`${this.basePath}/${this.entity}`, { recursive: true });
138
+ }
139
+ resolve('ok');
140
+ });
141
+ });
142
+ }
143
+ getAll() {
144
+ const items$ = [...this.index].map(({ id }) => this.get(id));
145
+ return Promise.all(items$);
146
+ }
147
+ async storageFile(key) {
148
+ const path = this.buildPath(key);
149
+ const folder = dirname(path);
150
+ if (existsSync(path)) {
151
+ return Promise.resolve(path);
152
+ }
153
+ return new Promise((resolve, reject) => {
154
+ mkdir(folder, { recursive: true }, (err) => {
155
+ if (err)
156
+ reject(err);
157
+ const fd = openSync(path, 'w');
158
+ close(fd, (err) => {
159
+ if (err)
160
+ reject(err);
161
+ resolve(path);
162
+ });
163
+ });
164
+ });
165
+ }
166
+ buildPath(id) {
167
+ return join(this.basePath, this.entity, `${id}.json`);
168
+ }
169
+ async get(id) {
170
+ const path = await this.storageFile(id);
171
+ const data = readFileSync(path, { encoding: 'utf8' });
172
+ let entity;
173
+ try {
174
+ entity = JSON.parse(data);
175
+ return entity;
176
+ }
177
+ catch (e) {
178
+ // 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
+ this.index.delete({ id, path });
183
+ }
184
+ return Promise.resolve(undefined);
185
+ }
186
+ async getIndex() {
187
+ const index = readFileSync(await this.storageFile('index'), { encoding: 'utf8' });
188
+ return JSON.parse(index || '[]');
189
+ }
190
+ async setItem(id, doc) {
191
+ writeFileSync(join(this.basePath, this.entity, `${id}.json`), JSON.stringify({ id, ...doc }));
192
+ // this.l('wrote doc to disk', id, doc);
193
+ return Promise.resolve('ok');
194
+ }
195
+ }
196
+ _JsonStorage_l = new WeakMap();
197
+ //# sourceMappingURL=json-storage.js.map
@@ -0,0 +1 @@
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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microphi/json-db",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
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,9 +29,18 @@
29
29
  "lint": "eslint ./src"
30
30
  },
31
31
  "dependencies": {
32
- "@microphi/debug": "^2.2.0"
32
+ "@microphi/debug": "^2.3.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@babel/plugin-transform-modules-commonjs": "^7.23.3"
36
- }
35
+ "@babel/plugin-transform-modules-commonjs": "^7.23.3",
36
+ "@datakitchen/rxjs-marbles": "^17.0.0",
37
+ "@types/node": "^20.11.30",
38
+ "minisearch": "^6.3.0",
39
+ "utility-types": "^3.10.0"
40
+ },
41
+ "peerDependencies": {
42
+ "minisearch": "^6.3.0",
43
+ "rxjs": "~7.8.0"
44
+ },
45
+ "gitHead": "6b2df1f7209ccda9b934bbdbcf71f59acc383380"
37
46
  }
@@ -1,35 +0,0 @@
1
- /**
2
- * Runs the `fn` after the annotated method
3
- *
4
- * @remarks
5
- * Decorate a method to execute `fn` after it.
6
- * `fn` params will be the same type as the decorated return type and it __must__ return this same type.
7
- * To have type checking you need to provide type information into this decorator generics.
8
- * `fn` can __must__ return that same type or void.
9
- *
10
- * @example
11
- * ```typescript
12
- * class TestClass {
13
- *
14
- * @After<string>((salutation) => {
15
- * return salutation.toUpperCase();
16
- * })
17
- * public testA(name: string): string {
18
- * return `Hello ${name}!`;
19
- * }
20
- *
21
- * @After<string>((salutation) => {
22
- * return salutation.toLowerCase();
23
- * })
24
- * public testB(name: string, nickname: string): string {
25
- * return `Hello ${name} aka ${nickname}!`;
26
- * }
27
- *
28
- * }
29
- *
30
- * ```
31
- *
32
- * @param fn
33
- */
34
- export declare function After<I, O = I>(fn: (args: I) => O): MethodDecorator;
35
- //# sourceMappingURL=after.decorator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"after.decorator.d.ts","sourceRoot":"","sources":["../../../src/lib/aspects/after.decorator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,eAAe,CAqBnE"}
@@ -1,45 +0,0 @@
1
- /**
2
- * Runs the `fn` after the annotated method
3
- *
4
- * @remarks
5
- * Decorate a method to execute `fn` after it.
6
- * `fn` params will be the same type as the decorated return type and it __must__ return this same type.
7
- * To have type checking you need to provide type information into this decorator generics.
8
- * `fn` can __must__ return that same type or void.
9
- *
10
- * @example
11
- * ```typescript
12
- * class TestClass {
13
- *
14
- * @After<string>((salutation) => {
15
- * return salutation.toUpperCase();
16
- * })
17
- * public testA(name: string): string {
18
- * return `Hello ${name}!`;
19
- * }
20
- *
21
- * @After<string>((salutation) => {
22
- * return salutation.toLowerCase();
23
- * })
24
- * public testB(name: string, nickname: string): string {
25
- * return `Hello ${name} aka ${nickname}!`;
26
- * }
27
- *
28
- * }
29
- *
30
- * ```
31
- *
32
- * @param fn
33
- */
34
- export function After(fn) {
35
- return (target, key, descriptor) => {
36
- const originalMethod = descriptor.value;
37
- descriptor.value = function () {
38
- // eslint-disable-next-line prefer-rest-params
39
- const retValue = originalMethod.apply(this, arguments);
40
- return fn.apply(this, [retValue]);
41
- };
42
- return descriptor;
43
- };
44
- }
45
- //# sourceMappingURL=after.decorator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"after.decorator.js","sourceRoot":"","sources":["../../../src/lib/aspects/after.decorator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,KAAK,CAAW,EAAkB;IAGhD,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,UAA8B,EAAE,EAAE;QAGrD,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC;QAExC,UAAU,CAAC,KAAK,GAAG;YAGjB,8CAA8C;YAC9C,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAEvD,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAGpC,CAAC,CAAC;QAEF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Runs the `fn` after the annotated method\n *\n * @remarks\n * Decorate a method to execute `fn` after it.\n * `fn` params will be the same type as the decorated return type and it __must__ return this same type.\n * To have type checking you need to provide type information into this decorator generics.\n * `fn` can __must__ return that same type or void.\n *\n * @example\n * ```typescript\n * class TestClass {\n *\n * @After<string>((salutation) => {\n * return salutation.toUpperCase();\n * })\n * public testA(name: string): string {\n * return `Hello ${name}!`;\n * }\n *\n * @After<string>((salutation) => {\n * return salutation.toLowerCase();\n * })\n * public testB(name: string, nickname: string): string {\n * return `Hello ${name} aka ${nickname}!`;\n * }\n *\n * }\n *\n * ```\n *\n * @param fn\n */\nexport function After<I, O = I>(fn: (args: I) => O): MethodDecorator {\n\n\n return (target, key, descriptor: PropertyDescriptor) => {\n\n\n const originalMethod = descriptor.value;\n\n descriptor.value = function() {\n\n\n // eslint-disable-next-line prefer-rest-params\n const retValue = originalMethod.apply(this, arguments);\n\n return fn.apply(this, [retValue]);\n\n\n };\n\n return descriptor;\n };\n}\n"]}
@@ -1,28 +0,0 @@
1
- /**
2
- * Runs the `fn` before the annotated method
3
- *
4
- * @remarks
5
- * Decorate a method to execute `fn` before it.
6
- * `fn` params will be the same type as the decorated function and it __must__ return the same type.
7
- * To have type checking you need to provide type information into this decorator generics.
8
- * `fn` can __must__ return this same type or void.
9
- *
10
- * @example
11
- * ```typescript
12
- * // basic example
13
- * class TestClass {
14
- *
15
- * @Before<string>((name) => {
16
- * return name.toUpperCase();
17
- * })
18
- * public simpleParamSimpleType(name: string) {
19
- * return `hello ${name}`;
20
- * }
21
- * }
22
- * ```
23
- * For more example see `before.decorator.spec.ts`
24
- *
25
- * @param fn
26
- */
27
- export declare function Before<P>(fn: (args: P) => P): MethodDecorator;
28
- //# sourceMappingURL=before.decorator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"before.decorator.d.ts","sourceRoot":"","sources":["../../../src/lib/aspects/before.decorator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,eAAe,CAyB7D"}
@@ -1,46 +0,0 @@
1
- /**
2
- * Runs the `fn` before the annotated method
3
- *
4
- * @remarks
5
- * Decorate a method to execute `fn` before it.
6
- * `fn` params will be the same type as the decorated function and it __must__ return the same type.
7
- * To have type checking you need to provide type information into this decorator generics.
8
- * `fn` can __must__ return this same type or void.
9
- *
10
- * @example
11
- * ```typescript
12
- * // basic example
13
- * class TestClass {
14
- *
15
- * @Before<string>((name) => {
16
- * return name.toUpperCase();
17
- * })
18
- * public simpleParamSimpleType(name: string) {
19
- * return `hello ${name}`;
20
- * }
21
- * }
22
- * ```
23
- * For more example see `before.decorator.spec.ts`
24
- *
25
- * @param fn
26
- */
27
- export function Before(fn) {
28
- return (target, key, descriptor) => {
29
- const originalMethod = descriptor.value;
30
- // use function() to keep original `this`
31
- descriptor.value = function () {
32
- // @ts-ignore
33
- // eslint-disable-next-line prefer-rest-params
34
- const retValue = fn.bind(this).apply(this, arguments);
35
- // so here we can call originalMethod with retValue
36
- // doing so beforeFn has the ability to change original arguments's values
37
- if (retValue === undefined) {
38
- // eslint-disable-next-line prefer-rest-params
39
- return originalMethod.apply(this, arguments);
40
- }
41
- return originalMethod.apply(this, [].concat(retValue));
42
- };
43
- return descriptor;
44
- };
45
- }
46
- //# sourceMappingURL=before.decorator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"before.decorator.js","sourceRoot":"","sources":["../../../src/lib/aspects/before.decorator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,MAAM,CAAI,EAAkB;IAE1C,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,UAA8B,EAAE,EAAE;QAErD,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC;QAExC,yCAAyC;QACzC,UAAU,CAAC,KAAK,GAAG;YAEjB,aAAa;YACb,8CAA8C;YAC9C,MAAM,QAAQ,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAQ,CAAC;YAE7D,mDAAmD;YACnD,0EAA0E;YAC1E,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,8CAA8C;gBAC9C,OAAO,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC/C,CAAC;YAED,OAAO,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QACzD,CAAC,CAAC;QAEF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Runs the `fn` before the annotated method\n *\n * @remarks\n * Decorate a method to execute `fn` before it.\n * `fn` params will be the same type as the decorated function and it __must__ return the same type.\n * To have type checking you need to provide type information into this decorator generics.\n * `fn` can __must__ return this same type or void.\n *\n * @example\n * ```typescript\n * // basic example\n * class TestClass {\n *\n * @Before<string>((name) => {\n * return name.toUpperCase();\n * })\n * public simpleParamSimpleType(name: string) {\n * return `hello ${name}`;\n * }\n * }\n * ```\n * For more example see `before.decorator.spec.ts`\n *\n * @param fn\n */\nexport function Before<P>(fn: (args: P) => P): MethodDecorator {\n\n return (target, key, descriptor: PropertyDescriptor) => {\n\n const originalMethod = descriptor.value;\n\n // use function() to keep original `this`\n descriptor.value = function() {\n\n // @ts-ignore\n // eslint-disable-next-line prefer-rest-params\n const retValue = fn.bind(this).apply(this, arguments) as any;\n\n // so here we can call originalMethod with retValue\n // doing so beforeFn has the ability to change original arguments's values\n if (retValue === undefined) {\n // eslint-disable-next-line prefer-rest-params\n return originalMethod.apply(this, arguments);\n }\n\n return originalMethod.apply(this, [].concat(retValue));\n };\n\n return descriptor;\n };\n}\n"]}
@@ -1,3 +0,0 @@
1
- import { Instance, Klass } from '../types';
2
- export declare function bootstrap(app: Klass): Instance;
3
- //# sourceMappingURL=bootstrap.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/lib/container/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAO3C,wBAAgB,SAAS,CAAC,GAAG,EAAE,KAAK,GAAG,QAAQ,CAc9C"}
@@ -1,15 +0,0 @@
1
- import { getDIMetadata, providers } from '../container/di.decorator';
2
- import { getDebugger } from '@microphi/debug';
3
- import { injector } from '../injctable/injector';
4
- const d = getDebugger('microphi:di:bootstrap');
5
- export function bootstrap(app) {
6
- const options = getDIMetadata(app);
7
- d('adding', app, 'to providers');
8
- providers.addInjectable(app);
9
- options.providers?.forEach((provider) => {
10
- d('configuring provider', provider);
11
- providers.addInjectable(provider);
12
- });
13
- return injector(app);
14
- }
15
- //# sourceMappingURL=bootstrap.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../../src/lib/container/bootstrap.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,GAAG,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAE/C,MAAM,UAAU,SAAS,CAAC,GAAU;IAClC,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAEnC,CAAC,CAAC,QAAQ,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;IAGjC,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAE7B,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QACtC,CAAC,CAAC,sBAAsB,EAAE,QAAQ,CAAC,CAAC;QACpC,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC","sourcesContent":["import { Instance, Klass } from '../types';\nimport { getDIMetadata, providers } from '../container/di.decorator';\nimport { getDebugger } from '@microphi/debug';\nimport { injector } from '../injctable/injector';\n\nconst d = getDebugger('microphi:di:bootstrap');\n\nexport function bootstrap(app: Klass): Instance {\n const options = getDIMetadata(app);\n\n d('adding', app, 'to providers');\n\n\n providers.addInjectable(app);\n\n options.providers?.forEach((provider) => {\n d('configuring provider', provider);\n providers.addInjectable(provider);\n });\n\n return injector(app);\n}\n"]}
@@ -1,10 +0,0 @@
1
- import { Klass, Provider } from '../types';
2
- import { Providers } from '../provider/providers';
3
- export declare const providers: Providers;
4
- export interface DIOptions {
5
- providers: Provider[];
6
- }
7
- export declare const DISymbol: unique symbol;
8
- export declare function DI(options: DIOptions): (target: any) => any;
9
- export declare function getDIMetadata(target: Klass): DIOptions;
10
- //# sourceMappingURL=di.decorator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"di.decorator.d.ts","sourceRoot":"","sources":["../../../src/lib/container/di.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,eAAO,MAAM,SAAS,WAAkB,CAAC;AAEzC,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,eAAO,MAAM,QAAQ,eAAgB,CAAC;AAEtC,wBAAgB,EAAE,CAAC,OAAO,EAAE,SAAS,wBAMpC;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,CAEtD"}
@@ -1,15 +0,0 @@
1
- import { Providers } from '../provider/providers';
2
- import { ClassNameSymbol, InjectableDecorator } from '../injctable/injectable.decorator';
3
- export const providers = new Providers();
4
- export const DISymbol = Symbol('@DI');
5
- export function DI(options) {
6
- return (target) => {
7
- target[ClassNameSymbol] = 'root';
8
- Reflect.metadata(DISymbol, options)(target);
9
- return InjectableDecorator(target);
10
- };
11
- }
12
- export function getDIMetadata(target) {
13
- return Reflect.getMetadata(DISymbol, target);
14
- }
15
- //# sourceMappingURL=di.decorator.js.map