add types and schemas
This commit is contained in:
26
bun.lock
26
bun.lock
@@ -9,7 +9,9 @@
|
|||||||
"@mikro-orm/postgresql": "6.5.9",
|
"@mikro-orm/postgresql": "6.5.9",
|
||||||
"compression": "1.8.1",
|
"compression": "1.8.1",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
|
"date-fns": "4.1.0",
|
||||||
"express": "5.1.0",
|
"express": "5.1.0",
|
||||||
|
"file-type": "21.0.0",
|
||||||
"helmet": "8.1.0",
|
"helmet": "8.1.0",
|
||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "0.2.2",
|
||||||
"zod": "4.1.12",
|
"zod": "4.1.12",
|
||||||
@@ -25,6 +27,8 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
|
"@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="],
|
||||||
|
|
||||||
"@jercle/yargonaut": ["@jercle/yargonaut@1.1.5", "", { "dependencies": { "chalk": "^4.1.2", "figlet": "^1.5.2", "parent-require": "^1.0.0" } }, "sha512-zBp2myVvBHp1UaJsNTyS6q4UDKT7eRiqTS4oNTS6VQMd6mpxYOdbeK4pY279cDCdakGy6hG0J3ejoXZVsPwHqw=="],
|
"@jercle/yargonaut": ["@jercle/yargonaut@1.1.5", "", { "dependencies": { "chalk": "^4.1.2", "figlet": "^1.5.2", "parent-require": "^1.0.0" } }, "sha512-zBp2myVvBHp1UaJsNTyS6q4UDKT7eRiqTS4oNTS6VQMd6mpxYOdbeK4pY279cDCdakGy6hG0J3ejoXZVsPwHqw=="],
|
||||||
|
|
||||||
"@mikro-orm/cli": ["@mikro-orm/cli@6.5.9", "", { "dependencies": { "@jercle/yargonaut": "1.1.5", "@mikro-orm/core": "6.5.9", "@mikro-orm/knex": "6.5.9", "fs-extra": "11.3.2", "tsconfig-paths": "4.2.0", "yargs": "17.7.2" }, "bin": { "mikro-orm": "cli", "mikro-orm-esm": "esm" } }, "sha512-Jihukq7STU5ZfRdjOBSR7mzOClqkhkic7t8GF/OAoMBeHgpUc93Ug2GvSMrJaNWGg4AKtgch/cP/KGv/3QtSsQ=="],
|
"@mikro-orm/cli": ["@mikro-orm/cli@6.5.9", "", { "dependencies": { "@jercle/yargonaut": "1.1.5", "@mikro-orm/core": "6.5.9", "@mikro-orm/knex": "6.5.9", "fs-extra": "11.3.2", "tsconfig-paths": "4.2.0", "yargs": "17.7.2" }, "bin": { "mikro-orm": "cli", "mikro-orm-esm": "esm" } }, "sha512-Jihukq7STU5ZfRdjOBSR7mzOClqkhkic7t8GF/OAoMBeHgpUc93Ug2GvSMrJaNWGg4AKtgch/cP/KGv/3QtSsQ=="],
|
||||||
@@ -49,6 +53,10 @@
|
|||||||
|
|
||||||
"@rushstack/ts-command-line": ["@rushstack/ts-command-line@4.23.7", "", { "dependencies": { "@rushstack/terminal": "0.15.2", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" } }, "sha512-Gr9cB7DGe6uz5vq2wdr89WbVDKz0UeuFEn5H2CfWDe7JvjFFaiV15gi6mqDBTbHhHCWS7w8mF1h3BnIfUndqdA=="],
|
"@rushstack/ts-command-line": ["@rushstack/ts-command-line@4.23.7", "", { "dependencies": { "@rushstack/terminal": "0.15.2", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" } }, "sha512-Gr9cB7DGe6uz5vq2wdr89WbVDKz0UeuFEn5H2CfWDe7JvjFFaiV15gi6mqDBTbHhHCWS7w8mF1h3BnIfUndqdA=="],
|
||||||
|
|
||||||
|
"@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="],
|
||||||
|
|
||||||
|
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
|
||||||
|
|
||||||
"@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="],
|
"@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="],
|
||||||
|
|
||||||
"@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="],
|
"@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="],
|
||||||
@@ -139,6 +147,8 @@
|
|||||||
|
|
||||||
"dataloader": ["dataloader@2.2.3", "", {}, "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA=="],
|
"dataloader": ["dataloader@2.2.3", "", {}, "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA=="],
|
||||||
|
|
||||||
|
"date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],
|
||||||
|
|
||||||
"debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
"debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||||
|
|
||||||
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
||||||
@@ -181,8 +191,12 @@
|
|||||||
|
|
||||||
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
||||||
|
|
||||||
|
"fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
|
||||||
|
|
||||||
"figlet": ["figlet@1.9.3", "", { "dependencies": { "commander": "^14.0.0" }, "bin": { "figlet": "bin/index.js" } }, "sha512-majPgOpVtrZN1iyNGbsUP6bOtZ6eaJgg5HHh0vFvm5DJhh8dc+FJpOC4GABvMZ/A7XHAJUuJujhgUY/2jPWgMA=="],
|
"figlet": ["figlet@1.9.3", "", { "dependencies": { "commander": "^14.0.0" }, "bin": { "figlet": "bin/index.js" } }, "sha512-majPgOpVtrZN1iyNGbsUP6bOtZ6eaJgg5HHh0vFvm5DJhh8dc+FJpOC4GABvMZ/A7XHAJUuJujhgUY/2jPWgMA=="],
|
||||||
|
|
||||||
|
"file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg=="],
|
||||||
|
|
||||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||||
|
|
||||||
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
|
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
|
||||||
@@ -225,6 +239,8 @@
|
|||||||
|
|
||||||
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||||
|
|
||||||
|
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||||
|
|
||||||
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||||
|
|
||||||
"import-lazy": ["import-lazy@4.0.0", "", {}, "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw=="],
|
"import-lazy": ["import-lazy@4.0.0", "", {}, "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw=="],
|
||||||
@@ -401,6 +417,8 @@
|
|||||||
|
|
||||||
"strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
|
"strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
|
||||||
|
|
||||||
|
"strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
|
||||||
|
|
||||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||||
|
|
||||||
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||||
@@ -413,6 +431,8 @@
|
|||||||
|
|
||||||
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||||
|
|
||||||
|
"token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="],
|
||||||
|
|
||||||
"tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="],
|
"tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="],
|
||||||
|
|
||||||
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
||||||
@@ -421,6 +441,8 @@
|
|||||||
|
|
||||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
|
"uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
|
||||||
|
|
||||||
"umzug": ["umzug@3.8.2", "", { "dependencies": { "@rushstack/ts-command-line": "^4.12.2", "emittery": "^0.13.0", "fast-glob": "^3.3.2", "pony-cause": "^2.1.4", "type-fest": "^4.0.0" } }, "sha512-BEWEF8OJjTYVC56GjELeHl/1XjFejrD7aHzn+HldRJTx+pL1siBrKHZC8n4K/xL3bEzVA9o++qD1tK2CpZu4KA=="],
|
"umzug": ["umzug@3.8.2", "", { "dependencies": { "@rushstack/ts-command-line": "^4.12.2", "emittery": "^0.13.0", "fast-glob": "^3.3.2", "pony-cause": "^2.1.4", "type-fest": "^4.0.0" } }, "sha512-BEWEF8OJjTYVC56GjELeHl/1XjFejrD7aHzn+HldRJTx+pL1siBrKHZC8n4K/xL3bEzVA9o++qD1tK2CpZu4KA=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||||
@@ -451,6 +473,8 @@
|
|||||||
|
|
||||||
"@rushstack/terminal/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
|
"@rushstack/terminal/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
|
||||||
|
|
||||||
|
"@tokenizer/inflate/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|
||||||
"accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
"accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||||
|
|
||||||
"body-parser/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
"body-parser/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
@@ -481,6 +505,8 @@
|
|||||||
|
|
||||||
"send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
"send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"@tokenizer/inflate/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
"body-parser/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
"body-parser/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
"express/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
"express/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|||||||
@@ -14,7 +14,9 @@
|
|||||||
"@mikro-orm/postgresql": "6.5.9",
|
"@mikro-orm/postgresql": "6.5.9",
|
||||||
"compression": "1.8.1",
|
"compression": "1.8.1",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
|
"date-fns": "4.1.0",
|
||||||
"express": "5.1.0",
|
"express": "5.1.0",
|
||||||
|
"file-type": "21.0.0",
|
||||||
"helmet": "8.1.0",
|
"helmet": "8.1.0",
|
||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "0.2.2",
|
||||||
"zod": "4.1.12"
|
"zod": "4.1.12"
|
||||||
|
|||||||
34
src/common/schemas.ts
Normal file
34
src/common/schemas.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { isValid, parse } from "date-fns";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const timeSchema = z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not be empty.")
|
||||||
|
.transform((val, ctx) => {
|
||||||
|
const parsedDate = parse(val, "HH:mm", new Date());
|
||||||
|
if (!isValid(parsedDate)) {
|
||||||
|
ctx.issues.push({
|
||||||
|
code: "custom",
|
||||||
|
message: "Must be in 'HH:mm' format.",
|
||||||
|
input: val,
|
||||||
|
});
|
||||||
|
return z.NEVER;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const dateSchema = z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not be empty.")
|
||||||
|
.transform((val, ctx) => {
|
||||||
|
const parsedDate = parse(val, "YYYY-MM-DD", new Date());
|
||||||
|
if (!isValid(parsedDate)) {
|
||||||
|
ctx.issues.push({
|
||||||
|
code: "custom",
|
||||||
|
message: "Must be in 'YYYY-MM-DD' format.",
|
||||||
|
input: val,
|
||||||
|
});
|
||||||
|
return z.NEVER;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
});
|
||||||
@@ -15,10 +15,6 @@ export class Airline {
|
|||||||
@PrimaryKey({ type: "varchar", length: 30 })
|
@PrimaryKey({ type: "varchar", length: 30 })
|
||||||
id!: string;
|
id!: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 10 })
|
|
||||||
@Unique()
|
|
||||||
code!: string;
|
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 200 })
|
@Property({ type: "varchar", length: 200 })
|
||||||
@Unique()
|
@Unique()
|
||||||
slug!: string;
|
slug!: string;
|
||||||
@@ -26,6 +22,10 @@ export class Airline {
|
|||||||
@Property({ type: "varchar", length: 100 })
|
@Property({ type: "varchar", length: 100 })
|
||||||
name!: string;
|
name!: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 10 })
|
||||||
|
@Unique()
|
||||||
|
code!: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 100 })
|
@Property({ type: "varchar", length: 100 })
|
||||||
@Unique()
|
@Unique()
|
||||||
logo!: string;
|
logo!: string;
|
||||||
|
|||||||
@@ -16,10 +16,6 @@ export class Airport {
|
|||||||
@PrimaryKey({ type: "varchar", length: 30 })
|
@PrimaryKey({ type: "varchar", length: 30 })
|
||||||
id!: string;
|
id!: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 10 })
|
|
||||||
@Unique()
|
|
||||||
code!: string;
|
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 200 })
|
@Property({ type: "varchar", length: 200 })
|
||||||
@Unique()
|
@Unique()
|
||||||
slug!: string;
|
slug!: string;
|
||||||
@@ -27,6 +23,10 @@ export class Airport {
|
|||||||
@Property({ type: "varchar", length: 100 })
|
@Property({ type: "varchar", length: 100 })
|
||||||
name!: string;
|
name!: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 10 })
|
||||||
|
@Unique()
|
||||||
|
code!: string;
|
||||||
|
|
||||||
@ManyToOne(() => City)
|
@ManyToOne(() => City)
|
||||||
city!: Rel<City>;
|
city!: Rel<City>;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export class FlightClass {
|
|||||||
@PrimaryKey({ type: "varchar", length: 30 })
|
@PrimaryKey({ type: "varchar", length: 30 })
|
||||||
id!: string;
|
id!: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 420 })
|
@Property({ type: "varchar", length: 200 })
|
||||||
@Unique()
|
@Unique()
|
||||||
slug!: string;
|
slug!: string;
|
||||||
|
|
||||||
|
|||||||
44
src/database/entities/hotel-schedule.entity.ts
Normal file
44
src/database/entities/hotel-schedule.entity.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { Hotel } from "@/database/entities/hotel.entity";
|
||||||
|
import { PackageDetail } from "@/database/entities/package-detail.entity";
|
||||||
|
import {
|
||||||
|
Collection,
|
||||||
|
Entity,
|
||||||
|
ManyToMany,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryKey,
|
||||||
|
Property,
|
||||||
|
type Rel,
|
||||||
|
} from "@mikro-orm/core";
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class HotelSchedule {
|
||||||
|
@PrimaryKey({ type: "varchar", length: 30 })
|
||||||
|
id!: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => Hotel)
|
||||||
|
hotel!: Rel<Hotel>;
|
||||||
|
|
||||||
|
@Property({ type: "time" })
|
||||||
|
checkIn!: string;
|
||||||
|
|
||||||
|
@Property({ type: "time" })
|
||||||
|
checkOut!: string;
|
||||||
|
|
||||||
|
@Property({
|
||||||
|
type: "timestamp",
|
||||||
|
onCreate: () => new Date(),
|
||||||
|
})
|
||||||
|
createdAt!: Date;
|
||||||
|
|
||||||
|
@Property({
|
||||||
|
type: "timestamp",
|
||||||
|
onCreate: () => new Date(),
|
||||||
|
onUpdate: () => new Date(),
|
||||||
|
})
|
||||||
|
updatedAt!: Date;
|
||||||
|
|
||||||
|
// Inverse side
|
||||||
|
|
||||||
|
@ManyToMany(() => PackageDetail, (packageDetail) => packageDetail.tourHotels)
|
||||||
|
tourPackageDetails = new Collection<PackageDetail>(this);
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import { City } from "@/database/entities/city.entity";
|
import { City } from "@/database/entities/city.entity";
|
||||||
import { HotelFacility } from "@/database/entities/hotel-facility.entity";
|
import { HotelFacility } from "@/database/entities/hotel-facility.entity";
|
||||||
import { HotelImage } from "@/database/entities/hotel-image.entity";
|
import { HotelImage } from "@/database/entities/hotel-image.entity";
|
||||||
import { PackageDetail } from "@/database/entities/package-detail.entity";
|
|
||||||
import {
|
import {
|
||||||
Collection,
|
Collection,
|
||||||
Entity,
|
Entity,
|
||||||
@@ -84,13 +83,4 @@ export class Hotel {
|
|||||||
owner: true,
|
owner: true,
|
||||||
})
|
})
|
||||||
facilities = new Collection<HotelFacility>(this);
|
facilities = new Collection<HotelFacility>(this);
|
||||||
|
|
||||||
@ManyToMany(() => PackageDetail, (packageDetail) => packageDetail.tourHotels)
|
|
||||||
tourPackageDetails = new Collection<PackageDetail>(this);
|
|
||||||
|
|
||||||
@OneToMany(() => PackageDetail, (packageDetail) => packageDetail.makkahHotel)
|
|
||||||
makkahPackageDetails = new Collection<PackageDetail>(this);
|
|
||||||
|
|
||||||
@OneToMany(() => PackageDetail, (packageDetail) => packageDetail.madinahHotel)
|
|
||||||
madinahPackageDetails = new Collection<PackageDetail>(this);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FlightClass } from "@/database/entities/flight-class.entity";
|
import { FlightClass } from "@/database/entities/flight-class.entity";
|
||||||
import { Hotel } from "@/database/entities/hotel.entity";
|
import { HotelSchedule } from "@/database/entities/hotel-schedule.entity";
|
||||||
import { Package } from "@/database/entities/package.entity";
|
import { Package } from "@/database/entities/package.entity";
|
||||||
import { TransportationClass } from "@/database/entities/transportation-class.entity";
|
import { TransportationClass } from "@/database/entities/transportation-class.entity";
|
||||||
import {
|
import {
|
||||||
@@ -29,42 +29,6 @@ export class PackageDetail {
|
|||||||
@Property({ type: "date" })
|
@Property({ type: "date" })
|
||||||
departureDate!: Date;
|
departureDate!: Date;
|
||||||
|
|
||||||
@ManyToOne(() => Hotel)
|
|
||||||
makkahHotel!: Rel<Hotel>;
|
|
||||||
|
|
||||||
@ManyToOne(() => Hotel)
|
|
||||||
madinahHotel!: Rel<Hotel>;
|
|
||||||
|
|
||||||
@ManyToOne(() => TransportationClass)
|
|
||||||
transportation!: Rel<TransportationClass>;
|
|
||||||
|
|
||||||
@Property({ type: "decimal", unsigned: true })
|
|
||||||
quadPrice!: number;
|
|
||||||
|
|
||||||
@Property({ type: "decimal", unsigned: true })
|
|
||||||
triplePrice!: number;
|
|
||||||
|
|
||||||
@Property({ type: "decimal", unsigned: true })
|
|
||||||
doublePrice!: number;
|
|
||||||
|
|
||||||
@Property({ type: "decimal", nullable: true, unsigned: true })
|
|
||||||
infantPrice?: number;
|
|
||||||
|
|
||||||
@Property({
|
|
||||||
type: "timestamp",
|
|
||||||
onCreate: () => new Date(),
|
|
||||||
})
|
|
||||||
createdAt!: Date;
|
|
||||||
|
|
||||||
@Property({
|
|
||||||
type: "timestamp",
|
|
||||||
onCreate: () => new Date(),
|
|
||||||
onUpdate: () => new Date(),
|
|
||||||
})
|
|
||||||
updatedAt!: Date;
|
|
||||||
|
|
||||||
// Collections
|
|
||||||
|
|
||||||
@ManyToMany(
|
@ManyToMany(
|
||||||
() => FlightClass,
|
() => FlightClass,
|
||||||
(flightClass) => flightClass.tourPackageDetails,
|
(flightClass) => flightClass.tourPackageDetails,
|
||||||
@@ -95,9 +59,47 @@ export class PackageDetail {
|
|||||||
)
|
)
|
||||||
inboundFlightClasses = new Collection<FlightClass>(this);
|
inboundFlightClasses = new Collection<FlightClass>(this);
|
||||||
|
|
||||||
@ManyToMany(() => Hotel, (hotel) => hotel.tourPackageDetails, {
|
@ManyToMany(
|
||||||
owner: true,
|
() => HotelSchedule,
|
||||||
fixedOrder: true,
|
(hotelSchedule) => hotelSchedule.tourPackageDetails,
|
||||||
|
{
|
||||||
|
owner: true,
|
||||||
|
fixedOrder: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
tourHotels = new Collection<HotelSchedule>(this);
|
||||||
|
|
||||||
|
@ManyToOne(() => HotelSchedule)
|
||||||
|
makkahHotel!: Rel<HotelSchedule>;
|
||||||
|
|
||||||
|
@ManyToOne(() => HotelSchedule)
|
||||||
|
madinahHotel!: Rel<HotelSchedule>;
|
||||||
|
|
||||||
|
@ManyToOne(() => TransportationClass)
|
||||||
|
transportation!: Rel<TransportationClass>;
|
||||||
|
|
||||||
|
@Property({ type: "decimal", unsigned: true })
|
||||||
|
quadPrice!: number;
|
||||||
|
|
||||||
|
@Property({ type: "decimal", unsigned: true })
|
||||||
|
triplePrice!: number;
|
||||||
|
|
||||||
|
@Property({ type: "decimal", unsigned: true })
|
||||||
|
doublePrice!: number;
|
||||||
|
|
||||||
|
@Property({ type: "decimal", nullable: true, unsigned: true })
|
||||||
|
infantPrice?: number;
|
||||||
|
|
||||||
|
@Property({
|
||||||
|
type: "timestamp",
|
||||||
|
onCreate: () => new Date(),
|
||||||
})
|
})
|
||||||
tourHotels = new Collection<Hotel>(this);
|
createdAt!: Date;
|
||||||
|
|
||||||
|
@Property({
|
||||||
|
type: "timestamp",
|
||||||
|
onCreate: () => new Date(),
|
||||||
|
onUpdate: () => new Date(),
|
||||||
|
})
|
||||||
|
updatedAt!: Date;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class TransportationClass {
|
|||||||
@PrimaryKey({ type: "varchar", length: 30 })
|
@PrimaryKey({ type: "varchar", length: 30 })
|
||||||
id!: string;
|
id!: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 400 })
|
@Property({ type: "varchar", length: 200 })
|
||||||
@Unique()
|
@Unique()
|
||||||
slug!: string;
|
slug!: string;
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,6 @@
|
|||||||
"length": 30,
|
"length": 30,
|
||||||
"mappedType": "string"
|
"mappedType": "string"
|
||||||
},
|
},
|
||||||
"code": {
|
|
||||||
"name": "code",
|
|
||||||
"type": "varchar(10)",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"length": 10,
|
|
||||||
"mappedType": "string"
|
|
||||||
},
|
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"type": "varchar(200)",
|
"type": "varchar(200)",
|
||||||
@@ -46,6 +36,16 @@
|
|||||||
"length": 100,
|
"length": 100,
|
||||||
"mappedType": "string"
|
"mappedType": "string"
|
||||||
},
|
},
|
||||||
|
"code": {
|
||||||
|
"name": "code",
|
||||||
|
"type": "varchar(10)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 10,
|
||||||
|
"mappedType": "string"
|
||||||
|
},
|
||||||
"logo": {
|
"logo": {
|
||||||
"name": "logo",
|
"name": "logo",
|
||||||
"type": "varchar(100)",
|
"type": "varchar(100)",
|
||||||
@@ -104,20 +104,20 @@
|
|||||||
"indexes": [
|
"indexes": [
|
||||||
{
|
{
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"code"
|
"slug"
|
||||||
],
|
],
|
||||||
"composite": false,
|
"composite": false,
|
||||||
"keyName": "airline_code_unique",
|
"keyName": "airline_slug_unique",
|
||||||
"constraint": true,
|
"constraint": true,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"unique": true
|
"unique": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"slug"
|
"code"
|
||||||
],
|
],
|
||||||
"composite": false,
|
"composite": false,
|
||||||
"keyName": "airline_slug_unique",
|
"keyName": "airline_code_unique",
|
||||||
"constraint": true,
|
"constraint": true,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"unique": true
|
"unique": true
|
||||||
@@ -344,16 +344,6 @@
|
|||||||
"length": 30,
|
"length": 30,
|
||||||
"mappedType": "string"
|
"mappedType": "string"
|
||||||
},
|
},
|
||||||
"code": {
|
|
||||||
"name": "code",
|
|
||||||
"type": "varchar(10)",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"length": 10,
|
|
||||||
"mappedType": "string"
|
|
||||||
},
|
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"type": "varchar(200)",
|
"type": "varchar(200)",
|
||||||
@@ -374,6 +364,16 @@
|
|||||||
"length": 100,
|
"length": 100,
|
||||||
"mappedType": "string"
|
"mappedType": "string"
|
||||||
},
|
},
|
||||||
|
"code": {
|
||||||
|
"name": "code",
|
||||||
|
"type": "varchar(10)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 10,
|
||||||
|
"mappedType": "string"
|
||||||
|
},
|
||||||
"city_id": {
|
"city_id": {
|
||||||
"name": "city_id",
|
"name": "city_id",
|
||||||
"type": "varchar(30)",
|
"type": "varchar(30)",
|
||||||
@@ -410,20 +410,20 @@
|
|||||||
"indexes": [
|
"indexes": [
|
||||||
{
|
{
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"code"
|
"slug"
|
||||||
],
|
],
|
||||||
"composite": false,
|
"composite": false,
|
||||||
"keyName": "airport_code_unique",
|
"keyName": "airport_slug_unique",
|
||||||
"constraint": true,
|
"constraint": true,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"unique": true
|
"unique": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"slug"
|
"code"
|
||||||
],
|
],
|
||||||
"composite": false,
|
"composite": false,
|
||||||
"keyName": "airport_slug_unique",
|
"keyName": "airport_code_unique",
|
||||||
"constraint": true,
|
"constraint": true,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"unique": true
|
"unique": true
|
||||||
@@ -697,12 +697,12 @@
|
|||||||
},
|
},
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"type": "varchar(420)",
|
"type": "varchar(200)",
|
||||||
"unsigned": false,
|
"unsigned": false,
|
||||||
"autoincrement": false,
|
"autoincrement": false,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"length": 420,
|
"length": 200,
|
||||||
"mappedType": "string"
|
"mappedType": "string"
|
||||||
},
|
},
|
||||||
"flight_id": {
|
"flight_id": {
|
||||||
@@ -1283,6 +1283,100 @@
|
|||||||
},
|
},
|
||||||
"nativeEnums": {}
|
"nativeEnums": {}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 30,
|
||||||
|
"mappedType": "string"
|
||||||
|
},
|
||||||
|
"hotel_id": {
|
||||||
|
"name": "hotel_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 30,
|
||||||
|
"mappedType": "string"
|
||||||
|
},
|
||||||
|
"check_in": {
|
||||||
|
"name": "check_in",
|
||||||
|
"type": "time(0)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 0,
|
||||||
|
"mappedType": "time"
|
||||||
|
},
|
||||||
|
"check_out": {
|
||||||
|
"name": "check_out",
|
||||||
|
"type": "time(0)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 0,
|
||||||
|
"mappedType": "time"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "hotel_schedule",
|
||||||
|
"schema": "public",
|
||||||
|
"indexes": [
|
||||||
|
{
|
||||||
|
"keyName": "hotel_schedule_pkey",
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": true,
|
||||||
|
"primary": true,
|
||||||
|
"unique": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"checks": [],
|
||||||
|
"foreignKeys": {
|
||||||
|
"hotel_schedule_hotel_id_foreign": {
|
||||||
|
"constraintName": "hotel_schedule_hotel_id_foreign",
|
||||||
|
"columnNames": [
|
||||||
|
"hotel_id"
|
||||||
|
],
|
||||||
|
"localTableName": "public.hotel_schedule",
|
||||||
|
"referencedColumnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"referencedTableName": "public.hotel",
|
||||||
|
"updateRule": "cascade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nativeEnums": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
@@ -1525,12 +1619,12 @@
|
|||||||
},
|
},
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"type": "varchar(400)",
|
"type": "varchar(200)",
|
||||||
"unsigned": false,
|
"unsigned": false,
|
||||||
"autoincrement": false,
|
"autoincrement": false,
|
||||||
"primary": false,
|
"primary": false,
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"length": 400,
|
"length": 200,
|
||||||
"mappedType": "string"
|
"mappedType": "string"
|
||||||
},
|
},
|
||||||
"transportation_id": {
|
"transportation_id": {
|
||||||
@@ -1830,7 +1924,7 @@
|
|||||||
"referencedColumnNames": [
|
"referencedColumnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"referencedTableName": "public.hotel",
|
"referencedTableName": "public.hotel_schedule",
|
||||||
"updateRule": "cascade"
|
"updateRule": "cascade"
|
||||||
},
|
},
|
||||||
"package_detail_madinah_hotel_id_foreign": {
|
"package_detail_madinah_hotel_id_foreign": {
|
||||||
@@ -1842,7 +1936,7 @@
|
|||||||
"referencedColumnNames": [
|
"referencedColumnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"referencedTableName": "public.hotel",
|
"referencedTableName": "public.hotel_schedule",
|
||||||
"updateRule": "cascade"
|
"updateRule": "cascade"
|
||||||
},
|
},
|
||||||
"package_detail_transportation_id_foreign": {
|
"package_detail_transportation_id_foreign": {
|
||||||
@@ -1881,8 +1975,8 @@
|
|||||||
"length": 30,
|
"length": 30,
|
||||||
"mappedType": "string"
|
"mappedType": "string"
|
||||||
},
|
},
|
||||||
"hotel_id": {
|
"hotel_schedule_id": {
|
||||||
"name": "hotel_id",
|
"name": "hotel_schedule_id",
|
||||||
"type": "varchar(30)",
|
"type": "varchar(30)",
|
||||||
"unsigned": false,
|
"unsigned": false,
|
||||||
"autoincrement": false,
|
"autoincrement": false,
|
||||||
@@ -1921,16 +2015,16 @@
|
|||||||
"deleteRule": "cascade",
|
"deleteRule": "cascade",
|
||||||
"updateRule": "cascade"
|
"updateRule": "cascade"
|
||||||
},
|
},
|
||||||
"package_detail_tour_hotels_hotel_id_foreign": {
|
"package_detail_tour_hotels_hotel_schedule_id_foreign": {
|
||||||
"constraintName": "package_detail_tour_hotels_hotel_id_foreign",
|
"constraintName": "package_detail_tour_hotels_hotel_schedule_id_foreign",
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"hotel_id"
|
"hotel_schedule_id"
|
||||||
],
|
],
|
||||||
"localTableName": "public.package_detail_tour_hotels",
|
"localTableName": "public.package_detail_tour_hotels",
|
||||||
"referencedColumnNames": [
|
"referencedColumnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"referencedTableName": "public.hotel",
|
"referencedTableName": "public.hotel_schedule",
|
||||||
"deleteRule": "cascade",
|
"deleteRule": "cascade",
|
||||||
"updateRule": "cascade"
|
"updateRule": "cascade"
|
||||||
}
|
}
|
||||||
|
|||||||
91
src/database/migrations/Migration20251108053920.ts
Normal file
91
src/database/migrations/Migration20251108053920.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { Migration } from "@mikro-orm/migrations";
|
||||||
|
|
||||||
|
export class Migration20251108053920 extends Migration {
|
||||||
|
override async up(): Promise<void> {
|
||||||
|
this.addSql(
|
||||||
|
`create table "hotel_schedule" ("id" varchar(30) not null, "hotel_id" varchar(30) not null, "check_in" time(0) not null, "check_out" time(0) not null, "created_at" timestamptz not null, "updated_at" timestamptz not null, constraint "hotel_schedule_pkey" primary key ("id"));`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "hotel_schedule" add constraint "hotel_schedule_hotel_id_foreign" foreign key ("hotel_id") references "hotel" ("id") on update cascade;`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" drop constraint "package_detail_makkah_hotel_id_foreign";`,
|
||||||
|
);
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" drop constraint "package_detail_madinah_hotel_id_foreign";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail_tour_hotels" drop constraint "package_detail_tour_hotels_hotel_id_foreign";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "flight_class" alter column "slug" type varchar(200) using ("slug"::varchar(200));`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "transportation_class" alter column "slug" type varchar(200) using ("slug"::varchar(200));`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" add constraint "package_detail_makkah_hotel_id_foreign" foreign key ("makkah_hotel_id") references "hotel_schedule" ("id") on update cascade;`,
|
||||||
|
);
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" add constraint "package_detail_madinah_hotel_id_foreign" foreign key ("madinah_hotel_id") references "hotel_schedule" ("id") on update cascade;`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail_tour_hotels" rename column "hotel_id" to "hotel_schedule_id";`,
|
||||||
|
);
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail_tour_hotels" add constraint "package_detail_tour_hotels_hotel_schedule_id_foreign" foreign key ("hotel_schedule_id") references "hotel_schedule" ("id") on update cascade on delete cascade;`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async down(): Promise<void> {
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" drop constraint "package_detail_makkah_hotel_id_foreign";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" drop constraint "package_detail_madinah_hotel_id_foreign";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail_tour_hotels" drop constraint "package_detail_tour_hotels_hotel_schedule_id_foreign";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(`drop table if exists "hotel_schedule" cascade;`);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" drop constraint "package_detail_makkah_hotel_id_foreign";`,
|
||||||
|
);
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" drop constraint "package_detail_madinah_hotel_id_foreign";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "flight_class" alter column "slug" type varchar(420) using ("slug"::varchar(420));`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "transportation_class" alter column "slug" type varchar(400) using ("slug"::varchar(400));`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" add constraint "package_detail_makkah_hotel_id_foreign" foreign key ("makkah_hotel_id") references "hotel" ("id") on update cascade;`,
|
||||||
|
);
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail" add constraint "package_detail_madinah_hotel_id_foreign" foreign key ("madinah_hotel_id") references "hotel" ("id") on update cascade;`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail_tour_hotels" rename column "hotel_schedule_id" to "hotel_id";`,
|
||||||
|
);
|
||||||
|
this.addSql(
|
||||||
|
`alter table "package_detail_tour_hotels" add constraint "package_detail_tour_hotels_hotel_id_foreign" foreign key ("hotel_id") references "hotel" ("id") on update cascade on delete cascade;`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/modules/airline/airline.schemas.ts
Normal file
29
src/modules/airline/airline.schemas.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const airlineRequestSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
code: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(10, "Max 10 characters."),
|
||||||
|
logo: z.base64("Must be base64 string.").nonempty("Must not empty."),
|
||||||
|
skytrax_rating: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.min(1, "Minimum 1.")
|
||||||
|
.max(5, "Maximum 5."),
|
||||||
|
skytrax_type: z.enum(
|
||||||
|
["full_service", "low_cost"],
|
||||||
|
"Must be either 'full_service' or 'low_cost'.",
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const airlineQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
21
src/modules/airline/airline.types.ts
Normal file
21
src/modules/airline/airline.types.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type {
|
||||||
|
airlineQuerySchema,
|
||||||
|
airlineRequestSchema,
|
||||||
|
} from "@/modules/airline/airline.schemas";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type AirlineRequest = z.infer<typeof airlineRequestSchema>;
|
||||||
|
|
||||||
|
export type AirlineQuery = z.infer<typeof airlineQuerySchema>;
|
||||||
|
|
||||||
|
export type AirlineResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
logo: string;
|
||||||
|
skytrax_rating: number;
|
||||||
|
skytrax_type: "full_service" | "low_cost";
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
23
src/modules/airport/airport.schemas.ts
Normal file
23
src/modules/airport/airport.schemas.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const airportRequestSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
code: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(10, "Max 10 characters."),
|
||||||
|
city_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const airportQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
20
src/modules/airport/airport.types.ts
Normal file
20
src/modules/airport/airport.types.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import type {
|
||||||
|
airportQuerySchema,
|
||||||
|
airportRequestSchema,
|
||||||
|
} from "@/modules/airport/airport.schemas";
|
||||||
|
import type { CityResponse } from "@/modules/city/city.types";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type AirportRequest = z.infer<typeof airportRequestSchema>;
|
||||||
|
|
||||||
|
export type AirportQuery = z.infer<typeof airportQuerySchema>;
|
||||||
|
|
||||||
|
export type AirportResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
city: CityResponse;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
19
src/modules/city/city.schemas.ts
Normal file
19
src/modules/city/city.schemas.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const cityRequestSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
country_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const cityQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
19
src/modules/city/city.types.ts
Normal file
19
src/modules/city/city.types.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import type {
|
||||||
|
cityQuerySchema,
|
||||||
|
cityRequestSchema,
|
||||||
|
} from "@/modules/city/city.schemas";
|
||||||
|
import type { CountryResponse } from "@/modules/country/country.types";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type CityRequest = z.infer<typeof cityRequestSchema>;
|
||||||
|
|
||||||
|
export type CityQuery = z.infer<typeof cityQuerySchema>;
|
||||||
|
|
||||||
|
export type CityResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
country: CountryResponse;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
15
src/modules/country/country.schemas.ts
Normal file
15
src/modules/country/country.schemas.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const countryRequestSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const countryQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
17
src/modules/country/country.types.ts
Normal file
17
src/modules/country/country.types.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type {
|
||||||
|
countryQuerySchema,
|
||||||
|
countryRequestSchema,
|
||||||
|
} from "@/modules/country/country.schemas";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type CountryRequest = z.infer<typeof countryRequestSchema>;
|
||||||
|
|
||||||
|
export type CountryQuery = z.infer<typeof countryQuerySchema>;
|
||||||
|
|
||||||
|
export type CountryResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
83
src/modules/flight/flight.schemas.ts
Normal file
83
src/modules/flight/flight.schemas.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import { timeSchema } from "@/common/schemas";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const flightRequestSchema = z.object({
|
||||||
|
airline_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
number: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
departure_airport_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
departure_terminal: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.max(100, "Max 100 characters.")
|
||||||
|
.nullable(),
|
||||||
|
departure_gate: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.max(100, "Max 100 characters.")
|
||||||
|
.nullable(),
|
||||||
|
departure_time: timeSchema,
|
||||||
|
arrival_airport_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
arrival_terminal: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.max(100, "Max 100 characters.")
|
||||||
|
.nullable(),
|
||||||
|
arrival_gate: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.max(100, "Max 100 characters.")
|
||||||
|
.nullable(),
|
||||||
|
duration: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
aircraft: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const flightClassRequestSchema = z.object({
|
||||||
|
class: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
seat_layout: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(10, "Max 10 characters."),
|
||||||
|
baggage: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
cabin_baggage: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const flightQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(220, "Max 220 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const flightClassQuerySchema = z.object({
|
||||||
|
flight_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(220, "Max 220 characters."),
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(420, "Max 420 characters."),
|
||||||
|
});
|
||||||
48
src/modules/flight/flight.types.ts
Normal file
48
src/modules/flight/flight.types.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import type { AirlineResponse } from "@/modules/airline/airline.types";
|
||||||
|
import type { AirportResponse } from "@/modules/airport/airport.types";
|
||||||
|
import type {
|
||||||
|
flightClassQuerySchema,
|
||||||
|
flightClassRequestSchema,
|
||||||
|
flightQuerySchema,
|
||||||
|
flightRequestSchema,
|
||||||
|
} from "@/modules/flight/flight.schemas";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type FlightRequest = z.infer<typeof flightRequestSchema>;
|
||||||
|
|
||||||
|
export type FlightClassRequest = z.infer<typeof flightClassRequestSchema>;
|
||||||
|
|
||||||
|
export type FlightQuery = z.infer<typeof flightQuerySchema>;
|
||||||
|
|
||||||
|
export type FlightClassQuery = z.infer<typeof flightClassQuerySchema>;
|
||||||
|
|
||||||
|
export type FlightResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
airline: AirlineResponse;
|
||||||
|
number: number;
|
||||||
|
departure_airport: AirportResponse;
|
||||||
|
departure_terminal: string | null;
|
||||||
|
departure_gate: string | null;
|
||||||
|
departure_time: string;
|
||||||
|
arrival_airport: AirportResponse;
|
||||||
|
arrival_terminal: string | null;
|
||||||
|
arrival_gate: string | null;
|
||||||
|
arrival_time: string;
|
||||||
|
duration: number;
|
||||||
|
aircraft: string;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FlightClassResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
flight: FlightResponse;
|
||||||
|
class: string;
|
||||||
|
seat_layout: string;
|
||||||
|
baggage: number;
|
||||||
|
cabin_baggage: number;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
96
src/modules/hotel/hotel.schemas.ts
Normal file
96
src/modules/hotel/hotel.schemas.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const hotelFacilityRequestSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
icon: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hotelRequestSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
city_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
star: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.min(1, "Minimum 1.")
|
||||||
|
.max(7, "Maximum 7."),
|
||||||
|
images: z
|
||||||
|
.array(
|
||||||
|
z.base64("Must be base64 string.").nonempty("Must not empty."),
|
||||||
|
"Must be array.",
|
||||||
|
)
|
||||||
|
.nonempty("Must not empty."),
|
||||||
|
google_maps_link: z
|
||||||
|
.url("Must be valid string URL.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(500, "Max 500 characters."),
|
||||||
|
google_maps_embed: z
|
||||||
|
.url("Must be valid string URL.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(500, "Max 500 characters."),
|
||||||
|
google_reviews_link: z
|
||||||
|
.url("Must be valid string URL.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(500, "Max 500 characters."),
|
||||||
|
description: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(1000, "Max 1000 characters."),
|
||||||
|
facility_slugs: z
|
||||||
|
.array(
|
||||||
|
z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
"Must be array.",
|
||||||
|
)
|
||||||
|
.nonempty("Must not empty."),
|
||||||
|
address: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
landmark: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
distance_to_landmark: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
food_type: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
food_amount: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
food_menu: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hotelFacilityQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hotelQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
45
src/modules/hotel/hotel.types.ts
Normal file
45
src/modules/hotel/hotel.types.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import type { CityResponse } from "@/modules/city/city.types";
|
||||||
|
import type {
|
||||||
|
hotelFacilityRequestSchema,
|
||||||
|
hotelQuerySchema,
|
||||||
|
hotelRequestSchema,
|
||||||
|
} from "@/modules/hotel/hotel.schemas";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type HotelFacilityRequest = z.infer<typeof hotelFacilityRequestSchema>;
|
||||||
|
|
||||||
|
export type HotelRequest = z.infer<typeof hotelRequestSchema>;
|
||||||
|
|
||||||
|
export type HotelFacilityQuery = z.infer<typeof hotelFacilityRequestSchema>;
|
||||||
|
|
||||||
|
export type HotelQuery = z.infer<typeof hotelQuerySchema>;
|
||||||
|
|
||||||
|
export type HotelFacilityResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
icon: string;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HotelResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
city: CityResponse;
|
||||||
|
star: number;
|
||||||
|
google_maps_link: string;
|
||||||
|
google_maps_embed: string;
|
||||||
|
google_reviews_link: string;
|
||||||
|
description: string;
|
||||||
|
facilities: HotelFacilityResponse[];
|
||||||
|
address: string;
|
||||||
|
landmark: string;
|
||||||
|
distance_to_landmark: number;
|
||||||
|
food_type: string;
|
||||||
|
food_amount: number;
|
||||||
|
food_menu: string;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
122
src/modules/package/package.schemas.ts
Normal file
122
src/modules/package/package.schemas.ts
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import { dateSchema, timeSchema } from "@/common/schemas";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const packageRequestSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
type: z.enum(["reguler", "plus"], "Must be either 'reguler' or 'plus'."),
|
||||||
|
class: z.enum(
|
||||||
|
["silver", "gold", "platinum"],
|
||||||
|
"Must be either 'silver', 'gold', or 'platinum'.",
|
||||||
|
),
|
||||||
|
thumbnail: z.base64("Must be base64 string.").nonempty("Must not empty."),
|
||||||
|
use_fast_train: z.boolean("Must be boolean."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const packageDetailRequestSchema = z.object({
|
||||||
|
departure_date: dateSchema,
|
||||||
|
tour_flight_slugs: z
|
||||||
|
.array(
|
||||||
|
z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(420, "Max 420 characters."),
|
||||||
|
"Must be array.",
|
||||||
|
)
|
||||||
|
.nonempty("Must not empty."),
|
||||||
|
outbound_flight_slugs: z
|
||||||
|
.array(
|
||||||
|
z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(420, "Max 420 characters."),
|
||||||
|
"Must be array.",
|
||||||
|
)
|
||||||
|
.nonempty("Must not empty."),
|
||||||
|
inbound_flight_slugs: z
|
||||||
|
.array(
|
||||||
|
z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(420, "Max 420 characters."),
|
||||||
|
"Must be array.",
|
||||||
|
)
|
||||||
|
.nonempty("Must not empty."),
|
||||||
|
tour_hotels: z.array(
|
||||||
|
z.object(
|
||||||
|
{
|
||||||
|
hotel_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
check_in: timeSchema,
|
||||||
|
check_out: timeSchema,
|
||||||
|
},
|
||||||
|
"Must be object.",
|
||||||
|
),
|
||||||
|
"Must be array.",
|
||||||
|
),
|
||||||
|
makkah_hotel: z.object(
|
||||||
|
{
|
||||||
|
hotel_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
check_in: timeSchema,
|
||||||
|
check_out: timeSchema,
|
||||||
|
},
|
||||||
|
"Must be object.",
|
||||||
|
),
|
||||||
|
madinah_hotel: z.object(
|
||||||
|
{
|
||||||
|
hotel_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
check_in: timeSchema,
|
||||||
|
check_out: timeSchema,
|
||||||
|
},
|
||||||
|
"Must be object.",
|
||||||
|
),
|
||||||
|
transportation_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
quad_price: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
triple_price: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
double_price: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
infant_price: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive.")
|
||||||
|
.nullable(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const packageQuerySchema = z.object({
|
||||||
|
detail_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const packageDetailQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
56
src/modules/package/package.types.ts
Normal file
56
src/modules/package/package.types.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import type { FlightClassResponse } from "@/modules/flight/flight.types";
|
||||||
|
import type { HotelResponse } from "@/modules/hotel/hotel.types";
|
||||||
|
import type {
|
||||||
|
packageDetailQuerySchema,
|
||||||
|
packageDetailRequestSchema,
|
||||||
|
packageQuerySchema,
|
||||||
|
packageRequestSchema,
|
||||||
|
} from "@/modules/package/package.schemas";
|
||||||
|
import type { TransportationClassResponse } from "@/modules/transportation/transportation.types";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type PackageRequest = z.infer<typeof packageRequestSchema>;
|
||||||
|
|
||||||
|
export type PackageDetailRequest = z.infer<typeof packageDetailRequestSchema>;
|
||||||
|
|
||||||
|
export type PackageQuery = z.infer<typeof packageQuerySchema>;
|
||||||
|
|
||||||
|
export type PackageDetailQuery = z.infer<typeof packageDetailQuerySchema>;
|
||||||
|
|
||||||
|
export type PackageResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
type: "reguler" | "plus";
|
||||||
|
class: "silver" | "gold" | "platinum";
|
||||||
|
thumbnail: string;
|
||||||
|
use_fast_train: boolean;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PackageHotelResponse = {
|
||||||
|
hotel: HotelResponse;
|
||||||
|
check_in: string;
|
||||||
|
check_out: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PackageDetailResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
package: PackageResponse;
|
||||||
|
departure_date: string;
|
||||||
|
tour_flights: FlightClassResponse[];
|
||||||
|
outbound_flights: FlightClassResponse[];
|
||||||
|
inbound_flights: FlightClassResponse[];
|
||||||
|
tour_hotels: PackageHotelResponse[];
|
||||||
|
makkah_hotel: PackageHotelResponse;
|
||||||
|
medina_hotel: PackageHotelResponse;
|
||||||
|
transportation: TransportationClassResponse;
|
||||||
|
quad_price: number;
|
||||||
|
triple_price: number;
|
||||||
|
double_price: number;
|
||||||
|
infant_price: number | null;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
47
src/modules/transportation/transportation.schemas.ts
Normal file
47
src/modules/transportation/transportation.schemas.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const transportationRequestSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
type: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const transportationClassRequestSchema = z.object({
|
||||||
|
class: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
total_seats: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
images: z
|
||||||
|
.array(
|
||||||
|
z.base64("Must be base64 string.").nonempty("Must not empty."),
|
||||||
|
"Must be array.",
|
||||||
|
)
|
||||||
|
.nonempty("Must not empty."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const transportationQuerySchema = z.object({
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const transportationClassQuerySchema = z.object({
|
||||||
|
transportation_slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(200, "Max 200 characters."),
|
||||||
|
slug: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(400, "Max 400 characters."),
|
||||||
|
});
|
||||||
38
src/modules/transportation/transportation.types.ts
Normal file
38
src/modules/transportation/transportation.types.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import type {
|
||||||
|
transportationClassQuerySchema,
|
||||||
|
transportationClassRequestSchema,
|
||||||
|
transportationQuerySchema,
|
||||||
|
transportationRequestSchema,
|
||||||
|
} from "@/modules/transportation/transportation.schemas";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type TransportationRequest = z.infer<typeof transportationRequestSchema>;
|
||||||
|
|
||||||
|
export type TransportationClassRequest = z.infer<
|
||||||
|
typeof transportationClassRequestSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type TransportationQuery = z.infer<typeof transportationQuerySchema>;
|
||||||
|
|
||||||
|
export type TransportationClassQuery = z.infer<
|
||||||
|
typeof transportationClassQuerySchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type TransportationResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TransportationClassResponse = {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
transportation: TransportationResponse;
|
||||||
|
class: string;
|
||||||
|
total_seats: number;
|
||||||
|
images: string[];
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user