@webda/core 2.4.1 → 3.0.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/lib/application.d.ts +171 -34
- package/lib/application.js +243 -47
- package/lib/application.js.map +1 -1
- package/lib/application.spec.js +44 -8
- package/lib/application.spec.js.map +1 -1
- package/lib/core.d.ts +113 -54
- package/lib/core.js +222 -135
- package/lib/core.js.map +1 -1
- package/lib/core.spec.js +87 -43
- package/lib/core.spec.js.map +1 -1
- package/lib/errors.d.ts +65 -0
- package/lib/errors.js +113 -0
- package/lib/errors.js.map +1 -0
- package/lib/errors.spec.d.ts +1 -0
- package/lib/errors.spec.js +33 -0
- package/lib/errors.spec.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/models/aclmodel.d.ts +4 -4
- package/lib/models/aclmodel.js +10 -6
- package/lib/models/aclmodel.js.map +1 -1
- package/lib/models/aclmodel.spec.js +33 -24
- package/lib/models/aclmodel.spec.js.map +1 -1
- package/lib/models/coremodel.d.ts +284 -92
- package/lib/models/coremodel.js +403 -103
- package/lib/models/coremodel.js.map +1 -1
- package/lib/models/coremodel.spec.js +162 -24
- package/lib/models/coremodel.spec.js.map +1 -1
- package/lib/models/ident.d.ts +20 -6
- package/lib/models/ident.js.map +1 -1
- package/lib/models/ownermodel.d.ts +13 -23
- package/lib/models/ownermodel.js +24 -51
- package/lib/models/ownermodel.js.map +1 -1
- package/lib/models/ownermodel.spec.js +23 -11
- package/lib/models/ownermodel.spec.js.map +1 -1
- package/lib/models/relations.d.ts +167 -0
- package/lib/models/relations.js +113 -0
- package/lib/models/relations.js.map +1 -0
- package/lib/models/rolemodel.d.ts +3 -3
- package/lib/models/rolemodel.js +6 -6
- package/lib/models/rolemodel.js.map +1 -1
- package/lib/models/rolemodel.spec.js +12 -12
- package/lib/models/rolemodel.spec.js.map +1 -1
- package/lib/models/user.d.ts +40 -24
- package/lib/models/user.js +74 -48
- package/lib/models/user.js.map +1 -1
- package/lib/models/user.spec.js +24 -4
- package/lib/models/user.spec.js.map +1 -1
- package/lib/queues/memoryqueue.spec.js +9 -5
- package/lib/queues/memoryqueue.spec.js.map +1 -1
- package/lib/queues/queueservice.js.map +1 -1
- package/lib/router.d.ts +17 -8
- package/lib/router.js +81 -9
- package/lib/router.js.map +1 -1
- package/lib/router.spec.js +89 -5
- package/lib/router.spec.js.map +1 -1
- package/lib/services/asyncevents.spec.js +4 -4
- package/lib/services/authentication.d.ts +21 -22
- package/lib/services/authentication.js +90 -109
- package/lib/services/authentication.js.map +1 -1
- package/lib/services/authentication.spec.js +51 -65
- package/lib/services/authentication.spec.js.map +1 -1
- package/lib/services/binary.d.ts +132 -31
- package/lib/services/binary.js +257 -72
- package/lib/services/binary.js.map +1 -1
- package/lib/services/binary.spec.d.ts +16 -6
- package/lib/services/binary.spec.js +44 -117
- package/lib/services/binary.spec.js.map +1 -1
- package/lib/services/cloudbinary.d.ts +9 -10
- package/lib/services/cloudbinary.js +14 -15
- package/lib/services/cloudbinary.js.map +1 -1
- package/lib/services/cloudbinary.spec.d.ts +2 -2
- package/lib/services/cloudbinary.spec.js +13 -12
- package/lib/services/cloudbinary.spec.js.map +1 -1
- package/lib/services/configuration.js +9 -9
- package/lib/services/configuration.js.map +1 -1
- package/lib/services/configuration.spec.js +5 -7
- package/lib/services/configuration.spec.js.map +1 -1
- package/lib/services/cron.spec.js +3 -4
- package/lib/services/cron.spec.js.map +1 -1
- package/lib/services/cryptoservice.d.ts +2 -2
- package/lib/services/cryptoservice.js +5 -2
- package/lib/services/cryptoservice.js.map +1 -1
- package/lib/services/domainservice.d.ts +113 -0
- package/lib/services/domainservice.js +357 -0
- package/lib/services/domainservice.js.map +1 -0
- package/lib/services/domainservice.spec.d.ts +1 -0
- package/lib/services/domainservice.spec.js +334 -0
- package/lib/services/domainservice.spec.js.map +1 -0
- package/lib/services/echo.d.ts +2 -2
- package/lib/services/echo.js.map +1 -1
- package/lib/services/echo.spec.js +9 -2
- package/lib/services/echo.spec.js.map +1 -1
- package/lib/services/filebinary.d.ts +13 -14
- package/lib/services/filebinary.js +79 -73
- package/lib/services/filebinary.js.map +1 -1
- package/lib/services/filebinary.spec.d.ts +5 -0
- package/lib/services/filebinary.spec.js +222 -11
- package/lib/services/filebinary.spec.js.map +1 -1
- package/lib/services/fileconfiguration.js +7 -7
- package/lib/services/fileconfiguration.js.map +1 -1
- package/lib/services/fileconfiguration.spec.js +23 -24
- package/lib/services/fileconfiguration.spec.js.map +1 -1
- package/lib/services/invitationservice.d.ts +11 -9
- package/lib/services/invitationservice.js +17 -23
- package/lib/services/invitationservice.js.map +1 -1
- package/lib/services/invitationservice.spec.js +43 -40
- package/lib/services/invitationservice.spec.js.map +1 -1
- package/lib/services/kubernetesconfiguration.js +12 -22
- package/lib/services/kubernetesconfiguration.js.map +1 -1
- package/lib/services/kubernetesconfiguration.spec.js +1 -6
- package/lib/services/kubernetesconfiguration.spec.js.map +1 -1
- package/lib/services/mailer.js +1 -1
- package/lib/services/mailer.js.map +1 -1
- package/lib/services/mailer.spec.js +4 -1
- package/lib/services/mailer.spec.js.map +1 -1
- package/lib/services/oauth.d.ts +17 -9
- package/lib/services/oauth.js +30 -4
- package/lib/services/oauth.js.map +1 -1
- package/lib/services/oauth.spec.js +32 -15
- package/lib/services/oauth.spec.js.map +1 -1
- package/lib/services/prometheus.spec.js.map +1 -1
- package/lib/services/proxy.d.ts +9 -8
- package/lib/services/proxy.js +65 -36
- package/lib/services/proxy.js.map +1 -1
- package/lib/services/proxy.spec.js +28 -2
- package/lib/services/proxy.spec.js.map +1 -1
- package/lib/services/resource.d.ts +3 -3
- package/lib/services/resource.js +4 -3
- package/lib/services/resource.js.map +1 -1
- package/lib/services/resource.spec.js +3 -3
- package/lib/services/resource.spec.js.map +1 -1
- package/lib/services/service.d.ts +10 -13
- package/lib/services/service.js +29 -13
- package/lib/services/service.js.map +1 -1
- package/lib/services/service.spec.js +49 -11
- package/lib/services/service.spec.js.map +1 -1
- package/lib/services/version.d.ts +2 -2
- package/lib/services/version.js.map +1 -1
- package/lib/stores/aggregator.js +1 -0
- package/lib/stores/aggregator.js.map +1 -1
- package/lib/stores/aliasstore.d.ts +2 -2
- package/lib/stores/aliasstore.js +15 -4
- package/lib/stores/aliasstore.js.map +1 -1
- package/lib/stores/aliasstore.spec.js +4 -2
- package/lib/stores/aliasstore.spec.js.map +1 -1
- package/lib/stores/file.d.ts +5 -2
- package/lib/stores/file.js +11 -8
- package/lib/stores/file.js.map +1 -1
- package/lib/stores/file.spec.js +21 -34
- package/lib/stores/file.spec.js.map +1 -1
- package/lib/stores/mapper.d.ts +4 -2
- package/lib/stores/mapper.js +18 -11
- package/lib/stores/mapper.js.map +1 -1
- package/lib/stores/mapper.spec.js +6 -3
- package/lib/stores/mapper.spec.js.map +1 -1
- package/lib/stores/memory.d.ts +5 -2
- package/lib/stores/memory.js +11 -9
- package/lib/stores/memory.js.map +1 -1
- package/lib/stores/memory.spec.d.ts +3 -0
- package/lib/stores/memory.spec.js +100 -11
- package/lib/stores/memory.spec.js.map +1 -1
- package/lib/stores/store.d.ts +177 -87
- package/lib/stores/store.js +312 -141
- package/lib/stores/store.js.map +1 -1
- package/lib/stores/store.spec.d.ts +2 -2
- package/lib/stores/store.spec.js +54 -38
- package/lib/stores/store.spec.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLLexer.d.ts +14 -13
- package/lib/stores/webdaql/WebdaQLLexer.js +121 -112
- package/lib/stores/webdaql/WebdaQLLexer.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserLexer.d.ts +14 -13
- package/lib/stores/webdaql/WebdaQLParserLexer.js +121 -112
- package/lib/stores/webdaql/WebdaQLParserLexer.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserListener.d.ts +15 -3
- package/lib/stores/webdaql/WebdaQLParserParser.d.ts +23 -13
- package/lib/stores/webdaql/WebdaQLParserParser.js +149 -94
- package/lib/stores/webdaql/WebdaQLParserParser.js.map +1 -1
- package/lib/stores/webdaql/WebdaQLParserVisitor.d.ts +9 -2
- package/lib/stores/webdaql/query.d.ts +6 -2
- package/lib/stores/webdaql/query.js +14 -1
- package/lib/stores/webdaql/query.js.map +1 -1
- package/lib/stores/webdaql/query.spec.js +10 -1
- package/lib/stores/webdaql/query.spec.js.map +1 -1
- package/lib/test.d.ts +48 -19
- package/lib/test.js +171 -63
- package/lib/test.js.map +1 -1
- package/lib/unpackedapplication.d.ts +5 -0
- package/lib/unpackedapplication.js +58 -10
- package/lib/unpackedapplication.js.map +1 -1
- package/lib/utils/context.d.ts +76 -29
- package/lib/utils/context.js +91 -55
- package/lib/utils/context.js.map +1 -1
- package/lib/utils/context.spec.d.ts +9 -1
- package/lib/utils/context.spec.js +73 -8
- package/lib/utils/context.spec.js.map +1 -1
- package/lib/utils/cookie.d.ts +4 -5
- package/lib/utils/cookie.js +1 -2
- package/lib/utils/cookie.js.map +1 -1
- package/lib/utils/cookie.spec.js +5 -3
- package/lib/utils/cookie.spec.js.map +1 -1
- package/lib/utils/httpcontext.spec.js +9 -3
- package/lib/utils/httpcontext.spec.js.map +1 -1
- package/lib/utils/serializers.d.ts +46 -17
- package/lib/utils/serializers.js +116 -2
- package/lib/utils/serializers.js.map +1 -1
- package/lib/utils/serializers.spec.js +84 -20
- package/lib/utils/serializers.spec.js.map +1 -1
- package/lib/utils/session.d.ts +14 -8
- package/lib/utils/session.js +14 -3
- package/lib/utils/session.js.map +1 -1
- package/lib/utils/session.spec.js +6 -1
- package/lib/utils/session.spec.js.map +1 -1
- package/package.json +16 -10
- package/test/cachedapp/webda.config.json +6 -1
- package/test/config-cached.json +5 -0
- package/test/config-file-missing-file.json +5 -7
- package/test/config-file-no-reload.json +5 -7
- package/test/config-file-reload.json +5 -7
- package/test/config-kube-reload.json +5 -11
- package/test/config-reload.json +2 -4
- package/test/config.json +12 -2
- package/test/moddas/voidstore.js +1 -1
- package/test/models/ident.js +6 -4
- package/test/models/task.js +4 -4
- package/webda.module.json +1587 -1266
package/lib/stores/store.js
CHANGED
|
@@ -4,16 +4,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { Counter, Histogram
|
|
7
|
+
import { Counter, Histogram } from "../core.js";
|
|
8
|
+
import { ModelMapLoaderImplementation, Throttler, WebdaError } from "../index.js";
|
|
8
9
|
import { CoreModel } from "../models/coremodel.js";
|
|
9
10
|
import { Route, Service, ServiceParameters } from "../services/service.js";
|
|
10
11
|
import { WebdaQL } from "./webdaql/query.js";
|
|
11
|
-
export class StoreNotFoundError extends WebdaError {
|
|
12
|
+
export class StoreNotFoundError extends WebdaError.CodeError {
|
|
12
13
|
constructor(uuid, storeName) {
|
|
13
14
|
super("STORE_NOTFOUND", `Item not found ${uuid} Store(${storeName})`);
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
|
-
export class UpdateConditionFailError extends WebdaError {
|
|
17
|
+
export class UpdateConditionFailError extends WebdaError.CodeError {
|
|
17
18
|
constructor(uuid, conditionField, condition) {
|
|
18
19
|
super("STORE_UPDATE_CONDITION_FAILED", `UpdateCondition not met on ${uuid}.${conditionField} === ${condition instanceof Date ? condition.toISOString() : condition}`);
|
|
19
20
|
}
|
|
@@ -26,7 +27,6 @@ export class StoreParameters extends ServiceParameters {
|
|
|
26
27
|
var _a;
|
|
27
28
|
super(params);
|
|
28
29
|
this.model ?? (this.model = "Webda/CoreModel");
|
|
29
|
-
this.models ?? (this.models = []);
|
|
30
30
|
let expose = params.expose;
|
|
31
31
|
if (typeof expose == "boolean") {
|
|
32
32
|
expose = {};
|
|
@@ -56,6 +56,7 @@ export class StoreParameters extends ServiceParameters {
|
|
|
56
56
|
this.defaultModel ?? (this.defaultModel = true);
|
|
57
57
|
this.forceModel ?? (this.forceModel = false);
|
|
58
58
|
this.slowQueryThreshold ?? (this.slowQueryThreshold = 30000);
|
|
59
|
+
this.modelAliases ?? (this.modelAliases = {});
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
/**
|
|
@@ -100,9 +101,9 @@ class Store extends Service {
|
|
|
100
101
|
*/
|
|
101
102
|
this._reverseMap = [];
|
|
102
103
|
/**
|
|
103
|
-
*
|
|
104
|
+
* Store teh manager hierarchy with their depth
|
|
104
105
|
*/
|
|
105
|
-
this.
|
|
106
|
+
this._modelsHierarchy = {};
|
|
106
107
|
/**
|
|
107
108
|
* Contain the model uuid field
|
|
108
109
|
*/
|
|
@@ -115,19 +116,32 @@ class Store extends Service {
|
|
|
115
116
|
*/
|
|
116
117
|
computeParameters() {
|
|
117
118
|
super.computeParameters();
|
|
119
|
+
const app = this.getWebda().getApplication();
|
|
118
120
|
const p = this.parameters;
|
|
119
|
-
this._model =
|
|
120
|
-
this.
|
|
121
|
-
this._model,
|
|
122
|
-
...this.parameters.models.map(m => this._webda.getModel(m))
|
|
123
|
-
];
|
|
124
|
-
this._modelType = this._webda.getApplication().getModelFromConstructor(this._model);
|
|
121
|
+
this._model = app.getModel(p.model);
|
|
122
|
+
this._modelType = this._model.getIdentifier();
|
|
125
123
|
this._uuidField = this._model.getUuidField();
|
|
126
|
-
this._lastUpdateField = this._model.getLastUpdateField();
|
|
127
|
-
this._creationDateField = this._model.getCreationField();
|
|
128
124
|
this._cacheStore?.computeParameters();
|
|
129
125
|
this.cacheStorePatchException();
|
|
130
|
-
|
|
126
|
+
const recursive = (tree, depth) => {
|
|
127
|
+
var _a;
|
|
128
|
+
for (let i in tree) {
|
|
129
|
+
(_a = this._modelsHierarchy)[i] ?? (_a[i] = depth);
|
|
130
|
+
this._modelsHierarchy[i] = Math.min(depth, this._modelsHierarchy[i]);
|
|
131
|
+
this._modelsHierarchy[app.completeNamespace(i)] = this._modelsHierarchy[i];
|
|
132
|
+
recursive(app.getModelHierarchy(i).children, depth + 1);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
// Compute the hierarchy
|
|
136
|
+
this._modelsHierarchy[this._model.getIdentifier(false)] = 0;
|
|
137
|
+
this._modelsHierarchy[this._model.getIdentifier()] = 0;
|
|
138
|
+
// Strict Store only store their model
|
|
139
|
+
if (!this.parameters.strict) {
|
|
140
|
+
recursive(this._model.getHierarchy().children, 1);
|
|
141
|
+
}
|
|
142
|
+
if (this.getParameters().expose) {
|
|
143
|
+
this.log("WARN", "Exposing a store is not recommended, use a DomainService instead to expose all your CoreModel");
|
|
144
|
+
}
|
|
131
145
|
}
|
|
132
146
|
logSlowQuery(_query, _reason, _time) {
|
|
133
147
|
// TODO Need to implement: https://github.com/loopingz/webda.io/issues/202
|
|
@@ -146,7 +160,10 @@ class Store extends Service {
|
|
|
146
160
|
name: "store_slow_queries",
|
|
147
161
|
help: "Number of slow queries encountered"
|
|
148
162
|
});
|
|
149
|
-
this.metrics.queries = this.getMetric(Histogram, {
|
|
163
|
+
this.metrics.queries = this.getMetric(Histogram, {
|
|
164
|
+
name: "store_queries",
|
|
165
|
+
help: "Query duration"
|
|
166
|
+
});
|
|
150
167
|
}
|
|
151
168
|
/**
|
|
152
169
|
* Return Store current model
|
|
@@ -155,9 +172,6 @@ class Store extends Service {
|
|
|
155
172
|
getModel() {
|
|
156
173
|
return this._model;
|
|
157
174
|
}
|
|
158
|
-
getLastUpdateField() {
|
|
159
|
-
return this._model.getLastUpdateField();
|
|
160
|
-
}
|
|
161
175
|
/**
|
|
162
176
|
* Return if a model is handled by the store
|
|
163
177
|
* @param model
|
|
@@ -165,29 +179,8 @@ class Store extends Service {
|
|
|
165
179
|
*
|
|
166
180
|
*/
|
|
167
181
|
handleModel(model) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
let inst = model.__class ? model : new model();
|
|
171
|
-
this._models
|
|
172
|
-
.filter(m => inst instanceof m)
|
|
173
|
-
.forEach(m => {
|
|
174
|
-
let next = model instanceof CoreModel ? model.__class : model;
|
|
175
|
-
let depth = 0;
|
|
176
|
-
while (next && next.name !== "") {
|
|
177
|
-
if (next === m) {
|
|
178
|
-
finalDepth = finalDepth !== undefined ? Math.min(depth, finalDepth) : depth;
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
// If Store strictly managed one Model
|
|
182
|
-
if (this.parameters.strict) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
depth++;
|
|
186
|
-
next = Object.getPrototypeOf(next);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
finalDepth ?? (finalDepth = -1);
|
|
190
|
-
return finalDepth;
|
|
182
|
+
const name = this.getWebda().getApplication().getModelName(model);
|
|
183
|
+
return this._modelsHierarchy[name] ?? -1;
|
|
191
184
|
}
|
|
192
185
|
/**
|
|
193
186
|
* Get From Cache or main
|
|
@@ -214,22 +207,6 @@ class Store extends Service {
|
|
|
214
207
|
this.metrics.operations_total.inc({ operation: "get" });
|
|
215
208
|
return this._getFromCache(uid);
|
|
216
209
|
}
|
|
217
|
-
/**
|
|
218
|
-
* Get the full url with the nested parent
|
|
219
|
-
* @param url
|
|
220
|
-
* @param methods
|
|
221
|
-
* @param depth
|
|
222
|
-
*/
|
|
223
|
-
getParentUrl(depth = 0) {
|
|
224
|
-
if (!this.parameters.expose) {
|
|
225
|
-
throw new Error(`Parent store need to be exposed ${this.getName()}`);
|
|
226
|
-
}
|
|
227
|
-
let res = `${this.parameters.url}/{P${depth}uuid}`;
|
|
228
|
-
if (this.parent) {
|
|
229
|
-
res = this.parent.getParentUrl(depth + 1) + res;
|
|
230
|
-
}
|
|
231
|
-
return res;
|
|
232
|
-
}
|
|
233
210
|
/**
|
|
234
211
|
* @override
|
|
235
212
|
*/
|
|
@@ -250,8 +227,7 @@ class Store extends Service {
|
|
|
250
227
|
(url === "." && methods.includes("PUT") && expose.restrict.query)) {
|
|
251
228
|
return undefined;
|
|
252
229
|
}
|
|
253
|
-
|
|
254
|
-
return parentUrl + super.getUrl(url, methods);
|
|
230
|
+
return super.getUrl(url, methods);
|
|
255
231
|
}
|
|
256
232
|
/**
|
|
257
233
|
* @inheritdoc
|
|
@@ -290,7 +266,7 @@ class Store extends Service {
|
|
|
290
266
|
requestBody,
|
|
291
267
|
responses: {
|
|
292
268
|
"200": {
|
|
293
|
-
description:
|
|
269
|
+
description: `Retrieve models ${this._model.name}`,
|
|
294
270
|
content: {
|
|
295
271
|
"application/json": {
|
|
296
272
|
schema: {
|
|
@@ -331,7 +307,6 @@ class Store extends Service {
|
|
|
331
307
|
if (action.global) {
|
|
332
308
|
// By default will grab the object and then call the action
|
|
333
309
|
if (!this._model[name] && !this._model["_" + name]) {
|
|
334
|
-
console.log(this._model);
|
|
335
310
|
throw Error("Action static method /_?" + name + "/ does not exist");
|
|
336
311
|
}
|
|
337
312
|
executer = this.httpGlobalAction;
|
|
@@ -378,7 +353,7 @@ class Store extends Service {
|
|
|
378
353
|
"_patch",
|
|
379
354
|
"_update",
|
|
380
355
|
"_delete",
|
|
381
|
-
"
|
|
356
|
+
"_incrementAttributes",
|
|
382
357
|
"_upsertItemToCollection",
|
|
383
358
|
"_deleteItemFromCollection",
|
|
384
359
|
"_removeAttribute"
|
|
@@ -397,7 +372,7 @@ class Store extends Service {
|
|
|
397
372
|
initModel(object = {}) {
|
|
398
373
|
var _a;
|
|
399
374
|
if (object instanceof CoreModel) {
|
|
400
|
-
object.__type = this.getWebda().getApplication().getModelFromInstance(object);
|
|
375
|
+
object.__type ?? (object.__type = this.getWebda().getApplication().getModelFromInstance(object) || this._modelType);
|
|
401
376
|
}
|
|
402
377
|
else {
|
|
403
378
|
object.__type ?? (object.__type = this._modelType);
|
|
@@ -407,7 +382,9 @@ class Store extends Service {
|
|
|
407
382
|
// Dynamic load type
|
|
408
383
|
if (object.__type && !this.getParameters().forceModel) {
|
|
409
384
|
try {
|
|
410
|
-
const modelType = this.getWebda()
|
|
385
|
+
const modelType = this.getWebda()
|
|
386
|
+
.getApplication()
|
|
387
|
+
.getModel(this.parameters.modelAliases[object.__type] || object.__type);
|
|
411
388
|
object = new modelType().load(object, true);
|
|
412
389
|
}
|
|
413
390
|
catch (err) {
|
|
@@ -428,6 +405,9 @@ class Store extends Service {
|
|
|
428
405
|
for (let i in this._reverseMap) {
|
|
429
406
|
object[_a = this._reverseMap[i].property] ?? (object[_a] = []);
|
|
430
407
|
for (let j in object[this._reverseMap[i].property]) {
|
|
408
|
+
if (object[this._reverseMap[i].property][j] instanceof ModelMapLoaderImplementation) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
431
411
|
// Use Partial
|
|
432
412
|
object[this._reverseMap[i].property][j] = this._reverseMap[i].mapper.newModel(object[this._reverseMap[i].property][j]);
|
|
433
413
|
object[this._reverseMap[i].property][j].setContext(object.getContext());
|
|
@@ -458,27 +438,52 @@ class Store extends Service {
|
|
|
458
438
|
mapper: store
|
|
459
439
|
});
|
|
460
440
|
}
|
|
461
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Increment attributes of an object
|
|
443
|
+
*
|
|
444
|
+
* @param uid
|
|
445
|
+
* @param info
|
|
446
|
+
* @returns
|
|
447
|
+
*/
|
|
448
|
+
async incrementAttributes(uid, info) {
|
|
449
|
+
let params = info.filter(i => i.value !== 0);
|
|
462
450
|
// If value === 0 no need to update anything
|
|
463
|
-
if (
|
|
464
|
-
return
|
|
451
|
+
if (params.length === 0) {
|
|
452
|
+
return;
|
|
465
453
|
}
|
|
466
454
|
let updateDate = new Date();
|
|
467
455
|
this.metrics.operations_total.inc({ operation: "increment" });
|
|
468
|
-
await this.
|
|
469
|
-
await this._cacheStore?.
|
|
456
|
+
await this._incrementAttributes(uid, params, updateDate);
|
|
457
|
+
await this._cacheStore?._incrementAttributes(uid, params, updateDate);
|
|
470
458
|
return this.emitSync("Store.PartialUpdated", {
|
|
471
459
|
object_id: uid,
|
|
472
460
|
store: this,
|
|
473
461
|
updateDate,
|
|
474
462
|
partial_update: {
|
|
475
|
-
|
|
476
|
-
value: value,
|
|
477
|
-
property: prop
|
|
478
|
-
}
|
|
463
|
+
increments: params
|
|
479
464
|
}
|
|
480
465
|
});
|
|
481
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* Helper function that call incrementAttributes
|
|
469
|
+
* @param uid
|
|
470
|
+
* @param prop
|
|
471
|
+
* @param value
|
|
472
|
+
* @returns
|
|
473
|
+
*/
|
|
474
|
+
async incrementAttribute(uid, prop, value) {
|
|
475
|
+
return this.incrementAttributes(uid, [{ property: prop, value }]);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Add or update an item to an array in the model
|
|
479
|
+
*
|
|
480
|
+
* @param uid of the model
|
|
481
|
+
* @param prop of the model to add in
|
|
482
|
+
* @param item to add in the array
|
|
483
|
+
* @param index if specified update item in this index
|
|
484
|
+
* @param itemWriteCondition value of the condition to test (in case of update)
|
|
485
|
+
* @param itemWriteConditionField field to read the condition from (in case of update)
|
|
486
|
+
*/
|
|
482
487
|
async upsertItemToCollection(uid, prop, item, index = undefined, itemWriteCondition = undefined, itemWriteConditionField = this._uuidField) {
|
|
483
488
|
let updateDate = new Date();
|
|
484
489
|
this.metrics.operations_total.inc({ operation: "collectionUpsert" });
|
|
@@ -497,6 +502,15 @@ class Store extends Service {
|
|
|
497
502
|
}
|
|
498
503
|
});
|
|
499
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Remove an item from an array in the model
|
|
507
|
+
*
|
|
508
|
+
* @param uid of the model
|
|
509
|
+
* @param prop of the model to remove from
|
|
510
|
+
* @param index of the item to remove in the array
|
|
511
|
+
* @param itemWriteCondition value of the condition
|
|
512
|
+
* @param itemWriteConditionField field to read the condition from
|
|
513
|
+
*/
|
|
500
514
|
async deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField = this._uuidField) {
|
|
501
515
|
let updateDate = new Date();
|
|
502
516
|
this.metrics.operations_total.inc({ operation: "collectionDelete" });
|
|
@@ -536,6 +550,14 @@ class Store extends Service {
|
|
|
536
550
|
} while (continuationToken);
|
|
537
551
|
return res;
|
|
538
552
|
}
|
|
553
|
+
/**
|
|
554
|
+
* Check that __type Comparison is only used with = and CONTAINS
|
|
555
|
+
* If CONTAINS is used, move __type to __types
|
|
556
|
+
* If __type = store._model, remove it
|
|
557
|
+
*/
|
|
558
|
+
queryTypeUpdater(query) {
|
|
559
|
+
return query;
|
|
560
|
+
}
|
|
539
561
|
/**
|
|
540
562
|
* Query store with WebdaQL
|
|
541
563
|
* @param query
|
|
@@ -560,7 +582,9 @@ class Store extends Service {
|
|
|
560
582
|
let queryValidator = new WebdaQL.QueryValidator(fullQuery);
|
|
561
583
|
let offset = queryValidator.getOffset();
|
|
562
584
|
const limit = queryValidator.getLimit();
|
|
563
|
-
const parsedQuery = queryValidator.getQuery();
|
|
585
|
+
const parsedQuery = this.queryTypeUpdater(queryValidator.getQuery());
|
|
586
|
+
parsedQuery.limit = limit;
|
|
587
|
+
// __type is a special field to filter on the type of the object
|
|
564
588
|
// Emit the default event
|
|
565
589
|
await this.emitSync("Store.Query", {
|
|
566
590
|
query,
|
|
@@ -587,7 +611,10 @@ class Store extends Service {
|
|
|
587
611
|
let duration = Date.now();
|
|
588
612
|
this.metrics.operations_total.inc({ operation: "query" });
|
|
589
613
|
while (result.results.length < limit) {
|
|
590
|
-
let tmpResults = await this.find({
|
|
614
|
+
let tmpResults = await this.find({
|
|
615
|
+
...parsedQuery,
|
|
616
|
+
continuationToken: mainOffset
|
|
617
|
+
});
|
|
591
618
|
// If no filter is returned assume it is by mistake and apply filtering
|
|
592
619
|
if (tmpResults.filter === undefined) {
|
|
593
620
|
tmpResults.filter = queryValidator.getExpression();
|
|
@@ -595,6 +622,7 @@ class Store extends Service {
|
|
|
595
622
|
}
|
|
596
623
|
let subOffsetCount = 0;
|
|
597
624
|
for (let item of tmpResults.results) {
|
|
625
|
+
item.setContext(context);
|
|
598
626
|
// Because of dynamic filter and permission we need to suboffset the pagination
|
|
599
627
|
subOffsetCount++;
|
|
600
628
|
if (subOffsetCount <= secondOffset) {
|
|
@@ -603,13 +631,8 @@ class Store extends Service {
|
|
|
603
631
|
if (tmpResults.filter !== true && !tmpResults.filter.eval(item)) {
|
|
604
632
|
continue;
|
|
605
633
|
}
|
|
606
|
-
if (context && partialPermission) {
|
|
607
|
-
|
|
608
|
-
await item.canAct(context, "get");
|
|
609
|
-
}
|
|
610
|
-
catch (err) {
|
|
611
|
-
continue;
|
|
612
|
-
}
|
|
634
|
+
if (context && partialPermission && (await item.canAct(context, "get")) !== true) {
|
|
635
|
+
continue;
|
|
613
636
|
}
|
|
614
637
|
result.results.push(item);
|
|
615
638
|
if (result.results.length >= limit) {
|
|
@@ -663,7 +686,7 @@ class Store extends Service {
|
|
|
663
686
|
catch (err) {
|
|
664
687
|
if (err instanceof SyntaxError) {
|
|
665
688
|
this.log("INFO", "Query syntax error");
|
|
666
|
-
throw
|
|
689
|
+
throw new WebdaError.BadRequest("Query syntax error");
|
|
667
690
|
}
|
|
668
691
|
throw err;
|
|
669
692
|
}
|
|
@@ -678,9 +701,7 @@ class Store extends Service {
|
|
|
678
701
|
* Might want to rename to create
|
|
679
702
|
*/
|
|
680
703
|
async save(object, ctx = undefined) {
|
|
681
|
-
if (object instanceof this._model &&
|
|
682
|
-
object[this._creationDateField] !== undefined &&
|
|
683
|
-
object[this._lastUpdateField] !== undefined) {
|
|
704
|
+
if (object instanceof this._model && object._creationDate !== undefined && object._lastUpdate !== undefined) {
|
|
684
705
|
if (ctx) {
|
|
685
706
|
object.setContext(ctx);
|
|
686
707
|
}
|
|
@@ -688,12 +709,19 @@ class Store extends Service {
|
|
|
688
709
|
}
|
|
689
710
|
return this.create(object, ctx);
|
|
690
711
|
}
|
|
712
|
+
/**
|
|
713
|
+
*
|
|
714
|
+
* @param object
|
|
715
|
+
* @param ctx
|
|
716
|
+
* @returns
|
|
717
|
+
*/
|
|
691
718
|
async create(object, ctx = undefined) {
|
|
692
|
-
var _a;
|
|
693
719
|
object = this.initModel(object);
|
|
694
720
|
// Dates should be store by the Store
|
|
695
|
-
object
|
|
696
|
-
object
|
|
721
|
+
object._creationDate ?? (object._creationDate = new Date());
|
|
722
|
+
object._lastUpdate = new Date();
|
|
723
|
+
const ancestors = this.getWebda().getApplication().getModelHierarchy(object.__type).ancestors;
|
|
724
|
+
object.__types = [object.__type, ...ancestors].filter(i => i !== "Webda/CoreModel" && i !== "CoreModel");
|
|
697
725
|
if (ctx) {
|
|
698
726
|
object.setContext(ctx);
|
|
699
727
|
}
|
|
@@ -806,7 +834,7 @@ class Store extends Service {
|
|
|
806
834
|
else {
|
|
807
835
|
model[prop][index] = item;
|
|
808
836
|
}
|
|
809
|
-
model
|
|
837
|
+
model._lastUpdate = updateDate;
|
|
810
838
|
await this._save(model);
|
|
811
839
|
}
|
|
812
840
|
/**
|
|
@@ -833,7 +861,7 @@ class Store extends Service {
|
|
|
833
861
|
if (Object.keys(object).length < 2) {
|
|
834
862
|
return undefined;
|
|
835
863
|
}
|
|
836
|
-
object
|
|
864
|
+
object._lastUpdate = new Date();
|
|
837
865
|
this.metrics.operations_total.inc({ operation: "get" });
|
|
838
866
|
let load = await this._getFromCache(object[this._uuidField], true);
|
|
839
867
|
if (load.__type !== this._modelType && this.parameters.strict) {
|
|
@@ -861,13 +889,13 @@ class Store extends Service {
|
|
|
861
889
|
await loaded._onUpdate(object);
|
|
862
890
|
let res;
|
|
863
891
|
if (conditionField !== null) {
|
|
864
|
-
conditionField ?? (conditionField =
|
|
892
|
+
conditionField ?? (conditionField = "_lastUpdate");
|
|
865
893
|
conditionValue ?? (conditionValue = load[conditionField]);
|
|
866
894
|
}
|
|
867
895
|
if (partial) {
|
|
868
896
|
this.metrics.operations_total.inc({ operation: "partialUpdate" });
|
|
869
897
|
await this._patch(object, object[this._uuidField], conditionValue, conditionField);
|
|
870
|
-
await this._cacheStore?._patch(object, object[this._uuidField], load
|
|
898
|
+
await this._cacheStore?._patch(object, object[this._uuidField], load._lastUpdate, "_lastUpdate");
|
|
871
899
|
res = object;
|
|
872
900
|
}
|
|
873
901
|
else {
|
|
@@ -878,7 +906,7 @@ class Store extends Service {
|
|
|
878
906
|
object = this.initModel(object);
|
|
879
907
|
this.metrics.operations_total.inc({ operation: "update" });
|
|
880
908
|
res = await this._update(object, object[this._uuidField], conditionValue, conditionField);
|
|
881
|
-
await this._cacheStore?._update(object, object[this._uuidField], load
|
|
909
|
+
await this._cacheStore?._update(object, object[this._uuidField], load._lastUpdate, "_lastUpdate");
|
|
882
910
|
}
|
|
883
911
|
// Return updated
|
|
884
912
|
for (let i in res) {
|
|
@@ -903,6 +931,138 @@ class Store extends Service {
|
|
|
903
931
|
await saved._onUpdated();
|
|
904
932
|
return saved;
|
|
905
933
|
}
|
|
934
|
+
/**
|
|
935
|
+
* Manage the store migration for __type case sensitivity
|
|
936
|
+
*/
|
|
937
|
+
async v3Migration() {
|
|
938
|
+
// Compute case for all object
|
|
939
|
+
await this.recomputeTypeCase();
|
|
940
|
+
// Compute all __types
|
|
941
|
+
await this.recomputeTypes();
|
|
942
|
+
// We do not move to short id as it is not compatible with v2
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
*
|
|
946
|
+
*/
|
|
947
|
+
async recomputeTypeShortId() {
|
|
948
|
+
this.log("INFO", "Ensuring __type is using its short id form");
|
|
949
|
+
const app = this.getWebda().getApplication();
|
|
950
|
+
// We need to be laxist for migration
|
|
951
|
+
this.parameters.strict = false;
|
|
952
|
+
await this.migration("typesShortId", async (item) => {
|
|
953
|
+
if (item.__type !== undefined && item.__type.includes("/")) {
|
|
954
|
+
const model = app.getWebdaObject("models", item.__type);
|
|
955
|
+
const name = app.getShortId(app.getModelName(model));
|
|
956
|
+
if (name !== item.__type) {
|
|
957
|
+
this.log("INFO", "Migrating type " + item.__type + " to " + name);
|
|
958
|
+
return {
|
|
959
|
+
__type: name
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Ensure model aliases are not used in this store
|
|
967
|
+
*
|
|
968
|
+
* So alias can be cleaned
|
|
969
|
+
*/
|
|
970
|
+
async cleanModelAliases() {
|
|
971
|
+
this.log("INFO", "Ensuring __type is not using any aliases");
|
|
972
|
+
// We need to be laxist for migration
|
|
973
|
+
this.parameters.strict = false;
|
|
974
|
+
await this.migration("cleanAliases", async (item) => {
|
|
975
|
+
if (this.parameters.modelAliases[item.__type]) {
|
|
976
|
+
this.log("INFO", "Migrating type " + item.__type + " to " + this.parameters.modelAliases[item.__type]);
|
|
977
|
+
return {
|
|
978
|
+
__type: this.parameters.modelAliases[item.__type]
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Recompute type case
|
|
985
|
+
*/
|
|
986
|
+
async recomputeTypeCase() {
|
|
987
|
+
this.log("INFO", "Ensuring __type is case sensitive from migration from v2.x");
|
|
988
|
+
const app = this.getWebda().getApplication();
|
|
989
|
+
// We need to be laxist for migration
|
|
990
|
+
this.parameters.strict = false;
|
|
991
|
+
await this.migration("typesCase", async (item) => {
|
|
992
|
+
if (item.__type !== undefined) {
|
|
993
|
+
if (!app.hasWebdaObject("models", item.__type, true) && app.hasWebdaObject("models", item.__type, false)) {
|
|
994
|
+
const model = app.getWebdaObject("models", item.__type, false);
|
|
995
|
+
const name = app.getModelName(model);
|
|
996
|
+
if (model) {
|
|
997
|
+
this.log("INFO", "Migrating type " + item.__type + " to " + name);
|
|
998
|
+
return {
|
|
999
|
+
__type: name
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Recompute the __types for all objects (storeMigration.Registry.typesCompute)
|
|
1008
|
+
*/
|
|
1009
|
+
async recomputeTypes() {
|
|
1010
|
+
this.log("INFO", "Ensuring __types is correct from migration from v2.x");
|
|
1011
|
+
// Update __types for each __type will be more efficient
|
|
1012
|
+
await this.migration("typesCompute", async (item) => {
|
|
1013
|
+
let __types = this.getWebda().getApplication().getModelTypes(item);
|
|
1014
|
+
if (!item.__types ||
|
|
1015
|
+
item.__types.length !== __types.length ||
|
|
1016
|
+
!__types.every((element, index) => element === item.__types[index])) {
|
|
1017
|
+
this.log("INFO", "Migrating types " + JSON.stringify(item.__types) + " to " + JSON.stringify(__types), "for", item.__type, item.getUuid());
|
|
1018
|
+
return {
|
|
1019
|
+
__types
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Delete a migration
|
|
1026
|
+
* @param name
|
|
1027
|
+
*/
|
|
1028
|
+
async cancelMigration(name) {
|
|
1029
|
+
await this.getWebda().getRegistry().delete(`storeMigration.${this.getName()}.${name}`);
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Get a migration
|
|
1033
|
+
* @param name
|
|
1034
|
+
*/
|
|
1035
|
+
async getMigration(name) {
|
|
1036
|
+
return await this.getWebda().getRegistry().get(`storeMigration.${this.getName()}.${name}`);
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Add a migration mechanism to store
|
|
1040
|
+
* @param name
|
|
1041
|
+
* @param patcher
|
|
1042
|
+
*/
|
|
1043
|
+
async migration(name, patcher, batchSize = 500) {
|
|
1044
|
+
let status = await this.getWebda().getRegistry().get(`storeMigration.${this.getName()}.${name}`, undefined, {});
|
|
1045
|
+
status.count ?? (status.count = 0);
|
|
1046
|
+
status.updated ?? (status.updated = 0);
|
|
1047
|
+
const worker = new Throttler(20);
|
|
1048
|
+
do {
|
|
1049
|
+
const res = await this.query(status.continuationToken ? `LIMIT ${batchSize} OFFSET "${status.continuationToken}"` : `LIMIT ${batchSize}`);
|
|
1050
|
+
status.count += res.results.length;
|
|
1051
|
+
for (let item of res.results) {
|
|
1052
|
+
let updated = await patcher(item);
|
|
1053
|
+
if (updated !== undefined) {
|
|
1054
|
+
status.updated++;
|
|
1055
|
+
worker.queue(async () => {
|
|
1056
|
+
await item.patch(updated, null);
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
this.log("INFO", `storeMigration.${this.getName()}.${name}: Migrated ${status.count} items: ${status.updated} updated`);
|
|
1061
|
+
status.continuationToken = res.continuationToken;
|
|
1062
|
+
await worker.waitForCompletion();
|
|
1063
|
+
await status.save();
|
|
1064
|
+
} while (status.continuationToken);
|
|
1065
|
+
}
|
|
906
1066
|
/**
|
|
907
1067
|
* Remove an attribute from an object
|
|
908
1068
|
*
|
|
@@ -918,7 +1078,8 @@ class Store extends Service {
|
|
|
918
1078
|
object_id: uuid,
|
|
919
1079
|
partial_update: {
|
|
920
1080
|
deleteAttribute: attribute
|
|
921
|
-
}
|
|
1081
|
+
},
|
|
1082
|
+
store: this
|
|
922
1083
|
});
|
|
923
1084
|
}
|
|
924
1085
|
/**
|
|
@@ -1023,7 +1184,7 @@ class Store extends Service {
|
|
|
1023
1184
|
}
|
|
1024
1185
|
let result = {};
|
|
1025
1186
|
for (let i in object) {
|
|
1026
|
-
if (i === this._uuidField || i ===
|
|
1187
|
+
if (i === this._uuidField || i === "_lastUpdate" || i.startsWith("_")) {
|
|
1027
1188
|
continue;
|
|
1028
1189
|
}
|
|
1029
1190
|
result[i] = object[i];
|
|
@@ -1039,7 +1200,7 @@ class Store extends Service {
|
|
|
1039
1200
|
if (await this.exists(uuid)) {
|
|
1040
1201
|
return this.update({ ...data, uuid });
|
|
1041
1202
|
}
|
|
1042
|
-
return this.save({ ...data, uuid });
|
|
1203
|
+
return this.save(data instanceof CoreModel ? data.setUuid(uuid) : { ...data, uuid });
|
|
1043
1204
|
}
|
|
1044
1205
|
/**
|
|
1045
1206
|
* Get an object
|
|
@@ -1157,19 +1318,28 @@ class Store extends Service {
|
|
|
1157
1318
|
* @param ctx
|
|
1158
1319
|
*/
|
|
1159
1320
|
async httpCreate(ctx) {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1321
|
+
return this.operationCreate(ctx, this.parameters.model);
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Create a new object based on the context
|
|
1325
|
+
* @param ctx
|
|
1326
|
+
* @param model
|
|
1327
|
+
*/
|
|
1328
|
+
async operationCreate(ctx, model) {
|
|
1329
|
+
let body = await ctx.getInput();
|
|
1330
|
+
const modelPrototype = this.getWebda().getApplication().getModel(model);
|
|
1331
|
+
let object = modelPrototype.factory(modelPrototype, body, ctx);
|
|
1332
|
+
object._creationDate = new Date();
|
|
1333
|
+
await object.checkAct(ctx, "create");
|
|
1164
1334
|
try {
|
|
1165
1335
|
await object.validate(ctx, body);
|
|
1166
1336
|
}
|
|
1167
1337
|
catch (err) {
|
|
1168
1338
|
this.log("INFO", "Object is not valid", err);
|
|
1169
|
-
throw
|
|
1339
|
+
throw new WebdaError.BadRequest("Object is not valid");
|
|
1170
1340
|
}
|
|
1171
1341
|
if (object[this._uuidField] && (await this.exists(object[this._uuidField]))) {
|
|
1172
|
-
throw
|
|
1342
|
+
throw new WebdaError.Conflict("Object already exists");
|
|
1173
1343
|
}
|
|
1174
1344
|
await this.save(object, ctx);
|
|
1175
1345
|
ctx.write(object);
|
|
@@ -1188,22 +1358,16 @@ class Store extends Service {
|
|
|
1188
1358
|
let action = ctx.getHttpContext().getUrl().split("/").pop();
|
|
1189
1359
|
let object = await this.get(ctx.parameter("uuid"), ctx);
|
|
1190
1360
|
if (object === undefined || object.__deleted) {
|
|
1191
|
-
throw
|
|
1361
|
+
throw new WebdaError.NotFound("Object not found or is deleted");
|
|
1192
1362
|
}
|
|
1193
|
-
await object.
|
|
1363
|
+
await object.checkAct(ctx, action);
|
|
1194
1364
|
await this.emitSync("Store.Action", {
|
|
1195
1365
|
action: action,
|
|
1196
1366
|
object: object,
|
|
1197
1367
|
store: this,
|
|
1198
1368
|
context: ctx
|
|
1199
1369
|
});
|
|
1200
|
-
|
|
1201
|
-
if (object["_" + action]) {
|
|
1202
|
-
res = await object["_" + action](ctx);
|
|
1203
|
-
}
|
|
1204
|
-
else {
|
|
1205
|
-
res = await object[action](ctx);
|
|
1206
|
-
}
|
|
1370
|
+
const res = await object[action](ctx);
|
|
1207
1371
|
if (res) {
|
|
1208
1372
|
ctx.write(res);
|
|
1209
1373
|
}
|
|
@@ -1219,20 +1383,15 @@ class Store extends Service {
|
|
|
1219
1383
|
* Handle collection action
|
|
1220
1384
|
* @param ctx
|
|
1221
1385
|
*/
|
|
1222
|
-
async httpGlobalAction(ctx) {
|
|
1386
|
+
async httpGlobalAction(ctx, model = this._model) {
|
|
1223
1387
|
let action = ctx.getHttpContext().getUrl().split("/").pop();
|
|
1224
1388
|
await this.emitSync("Store.Action", {
|
|
1225
1389
|
action: action,
|
|
1226
1390
|
store: this,
|
|
1227
|
-
context: ctx
|
|
1391
|
+
context: ctx,
|
|
1392
|
+
model
|
|
1228
1393
|
});
|
|
1229
|
-
|
|
1230
|
-
if (this._model["_" + action]) {
|
|
1231
|
-
res = await this._model["_" + action](ctx);
|
|
1232
|
-
}
|
|
1233
|
-
else {
|
|
1234
|
-
res = await this._model[action](ctx);
|
|
1235
|
-
}
|
|
1394
|
+
const res = await model[action](ctx);
|
|
1236
1395
|
if (res) {
|
|
1237
1396
|
ctx.write(res);
|
|
1238
1397
|
}
|
|
@@ -1240,7 +1399,8 @@ class Store extends Service {
|
|
|
1240
1399
|
action: action,
|
|
1241
1400
|
store: this,
|
|
1242
1401
|
context: ctx,
|
|
1243
|
-
result: res
|
|
1402
|
+
result: res,
|
|
1403
|
+
model
|
|
1244
1404
|
});
|
|
1245
1405
|
}
|
|
1246
1406
|
/**
|
|
@@ -1249,20 +1409,20 @@ class Store extends Service {
|
|
|
1249
1409
|
* @param ctx context of the request
|
|
1250
1410
|
*/
|
|
1251
1411
|
async httpUpdate(ctx) {
|
|
1252
|
-
|
|
1253
|
-
|
|
1412
|
+
const { uuid } = ctx.getParameters();
|
|
1413
|
+
const body = await ctx.getInput();
|
|
1254
1414
|
body[this._uuidField] = uuid;
|
|
1255
1415
|
let object = await this.get(uuid, ctx);
|
|
1256
1416
|
if (!object || object.__deleted)
|
|
1257
|
-
throw
|
|
1258
|
-
await object.
|
|
1417
|
+
throw new WebdaError.NotFound("Object not found or is deleted");
|
|
1418
|
+
await object.checkAct(ctx, "update");
|
|
1259
1419
|
if (ctx.getHttpContext().getMethod() === "PATCH") {
|
|
1260
1420
|
try {
|
|
1261
1421
|
await object.validate(ctx, body, true);
|
|
1262
1422
|
}
|
|
1263
1423
|
catch (err) {
|
|
1264
1424
|
this.log("INFO", "Object invalid", err, object);
|
|
1265
|
-
throw
|
|
1425
|
+
throw new WebdaError.BadRequest("Object is not valid");
|
|
1266
1426
|
}
|
|
1267
1427
|
let updateObject = new this._model();
|
|
1268
1428
|
// Clean any default attributes from the model
|
|
@@ -1291,7 +1451,7 @@ class Store extends Service {
|
|
|
1291
1451
|
}
|
|
1292
1452
|
catch (err) {
|
|
1293
1453
|
this.log("INFO", "Object invalid", err);
|
|
1294
|
-
throw
|
|
1454
|
+
throw new WebdaError.BadRequest("Object is not valid");
|
|
1295
1455
|
}
|
|
1296
1456
|
// Add mappers back to
|
|
1297
1457
|
object = await this.update(updateObject);
|
|
@@ -1319,9 +1479,9 @@ class Store extends Service {
|
|
|
1319
1479
|
store: this
|
|
1320
1480
|
});
|
|
1321
1481
|
if (object === undefined || object.__deleted) {
|
|
1322
|
-
throw
|
|
1482
|
+
throw new WebdaError.NotFound("Object not found or is deleted");
|
|
1323
1483
|
}
|
|
1324
|
-
await object.
|
|
1484
|
+
await object.checkAct(ctx, "get");
|
|
1325
1485
|
ctx.write(object);
|
|
1326
1486
|
await this.emitSync("Store.WebGet", {
|
|
1327
1487
|
context: ctx,
|
|
@@ -1336,16 +1496,16 @@ class Store extends Service {
|
|
|
1336
1496
|
* @param ctx context of the request
|
|
1337
1497
|
* @returns
|
|
1338
1498
|
*/
|
|
1339
|
-
async
|
|
1499
|
+
async httpDelete(ctx) {
|
|
1340
1500
|
let uuid = ctx.parameter("uuid");
|
|
1341
1501
|
let object = await this.get(uuid, ctx);
|
|
1342
1502
|
if (!object || object.__deleted)
|
|
1343
|
-
throw
|
|
1344
|
-
await object.
|
|
1503
|
+
throw new WebdaError.NotFound("Object not found or is deleted");
|
|
1504
|
+
await object.checkAct(ctx, "delete");
|
|
1345
1505
|
// http://stackoverflow.com/questions/28684209/huge-delay-on-delete-requests-with-204-response-and-no-content-in-objectve-c#
|
|
1346
1506
|
// IOS don't handle 204 with Content-Length != 0 it seems
|
|
1347
|
-
// Have trouble to handle the Content-Length on API Gateway so returning an empty object for now
|
|
1348
|
-
ctx.
|
|
1507
|
+
// Might still run into: Have trouble to handle the Content-Length on API Gateway so returning an empty object for now
|
|
1508
|
+
ctx.writeHead(204, { "Content-Length": "0" });
|
|
1349
1509
|
await this.delete(uuid);
|
|
1350
1510
|
await this.emitSync("Store.WebDelete", {
|
|
1351
1511
|
context: ctx,
|
|
@@ -1359,9 +1519,20 @@ class Store extends Service {
|
|
|
1359
1519
|
getUuidField() {
|
|
1360
1520
|
return this._uuidField;
|
|
1361
1521
|
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Check if an object exists
|
|
1524
|
+
* @abstract
|
|
1525
|
+
* @params {String} uuid of the object or the object
|
|
1526
|
+
*/
|
|
1527
|
+
async exists(uid) {
|
|
1528
|
+
if (typeof uid !== "string") {
|
|
1529
|
+
uid = uid.getUuid();
|
|
1530
|
+
}
|
|
1531
|
+
return this._exists(uid);
|
|
1532
|
+
}
|
|
1362
1533
|
}
|
|
1363
1534
|
__decorate([
|
|
1364
|
-
Route(".", ["POST"],
|
|
1535
|
+
Route(".", ["POST"], {
|
|
1365
1536
|
post: {
|
|
1366
1537
|
description: "The way to create a new ${modelName} model",
|
|
1367
1538
|
summary: "Create a new ${modelName}",
|
|
@@ -1400,7 +1571,7 @@ __decorate([
|
|
|
1400
1571
|
})
|
|
1401
1572
|
], Store.prototype, "httpCreate", null);
|
|
1402
1573
|
__decorate([
|
|
1403
|
-
Route("./{uuid}", ["PUT", "PATCH"],
|
|
1574
|
+
Route("./{uuid}", ["PUT", "PATCH"], {
|
|
1404
1575
|
put: {
|
|
1405
1576
|
description: "Update a ${modelName} if the permissions allow",
|
|
1406
1577
|
summary: "Update a ${modelName}",
|
|
@@ -1447,7 +1618,7 @@ __decorate([
|
|
|
1447
1618
|
})
|
|
1448
1619
|
], Store.prototype, "httpUpdate", null);
|
|
1449
1620
|
__decorate([
|
|
1450
|
-
Route("./{uuid}", ["GET"],
|
|
1621
|
+
Route("./{uuid}", ["GET"], {
|
|
1451
1622
|
get: {
|
|
1452
1623
|
description: "Retrieve ${modelName} model if permissions allow",
|
|
1453
1624
|
summary: "Retrieve a ${modelName}",
|
|
@@ -1471,7 +1642,7 @@ __decorate([
|
|
|
1471
1642
|
})
|
|
1472
1643
|
], Store.prototype, "httpGet", null);
|
|
1473
1644
|
__decorate([
|
|
1474
|
-
Route("./{uuid}", ["DELETE"],
|
|
1645
|
+
Route("./{uuid}", ["DELETE"], {
|
|
1475
1646
|
delete: {
|
|
1476
1647
|
operationId: "delete${modelName}",
|
|
1477
1648
|
description: "Delete ${modelName} if the permissions allow",
|
|
@@ -1489,6 +1660,6 @@ __decorate([
|
|
|
1489
1660
|
}
|
|
1490
1661
|
}
|
|
1491
1662
|
})
|
|
1492
|
-
], Store.prototype, "
|
|
1663
|
+
], Store.prototype, "httpDelete", null);
|
|
1493
1664
|
export { Store };
|
|
1494
1665
|
//# sourceMappingURL=store.js.map
|