From 286e62dcd2690a73b065ea796efbaf8e797b8ced Mon Sep 17 00:00:00 2001 From: Ulad Kasach Date: Sun, 9 Jun 2024 18:46:20 -0400 Subject: [PATCH] fix(control): reliably sort schema control declaration by dependency order --- package-lock.json | 292 +++++++++++++++--- package.json | 5 +- .../AsyncTaskPredictStationCongestion.ts | 33 ++ .../src/domain/objects/index.ts | 1 + ...erenceAvailableProvisionOrder.test.ts.snap | 55 ++++ ...sForDomainObjects.integration.test.ts.snap | 92 +++--- ...ntReferenceAvailableProvisionOrder.test.ts | 24 ++ ...pendentReferenceAvailableProvisionOrder.ts | 75 +++++ ...eFilesForDomainObjects.integration.test.ts | 1 + ...lSchemaControlCodeFilesForDomainObjects.ts | 64 ++-- 10 files changed, 513 insertions(+), 129 deletions(-) create mode 100644 src/logic/__test_assets__/exampleProject/src/domain/objects/AsyncTaskPredictStationCongestion.ts create mode 100644 src/logic/define/sqlSchemaControl/__snapshots__/defineDependentReferenceAvailableProvisionOrder.test.ts.snap create mode 100644 src/logic/define/sqlSchemaControl/defineDependentReferenceAvailableProvisionOrder.test.ts create mode 100644 src/logic/define/sqlSchemaControl/defineDependentReferenceAvailableProvisionOrder.ts diff --git a/package-lock.json b/package-lock.json index a1c6137..4e41eec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,14 +16,15 @@ "chalk": "2.4.2", "change-case": "4.1.1", "domain-objects": "0.20.0", - "domain-objects-metadata": "0.5.1", + "domain-objects-metadata": "0.7.1", "fast-glob": "3.2.2", "joi": "17.4.0", "lodash.omit": "4.5.0", "oclif": "4.11.3", "shelljs": "0.8.5", + "simple-async-tasks": "1.4.2", "ts-node": "10.9.2", - "type-fns": "0.8.1", + "type-fns": "1.15.0", "uuid": "9.0.0", "yaml": "1.6.0" }, @@ -8029,6 +8030,15 @@ "declapract": "0.11.2" } }, + "node_modules/declapract-typescript-ehmpathy/node_modules/type-fns": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.8.1.tgz", + "integrity": "sha512-cfOaPy1BoEIWsUA1GXrZMxVxSqykeK5GcADT2NeYFb/VWJClfTQUiEIMGaipwamjk85t4AoABI8LPEZS2QYE3w==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/declapract/node_modules/@oclif/core": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.0.11.tgz", @@ -9283,16 +9293,16 @@ } }, "node_modules/domain-objects-metadata": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/domain-objects-metadata/-/domain-objects-metadata-0.5.1.tgz", - "integrity": "sha512-xHbL0jChzp7386lwHfADjUh4N8icqkadYdkAAzAlxvpqHW8FH+S89AJqmWWPpWHRapM0eOLHIPOOZjhRrxIoXQ==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/domain-objects-metadata/-/domain-objects-metadata-0.7.1.tgz", + "integrity": "sha512-zFpHkixEWYylz1PGjIeXNx3Pu6yAJVSawcLQ1VTd5NIa8xmHgrxnrDm8VwXlhhO52wp6T+HW1KHTICNebPkEZw==", "hasInstallScript": true, "dependencies": { "@ehmpathy/error-fns": "1.0.2", "domain-objects": "^0.20.0", "joi": "17.4.0", "lodash.omit": "^4.5.0", - "type-fns": "^0.9.1", + "type-fns": "^1.15.0", "typescript": "^3.8.3", "uuid": "9.0.0" }, @@ -9300,14 +9310,6 @@ "node": ">=8.0.0" } }, - "node_modules/domain-objects-metadata/node_modules/type-fns": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.9.1.tgz", - "integrity": "sha512-zqb5HlYUnwsY/xQUX0EfpVBid1ItCKxDJSPjFWpdPop+f3MxZ5eQer3JMsjXrR+QRVSX2vWYnGzEJa5vET5zsA==", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/domain-objects-metadata/node_modules/typescript": { "version": "3.9.10", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", @@ -9359,17 +9361,6 @@ "node": ">=8.0.0" } }, - "node_modules/domain-objects/node_modules/type-fns": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-1.15.0.tgz", - "integrity": "sha512-IAxaiIMleiQ1pU6pBbmJagVmQz/88JVydpGXSEGYoIBo1F1Zkz9ibC1IWN+t5mj1PAByDf7S4yOsc6LNYxQM+Q==", - "dependencies": { - "@ehmpathy/error-fns": "1.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -10050,6 +10041,25 @@ "node": ">=0.10.0" } }, + "node_modules/event-stream-pubsub": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/event-stream-pubsub/-/event-stream-pubsub-0.1.3.tgz", + "integrity": "sha512-LhpWwAzOYyP1o9DEjugGh+K6MkibhWswZCWbsY4HtPkMd0LwHPIblKLrnd9YSAk76RDYcO4+f9dmkZFDbTs+iA==", + "dependencies": { + "events": "^3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/event-stream-pubsub/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -17626,6 +17636,76 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/simple-async-tasks": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/simple-async-tasks/-/simple-async-tasks-1.4.2.tgz", + "integrity": "sha512-oNmyoKxUN7HzOVlxELBa5H5nyKF4WRR120ECQkRUuLtzgq6xn+1tKnmpleLqor6FW9c4GxOMYRp/If2a6wDYqQ==", + "dependencies": { + "@ehmpathy/error-fns": "1.0.2", + "date-fns": "2.30.0", + "simple-in-memory-queue": "1.1.7", + "uuid": "9.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "type-fns": "^1.13.0" + } + }, + "node_modules/simple-async-tasks/node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/simple-async-tasks/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/simple-in-memory-cache": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/simple-in-memory-cache/-/simple-in-memory-cache-0.3.0.tgz", + "integrity": "sha512-AK/kLSR9ROz6jJvTfpgtCVITBvc4wn9gE/Ey7UklYFGA36+kJfqoMdzKvrOrrrQh+NVMAh/QiZXnwaumh/j7vQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/simple-in-memory-queue": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/simple-in-memory-queue/-/simple-in-memory-queue-1.1.7.tgz", + "integrity": "sha512-uI6NMiyRwVxNBFHax83KOHnP+GHjX15Bz5V0cL3/UvZoEnySlchpv4zMmYJPq7oGoXWLHYQtGoappw/pHGTiQQ==", + "dependencies": { + "event-stream-pubsub": "0.1.3", + "simple-in-memory-cache": "0.3.0", + "uuid": "9.0.0", + "with-simple-caching": "0.11.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/simple-in-memory-queue/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/simple-leveled-log-methods": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/simple-leveled-log-methods/-/simple-leveled-log-methods-0.1.4.tgz", @@ -20488,6 +20568,15 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/sql-schema-generator/node_modules/type-fns": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.8.1.tgz", + "integrity": "sha512-cfOaPy1BoEIWsUA1GXrZMxVxSqykeK5GcADT2NeYFb/VWJClfTQUiEIMGaipwamjk85t4AoABI8LPEZS2QYE3w==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/sql-schema-generator/node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -21549,9 +21638,12 @@ } }, "node_modules/type-fns": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.8.1.tgz", - "integrity": "sha512-cfOaPy1BoEIWsUA1GXrZMxVxSqykeK5GcADT2NeYFb/VWJClfTQUiEIMGaipwamjk85t4AoABI8LPEZS2QYE3w==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-1.15.0.tgz", + "integrity": "sha512-IAxaiIMleiQ1pU6pBbmJagVmQz/88JVydpGXSEGYoIBo1F1Zkz9ibC1IWN+t5mj1PAByDf7S4yOsc6LNYxQM+Q==", + "dependencies": { + "@ehmpathy/error-fns": "1.0.2" + }, "engines": { "node": ">=8.0.0" } @@ -21950,6 +22042,26 @@ "node": ">=8" } }, + "node_modules/with-simple-caching": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/with-simple-caching/-/with-simple-caching-0.11.1.tgz", + "integrity": "sha512-hIHHGbScthc/UVNSDiClAsEDBOuZlmtPriW6wPlhdpDQeEDX+uJlan/yTT7Zf2YyHT31nTGhU1qhFZlsDloKcA==", + "dependencies": { + "simple-in-memory-cache": "^0.3.0", + "type-fns": "^0.6.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/with-simple-caching/node_modules/type-fns": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.6.0.tgz", + "integrity": "sha512-PRECv24BnwGm1/bUWtcNJYSTjM2pyZXy8B5+qINXmsfQNnhK3VFQgfn6/SzukaCdQAxz9B5LhmAuKrEcDvBQug==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -30551,6 +30663,14 @@ "flat": "5.0.2", "lodash.uniq": "4.5.0", "type-fns": "0.8.1" + }, + "dependencies": { + "type-fns": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.8.1.tgz", + "integrity": "sha512-cfOaPy1BoEIWsUA1GXrZMxVxSqykeK5GcADT2NeYFb/VWJClfTQUiEIMGaipwamjk85t4AoABI8LPEZS2QYE3w==", + "dev": true + } } }, "decompress-response": { @@ -30809,36 +30929,23 @@ "requires": { "@ehmpathy/error-fns": "1.0.2" } - }, - "type-fns": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-1.15.0.tgz", - "integrity": "sha512-IAxaiIMleiQ1pU6pBbmJagVmQz/88JVydpGXSEGYoIBo1F1Zkz9ibC1IWN+t5mj1PAByDf7S4yOsc6LNYxQM+Q==", - "requires": { - "@ehmpathy/error-fns": "1.0.2" - } } } }, "domain-objects-metadata": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/domain-objects-metadata/-/domain-objects-metadata-0.5.1.tgz", - "integrity": "sha512-xHbL0jChzp7386lwHfADjUh4N8icqkadYdkAAzAlxvpqHW8FH+S89AJqmWWPpWHRapM0eOLHIPOOZjhRrxIoXQ==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/domain-objects-metadata/-/domain-objects-metadata-0.7.1.tgz", + "integrity": "sha512-zFpHkixEWYylz1PGjIeXNx3Pu6yAJVSawcLQ1VTd5NIa8xmHgrxnrDm8VwXlhhO52wp6T+HW1KHTICNebPkEZw==", "requires": { "@ehmpathy/error-fns": "1.0.2", "domain-objects": "^0.20.0", "joi": "17.4.0", "lodash.omit": "^4.5.0", - "type-fns": "^0.9.1", + "type-fns": "^1.15.0", "typescript": "^3.8.3", "uuid": "9.0.0" }, "dependencies": { - "type-fns": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.9.1.tgz", - "integrity": "sha512-zqb5HlYUnwsY/xQUX0EfpVBid1ItCKxDJSPjFWpdPop+f3MxZ5eQer3JMsjXrR+QRVSX2vWYnGzEJa5vET5zsA==" - }, "typescript": { "version": "3.9.10", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", @@ -31369,6 +31476,21 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "event-stream-pubsub": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/event-stream-pubsub/-/event-stream-pubsub-0.1.3.tgz", + "integrity": "sha512-LhpWwAzOYyP1o9DEjugGh+K6MkibhWswZCWbsY4HtPkMd0LwHPIblKLrnd9YSAk76RDYcO4+f9dmkZFDbTs+iA==", + "requires": { + "events": "^3.0.0" + }, + "dependencies": { + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + } + } + }, "event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -37125,6 +37247,55 @@ } } }, + "simple-async-tasks": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/simple-async-tasks/-/simple-async-tasks-1.4.2.tgz", + "integrity": "sha512-oNmyoKxUN7HzOVlxELBa5H5nyKF4WRR120ECQkRUuLtzgq6xn+1tKnmpleLqor6FW9c4GxOMYRp/If2a6wDYqQ==", + "requires": { + "@ehmpathy/error-fns": "1.0.2", + "date-fns": "2.30.0", + "simple-in-memory-queue": "1.1.7", + "uuid": "9.0.0" + }, + "dependencies": { + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "requires": { + "@babel/runtime": "^7.21.0" + } + }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + } + } + }, + "simple-in-memory-cache": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/simple-in-memory-cache/-/simple-in-memory-cache-0.3.0.tgz", + "integrity": "sha512-AK/kLSR9ROz6jJvTfpgtCVITBvc4wn9gE/Ey7UklYFGA36+kJfqoMdzKvrOrrrQh+NVMAh/QiZXnwaumh/j7vQ==" + }, + "simple-in-memory-queue": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/simple-in-memory-queue/-/simple-in-memory-queue-1.1.7.tgz", + "integrity": "sha512-uI6NMiyRwVxNBFHax83KOHnP+GHjX15Bz5V0cL3/UvZoEnySlchpv4zMmYJPq7oGoXWLHYQtGoappw/pHGTiQQ==", + "requires": { + "event-stream-pubsub": "0.1.3", + "simple-in-memory-cache": "0.3.0", + "uuid": "9.0.0", + "with-simple-caching": "0.11.1" + }, + "dependencies": { + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + } + } + }, "simple-leveled-log-methods": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/simple-leveled-log-methods/-/simple-leveled-log-methods-0.1.4.tgz", @@ -39450,6 +39621,12 @@ "is-fullwidth-code-point": "^3.0.0" } }, + "type-fns": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.8.1.tgz", + "integrity": "sha512-cfOaPy1BoEIWsUA1GXrZMxVxSqykeK5GcADT2NeYFb/VWJClfTQUiEIMGaipwamjk85t4AoABI8LPEZS2QYE3w==", + "dev": true + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -40245,9 +40422,12 @@ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" }, "type-fns": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.8.1.tgz", - "integrity": "sha512-cfOaPy1BoEIWsUA1GXrZMxVxSqykeK5GcADT2NeYFb/VWJClfTQUiEIMGaipwamjk85t4AoABI8LPEZS2QYE3w==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-1.15.0.tgz", + "integrity": "sha512-IAxaiIMleiQ1pU6pBbmJagVmQz/88JVydpGXSEGYoIBo1F1Zkz9ibC1IWN+t5mj1PAByDf7S4yOsc6LNYxQM+Q==", + "requires": { + "@ehmpathy/error-fns": "1.0.2" + } }, "typed-array-length": { "version": "1.0.4", @@ -40572,6 +40752,22 @@ "string-width": "^4.0.0" } }, + "with-simple-caching": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/with-simple-caching/-/with-simple-caching-0.11.1.tgz", + "integrity": "sha512-hIHHGbScthc/UVNSDiClAsEDBOuZlmtPriW6wPlhdpDQeEDX+uJlan/yTT7Zf2YyHT31nTGhU1qhFZlsDloKcA==", + "requires": { + "simple-in-memory-cache": "^0.3.0", + "type-fns": "^0.6.0" + }, + "dependencies": { + "type-fns": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fns/-/type-fns-0.6.0.tgz", + "integrity": "sha512-PRECv24BnwGm1/bUWtcNJYSTjM2pyZXy8B5+qINXmsfQNnhK3VFQgfn6/SzukaCdQAxz9B5LhmAuKrEcDvBQug==" + } + } + }, "word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index 94de38e..4b0bfde 100644 --- a/package.json +++ b/package.json @@ -80,14 +80,15 @@ "chalk": "2.4.2", "change-case": "4.1.1", "domain-objects": "0.20.0", - "domain-objects-metadata": "0.5.1", + "domain-objects-metadata": "0.7.1", "fast-glob": "3.2.2", "joi": "17.4.0", "lodash.omit": "4.5.0", "oclif": "4.11.3", "shelljs": "0.8.5", + "simple-async-tasks": "1.4.2", "ts-node": "10.9.2", - "type-fns": "0.8.1", + "type-fns": "1.15.0", "uuid": "9.0.0", "yaml": "1.6.0" }, diff --git a/src/logic/__test_assets__/exampleProject/src/domain/objects/AsyncTaskPredictStationCongestion.ts b/src/logic/__test_assets__/exampleProject/src/domain/objects/AsyncTaskPredictStationCongestion.ts new file mode 100644 index 0000000..f4d4a5c --- /dev/null +++ b/src/logic/__test_assets__/exampleProject/src/domain/objects/AsyncTaskPredictStationCongestion.ts @@ -0,0 +1,33 @@ +import { DomainEntity } from 'domain-objects'; +import { AsyncTask, AsyncTaskStatus } from 'simple-async-tasks'; + +/** + * an async task which predicts station congestion by comparing expected arrival time with estimated arrival time + */ +export interface AsyncTaskPredictStationCongestion extends AsyncTask { + id?: number; + uuid?: string; + createdAt?: Date; + updatedAt?: Date; + status: AsyncTaskStatus; + + /** + * the station to run this prediction for + */ + stationUuid: string; + + /** + * the event to run the prediction on + * + * note + * - this has a nested dependency on a train, which we use to test sql-schema-control order + */ + trainLocatedEventUuid: string; +} +export class AsyncTaskPredictStationCongestion + extends DomainEntity + implements AsyncTaskPredictStationCongestion +{ + public static unique = ['stationUuid', 'trainLocatedEventUuid']; + public static updatable = ['status']; +} diff --git a/src/logic/__test_assets__/exampleProject/src/domain/objects/index.ts b/src/logic/__test_assets__/exampleProject/src/domain/objects/index.ts index 06a47f0..c5c5140 100644 --- a/src/logic/__test_assets__/exampleProject/src/domain/objects/index.ts +++ b/src/logic/__test_assets__/exampleProject/src/domain/objects/index.ts @@ -1,3 +1,4 @@ +export * from './AsyncTaskPredictStationCongestion' export * from './Carriage'; export * from './Certificate'; export * from './Engineer'; diff --git a/src/logic/define/sqlSchemaControl/__snapshots__/defineDependentReferenceAvailableProvisionOrder.test.ts.snap b/src/logic/define/sqlSchemaControl/__snapshots__/defineDependentReferenceAvailableProvisionOrder.test.ts.snap new file mode 100644 index 0000000..21211ad --- /dev/null +++ b/src/logic/define/sqlSchemaControl/__snapshots__/defineDependentReferenceAvailableProvisionOrder.test.ts.snap @@ -0,0 +1,55 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`defineDependentReferenceAvailableProvisionOrder should work on the example project 1`] = ` +{ + "depth": 3, + "order": [ + "Carriage", + "Certificate", + "Geocode", + "Locomotive", + "Price", + "TrainEngineer", + "TrainStation", + "InvoiceLineItem", + "Train", + "TrainLocatedEvent", + "AsyncTaskPredictStationCongestion", + "Invoice", + ], + "reason": { + "AsyncTaskPredictStationCongestion": [ + "TrainStation", + "TrainLocatedEvent", + ], + "Carriage": [], + "Certificate": [], + "Geocode": [], + "Invoice": [ + "InvoiceLineItem", + "Price", + ], + "InvoiceLineItem": [ + "Price", + ], + "Locomotive": [], + "Price": [], + "Train": [ + "Geocode", + "Locomotive", + "Carriage", + "TrainEngineer", + ], + "TrainEngineer": [ + "Certificate", + ], + "TrainLocatedEvent": [ + "Train", + "Geocode", + ], + "TrainStation": [ + "Geocode", + ], + }, +} +`; diff --git a/src/logic/define/sqlSchemaControl/__snapshots__/defineSqlSchemaControlCodeFilesForDomainObjects.integration.test.ts.snap b/src/logic/define/sqlSchemaControl/__snapshots__/defineSqlSchemaControlCodeFilesForDomainObjects.integration.test.ts.snap index d9cb020..95e2948 100644 --- a/src/logic/define/sqlSchemaControl/__snapshots__/defineSqlSchemaControlCodeFilesForDomainObjects.integration.test.ts.snap +++ b/src/logic/define/sqlSchemaControl/__snapshots__/defineSqlSchemaControlCodeFilesForDomainObjects.integration.test.ts.snap @@ -14,22 +14,6 @@ GeneratedCodeFile { - type: resource path: ./functions/upsert_certificate.sql -# train_engineer -- type: resource - path: ./tables/train_engineer.sql -- type: resource - path: ./tables/train_engineer_version.sql -- type: resource - path: ./tables/train_engineer_version_to_certificate.sql -- type: resource - path: ./tables/train_engineer_version_to_license_uuid.sql -- type: resource - path: ./tables/train_engineer_cvp.sql -- type: resource - path: ./views/view_train_engineer_current.sql -- type: resource - path: ./functions/upsert_train_engineer.sql - # geocode - type: resource path: ./tables/geocode.sql @@ -48,11 +32,27 @@ GeneratedCodeFile { - type: resource path: ./functions/upsert_locomotive.sql -# train_located_event +# price - type: resource - path: ./tables/train_located_event.sql + path: ./tables/price.sql - type: resource - path: ./functions/upsert_train_located_event.sql + path: ./functions/upsert_price.sql + +# train_engineer +- type: resource + path: ./tables/train_engineer.sql +- type: resource + path: ./tables/train_engineer_version.sql +- type: resource + path: ./tables/train_engineer_version_to_certificate.sql +- type: resource + path: ./tables/train_engineer_version_to_license_uuid.sql +- type: resource + path: ./tables/train_engineer_cvp.sql +- type: resource + path: ./views/view_train_engineer_current.sql +- type: resource + path: ./functions/upsert_train_engineer.sql # train_station - type: resource @@ -66,32 +66,12 @@ GeneratedCodeFile { - type: resource path: ./functions/upsert_train_station.sql -# price -- type: resource - path: ./tables/price.sql -- type: resource - path: ./functions/upsert_price.sql - # invoice_line_item - type: resource path: ./tables/invoice_line_item.sql - type: resource path: ./functions/upsert_invoice_line_item.sql -# invoice -- type: resource - path: ./tables/invoice.sql -- type: resource - path: ./tables/invoice_version.sql -- type: resource - path: ./tables/invoice_version_to_invoice_line_item.sql -- type: resource - path: ./tables/invoice_cvp.sql -- type: resource - path: ./views/view_invoice_current.sql -- type: resource - path: ./functions/upsert_invoice.sql - # train - type: resource path: ./tables/train.sql @@ -108,7 +88,39 @@ GeneratedCodeFile { - type: resource path: ./views/view_train_current.sql - type: resource - path: ./functions/upsert_train.sql", + path: ./functions/upsert_train.sql + +# train_located_event +- type: resource + path: ./tables/train_located_event.sql +- type: resource + path: ./functions/upsert_train_located_event.sql + +# async_task_predict_station_congestion +- type: resource + path: ./tables/async_task_predict_station_congestion.sql +- type: resource + path: ./tables/async_task_predict_station_congestion_version.sql +- type: resource + path: ./tables/async_task_predict_station_congestion_cvp.sql +- type: resource + path: ./views/view_async_task_predict_station_congestion_current.sql +- type: resource + path: ./functions/upsert_async_task_predict_station_congestion.sql + +# invoice +- type: resource + path: ./tables/invoice.sql +- type: resource + path: ./tables/invoice_version.sql +- type: resource + path: ./tables/invoice_version_to_invoice_line_item.sql +- type: resource + path: ./tables/invoice_cvp.sql +- type: resource + path: ./views/view_invoice_current.sql +- type: resource + path: ./functions/upsert_invoice.sql", "relpath": "./domain.control.yml", } `; diff --git a/src/logic/define/sqlSchemaControl/defineDependentReferenceAvailableProvisionOrder.test.ts b/src/logic/define/sqlSchemaControl/defineDependentReferenceAvailableProvisionOrder.test.ts new file mode 100644 index 0000000..98fcaf5 --- /dev/null +++ b/src/logic/define/sqlSchemaControl/defineDependentReferenceAvailableProvisionOrder.test.ts @@ -0,0 +1,24 @@ +import { introspect } from 'domain-objects-metadata'; + +import { defineSqlSchemaRelationshipsForDomainObjects } from '../sqlSchemaRelationship/defineSqlSchemaRelationshipsForDomainObjects'; +import { defineDependentReferenceAvailableProvisionOrder } from './defineDependentReferenceAvailableProvisionOrder'; +import { defineSqlSchemaControlCodeFilesForDomainObjects } from './defineSqlSchemaControlCodeFilesForDomainObjects'; + +describe('defineDependentReferenceAvailableProvisionOrder', () => { + it('should work on the example project', () => { + const domainObjects = introspect( + `${__dirname}/../../__test_assets__/exampleProject/src/domain/objects/index.ts`, + ); + const sqlSchemaRelationships = defineSqlSchemaRelationshipsForDomainObjects( + { domainObjects }, + ); + + const { order, reason, depth } = + defineDependentReferenceAvailableProvisionOrder({ + sqlSchemaRelationships, + }); + console.log({ order, reason, depth }); + + expect({ order, reason, depth }).toMatchSnapshot(); + }); +}); diff --git a/src/logic/define/sqlSchemaControl/defineDependentReferenceAvailableProvisionOrder.ts b/src/logic/define/sqlSchemaControl/defineDependentReferenceAvailableProvisionOrder.ts new file mode 100644 index 0000000..239e501 --- /dev/null +++ b/src/logic/define/sqlSchemaControl/defineDependentReferenceAvailableProvisionOrder.ts @@ -0,0 +1,75 @@ +import { UnexpectedCodePathError } from '@ehmpathy/error-fns'; +import { isPresent } from 'type-fns'; + +import { SqlSchemaToDomainObjectRelationship } from '../../../domain'; + +/** + * .what = defines the order in which schemas must be provisioned to ensure their dependent references are available + * .why = + * - guarantees that if this order is followed, there will be no schema declaration issues + */ +export const defineDependentReferenceAvailableProvisionOrder = ({ + sqlSchemaRelationships, +}: { + sqlSchemaRelationships: SqlSchemaToDomainObjectRelationship[]; +}): { order: string[]; reason: Record; depth: number } => { + // create a map of DobjName -> ReferencedDobjName[] + const dependencyMap = sqlSchemaRelationships.reduce( + (summary, thisRelationship) => { + const key = thisRelationship.name.domainObject; + const value = [ + ...new Set( + thisRelationship.properties + .map((property) => property.sqlSchema.reference?.of.name) + .filter(isPresent), + ), + ]; + return { + ...summary, + [key]: value, + }; + }, + {} as Record, + ); + + // loop through each until its dependencies are in the sorted array + const dobjNamesToOrder = Object.keys(dependencyMap).sort(); + const order: string[] = []; + let iterations = 0; + while (order.length < dobjNamesToOrder.length) { + // increment the iterations; fail fast if we've iterated more than 21 times. there should not be a reason to have a reference depth of 21+ times, meaning there's probably a cyclical reference + iterations++; + if (iterations > 21) + throw new UnexpectedCodePathError( + 'attempted to resolve reference order for more than 21 iterations. is there a cyclical import?', + { dependencyMap: dependencyMap }, + ); + + // loop through each dobj + for (const dobjName of dobjNamesToOrder) { + // if already ordered, no need to try again + if (order.includes(dobjName)) continue; + + // if a dependency is not found yet, continue until it is + const dependencies = dependencyMap[dobjName]; + if (!dependencies) + throw new UnexpectedCodePathError( + 'could not find dependencies for dobj. how is that possible?', + { dobjName, dependencies }, + ); + const hasSomeDependencyMissed = dependencies.some( + (dependency) => !order.includes(dependency), + ); + if (hasSomeDependencyMissed) continue; + + // otherwise, add this dobj to the order + order.push(dobjName); + } + } + + return { + order: order, + reason: dependencyMap, + depth: iterations, + }; +}; diff --git a/src/logic/define/sqlSchemaControl/defineSqlSchemaControlCodeFilesForDomainObjects.integration.test.ts b/src/logic/define/sqlSchemaControl/defineSqlSchemaControlCodeFilesForDomainObjects.integration.test.ts index a40c58f..47d6ba2 100644 --- a/src/logic/define/sqlSchemaControl/defineSqlSchemaControlCodeFilesForDomainObjects.integration.test.ts +++ b/src/logic/define/sqlSchemaControl/defineSqlSchemaControlCodeFilesForDomainObjects.integration.test.ts @@ -11,6 +11,7 @@ describe('defineSqlSchemaControlCodeFilesForDomainObjects', () => { const sqlSchemaRelationships = defineSqlSchemaRelationshipsForDomainObjects( { domainObjects }, ); + const file = defineSqlSchemaControlCodeFilesForDomainObjects({ domainObjects, sqlSchemaRelationships, diff --git a/src/logic/define/sqlSchemaControl/defineSqlSchemaControlCodeFilesForDomainObjects.ts b/src/logic/define/sqlSchemaControl/defineSqlSchemaControlCodeFilesForDomainObjects.ts index c02590a..4beb1d6 100644 --- a/src/logic/define/sqlSchemaControl/defineSqlSchemaControlCodeFilesForDomainObjects.ts +++ b/src/logic/define/sqlSchemaControl/defineSqlSchemaControlCodeFilesForDomainObjects.ts @@ -1,10 +1,9 @@ -import { snakeCase } from 'change-case'; +import { UnexpectedCodePathError } from '@ehmpathy/error-fns'; import { DomainObjectMetadata } from 'domain-objects-metadata'; -import { isPresent } from 'type-fns'; import { GeneratedCodeFile } from '../../../domain/objects/GeneratedCodeFile'; import { SqlSchemaToDomainObjectRelationship } from '../../../domain/objects/SqlSchemaToDomainObjectRelationship'; -import { UnexpectedCodePathDetectedError } from '../../UnexpectedCodePathDetectedError'; +import { defineDependentReferenceAvailableProvisionOrder } from './defineDependentReferenceAvailableProvisionOrder'; import { defineSqlSchemaControlCodeForDomainObject } from './defineSqlSchemaControlCodeForDomainObject'; export const defineSqlSchemaControlCodeFilesForDomainObjects = ({ @@ -14,47 +13,34 @@ export const defineSqlSchemaControlCodeFilesForDomainObjects = ({ sqlSchemaRelationships: SqlSchemaToDomainObjectRelationship[]; }) => { // grab code per domain object - const codePerDomainObject = sqlSchemaRelationships.map( - (sqlSchemaRelationship) => ({ - sqlSchemaRelationship, - code: defineSqlSchemaControlCodeForDomainObject({ + const dobjToCodeMap: Record = Object.fromEntries( + sqlSchemaRelationships.map((sqlSchemaRelationship) => [ + // dobj name + sqlSchemaRelationship.name.domainObject, + + // code + defineSqlSchemaControlCodeForDomainObject({ sqlSchemaRelationship, }), - }), + ]), ); - // sort them by references; go through them alphabetically over and over until each has its references defined - const sortedCodePerDomainObject: string[] = []; - let timesLooped = 0; // for infi loop prevention - while (sortedCodePerDomainObject.length < codePerDomainObject.length) { - for (const { - code: thisCode, - sqlSchemaRelationship: thisRelationship, - } of codePerDomainObject) { - if (sortedCodePerDomainObject.includes(thisCode)) continue; // if its already in there, no need to re-evaluate - const domainObjectsThisSchemaReferences = thisRelationship.properties - .map( - (propertyRelationship) => - propertyRelationship.sqlSchema.reference?.of.name, - ) - .filter(isPresent); - const someReferencedDomainObjectIsNotAlreadyIncluded = - domainObjectsThisSchemaReferences.some( - (domainObjectName) => - !sortedCodePerDomainObject.some((code) => - code.includes(`# ${snakeCase(domainObjectName)}`), - ), // probably not the best way of checking, but if this breaks tests will catch it and we can fix it then + // determine the order in which we should declare them + const { order } = defineDependentReferenceAvailableProvisionOrder({ + sqlSchemaRelationships, + }); + + // declare them in that order + const sortedCodePerDomainObject: string[] = order.map( + (dobjName) => + dobjToCodeMap[dobjName] ?? + (() => { + throw new UnexpectedCodePathError( + 'could not find code for dobj. how is that possible?', + { dobjName }, ); - if (someReferencedDomainObjectIsNotAlreadyIncluded) continue; // cant include it yet - sortedCodePerDomainObject.push(thisCode); - } - timesLooped += 1; - if (timesLooped > codePerDomainObject.length * 20) - throw new UnexpectedCodePathDetectedError({ - reason: - 'infinite loop prevention error in defining sql schema control code files for domain objects', - }); - } + })(), + ); // define the content of the config file const content = sortedCodePerDomainObject.join('\n\n');