@acodeninja/persist 1.0.0 → 1.1.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.
package/package.json
CHANGED
package/src/engine/Engine.js
CHANGED
@@ -40,6 +40,7 @@ export default class Engine {
|
|
40
40
|
}
|
41
41
|
|
42
42
|
static async search(model, query) {
|
43
|
+
this._checkConfiguration?.();
|
43
44
|
const index = await this.getSearchIndexCompiled(model);
|
44
45
|
|
45
46
|
try {
|
@@ -61,12 +62,14 @@ export default class Engine {
|
|
61
62
|
}
|
62
63
|
|
63
64
|
static async find(model, parameters) {
|
65
|
+
this._checkConfiguration?.();
|
64
66
|
const response = await this.findByValue(model, parameters);
|
65
67
|
|
66
68
|
return response.map(m => model.fromData(m));
|
67
69
|
}
|
68
70
|
|
69
71
|
static async put(model) {
|
72
|
+
this._checkConfiguration?.();
|
70
73
|
const uploadedModels = [];
|
71
74
|
const indexUpdates = {};
|
72
75
|
|
@@ -87,7 +90,7 @@ export default class Engine {
|
|
87
90
|
await this.putSearchIndexRaw(model.constructor, rawSearchIndex);
|
88
91
|
|
89
92
|
const compiledIndex = lunr(function () {
|
90
|
-
this.ref('id')
|
93
|
+
this.ref('id');
|
91
94
|
|
92
95
|
for (const field of model.constructor.searchProperties()) {
|
93
96
|
this.field(field);
|
@@ -95,7 +98,7 @@ export default class Engine {
|
|
95
98
|
|
96
99
|
Object.values(rawSearchIndex).forEach(function (doc) {
|
97
100
|
this.add(doc);
|
98
|
-
}, this)
|
101
|
+
}, this);
|
99
102
|
});
|
100
103
|
|
101
104
|
await this.putSearchIndexCompiled(model.constructor, compiledIndex);
|
@@ -118,6 +121,7 @@ export default class Engine {
|
|
118
121
|
}
|
119
122
|
|
120
123
|
static async get(model, id) {
|
124
|
+
this._checkConfiguration?.();
|
121
125
|
const found = await this.getById(id);
|
122
126
|
|
123
127
|
try {
|
@@ -128,6 +132,7 @@ export default class Engine {
|
|
128
132
|
}
|
129
133
|
|
130
134
|
static async hydrate(model) {
|
135
|
+
this._checkConfiguration?.();
|
131
136
|
const hydratedModels = {};
|
132
137
|
|
133
138
|
const hydrateModel = async (modelToProcess) => {
|
@@ -142,7 +147,7 @@ export default class Engine {
|
|
142
147
|
}
|
143
148
|
|
144
149
|
return modelToProcess;
|
145
|
-
}
|
150
|
+
};
|
146
151
|
|
147
152
|
const hydrateSubModel = async (property, modelToProcess, name) => {
|
148
153
|
if (hydratedModels[property.id]) {
|
@@ -155,7 +160,7 @@ export default class Engine {
|
|
155
160
|
const hydratedSubModel = await hydrateModel(subModel);
|
156
161
|
hydratedModels[property.id] = hydratedSubModel;
|
157
162
|
return hydratedSubModel;
|
158
|
-
}
|
163
|
+
};
|
159
164
|
|
160
165
|
const hydrateModelList = async (property, modelToProcess, name) => {
|
161
166
|
const subModelClass = getSubModelClass(modelToProcess, name, true);
|
@@ -177,7 +182,7 @@ export default class Engine {
|
|
177
182
|
hydratedModels[hydratedSubModel.id] = hydratedSubModel;
|
178
183
|
return hydratedSubModel;
|
179
184
|
}));
|
180
|
-
}
|
185
|
+
};
|
181
186
|
|
182
187
|
function getSubModelClass(modelToProcess, name, isArray = false) {
|
183
188
|
const constructorField = modelToProcess.constructor[name];
|
@@ -195,7 +200,7 @@ export default class Engine {
|
|
195
200
|
static _configuration = configuration;
|
196
201
|
}
|
197
202
|
|
198
|
-
Object.defineProperty(ConfiguredStore, 'name', {value: `${this.toString()}`})
|
203
|
+
Object.defineProperty(ConfiguredStore, 'name', {value: `${this.toString()}`});
|
199
204
|
|
200
205
|
return ConfiguredStore;
|
201
206
|
}
|
@@ -213,3 +218,12 @@ export class NotFoundEngineError extends EngineError {
|
|
213
218
|
|
214
219
|
export class NotImplementedError extends EngineError {
|
215
220
|
}
|
221
|
+
|
222
|
+
export class MissConfiguredError extends EngineError {
|
223
|
+
configuration;
|
224
|
+
|
225
|
+
constructor(configuration) {
|
226
|
+
super('Engine is miss-configured');
|
227
|
+
this.configuration = configuration;
|
228
|
+
}
|
229
|
+
}
|
@@ -0,0 +1,175 @@
|
|
1
|
+
import Engine, {MissConfiguredError} from './Engine.js';
|
2
|
+
|
3
|
+
export default class HTTPEngine extends Engine {
|
4
|
+
static configure(configuration = {}) {
|
5
|
+
configuration.fetchOptions = {
|
6
|
+
...(configuration.fetchOptions ?? {}),
|
7
|
+
headers: {
|
8
|
+
...(configuration.fetchOptions?.headers ?? {}),
|
9
|
+
Accept: 'application/json',
|
10
|
+
},
|
11
|
+
};
|
12
|
+
|
13
|
+
return super.configure(configuration);
|
14
|
+
}
|
15
|
+
|
16
|
+
static _checkConfiguration() {
|
17
|
+
if (
|
18
|
+
!this._configuration?.host
|
19
|
+
) throw new MissConfiguredError(this._configuration);
|
20
|
+
}
|
21
|
+
|
22
|
+
static _getReadOptions() {
|
23
|
+
return this._configuration.fetchOptions;
|
24
|
+
}
|
25
|
+
|
26
|
+
static _getWriteOptions() {
|
27
|
+
return {
|
28
|
+
...this._getReadOptions(),
|
29
|
+
headers: {
|
30
|
+
...this._getReadOptions().headers,
|
31
|
+
'Content-Type': 'application/json',
|
32
|
+
},
|
33
|
+
method: 'PUT',
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
static async getById(id) {
|
38
|
+
this._checkConfiguration();
|
39
|
+
const url = new URL([
|
40
|
+
this._configuration.host,
|
41
|
+
this._configuration.prefix,
|
42
|
+
`${id}.json`,
|
43
|
+
].filter(e => !!e).join('/'));
|
44
|
+
|
45
|
+
try {
|
46
|
+
return await this._configuration.fetch(url, this._getReadOptions()).then(r => r.json());
|
47
|
+
} catch (_error) {
|
48
|
+
return undefined;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
static async findByValue(model, parameters) {
|
53
|
+
const index = await this.getIndex(model.name);
|
54
|
+
return Object.values(index)
|
55
|
+
.filter((model) =>
|
56
|
+
Object.entries(parameters)
|
57
|
+
.some(([name, value]) => model[name] === value),
|
58
|
+
);
|
59
|
+
}
|
60
|
+
|
61
|
+
static async putModel(model) {
|
62
|
+
const url = new URL([
|
63
|
+
this._configuration.host,
|
64
|
+
this._configuration.prefix,
|
65
|
+
`${model.id}.json`,
|
66
|
+
].filter(e => !!e).join('/'));
|
67
|
+
|
68
|
+
try {
|
69
|
+
return await this._configuration.fetch(url, {
|
70
|
+
...this._getWriteOptions(),
|
71
|
+
body: JSON.stringify(model.toData()),
|
72
|
+
}).then(r => r.json());
|
73
|
+
} catch (_error) {
|
74
|
+
return undefined;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
static async putIndex(index) {
|
79
|
+
const processIndex = async (location, models) => {
|
80
|
+
const modelIndex = Object.fromEntries(models.map(m => [m.id, m.toIndexData()]));
|
81
|
+
const url = new URL([
|
82
|
+
this._configuration.host,
|
83
|
+
this._configuration.prefix,
|
84
|
+
location,
|
85
|
+
'_index.json',
|
86
|
+
].filter(e => !!e).join('/'));
|
87
|
+
|
88
|
+
const currentIndex = await this.getIndex(location);
|
89
|
+
|
90
|
+
try {
|
91
|
+
return await this._configuration.fetch(url, {
|
92
|
+
...this._getWriteOptions(),
|
93
|
+
body: JSON.stringify({
|
94
|
+
...currentIndex,
|
95
|
+
...modelIndex,
|
96
|
+
}),
|
97
|
+
}).then(r => r.json());
|
98
|
+
} catch (_error) {
|
99
|
+
return undefined;
|
100
|
+
}
|
101
|
+
};
|
102
|
+
|
103
|
+
for (const [location, models] of Object.entries(index)) {
|
104
|
+
await processIndex(location, models);
|
105
|
+
}
|
106
|
+
|
107
|
+
await processIndex(null, Object.values(index).flat());
|
108
|
+
}
|
109
|
+
|
110
|
+
static async getIndex(location) {
|
111
|
+
const url = new URL(this._configuration.host + '/' + [this._configuration.prefix, location, '_index.json'].filter(e => !!e).join('/'));
|
112
|
+
|
113
|
+
try {
|
114
|
+
return await this._configuration.fetch(url, this._getReadOptions()).then(r => r.json());
|
115
|
+
} catch (_error) {
|
116
|
+
return {};
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
static async getSearchIndexCompiled(model) {
|
121
|
+
const url = new URL(this._configuration.host + '/' + [this._configuration.prefix].concat([model.name]).concat(['_search_index.json']).join('/'));
|
122
|
+
|
123
|
+
try {
|
124
|
+
return await this._configuration.fetch(url, this._getReadOptions()).then(r => r.json());
|
125
|
+
} catch (_error) {
|
126
|
+
return {};
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
static async getSearchIndexRaw(model) {
|
131
|
+
const url = new URL(this._configuration.host + '/' + [this._configuration.prefix].concat([model.name]).concat(['_search_index_raw.json']).join('/'));
|
132
|
+
|
133
|
+
try {
|
134
|
+
return await this._configuration.fetch(url, this._getReadOptions()).then(r => r.json());
|
135
|
+
} catch (_error) {
|
136
|
+
return {};
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
static async putSearchIndexCompiled(model, compiledIndex) {
|
141
|
+
const url = new URL([
|
142
|
+
this._configuration.host,
|
143
|
+
this._configuration.prefix,
|
144
|
+
model.name,
|
145
|
+
'_search_index.json',
|
146
|
+
].filter(e => !!e).join('/'));
|
147
|
+
|
148
|
+
try {
|
149
|
+
return await this._configuration.fetch(url, {
|
150
|
+
...this._getWriteOptions(),
|
151
|
+
body: JSON.stringify(compiledIndex),
|
152
|
+
}).then(r => r.json());
|
153
|
+
} catch (_error) {
|
154
|
+
return undefined;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
static async putSearchIndexRaw(model, rawIndex) {
|
159
|
+
const url = new URL([
|
160
|
+
this._configuration.host,
|
161
|
+
this._configuration.prefix,
|
162
|
+
model.name,
|
163
|
+
'_search_index_raw.json',
|
164
|
+
].filter(e => !!e).join('/'));
|
165
|
+
|
166
|
+
try {
|
167
|
+
return await this._configuration.fetch(url, {
|
168
|
+
...this._getWriteOptions(),
|
169
|
+
body: JSON.stringify(rawIndex),
|
170
|
+
}).then(r => r.json());
|
171
|
+
} catch (_error) {
|
172
|
+
return undefined;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
package/src/type/Model.js
CHANGED
@@ -3,7 +3,7 @@ import Type from '../Type.js';
|
|
3
3
|
export default class ArrayType {
|
4
4
|
static of(type) {
|
5
5
|
class ArrayOf extends Type {
|
6
|
-
static _type = 'array'
|
6
|
+
static _type = 'array';
|
7
7
|
static _items = type;
|
8
8
|
|
9
9
|
static toString() {
|
@@ -19,7 +19,7 @@ export default class ArrayType {
|
|
19
19
|
}
|
20
20
|
}
|
21
21
|
|
22
|
-
Object.defineProperty(Required, 'name', {value: `Required${this.toString()}Type`})
|
22
|
+
Object.defineProperty(Required, 'name', {value: `Required${this.toString()}Type`});
|
23
23
|
|
24
24
|
return Required;
|
25
25
|
}
|