@webda/core 1.2.1 → 1.6.0-beta.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 (199) hide show
  1. package/lib/application.d.ts +3 -0
  2. package/lib/application.js +26 -22
  3. package/lib/application.js.map +1 -1
  4. package/lib/application.spec.js +185 -2
  5. package/lib/application.spec.js.map +1 -1
  6. package/lib/core.d.ts +62 -6
  7. package/lib/core.js +127 -86
  8. package/lib/core.js.map +1 -1
  9. package/lib/core.spec.js +151 -6
  10. package/lib/core.spec.js.map +1 -1
  11. package/lib/index.d.ts +4 -0
  12. package/lib/index.js +4 -0
  13. package/lib/index.js.map +1 -1
  14. package/lib/models/aclmodel.d.ts +42 -3
  15. package/lib/models/aclmodel.js +58 -3
  16. package/lib/models/aclmodel.js.map +1 -1
  17. package/lib/models/aclmodel.spec.js +46 -0
  18. package/lib/models/aclmodel.spec.js.map +1 -1
  19. package/lib/models/coremodel.d.ts +58 -10
  20. package/lib/models/coremodel.js +39 -32
  21. package/lib/models/coremodel.js.map +1 -1
  22. package/lib/models/coremodel.spec.js +68 -6
  23. package/lib/models/coremodel.spec.js.map +1 -1
  24. package/lib/models/ident.d.ts +8 -2
  25. package/lib/models/ident.js.map +1 -1
  26. package/lib/models/ident.spec.js +16 -0
  27. package/lib/models/ident.spec.js.map +1 -1
  28. package/lib/models/ownermodel.d.ts +1 -1
  29. package/lib/models/ownermodel.js.map +1 -1
  30. package/lib/models/ownermodel.spec.js +22 -19
  31. package/lib/models/ownermodel.spec.js.map +1 -1
  32. package/lib/models/user.d.ts +2 -0
  33. package/lib/models/user.js +4 -2
  34. package/lib/models/user.js.map +1 -1
  35. package/lib/models/user.spec.js +9 -2
  36. package/lib/models/user.spec.js.map +1 -1
  37. package/lib/queues/filequeue.d.ts +63 -0
  38. package/lib/queues/filequeue.js +161 -0
  39. package/lib/queues/filequeue.js.map +1 -0
  40. package/lib/queues/filequeue.spec.d.ts +1 -0
  41. package/lib/queues/filequeue.spec.js +90 -0
  42. package/lib/queues/filequeue.spec.js.map +1 -0
  43. package/lib/queues/memoryqueue.d.ts +18 -4
  44. package/lib/queues/memoryqueue.js +20 -13
  45. package/lib/queues/memoryqueue.js.map +1 -1
  46. package/lib/queues/memoryqueue.spec.js +142 -39
  47. package/lib/queues/memoryqueue.spec.js.map +1 -1
  48. package/lib/queues/pubsubservice.d.ts +27 -0
  49. package/lib/queues/pubsubservice.js +21 -0
  50. package/lib/queues/pubsubservice.js.map +1 -0
  51. package/lib/queues/queue.spec.js +16 -7
  52. package/lib/queues/queue.spec.js.map +1 -1
  53. package/lib/queues/queueservice.d.ts +108 -13
  54. package/lib/queues/queueservice.js +100 -36
  55. package/lib/queues/queueservice.js.map +1 -1
  56. package/lib/router.js +4 -6
  57. package/lib/router.js.map +1 -1
  58. package/lib/router.spec.js +27 -2
  59. package/lib/router.spec.js.map +1 -1
  60. package/lib/services/asyncevents.d.ts +110 -5
  61. package/lib/services/asyncevents.js +134 -39
  62. package/lib/services/asyncevents.js.map +1 -1
  63. package/lib/services/asyncevents.spec.js +58 -4
  64. package/lib/services/asyncevents.spec.js.map +1 -1
  65. package/lib/services/authentication.d.ts +57 -5
  66. package/lib/services/authentication.js +93 -84
  67. package/lib/services/authentication.js.map +1 -1
  68. package/lib/services/authentication.spec.js +118 -82
  69. package/lib/services/authentication.spec.js.map +1 -1
  70. package/lib/services/binary.d.ts +175 -48
  71. package/lib/services/binary.js +205 -170
  72. package/lib/services/binary.js.map +1 -1
  73. package/lib/services/binary.spec.d.ts +22 -3
  74. package/lib/services/binary.spec.js +327 -22
  75. package/lib/services/binary.spec.js.map +1 -1
  76. package/lib/services/configuration.d.ts +94 -13
  77. package/lib/services/configuration.js +98 -28
  78. package/lib/services/configuration.js.map +1 -1
  79. package/lib/services/configuration.spec.js +40 -1
  80. package/lib/services/configuration.spec.js.map +1 -1
  81. package/lib/services/cron.d.ts +4 -4
  82. package/lib/services/cron.js +37 -53
  83. package/lib/services/cron.js.map +1 -1
  84. package/lib/services/cron.spec.d.ts +1 -0
  85. package/lib/services/cron.spec.js +76 -0
  86. package/lib/services/cron.spec.js.map +1 -0
  87. package/lib/services/debugmailer.spec.js +18 -4
  88. package/lib/services/debugmailer.spec.js.map +1 -1
  89. package/lib/services/echo.js +22 -13
  90. package/lib/services/echo.js.map +1 -1
  91. package/lib/services/echo.spec.d.ts +1 -0
  92. package/lib/services/echo.spec.js +52 -0
  93. package/lib/services/echo.spec.js.map +1 -0
  94. package/lib/services/filebinary.d.ts +16 -9
  95. package/lib/services/filebinary.js +58 -73
  96. package/lib/services/filebinary.js.map +1 -1
  97. package/lib/services/filebinary.spec.d.ts +8 -1
  98. package/lib/services/filebinary.spec.js +133 -7
  99. package/lib/services/filebinary.spec.js.map +1 -1
  100. package/lib/services/fileconfiguration.d.ts +9 -3
  101. package/lib/services/fileconfiguration.js +13 -6
  102. package/lib/services/fileconfiguration.js.map +1 -1
  103. package/lib/services/fileconfiguration.spec.js +100 -5
  104. package/lib/services/fileconfiguration.spec.js.map +1 -1
  105. package/lib/services/kubernetesconfiguration.d.ts +8 -2
  106. package/lib/services/kubernetesconfiguration.js +16 -5
  107. package/lib/services/kubernetesconfiguration.js.map +1 -1
  108. package/lib/services/kubernetesconfiguration.spec.js +53 -16
  109. package/lib/services/kubernetesconfiguration.spec.js.map +1 -1
  110. package/lib/services/mailer.d.ts +11 -2
  111. package/lib/services/mailer.js +28 -34
  112. package/lib/services/mailer.js.map +1 -1
  113. package/lib/services/mailer.spec.js +69 -23
  114. package/lib/services/mailer.spec.js.map +1 -1
  115. package/lib/services/oauth.d.ts +5 -2
  116. package/lib/services/oauth.js +22 -8
  117. package/lib/services/oauth.js.map +1 -1
  118. package/lib/services/oauth.spec.js +33 -3
  119. package/lib/services/oauth.spec.js.map +1 -1
  120. package/lib/services/resource.spec.js +39 -2
  121. package/lib/services/resource.spec.js.map +1 -1
  122. package/lib/services/service.d.ts +16 -0
  123. package/lib/services/service.js +47 -6
  124. package/lib/services/service.js.map +1 -1
  125. package/lib/services/service.spec.d.ts +1 -0
  126. package/lib/services/service.spec.js +119 -0
  127. package/lib/services/service.spec.js.map +1 -0
  128. package/lib/stores/aggregator.d.ts +43 -0
  129. package/lib/stores/aggregator.js +106 -0
  130. package/lib/stores/aggregator.js.map +1 -0
  131. package/lib/stores/file.d.ts +49 -11
  132. package/lib/stores/file.js +84 -81
  133. package/lib/stores/file.js.map +1 -1
  134. package/lib/stores/file.spec.d.ts +6 -1
  135. package/lib/stores/file.spec.js +134 -9
  136. package/lib/stores/file.spec.js.map +1 -1
  137. package/lib/stores/mapper.d.ts +151 -0
  138. package/lib/stores/mapper.js +294 -0
  139. package/lib/stores/mapper.js.map +1 -0
  140. package/lib/stores/mapper.spec.d.ts +1 -0
  141. package/lib/stores/mapper.spec.js +55 -0
  142. package/lib/stores/mapper.spec.js.map +1 -0
  143. package/lib/stores/memory.d.ts +52 -7
  144. package/lib/stores/memory.js +71 -33
  145. package/lib/stores/memory.js.map +1 -1
  146. package/lib/stores/memory.spec.d.ts +6 -1
  147. package/lib/stores/memory.spec.js +65 -4
  148. package/lib/stores/memory.spec.js.map +1 -1
  149. package/lib/stores/store.d.ts +263 -126
  150. package/lib/stores/store.js +285 -493
  151. package/lib/stores/store.js.map +1 -1
  152. package/lib/stores/store.spec.d.ts +20 -0
  153. package/lib/stores/store.spec.js +242 -18
  154. package/lib/stores/store.spec.js.map +1 -1
  155. package/lib/test.d.ts +1 -7
  156. package/lib/test.js +3 -12
  157. package/lib/test.js.map +1 -1
  158. package/lib/utils/abstractdeployer.spec.d.ts +1 -0
  159. package/lib/utils/abstractdeployer.spec.js +23 -0
  160. package/lib/utils/abstractdeployer.spec.js.map +1 -0
  161. package/lib/utils/context.d.ts +25 -2
  162. package/lib/utils/context.js +33 -12
  163. package/lib/utils/context.js.map +1 -1
  164. package/lib/utils/context.spec.js +81 -11
  165. package/lib/utils/context.spec.js.map +1 -1
  166. package/lib/utils/cookie.d.ts +12 -0
  167. package/lib/utils/cookie.js +13 -1
  168. package/lib/utils/cookie.js.map +1 -1
  169. package/lib/utils/cookie.spec.js +42 -11
  170. package/lib/utils/cookie.spec.js.map +1 -1
  171. package/lib/utils/logger.d.ts +23 -4
  172. package/lib/utils/logger.js +29 -6
  173. package/lib/utils/logger.js.map +1 -1
  174. package/lib/utils/logger.spec.js +8 -0
  175. package/lib/utils/logger.spec.js.map +1 -1
  176. package/lib/utils/serializers.d.ts +5 -5
  177. package/lib/utils/serializers.js +10 -10
  178. package/lib/utils/serializers.js.map +1 -1
  179. package/lib/utils/serializers.spec.js +41 -16
  180. package/lib/utils/serializers.spec.js.map +1 -1
  181. package/lib/utils/waiter.d.ts +59 -1
  182. package/lib/utils/waiter.js +86 -3
  183. package/lib/utils/waiter.js.map +1 -1
  184. package/lib/utils/waiter.spec.js +48 -4
  185. package/lib/utils/waiter.spec.js.map +1 -1
  186. package/package.json +16 -11
  187. package/test/badapp/package.json +4 -0
  188. package/test/badapp/webda.config.json +1 -0
  189. package/test/cachedapp/webda.config.json +7 -0
  190. package/test/config-file-no-reload.json +70 -0
  191. package/test/config-file-reload.json +7 -1
  192. package/test/config-kube-reload.json +7 -1
  193. package/test/config.json +45 -21
  194. package/test/config.old-default.json +0 -16
  195. package/test/config.old.json +0 -16
  196. package/test/deployments/invalid.json +1 -0
  197. package/test/moddas/fakeservice.js +5 -0
  198. package/test/models/ident.js +10 -14
  199. package/test/models/task.js +2 -4
@@ -9,19 +9,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.Store = exports.StoreParameters = void 0;
13
- const uuid_1 = require("uuid");
12
+ exports.Store = exports.StoreParameters = exports.UpdateConditionFailError = exports.StoreNotFoundError = void 0;
13
+ const core_1 = require("../core");
14
+ const coremodel_1 = require("../models/coremodel");
14
15
  const service_1 = require("../services/service");
16
+ class StoreNotFoundError extends core_1.WebdaError {
17
+ constructor(uuid, storeName) {
18
+ super("STORE_NOTFOUND", `Item not found ${uuid} Store(${storeName})`);
19
+ }
20
+ }
21
+ exports.StoreNotFoundError = StoreNotFoundError;
22
+ class UpdateConditionFailError extends core_1.WebdaError {
23
+ constructor(uuid, conditionField, condition) {
24
+ super("STORE_UPDATE_CONDITION_FAILED", `UpdateCondition not met on ${uuid}.${conditionField} === ${condition instanceof Date ? condition.toISOString() : condition}`);
25
+ }
26
+ }
27
+ exports.UpdateConditionFailError = UpdateConditionFailError;
15
28
  /**
16
29
  * Store parameter
17
30
  */
18
31
  class StoreParameters extends service_1.ServiceParameters {
19
32
  constructor(params, service) {
20
- var _a, _b, _c;
33
+ var _a, _b;
21
34
  super(params);
22
- (_a = this.lastUpdateField) !== null && _a !== void 0 ? _a : (this.lastUpdateField = "_lastUpdate");
23
- (_b = this.creationDateField) !== null && _b !== void 0 ? _b : (this.creationDateField = "_creationDate");
24
- (_c = this.model) !== null && _c !== void 0 ? _c : (this.model = "Webda/CoreModel");
35
+ (_a = this.model) !== null && _a !== void 0 ? _a : (this.model = "Webda/CoreModel");
25
36
  let expose = params.expose;
26
37
  if (typeof expose == "boolean") {
27
38
  expose = {};
@@ -39,6 +50,13 @@ class StoreParameters extends service_1.ServiceParameters {
39
50
  expose.restrict = expose.restrict || {};
40
51
  this.expose = expose;
41
52
  }
53
+ if (params.map) {
54
+ throw new Error("Deprecated map usage, use a MapperService");
55
+ }
56
+ if (params.index) {
57
+ throw new Error("Deprecated index usage, use an AggregatorService");
58
+ }
59
+ (_b = this.strict) !== null && _b !== void 0 ? _b : (this.strict = true);
42
60
  }
43
61
  }
44
62
  exports.StoreParameters = StoreParameters;
@@ -79,8 +97,13 @@ exports.StoreParameters = StoreParameters;
79
97
  class Store extends service_1.Service {
80
98
  constructor() {
81
99
  super(...arguments);
100
+ /**
101
+ * Contain the reverse map
102
+ */
82
103
  this._reverseMap = [];
83
- this._cascade = [];
104
+ /**
105
+ * Contain the model uuid field
106
+ */
84
107
  this._uuidField = "uuid";
85
108
  }
86
109
  /**
@@ -98,31 +121,31 @@ class Store extends service_1.Service {
98
121
  super.computeParameters();
99
122
  const p = this.parameters;
100
123
  this._model = this._webda.getModel(p.model);
101
- if (!this._model) {
102
- throw new Error(`${p.model} model is not found`);
103
- }
104
124
  this._uuidField = this._model.getUuidField();
105
- this._lastUpdateField = p.lastUpdateField || "_lastUpdate";
106
- this._creationDateField = p.creationDateField || "_creationDate";
125
+ this._lastUpdateField = this._model.getLastUpdateField();
126
+ this._creationDateField = this._model.getCreationField();
107
127
  }
128
+ /**
129
+ * Return Store current model
130
+ * @returns
131
+ */
108
132
  getModel() {
109
133
  return this._model;
110
134
  }
111
- getUuidField() {
112
- return this._uuidField;
135
+ getLastUpdateField() {
136
+ return this._model.getLastUpdateField();
113
137
  }
114
- init() {
115
- return __awaiter(this, void 0, void 0, function* () {
116
- this.initMap(this.parameters.map);
117
- if (this.parameters.index) {
118
- yield this.createIndex();
119
- }
120
- });
138
+ getObject(uid) {
139
+ return this._get(uid);
121
140
  }
141
+ /**
142
+ * @inheritdoc
143
+ */
122
144
  initRoutes() {
123
145
  if (!this.parameters.expose) {
124
146
  return;
125
147
  }
148
+ // We enforce ExposeParameters within the constructor
126
149
  const expose = this.parameters.expose;
127
150
  if (!expose.restrict.create) {
128
151
  this.addRoute(expose.url, ["POST"], this.httpCreate, {
@@ -155,7 +178,6 @@ class Store extends service_1.Service {
155
178
  if (!expose.restrict.delete) {
156
179
  methods.push("DELETE");
157
180
  }
158
- this._exposeUrl = expose.url;
159
181
  if (methods.length) {
160
182
  this.addRoute(expose.url + "/{uuid}", methods, this.httpRoute, {
161
183
  model: this._model.name,
@@ -215,86 +237,77 @@ class Store extends service_1.Service {
215
237
  let actions = this._model.getActions();
216
238
  Object.keys(actions).forEach(name => {
217
239
  let action = actions[name];
218
- action.name = name;
219
- if (!action.name) {
220
- throw Error("Action needs a name got:" + action);
221
- }
222
- if (!action.method) {
223
- action.method = ["PUT"];
240
+ if (!action.methods) {
241
+ action.methods = ["PUT"];
224
242
  }
243
+ let executer;
225
244
  if (action.global) {
226
245
  // By default will grab the object and then call the action
227
- if (!action._method) {
228
- if (!this._model["_" + action.name]) {
229
- throw Error("Action static method _" + action.name + " does not exist");
230
- }
231
- action._method = this.httpGlobalAction;
246
+ if (!this._model["_" + name]) {
247
+ throw Error("Action static method _" + name + " does not exist");
232
248
  }
233
- this.addRoute(expose.url + "/" + action.name, action.method, action._method, action.openapi);
249
+ executer = this.httpGlobalAction;
250
+ this.addRoute(expose.url + "/" + name, action.methods, executer, action.openapi);
234
251
  }
235
252
  else {
236
253
  // By default will grab the object and then call the action
237
- if (!action._method) {
238
- if (!this._model.prototype["_" + action.name]) {
239
- throw Error("Action method _" + action.name + " does not exist");
240
- }
241
- action._method = this.httpAction;
254
+ if (!this._model.prototype["_" + name]) {
255
+ throw Error("Action method _" + name + " does not exist");
242
256
  }
243
- this.addRoute(expose.url + "/{uuid}/" + action.name, action.method, action._method, action.openapi);
257
+ executer = this.httpAction;
258
+ this.addRoute(expose.url + "/{uuid}/" + name, action.methods, executer, action.openapi);
244
259
  }
245
260
  });
246
261
  }
247
262
  }
263
+ /**
264
+ * Get the url where the store is exposed
265
+ */
248
266
  getUrl() {
249
- return this._exposeUrl;
267
+ return this.parameters.expose.url;
250
268
  }
269
+ /**
270
+ * Init a model from the current stored data
271
+ *
272
+ * Initial the reverse map as well
273
+ *
274
+ * @param object
275
+ * @returns
276
+ */
251
277
  initModel(object = {}) {
278
+ var _a;
279
+ var _b;
252
280
  // Make sure to send a model object
253
281
  if (!(object instanceof this._model)) {
254
282
  let model = new this._model();
255
283
  model.load(object, true);
256
284
  object = model;
257
285
  }
286
+ if (!object.getUuid()) {
287
+ object.setUuid(object.generateUid(object));
288
+ }
258
289
  object.__store = this;
259
290
  for (var i in this._reverseMap) {
291
+ (_a = object[_b = this._reverseMap[i].property]) !== null && _a !== void 0 ? _a : (object[_b] = []);
260
292
  for (var j in object[this._reverseMap[i].property]) {
261
- object[this._reverseMap[i].property][j] = this._reverseMap[i].store.initModel(object[this._reverseMap[i].property][j]);
293
+ // Use Partial
294
+ object[this._reverseMap[i].property][j] = this._reverseMap[i].mapper.initModel(object[this._reverseMap[i].property][j]);
262
295
  object[this._reverseMap[i].property][j].setContext(object.getContext());
263
296
  }
264
297
  }
265
298
  return object;
266
299
  }
267
- addReverseMap(prop, cascade, store) {
300
+ /**
301
+ * Add reverse map information
302
+ *
303
+ * @param prop
304
+ * @param cascade
305
+ * @param store
306
+ */
307
+ addReverseMap(prop, store) {
268
308
  this._reverseMap.push({
269
309
  property: prop,
270
- store: store
271
- });
272
- if (cascade) {
273
- this._cascade.push(cascade);
274
- }
275
- }
276
- isMapped(property) {
277
- if (property === undefined) {
278
- return false;
279
- }
280
- if (!this.parameters.map) {
281
- return false;
282
- }
283
- let map = this.parameters.map;
284
- for (let prop in map) {
285
- // No mapped property or not in the object
286
- if (map[prop].key === undefined) {
287
- continue;
288
- }
289
- if (map[prop].fields.split(",").indexOf(property) >= 0) {
290
- return true;
291
- }
292
- }
293
- return false;
294
- }
295
- _incrementAttribute(uid, prop, value, updateDate) {
296
- return __awaiter(this, void 0, void 0, function* () {
297
- throw Error("Virtual abstract class - concrete only for MixIn usage");
310
+ mapper: store
298
311
  });
299
312
  }
300
313
  incrementAttribute(uid, prop, value) {
@@ -305,10 +318,10 @@ class Store extends service_1.Service {
305
318
  }
306
319
  let updateDate = new Date();
307
320
  yield this._incrementAttribute(uid, prop, value, updateDate);
308
- yield this._handleMapFromPartial(uid, updateDate, prop);
309
321
  return this.emitSync("Store.PartialUpdated", {
310
322
  object_id: uid,
311
323
  store: this,
324
+ updateDate,
312
325
  partial_update: {
313
326
  increment: {
314
327
  value: value,
@@ -325,10 +338,10 @@ class Store extends service_1.Service {
325
338
  }
326
339
  let updateDate = new Date();
327
340
  yield this._upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate);
328
- yield this._handleMapFromPartial(uid, updateDate);
329
341
  yield this.emitSync("Store.PartialUpdated", {
330
342
  object_id: uid,
331
343
  store: this,
344
+ updateDate,
332
345
  partial_update: {
333
346
  addItem: {
334
347
  value: item,
@@ -339,39 +352,14 @@ class Store extends service_1.Service {
339
352
  });
340
353
  });
341
354
  }
342
- _handleMapFromPartial(uid, updateDate, prop = undefined) {
355
+ deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField = this._uuidField) {
343
356
  return __awaiter(this, void 0, void 0, function* () {
344
- if (this.isMapped(prop) || this.isMapped(this._lastUpdateField)) {
345
- // Not optimal need to reload the object
346
- let object = yield this._get(uid);
347
- let updates = {};
348
- updates[this._lastUpdateField] = updateDate;
349
- if (this.isMapped(prop)) {
350
- updates[prop] = object.prop;
351
- }
352
- yield this.handleMap(object, this.parameters.map, updates);
353
- }
354
- });
355
- }
356
- _upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate) {
357
- return __awaiter(this, void 0, void 0, function* () {
358
- throw Error("Virtual abstract class - concrete only for MixIn usage");
359
- });
360
- }
361
- deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField) {
362
- return __awaiter(this, void 0, void 0, function* () {
363
- if (index === undefined || prop === undefined) {
364
- throw Error("Invalid Argument");
365
- }
366
- if (itemWriteConditionField === undefined) {
367
- itemWriteConditionField = this._uuidField;
368
- }
369
357
  let updateDate = new Date();
370
358
  yield this._deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate);
371
- yield this._handleMapFromPartial(uid, updateDate);
372
359
  yield this.emitSync("Store.PartialUpdated", {
373
360
  object_id: uid,
374
361
  store: this,
362
+ updateDate,
375
363
  partial_update: {
376
364
  deleteItem: {
377
365
  property: prop,
@@ -381,76 +369,26 @@ class Store extends service_1.Service {
381
369
  });
382
370
  });
383
371
  }
384
- _deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate) {
385
- return __awaiter(this, void 0, void 0, function* () {
386
- throw Error("Virtual abstract class - concrete only for MixIn usage");
387
- });
388
- }
389
- createIndex() {
390
- return __awaiter(this, void 0, void 0, function* () {
391
- if (!this.parameters.index || (yield this.exists("index"))) {
392
- return;
393
- }
394
- let index = {};
395
- index[this._uuidField] = "index";
396
- index[this._lastUpdateField] = new Date();
397
- yield this.save(index);
398
- });
399
- }
400
- initMap(map) {
401
- if (map == undefined || map._init) {
402
- return;
403
- }
404
- for (var prop in map) {
405
- var reverseStore = this._webda.getService(prop);
406
- if (reverseStore === undefined || !(reverseStore instanceof Store)) {
407
- map[prop]["-onerror"] = "NoStore";
408
- this.log("WARN", "Can't setup mapping as store \"", prop, "\" doesn't exist");
409
- continue;
410
- }
411
- var cascade = undefined;
412
- if (map[prop].cascade) {
413
- cascade = {
414
- store: this._name,
415
- name: map[prop].target
416
- };
417
- }
418
- reverseStore.addReverseMap(map[prop].target, cascade, this);
419
- }
420
- }
421
- toString() {
422
- return this.parameters.type + "[" + this._name + "]";
423
- }
424
- generateUid() {
425
- return uuid_1.v4();
426
- }
427
372
  /**
428
373
  * Save an object
429
374
  *
430
375
  * @param {Object} Object to save
431
376
  * @param {String} Uuid to use, if not specified take the object.uuid or generate one if not found
432
377
  * @return {Promise} with saved object
378
+ *
379
+ * Might want to rename to create
433
380
  */
434
381
  save(object, ctx = undefined) {
382
+ var _a;
383
+ var _b;
435
384
  return __awaiter(this, void 0, void 0, function* () {
436
- /** @ignore */
437
- for (var i in this._reverseMap) {
438
- if (object[this._reverseMap[i].property] === undefined) {
439
- object[this._reverseMap[i].property] = [];
440
- }
441
- }
442
- object[this._creationDateField] = object[this._lastUpdateField] = new Date();
443
385
  object = this.initModel(object);
386
+ // Dates should be store by the Store
387
+ (_a = object[_b = this._creationDateField]) !== null && _a !== void 0 ? _a : (object[_b] = new Date());
388
+ object[this._lastUpdateField] = new Date();
444
389
  if (ctx) {
445
390
  object.setContext(ctx);
446
391
  }
447
- if (!object[this._uuidField]) {
448
- object[this._uuidField] = object.generateUid();
449
- object[this._creationDateField] = new Date();
450
- if (!object[this._uuidField]) {
451
- object[this._uuidField] = this.generateUid();
452
- }
453
- }
454
392
  yield this.emitSync("Store.Save", {
455
393
  object: object,
456
394
  store: this
@@ -464,35 +402,68 @@ class Store extends service_1.Service {
464
402
  store: this
465
403
  });
466
404
  yield object._onSaved();
467
- if (this.parameters.map != undefined) {
468
- yield this.handleMap(object, this.parameters.map, "created");
469
- }
470
- // Handle index
471
- if (this.parameters.index && object[this._uuidField] !== "index" && object[this._uuidField]) {
472
- yield this.handleIndex(object, "created");
473
- }
474
405
  return object;
475
406
  });
476
407
  }
477
- _save(object) {
478
- return __awaiter(this, void 0, void 0, function* () {
479
- throw Error("Virtual abstract class - concrete only for MixIn usage");
480
- });
481
- }
408
+ /**
409
+ * Patch an object
410
+ *
411
+ * @param object
412
+ * @param reverseMap
413
+ * @returns
414
+ */
482
415
  patch(object, reverseMap = true) {
483
416
  return __awaiter(this, void 0, void 0, function* () {
484
417
  return this.update(object, reverseMap, true);
485
418
  });
486
419
  }
487
- emulateUpsertItemToCollection(model, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate) {
488
- return __awaiter(this, void 0, void 0, function* () {
489
- if (model === undefined) {
490
- throw Error("NotFound");
420
+ /**
421
+ * Check if an UpdateCondition is met
422
+ * @param model
423
+ * @param conditionField
424
+ * @param condition
425
+ * @param uid
426
+ */
427
+ checkUpdateCondition(model, conditionField, condition, uid) {
428
+ if (conditionField) {
429
+ if (model[conditionField] !== condition) {
430
+ throw new UpdateConditionFailError(uid ? uid : model.getUuid(), conditionField, condition);
491
431
  }
432
+ }
433
+ }
434
+ /**
435
+ * Check if an UpdateCondition is met
436
+ * @param model
437
+ * @param conditionField
438
+ * @param condition
439
+ * @param uid
440
+ */
441
+ checkCollectionUpdateCondition(model, collection, conditionField, condition, index) {
442
+ // No index so addition to collection
443
+ if (index === null) {
444
+ // The condition must be length of the collection
445
+ if (!model[collection] || model[collection].length !== condition) {
446
+ throw new UpdateConditionFailError(model.getUuid(), collection, condition);
447
+ }
448
+ }
449
+ else if (condition && model[collection][index][conditionField] !== condition) {
450
+ throw new UpdateConditionFailError(model.getUuid(), `${collection}[${index}].${conditionField}`, condition);
451
+ }
452
+ }
453
+ /**
454
+ *
455
+ * @param model
456
+ * @param prop
457
+ * @param item
458
+ * @param index
459
+ * @param itemWriteCondition
460
+ * @param itemWriteConditionField
461
+ * @param updateDate
462
+ */
463
+ simulateUpsertItemToCollection(model, prop, item, updateDate, index, itemWriteCondition, itemWriteConditionField) {
464
+ return __awaiter(this, void 0, void 0, function* () {
465
+ this.checkCollectionUpdateCondition(model, prop, itemWriteConditionField, itemWriteCondition, index);
492
466
  if (index === undefined) {
493
- if (itemWriteCondition !== undefined && model[prop].length !== itemWriteCondition) {
494
- throw Error("UpdateCondition not met");
495
- }
496
467
  if (model[prop] === undefined) {
497
468
  model[prop] = [item];
498
469
  }
@@ -501,9 +472,6 @@ class Store extends service_1.Service {
501
472
  }
502
473
  }
503
474
  else {
504
- if (itemWriteCondition && model[prop][index][itemWriteConditionField] != itemWriteCondition) {
505
- throw Error("UpdateCondition not met");
506
- }
507
475
  model[prop][index] = item;
508
476
  }
509
477
  model[this._lastUpdateField] = updateDate;
@@ -531,16 +499,18 @@ class Store extends service_1.Service {
531
499
  }
532
500
  }
533
501
  let partialEvent = partial ? "Patch" : "";
534
- if (Object.keys(object).length === 0) {
502
+ if (Object.keys(object).length < 2) {
535
503
  return {};
536
504
  }
537
505
  object[this._lastUpdateField] = new Date();
538
- let load = yield this._get(object[this._uuidField]);
506
+ let load = yield this._get(object[this._uuidField], true);
507
+ if (load.__type !== this._model.name && this.parameters.strict) {
508
+ this.log("WARN", `Object '${object[this._uuidField]}' was not created by this store`);
509
+ throw new StoreNotFoundError(object[this._uuidField], this.getName());
510
+ }
539
511
  loaded = this.initModel(load);
540
- yield this.handleMap(loaded, this.parameters.map, object);
541
- // Handle index
542
- if (this.parameters.index && loaded[this._uuidField] !== "index" && loaded[this._uuidField]) {
543
- yield this.handleIndex(loaded, object);
512
+ if (object instanceof coremodel_1.CoreModel) {
513
+ loaded.setContext(object.getContext());
544
514
  }
545
515
  yield this.emitSync(`Store.${partialEvent}Update`, {
546
516
  object: loaded,
@@ -576,241 +546,45 @@ class Store extends service_1.Service {
576
546
  return saved;
577
547
  });
578
548
  }
579
- getMapper(map, uuid) {
580
- for (var i = 0; i < map.length; i++) {
581
- if (map[i][this._uuidField] === uuid) {
582
- return i;
583
- }
584
- }
585
- return -1;
586
- }
587
- removeMapper(map, uuid) {
588
- let i = this.getMapper(map, uuid);
589
- if (i >= 0) {
590
- map.splice(i, 1);
591
- return true;
592
- }
593
- return false;
594
- }
595
- _handleUpdatedMap(object, map, mapped, store, updates) {
596
- return __awaiter(this, void 0, void 0, function* () {
597
- var mapper = {};
598
- mapper[this._uuidField] = object[this._uuidField];
599
- // Update only if the key field has been updated
600
- var found = false;
601
- for (var field in updates) {
602
- if (map.fields) {
603
- let fields = map.fields.split(",");
604
- for (let i in fields) {
605
- let mapperfield = fields[i];
606
- // Create the mapper object
607
- if (updates[mapperfield] !== undefined) {
608
- mapper[mapperfield] = updates[mapperfield];
609
- found = true;
610
- }
611
- else if (object[mapperfield] !== undefined) {
612
- mapper[mapperfield] = object[mapperfield];
613
- }
614
- }
615
- }
616
- // TODO Need to verify also if fields are updated
617
- if (field == map.key) {
618
- found = true;
619
- break;
620
- }
621
- }
622
- if (!found) {
623
- // None of the mapped keys has been modified -> return
624
- return;
625
- }
626
- // check if reference object has changed
627
- if (updates[map.key] != undefined && mapped[this._uuidField] != updates[map.key]) {
628
- // create mapper
629
- if (map.fields) {
630
- let fields = map.fields.split(",");
631
- for (var j in fields) {
632
- let mapperfield = fields[j];
633
- // Create the mapper object
634
- if (updates[mapperfield] !== undefined) {
635
- mapper[mapperfield] = updates[mapperfield];
636
- }
637
- else if (object[mapperfield] !== undefined) {
638
- mapper[mapperfield] = object[mapperfield];
639
- }
640
- }
641
- }
642
- let i = this.getMapper(mapped[map.target], object[this._uuidField]);
643
- if (i >= 0) {
644
- // Remove the data from old object
645
- yield store.deleteItemFromCollection(mapped[this._uuidField], map.target, i, object[this._uuidField], this._uuidField);
646
- }
647
- // Add the data to new object
648
- yield store.upsertItemToCollection(updates[map.key], map.target, mapper);
649
- }
650
- else {
651
- return this._handleUpdatedMapMapper(object, map, mapped, store, updates);
652
- }
653
- });
654
- }
655
- _handleUpdatedMapTransferOut(object, map, mapped, store, updates) {
656
- var update = {};
657
- update[map.target] = mapped[map.target];
658
- return store.update(update, mapped[this._uuidField], false).then(() => {
659
- return this._handleUpdatedMapTransferIn(object, map, store, updates);
660
- });
661
- }
662
- _handleUpdatedMapTransferIn(object, map, store, updates) {
663
- // TODO Should be update
664
- return store.get(updates[map.key]).then(mapped => {
665
- if (mapped == undefined) {
666
- return Promise.resolve();
667
- }
668
- // Enforce the collection if needed
669
- if (mapped[map.target] == undefined) {
670
- mapped[map.target] = [];
671
- }
672
- return this._handleUpdatedMapMapper(object, map, mapped, store, updates);
673
- });
674
- }
675
- _handleUpdatedMapMapper(object, map, mapped, store, updates) {
676
- // Update the mapper
677
- var mapper = {};
678
- mapper[this._uuidField] = object[this._uuidField];
679
- if (map.fields) {
680
- var fields = map.fields.split(",");
681
- for (var field in fields) {
682
- if (updates[fields[field]] != undefined) {
683
- mapper[fields[field]] = updates[fields[field]];
684
- }
685
- else {
686
- mapper[fields[field]] = object[fields[field]];
687
- }
688
- }
689
- }
690
- // Remove old reference
691
- let i = this.getMapper(mapped[map.target], object[this._uuidField]);
692
- // If not found just add it to the collection
693
- if (i < 0) {
694
- return store.upsertItemToCollection(mapped[this._uuidField], map.target, mapper);
695
- }
696
- // Else update with a check on the uuid
697
- return store.upsertItemToCollection(mapped[this._uuidField], map.target, mapper, i, object[this._uuidField], this._uuidField);
698
- }
699
- _handleDeletedMap(object, map, mapped, store) {
700
- // Remove from the collection
701
- if (mapped[map.target] === undefined) {
702
- return Promise.resolve();
703
- }
704
- let i = this.getMapper(mapped[map.target], object[this._uuidField]);
705
- if (i >= 0) {
706
- return store.deleteItemFromCollection(mapped[this._uuidField], map.target, i, object[this._uuidField], this._uuidField);
707
- }
708
- return Promise.resolve();
709
- }
710
- _handleCreatedMap(object, map, mapped, store) {
711
- // Add to the object
712
- var mapper = {};
713
- mapper[this._uuidField] = object[this._uuidField];
714
- // Add info to the mapped
715
- if (map.fields) {
716
- var fields = map.fields.split(",");
717
- for (var field in fields) {
718
- mapper[fields[field]] = object[fields[field]];
719
- }
720
- }
721
- return store.upsertItemToCollection(mapped[this._uuidField], map.target, mapper);
722
- }
723
- _handleMapProperty(store, object, property, updates) {
724
- return __awaiter(this, void 0, void 0, function* () {
725
- let mapped = yield store.get(object[property.key] || updates[property.key]);
726
- if (mapped == undefined) {
727
- return;
728
- }
729
- if (updates === "created") {
730
- return this._handleCreatedMap(object, property, mapped, store);
731
- }
732
- else if (updates == "deleted") {
733
- return this._handleDeletedMap(object, property, mapped, store);
734
- }
735
- else if (typeof updates == "object") {
736
- return this._handleUpdatedMap(object, property, mapped, store, updates);
737
- }
738
- else {
739
- return Promise.reject(Error("Unknown handleMap type " + updates));
740
- }
741
- });
742
- }
743
- removeAttribute(uuid, attribute) {
744
- return __awaiter(this, void 0, void 0, function* () {
745
- return this._removeAttribute(uuid, attribute);
746
- });
747
- }
748
- handleIndex(object, updates) {
549
+ /**
550
+ * Remove an attribute from an object
551
+ *
552
+ * @param uuid
553
+ * @param attribute
554
+ * @returns
555
+ */
556
+ removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField) {
749
557
  return __awaiter(this, void 0, void 0, function* () {
750
- let mapUpdates = {};
751
- if (typeof updates === "object") {
752
- let toUpdate = false;
753
- for (let i in updates) {
754
- if (this.parameters.index.indexOf(i) >= 0) {
755
- toUpdate = true;
756
- }
757
- }
758
- if (!toUpdate) {
759
- return;
558
+ yield this._removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField);
559
+ yield this.emitSync("Store.PartialUpdated", {
560
+ object_id: uuid,
561
+ partial_update: {
562
+ deleteAttribute: attribute
760
563
  }
761
- }
762
- else if (updates === "deleted") {
763
- yield this.removeAttribute("index", object[this._uuidField]);
764
- return;
765
- }
766
- else if (updates === "created") {
767
- updates = object;
768
- }
769
- let mapper = {};
770
- this.parameters.index.forEach(id => {
771
- mapper[id] = updates[id];
772
564
  });
773
- mapUpdates[object[this._uuidField]] = mapper;
774
- mapUpdates[this._lastUpdateField] = new Date();
775
- yield this._patch(mapUpdates, "index");
776
565
  });
777
566
  }
778
- handleMap(object, map, updates) {
779
- return __awaiter(this, void 0, void 0, function* () {
780
- let promises = [];
781
- if (object === undefined) {
782
- return;
783
- }
784
- for (let prop in map) {
785
- // No mapped property or not in the object
786
- if (map[prop].key === undefined ||
787
- (object[map[prop].key] === undefined && updates[map[prop].key] === undefined)) {
788
- continue;
789
- }
790
- let store = this.getService(prop);
791
- // Cant find the store for this collection
792
- if (store == undefined) {
793
- continue;
794
- }
795
- promises.push(this._handleMapProperty(store, object, map[prop], updates));
796
- }
797
- return Promise.all(promises);
798
- });
799
- }
800
- _update(object, uid, itemWriteCondition = undefined, itemWriteConditionField = undefined) {
801
- return __awaiter(this, void 0, void 0, function* () {
802
- throw Error("Virtual abstract class - concrete only for MixIn usage");
803
- });
804
- }
805
- _patch(object, uid, itemWriteCondition = undefined, itemWriteConditionField = undefined) {
567
+ /**
568
+ * Cascade delete a related object
569
+ *
570
+ * @param obj
571
+ * @param uuid
572
+ * @returns
573
+ */
574
+ cascadeDelete(obj, uuid) {
806
575
  return __awaiter(this, void 0, void 0, function* () {
807
- throw Error("Virtual abstract class - concrete only for MixIn usage");
576
+ // We dont need uuid but Binary store will need it
577
+ return this.delete(obj.getUuid());
808
578
  });
809
579
  }
810
- cascadeDelete(obj, uuid) {
580
+ /**
581
+ * Delete an object from the store without condition nor async
582
+ * @param uid to delete
583
+ * @returns
584
+ */
585
+ forceDelete(uid) {
811
586
  return __awaiter(this, void 0, void 0, function* () {
812
- // We dont need uuid but Binary store will need it
813
- return this.delete(obj[this._uuidField]);
587
+ return this.delete(uid, undefined, undefined, true);
814
588
  });
815
589
  }
816
590
  /**
@@ -820,58 +594,48 @@ class Store extends service_1.Service {
820
594
  * @param {Boolean} delete sync even if asyncDelete is active
821
595
  * @return {Promise} the deletion promise
822
596
  */
823
- delete(uid, sync = false) {
597
+ delete(uid, writeCondition, writeConditionField, sync = false) {
824
598
  return __awaiter(this, void 0, void 0, function* () {
825
599
  /** @ignore */
826
600
  let to_delete;
601
+ // Allow full object or just its uuid
827
602
  if (typeof uid === "object") {
828
603
  to_delete = uid;
829
- uid = to_delete[this._uuidField];
830
- if (!(to_delete instanceof this._model)) {
831
- to_delete = this.initModel(yield this._get(uid));
832
- }
833
604
  }
834
605
  else {
835
- to_delete = this.initModel(yield this._get(uid));
606
+ to_delete = yield this._get(uid);
607
+ if (to_delete === undefined) {
608
+ return;
609
+ }
610
+ if (to_delete.__type !== this._model.name && this.parameters.strict) {
611
+ this.log("WARN", `Object '${uid}' was not created by this store`);
612
+ return;
613
+ }
614
+ to_delete = this.initModel(to_delete);
836
615
  }
837
- if (to_delete === undefined) {
838
- throw 404;
616
+ // Check condition as we have the object
617
+ if (writeCondition) {
618
+ if (to_delete[writeConditionField] !== writeCondition) {
619
+ throw new UpdateConditionFailError(to_delete.getUuid(), writeConditionField, writeCondition);
620
+ }
839
621
  }
622
+ // Send preevent
840
623
  yield this.emitSync("Store.Delete", {
841
624
  object: to_delete,
842
625
  store: this
843
626
  });
844
627
  yield to_delete._onDelete();
845
- if (this.parameters.map != undefined) {
846
- yield this.handleMap(to_delete, this.parameters.map, "deleted");
847
- }
848
- // Handle index
849
- if (this.parameters.index && to_delete[this._uuidField] !== "index" && to_delete[this._uuidField]) {
850
- yield this.handleIndex(to_delete, "deleted");
851
- }
852
- if (this._cascade != undefined && to_delete !== undefined) {
853
- var promises = [];
854
- // Should deactiate the mapping in that case
855
- for (let i in this._cascade) {
856
- if (typeof this._cascade[i] != "object" || to_delete[this._cascade[i].name] == undefined)
857
- continue;
858
- var targetStore = this.getService(this._cascade[i].store);
859
- if (targetStore == undefined)
860
- continue;
861
- for (var item in to_delete[this._cascade[i].name]) {
862
- promises.push(targetStore.cascadeDelete(to_delete[this._cascade[i].name][item], to_delete[this._uuidField]));
863
- }
864
- }
865
- yield Promise.all(promises);
866
- }
628
+ // If async we just tag the object as deleted
867
629
  if (this.parameters.asyncDelete && !sync) {
868
630
  yield this._patch({
869
631
  __deleted: true
870
- }, uid);
632
+ }, to_delete.getUuid());
871
633
  }
872
634
  else {
873
- yield this._delete(uid);
635
+ // Delete from the DB for real
636
+ yield this._delete(to_delete.getUuid(), writeCondition, writeConditionField);
874
637
  }
638
+ // Send post event
875
639
  yield this.emitSync("Store.Deleted", {
876
640
  object: to_delete,
877
641
  store: this
@@ -879,37 +643,6 @@ class Store extends service_1.Service {
879
643
  yield to_delete._onDeleted();
880
644
  });
881
645
  }
882
- /**
883
- * Check if an object exists
884
- * @abstract
885
- * @params {String} uuid of the object
886
- */
887
- exists(uid) {
888
- return __awaiter(this, void 0, void 0, function* () {
889
- throw Error("Virtual abstract class - concrete only for MixIn usage");
890
- });
891
- }
892
- _delete(uid, writeCondition, itemWriteConditionField) {
893
- return __awaiter(this, void 0, void 0, function* () {
894
- throw Error("Virtual abstract class - concrete only for MixIn usage");
895
- });
896
- }
897
- _get(uid) {
898
- return __awaiter(this, void 0, void 0, function* () {
899
- throw Error("Virtual abstract class - concrete only for MixIn usage");
900
- });
901
- }
902
- /**
903
- * Get an object
904
- *
905
- * @param {Array} uuid to gets if undefined then retrieve the all table
906
- * @return {Promise} the objects retrieved ( can be [] if not found )
907
- */
908
- getAll(list = undefined) {
909
- return __awaiter(this, void 0, void 0, function* () {
910
- throw Error("Virtual abstract class - concrete only for MixIn usage");
911
- });
912
- }
913
646
  /**
914
647
  * By default we cannot know if the store will trigger or not
915
648
  *
@@ -930,7 +663,7 @@ class Store extends service_1.Service {
930
663
  if (!object) {
931
664
  return undefined;
932
665
  }
933
- let result = new Map();
666
+ let result = {};
934
667
  for (let i in object) {
935
668
  if (i === this._uuidField || i === this._lastUpdateField || i.startsWith("_")) {
936
669
  continue;
@@ -956,6 +689,10 @@ class Store extends service_1.Service {
956
689
  if (!object) {
957
690
  return undefined;
958
691
  }
692
+ if (object.__type !== this._model.name && this.parameters.strict) {
693
+ this.log("WARN", `Object '${uid}' was not created by this store`);
694
+ return undefined;
695
+ }
959
696
  object = this.initModel(object);
960
697
  object.setContext(ctx);
961
698
  yield this.emitSync("Store.Get", {
@@ -966,6 +703,34 @@ class Store extends service_1.Service {
966
703
  return object;
967
704
  });
968
705
  }
706
+ /**
707
+ * Set one attribute in an object
708
+ *
709
+ * this is an helper function that calls patch
710
+ *
711
+ * @param uid of the object
712
+ * @param property to update1
713
+ * @param value new value
714
+ * @returns
715
+ */
716
+ setAttribute(uid, property, value) {
717
+ return __awaiter(this, void 0, void 0, function* () {
718
+ let patch = {};
719
+ patch[property] = value;
720
+ patch[this.getUuidField()] = uid;
721
+ yield this.patch(patch);
722
+ });
723
+ }
724
+ /**
725
+ * Search inside the store
726
+ *
727
+ * Still need to define a good abstraction for it
728
+ *
729
+ * @param request
730
+ * @param offset
731
+ * @param limit
732
+ * @returns
733
+ */
969
734
  find(request = undefined, offset = 0, limit = undefined) {
970
735
  return __awaiter(this, void 0, void 0, function* () {
971
736
  yield this.emitSync("Store.Find", {
@@ -985,12 +750,10 @@ class Store extends service_1.Service {
985
750
  return result;
986
751
  });
987
752
  }
988
- _find(request, offset, limit) {
989
- return __awaiter(this, void 0, void 0, function* () {
990
- throw Error("Virtual abstract class - concrete only for MixIn usage");
991
- });
992
- }
993
- // ADD THE EXECUTOR PART
753
+ /**
754
+ * Handle POST
755
+ * @param ctx
756
+ */
994
757
  httpCreate(ctx) {
995
758
  return __awaiter(this, void 0, void 0, function* () {
996
759
  let body = ctx.getRequestBody();
@@ -1019,14 +782,14 @@ class Store extends service_1.Service {
1019
782
  });
1020
783
  });
1021
784
  }
785
+ /**
786
+ * Handle obect action
787
+ * @param ctx
788
+ */
1022
789
  httpAction(ctx) {
1023
790
  return __awaiter(this, void 0, void 0, function* () {
1024
791
  let action = ctx.getHttpContext().getUrl().split("/").pop();
1025
- let uuid = ctx.parameter("uuid");
1026
- if (!uuid) {
1027
- throw 400;
1028
- }
1029
- let object = yield this.get(uuid, ctx);
792
+ let object = yield this.get(ctx.parameter("uuid"), ctx);
1030
793
  if (object === undefined || object.__deleted) {
1031
794
  throw 404;
1032
795
  }
@@ -1050,6 +813,10 @@ class Store extends service_1.Service {
1050
813
  });
1051
814
  });
1052
815
  }
816
+ /**
817
+ * Handle collection action
818
+ * @param ctx
819
+ */
1053
820
  httpGlobalAction(ctx) {
1054
821
  return __awaiter(this, void 0, void 0, function* () {
1055
822
  let action = ctx.getHttpContext().getUrl().split("/").pop();
@@ -1084,15 +851,22 @@ class Store extends service_1.Service {
1084
851
  if (!object || object.__deleted)
1085
852
  throw 404;
1086
853
  yield object.canAct(ctx, "update");
1087
- try {
1088
- yield object.validate(ctx, body);
1089
- }
1090
- catch (err) {
1091
- this.log("INFO", "Object invalid", err);
1092
- throw 400;
1093
- }
1094
854
  if (ctx.getHttpContext().getMethod() === "PATCH") {
855
+ try {
856
+ yield object.validate(ctx, body);
857
+ }
858
+ catch (err) {
859
+ this.log("INFO", "Object invalid", err);
860
+ throw 400;
861
+ }
1095
862
  let updateObject = new this._model();
863
+ // Clean any default attributes from the model
864
+ for (let i in updateObject) {
865
+ if (i.startsWith("__")) {
866
+ continue;
867
+ }
868
+ delete updateObject[i];
869
+ }
1096
870
  updateObject.setContext(ctx);
1097
871
  updateObject.load(body);
1098
872
  yield this.patch(updateObject);
@@ -1107,6 +881,13 @@ class Store extends service_1.Service {
1107
881
  updateObject[i] = object[i];
1108
882
  }
1109
883
  }
884
+ try {
885
+ yield updateObject.validate(ctx);
886
+ }
887
+ catch (err) {
888
+ this.log("INFO", "Object invalid", err);
889
+ throw 400;
890
+ }
1110
891
  // Add mappers back to
1111
892
  object = yield this.update(updateObject);
1112
893
  }
@@ -1130,6 +911,11 @@ class Store extends service_1.Service {
1130
911
  let uuid = ctx.parameter("uuid");
1131
912
  if (uuid) {
1132
913
  let object = yield this.get(uuid, ctx);
914
+ yield this.emitSync("Store.WebGetNotFound", {
915
+ context: ctx,
916
+ uuid,
917
+ store: this
918
+ });
1133
919
  if (object === undefined || object.__deleted) {
1134
920
  throw 404;
1135
921
  }
@@ -1180,6 +966,12 @@ class Store extends service_1.Service {
1180
966
  }
1181
967
  });
1182
968
  }
969
+ /**
970
+ * Return the model uuid field
971
+ */
972
+ getUuidField() {
973
+ return this._uuidField;
974
+ }
1183
975
  }
1184
976
  exports.Store = Store;
1185
977
  //# sourceMappingURL=store.js.map