@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acodeninja/persist",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A JSON based data modelling and persistence module with alternate storage mechanisms.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -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
@@ -75,7 +75,7 @@ export default class Model {
75
75
  static _required = true;
76
76
  }
77
77
 
78
- Object.defineProperty(Required, 'name', {value: `${this.toString()}`})
78
+ Object.defineProperty(Required, 'name', {value: `${this.toString()}`});
79
79
 
80
80
  return Required;
81
81
  }
@@ -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
  }
@@ -4,7 +4,7 @@ import slugify from 'slugify';
4
4
  export default class SlugType extends ResolvedType {
5
5
  static of(property) {
6
6
  class SlugOf extends ResolvedType {
7
- static _type = 'string'
7
+ static _type = 'string';
8
8
 
9
9
  static toString() {
10
10
  return `SlugOf(${property})`;