@acodeninja/persist 3.0.0-next.16 → 3.0.0-next.18
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 +1 -0
- package/docs/storage-engines.md +4 -3
- package/docs/structured-queries.md +5 -5
- package/package.json +1 -1
- package/src/Persist.js +6 -4
- package/src/data/FindIndex.js +8 -7
- package/src/data/Model.js +13 -23
- package/src/engine/storage/HTTPStorageEngine.js +12 -12
- package/src/engine/storage/S3StorageEngine.js +12 -12
package/README.md
CHANGED
@@ -9,6 +9,7 @@ A JSON based data modelling and persistence library with alternate storage mecha
|
|
9
9
|
|
10
10
|
[](https://app.deepsource.com/gh/acodeninja/persist/)
|
11
11
|
[](https://app.deepsource.com/gh/acodeninja/persist/)
|
12
|
+

|
12
13
|
|
13
14
|
## Features
|
14
15
|
|
package/docs/storage-engines.md
CHANGED
@@ -8,6 +8,7 @@ To store models using an S3 Bucket, use the `S3` storage engine. To use the `S3`
|
|
8
8
|
|
9
9
|
```javascript
|
10
10
|
import Persist from "@acodeninja/persist";
|
11
|
+
import {S3Client} from "@aws-sdk/client-s3";
|
11
12
|
import S3StorageEngine from "@acodeninja/persist/storage/s3";
|
12
13
|
|
13
14
|
const connection = Persist.registerConnection('remote', new S3StorageEngine({
|
@@ -28,14 +29,14 @@ To store models using an HTTP server, use the `HTTP` storage engine. When using
|
|
28
29
|
|
29
30
|
```javascript
|
30
31
|
import Persist from "@acodeninja/persist";
|
31
|
-
import HTTPStorageEngine from "@acodeninja/persist/
|
32
|
+
import HTTPStorageEngine from "@acodeninja/persist/storage/http";
|
32
33
|
|
33
34
|
const connection = Persist.registerConnection('remote', new HTTPStorageEngine({
|
34
35
|
baseUrl: 'https://api.example.com',
|
35
36
|
}));
|
36
37
|
|
37
|
-
export class Tag extends Persist.
|
38
|
-
static tag = Persist.
|
38
|
+
export class Tag extends Persist.Model {
|
39
|
+
static tag = Persist.Property.String.required;
|
39
40
|
}
|
40
41
|
|
41
42
|
await connection.put(new Tag({tag: 'documentation'}));
|
@@ -41,7 +41,7 @@ To query for a `Person` called `Joe Bloggs` an exact query can be written:
|
|
41
41
|
```javascript
|
42
42
|
import Persist from "@acodeninja/persist";
|
43
43
|
|
44
|
-
const connection = Persist.
|
44
|
+
const connection = Persist.getConnection('people');
|
45
45
|
|
46
46
|
await connection.find(Person, {
|
47
47
|
name: {$is: 'Joe Bloggs'},
|
@@ -55,7 +55,7 @@ To query for a `Person` with name `Joe` a contains query can be written:
|
|
55
55
|
```javascript
|
56
56
|
import Persist from "@acodeninja/persist";
|
57
57
|
|
58
|
-
const connection = Persist.
|
58
|
+
const connection = Persist.getConnection('people');
|
59
59
|
|
60
60
|
await connection.find(Person, {
|
61
61
|
name: {$contains: 'Joe'},
|
@@ -69,7 +69,7 @@ To query for all instances of `Address` with a linked `Person` with a name that
|
|
69
69
|
```javascript
|
70
70
|
import Persist from "@acodeninja/persist";
|
71
71
|
|
72
|
-
const connection = Persist.
|
72
|
+
const connection = Persist.getConnection('people');
|
73
73
|
|
74
74
|
await connection.find(Address, {
|
75
75
|
people: {
|
@@ -87,7 +87,7 @@ To query for a `Person` who lives at `SW1 1AA` a combination of contains and exa
|
|
87
87
|
```javascript
|
88
88
|
import Persist from "@acodeninja/persist";
|
89
89
|
|
90
|
-
const connection = Persist.
|
90
|
+
const connection = Persist.getConnection('people');
|
91
91
|
|
92
92
|
await connection.find(Person, {
|
93
93
|
address: {
|
@@ -105,7 +105,7 @@ To query for anyone called `Joe Bloggs` who lives in the `SW1` postcode area, we
|
|
105
105
|
```javascript
|
106
106
|
import Persist from "@acodeninja/persist";
|
107
107
|
|
108
|
-
const connection = Persist.
|
108
|
+
const connection = Persist.getConnection('people');
|
109
109
|
|
110
110
|
await connection.find(Person, {
|
111
111
|
name: {$is: 'Joe Bloggs'},
|
package/package.json
CHANGED
package/src/Persist.js
CHANGED
@@ -15,7 +15,7 @@ class Persist {
|
|
15
15
|
ValidationError,
|
16
16
|
};
|
17
17
|
|
18
|
-
static #connections =
|
18
|
+
static #connections = new Map();
|
19
19
|
|
20
20
|
/**
|
21
21
|
* Register a new connection.
|
@@ -25,9 +25,11 @@ class Persist {
|
|
25
25
|
* @return {Connection}
|
26
26
|
*/
|
27
27
|
static registerConnection(name, storage, models) {
|
28
|
-
|
28
|
+
const connection = new Connection(storage, models);
|
29
29
|
|
30
|
-
|
30
|
+
Persist.#connections.set(name, connection);
|
31
|
+
|
32
|
+
return connection;
|
31
33
|
}
|
32
34
|
|
33
35
|
/**
|
@@ -36,7 +38,7 @@ class Persist {
|
|
36
38
|
* @return {Connection|undefined}
|
37
39
|
*/
|
38
40
|
static getConnection(name) {
|
39
|
-
return
|
41
|
+
return Persist.#connections.get(name);
|
40
42
|
}
|
41
43
|
}
|
42
44
|
|
package/src/data/FindIndex.js
CHANGED
@@ -43,12 +43,12 @@ class FindIndex {
|
|
43
43
|
/**
|
44
44
|
* Constructs a new `Query` instance with the provided query object.
|
45
45
|
*
|
46
|
-
* @param {Model.constructor}
|
46
|
+
* @param {Model.constructor} modelConstructor - The model class.
|
47
47
|
* @param {Record<string, Model>} index - The index dataset to search through.
|
48
48
|
*/
|
49
|
-
constructor(
|
49
|
+
constructor(modelConstructor, index) {
|
50
50
|
this.#index = index;
|
51
|
-
this.#modelConstructor =
|
51
|
+
this.#modelConstructor = modelConstructor;
|
52
52
|
}
|
53
53
|
|
54
54
|
/**
|
@@ -93,10 +93,11 @@ class FindIndex {
|
|
93
93
|
if (subject.includes?.(inputQuery.$contains))
|
94
94
|
return true;
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
if (typeof subject[Symbol.iterator] === 'function')
|
97
|
+
for (const value of subject) {
|
98
|
+
if (this.#matchesQuery(value, inputQuery.$contains))
|
99
|
+
return true;
|
100
|
+
}
|
100
101
|
}
|
101
102
|
|
102
103
|
for (const key of Object.keys(inputQuery)) {
|
package/src/data/Model.js
CHANGED
@@ -171,6 +171,10 @@ class Model {
|
|
171
171
|
/**
|
172
172
|
* Returns a list of properties that are indexed.
|
173
173
|
*
|
174
|
+
* - To link to properties of a model use `<name>`
|
175
|
+
* - To link to properties of linked models use `<model>.<name>`
|
176
|
+
* - To link to properties of many linked models use `<model>.[*].<name>`
|
177
|
+
*
|
174
178
|
* @returns {Array<string>} - The indexed properties.
|
175
179
|
* @abstract
|
176
180
|
* @static
|
@@ -187,29 +191,15 @@ class Model {
|
|
187
191
|
* @static
|
188
192
|
*/
|
189
193
|
static indexedPropertiesResolved() {
|
190
|
-
return [
|
191
|
-
.
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
)
|
200
|
-
.map(([name, _type]) => `${name}.id`),
|
201
|
-
)
|
202
|
-
.concat(
|
203
|
-
Object.entries(this)
|
204
|
-
.filter(([_name, type]) =>
|
205
|
-
!/^class/.test(Function.prototype.toString.call(type)) || type.toString().includes('Array'),
|
206
|
-
)
|
207
|
-
.filter(([_name, type]) =>
|
208
|
-
this.isModel(type._items ?? type()._items ?? type),
|
209
|
-
)
|
210
|
-
.map(([name, _type]) => `${name}.[*].id`),
|
211
|
-
)
|
212
|
-
.concat(this.indexedProperties());
|
194
|
+
return [
|
195
|
+
...Object.entries(this)
|
196
|
+
.filter(([_name, type]) => !type._type && (this.isModel(type) || this.isModel(type())))
|
197
|
+
.map(([name, _type]) => `${name}.id`),
|
198
|
+
...Object.entries(this)
|
199
|
+
.filter(([_name, type]) => !type._type && !this.isModel(type) && !type._items?._type && (this.isModel(type._items) || this.isModel(type()._items)))
|
200
|
+
.map(([name, _type]) => `${name}.[*].id`),
|
201
|
+
...this.indexedProperties(),
|
202
|
+
];
|
213
203
|
}
|
214
204
|
|
215
205
|
/**
|
@@ -74,12 +74,12 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
74
74
|
|
75
75
|
/**
|
76
76
|
* Get a model's index data
|
77
|
-
* @param {Model.constructor}
|
77
|
+
* @param {Model.constructor} modelConstructor
|
78
78
|
* @return Promise<void>
|
79
79
|
*/
|
80
|
-
getIndex(
|
80
|
+
getIndex(modelConstructor) {
|
81
81
|
return this.#processFetch(
|
82
|
-
this.#generateURL([
|
82
|
+
this.#generateURL([modelConstructor.name]),
|
83
83
|
this.#getReadOptions(),
|
84
84
|
{},
|
85
85
|
);
|
@@ -87,13 +87,13 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
87
87
|
|
88
88
|
/**
|
89
89
|
* Put a model's index data
|
90
|
-
* @param {Model.constructor}
|
90
|
+
* @param {Model.constructor} modelConstructor
|
91
91
|
* @param {object} index
|
92
92
|
* @throws MethodNotImplementedStorageEngineError
|
93
93
|
* @return Promise<void>
|
94
94
|
*/
|
95
|
-
putIndex(
|
96
|
-
return this.#processFetch(this.#generateURL([
|
95
|
+
putIndex(modelConstructor, index) {
|
96
|
+
return this.#processFetch(this.#generateURL([modelConstructor.name]), {
|
97
97
|
...this.#getWriteOptions(),
|
98
98
|
body: JSON.stringify(index),
|
99
99
|
});
|
@@ -101,13 +101,13 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
101
101
|
|
102
102
|
/**
|
103
103
|
* Get a model's raw search index data
|
104
|
-
* @param {Model.constructor}
|
104
|
+
* @param {Model.constructor} modelConstructor
|
105
105
|
* @throws MethodNotImplementedStorageEngineError
|
106
106
|
* @return Promise<object>
|
107
107
|
*/
|
108
|
-
getSearchIndex(
|
108
|
+
getSearchIndex(modelConstructor) {
|
109
109
|
return this.#processFetch(
|
110
|
-
this.#generateURL([
|
110
|
+
this.#generateURL([modelConstructor.name, 'search']),
|
111
111
|
this.#getReadOptions(),
|
112
112
|
{},
|
113
113
|
);
|
@@ -115,13 +115,13 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
115
115
|
|
116
116
|
/**
|
117
117
|
* Put a model's raw and compiled search index data
|
118
|
-
* @param {Model.constructor}
|
118
|
+
* @param {Model.constructor} modelConstructor
|
119
119
|
* @param {Record<string, object>} index
|
120
120
|
* @throws MethodNotImplementedStorageEngineError
|
121
121
|
* @return Promise<void>
|
122
122
|
*/
|
123
|
-
putSearchIndex(
|
124
|
-
return this.#processFetch(this.#generateURL([
|
123
|
+
putSearchIndex(modelConstructor, index) {
|
124
|
+
return this.#processFetch(this.#generateURL([modelConstructor.name, 'search']), {
|
125
125
|
...this.#getWriteOptions(),
|
126
126
|
body: JSON.stringify(index),
|
127
127
|
});
|
@@ -85,12 +85,12 @@ class S3StorageEngine extends StorageEngine {
|
|
85
85
|
|
86
86
|
/**
|
87
87
|
* Get a model's index data
|
88
|
-
* @param {Model.constructor}
|
88
|
+
* @param {Model.constructor} modelConstructor
|
89
89
|
* @throws MethodNotImplementedStorageEngineError
|
90
90
|
* @return Promise<object>
|
91
91
|
*/
|
92
|
-
async getIndex(
|
93
|
-
const Key = this.#generatePath([
|
92
|
+
async getIndex(modelConstructor) {
|
93
|
+
const Key = this.#generatePath([modelConstructor.name, '_index.json']);
|
94
94
|
try {
|
95
95
|
const data = await this.configuration.client.send(new GetObjectCommand({
|
96
96
|
Bucket: this.configuration.bucket,
|
@@ -105,13 +105,13 @@ class S3StorageEngine extends StorageEngine {
|
|
105
105
|
|
106
106
|
/**
|
107
107
|
* Put a model's index data
|
108
|
-
* @param {Model.constructor}
|
108
|
+
* @param {Model.constructor} modelConstructor
|
109
109
|
* @param {object} index
|
110
110
|
* @throws MethodNotImplementedStorageEngineError
|
111
111
|
* @return Promise<void>
|
112
112
|
*/
|
113
|
-
async putIndex(
|
114
|
-
const Key = this.#generatePath([
|
113
|
+
async putIndex(modelConstructor, index) {
|
114
|
+
const Key = this.#generatePath([modelConstructor.name, '_index.json']);
|
115
115
|
await this.configuration.client.send(new PutObjectCommand({
|
116
116
|
Key,
|
117
117
|
Bucket: this.configuration.bucket,
|
@@ -122,11 +122,11 @@ class S3StorageEngine extends StorageEngine {
|
|
122
122
|
|
123
123
|
/**
|
124
124
|
* Get a model's raw search index data
|
125
|
-
* @param {Model.constructor}
|
125
|
+
* @param {Model.constructor} modelConstructor
|
126
126
|
* @return Promise<Record<string, object>>
|
127
127
|
*/
|
128
|
-
async getSearchIndex(
|
129
|
-
const Key = this.#generatePath([
|
128
|
+
async getSearchIndex(modelConstructor) {
|
129
|
+
const Key = this.#generatePath([modelConstructor.name, '_search_index.json']);
|
130
130
|
|
131
131
|
try {
|
132
132
|
const data = await this.configuration.client.send(new GetObjectCommand({
|
@@ -142,12 +142,12 @@ class S3StorageEngine extends StorageEngine {
|
|
142
142
|
|
143
143
|
/**
|
144
144
|
* Put a model's search index data
|
145
|
-
* @param {Model.constructor}
|
145
|
+
* @param {Model.constructor} modelConstructor
|
146
146
|
* @param {Record<string, object>} index
|
147
147
|
* @return Promise<void>
|
148
148
|
*/
|
149
|
-
async putSearchIndex(
|
150
|
-
const Key = this.#generatePath([
|
149
|
+
async putSearchIndex(modelConstructor, index) {
|
150
|
+
const Key = this.#generatePath([modelConstructor.name, '_search_index.json']);
|
151
151
|
|
152
152
|
await this.configuration.client.send(new PutObjectCommand({
|
153
153
|
Key,
|