@webda/core 1.6.0-beta.1 → 2.0.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 (232) hide show
  1. package/lib/application.d.ts +317 -195
  2. package/lib/application.js +171 -674
  3. package/lib/application.js.map +1 -1
  4. package/lib/application.spec.js +97 -289
  5. package/lib/application.spec.js.map +1 -1
  6. package/lib/core.d.ts +102 -214
  7. package/lib/core.js +146 -70
  8. package/lib/core.js.map +1 -1
  9. package/lib/core.spec.js +80 -17
  10. package/lib/core.spec.js.map +1 -1
  11. package/lib/index.d.ts +14 -9
  12. package/lib/index.js +19 -10
  13. package/lib/index.js.map +1 -1
  14. package/lib/models/aclmodel.d.ts +29 -8
  15. package/lib/models/aclmodel.js +68 -18
  16. package/lib/models/aclmodel.js.map +1 -1
  17. package/lib/models/aclmodel.spec.js +56 -19
  18. package/lib/models/aclmodel.spec.js.map +1 -1
  19. package/lib/models/coremodel.d.ts +9 -17
  20. package/lib/models/coremodel.js +36 -36
  21. package/lib/models/coremodel.js.map +1 -1
  22. package/lib/models/ident.d.ts +8 -3
  23. package/lib/models/ident.js +8 -1
  24. package/lib/models/ident.js.map +1 -1
  25. package/lib/models/ident.spec.js +3 -0
  26. package/lib/models/ident.spec.js.map +1 -1
  27. package/lib/models/ownermodel.d.ts +8 -4
  28. package/lib/models/ownermodel.js +10 -6
  29. package/lib/models/ownermodel.js.map +1 -1
  30. package/lib/models/rolemodel.js.map +1 -1
  31. package/lib/models/rolemodel.spec.js +4 -1
  32. package/lib/models/rolemodel.spec.js.map +1 -1
  33. package/lib/models/user.d.ts +32 -3
  34. package/lib/models/user.js +31 -0
  35. package/lib/models/user.js.map +1 -1
  36. package/lib/models/user.spec.js +11 -0
  37. package/lib/models/user.spec.js.map +1 -1
  38. package/lib/queues/filequeue.d.ts +2 -7
  39. package/lib/queues/filequeue.js +2 -11
  40. package/lib/queues/filequeue.js.map +1 -1
  41. package/lib/queues/filequeue.spec.js +0 -1
  42. package/lib/queues/filequeue.spec.js.map +1 -1
  43. package/lib/queues/memoryqueue.d.ts +2 -7
  44. package/lib/queues/memoryqueue.js +1 -11
  45. package/lib/queues/memoryqueue.js.map +1 -1
  46. package/lib/queues/memoryqueue.spec.js +0 -1
  47. package/lib/queues/memoryqueue.spec.js.map +1 -1
  48. package/lib/queues/queue.spec.d.ts +1 -1
  49. package/lib/queues/queue.spec.js +11 -9
  50. package/lib/queues/queue.spec.js.map +1 -1
  51. package/lib/queues/queueservice.js +1 -1
  52. package/lib/queues/queueservice.js.map +1 -1
  53. package/lib/router.d.ts +46 -1
  54. package/lib/router.js +89 -51
  55. package/lib/router.js.map +1 -1
  56. package/lib/router.spec.js +19 -2
  57. package/lib/router.spec.js.map +1 -1
  58. package/lib/services/asyncevents.d.ts +1 -0
  59. package/lib/services/asyncevents.js +4 -3
  60. package/lib/services/asyncevents.js.map +1 -1
  61. package/lib/services/authentication.d.ts +47 -5
  62. package/lib/services/authentication.js +99 -40
  63. package/lib/services/authentication.js.map +1 -1
  64. package/lib/services/authentication.spec.js +10 -0
  65. package/lib/services/authentication.spec.js.map +1 -1
  66. package/lib/services/binary.d.ts +126 -64
  67. package/lib/services/binary.js +247 -96
  68. package/lib/services/binary.js.map +1 -1
  69. package/lib/services/binary.spec.d.ts +1 -0
  70. package/lib/services/binary.spec.js +96 -25
  71. package/lib/services/binary.spec.js.map +1 -1
  72. package/lib/services/cloudbinary.d.ts +67 -0
  73. package/lib/services/cloudbinary.js +178 -0
  74. package/lib/services/cloudbinary.js.map +1 -0
  75. package/lib/services/cloudbinary.spec.d.ts +13 -0
  76. package/lib/services/cloudbinary.spec.js +205 -0
  77. package/lib/services/cloudbinary.spec.js.map +1 -0
  78. package/lib/services/configuration.d.ts +7 -2
  79. package/lib/services/configuration.js +4 -3
  80. package/lib/services/configuration.js.map +1 -1
  81. package/lib/services/configuration.spec.js +1 -0
  82. package/lib/services/configuration.spec.js.map +1 -1
  83. package/lib/services/cron.d.ts +5 -6
  84. package/lib/services/cron.js +4 -11
  85. package/lib/services/cron.js.map +1 -1
  86. package/lib/services/cron.spec.js +2 -3
  87. package/lib/services/cron.spec.js.map +1 -1
  88. package/lib/services/debugmailer.d.ts +11 -6
  89. package/lib/services/debugmailer.js +20 -14
  90. package/lib/services/debugmailer.js.map +1 -1
  91. package/lib/services/debugmailer.spec.js +1 -0
  92. package/lib/services/debugmailer.spec.js.map +1 -1
  93. package/lib/services/echo.d.ts +2 -6
  94. package/lib/services/echo.js +1 -11
  95. package/lib/services/echo.js.map +1 -1
  96. package/lib/services/echo.spec.js +1 -0
  97. package/lib/services/echo.spec.js.map +1 -1
  98. package/lib/services/filebinary.d.ts +36 -12
  99. package/lib/services/filebinary.js +123 -38
  100. package/lib/services/filebinary.js.map +1 -1
  101. package/lib/services/filebinary.spec.d.ts +4 -2
  102. package/lib/services/filebinary.spec.js +48 -8
  103. package/lib/services/filebinary.spec.js.map +1 -1
  104. package/lib/services/fileconfiguration.d.ts +1 -5
  105. package/lib/services/fileconfiguration.js +1 -10
  106. package/lib/services/fileconfiguration.js.map +1 -1
  107. package/lib/services/invitationservice.d.ts +198 -0
  108. package/lib/services/invitationservice.js +443 -0
  109. package/lib/services/invitationservice.js.map +1 -0
  110. package/lib/services/invitationservice.spec.d.ts +1 -0
  111. package/lib/services/invitationservice.spec.js +517 -0
  112. package/lib/services/invitationservice.spec.js.map +1 -0
  113. package/lib/services/kubernetesconfiguration.d.ts +3 -5
  114. package/lib/services/kubernetesconfiguration.js +5 -12
  115. package/lib/services/kubernetesconfiguration.js.map +1 -1
  116. package/lib/services/kubernetesconfiguration.spec.js +1 -1
  117. package/lib/services/kubernetesconfiguration.spec.js.map +1 -1
  118. package/lib/services/mailer.d.ts +44 -7
  119. package/lib/services/mailer.js +34 -14
  120. package/lib/services/mailer.js.map +1 -1
  121. package/lib/services/mailer.spec.js +29 -0
  122. package/lib/services/mailer.spec.js.map +1 -1
  123. package/lib/services/notificationservice.d.ts +76 -0
  124. package/lib/services/notificationservice.js +91 -0
  125. package/lib/services/notificationservice.js.map +1 -0
  126. package/lib/services/notificationservice.spec.d.ts +1 -0
  127. package/lib/services/notificationservice.spec.js +104 -0
  128. package/lib/services/notificationservice.spec.js.map +1 -0
  129. package/lib/services/oauth.d.ts +6 -4
  130. package/lib/services/oauth.js +28 -11
  131. package/lib/services/oauth.js.map +1 -1
  132. package/lib/services/oauth.spec.js +7 -10
  133. package/lib/services/oauth.spec.js.map +1 -1
  134. package/lib/services/resource.d.ts +1 -5
  135. package/lib/services/resource.js +22 -17
  136. package/lib/services/resource.js.map +1 -1
  137. package/lib/services/resource.spec.js +0 -1
  138. package/lib/services/resource.spec.js.map +1 -1
  139. package/lib/services/service.d.ts +29 -26
  140. package/lib/services/service.js +16 -22
  141. package/lib/services/service.js.map +1 -1
  142. package/lib/services/service.spec.js +3 -0
  143. package/lib/services/service.spec.js.map +1 -1
  144. package/lib/services/version.d.ts +2 -5
  145. package/lib/services/version.js +1 -10
  146. package/lib/services/version.js.map +1 -1
  147. package/lib/stores/aggregator.d.ts +3 -5
  148. package/lib/stores/aggregator.js +3 -10
  149. package/lib/stores/aggregator.js.map +1 -1
  150. package/lib/stores/file.d.ts +7 -8
  151. package/lib/stores/file.js +18 -18
  152. package/lib/stores/file.js.map +1 -1
  153. package/lib/stores/file.spec.js +8 -6
  154. package/lib/stores/file.spec.js.map +1 -1
  155. package/lib/stores/mapper.d.ts +1 -5
  156. package/lib/stores/mapper.js +56 -39
  157. package/lib/stores/mapper.js.map +1 -1
  158. package/lib/stores/mapper.spec.js +120 -1
  159. package/lib/stores/mapper.spec.js.map +1 -1
  160. package/lib/stores/memory.d.ts +5 -9
  161. package/lib/stores/memory.js +5 -17
  162. package/lib/stores/memory.js.map +1 -1
  163. package/lib/stores/memory.spec.d.ts +1 -0
  164. package/lib/stores/memory.spec.js +32 -0
  165. package/lib/stores/memory.spec.js.map +1 -1
  166. package/lib/stores/store.d.ts +131 -26
  167. package/lib/stores/store.js +399 -80
  168. package/lib/stores/store.js.map +1 -1
  169. package/lib/stores/store.spec.d.ts +29 -2
  170. package/lib/stores/store.spec.js +204 -31
  171. package/lib/stores/store.spec.js.map +1 -1
  172. package/lib/stores/webdaql/WebdaQLLexer.d.ts +53 -0
  173. package/lib/stores/webdaql/WebdaQLLexer.js +290 -0
  174. package/lib/stores/webdaql/WebdaQLLexer.js.map +1 -0
  175. package/lib/stores/webdaql/WebdaQLParserLexer.d.ts +53 -0
  176. package/lib/stores/webdaql/WebdaQLParserLexer.js +290 -0
  177. package/lib/stores/webdaql/WebdaQLParserLexer.js.map +1 -0
  178. package/lib/stores/webdaql/WebdaQLParserListener.d.ts +308 -0
  179. package/lib/stores/webdaql/WebdaQLParserListener.js +4 -0
  180. package/lib/stores/webdaql/WebdaQLParserListener.js.map +1 -0
  181. package/lib/stores/webdaql/WebdaQLParserParser.d.ts +301 -0
  182. package/lib/stores/webdaql/WebdaQLParserParser.js +1781 -0
  183. package/lib/stores/webdaql/WebdaQLParserParser.js.map +1 -0
  184. package/lib/stores/webdaql/WebdaQLParserVisitor.d.ts +198 -0
  185. package/lib/stores/webdaql/WebdaQLParserVisitor.js +4 -0
  186. package/lib/stores/webdaql/WebdaQLParserVisitor.js.map +1 -0
  187. package/lib/stores/webdaql/query.d.ts +300 -0
  188. package/lib/stores/webdaql/query.js +471 -0
  189. package/lib/stores/webdaql/query.js.map +1 -0
  190. package/lib/stores/webdaql/query.spec.d.ts +1 -0
  191. package/lib/stores/webdaql/query.spec.js +136 -0
  192. package/lib/stores/webdaql/query.spec.js.map +1 -0
  193. package/lib/test.d.ts +50 -2
  194. package/lib/test.js +161 -16
  195. package/lib/test.js.map +1 -1
  196. package/lib/unpackedapplication.d.ts +66 -0
  197. package/lib/unpackedapplication.js +202 -0
  198. package/lib/unpackedapplication.js.map +1 -0
  199. package/lib/utils/context.d.ts +14 -12
  200. package/lib/utils/context.js +14 -9
  201. package/lib/utils/context.js.map +1 -1
  202. package/lib/utils/context.spec.js +1 -1
  203. package/lib/utils/context.spec.js.map +1 -1
  204. package/lib/utils/cookie.d.ts +6 -3
  205. package/lib/utils/cookie.js +22 -20
  206. package/lib/utils/cookie.js.map +1 -1
  207. package/lib/utils/cookie.spec.js +0 -1
  208. package/lib/utils/cookie.spec.js.map +1 -1
  209. package/lib/utils/logger.d.ts +16 -3
  210. package/lib/utils/logger.js +16 -3
  211. package/lib/utils/logger.js.map +1 -1
  212. package/lib/utils/logger.spec.js.map +1 -1
  213. package/lib/utils/serializers.js +5 -1
  214. package/lib/utils/serializers.js.map +1 -1
  215. package/lib/utils/waiter.d.ts +1 -1
  216. package/lib/utils/waiter.js.map +1 -1
  217. package/package.json +25 -18
  218. package/test/config-file-no-reload.json +2 -1
  219. package/test/config-file-reload.json +2 -1
  220. package/test/config-invitation.json +63 -0
  221. package/test/config-kube-reload.json +2 -1
  222. package/test/config-reload.json +1 -1
  223. package/test/config.json +6 -10
  224. package/test/config.old.json +1 -1
  225. package/test/moddas/annotatedservice.js +1 -3
  226. package/test/moddas/debugmailer.js +2 -7
  227. package/test/moddas/fakeservice.js +1 -1
  228. package/test/moddas/voidstore.js +2 -4
  229. package/test/models/ident.js +1 -1
  230. package/test/models/task.js +1 -5
  231. package/webda.module.json +1124 -0
  232. package/test/config.old-default.json +0 -151
@@ -13,6 +13,7 @@ exports.Store = exports.StoreParameters = exports.UpdateConditionFailError = exp
13
13
  const core_1 = require("../core");
14
14
  const coremodel_1 = require("../models/coremodel");
15
15
  const service_1 = require("../services/service");
16
+ const query_1 = require("./webdaql/query");
16
17
  class StoreNotFoundError extends core_1.WebdaError {
17
18
  constructor(uuid, storeName) {
18
19
  super("STORE_NOTFOUND", `Item not found ${uuid} Store(${storeName})`);
@@ -30,7 +31,8 @@ exports.UpdateConditionFailError = UpdateConditionFailError;
30
31
  */
31
32
  class StoreParameters extends service_1.ServiceParameters {
32
33
  constructor(params, service) {
33
- var _a, _b;
34
+ var _a, _b, _c, _d;
35
+ var _e;
34
36
  super(params);
35
37
  (_a = this.model) !== null && _a !== void 0 ? _a : (this.model = "Webda/CoreModel");
36
38
  let expose = params.expose;
@@ -49,6 +51,7 @@ class StoreParameters extends service_1.ServiceParameters {
49
51
  if (expose) {
50
52
  expose.restrict = expose.restrict || {};
51
53
  this.expose = expose;
54
+ (_b = (_e = this.expose).queryMethod) !== null && _b !== void 0 ? _b : (_e.queryMethod = "GET");
52
55
  }
53
56
  if (params.map) {
54
57
  throw new Error("Deprecated map usage, use a MapperService");
@@ -56,7 +59,8 @@ class StoreParameters extends service_1.ServiceParameters {
56
59
  if (params.index) {
57
60
  throw new Error("Deprecated index usage, use an AggregatorService");
58
61
  }
59
- (_b = this.strict) !== null && _b !== void 0 ? _b : (this.strict = true);
62
+ (_c = this.strict) !== null && _c !== void 0 ? _c : (this.strict = true);
63
+ (_d = this.slowQueryThreshold) !== null && _d !== void 0 ? _d : (this.slowQueryThreshold = 30000);
60
64
  }
61
65
  }
62
66
  exports.StoreParameters = StoreParameters;
@@ -105,6 +109,23 @@ class Store extends service_1.Service {
105
109
  * Contain the model uuid field
106
110
  */
107
111
  this._uuidField = "uuid";
112
+ /**
113
+ * Add metrics counter
114
+ */
115
+ this.metrics = {
116
+ save: 0,
117
+ update: 0,
118
+ partialUpdate: 0,
119
+ get: 0,
120
+ increment: 0,
121
+ delete: 0,
122
+ collectionUpsert: 0,
123
+ collectionDelete: 0,
124
+ attributeDelete: 0,
125
+ query: 0,
126
+ queryDuration: 0,
127
+ slowQueries: 0
128
+ };
108
129
  }
109
130
  /**
110
131
  * Load the parameters for a service
@@ -118,13 +139,16 @@ class Store extends service_1.Service {
118
139
  * @throws Error if model is not found
119
140
  */
120
141
  computeParameters() {
142
+ var _a;
121
143
  super.computeParameters();
122
144
  const p = this.parameters;
123
145
  this._model = this._webda.getModel(p.model);
124
146
  this._uuidField = this._model.getUuidField();
125
147
  this._lastUpdateField = this._model.getLastUpdateField();
126
148
  this._creationDateField = this._model.getCreationField();
149
+ (_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a.computeParameters();
127
150
  }
151
+ logSlowQuery(query, reason, time) { }
128
152
  /**
129
153
  * Return Store current model
130
154
  * @returns
@@ -135,8 +159,35 @@ class Store extends service_1.Service {
135
159
  getLastUpdateField() {
136
160
  return this._model.getLastUpdateField();
137
161
  }
162
+ /**
163
+ * Get From Cache or main
164
+ * @param uid
165
+ * @param raiseIfNotFound
166
+ * @returns
167
+ */
168
+ _getFromCache(uid, raiseIfNotFound = false) {
169
+ var _a;
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ let res = yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._get(uid));
172
+ if (!res) {
173
+ res = yield this._get(uid, raiseIfNotFound);
174
+ }
175
+ else {
176
+ res.__store = this;
177
+ }
178
+ return res;
179
+ });
180
+ }
181
+ /**
182
+ * Get object from store
183
+ * @param uid
184
+ * @returns
185
+ */
138
186
  getObject(uid) {
139
- return this._get(uid);
187
+ return __awaiter(this, void 0, void 0, function* () {
188
+ this.metrics.get++;
189
+ return this._getFromCache(uid);
190
+ });
140
191
  }
141
192
  /**
142
193
  * @inheritdoc
@@ -153,15 +204,25 @@ class Store extends service_1.Service {
153
204
  post: {
154
205
  description: `The way to create a new ${this._model.name} model`,
155
206
  summary: "Create a new " + this._model.name,
156
- model: this._model.name,
157
207
  operationId: `create${this._model.name}`,
158
208
  responses: {
159
209
  "200": {
160
- model: this._model.name
210
+ description: "Retrieve model",
211
+ content: {
212
+ "application/json": {
213
+ // schema: this._model.name
214
+ }
215
+ }
216
+ },
217
+ "400": {
218
+ description: "Object is invalid"
161
219
  },
162
- "400": "Object is invalid",
163
- "403": "You don't have permissions",
164
- "409": "Object already exists"
220
+ "403": {
221
+ description: "You don't have permissions"
222
+ },
223
+ "409": {
224
+ description: "Object already exists"
225
+ }
165
226
  }
166
227
  }
167
228
  });
@@ -175,6 +236,33 @@ class Store extends service_1.Service {
175
236
  if (!expose.restrict.get) {
176
237
  methods.push("GET");
177
238
  }
239
+ // Query endpoint
240
+ if (!expose.restrict.query) {
241
+ this.addRoute(expose.queryMethod === "GET" ? `${expose.url}{?q}` : expose.url, [expose.queryMethod], this.httpQuery, {
242
+ model: this._model.name,
243
+ [expose.queryMethod.toLowerCase()]: {
244
+ description: `Query on ${this._model.name} model with WebdaQL`,
245
+ summary: "Query " + this._model.name,
246
+ operationId: `create${this._model.name}`,
247
+ responses: {
248
+ "200": {
249
+ description: "Retrieve models",
250
+ content: {
251
+ "application/json": {
252
+ // schema: this._model.name
253
+ }
254
+ }
255
+ },
256
+ "400": {
257
+ description: "Query is invalid"
258
+ },
259
+ "403": {
260
+ description: "You don't have permissions"
261
+ }
262
+ }
263
+ }
264
+ });
265
+ }
178
266
  if (!expose.restrict.delete) {
179
267
  methods.push("DELETE");
180
268
  }
@@ -187,48 +275,71 @@ class Store extends service_1.Service {
187
275
  operationId: `get${this._model.name}`,
188
276
  responses: {
189
277
  "200": {
190
- model: this._model.name
278
+ //model: this._model.name
279
+ },
280
+ "400": {
281
+ description: "Object is invalid"
191
282
  },
192
- "400": "Object is invalid",
193
- "403": "You don't have permissions",
194
- "404": "Unknown object"
283
+ "403": {
284
+ description: "You don't have permissions"
285
+ },
286
+ "404": {
287
+ description: "Unknown object"
288
+ }
195
289
  }
196
290
  },
197
291
  put: {
198
292
  description: `Update a ${this._model.name} if the permissions allow`,
199
293
  summary: "Update a " + this._model.name,
200
- model: this._model.name,
201
294
  operationId: `updatet${this._model.name}`,
202
295
  responses: {
203
296
  "200": {
204
- model: this._model.name
297
+ // model: this._model.name
298
+ },
299
+ "400": {
300
+ description: "Object is invalid"
301
+ },
302
+ "403": {
303
+ description: "You don't have permissions"
205
304
  },
206
- "400": "Object is invalid",
207
- "403": "You don't have permissions",
208
- "404": "Unknown object"
305
+ "404": {
306
+ description: "Unknown object"
307
+ }
209
308
  }
210
309
  },
211
310
  patch: {
212
311
  description: `Patch a ${this._model.name} if the permissions allow`,
213
312
  summary: "Patch a " + this._model.name,
214
- model: this._model.name,
215
313
  operationId: `updatet${this._model.name}`,
216
314
  responses: {
217
- "204": "",
218
- "400": "Object is invalid",
219
- "403": "You don't have permissions",
220
- "404": "Unknown object"
315
+ "204": {
316
+ description: ""
317
+ },
318
+ "400": {
319
+ description: "Object is invalid"
320
+ },
321
+ "403": {
322
+ description: "You don't have permissions"
323
+ },
324
+ "404": {
325
+ description: "Unknown object"
326
+ }
221
327
  }
222
328
  },
223
329
  delete: {
224
330
  operationId: `delete${this._model.name}`,
225
331
  description: `Delete ${this._model.name} if the permissions allow`,
226
332
  summary: "Delete a " + this._model.name,
227
- model: this._model.name,
228
333
  responses: {
229
- "204": "",
230
- "403": "You don't have permissions",
231
- "404": "Unknown object"
334
+ "204": {
335
+ description: ""
336
+ },
337
+ "403": {
338
+ description: "You don't have permissions"
339
+ },
340
+ "404": {
341
+ description: "Unknown object"
342
+ }
232
343
  }
233
344
  }
234
345
  });
@@ -260,6 +371,16 @@ class Store extends service_1.Service {
260
371
  });
261
372
  }
262
373
  }
374
+ /**
375
+ * OVerwrite the model
376
+ * Used mainly in test
377
+ */
378
+ setModel(model) {
379
+ var _a;
380
+ this._model = model;
381
+ (_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a.setModel(model);
382
+ this.parameters.strict = false;
383
+ }
263
384
  /**
264
385
  * Get the url where the store is exposed
265
386
  */
@@ -311,13 +432,16 @@ class Store extends service_1.Service {
311
432
  });
312
433
  }
313
434
  incrementAttribute(uid, prop, value) {
435
+ var _a;
314
436
  return __awaiter(this, void 0, void 0, function* () {
315
437
  // If value === 0 no need to update anything
316
438
  if (value === 0) {
317
439
  return Promise.resolve();
318
440
  }
319
441
  let updateDate = new Date();
442
+ this.metrics.increment++;
320
443
  yield this._incrementAttribute(uid, prop, value, updateDate);
444
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._incrementAttribute(uid, prop, value, updateDate));
321
445
  return this.emitSync("Store.PartialUpdated", {
322
446
  object_id: uid,
323
447
  store: this,
@@ -332,12 +456,15 @@ class Store extends service_1.Service {
332
456
  });
333
457
  }
334
458
  upsertItemToCollection(uid, prop, item, index = undefined, itemWriteCondition = undefined, itemWriteConditionField = undefined) {
459
+ var _a;
335
460
  return __awaiter(this, void 0, void 0, function* () {
336
461
  if (itemWriteConditionField === undefined) {
337
462
  itemWriteConditionField = this._uuidField;
338
463
  }
339
464
  let updateDate = new Date();
465
+ this.metrics.collectionUpsert++;
340
466
  yield this._upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate);
467
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate));
341
468
  yield this.emitSync("Store.PartialUpdated", {
342
469
  object_id: uid,
343
470
  store: this,
@@ -353,9 +480,12 @@ class Store extends service_1.Service {
353
480
  });
354
481
  }
355
482
  deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField = this._uuidField) {
483
+ var _a;
356
484
  return __awaiter(this, void 0, void 0, function* () {
357
485
  let updateDate = new Date();
486
+ this.metrics.collectionDelete++;
358
487
  yield this._deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate);
488
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate));
359
489
  yield this.emitSync("Store.PartialUpdated", {
360
490
  object_id: uid,
361
491
  store: this,
@@ -369,6 +499,125 @@ class Store extends service_1.Service {
369
499
  });
370
500
  });
371
501
  }
502
+ /**
503
+ * Query store with WebdaQL
504
+ * @param query
505
+ * @param context to apply permission
506
+ */
507
+ query(query, context) {
508
+ return __awaiter(this, void 0, void 0, function* () {
509
+ let queryValidator = new query_1.WebdaQL.QueryValidator(query);
510
+ let offset = queryValidator.getOffset();
511
+ const limit = queryValidator.getLimit();
512
+ const parsedQuery = queryValidator.getQuery();
513
+ // Emit the default event
514
+ yield this.emitSync("Store.Query", {
515
+ query,
516
+ parsedQuery,
517
+ store: this
518
+ });
519
+ const result = {
520
+ results: [],
521
+ continuationToken: undefined
522
+ };
523
+ /*
524
+ Offset are split in two with _
525
+
526
+ MainOffset is the database offset, retrieving a page from the database
527
+ SubOffset is the offset within the page
528
+
529
+ As we filter through the page, for additional filters or permissions, the page cut
530
+ by database does not endup being our final page cut, so we need a page offset to
531
+ abstract this completely
532
+ */
533
+ let [mainOffset, subOffset] = offset.split("_");
534
+ let secondOffset = parseInt(subOffset || "0");
535
+ let duration = Date.now();
536
+ this.metrics.query++;
537
+ while (result.results.length < limit) {
538
+ let tmpResults = yield this.find(Object.assign(Object.assign({}, parsedQuery), { continuationToken: mainOffset }));
539
+ // If no filter is returned assume it is by mistake and apply filtering
540
+ if (tmpResults.filter === undefined) {
541
+ tmpResults.filter = queryValidator.getExpression();
542
+ this.log("WARN", `Store '${this.getName()}' postquery full filtering`);
543
+ }
544
+ let subOffsetCount = 0;
545
+ for (let item of tmpResults.results) {
546
+ // Because of dynamic filter and permission we need to suboffset the pagination
547
+ subOffsetCount++;
548
+ if (subOffsetCount <= secondOffset) {
549
+ continue;
550
+ }
551
+ if (tmpResults.filter !== true && !tmpResults.filter.eval(item)) {
552
+ continue;
553
+ }
554
+ if (context) {
555
+ try {
556
+ yield item.canAct(context, "get");
557
+ }
558
+ catch (err) {
559
+ continue;
560
+ }
561
+ }
562
+ result.results.push(item);
563
+ if (result.results.length >= limit) {
564
+ if (subOffsetCount === tmpResults.results.length) {
565
+ result.continuationToken = tmpResults.continuationToken;
566
+ }
567
+ else {
568
+ result.continuationToken = `${mainOffset}_${subOffsetCount}`;
569
+ }
570
+ break;
571
+ }
572
+ }
573
+ // Update both offset
574
+ mainOffset = tmpResults.continuationToken;
575
+ // Fresh new query so we do not need to skip
576
+ secondOffset = 0;
577
+ if (mainOffset === undefined || result.results.length >= limit) {
578
+ break;
579
+ }
580
+ }
581
+ duration = Date.now() - duration;
582
+ this.metrics.queryDuration =
583
+ (this.metrics.queryDuration * (this.metrics.query - 1) + duration) / this.metrics.query;
584
+ if (duration > this.parameters.slowQueryThreshold) {
585
+ this.logSlowQuery(query, "", duration);
586
+ }
587
+ yield this.emitSync("Store.Queried", {
588
+ query,
589
+ parsedQuery: parsedQuery,
590
+ store: this,
591
+ continuationToken: result.continuationToken,
592
+ results: result.results
593
+ });
594
+ return result;
595
+ });
596
+ }
597
+ /**
598
+ * Expose query to http
599
+ */
600
+ httpQuery(ctx) {
601
+ return __awaiter(this, void 0, void 0, function* () {
602
+ let query;
603
+ if (ctx.getHttpContext().getMethod() === "GET") {
604
+ query = ctx.getParameters().q;
605
+ }
606
+ else {
607
+ query = ctx.getRequestBody().q;
608
+ }
609
+ try {
610
+ ctx.write(yield this.query(query, ctx));
611
+ }
612
+ catch (err) {
613
+ if (err instanceof SyntaxError) {
614
+ this.log("INFO", "Query syntax error");
615
+ throw 400;
616
+ }
617
+ throw err;
618
+ }
619
+ });
620
+ }
372
621
  /**
373
622
  * Save an object
374
623
  *
@@ -379,12 +628,12 @@ class Store extends service_1.Service {
379
628
  * Might want to rename to create
380
629
  */
381
630
  save(object, ctx = undefined) {
382
- var _a;
383
- var _b;
631
+ var _a, _b;
632
+ var _c;
384
633
  return __awaiter(this, void 0, void 0, function* () {
385
634
  object = this.initModel(object);
386
635
  // Dates should be store by the Store
387
- (_a = object[_b = this._creationDateField]) !== null && _a !== void 0 ? _a : (object[_b] = new Date());
636
+ (_a = object[_c = this._creationDateField]) !== null && _a !== void 0 ? _a : (object[_c] = new Date());
388
637
  object[this._lastUpdateField] = new Date();
389
638
  if (ctx) {
390
639
  object.setContext(ctx);
@@ -395,7 +644,9 @@ class Store extends service_1.Service {
395
644
  });
396
645
  // Handle object auto listener
397
646
  yield object._onSave();
647
+ this.metrics.save++;
398
648
  let res = yield this._save(object);
649
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._save(object));
399
650
  object = this.initModel(res);
400
651
  yield this.emitSync("Store.Saved", {
401
652
  object: object,
@@ -462,6 +713,9 @@ class Store extends service_1.Service {
462
713
  */
463
714
  simulateUpsertItemToCollection(model, prop, item, updateDate, index, itemWriteCondition, itemWriteConditionField) {
464
715
  return __awaiter(this, void 0, void 0, function* () {
716
+ if (prop === "__proto__") {
717
+ throw new Error("Cannot update __proto__: js/prototype-polluting-assignment");
718
+ }
465
719
  this.checkCollectionUpdateCondition(model, prop, itemWriteConditionField, itemWriteCondition, index);
466
720
  if (index === undefined) {
467
721
  if (model[prop] === undefined) {
@@ -486,6 +740,7 @@ class Store extends service_1.Service {
486
740
  * @return {Promise} with saved object
487
741
  */
488
742
  update(object, reverseMap = true, partial = false) {
743
+ var _a, _b;
489
744
  return __awaiter(this, void 0, void 0, function* () {
490
745
  /** @ignore */
491
746
  var saved;
@@ -498,12 +753,12 @@ class Store extends service_1.Service {
498
753
  }
499
754
  }
500
755
  }
501
- let partialEvent = partial ? "Patch" : "";
502
756
  if (Object.keys(object).length < 2) {
503
757
  return {};
504
758
  }
505
759
  object[this._lastUpdateField] = new Date();
506
- let load = yield this._get(object[this._uuidField], true);
760
+ this.metrics.get++;
761
+ let load = yield this._getFromCache(object[this._uuidField], true);
507
762
  if (load.__type !== this._model.name && this.parameters.strict) {
508
763
  this.log("WARN", `Object '${object[this._uuidField]}' was not created by this store`);
509
764
  throw new StoreNotFoundError(object[this._uuidField], this.getName());
@@ -512,15 +767,26 @@ class Store extends service_1.Service {
512
767
  if (object instanceof coremodel_1.CoreModel) {
513
768
  loaded.setContext(object.getContext());
514
769
  }
515
- yield this.emitSync(`Store.${partialEvent}Update`, {
516
- object: loaded,
517
- store: this,
518
- update: object
519
- });
770
+ if (partial) {
771
+ yield this.emitSync(`Store.PatchUpdate`, {
772
+ object: loaded,
773
+ store: this,
774
+ update: object
775
+ });
776
+ }
777
+ else {
778
+ yield this.emitSync(`Store.Update`, {
779
+ object: loaded,
780
+ store: this,
781
+ update: object
782
+ });
783
+ }
520
784
  yield loaded._onUpdate(object);
521
785
  let res;
522
786
  if (partial) {
787
+ this.metrics.partialUpdate++;
523
788
  yield this._patch(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField);
789
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._patch(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField));
524
790
  res = object;
525
791
  }
526
792
  else {
@@ -528,7 +794,9 @@ class Store extends service_1.Service {
528
794
  for (let i in this._reverseMap) {
529
795
  object[this._reverseMap[i].property] = loaded[this._reverseMap[i].property];
530
796
  }
797
+ this.metrics.update++;
531
798
  res = yield this._update(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField);
799
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._update(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField));
532
800
  }
533
801
  // Return updated
534
802
  for (let i in res) {
@@ -538,10 +806,18 @@ class Store extends service_1.Service {
538
806
  loaded[i] = object[i];
539
807
  }
540
808
  saved = this.initModel(loaded);
541
- yield this.emitSync(`Store.${partialEvent}Updated`, {
542
- object: saved,
543
- store: this
544
- });
809
+ if (partial) {
810
+ yield this.emitSync(`Store.PatchUpdated`, {
811
+ object: saved,
812
+ store: this
813
+ });
814
+ }
815
+ else {
816
+ yield this.emitSync(`Store.Updated`, {
817
+ object: saved,
818
+ store: this
819
+ });
820
+ }
545
821
  yield saved._onUpdated();
546
822
  return saved;
547
823
  });
@@ -554,8 +830,11 @@ class Store extends service_1.Service {
554
830
  * @returns
555
831
  */
556
832
  removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField) {
833
+ var _a;
557
834
  return __awaiter(this, void 0, void 0, function* () {
835
+ this.metrics.attributeDelete++;
558
836
  yield this._removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField);
837
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField));
559
838
  yield this.emitSync("Store.PartialUpdated", {
560
839
  object_id: uuid,
561
840
  partial_update: {
@@ -571,7 +850,7 @@ class Store extends service_1.Service {
571
850
  * @param uuid
572
851
  * @returns
573
852
  */
574
- cascadeDelete(obj, uuid) {
853
+ cascadeDelete(obj, _uuid) {
575
854
  return __awaiter(this, void 0, void 0, function* () {
576
855
  // We dont need uuid but Binary store will need it
577
856
  return this.delete(obj.getUuid());
@@ -595,6 +874,7 @@ class Store extends service_1.Service {
595
874
  * @return {Promise} the deletion promise
596
875
  */
597
876
  delete(uid, writeCondition, writeConditionField, sync = false) {
877
+ var _a, _b;
598
878
  return __awaiter(this, void 0, void 0, function* () {
599
879
  /** @ignore */
600
880
  let to_delete;
@@ -603,7 +883,8 @@ class Store extends service_1.Service {
603
883
  to_delete = uid;
604
884
  }
605
885
  else {
606
- to_delete = yield this._get(uid);
886
+ this.metrics.get++;
887
+ to_delete = yield this._getFromCache(uid);
607
888
  if (to_delete === undefined) {
608
889
  return;
609
890
  }
@@ -627,13 +908,19 @@ class Store extends service_1.Service {
627
908
  yield to_delete._onDelete();
628
909
  // If async we just tag the object as deleted
629
910
  if (this.parameters.asyncDelete && !sync) {
911
+ this.metrics.partialUpdate++;
630
912
  yield this._patch({
631
913
  __deleted: true
632
914
  }, to_delete.getUuid());
915
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._patch({
916
+ __deleted: true
917
+ }, to_delete.getUuid()));
633
918
  }
634
919
  else {
920
+ this.metrics.delete++;
635
921
  // Delete from the DB for real
636
922
  yield this._delete(to_delete.getUuid(), writeCondition, writeConditionField);
923
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._delete(to_delete.getUuid(), writeCondition, writeConditionField));
637
924
  }
638
925
  // Send post event
639
926
  yield this.emitSync("Store.Deleted", {
@@ -649,7 +936,7 @@ class Store extends service_1.Service {
649
936
  * @param id
650
937
  * @param callback
651
938
  */
652
- canTriggerConfiguration(id, callback) {
939
+ canTriggerConfiguration(_id, _callback) {
653
940
  return false;
654
941
  }
655
942
  /**
@@ -659,7 +946,8 @@ class Store extends service_1.Service {
659
946
  */
660
947
  getConfiguration(id) {
661
948
  return __awaiter(this, void 0, void 0, function* () {
662
- let object = yield this._get(id);
949
+ this.metrics.get++;
950
+ let object = yield this._getFromCache(id);
663
951
  if (!object) {
664
952
  return undefined;
665
953
  }
@@ -685,7 +973,8 @@ class Store extends service_1.Service {
685
973
  if (!uid) {
686
974
  return undefined;
687
975
  }
688
- let object = yield this._get(uid);
976
+ this.metrics.get++;
977
+ let object = yield this._getFromCache(uid);
689
978
  if (!object) {
690
979
  return undefined;
691
980
  }
@@ -722,31 +1011,62 @@ class Store extends service_1.Service {
722
1011
  });
723
1012
  }
724
1013
  /**
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
1014
+ * @override
733
1015
  */
734
- find(request = undefined, offset = 0, limit = undefined) {
1016
+ simulateFind(query, uuids) {
735
1017
  return __awaiter(this, void 0, void 0, function* () {
736
- yield this.emitSync("Store.Find", {
737
- request: request,
738
- store: this,
739
- offset: offset,
740
- limit: limit
741
- });
742
- let result = yield this._find(request, offset, limit);
743
- yield this.emitSync("Store.Found", {
744
- request: request,
745
- store: this,
746
- offset: offset,
747
- limit: limit,
748
- results: result
749
- });
1018
+ let result = {
1019
+ results: [],
1020
+ continuationToken: undefined,
1021
+ filter: true
1022
+ };
1023
+ let count = 0;
1024
+ let limit = query.limit;
1025
+ let offset = parseInt(query.continuationToken || "0");
1026
+ let originalOffset = offset;
1027
+ if (query.orderBy && query.orderBy.length) {
1028
+ offset = 0;
1029
+ limit = Number.MAX_SAFE_INTEGER;
1030
+ }
1031
+ // Need to transfert to Array
1032
+ for (let uuid of uuids) {
1033
+ count++;
1034
+ // Offset start
1035
+ if (offset >= count) {
1036
+ continue;
1037
+ }
1038
+ let obj = yield this._getFromCache(uuid);
1039
+ if (obj && query.filter.eval(obj)) {
1040
+ result.results.push(obj);
1041
+ if (result.results.length >= limit) {
1042
+ result.continuationToken = count.toString();
1043
+ return result;
1044
+ }
1045
+ }
1046
+ }
1047
+ if (query.orderBy && query.orderBy.length) {
1048
+ result.results = result.results
1049
+ .sort((a, b) => {
1050
+ let valA, valB;
1051
+ for (let orderBy of query.orderBy) {
1052
+ let invert = orderBy.direction === "ASC" ? 1 : -1;
1053
+ valA = query_1.WebdaQL.ComparisonExpression.getAttributeValue(a, orderBy.field.split("."));
1054
+ valB = query_1.WebdaQL.ComparisonExpression.getAttributeValue(b, orderBy.field.split("."));
1055
+ if (valA === valB) {
1056
+ continue;
1057
+ }
1058
+ if (typeof valA === "string") {
1059
+ return valA.localeCompare(valB) * invert;
1060
+ }
1061
+ return (valA < valB ? -1 : 1) * invert;
1062
+ }
1063
+ return -1;
1064
+ })
1065
+ .slice(originalOffset, query.limit + originalOffset);
1066
+ if (result.results.length >= query.limit) {
1067
+ result.continuationToken = (query.limit + originalOffset).toString();
1068
+ }
1069
+ }
750
1070
  return result;
751
1071
  });
752
1072
  }
@@ -763,7 +1083,7 @@ class Store extends service_1.Service {
763
1083
  object[this._creationDateField] = new Date();
764
1084
  yield object.canAct(ctx, "create");
765
1085
  try {
766
- yield object.validate(ctx);
1086
+ yield object.validate(ctx, body);
767
1087
  }
768
1088
  catch (err) {
769
1089
  this.log("INFO", "Object is not valid", err);
@@ -861,12 +1181,11 @@ class Store extends service_1.Service {
861
1181
  }
862
1182
  let updateObject = new this._model();
863
1183
  // Clean any default attributes from the model
864
- for (let i in updateObject) {
865
- if (i.startsWith("__")) {
866
- continue;
867
- }
1184
+ Object.keys(updateObject)
1185
+ .filter(i => i !== "__class")
1186
+ .forEach(i => {
868
1187
  delete updateObject[i];
869
- }
1188
+ });
870
1189
  updateObject.setContext(ctx);
871
1190
  updateObject.load(body);
872
1191
  yield this.patch(updateObject);
@@ -876,13 +1195,13 @@ class Store extends service_1.Service {
876
1195
  let updateObject = new this._model();
877
1196
  updateObject.load(body);
878
1197
  // Copy back the _ attributes
879
- for (let i in object) {
880
- if (i.startsWith("_")) {
881
- updateObject[i] = object[i];
882
- }
883
- }
1198
+ Object.keys(object)
1199
+ .filter(i => i.startsWith("_"))
1200
+ .forEach(i => {
1201
+ updateObject[i] = object[i];
1202
+ });
884
1203
  try {
885
- yield updateObject.validate(ctx);
1204
+ yield updateObject.validate(ctx, body);
886
1205
  }
887
1206
  catch (err) {
888
1207
  this.log("INFO", "Object invalid", err);