From 08a9d5ec087499cd75bcdeb801f5a15317dd567a Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 10:55:59 -0800 Subject: [PATCH 01/20] Initial commit and created branch for module work --- package-lock.json | 258 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +- 2 files changed, 261 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 1e3d92c1..6f0ead1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -141,6 +141,11 @@ "concat-map": "0.0.1" } }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -298,6 +303,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -426,6 +441,11 @@ "once": "^1.4.0" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, "escape-goat": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", @@ -437,6 +457,11 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -510,6 +535,11 @@ "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -519,6 +549,11 @@ "pump": "^3.0.0" } }, + "getopts": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", + "integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==" + }, "glob-parent": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", @@ -562,6 +597,14 @@ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -629,6 +672,11 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -652,6 +700,14 @@ "ci-info": "^2.0.0" } }, + "is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "requires": { + "has": "^1.0.3" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -728,6 +784,41 @@ "json-buffer": "3.0.0" } }, + "knex": { + "version": "0.95.14", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.95.14.tgz", + "integrity": "sha512-j4qLjWySrC/JRRVtOpoR2LcS1yBOsd7Krc6mEukPvmTDX/w11pD52Pq9FYR56/kLXGeAV8jFdWBjsZFi1mscWg==", + "requires": { + "colorette": "2.0.16", + "commander": "^7.1.0", + "debug": "4.3.2", + "escalade": "^3.1.1", + "esm": "^3.2.25", + "getopts": "2.2.5", + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.5.0", + "rechoir": "0.7.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.1", + "tildify": "2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -737,6 +828,11 @@ "package-json": "^6.3.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -923,22 +1019,109 @@ } } }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pg": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", + "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.4.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", + "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==" + }, + "pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", + "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "requires": { + "split2": "^3.1.1" + } + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", @@ -1012,6 +1195,16 @@ "strip-json-comments": "~2.0.1" } }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "readdirp": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", @@ -1021,6 +1214,14 @@ "picomatch": "^2.2.1" } }, + "rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "requires": { + "resolve": "^1.9.0" + } + }, "registry-auth-token": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", @@ -1039,6 +1240,20 @@ "rc": "^1.2.8" } }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + }, "responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -1130,6 +1345,14 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1175,6 +1398,21 @@ } } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -1199,12 +1437,22 @@ "has-flag": "^3.0.0" } }, + "tarn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", + "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==" + }, "term-size": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", "dev": true }, + "tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" + }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", @@ -1302,6 +1550,11 @@ "prepend-http": "^2.0.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -1344,6 +1597,11 @@ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" } } } diff --git a/package.json b/package.json index 735d2834..274aa4d9 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "author": "", "license": "ISC", "dependencies": { - "express": "^4.17.1" + "express": "^4.17.1", + "knex": "^0.95.14", + "pg": "^8.7.1" }, "devDependencies": { "nodemon": "^2.0.6" From 82970dfe005f72307dfff99e3904635c4bf3b29e Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 11:13:48 -0800 Subject: [PATCH 02/20] initialized knex config file --- knexfile.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 knexfile.js diff --git a/knexfile.js b/knexfile.js new file mode 100644 index 00000000..860409e7 --- /dev/null +++ b/knexfile.js @@ -0,0 +1,50 @@ +// Update with your config settings. + +module.exports = { + development: { + client: "postgresql", + connection: "", + }, + + // test: { + // client: "postgresql", + // pool: { min: 1, max: 5 }, + // connection: { + // database: "db_test", + // user: "username_test", + // password: "password_test", + // }, + // }, + + // staging: { + // client: "postgresql", + // connection: { + // database: "my_db", + // user: "username", + // password: "password", + // }, + // pool: { + // min: 2, + // max: 10, + // }, + // migrations: { + // tableName: "knex_migrations", + // }, + // }, + + // production: { + // client: "postgresql", + // connection: { + // database: "my_db", + // user: "username", + // password: "password", + // }, + // pool: { + // min: 2, + // max: 10, + // }, + // migrations: { + // tableName: "knex_migrations", + // }, + // }, +}; From 0bcf73c74aed98b4a11e5b93f9be44ceebb7f72a Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 11:20:55 -0800 Subject: [PATCH 03/20] Imported connection from EV --- knexfile.js | 4 +++- package-lock.json | 5 +++++ package.json | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/knexfile.js b/knexfile.js index 860409e7..9b519366 100644 --- a/knexfile.js +++ b/knexfile.js @@ -1,9 +1,11 @@ // Update with your config settings. +const dotenv = require("dotenv").config(); +const { DATABASE_URL } = process.env; module.exports = { development: { client: "postgresql", - connection: "", + connection: DATABASE_URL, }, // test: { diff --git a/package-lock.json b/package-lock.json index 6f0ead1d..e8962904 100644 --- a/package-lock.json +++ b/package-lock.json @@ -410,6 +410,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", diff --git a/package.json b/package.json index 274aa4d9..17b3c73c 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "author": "", "license": "ISC", "dependencies": { + "dotenv": "^10.0.0", "express": "^4.17.1", "knex": "^0.95.14", "pg": "^8.7.1" From ea7f136d72714a2a4f25e110041d1c5575a5813c Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 11:26:19 -0800 Subject: [PATCH 04/20] Setup a connection file for knex to configure the development environment --- src/db/connection.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/db/connection.js diff --git a/src/db/connection.js b/src/db/connection.js new file mode 100644 index 00000000..25733ec1 --- /dev/null +++ b/src/db/connection.js @@ -0,0 +1,5 @@ +const env = process.env.NODE_ENV || "development"; +const config = require("../../knexfile")[env]; +const knex = require("knex")(config); + +module.exports = knex; From 5693a47e759d874e915b86a5fb1bac7b3735dcd2 Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 13:37:49 -0800 Subject: [PATCH 05/20] Created suppliers migrations file and config --- knexfile.js | 4 ++++ .../20211204211512_createSuppliersTable.js | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/db/migrations/20211204211512_createSuppliersTable.js diff --git a/knexfile.js b/knexfile.js index 9b519366..3626f2d0 100644 --- a/knexfile.js +++ b/knexfile.js @@ -1,4 +1,5 @@ // Update with your config settings. +const path = require("path"); const dotenv = require("dotenv").config(); const { DATABASE_URL } = process.env; @@ -6,6 +7,9 @@ module.exports = { development: { client: "postgresql", connection: DATABASE_URL, + migrations: { + directory: path.join(__dirname, "src", "db", "migrations"), + }, }, // test: { diff --git a/src/db/migrations/20211204211512_createSuppliersTable.js b/src/db/migrations/20211204211512_createSuppliersTable.js new file mode 100644 index 00000000..846b5413 --- /dev/null +++ b/src/db/migrations/20211204211512_createSuppliersTable.js @@ -0,0 +1,23 @@ +exports.up = function (knex) { + return knex.schema.createTable("suppliers", (table) => { + table.increments("supplier_id").primary(); // sets supplier_id as the primary key + table.string("supplier_name"); + table.string("supplier_address_line_1"); + table.string("supplier_address_line_2"); + table.string("supplier_city"); + table.string("supplier_state"); + table.string("supplier_zip"); + table.string("supplier_phone"); + table.string("supplier_email"); + table.text("supplier_notes"); + table.string("supplier_type_of_goods"); + table.timestamps(true, true); // Adds `created_at` and `updated_at` columns; + // passing `true` as the first argument sets the columns to be a timestamp type + // while passing `true` as the second argument sets those columns to be non-nullable + // and to use the current timestamp by default + }); +}; + +exports.down = function (knex) { + return knex.schema.dropTable("suppliers"); +}; From 5f41ebdc13c8d8fcbf092eb8da36ff59528cec1f Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 13:43:25 -0800 Subject: [PATCH 06/20] Created migrations file for the products table --- .../20211204213838_createProductsTable.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/db/migrations/20211204213838_createProductsTable.js diff --git a/src/db/migrations/20211204213838_createProductsTable.js b/src/db/migrations/20211204213838_createProductsTable.js new file mode 100644 index 00000000..d459773a --- /dev/null +++ b/src/db/migrations/20211204213838_createProductsTable.js @@ -0,0 +1,22 @@ +exports.up = function (knex) { + return knex.schema.createTable("products", (table) => { + table.increments("product_id").primary(); // Sets `product_id` as the primary key + table.string("product_sku"); + table.string("product_name"); + table.text("product_description"); + table.integer("product_quantity_in_stock"); + table.decimal("product_weight_in_lbs"); + table.integer("supplier_id").unsigned().notNullable(); + // Links the product to the supoplier table + table + .foreign("supplier_id") + .references("supplier_id") + .inTable("suppliers") + .onDelete("cascade"); // If the supplier is deleted, also deletes all products that are associated with the supplier + table.timestamps(true, true); + }); +}; + +exports.down = function (knex) { + return knex.schema.dropTable("products"); +}; From a208685dbd0557bba6ea8d20708080f57d3e806b Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 13:46:18 -0800 Subject: [PATCH 07/20] Created migrations file for the categories table --- .../20211204214404_createCategoriesTable.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/db/migrations/20211204214404_createCategoriesTable.js diff --git a/src/db/migrations/20211204214404_createCategoriesTable.js b/src/db/migrations/20211204214404_createCategoriesTable.js new file mode 100644 index 00000000..81345255 --- /dev/null +++ b/src/db/migrations/20211204214404_createCategoriesTable.js @@ -0,0 +1,12 @@ +exports.up = function (knex) { + return knex.schema.createTable("categories", (table) => { + table.increments("category_id").primary(); + table.string("category_name"); + table.text("category_description"); + table.timestamps(true, true); + }); +}; + +exports.down = function (knex) { + return knex.schema.dropTable("categories"); +}; From be43ea0be259d974193488e92422c3586a52f8ec Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 13:48:26 -0800 Subject: [PATCH 08/20] Created migrations file for the products_categories table --- ...204214624_createProductsCategoriesTable.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/db/migrations/20211204214624_createProductsCategoriesTable.js diff --git a/src/db/migrations/20211204214624_createProductsCategoriesTable.js b/src/db/migrations/20211204214624_createProductsCategoriesTable.js new file mode 100644 index 00000000..6f561de2 --- /dev/null +++ b/src/db/migrations/20211204214624_createProductsCategoriesTable.js @@ -0,0 +1,22 @@ +exports.up = function (knex) { + return knex.schema.createTable("products_categories", (table) => { + table.integer("product_id").unsigned().notNullable(); + table + .foreign("product_id") + .references("product_id") + .inTable("products") + .onDelete("CASCADE"); + table.integer("category_id").unsigned().notNullable(); + table + .foreign("category_id") + .references("category_id") + .inTable("categories") + .onDelete("CASCADE"); + + table.timestamps(true, true); + }); +}; + +exports.down = function (knex) { + return knex.schema.dropTable("products_categories"); +}; From 75e7879ec38460e89eee92cc555c8ce94048abea Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 14:09:00 -0800 Subject: [PATCH 09/20] Created migrations file for updating product name and adding price --- .env.sample | 1 - ...ctsAddPriceAndChangeProductNameToProductTitle.js | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) delete mode 100644 .env.sample create mode 100644 src/db/migrations/20211204220401_productsAddPriceAndChangeProductNameToProductTitle.js diff --git a/.env.sample b/.env.sample deleted file mode 100644 index 4cc714a2..00000000 --- a/.env.sample +++ /dev/null @@ -1 +0,0 @@ -DATABASE_URL= \ No newline at end of file diff --git a/src/db/migrations/20211204220401_productsAddPriceAndChangeProductNameToProductTitle.js b/src/db/migrations/20211204220401_productsAddPriceAndChangeProductNameToProductTitle.js new file mode 100644 index 00000000..0cac92af --- /dev/null +++ b/src/db/migrations/20211204220401_productsAddPriceAndChangeProductNameToProductTitle.js @@ -0,0 +1,13 @@ +exports.up = function (knex) { + return knex.schema.table("products", (table) => { + table.renameColumn("product_name", "product_title"); + table.decimal("product_price"); // Add a new column + }); +}; + +exports.down = function (knex) { + return knex.schema.table("products", (table) => { + table.renameColumn("product_title", "product_name"); + table.dropColumn("product_price"); + }); +}; From 07a0e9cced2a73f1630d8b9a9c5fa85045b6f403 Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 16:50:27 -0800 Subject: [PATCH 10/20] Added seed config to knex and created seeds with seed data for all tables --- knexfile.js | 3 +++ src/db/seeds/00-suppliers.js | 14 ++++++++++++++ src/db/seeds/01-products.js | 10 ++++++++++ src/db/seeds/02-categories.js | 9 +++++++++ src/db/seeds/03-products_categories.js | 9 +++++++++ 5 files changed, 45 insertions(+) create mode 100644 src/db/seeds/00-suppliers.js create mode 100644 src/db/seeds/01-products.js create mode 100644 src/db/seeds/02-categories.js create mode 100644 src/db/seeds/03-products_categories.js diff --git a/knexfile.js b/knexfile.js index 3626f2d0..f5d4beaf 100644 --- a/knexfile.js +++ b/knexfile.js @@ -10,6 +10,9 @@ module.exports = { migrations: { directory: path.join(__dirname, "src", "db", "migrations"), }, + seeds: { + directory: path.join(__dirname, "src", "db", "seeds"), + }, }, // test: { diff --git a/src/db/seeds/00-suppliers.js b/src/db/seeds/00-suppliers.js new file mode 100644 index 00000000..53259253 --- /dev/null +++ b/src/db/seeds/00-suppliers.js @@ -0,0 +1,14 @@ +const suppliers = require("../fixtures/suppliers"); + +exports.seed = (knex) => { + // Deletes ALL existing entries + // resets primary keys values + // deletes all associated products to the supplier + // then + // insert key/value pairs from fixtures into the table + return knex + .raw("TRUNCATE TABLE suppliers RESTART IDENTITY CASCADE") + .then(() => { + return knex("suppliers").insert(suppliers); + }); +}; diff --git a/src/db/seeds/01-products.js b/src/db/seeds/01-products.js new file mode 100644 index 00000000..6eb58a08 --- /dev/null +++ b/src/db/seeds/01-products.js @@ -0,0 +1,10 @@ +const products = require("../fixtures/products"); + +exports.seed = (knex) => { + // populates products table with products key/value pairs + return knex + .raw("TRUNCATE TABLE products RESTART IDENTITY CASCADE") + .then(() => { + return knex("products").insert(products); + }); +}; diff --git a/src/db/seeds/02-categories.js b/src/db/seeds/02-categories.js new file mode 100644 index 00000000..c1467cd1 --- /dev/null +++ b/src/db/seeds/02-categories.js @@ -0,0 +1,9 @@ +const categories = require("../fixtures/categories"); + +exports.seed = (knex) => { + return knex + .raw("TRUNCATE TABLE categories RESTART IDENTITY CASCADE") + .then(() => { + return knex("categories").insert(categories); + }); +}; diff --git a/src/db/seeds/03-products_categories.js b/src/db/seeds/03-products_categories.js new file mode 100644 index 00000000..75068900 --- /dev/null +++ b/src/db/seeds/03-products_categories.js @@ -0,0 +1,9 @@ +const productsCategories = require("../fixtures/productsCategories"); + +exports.seed = (knex) => { + return knex + .raw("TRUNCATE TABLE products_categories RESTART IDENTITY CASCADE") + .then(() => { + return knex("products_categories").insert(productsCategories); + }); +}; From ba5687bc89df8b31e1a70cd07e883efe1871800c Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 17:18:07 -0800 Subject: [PATCH 11/20] Added categories.service to handle knex queries for get --- src/categories/categories.controller.js | 19 +++++++++---------- src/categories/categories.service.js | 7 +++++++ 2 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 src/categories/categories.service.js diff --git a/src/categories/categories.controller.js b/src/categories/categories.controller.js index 54354238..8a7ad165 100644 --- a/src/categories/categories.controller.js +++ b/src/categories/categories.controller.js @@ -1,13 +1,12 @@ -async function list(req, res, next) { - res.json({ - data: [ - { category_name: "category 1" }, - { category_name: "category 2" }, - { category_name: "category 3" }, - ], - }); -} +const categoriesService = require("./categories.service"); + +const list = (req, res, next) => { + categoriesService + .list() + .then((data) => res.json({ data })) + .catch(next); +}; module.exports = { - list: [list], + list, }; diff --git a/src/categories/categories.service.js b/src/categories/categories.service.js new file mode 100644 index 00000000..b706862e --- /dev/null +++ b/src/categories/categories.service.js @@ -0,0 +1,7 @@ +const knex = require("../db/connection"); + +const list = () => { + return knex("categories").select("*"); +}; + +module.exports = { list }; From 6ff2ccbb5950c354cdf0eff0748eea467fc0c2f2 Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 18:26:31 -0800 Subject: [PATCH 12/20] Created products.service to hanbdle querying products list and product_id --- package.json | 2 +- src/products/products.controller.js | 38 +++++++++++++++++++++++------ src/products/products.router.js | 2 +- src/products/products.service.js | 14 +++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 src/products/products.service.js diff --git a/package.json b/package.json index 17b3c73c..3dd548db 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Starter code for the Node.js, Express, and PostgreSQL module", "main": "src/app.js", "scripts": { - "start": "node src/server.js", + "start": "nodemon src/server.js", "start:dev": "nodemon src/server.js" }, "keywords": [], diff --git a/src/products/products.controller.js b/src/products/products.controller.js index 961703ab..5ff68524 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -1,14 +1,36 @@ +const productsService = require("./products.service"); + +// Middlewares ============================================================================================================= + +const productExists = (req, res, next) => { + productsService + .read(req.params.productId) + .then((product) => { + if (product) { + res.locals.product = product; + return next(); + } + + next({ status: 404, message: `Product cannot be found.` }); + }) + .catch(next); +}; + +// Resource Queries ==================================================================================== + function read(req, res, next) { - res.json({ data: { product_title: "some product title" } }); + const { product: data } = res.locals; + res.json({ data }); } -function list(req, res, next) { - res.json({ - data: [{ product_title: "product 1" }, { product_title: "product 2" }], - }); -} +const list = (req, res, next) => { + productsService + .list() + .then((data) => res.json({ data })) + .catch(next); +}; module.exports = { - read: [read], - list: [list], + list, + read: [productExists, read], }; diff --git a/src/products/products.router.js b/src/products/products.router.js index da9e571c..4827291f 100644 --- a/src/products/products.router.js +++ b/src/products/products.router.js @@ -3,6 +3,6 @@ const controller = require("./products.controller"); const methodNotAllowed = require("../errors/methodNotAllowed"); router.route("/").get(controller.list).all(methodNotAllowed); -router.route("/:productId").get(controller.read).all(methodNotAllowed); +router.route("/:productId([0-9]+)").get(controller.read).all(methodNotAllowed); module.exports = router; diff --git a/src/products/products.service.js b/src/products/products.service.js new file mode 100644 index 00000000..3c208adf --- /dev/null +++ b/src/products/products.service.js @@ -0,0 +1,14 @@ +const knex = require("../db/connection"); + +const list = () => { + return knex("products").select("*"); +}; + +const read = (product_id) => { + return knex("products").select("*").where({ product_id }).first(); +}; + +module.exports = { + list, + read, +}; From 92b625976b769d00d1bd1ee75e4f530fc7588bd9 Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 18:41:07 -0800 Subject: [PATCH 13/20] Added middleware to handle invalid fields --- src/suppliers/suppliers.controller.js | 38 ++++++++++++++++++++++++++- src/suppliers/suppliers.service.js | 12 +++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/suppliers/suppliers.service.js diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 51448dbc..a6a4b16a 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -1,3 +1,39 @@ +const suppliersService = require("./suppliers.service.js"); + +// Middlewares ============================================================================================================= + +const VALID_PROPERTIES = [ + "supplier_name", + "supplier_address_line_1", + "supplier_address_line_2", + "supplier_city", + "supplier_state", + "supplier_zip", + "supplier_phone", + "supplier_email", + "supplier_notes", + "supplier_type_of_goods", +]; + +// Check for valid field properties +const hasValidProperties = (req, res, next) => { + const { data = {} } = req.body; + + const invalidFields = Object.keys(data).filter( + (property) => !VALID_PROPERTIES.includes(property) + ); + + if (invalidFields.length) { + return next({ + status: 400, + message: `Invalid field(s): ${invalidFields.join(", ")}`, + }); + } + next(); +}; + +// Resource Queries ==================================================================================== + async function create(req, res, next) { res.status(201).json({ data: { supplier_name: "new supplier" } }); } @@ -11,7 +47,7 @@ async function destroy(req, res, next) { } module.exports = { - create, + create: [hasValidProperties], update, delete: destroy, }; diff --git a/src/suppliers/suppliers.service.js b/src/suppliers/suppliers.service.js new file mode 100644 index 00000000..62d38198 --- /dev/null +++ b/src/suppliers/suppliers.service.js @@ -0,0 +1,12 @@ +const knex = require("../db/connection"); + +const create = (supplier) => { + return knex("suppliers") + .insert(supplier) + .returning("*") + .then((createdRecords) => createdRecords[0]); +}; + +module.exports = { + create, +}; From 92c707b32d155129580f11304f4f201cd14f0980 Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sat, 4 Dec 2021 18:45:26 -0800 Subject: [PATCH 14/20] Added hasProperties middleware to handle property error --- src/errors/hasProperties.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/errors/hasProperties.js diff --git a/src/errors/hasProperties.js b/src/errors/hasProperties.js new file mode 100644 index 00000000..740b5098 --- /dev/null +++ b/src/errors/hasProperties.js @@ -0,0 +1,20 @@ +const hasProperties = (...properties) => { + return (req, res, next) => { + const { data = {} } = req.body; + + try { + properties.forEach((property) => { + if (!data[property]) { + const error = new Error(`A '${property}' property is required.`); + error.status = 400; + throw error; + } + }); + next(); + } catch (error) { + next(error); + } + }; +}; + +module.exports = hasProperties; From f659b60c5d1de4adf77a49492dba76fc6eea679f Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sun, 5 Dec 2021 09:52:59 -0800 Subject: [PATCH 15/20] Added supplierExists and read and update services for supplier updating method --- src/suppliers/suppliers.controller.js | 29 ++++++++++++++++++++++----- src/suppliers/suppliers.service.js | 13 ++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index a6a4b16a..7dbde393 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -1,4 +1,5 @@ const suppliersService = require("./suppliers.service.js"); +const hasProperties = require("../errors/hasProperties"); // Middlewares ============================================================================================================= @@ -15,6 +16,8 @@ const VALID_PROPERTIES = [ "supplier_type_of_goods", ]; +const hasRequiredProperties = hasProperties("supplier_name", "supplier_email"); + // Check for valid field properties const hasValidProperties = (req, res, next) => { const { data = {} } = req.body; @@ -32,11 +35,27 @@ const hasValidProperties = (req, res, next) => { next(); }; +const supplierExists = (req, res, next) => { + suppliersService + .read(req.params.supplierId) + .then((supplier) => { + if (supplier) { + res.locals.supplier = supplier; + return next(); + } + next({ status: 404, message: `Supplier cannot be found.` }); + }) + .catch(next); +}; + // Resource Queries ==================================================================================== -async function create(req, res, next) { - res.status(201).json({ data: { supplier_name: "new supplier" } }); -} +const create = (req, res, next) => { + suppliersService + .create(req.body.data) + .then((data) => res.status(201).json({ data })) + .catch(next); +}; async function update(req, res, next) { res.json({ data: { supplier_name: "updated supplier" } }); @@ -47,7 +66,7 @@ async function destroy(req, res, next) { } module.exports = { - create: [hasValidProperties], - update, + create: [hasValidProperties, hasRequiredProperties, create], + update: [hasValidProperties, hasRequiredProperties, update], delete: destroy, }; diff --git a/src/suppliers/suppliers.service.js b/src/suppliers/suppliers.service.js index 62d38198..7fa019a5 100644 --- a/src/suppliers/suppliers.service.js +++ b/src/suppliers/suppliers.service.js @@ -7,6 +7,19 @@ const create = (supplier) => { .then((createdRecords) => createdRecords[0]); }; +const read = (supplier_id) => { + return knex("suppliers").select("*").where({ supplier_id }).first(); +}; + +const update = (updatedSupplier) => { + return knex("suppliers") + .select("*") + .where({ supplier_id: updatedSupplier.supplier_id }) + .update(updatedSupplier, "*"); +}; + module.exports = { create, + read, + update, }; From 0903bcf842285cf82b2fa66e4466949e9a02f9af Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sun, 5 Dec 2021 10:07:20 -0800 Subject: [PATCH 16/20] Completed update supplier method for updating supplier in the db --- src/suppliers/suppliers.controller.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 7dbde393..3d5e571b 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -57,9 +57,19 @@ const create = (req, res, next) => { .catch(next); }; -async function update(req, res, next) { - res.json({ data: { supplier_name: "updated supplier" } }); -} +const update = (req, res, next) => { + const updatedSupplier = { + ...req.body.data, + supplier_id: res.locals.supplier.supplier_id, + }; + + console.log("updatedSupplier:", updatedSupplier); + + suppliersService + .update(updatedSupplier) + .then((data) => res.json({ data })) + .catch(next); +}; async function destroy(req, res, next) { res.sendStatus(204); @@ -67,6 +77,6 @@ async function destroy(req, res, next) { module.exports = { create: [hasValidProperties, hasRequiredProperties, create], - update: [hasValidProperties, hasRequiredProperties, update], + update: [supplierExists, hasValidProperties, hasRequiredProperties, update], delete: destroy, }; From 1cda1b2f6372ebdce14eae5d8acac4349310c832 Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sun, 5 Dec 2021 10:14:25 -0800 Subject: [PATCH 17/20] Added delete (destroy) methods for deleting supplier from db in service and controller --- src/suppliers/suppliers.controller.js | 11 +++++++---- src/suppliers/suppliers.service.js | 5 +++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 3d5e571b..86625591 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -71,12 +71,15 @@ const update = (req, res, next) => { .catch(next); }; -async function destroy(req, res, next) { - res.sendStatus(204); -} +const destroy = (req, res, next) => { + suppliersService + .destroy(res.locals.supplier.supplier_id) + .then(() => res.sendStatus(204)) + .catch(next); +}; module.exports = { create: [hasValidProperties, hasRequiredProperties, create], update: [supplierExists, hasValidProperties, hasRequiredProperties, update], - delete: destroy, + delete: [supplierExists, destroy], }; diff --git a/src/suppliers/suppliers.service.js b/src/suppliers/suppliers.service.js index 7fa019a5..5ade9e7b 100644 --- a/src/suppliers/suppliers.service.js +++ b/src/suppliers/suppliers.service.js @@ -18,8 +18,13 @@ const update = (updatedSupplier) => { .update(updatedSupplier, "*"); }; +const destroy = (supplier_id) => { + return knex("suppliers").select("*").where({ supplier_id }).del(); +}; + module.exports = { create, read, update, + destroy, }; From 82d113d4545b29c6ae8daf36cfd850e0453b9d2b Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sun, 5 Dec 2021 16:07:55 -0800 Subject: [PATCH 18/20] Refactored CRUD functions for all controllers and wrapped error handlers in higher order function --- src/categories/categories.controller.js | 15 +++--- src/errors/asyncErrorBoundary.js | 15 ++++++ src/products/products.controller.js | 33 ++++++------- src/suppliers/suppliers.controller.js | 64 ++++++++++++++----------- 4 files changed, 74 insertions(+), 53 deletions(-) create mode 100644 src/errors/asyncErrorBoundary.js diff --git a/src/categories/categories.controller.js b/src/categories/categories.controller.js index 8a7ad165..b5585705 100644 --- a/src/categories/categories.controller.js +++ b/src/categories/categories.controller.js @@ -1,12 +1,15 @@ const categoriesService = require("./categories.service"); +const asyncErrorBoundary = require("../errors/asyncErrorBoundary"); -const list = (req, res, next) => { - categoriesService - .list() - .then((data) => res.json({ data })) - .catch(next); +const list = async (req, res, next) => { + try { + const data = await categoriesService.list(); + res.json({ data }); + } catch (error) { + next(error); + } }; module.exports = { - list, + list: asyncErrorBoundary(list), }; diff --git a/src/errors/asyncErrorBoundary.js b/src/errors/asyncErrorBoundary.js new file mode 100644 index 00000000..89a89342 --- /dev/null +++ b/src/errors/asyncErrorBoundary.js @@ -0,0 +1,15 @@ +const asyncErrorBoundary = (delegate, defaultStatus) => { + return (request, response, next) => { + Promise.resolve() + .then(() => delegate(request, response, next)) + .catch((error = {}) => { + const { status = defaultStatus, message = error } = error; + next({ + status, + message, + }); + }); + }; +}; + +module.exports = asyncErrorBoundary; diff --git a/src/products/products.controller.js b/src/products/products.controller.js index 5ff68524..a1418834 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -1,19 +1,17 @@ const productsService = require("./products.service"); +const asyncErrorBoundary = require("../errors/asyncErrorBoundary"); // Middlewares ============================================================================================================= -const productExists = (req, res, next) => { - productsService - .read(req.params.productId) - .then((product) => { - if (product) { - res.locals.product = product; - return next(); - } - - next({ status: 404, message: `Product cannot be found.` }); - }) - .catch(next); +const productExists = async (req, res, next) => { + const product = await productsService.read(req.params.productId); + + if (product) { + res.locals.product = product; + return next(); + } + + next({ status: 404, message: `Product cannot be found.` }); }; // Resource Queries ==================================================================================== @@ -23,14 +21,13 @@ function read(req, res, next) { res.json({ data }); } -const list = (req, res, next) => { - productsService - .list() - .then((data) => res.json({ data })) - .catch(next); +const list = async (req, res, next) => { + const data = await productsService.list(); + + res.json({ data }); }; module.exports = { list, - read: [productExists, read], + read: [asyncErrorBoundary(productExists), read], }; diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 86625591..b2b4b9a4 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -1,5 +1,6 @@ const suppliersService = require("./suppliers.service.js"); const hasProperties = require("../errors/hasProperties"); +const asyncErrorBoundary = require("../errors/asyncErrorBoundary"); // Middlewares ============================================================================================================= @@ -35,29 +36,25 @@ const hasValidProperties = (req, res, next) => { next(); }; -const supplierExists = (req, res, next) => { - suppliersService - .read(req.params.supplierId) - .then((supplier) => { - if (supplier) { - res.locals.supplier = supplier; - return next(); - } - next({ status: 404, message: `Supplier cannot be found.` }); - }) - .catch(next); +const supplierExists = async (req, res, next) => { + const supplier = await suppliersService.read(req.params.supplierId); + + if (supplier) { + res.locals.supplier = supplier; + return next(); + } + next({ status: 404, message: `Supplier cannot be found.` }); }; // Resource Queries ==================================================================================== -const create = (req, res, next) => { - suppliersService - .create(req.body.data) - .then((data) => res.status(201).json({ data })) - .catch(next); +const create = async (req, res, next) => { + const data = await suppliersService.create(req.body.data); + + res.status(201).json({ data }); }; -const update = (req, res, next) => { +const update = async (req, res, next) => { const updatedSupplier = { ...req.body.data, supplier_id: res.locals.supplier.supplier_id, @@ -65,21 +62,30 @@ const update = (req, res, next) => { console.log("updatedSupplier:", updatedSupplier); - suppliersService - .update(updatedSupplier) - .then((data) => res.json({ data })) - .catch(next); + const data = await suppliersService.update(updatedSupplier); + + res.json({ data }); }; -const destroy = (req, res, next) => { - suppliersService - .destroy(res.locals.supplier.supplier_id) - .then(() => res.sendStatus(204)) - .catch(next); +const destroy = async (req, res, next) => { + const { supplier } = res.locals; + + await suppliersService.destroy(supplier.supplier_id); + + res.sendStatus(204); }; module.exports = { - create: [hasValidProperties, hasRequiredProperties, create], - update: [supplierExists, hasValidProperties, hasRequiredProperties, update], - delete: [supplierExists, destroy], + create: [ + hasValidProperties, + hasRequiredProperties, + asyncErrorBoundary(create), + ], + update: [ + asyncErrorBoundary(supplierExists), + hasValidProperties, + hasRequiredProperties, + asyncErrorBoundary(update), + ], + delete: [asyncErrorBoundary(supplierExists), asyncErrorBoundary(destroy)], }; From a315d1fb7070a39c8ee8d9cc84e4a72cca9e4ea4 Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sun, 5 Dec 2021 16:33:14 -0800 Subject: [PATCH 19/20] Added listOutOfStockCount to handle count query for out of stock products --- src/products/products.controller.js | 5 +++++ src/products/products.router.js | 6 ++++++ src/products/products.service.js | 9 +++++++++ 3 files changed, 20 insertions(+) diff --git a/src/products/products.controller.js b/src/products/products.controller.js index a1418834..c9907444 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -27,7 +27,12 @@ const list = async (req, res, next) => { res.json({ data }); }; +const listOutOfStockCount = async (req, res, next) => { + res.json({ data: await productsService.listOutOfStockCount() }); +}; + module.exports = { list, read: [asyncErrorBoundary(productExists), read], + listOutOfStockCount: asyncErrorBoundary(listOutOfStockCount), }; diff --git a/src/products/products.router.js b/src/products/products.router.js index 4827291f..888b1ea7 100644 --- a/src/products/products.router.js +++ b/src/products/products.router.js @@ -3,6 +3,12 @@ const controller = require("./products.controller"); const methodNotAllowed = require("../errors/methodNotAllowed"); router.route("/").get(controller.list).all(methodNotAllowed); + +router + .route("/out-of-stock-count") + .get(controller.listOutOfStockCount) + .all(methodNotAllowed); + router.route("/:productId([0-9]+)").get(controller.read).all(methodNotAllowed); module.exports = router; diff --git a/src/products/products.service.js b/src/products/products.service.js index 3c208adf..d13931d8 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -4,6 +4,14 @@ const list = () => { return knex("products").select("*"); }; +const listOutOfStockCount = () => { + return knex("products") + .select("product_quantity_in_stock as out_of_stock") + .count("product_id") + .where({ product_quantity_in_stock: 0 }) + .groupBy("out_of_stock"); +}; + const read = (product_id) => { return knex("products").select("*").where({ product_id }).first(); }; @@ -11,4 +19,5 @@ const read = (product_id) => { module.exports = { list, read, + listOutOfStockCount, }; From f18d795fc5c112f404d9bdb38c88fced3fcf7439 Mon Sep 17 00:00:00 2001 From: Joseph Thomas Vasquez Date: Sun, 5 Dec 2021 16:57:36 -0800 Subject: [PATCH 20/20] Added more list query methods and updated service controller and routes --- src/products/products.controller.js | 10 ++++++++++ src/products/products.router.js | 10 ++++++++++ src/products/products.service.js | 25 +++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/src/products/products.controller.js b/src/products/products.controller.js index c9907444..459a7d80 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -31,8 +31,18 @@ const listOutOfStockCount = async (req, res, next) => { res.json({ data: await productsService.listOutOfStockCount() }); }; +const listPriceSummary = async (req, res, next) => { + res.json({ data: await productsService.listPriceSummary() }); +}; + +const listTotalWeightByProduct = async (req, res, next) => { + res.json({ data: await productsService.listTotalWeightByProduct() }); +}; + module.exports = { list, read: [asyncErrorBoundary(productExists), read], listOutOfStockCount: asyncErrorBoundary(listOutOfStockCount), + listPriceSummary: asyncErrorBoundary(listPriceSummary), + listTotalWeightByProduct: asyncErrorBoundary(listTotalWeightByProduct), }; diff --git a/src/products/products.router.js b/src/products/products.router.js index 888b1ea7..2c20f04b 100644 --- a/src/products/products.router.js +++ b/src/products/products.router.js @@ -9,6 +9,16 @@ router .get(controller.listOutOfStockCount) .all(methodNotAllowed); +router + .route("/price-summary") + .get(controller.listPriceSummary) + .all(methodNotAllowed); + +router + .route("/total-weight-by-product") + .get(controller.listTotalWeightByProduct) + .all(methodNotAllowed); + router.route("/:productId([0-9]+)").get(controller.read).all(methodNotAllowed); module.exports = router; diff --git a/src/products/products.service.js b/src/products/products.service.js index d13931d8..37b8a41c 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -1,5 +1,7 @@ const knex = require("../db/connection"); +// PRODUCTS - list queries =============================================================== + const list = () => { return knex("products").select("*"); }; @@ -12,6 +14,27 @@ const listOutOfStockCount = () => { .groupBy("out_of_stock"); }; +const listPriceSummary = () => { + return knex("products") + .select("supplier_id") + .min("product_price") + .max("product_price") + .avg("product_price") + .groupBy("supplier_id"); +}; + +const listTotalWeightByProduct = () => { + return knex("products") + .select( + "product_sku", + "product_title", + knex.raw( + "sum(product_weight_in_lbs * product_quantity_in_stock) as total_weight_in_lbs" + ) + ) + .groupBy("product_title", "product_sku"); +}; + const read = (product_id) => { return knex("products").select("*").where({ product_id }).first(); }; @@ -20,4 +43,6 @@ module.exports = { list, read, listOutOfStockCount, + listPriceSummary, + listTotalWeightByProduct, };