velocious 1.0.577 → 1.0.578
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/README.md +11 -5
- package/build/background-jobs/main.js +2 -2
- package/build/configuration-types.js +1 -0
- package/build/configuration.js +52 -10
- package/build/database/drivers/mysql/structure-sql.js +70 -9
- package/build/database/query/with-count.js +8 -8
- package/build/database/record/record-not-found-error.js +1 -0
- package/build/frontend-model-controller.js +71 -69
- package/build/frontend-models/base.js +10 -1
- package/build/src/background-jobs/main.js +3 -3
- package/build/src/configuration-types.d.ts +5 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +2 -1
- package/build/src/configuration.d.ts +13 -1
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +52 -11
- package/build/src/database/drivers/mysql/structure-sql.d.ts +11 -0
- package/build/src/database/drivers/mysql/structure-sql.d.ts.map +1 -1
- package/build/src/database/drivers/mysql/structure-sql.js +61 -10
- package/build/src/database/query/with-count.js +8 -8
- package/build/src/database/record/record-not-found-error.d.ts +1 -0
- package/build/src/database/record/record-not-found-error.d.ts.map +1 -1
- package/build/src/database/record/record-not-found-error.js +2 -1
- package/build/src/frontend-model-controller.d.ts +10 -10
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +73 -67
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +11 -2
- package/build/src/velocious-error.d.ts +10 -0
- package/build/src/velocious-error.d.ts.map +1 -1
- package/build/src/velocious-error.js +8 -2
- package/build/velocious-error.js +7 -1
- package/package.json +2 -2
- package/src/background-jobs/main.js +2 -2
- package/src/configuration-types.js +1 -0
- package/src/configuration.js +52 -10
- package/src/database/drivers/mysql/structure-sql.js +70 -9
- package/src/database/query/with-count.js +8 -8
- package/src/database/record/record-not-found-error.js +1 -0
- package/src/frontend-model-controller.js +71 -69
- package/src/frontend-models/base.js +10 -1
- package/src/velocious-error.js +7 -1
|
@@ -6,11 +6,15 @@ export default class VelociousError extends Error {
|
|
|
6
6
|
* @param {object} [args] - Options.
|
|
7
7
|
* @param {?} [args.cause] - Error cause.
|
|
8
8
|
* @param {string} [args.code] - Optional error code.
|
|
9
|
+
* @param {import("./configuration-types.js").ClientErrorPayloadReporterPayload} [args.details] - Structured client-safe error details.
|
|
10
|
+
* @param {"application_error" | "authorization_error" | "record_not_found" | "validation_error"} [args.errorType] - Stable client-facing error category.
|
|
9
11
|
* @returns {VelociousError} - Client-safe error instance.
|
|
10
12
|
*/
|
|
11
13
|
static safe(message: string, args?: {
|
|
12
14
|
cause?: unknown;
|
|
13
15
|
code?: string | undefined;
|
|
16
|
+
details?: import("./configuration-types.js").ClientErrorPayloadReporterPayload | undefined;
|
|
17
|
+
errorType?: "application_error" | "authorization_error" | "record_not_found" | "validation_error" | undefined;
|
|
14
18
|
}): VelociousError;
|
|
15
19
|
/**
|
|
16
20
|
* Runs constructor.
|
|
@@ -18,14 +22,20 @@ export default class VelociousError extends Error {
|
|
|
18
22
|
* @param {object} [args] - Options.
|
|
19
23
|
* @param {?} [args.cause] - Error cause.
|
|
20
24
|
* @param {string} [args.code] - Optional error code.
|
|
25
|
+
* @param {import("./configuration-types.js").ClientErrorPayloadReporterPayload} [args.details] - Structured client-safe error details.
|
|
26
|
+
* @param {"application_error" | "authorization_error" | "record_not_found" | "validation_error"} [args.errorType] - Stable client-facing error category.
|
|
21
27
|
* @param {boolean} [args.safeToExpose] - Whether the message is safe to return to clients.
|
|
22
28
|
*/
|
|
23
29
|
constructor(message: string, args?: {
|
|
24
30
|
cause?: unknown;
|
|
25
31
|
code?: string | undefined;
|
|
32
|
+
details?: import("./configuration-types.js").ClientErrorPayloadReporterPayload | undefined;
|
|
33
|
+
errorType?: "application_error" | "authorization_error" | "record_not_found" | "validation_error" | undefined;
|
|
26
34
|
safeToExpose?: boolean | undefined;
|
|
27
35
|
});
|
|
28
36
|
code: string | undefined;
|
|
37
|
+
details: import("./configuration-types.js").ClientErrorPayloadReporterPayload | undefined;
|
|
38
|
+
errorType: "application_error" | "authorization_error" | "record_not_found" | "validation_error" | undefined;
|
|
29
39
|
safeToExpose: boolean;
|
|
30
40
|
}
|
|
31
41
|
//# sourceMappingURL=velocious-error.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"velocious-error.d.ts","sourceRoot":"","sources":["../../src/velocious-error.js"],"names":[],"mappings":"AAEA,uEAAuE;AACvE;
|
|
1
|
+
{"version":3,"file":"velocious-error.d.ts","sourceRoot":"","sources":["../../src/velocious-error.js"],"names":[],"mappings":"AAEA,uEAAuE;AACvE;IAuBE;;;;;;;;;OASG;IACH,qBARW,MAAM,SAEd;QAAiB,KAAK,GAAd,OAAC;QACa,IAAI;QAC0D,OAAO;QACU,SAAS;KAC9G,GAAU,cAAc,CAI1B;IAlCD;;;;;;;;;OASG;IACH,qBARW,MAAM,SAEd;QAAiB,KAAK,GAAd,OAAC;QACa,IAAI;QAC0D,OAAO;QACU,SAAS;QACvF,YAAY;KACrC,EAWA;IAJC,yBAAgB;IAChB,0FAAsB;IACtB,6GAA0B;IAC1B,sBAAgC;CAgBnC"}
|
|
@@ -7,13 +7,17 @@ export default class VelociousError extends Error {
|
|
|
7
7
|
* @param {object} [args] - Options.
|
|
8
8
|
* @param {?} [args.cause] - Error cause.
|
|
9
9
|
* @param {string} [args.code] - Optional error code.
|
|
10
|
+
* @param {import("./configuration-types.js").ClientErrorPayloadReporterPayload} [args.details] - Structured client-safe error details.
|
|
11
|
+
* @param {"application_error" | "authorization_error" | "record_not_found" | "validation_error"} [args.errorType] - Stable client-facing error category.
|
|
10
12
|
* @param {boolean} [args.safeToExpose] - Whether the message is safe to return to clients.
|
|
11
13
|
*/
|
|
12
14
|
constructor(message, args = {}) {
|
|
13
|
-
const { cause, code, safeToExpose = false } = args;
|
|
15
|
+
const { cause, code, details, errorType, safeToExpose = false } = args;
|
|
14
16
|
super(message, { cause });
|
|
15
17
|
this.name = "VelociousError";
|
|
16
18
|
this.code = code;
|
|
19
|
+
this.details = details;
|
|
20
|
+
this.errorType = errorType;
|
|
17
21
|
this.safeToExpose = safeToExpose;
|
|
18
22
|
}
|
|
19
23
|
/**
|
|
@@ -22,10 +26,12 @@ export default class VelociousError extends Error {
|
|
|
22
26
|
* @param {object} [args] - Options.
|
|
23
27
|
* @param {?} [args.cause] - Error cause.
|
|
24
28
|
* @param {string} [args.code] - Optional error code.
|
|
29
|
+
* @param {import("./configuration-types.js").ClientErrorPayloadReporterPayload} [args.details] - Structured client-safe error details.
|
|
30
|
+
* @param {"application_error" | "authorization_error" | "record_not_found" | "validation_error"} [args.errorType] - Stable client-facing error category.
|
|
25
31
|
* @returns {VelociousError} - Client-safe error instance.
|
|
26
32
|
*/
|
|
27
33
|
static safe(message, args = {}) {
|
|
28
34
|
return new VelociousError(message, { ...args, safeToExpose: true });
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVsb2Npb3VzLWVycm9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3ZlbG9jaW91cy1lcnJvci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosdUVBQXVFO0FBQ3ZFLE1BQU0sQ0FBQyxPQUFPLE9BQU8sY0FBZSxTQUFRLEtBQUs7SUFDL0M7Ozs7Ozs7OztPQVNHO0lBQ0gsWUFBWSxPQUFPLEVBQUUsSUFBSSxHQUFHLEVBQUU7UUFDNUIsTUFBTSxFQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEdBQUcsS0FBSyxFQUFDLEdBQUcsSUFBSSxDQUFBO1FBRXBFLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFBQyxLQUFLLEVBQUMsQ0FBQyxDQUFBO1FBRXZCLElBQUksQ0FBQyxJQUFJLEdBQUcsZ0JBQWdCLENBQUE7UUFDNUIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUE7UUFDaEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUE7UUFDdEIsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUE7UUFDMUIsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUE7SUFDbEMsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNILE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksR0FBRyxFQUFFO1FBQzVCLE9BQU8sSUFBSSxjQUFjLENBQUMsT0FBTyxFQUFFLEVBQUMsR0FBRyxJQUFJLEVBQUUsWUFBWSxFQUFFLElBQUksRUFBQyxDQUFDLENBQUE7SUFDbkUsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbi8qKiBGcmFtZXdvcmsgZXJyb3Igd2l0aCBvcHRpb25hbCBjbGllbnQtc2FmZSBtZXNzYWdlIGV4cG9zdXJlIGZsYWcuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWZWxvY2lvdXNFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gRXJyb3IgbWVzc2FnZS5cbiAgICogQHBhcmFtIHtvYmplY3R9IFthcmdzXSAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7P30gW2FyZ3MuY2F1c2VdIC0gRXJyb3IgY2F1c2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5jb2RlXSAtIE9wdGlvbmFsIGVycm9yIGNvZGUuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkNsaWVudEVycm9yUGF5bG9hZFJlcG9ydGVyUGF5bG9hZH0gW2FyZ3MuZGV0YWlsc10gLSBTdHJ1Y3R1cmVkIGNsaWVudC1zYWZlIGVycm9yIGRldGFpbHMuXG4gICAqIEBwYXJhbSB7XCJhcHBsaWNhdGlvbl9lcnJvclwiIHwgXCJhdXRob3JpemF0aW9uX2Vycm9yXCIgfCBcInJlY29yZF9ub3RfZm91bmRcIiB8IFwidmFsaWRhdGlvbl9lcnJvclwifSBbYXJncy5lcnJvclR5cGVdIC0gU3RhYmxlIGNsaWVudC1mYWNpbmcgZXJyb3IgY2F0ZWdvcnkuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2FyZ3Muc2FmZVRvRXhwb3NlXSAtIFdoZXRoZXIgdGhlIG1lc3NhZ2UgaXMgc2FmZSB0byByZXR1cm4gdG8gY2xpZW50cy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIGFyZ3MgPSB7fSkge1xuICAgIGNvbnN0IHtjYXVzZSwgY29kZSwgZGV0YWlscywgZXJyb3JUeXBlLCBzYWZlVG9FeHBvc2UgPSBmYWxzZX0gPSBhcmdzXG5cbiAgICBzdXBlcihtZXNzYWdlLCB7Y2F1c2V9KVxuXG4gICAgdGhpcy5uYW1lID0gXCJWZWxvY2lvdXNFcnJvclwiXG4gICAgdGhpcy5jb2RlID0gY29kZVxuICAgIHRoaXMuZGV0YWlscyA9IGRldGFpbHNcbiAgICB0aGlzLmVycm9yVHlwZSA9IGVycm9yVHlwZVxuICAgIHRoaXMuc2FmZVRvRXhwb3NlID0gc2FmZVRvRXhwb3NlXG4gIH1cblxuICAvKipcbiAgICogUnVucyBzYWZlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIEVycm9yIG1lc3NhZ2UuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBbYXJnc10gLSBPcHRpb25zLlxuICAgKiBAcGFyYW0gez99IFthcmdzLmNhdXNlXSAtIEVycm9yIGNhdXNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3MuY29kZV0gLSBPcHRpb25hbCBlcnJvciBjb2RlLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5DbGllbnRFcnJvclBheWxvYWRSZXBvcnRlclBheWxvYWR9IFthcmdzLmRldGFpbHNdIC0gU3RydWN0dXJlZCBjbGllbnQtc2FmZSBlcnJvciBkZXRhaWxzLlxuICAgKiBAcGFyYW0ge1wiYXBwbGljYXRpb25fZXJyb3JcIiB8IFwiYXV0aG9yaXphdGlvbl9lcnJvclwiIHwgXCJyZWNvcmRfbm90X2ZvdW5kXCIgfCBcInZhbGlkYXRpb25fZXJyb3JcIn0gW2FyZ3MuZXJyb3JUeXBlXSAtIFN0YWJsZSBjbGllbnQtZmFjaW5nIGVycm9yIGNhdGVnb3J5LlxuICAgKiBAcmV0dXJucyB7VmVsb2Npb3VzRXJyb3J9IC0gQ2xpZW50LXNhZmUgZXJyb3IgaW5zdGFuY2UuXG4gICAqL1xuICBzdGF0aWMgc2FmZShtZXNzYWdlLCBhcmdzID0ge30pIHtcbiAgICByZXR1cm4gbmV3IFZlbG9jaW91c0Vycm9yKG1lc3NhZ2UsIHsuLi5hcmdzLCBzYWZlVG9FeHBvc2U6IHRydWV9KVxuICB9XG59XG4iXX0=
|
package/build/velocious-error.js
CHANGED
|
@@ -8,15 +8,19 @@ export default class VelociousError extends Error {
|
|
|
8
8
|
* @param {object} [args] - Options.
|
|
9
9
|
* @param {?} [args.cause] - Error cause.
|
|
10
10
|
* @param {string} [args.code] - Optional error code.
|
|
11
|
+
* @param {import("./configuration-types.js").ClientErrorPayloadReporterPayload} [args.details] - Structured client-safe error details.
|
|
12
|
+
* @param {"application_error" | "authorization_error" | "record_not_found" | "validation_error"} [args.errorType] - Stable client-facing error category.
|
|
11
13
|
* @param {boolean} [args.safeToExpose] - Whether the message is safe to return to clients.
|
|
12
14
|
*/
|
|
13
15
|
constructor(message, args = {}) {
|
|
14
|
-
const {cause, code, safeToExpose = false} = args
|
|
16
|
+
const {cause, code, details, errorType, safeToExpose = false} = args
|
|
15
17
|
|
|
16
18
|
super(message, {cause})
|
|
17
19
|
|
|
18
20
|
this.name = "VelociousError"
|
|
19
21
|
this.code = code
|
|
22
|
+
this.details = details
|
|
23
|
+
this.errorType = errorType
|
|
20
24
|
this.safeToExpose = safeToExpose
|
|
21
25
|
}
|
|
22
26
|
|
|
@@ -26,6 +30,8 @@ export default class VelociousError extends Error {
|
|
|
26
30
|
* @param {object} [args] - Options.
|
|
27
31
|
* @param {?} [args.cause] - Error cause.
|
|
28
32
|
* @param {string} [args.code] - Optional error code.
|
|
33
|
+
* @param {import("./configuration-types.js").ClientErrorPayloadReporterPayload} [args.details] - Structured client-safe error details.
|
|
34
|
+
* @param {"application_error" | "authorization_error" | "record_not_found" | "validation_error"} [args.errorType] - Stable client-facing error category.
|
|
29
35
|
* @returns {VelociousError} - Client-safe error instance.
|
|
30
36
|
*/
|
|
31
37
|
static safe(message, args = {}) {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"velocious": "build/bin/velocious.js"
|
|
4
4
|
},
|
|
5
5
|
"name": "velocious",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.578",
|
|
7
7
|
"main": "build/index.js",
|
|
8
8
|
"types": "build/index.d.ts",
|
|
9
9
|
"files": [
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"eslint-plugin-jsdoc": "^63.0.0",
|
|
112
112
|
"eslint-plugin-jsdoc-inline-type-casts": "https://github.com/kaspernj/eslint-plugin-jsdoc-inline-type-casts/archive/refs/heads/master.tar.gz",
|
|
113
113
|
"eslint-plugin-jsdoc-tag-lines": "^1.0.1",
|
|
114
|
-
"fallow": "3.
|
|
114
|
+
"fallow": "3.11.0",
|
|
115
115
|
"globals": "^17.0.0",
|
|
116
116
|
"mssql": "^12.0.0",
|
|
117
117
|
"mysql": "^2.18.1",
|
|
@@ -786,9 +786,9 @@ export default class BackgroundJobsMain {
|
|
|
786
786
|
options: message.options || {}
|
|
787
787
|
})
|
|
788
788
|
|
|
789
|
-
jsonSocket.send({type: "schedule-replaced", ...result})
|
|
790
789
|
this._notifyEnqueued()
|
|
791
790
|
await this._drain()
|
|
791
|
+
jsonSocket.send({type: "schedule-replaced", ...result})
|
|
792
792
|
} catch (error) {
|
|
793
793
|
this._handleClientMutationError({
|
|
794
794
|
context: {jobName: message.jobName, scheduleKey: message.scheduleKey, stage: "background-job-replace-scheduled"},
|
|
@@ -812,9 +812,9 @@ export default class BackgroundJobsMain {
|
|
|
812
812
|
try {
|
|
813
813
|
const result = await this.store.cancelScheduled(message.scheduleKey)
|
|
814
814
|
|
|
815
|
-
jsonSocket.send({type: "schedule-cancelled", ...result})
|
|
816
815
|
this._notifyEnqueued()
|
|
817
816
|
await this._drain()
|
|
817
|
+
jsonSocket.send({type: "schedule-cancelled", ...result})
|
|
818
818
|
} catch (error) {
|
|
819
819
|
this._handleClientMutationError({
|
|
820
820
|
context: {scheduleKey: message.scheduleKey, stage: "background-job-cancel-scheduled"},
|
|
@@ -312,6 +312,7 @@
|
|
|
312
312
|
* @property {string} controller - Controller class name.
|
|
313
313
|
* @property {string} [action] - Controller action or endpoint label.
|
|
314
314
|
* @property {"index" | "find" | "create" | "update" | "destroy" | "attach" | "attachmentList" | "download" | "url" | "custom-command"} [commandType] - Frontend-model command type.
|
|
315
|
+
* @property {string} [correlationId] - Server-generated identifier shared by an unexpected client error and framework reports.
|
|
315
316
|
* @property {boolean} [expectedError] - Whether the error is an expected user-flow failure.
|
|
316
317
|
* @property {boolean} [frontendModelEndpoint] - Whether the error came from the frontend-model endpoint.
|
|
317
318
|
* @property {string} [model] - Frontend-model name from the failed request.
|
package/src/configuration.js
CHANGED
|
@@ -286,6 +286,19 @@ export default class VelociousConfiguration {
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
this._isInitialized = false
|
|
289
|
+
this._modelsInitialized = false
|
|
290
|
+
/**
|
|
291
|
+
* Invalidates model phases that started before database connections closed.
|
|
292
|
+
* @type {number}
|
|
293
|
+
*/
|
|
294
|
+
this._modelInitializationGeneration = 0
|
|
295
|
+
/**
|
|
296
|
+
* In-progress `initializeModels()` promise. Model initialization is an
|
|
297
|
+
* atomic bootstrap phase: concurrent callers share it, and a rejection
|
|
298
|
+
* leaves the phase eligible for a later complete attempt.
|
|
299
|
+
* @type {Promise<void> | undefined}
|
|
300
|
+
*/
|
|
301
|
+
this._initializeModelsPromise = undefined
|
|
289
302
|
/**
|
|
290
303
|
* In-progress `initialize()` promise, memoized so concurrent callers await
|
|
291
304
|
* the same bootstrap. Reset to undefined if initialization fails.
|
|
@@ -2020,25 +2033,39 @@ export default class VelociousConfiguration {
|
|
|
2020
2033
|
* @returns {Promise<void>} - Resolves when complete.
|
|
2021
2034
|
*/
|
|
2022
2035
|
async initializeModels(args = {type: "server"}) {
|
|
2023
|
-
if (
|
|
2024
|
-
|
|
2036
|
+
if (this._modelsInitialized) return
|
|
2037
|
+
if (this._initializeModelsPromise) return await this._initializeModelsPromise
|
|
2025
2038
|
|
|
2039
|
+
const modelInitializationGeneration = this._modelInitializationGeneration
|
|
2040
|
+
const initializeModelsPromise = (async () => {
|
|
2026
2041
|
const shouldSkipDummyModelInitialization = process.env.VELOCIOUS_SKIP_DUMMY_MODEL_INITIALIZATION === "1"
|
|
2027
2042
|
&& process.env.VELOCIOUS_BROWSER_TESTS === "true"
|
|
2028
2043
|
&& this.getEnvironment() === "test"
|
|
2029
2044
|
|
|
2030
|
-
if (shouldSkipDummyModelInitialization) {
|
|
2031
|
-
|
|
2045
|
+
if (!shouldSkipDummyModelInitialization) {
|
|
2046
|
+
if (this._initializeModels) {
|
|
2047
|
+
await this._initializeModels({configuration: this, type: args.type})
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
await this.getEnvironmentHandler().initializePackageModels(this)
|
|
2051
|
+
await initializeAuditedModelRelationships(this)
|
|
2052
|
+
|
|
2053
|
+
await this.getEnvironmentHandler().initializeFrontendModelWebsocketPublishers(this)
|
|
2032
2054
|
}
|
|
2033
2055
|
|
|
2034
|
-
if (this.
|
|
2035
|
-
|
|
2056
|
+
if (this._modelInitializationGeneration === modelInitializationGeneration) {
|
|
2057
|
+
this._modelsInitialized = true
|
|
2036
2058
|
}
|
|
2059
|
+
})()
|
|
2037
2060
|
|
|
2038
|
-
|
|
2039
|
-
await initializeAuditedModelRelationships(this)
|
|
2061
|
+
this._initializeModelsPromise = initializeModelsPromise
|
|
2040
2062
|
|
|
2041
|
-
|
|
2063
|
+
try {
|
|
2064
|
+
await initializeModelsPromise
|
|
2065
|
+
} finally {
|
|
2066
|
+
if (this._initializeModelsPromise === initializeModelsPromise) {
|
|
2067
|
+
this._initializeModelsPromise = undefined
|
|
2068
|
+
}
|
|
2042
2069
|
}
|
|
2043
2070
|
}
|
|
2044
2071
|
|
|
@@ -2073,6 +2100,12 @@ export default class VelociousConfiguration {
|
|
|
2073
2100
|
|
|
2074
2101
|
this._initializePromise = (async () => {
|
|
2075
2102
|
await this.initializeModels({type})
|
|
2103
|
+
|
|
2104
|
+
// Model initialization can be invalidated by a concurrent connection close.
|
|
2105
|
+
// If models are not ready, stop without marking the configuration initialized
|
|
2106
|
+
// so the next caller retries a full bootstrap.
|
|
2107
|
+
if (!this._modelsInitialized) return
|
|
2108
|
+
|
|
2076
2109
|
await this.getEnvironmentHandler().autoDiscoverResources(this)
|
|
2077
2110
|
this._mergeDiscoveredAbilityResources()
|
|
2078
2111
|
this._validateResourceRelationshipsOnModels()
|
|
@@ -2104,6 +2137,13 @@ export default class VelociousConfiguration {
|
|
|
2104
2137
|
this._initializePromise = undefined
|
|
2105
2138
|
throw error
|
|
2106
2139
|
}
|
|
2140
|
+
|
|
2141
|
+
// If the inner IIFE returned without marking the configuration initialized
|
|
2142
|
+
// (e.g. because models were invalidated mid-bootstrap), clear the promise so
|
|
2143
|
+
// a later call retries a full bootstrap.
|
|
2144
|
+
if (!this._isInitialized) {
|
|
2145
|
+
this._initializePromise = undefined
|
|
2146
|
+
}
|
|
2107
2147
|
}
|
|
2108
2148
|
|
|
2109
2149
|
/**
|
|
@@ -3244,8 +3284,10 @@ export default class VelociousConfiguration {
|
|
|
3244
3284
|
PoolClass.clearGlobalConnections(this)
|
|
3245
3285
|
}
|
|
3246
3286
|
|
|
3247
|
-
// Allow
|
|
3287
|
+
// Allow full re-initialization after connections are closed.
|
|
3288
|
+
this._modelInitializationGeneration += 1
|
|
3248
3289
|
this._modelsInitialized = false
|
|
3290
|
+
this._isInitialized = false
|
|
3249
3291
|
}
|
|
3250
3292
|
})()
|
|
3251
3293
|
|
|
@@ -20,6 +20,9 @@ export default class VelociousDatabaseDriversMysqlStructureSql {
|
|
|
20
20
|
const {driver} = this
|
|
21
21
|
const isMariaDb = await this._isMariaDb()
|
|
22
22
|
const rows = await driver.query("SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = DATABASE() ORDER BY table_type, table_name")
|
|
23
|
+
const foreignKeyRows = await driver.query("SELECT table_name, referenced_table_name FROM information_schema.key_column_usage WHERE table_schema = DATABASE() AND referenced_table_schema = DATABASE() AND referenced_table_name IS NOT NULL")
|
|
24
|
+
const baseTableNames = []
|
|
25
|
+
const views = []
|
|
23
26
|
const statements = []
|
|
24
27
|
|
|
25
28
|
for (const row of rows) {
|
|
@@ -31,24 +34,82 @@ export default class VelociousDatabaseDriversMysqlStructureSql {
|
|
|
31
34
|
if (!tableName || !tableType) continue
|
|
32
35
|
|
|
33
36
|
if (tableType == "BASE TABLE") {
|
|
34
|
-
|
|
35
|
-
const rawCreateStatement = this._mysqlCreateStatement(createRows?.[0])
|
|
36
|
-
const createStatement = rawCreateStatement ? this._stripAutoIncrement(rawCreateStatement) : null
|
|
37
|
-
|
|
38
|
-
if (createStatement) statements.push(normalizeSqlStatement(createStatement))
|
|
37
|
+
baseTableNames.push(tableName)
|
|
39
38
|
} else if (tableType == "VIEW" || (isMariaDb && tableType == "SYSTEM VIEW")) {
|
|
40
|
-
|
|
41
|
-
const createStatement = this._mysqlCreateStatement(createRows?.[0])
|
|
42
|
-
|
|
43
|
-
if (createStatement) statements.push(normalizeSqlStatement(createStatement))
|
|
39
|
+
views.push(tableName)
|
|
44
40
|
}
|
|
45
41
|
}
|
|
46
42
|
|
|
43
|
+
for (const tableName of this._orderBaseTables({foreignKeyRows, tableNames: baseTableNames})) {
|
|
44
|
+
const createRows = await driver.query(`SHOW CREATE TABLE ${driver.quoteTable(tableName)}`)
|
|
45
|
+
const rawCreateStatement = this._mysqlCreateStatement(createRows?.[0])
|
|
46
|
+
const createStatement = rawCreateStatement ? this._stripAutoIncrement(rawCreateStatement) : null
|
|
47
|
+
|
|
48
|
+
if (createStatement) statements.push(normalizeSqlStatement(createStatement))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (const tableName of views) {
|
|
52
|
+
const createRows = await driver.query(`SHOW CREATE VIEW ${driver.quoteTable(tableName)}`)
|
|
53
|
+
const createStatement = this._mysqlCreateStatement(createRows?.[0])
|
|
54
|
+
|
|
55
|
+
if (createStatement) statements.push(normalizeSqlStatement(createStatement))
|
|
56
|
+
}
|
|
57
|
+
|
|
47
58
|
if (statements.length == 0) return null
|
|
48
59
|
|
|
49
60
|
return `${statements.join("\n\n")}\n`
|
|
50
61
|
}
|
|
51
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Orders tables so referenced tables are created before their dependents.
|
|
65
|
+
* @param {object} args - Options object.
|
|
66
|
+
* @param {Array<Record<string, ?>>} args.foreignKeyRows - Foreign key metadata rows.
|
|
67
|
+
* @param {string[]} args.tableNames - Base table names in their existing order.
|
|
68
|
+
* @returns {string[]} - Ordered table names.
|
|
69
|
+
*/
|
|
70
|
+
_orderBaseTables({foreignKeyRows, tableNames}) {
|
|
71
|
+
const pendingTableNames = new Set(tableNames)
|
|
72
|
+
/** @type {Record<string, Set<string>>} */
|
|
73
|
+
const dependenciesByTableName = {}
|
|
74
|
+
const orderedTableNames = []
|
|
75
|
+
|
|
76
|
+
for (const tableName of tableNames) {
|
|
77
|
+
dependenciesByTableName[tableName] = new Set()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (const row of foreignKeyRows) {
|
|
81
|
+
const tableNameValue = row.table_name || row.TABLE_NAME
|
|
82
|
+
const referencedTableNameValue = row.referenced_table_name || row.REFERENCED_TABLE_NAME
|
|
83
|
+
const tableName = tableNameValue ? String(tableNameValue) : ""
|
|
84
|
+
const referencedTableName = referencedTableNameValue ? String(referencedTableNameValue) : ""
|
|
85
|
+
|
|
86
|
+
if (tableName == referencedTableName || !pendingTableNames.has(tableName) || !pendingTableNames.has(referencedTableName)) continue
|
|
87
|
+
|
|
88
|
+
dependenciesByTableName[tableName].add(referencedTableName)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
while (pendingTableNames.size > 0) {
|
|
92
|
+
const nextTableName = tableNames.find((tableName) => {
|
|
93
|
+
if (!pendingTableNames.has(tableName)) return false
|
|
94
|
+
|
|
95
|
+
return Array.from(dependenciesByTableName[tableName]).every((dependencyTableName) => !pendingTableNames.has(dependencyTableName))
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
if (!nextTableName) {
|
|
99
|
+
for (const tableName of tableNames) {
|
|
100
|
+
if (pendingTableNames.has(tableName)) orderedTableNames.push(tableName)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
break
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
orderedTableNames.push(nextTableName)
|
|
107
|
+
pendingTableNames.delete(nextTableName)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return orderedTableNames
|
|
111
|
+
}
|
|
112
|
+
|
|
52
113
|
/**
|
|
53
114
|
* Runs is maria db.
|
|
54
115
|
* @returns {Promise<boolean>} - Resolves with Whether maria db.
|
|
@@ -161,22 +161,22 @@ function queryForEntry({entry, modelClass, parentIds, sourceModel}) {
|
|
|
161
161
|
|
|
162
162
|
const foreignKey = relationship.getForeignKey()
|
|
163
163
|
/**
|
|
164
|
-
*
|
|
164
|
+
* Mandatory cohort conditions.
|
|
165
165
|
* @type {Record<string, ?>} */
|
|
166
|
-
const
|
|
166
|
+
const mandatoryWhereConditions = {[foreignKey]: parentIds}
|
|
167
167
|
|
|
168
168
|
if (relationship.getPolymorphic && relationship.getPolymorphic()) {
|
|
169
169
|
const typeColumn = relationship.getPolymorphicTypeColumn()
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (entry.where) {
|
|
174
|
-
Object.assign(whereConditions, entry.where)
|
|
170
|
+
mandatoryWhereConditions[typeColumn] = modelClass.getModelName()
|
|
175
171
|
}
|
|
176
172
|
|
|
177
173
|
const baseQuery = sourceModel.queryForModel(targetModelClass)
|
|
178
174
|
baseQuery._forceQualifyBaseTable = true
|
|
179
|
-
baseQuery.where(
|
|
175
|
+
baseQuery.where(mandatoryWhereConditions)
|
|
176
|
+
|
|
177
|
+
if (entry.where) {
|
|
178
|
+
baseQuery.where(entry.where)
|
|
179
|
+
}
|
|
180
180
|
|
|
181
181
|
const countQuery = relationship.applyScope(baseQuery)
|
|
182
182
|
|