From 6d992ca88534c22847712b4be52332885ea26f54 Mon Sep 17 00:00:00 2001 From: kchia Date: Sun, 29 Nov 2020 17:00:35 -1000 Subject: [PATCH 01/35] create database configuration --- knexfile.js | 6 + package-lock.json | 1401 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 4 +- 3 files changed, 1405 insertions(+), 6 deletions(-) create mode 100644 knexfile.js diff --git a/knexfile.js b/knexfile.js new file mode 100644 index 00000000..3682fb66 --- /dev/null +++ b/knexfile.js @@ -0,0 +1,6 @@ +module.exports = { + development: { + client: "postgresql", + connection: "", + }, +}; diff --git a/package-lock.json b/package-lock.json index 1e3d92c1..5d4c9c50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,17 +81,107 @@ "picomatch": "^2.0.4" } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "binary-extensions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", @@ -141,11 +231,59 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "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", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, "cacheable-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", @@ -268,6 +406,27 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, "cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", @@ -283,6 +442,15 @@ "mimic-response": "^1.0.0" } }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -298,6 +466,21 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -341,6 +524,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, "crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -355,6 +543,11 @@ "ms": "2.0.0" } }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -376,6 +569,43 @@ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -386,6 +616,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, "dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -437,11 +672,56 @@ "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", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -479,6 +759,110 @@ "vary": "~1.1.2" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -493,11 +877,60 @@ "unpipe": "~1.0.0" } }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -510,6 +943,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 +957,16 @@ "pump": "^3.0.0" } }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "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", @@ -537,6 +985,28 @@ "ini": "^1.3.5" } }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, "got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -562,18 +1032,63 @@ "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", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "dev": true }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -626,14 +1141,45 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "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", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -643,6 +1189,11 @@ "binary-extensions": "^2.0.0" } }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -652,11 +1203,58 @@ "ci-info": "^2.0.0" } }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -668,7 +1266,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -689,6 +1286,24 @@ "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", "dev": true }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -701,18 +1316,62 @@ "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", "dev": true }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, "is-yarn-global": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", "dev": true }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", @@ -728,6 +1387,45 @@ "json-buffer": "3.0.0" } }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "knex": { + "version": "0.21.12", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.21.12.tgz", + "integrity": "sha512-AEyyiTM9p/x/Pb38TPZkvphKPmn8UWxP7MdIphzjAOielOfFFeU6pjP6y3M7UJ7rxrQsCrAYHwdonLQ3l1JCDw==", + "requires": { + "colorette": "1.2.1", + "commander": "^5.1.0", + "debug": "4.1.1", + "esm": "^3.2.25", + "getopts": "2.2.5", + "interpret": "^2.2.0", + "liftoff": "3.1.0", + "lodash": "^4.17.20", + "pg-connection-string": "2.3.0", + "tarn": "^3.0.1", + "tildify": "2.0.0", + "v8flags": "^3.2.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "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 +1435,26 @@ "package-json": "^6.3.0" } }, + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "requires": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -760,6 +1478,27 @@ } } }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -775,6 +1514,26 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -814,11 +1573,48 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -880,6 +1676,70 @@ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", "dev": true }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -923,22 +1783,154 @@ } } }, + "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==" + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" + }, "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.5.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz", + "integrity": "sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.4.0", + "pg-pool": "^3.2.2", + "pg-protocol": "^1.4.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "dependencies": { + "pg-connection-string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz", + "integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ==" + } + } + }, + "pg-connection-string": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.3.0.tgz", + "integrity": "sha512-ukMTJXLI7/hZIwTW7hGMZJ0Lj0S2XQBCJ4Shv4y1zgQ/vqVea+FLhzywvPj0ujSuofu+yA4MYHGZPTsgjBgJ+w==" + }, + "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.2.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.2.tgz", + "integrity": "sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA==" + }, + "pg-protocol": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.4.0.tgz", + "integrity": "sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA==" + }, + "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 }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "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 +2004,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 +2023,23 @@ "picomatch": "^2.2.1" } }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "^1.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.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 +2058,39 @@ "rc": "^1.2.8" } }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, "responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -1048,11 +2100,24 @@ "lowercase-keys": "^1.0.0" } }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -1119,6 +2184,27 @@ "send": "0.17.1" } }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", @@ -1130,6 +2216,160 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "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" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1175,6 +2415,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,18 +2454,66 @@ "has-flag": "^3.0.0" } }, + "tarn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.1.tgz", + "integrity": "sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw==" + }, "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-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", "dev": true }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -1249,6 +2552,11 @@ "is-typedarray": "^1.0.0" } }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, "undefsafe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", @@ -1258,6 +2566,17 @@ "debug": "^2.2.0" } }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, "unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", @@ -1272,6 +2591,42 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, "update-notifier": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", @@ -1293,6 +2648,11 @@ "xdg-basedir": "^4.0.0" } }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -1302,16 +2662,42 @@ "prepend-http": "^2.0.0" } }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "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", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, "widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -1344,6 +2730,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..28b17976 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.21.12", + "pg": "^8.5.1" }, "devDependencies": { "nodemon": "^2.0.6" From 82f5e069e47ca0640a0fcb99892a58e75774fa6a Mon Sep 17 00:00:00 2001 From: kchia Date: Sun, 29 Nov 2020 19:38:36 -1000 Subject: [PATCH 02/35] initialize a Knex instance --- knexfile.js | 5 ++++- package-lock.json | 5 +++++ package.json | 1 + src/db/connection.js | 5 +++++ 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/db/connection.js diff --git a/knexfile.js b/knexfile.js index 3682fb66..19feb34f 100644 --- a/knexfile.js +++ b/knexfile.js @@ -1,6 +1,9 @@ +require("dotenv").config(); +const { DATABASE_URL } = process.env; + module.exports = { development: { client: "postgresql", - connection: "", + connection: DATABASE_URL, }, }; diff --git a/package-lock.json b/package-lock.json index 5d4c9c50..e5d459b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -630,6 +630,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, "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 28b17976..53803528 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "author": "", "license": "ISC", "dependencies": { + "dotenv": "^8.2.0", "express": "^4.17.1", "knex": "^0.21.12", "pg": "^8.5.1" 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 1e74382c1321c79af85145733f89717cf9834350 Mon Sep 17 00:00:00 2001 From: kchia Date: Mon, 30 Nov 2020 09:28:06 -1000 Subject: [PATCH 03/35] perform database migrations --- knexfile.js | 4 ++++ .../20201130084659_createSuppliersTable.js | 20 ++++++++++++++++ .../20201130084710_createProductsTable.js | 23 +++++++++++++++++++ .../20201130084715_createCategoriesTable.js | 12 ++++++++++ ...130084720_createProductsCategoriesTable.js | 18 +++++++++++++++ ...1_renameProductNameColumnToProductTitle.js | 11 +++++++++ 6 files changed, 88 insertions(+) create mode 100644 src/db/migrations/20201130084659_createSuppliersTable.js create mode 100644 src/db/migrations/20201130084710_createProductsTable.js create mode 100644 src/db/migrations/20201130084715_createCategoriesTable.js create mode 100644 src/db/migrations/20201130084720_createProductsCategoriesTable.js create mode 100644 src/db/migrations/20201130091021_renameProductNameColumnToProductTitle.js diff --git a/knexfile.js b/knexfile.js index 19feb34f..f070fbbc 100644 --- a/knexfile.js +++ b/knexfile.js @@ -1,3 +1,4 @@ +const path = require("path"); require("dotenv").config(); const { DATABASE_URL } = process.env; @@ -5,5 +6,8 @@ module.exports = { development: { client: "postgresql", connection: DATABASE_URL, + migrations: { + directory: path.join(__dirname, "src", "db", "migrations"), + }, }, }; diff --git a/src/db/migrations/20201130084659_createSuppliersTable.js b/src/db/migrations/20201130084659_createSuppliersTable.js new file mode 100644 index 00000000..fdaa88d5 --- /dev/null +++ b/src/db/migrations/20201130084659_createSuppliersTable.js @@ -0,0 +1,20 @@ +exports.up = function (knex) { + return knex.schema.createTable("suppliers", table => { + table.increments("supplier_id").primary(); + 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); + }); +}; + +exports.down = function (knex) { + return knex.schema.dropTable("suppliers"); +}; diff --git a/src/db/migrations/20201130084710_createProductsTable.js b/src/db/migrations/20201130084710_createProductsTable.js new file mode 100644 index 00000000..74c11c15 --- /dev/null +++ b/src/db/migrations/20201130084710_createProductsTable.js @@ -0,0 +1,23 @@ +exports.up = function (knex) { + return knex.schema.createTable("products", table => { + table.increments("product_id").primary(); + table.string("product_sku"); + table.string("product_name"); + table.text("product_description"); + table.decimal("product_price"); + table.integer("product_quantity_in_stock"); + table.decimal("product_weight_in_lbs"); + + table.integer("supplier_id").unsigned().notNullable(); + table + .foreign("supplier_id") + .references("supplier_id") + .inTable("suppliers") + .onDelete("cascade"); + table.timestamps(true, true); + }); +}; + +exports.down = function (knex) { + return knex.schema.dropTable("products"); +}; diff --git a/src/db/migrations/20201130084715_createCategoriesTable.js b/src/db/migrations/20201130084715_createCategoriesTable.js new file mode 100644 index 00000000..5b4880dc --- /dev/null +++ b/src/db/migrations/20201130084715_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"); +}; diff --git a/src/db/migrations/20201130084720_createProductsCategoriesTable.js b/src/db/migrations/20201130084720_createProductsCategoriesTable.js new file mode 100644 index 00000000..c11cd276 --- /dev/null +++ b/src/db/migrations/20201130084720_createProductsCategoriesTable.js @@ -0,0 +1,18 @@ +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"); + + table.integer("category_id").unsigned().notNullable(); + table + .foreign("category_id") + .references("category_id") + .inTable("categories"); + + table.timestamps(true, true); + }); +}; + +exports.down = function (knex) { + return knex.schema.dropTable("products_categories"); +}; diff --git a/src/db/migrations/20201130091021_renameProductNameColumnToProductTitle.js b/src/db/migrations/20201130091021_renameProductNameColumnToProductTitle.js new file mode 100644 index 00000000..4df481c9 --- /dev/null +++ b/src/db/migrations/20201130091021_renameProductNameColumnToProductTitle.js @@ -0,0 +1,11 @@ +exports.up = function (knex) { + return knex.schema.table("products", table => { + table.renameColumn("product_name", "product_title"); + }); +}; + +exports.down = function (knex) { + return knex.schema.table("products", table => { + table.renameColumn("product_title", "product_name"); + }); +}; From 00d3dab0c8f08c0123a700b0d948022d7fae8909 Mon Sep 17 00:00:00 2001 From: kchia Date: Tue, 1 Dec 2020 10:40:13 -1000 Subject: [PATCH 04/35] cascade deletes in migrations --- .../20201130084720_createProductsCategoriesTable.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/db/migrations/20201130084720_createProductsCategoriesTable.js b/src/db/migrations/20201130084720_createProductsCategoriesTable.js index c11cd276..e59da4fe 100644 --- a/src/db/migrations/20201130084720_createProductsCategoriesTable.js +++ b/src/db/migrations/20201130084720_createProductsCategoriesTable.js @@ -1,13 +1,18 @@ 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"); + 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"); + .inTable("categories") + .onDelete("CASCADE"); table.timestamps(true, true); }); From 4b482748193e3bde9b8798c3a0977831411eedd9 Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Tue, 2 Mar 2021 22:50:54 -0700 Subject: [PATCH 05/35] feat(server.js): add automatic migration --- src/server.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/server.js b/src/server.js index dd5a5679..962b90e8 100644 --- a/src/server.js +++ b/src/server.js @@ -1,5 +1,17 @@ const { PORT = 5000 } = process.env; const app = require("./app"); +const knex = require("./db/connection"); + const listener = () => console.log(`Listening on Port ${PORT}!`); -app.listen(PORT, listener); + +knex.migrate + .latest() + .then((migrations) => { + console.log("migrations", migrations); + app.listen(PORT, listener); + }) + .catch((error) => { + console.error(error); + knex.destroy(); + }); From 6df3b1b32f797a410dbdf9b83da37b3d83fb4a98 Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Sun, 7 Mar 2021 22:02:19 -0700 Subject: [PATCH 06/35] feat: include dropColumn --- src/db/migrations/20201130084710_createProductsTable.js | 2 -- ...91021_productsAddPriceAndChangeProductNameToProductTitle.js} | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) rename src/db/migrations/{20201130091021_renameProductNameColumnToProductTitle.js => 20201130091021_productsAddPriceAndChangeProductNameToProductTitle.js} (75%) diff --git a/src/db/migrations/20201130084710_createProductsTable.js b/src/db/migrations/20201130084710_createProductsTable.js index 74c11c15..a5522894 100644 --- a/src/db/migrations/20201130084710_createProductsTable.js +++ b/src/db/migrations/20201130084710_createProductsTable.js @@ -4,10 +4,8 @@ exports.up = function (knex) { table.string("product_sku"); table.string("product_name"); table.text("product_description"); - table.decimal("product_price"); table.integer("product_quantity_in_stock"); table.decimal("product_weight_in_lbs"); - table.integer("supplier_id").unsigned().notNullable(); table .foreign("supplier_id") diff --git a/src/db/migrations/20201130091021_renameProductNameColumnToProductTitle.js b/src/db/migrations/20201130091021_productsAddPriceAndChangeProductNameToProductTitle.js similarity index 75% rename from src/db/migrations/20201130091021_renameProductNameColumnToProductTitle.js rename to src/db/migrations/20201130091021_productsAddPriceAndChangeProductNameToProductTitle.js index 4df481c9..92e1f079 100644 --- a/src/db/migrations/20201130091021_renameProductNameColumnToProductTitle.js +++ b/src/db/migrations/20201130091021_productsAddPriceAndChangeProductNameToProductTitle.js @@ -1,11 +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 6f0d104030916e9d27698a724027d0ea2ac453d1 Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Wed, 14 Apr 2021 11:10:12 -0500 Subject: [PATCH 07/35] style: run prettier on migrations --- src/db/migrations/20201130084659_createSuppliersTable.js | 2 +- src/db/migrations/20201130084710_createProductsTable.js | 2 +- src/db/migrations/20201130084715_createCategoriesTable.js | 2 +- .../20201130084720_createProductsCategoriesTable.js | 2 +- ...21_productsAddPriceAndChangeProductNameToProductTitle.js | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/db/migrations/20201130084659_createSuppliersTable.js b/src/db/migrations/20201130084659_createSuppliersTable.js index fdaa88d5..0180b60a 100644 --- a/src/db/migrations/20201130084659_createSuppliersTable.js +++ b/src/db/migrations/20201130084659_createSuppliersTable.js @@ -1,5 +1,5 @@ exports.up = function (knex) { - return knex.schema.createTable("suppliers", table => { + return knex.schema.createTable("suppliers", (table) => { table.increments("supplier_id").primary(); table.string("supplier_name"); table.string("supplier_address_line_1"); diff --git a/src/db/migrations/20201130084710_createProductsTable.js b/src/db/migrations/20201130084710_createProductsTable.js index a5522894..b16c2977 100644 --- a/src/db/migrations/20201130084710_createProductsTable.js +++ b/src/db/migrations/20201130084710_createProductsTable.js @@ -1,5 +1,5 @@ exports.up = function (knex) { - return knex.schema.createTable("products", table => { + return knex.schema.createTable("products", (table) => { table.increments("product_id").primary(); table.string("product_sku"); table.string("product_name"); diff --git a/src/db/migrations/20201130084715_createCategoriesTable.js b/src/db/migrations/20201130084715_createCategoriesTable.js index 5b4880dc..81345255 100644 --- a/src/db/migrations/20201130084715_createCategoriesTable.js +++ b/src/db/migrations/20201130084715_createCategoriesTable.js @@ -1,5 +1,5 @@ exports.up = function (knex) { - return knex.schema.createTable("categories", table => { + return knex.schema.createTable("categories", (table) => { table.increments("category_id").primary(); table.string("category_name"); table.text("category_description"); diff --git a/src/db/migrations/20201130084720_createProductsCategoriesTable.js b/src/db/migrations/20201130084720_createProductsCategoriesTable.js index e59da4fe..77954598 100644 --- a/src/db/migrations/20201130084720_createProductsCategoriesTable.js +++ b/src/db/migrations/20201130084720_createProductsCategoriesTable.js @@ -1,5 +1,5 @@ exports.up = function (knex) { - return knex.schema.createTable("products_categories", table => { + return knex.schema.createTable("products_categories", (table) => { table.integer("product_id").unsigned().notNullable(); table .foreign("product_id") diff --git a/src/db/migrations/20201130091021_productsAddPriceAndChangeProductNameToProductTitle.js b/src/db/migrations/20201130091021_productsAddPriceAndChangeProductNameToProductTitle.js index 92e1f079..0cac92af 100644 --- a/src/db/migrations/20201130091021_productsAddPriceAndChangeProductNameToProductTitle.js +++ b/src/db/migrations/20201130091021_productsAddPriceAndChangeProductNameToProductTitle.js @@ -1,12 +1,12 @@ exports.up = function (knex) { - return knex.schema.table("products", table => { + return knex.schema.table("products", (table) => { table.renameColumn("product_name", "product_title"); - table.decimal("product_price"); // Add a new column + table.decimal("product_price"); // Add a new column }); }; exports.down = function (knex) { - return knex.schema.table("products", table => { + return knex.schema.table("products", (table) => { table.renameColumn("product_title", "product_name"); table.dropColumn("product_price"); }); From bd0db3e68a75b0ac545977d242e1d0a379330c7d Mon Sep 17 00:00:00 2001 From: kchia Date: Mon, 30 Nov 2020 11:14:20 -1000 Subject: [PATCH 08/35] add seed scripts --- knexfile.js | 3 +++ src/db/seeds/00-suppliers.js | 11 +++++++++++ src/db/seeds/01-products.js | 11 +++++++++++ src/db/seeds/03-categories.js | 11 +++++++++++ src/db/seeds/04-products_categories.js | 11 +++++++++++ 5 files changed, 47 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/03-categories.js create mode 100644 src/db/seeds/04-products_categories.js diff --git a/knexfile.js b/knexfile.js index f070fbbc..bc97b719 100644 --- a/knexfile.js +++ b/knexfile.js @@ -9,5 +9,8 @@ module.exports = { migrations: { directory: path.join(__dirname, "src", "db", "migrations"), }, + seeds: { + directory: path.join(__dirname, "src", "db", "seeds"), + }, }, }; diff --git a/src/db/seeds/00-suppliers.js b/src/db/seeds/00-suppliers.js new file mode 100644 index 00000000..25df32c9 --- /dev/null +++ b/src/db/seeds/00-suppliers.js @@ -0,0 +1,11 @@ +const suppliers = require("../fixtures/suppliers"); + +exports.seed = function (knex) { + // Deletes ALL existing entries + return knex + .raw("TRUNCATE TABLE suppliers RESTART IDENTITY CASCADE") + .then(function () { + // Inserts seed entries + 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..29759c7f --- /dev/null +++ b/src/db/seeds/01-products.js @@ -0,0 +1,11 @@ +const products = require("../fixtures/products"); + +exports.seed = function (knex) { + // Deletes ALL existing entries + return knex + .raw("TRUNCATE TABLE products RESTART IDENTITY CASCADE") + .then(function () { + // Inserts seed entries + return knex("products").insert(products); + }); +}; diff --git a/src/db/seeds/03-categories.js b/src/db/seeds/03-categories.js new file mode 100644 index 00000000..400e9254 --- /dev/null +++ b/src/db/seeds/03-categories.js @@ -0,0 +1,11 @@ +const categories = require("../fixtures/categories"); + +exports.seed = function (knex) { + // Deletes ALL existing entries + return knex + .raw("TRUNCATE TABLE categories RESTART IDENTITY CASCADE") + .then(function () { + // Inserts seed entries + return knex("categories").insert(categories); + }); +}; diff --git a/src/db/seeds/04-products_categories.js b/src/db/seeds/04-products_categories.js new file mode 100644 index 00000000..4fb4500c --- /dev/null +++ b/src/db/seeds/04-products_categories.js @@ -0,0 +1,11 @@ +const productsCategories = require("../fixtures/productsCategories"); + +exports.seed = function (knex) { + // Deletes ALL existing entries + return knex + .raw("TRUNCATE TABLE products_categories RESTART IDENTITY CASCADE") + .then(function () { + // Inserts seed entries + return knex("products_categories").insert(productsCategories); + }); +}; From b970b7be2321ac8b3193cdd80584f11c62b2bb7f Mon Sep 17 00:00:00 2001 From: kchia Date: Mon, 30 Nov 2020 20:40:30 -1000 Subject: [PATCH 09/35] create CRUD functionality --- src/categories/categories.controller.js | 14 ++++---- src/categories/categories.service.js | 7 ++++ src/products/products.controller.js | 26 ++++++++++++--- src/products/products.service.js | 13 ++++++++ src/suppliers/suppliers.controller.js | 43 ++++++++++++++++++++----- src/suppliers/suppliers.service.js | 21 ++++++++++++ 6 files changed, 103 insertions(+), 21 deletions(-) create mode 100644 src/categories/categories.service.js create mode 100644 src/products/products.service.js create mode 100644 src/suppliers/suppliers.service.js diff --git a/src/categories/categories.controller.js b/src/categories/categories.controller.js index 54354238..663a8dbe 100644 --- a/src/categories/categories.controller.js +++ b/src/categories/categories.controller.js @@ -1,11 +1,9 @@ -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"); + +function list(req, res, next) { + CategoriesService.getAllCategories().then(categories => + res.json({ data: categories }) + ); } module.exports = { diff --git a/src/categories/categories.service.js b/src/categories/categories.service.js new file mode 100644 index 00000000..01008ee0 --- /dev/null +++ b/src/categories/categories.service.js @@ -0,0 +1,7 @@ +const knex = require("../db/connection"); + +const getAllCategories = () => knex("categories").select("*"); + +module.exports = { + getAllCategories, +}; diff --git a/src/products/products.controller.js b/src/products/products.controller.js index 961703ab..7b82a576 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -1,14 +1,30 @@ +const ProductsService = require("./products.service"); + +function productExists(req, res, next) { + const error = { status: 404, message: `Product cannot be found.` }; + + const { productId } = req.params; + if (!productId) return next(error); + + ProductsService.getProductById(productId).then(product => { + if (!product) return next(error); + res.locals.product = product; + next(); + }); +} + function read(req, res, next) { - res.json({ data: { product_title: "some product title" } }); + const { product } = res.locals; + res.json({ data: product }); } function list(req, res, next) { - res.json({ - data: [{ product_title: "product 1" }, { product_title: "product 2" }], - }); + ProductsService.getAllProducts().then(products => + res.json({ data: products }) + ); } module.exports = { - read: [read], + read: [productExists, read], list: [list], }; diff --git a/src/products/products.service.js b/src/products/products.service.js new file mode 100644 index 00000000..3302f28c --- /dev/null +++ b/src/products/products.service.js @@ -0,0 +1,13 @@ +const knex = require("../db/connection"); + +const products = knex("products"); + +const getAllProducts = () => products.select("*"); + +const getProductById = productId => + products.select("*").where({ product_id: productId }).first(); + +module.exports = { + getAllProducts, + getProductById, +}; diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 51448dbc..42f1bb64 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -1,17 +1,44 @@ -async function create(req, res, next) { - res.status(201).json({ data: { supplier_name: "new supplier" } }); +const SuppliersService = require("./suppliers.service.js"); + +function supplierExists(req, res, next) { + const error = { status: 404, message: `Supplier cannot be found.` }; + const { supplierId } = req.params; + if (!supplierId) return next(error); + + SuppliersService.getSupplierById(supplierId).then(supplier => { + if (!supplier) return next(error); + res.locals.supplier = supplier; + next(); + }); } -async function update(req, res, next) { - res.json({ data: { supplier_name: "updated supplier" } }); +function create(req, res, next) { + SuppliersService.createSupplier(req.body.data).then(newSupplier => + res.status(201).json({ data: newSupplier }) + ); +} + +function update(req, res, next) { + const { + supplier: { supplier_id: supplierId, ...supplier }, + } = res.locals; + const updatedSupplier = { ...supplier, ...req.body.data }; + + SuppliersService.updateSupplierById( + supplierId, + updatedSupplier + ).then(updatedSupplier => res.json({ data: updatedSupplier })); } -async function destroy(req, res, next) { - res.sendStatus(204); +function destroy(req, res, next) { + const { supplier } = res.locals; + SuppliersService.deleteSupplierById(supplier.supplier_id).then(() => + res.sendStatus(204) + ); } module.exports = { create, - update, - delete: destroy, + update: [supplierExists, update], + delete: [supplierExists, destroy], }; diff --git a/src/suppliers/suppliers.service.js b/src/suppliers/suppliers.service.js new file mode 100644 index 00000000..2d786163 --- /dev/null +++ b/src/suppliers/suppliers.service.js @@ -0,0 +1,21 @@ +const knex = require("../db/connection"); + +const suppliers = knex("suppliers"); + +const createSupplier = supplier => suppliers.insert(supplier).returning("*"); + +const getSupplierById = supplierId => + suppliers.select("*").where({ supplier_id: supplierId }).first(); + +const updateSupplierById = (supplierId, updatedSupplier) => + suppliers.where({ supplier_id: supplierId }).update(updatedSupplier, "*"); + +const deleteSupplierById = supplierId => + suppliers.where({ supplier_id: supplierId }).del(); + +module.exports = { + createSupplier, + getSupplierById, + updateSupplierById, + deleteSupplierById, +}; From e861f29e24b9a0c956e051ba98ad264443caecbd Mon Sep 17 00:00:00 2001 From: kchia Date: Tue, 1 Dec 2020 10:40:51 -1000 Subject: [PATCH 10/35] fix updateSupplierById query --- src/suppliers/suppliers.service.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/suppliers/suppliers.service.js b/src/suppliers/suppliers.service.js index 2d786163..669a5f5f 100644 --- a/src/suppliers/suppliers.service.js +++ b/src/suppliers/suppliers.service.js @@ -8,7 +8,10 @@ const getSupplierById = supplierId => suppliers.select("*").where({ supplier_id: supplierId }).first(); const updateSupplierById = (supplierId, updatedSupplier) => - suppliers.where({ supplier_id: supplierId }).update(updatedSupplier, "*"); + suppliers + .select("*") + .where({ supplier_id: supplierId }) + .update(updatedSupplier, "*"); const deleteSupplierById = supplierId => suppliers.where({ supplier_id: supplierId }).del(); From d8ceb80e31e2e91d199473f7cf07cc0306aaa556 Mon Sep 17 00:00:00 2001 From: kchia Date: Wed, 27 Jan 2021 16:15:02 -1000 Subject: [PATCH 11/35] feat: add create api validation --- src/suppliers/suppliers.controller.js | 59 +++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 42f1bb64..dba86a29 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -12,9 +12,62 @@ function supplierExists(req, res, next) { }); } +function hasValidFields(req, res, next) { + const { data = {} } = req.body; + const validFields = new Set([ + "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", + ]); + + const invalidFields = Object.keys(data).filter( + field => !validFields.has(field) + ); + + if (invalidFields.length) + return next({ + status: 400, + message: `Invalid field(s): ${invalidFields.join(", ")}`, + }); + next(); +} + +function bodyDataHas(propertyName) { + return function (req, res, next) { + const { data = {} } = req.body; + if (data[propertyName]) { + return next(); + } + next({ status: 400, message: `Supplier must include a ${propertyName}` }); + }; +} + +const hasSupplierName = bodyDataHas("supplier_name"); +const hasSupplierEmail = bodyDataHas("supplier_email"); + function create(req, res, next) { - SuppliersService.createSupplier(req.body.data).then(newSupplier => - res.status(201).json({ data: newSupplier }) + const newSupplier = ({ + 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, + } = req.body.data); + + SuppliersService.createSupplier(newSupplier).then(createdSupplier => + res.status(201).json({ data: createdSupplier }) ); } @@ -38,7 +91,7 @@ function destroy(req, res, next) { } module.exports = { - create, + create: [hasValidFields, hasSupplierName, hasSupplierEmail, create], update: [supplierExists, update], delete: [supplierExists, destroy], }; From 53a67385b32c3a5da253c6556f7c9e5ee9bfa21e Mon Sep 17 00:00:00 2001 From: kchia Date: Wed, 27 Jan 2021 16:49:52 -1000 Subject: [PATCH 12/35] move supplierExists function down for consistency --- src/suppliers/suppliers.controller.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index dba86a29..c40246e9 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -1,17 +1,5 @@ const SuppliersService = require("./suppliers.service.js"); -function supplierExists(req, res, next) { - const error = { status: 404, message: `Supplier cannot be found.` }; - const { supplierId } = req.params; - if (!supplierId) return next(error); - - SuppliersService.getSupplierById(supplierId).then(supplier => { - if (!supplier) return next(error); - res.locals.supplier = supplier; - next(); - }); -} - function hasValidFields(req, res, next) { const { data = {} } = req.body; const validFields = new Set([ @@ -71,6 +59,18 @@ function create(req, res, next) { ); } +function supplierExists(req, res, next) { + const error = { status: 404, message: `Supplier cannot be found.` }; + const { supplierId } = req.params; + if (!supplierId) return next(error); + + SuppliersService.getSupplierById(supplierId).then(supplier => { + if (!supplier) return next(error); + res.locals.supplier = supplier; + next(); + }); +} + function update(req, res, next) { const { supplier: { supplier_id: supplierId, ...supplier }, From cd89dea1440c634c02f44abb4e992609ab3c5dc4 Mon Sep 17 00:00:00 2001 From: kchia Date: Thu, 28 Jan 2021 23:48:35 -1000 Subject: [PATCH 13/35] validate :productId with regex --- src/products/products.router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From 889beaadccfa79225201b9f7a600a01069ddd54d Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Fri, 19 Mar 2021 22:56:54 -0700 Subject: [PATCH 14/35] fix: make update a full update, not patch --- src/categories/categories.controller.js | 10 +-- src/categories/categories.router.js | 4 +- src/categories/categories.service.js | 6 +- src/errors/hasProperties.js | 21 +++++ src/products/products.controller.js | 31 +++---- src/products/products.router.js | 2 +- src/products/products.service.js | 15 ++-- src/suppliers/suppliers.controller.js | 113 +++++++++--------------- src/suppliers/suppliers.router.js | 2 +- src/suppliers/suppliers.service.js | 31 ++++--- 10 files changed, 114 insertions(+), 121 deletions(-) create mode 100644 src/errors/hasProperties.js diff --git a/src/categories/categories.controller.js b/src/categories/categories.controller.js index 663a8dbe..813d9b14 100644 --- a/src/categories/categories.controller.js +++ b/src/categories/categories.controller.js @@ -1,11 +1,11 @@ -const CategoriesService = require("./categories.service"); +const categoriesService = require("./categories.service"); -function list(req, res, next) { - CategoriesService.getAllCategories().then(categories => - res.json({ data: categories }) +function list(req, res) { + categoriesService.list().then((data) => + res.json({ data }) ); } module.exports = { - list: [list], + list, }; diff --git a/src/categories/categories.router.js b/src/categories/categories.router.js index e9ed0acd..0972ef44 100644 --- a/src/categories/categories.router.js +++ b/src/categories/categories.router.js @@ -1,8 +1,8 @@ -const router = require("express").Router({ mergeParams: true }); +const router = require("express").Router(); const controller = require("./categories.controller"); const methodNotAllowed = require("../errors/methodNotAllowed"); router.route("/").get(controller.list).all(methodNotAllowed); -router.route("/:categoryId").all(methodNotAllowed); +router.route("/:categoryId([0-9]+)").all(methodNotAllowed); module.exports = router; diff --git a/src/categories/categories.service.js b/src/categories/categories.service.js index 01008ee0..8c265953 100644 --- a/src/categories/categories.service.js +++ b/src/categories/categories.service.js @@ -1,7 +1,9 @@ const knex = require("../db/connection"); -const getAllCategories = () => knex("categories").select("*"); +function list () { + return knex("categories").select("*"); +} module.exports = { - getAllCategories, + list, }; diff --git a/src/errors/hasProperties.js b/src/errors/hasProperties.js new file mode 100644 index 00000000..4d64afb9 --- /dev/null +++ b/src/errors/hasProperties.js @@ -0,0 +1,21 @@ + +function hasProperties(...properties) { + return function (res, req, next) { + const { data = {} } = res.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; diff --git a/src/products/products.controller.js b/src/products/products.controller.js index 7b82a576..27a3c8d1 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -1,30 +1,25 @@ -const ProductsService = require("./products.service"); +const productsService = require("./products.service"); function productExists(req, res, next) { - const error = { status: 404, message: `Product cannot be found.` }; - - const { productId } = req.params; - if (!productId) return next(error); - - ProductsService.getProductById(productId).then(product => { - if (!product) return next(error); - res.locals.product = product; - next(); + productsService.read(req.params.productId).then(product => { + if (product) { + res.locals.product = product; + return next(); + } + next({ status: 404, message: `Product cannot be found.` }); }); } -function read(req, res, next) { - const { product } = res.locals; - res.json({ data: product }); +function read (req, res) { + const { product: data } = res.locals; + res.json({ data }); } -function list(req, res, next) { - ProductsService.getAllProducts().then(products => - res.json({ data: products }) - ); +function list (req, res) { + productsService.list().then((data) => res.json({ data })); } module.exports = { read: [productExists, read], - list: [list], + list, }; diff --git a/src/products/products.router.js b/src/products/products.router.js index 4827291f..dad38178 100644 --- a/src/products/products.router.js +++ b/src/products/products.router.js @@ -1,4 +1,4 @@ -const router = require("express").Router({ mergeParams: true }); +const router = require("express").Router(); const controller = require("./products.controller"); const methodNotAllowed = require("../errors/methodNotAllowed"); diff --git a/src/products/products.service.js b/src/products/products.service.js index 3302f28c..48014595 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -1,13 +1,14 @@ const knex = require("../db/connection"); -const products = knex("products"); +function list () { + return knex("products").select("*"); +} -const getAllProducts = () => products.select("*"); - -const getProductById = productId => - products.select("*").where({ product_id: productId }).first(); +function read (product_id) { + return knex("products").select("*").where({ product_id }).first(); +} module.exports = { - getAllProducts, - getProductById, + list, + read, }; diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index c40246e9..210e854d 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -1,22 +1,24 @@ -const SuppliersService = require("./suppliers.service.js"); +const suppliersService = require("./suppliers.service.js"); +const hasProperties = require("../errors/hasProperties"); -function hasValidFields(req, res, next) { +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", +]; + +function hasOnlyValidProperties (req, res, next) { const { data = {} } = req.body; - const validFields = new Set([ - "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", - ]); const invalidFields = Object.keys(data).filter( - field => !validFields.has(field) + (field) => !VALID_PROPERTIES.includes(field) ); if (invalidFields.length) @@ -27,71 +29,40 @@ function hasValidFields(req, res, next) { next(); } -function bodyDataHas(propertyName) { - return function (req, res, next) { - const { data = {} } = req.body; - if (data[propertyName]) { - return next(); - } - next({ status: 400, message: `Supplier must include a ${propertyName}` }); - }; -} - -const hasSupplierName = bodyDataHas("supplier_name"); -const hasSupplierEmail = bodyDataHas("supplier_email"); - -function create(req, res, next) { - const newSupplier = ({ - 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, - } = req.body.data); +const hasRequiredProperties = hasProperties("supplier_name", "supplier_email"); - SuppliersService.createSupplier(newSupplier).then(createdSupplier => - res.status(201).json({ data: createdSupplier }) - ); +function create (req, res) { + suppliersService + .create(req.body.data) + .then((data) => res.status(201).json({ data })); } -function supplierExists(req, res, next) { - const error = { status: 404, message: `Supplier cannot be found.` }; - const { supplierId } = req.params; - if (!supplierId) return next(error); - - SuppliersService.getSupplierById(supplierId).then(supplier => { - if (!supplier) return next(error); - res.locals.supplier = supplier; - next(); +function 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.` }); }); } -function update(req, res, next) { - const { - supplier: { supplier_id: supplierId, ...supplier }, - } = res.locals; - const updatedSupplier = { ...supplier, ...req.body.data }; - - SuppliersService.updateSupplierById( - supplierId, - updatedSupplier - ).then(updatedSupplier => res.json({ data: updatedSupplier })); +function update (req, res) { + const updatedSupplier = { + ...req.body.data, + supplier_id: res.locals.supplier.supplier_id, + }; + suppliersService.update(updatedSupplier).then((data) => res.json({ data })); } -function destroy(req, res, next) { - const { supplier } = res.locals; - SuppliersService.deleteSupplierById(supplier.supplier_id).then(() => - res.sendStatus(204) - ); +function destroy (req, res) { + suppliersService + .delete(res.locals.supplier.supplier_id) + .then(() => res.sendStatus(204)); } module.exports = { - create: [hasValidFields, hasSupplierName, hasSupplierEmail, create], - update: [supplierExists, update], - delete: [supplierExists, destroy], + create: [hasOnlyValidProperties, hasRequiredProperties, create], + update: [supplierExists, hasOnlyValidProperties, hasRequiredProperties, update], + destroy: [supplierExists, destroy], }; diff --git a/src/suppliers/suppliers.router.js b/src/suppliers/suppliers.router.js index b9be48a1..80c90603 100644 --- a/src/suppliers/suppliers.router.js +++ b/src/suppliers/suppliers.router.js @@ -5,7 +5,7 @@ const methodNotAllowed = require("../errors/methodNotAllowed"); router.route("/").post(controller.create).all(methodNotAllowed); router - .route("/:supplierId") + .route("/:supplierId([0-9]+)") .put(controller.update) .delete(controller.delete) .all(methodNotAllowed); diff --git a/src/suppliers/suppliers.service.js b/src/suppliers/suppliers.service.js index 669a5f5f..27124976 100644 --- a/src/suppliers/suppliers.service.js +++ b/src/suppliers/suppliers.service.js @@ -1,24 +1,27 @@ const knex = require("../db/connection"); -const suppliers = knex("suppliers"); +function create(supplier) { + return knex("suppliers").insert(supplier).returning("*"); +} -const createSupplier = supplier => suppliers.insert(supplier).returning("*"); +function read(supplier_id) { + return knex("suppliers").select("*").where({ supplier_id }).first(); +} -const getSupplierById = supplierId => - suppliers.select("*").where({ supplier_id: supplierId }).first(); - -const updateSupplierById = (supplierId, updatedSupplier) => - suppliers +function update(updatedSupplier) { + return knex("suppliers") .select("*") - .where({ supplier_id: supplierId }) + .where({ supplier_id: updatedSupplier.supplier_id }) .update(updatedSupplier, "*"); +} -const deleteSupplierById = supplierId => - suppliers.where({ supplier_id: supplierId }).del(); +function destroy(supplierId) { + return knex("suppliers").where({ supplier_id: supplierId }).del(); +} module.exports = { - createSupplier, - getSupplierById, - updateSupplierById, - deleteSupplierById, + create, + read, + update, + delete: destroy, }; From e5368e6a0db9a1fd667af3a064ab545326f67154 Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Wed, 14 Apr 2021 10:58:01 -0500 Subject: [PATCH 15/35] fix: add .catch(next) to each knex promise catch methods were missing from earlier implementations fix TFENG-450 and fix #6238 --- src/categories/categories.controller.js | 9 ++--- src/products/products.controller.js | 26 ++++++++------ src/suppliers/suppliers.controller.js | 48 ++++++++++++++++--------- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/src/categories/categories.controller.js b/src/categories/categories.controller.js index 813d9b14..979f8cb4 100644 --- a/src/categories/categories.controller.js +++ b/src/categories/categories.controller.js @@ -1,9 +1,10 @@ const categoriesService = require("./categories.service"); -function list(req, res) { - categoriesService.list().then((data) => - res.json({ data }) - ); +function list(req, res, next) { + categoriesService + .list() + .then((data) => res.json({ data })) + .catch(next); } module.exports = { diff --git a/src/products/products.controller.js b/src/products/products.controller.js index 27a3c8d1..9774cdd5 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -1,22 +1,28 @@ const productsService = require("./products.service"); function 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.` }); - }); + 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); } -function read (req, res) { +function read(req, res) { const { product: data } = res.locals; res.json({ data }); } -function list (req, res) { - productsService.list().then((data) => res.json({ data })); +function list(req, res, next) { + productsService + .list() + .then((data) => res.json({ data })) + .catch(next); } module.exports = { diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 210e854d..6e2780cc 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -14,55 +14,69 @@ const VALID_PROPERTIES = [ "supplier_type_of_goods", ]; -function hasOnlyValidProperties (req, res, next) { +function hasOnlyValidProperties(req, res, next) { const { data = {} } = req.body; const invalidFields = Object.keys(data).filter( (field) => !VALID_PROPERTIES.includes(field) ); - if (invalidFields.length) + if (invalidFields.length) { return next({ status: 400, message: `Invalid field(s): ${invalidFields.join(", ")}`, }); + } next(); } const hasRequiredProperties = hasProperties("supplier_name", "supplier_email"); -function create (req, res) { +function create(req, res, next) { suppliersService .create(req.body.data) - .then((data) => res.status(201).json({ data })); + .then((data) => res.status(201).json({ data })) + .catch(next); } -function 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.` }); - }); +function 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); } -function update (req, res) { +function update(req, res, next) { const updatedSupplier = { ...req.body.data, supplier_id: res.locals.supplier.supplier_id, }; - suppliersService.update(updatedSupplier).then((data) => res.json({ data })); + suppliersService + .update(updatedSupplier) + .then((data) => res.json({ data })) + .catch(next); } -function destroy (req, res) { +function destroy(req, res, next) { suppliersService .delete(res.locals.supplier.supplier_id) - .then(() => res.sendStatus(204)); + .then(() => res.sendStatus(204)) + .catch(next); } module.exports = { create: [hasOnlyValidProperties, hasRequiredProperties, create], - update: [supplierExists, hasOnlyValidProperties, hasRequiredProperties, update], + update: [ + supplierExists, + hasOnlyValidProperties, + hasRequiredProperties, + update, + ], destroy: [supplierExists, destroy], }; From e5a1ac9e39e8edab85890b9df2d20d8865ccf25f Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Wed, 14 Apr 2021 11:18:38 -0500 Subject: [PATCH 16/35] style: run prettier on code --- src/categories/categories.service.js | 2 +- src/errors/hasProperties.js | 1 - src/products/products.service.js | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/categories/categories.service.js b/src/categories/categories.service.js index 8c265953..ecb36610 100644 --- a/src/categories/categories.service.js +++ b/src/categories/categories.service.js @@ -1,6 +1,6 @@ const knex = require("../db/connection"); -function list () { +function list() { return knex("categories").select("*"); } diff --git a/src/errors/hasProperties.js b/src/errors/hasProperties.js index 4d64afb9..605dae3d 100644 --- a/src/errors/hasProperties.js +++ b/src/errors/hasProperties.js @@ -1,4 +1,3 @@ - function hasProperties(...properties) { return function (res, req, next) { const { data = {} } = res.body; diff --git a/src/products/products.service.js b/src/products/products.service.js index 48014595..c0dea6c3 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -1,10 +1,10 @@ const knex = require("../db/connection"); -function list () { +function list() { return knex("products").select("*"); } -function read (product_id) { +function read(product_id) { return knex("products").select("*").where({ product_id }).first(); } From 0485d4cbf6c890cd9234a6209584296ff3c2553b Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Wed, 14 Apr 2021 11:31:28 -0500 Subject: [PATCH 17/35] fix(suppliers): export destroy as delete --- src/suppliers/suppliers.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 6e2780cc..9795620c 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -78,5 +78,5 @@ module.exports = { hasRequiredProperties, update, ], - destroy: [supplierExists, destroy], + delete: [supplierExists, destroy], }; From be04b1ce67576ddc58c3b0a28e3eecfd958af583 Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Fri, 16 Apr 2021 09:24:44 -0500 Subject: [PATCH 18/35] refactor(suppliers): simplify delete implementation --- src/suppliers/suppliers.service.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/suppliers/suppliers.service.js b/src/suppliers/suppliers.service.js index 27124976..8ae82505 100644 --- a/src/suppliers/suppliers.service.js +++ b/src/suppliers/suppliers.service.js @@ -15,8 +15,8 @@ function update(updatedSupplier) { .update(updatedSupplier, "*"); } -function destroy(supplierId) { - return knex("suppliers").where({ supplier_id: supplierId }).del(); +function destroy(supplier_id) { + return knex("suppliers").where({ supplier_id }).del(); } module.exports = { From ae709d84fb13e4e7f32ac7a02541da146efa9300 Mon Sep 17 00:00:00 2001 From: kchia Date: Tue, 1 Dec 2020 10:39:23 -1000 Subject: [PATCH 19/35] refactor controllers to use async await --- src/categories/categories.controller.js | 9 ++-- src/products/products.controller.js | 28 +++++------- src/suppliers/suppliers.controller.js | 57 +++++++++---------------- 3 files changed, 36 insertions(+), 58 deletions(-) diff --git a/src/categories/categories.controller.js b/src/categories/categories.controller.js index 979f8cb4..7fe026de 100644 --- a/src/categories/categories.controller.js +++ b/src/categories/categories.controller.js @@ -1,10 +1,9 @@ const categoriesService = require("./categories.service"); -function list(req, res, next) { - categoriesService - .list() - .then((data) => res.json({ data })) - .catch(next); + +async function list(req, res) { + const data = await categoriesService.list(); + res.json({ data }); } module.exports = { diff --git a/src/products/products.controller.js b/src/products/products.controller.js index 9774cdd5..b4799560 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -1,28 +1,22 @@ const productsService = require("./products.service"); -function 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); +async function productExists(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.` }); } -function read(req, res) { +function read (req, res) { const { product: data } = res.locals; res.json({ data }); } -function list(req, res, next) { - productsService - .list() - .then((data) => res.json({ data })) - .catch(next); +async function list(req, res) { + const data = await productsService.list(); + res.json({ data }); } module.exports = { diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 9795620c..a16c7744 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -14,69 +14,54 @@ const VALID_PROPERTIES = [ "supplier_type_of_goods", ]; -function hasOnlyValidProperties(req, res, next) { +function hasOnlyValidProperties (req, res, next) { const { data = {} } = req.body; const invalidFields = Object.keys(data).filter( (field) => !VALID_PROPERTIES.includes(field) ); - if (invalidFields.length) { + if (invalidFields.length) return next({ status: 400, message: `Invalid field(s): ${invalidFields.join(", ")}`, }); - } next(); } const hasRequiredProperties = hasProperties("supplier_name", "supplier_email"); -function create(req, res, next) { - suppliersService - .create(req.body.data) - .then((data) => res.status(201).json({ data })) - .catch(next); +async function supplierExists (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.` }); } -function 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); +async function create (req, res) { + const data = await suppliersService.create(req.body.data) + res.status(201).json({ data }); } -function update(req, res, next) { +function update (req, res) { const updatedSupplier = { ...req.body.data, supplier_id: res.locals.supplier.supplier_id, }; - suppliersService - .update(updatedSupplier) - .then((data) => res.json({ data })) - .catch(next); + const data = suppliersService.update(updatedSupplier); + res.json({ data }); } -function destroy(req, res, next) { - suppliersService - .delete(res.locals.supplier.supplier_id) - .then(() => res.sendStatus(204)) - .catch(next); +async function destroy(req, res, next) { + const { supplier } = res.locals; + await suppliersService.delete(supplier.supplier_id); + res.sendStatus(204); } module.exports = { create: [hasOnlyValidProperties, hasRequiredProperties, create], - update: [ - supplierExists, - hasOnlyValidProperties, - hasRequiredProperties, - update, - ], - delete: [supplierExists, destroy], + update: [supplierExists, hasOnlyValidProperties, hasRequiredProperties, update], + destroy: [supplierExists, destroy], }; From 025a39bdab05ff7bc357dac8e84d00e1b489eb73 Mon Sep 17 00:00:00 2001 From: kchia Date: Wed, 27 Jan 2021 16:15:02 -1000 Subject: [PATCH 20/35] feat: add create api validation --- src/suppliers/suppliers.controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index a16c7744..fbad2202 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -45,12 +45,12 @@ async function create (req, res) { res.status(201).json({ data }); } -function update (req, res) { +async function update (req, res) { const updatedSupplier = { ...req.body.data, supplier_id: res.locals.supplier.supplier_id, }; - const data = suppliersService.update(updatedSupplier); + const data = await suppliersService.update(updatedSupplier); res.json({ data }); } From 985088af0b6234220656bb021057cfb5dddf6dcf Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Sun, 28 Feb 2021 13:23:41 -0700 Subject: [PATCH 21/35] feat: add asyncErrorBoundary --- src/categories/categories.controller.js | 4 ++-- src/errors/asyncErrorBoundary.js | 15 +++++++++++++ src/products/products.controller.js | 5 +++-- src/suppliers/suppliers.controller.js | 28 +++++++++++++++++-------- 4 files changed, 39 insertions(+), 13 deletions(-) create mode 100644 src/errors/asyncErrorBoundary.js diff --git a/src/categories/categories.controller.js b/src/categories/categories.controller.js index 7fe026de..5012cf43 100644 --- a/src/categories/categories.controller.js +++ b/src/categories/categories.controller.js @@ -1,5 +1,5 @@ const categoriesService = require("./categories.service"); - +const asyncErrorBoundary = require("../errors/asyncErrorBoundary"); async function list(req, res) { const data = await categoriesService.list(); @@ -7,5 +7,5 @@ async function list(req, res) { } module.exports = { - list, + list: asyncErrorBoundary(list), }; diff --git a/src/errors/asyncErrorBoundary.js b/src/errors/asyncErrorBoundary.js new file mode 100644 index 00000000..ab4ea140 --- /dev/null +++ b/src/errors/asyncErrorBoundary.js @@ -0,0 +1,15 @@ +function 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 b4799560..22f104fd 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -1,4 +1,5 @@ const productsService = require("./products.service"); +const asyncErrorBoundary = require("../errors/asyncErrorBoundary"); async function productExists(req, res, next) { const product = await productsService.read(req.params.productId); @@ -20,6 +21,6 @@ async function list(req, res) { } module.exports = { - read: [productExists, read], - list, + read: [asyncErrorBoundary(productExists), read], + list: asyncErrorBoundary(list), }; diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index fbad2202..90071f5a 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"); const VALID_PROPERTIES = [ "supplier_name", @@ -14,7 +15,7 @@ const VALID_PROPERTIES = [ "supplier_type_of_goods", ]; -function hasOnlyValidProperties (req, res, next) { +function hasOnlyValidProperties(req, res, next) { const { data = {} } = req.body; const invalidFields = Object.keys(data).filter( @@ -31,7 +32,7 @@ function hasOnlyValidProperties (req, res, next) { const hasRequiredProperties = hasProperties("supplier_name", "supplier_email"); -async function supplierExists (req, res, next) { +async function supplierExists(req, res, next) { const supplier = await suppliersService.read(req.params.supplierId); if (supplier) { res.locals.supplier = supplier; @@ -40,12 +41,12 @@ async function supplierExists (req, res, next) { next({ status: 404, message: `Supplier cannot be found.` }); } -async function create (req, res) { - const data = await suppliersService.create(req.body.data) +async function create(req, res) { + const data = await suppliersService.create(req.body.data); res.status(201).json({ data }); } -async function update (req, res) { +async function update(req, res) { const updatedSupplier = { ...req.body.data, supplier_id: res.locals.supplier.supplier_id, @@ -54,14 +55,23 @@ async function update (req, res) { res.json({ data }); } -async function destroy(req, res, next) { +async function destroy(req, res) { const { supplier } = res.locals; await suppliersService.delete(supplier.supplier_id); res.sendStatus(204); } module.exports = { - create: [hasOnlyValidProperties, hasRequiredProperties, create], - update: [supplierExists, hasOnlyValidProperties, hasRequiredProperties, update], - destroy: [supplierExists, destroy], + create: [ + hasOnlyValidProperties, + hasRequiredProperties, + asyncErrorBoundary(create), + ], + update: [ + asyncErrorBoundary(supplierExists), + hasOnlyValidProperties, + hasRequiredProperties, + asyncErrorBoundary(update), + ], + destroy: [asyncErrorBoundary(supplierExists), asyncErrorBoundary(destroy)], }; From ba7f521a2ab49cb0b9c4a2d1a58a4b793c7dd999 Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Sun, 28 Feb 2021 13:56:30 -0700 Subject: [PATCH 22/35] feat: use const where appropriate --- src/products/products.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/products/products.controller.js b/src/products/products.controller.js index 22f104fd..a60a6ef1 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -21,6 +21,6 @@ async function list(req, res) { } module.exports = { - read: [asyncErrorBoundary(productExists), read], + read: [asyncErrorBoundary(productExists), asyncErrorBoundary(read)], list: asyncErrorBoundary(list), }; From 4bd71f0ad4290b6a4c13dc697ad972e4939f8ecb Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Wed, 14 Apr 2021 11:39:48 -0500 Subject: [PATCH 23/35] fix: export suppliers controller destroy as delete --- src/suppliers/suppliers.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/suppliers/suppliers.controller.js b/src/suppliers/suppliers.controller.js index 90071f5a..d9471059 100644 --- a/src/suppliers/suppliers.controller.js +++ b/src/suppliers/suppliers.controller.js @@ -73,5 +73,5 @@ module.exports = { hasRequiredProperties, asyncErrorBoundary(update), ], - destroy: [asyncErrorBoundary(supplierExists), asyncErrorBoundary(destroy)], + delete: [asyncErrorBoundary(supplierExists), asyncErrorBoundary(destroy)], }; From 19c3d60bc788e05d1eb74ec9652d0c3b506f4f05 Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Wed, 14 Apr 2021 11:41:04 -0500 Subject: [PATCH 24/35] style: run prettier on code --- src/products/products.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/products/products.controller.js b/src/products/products.controller.js index a60a6ef1..df40ba50 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -10,7 +10,7 @@ async function productExists(req, res, next) { next({ status: 404, message: `Product cannot be found.` }); } -function read (req, res) { +function read(req, res) { const { product: data } = res.locals; res.json({ data }); } From f154f66ae6a4baa650c4c32a13f330721151a107 Mon Sep 17 00:00:00 2001 From: kchia Date: Wed, 27 Jan 2021 23:07:04 -1000 Subject: [PATCH 25/35] update aggregate controllers --- src/products/products.controller.js | 17 ++++++++++++++- src/products/products.router.js | 14 ++++++++++++- src/products/products.service.js | 32 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/products/products.controller.js b/src/products/products.controller.js index df40ba50..c38a40e3 100644 --- a/src/products/products.controller.js +++ b/src/products/products.controller.js @@ -20,7 +20,22 @@ async function list(req, res) { res.json({ data }); } +async function listOutOfStockCount(req, res) { + res.json({ data: await productsService.listOutOfStockCount() }); +} + +async function listPriceSummary(req, res) { + res.json({ data: await productsService.listPriceSummary() }); +} + +async function listTotalWeightByProduct(req, res) { + res.json({ data: await productsService.listTotalWeightByProduct() }); +} + module.exports = { - read: [asyncErrorBoundary(productExists), asyncErrorBoundary(read)], + read: [asyncErrorBoundary(productExists), read], list: asyncErrorBoundary(list), + listOutOfStockCount: asyncErrorBoundary(listOutOfStockCount), + listPriceSummary: asyncErrorBoundary(listPriceSummary), + listTotalWeightByProduct: asyncErrorBoundary(listTotalWeightByProduct), }; diff --git a/src/products/products.router.js b/src/products/products.router.js index dad38178..08548f57 100644 --- a/src/products/products.router.js +++ b/src/products/products.router.js @@ -3,6 +3,18 @@ const controller = require("./products.controller"); const methodNotAllowed = require("../errors/methodNotAllowed"); router.route("/").get(controller.list).all(methodNotAllowed); -router.route("/:productId([0-9]+)").get(controller.read).all(methodNotAllowed); +router + .route("/out_of_stock_count") + .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").get(controller.read).all(methodNotAllowed); module.exports = router; diff --git a/src/products/products.service.js b/src/products/products.service.js index c0dea6c3..db828789 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -8,7 +8,39 @@ function read(product_id) { return knex("products").select("*").where({ product_id }).first(); } +function 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"); +} + +function listPriceSummary () { + return knex("products") + .select("supplier_id") + .min("product_price") + .max("product_price") + .avg("product_price") + .groupBy("supplier_id"); +} + +function 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"); +} + module.exports = { list, read, + listOutOfStockCount, + listPriceSummary, + listTotalWeightByProduct, }; From 0e89a735e755475fff7eb220a2aa60493774bfee Mon Sep 17 00:00:00 2001 From: kchia Date: Thu, 28 Jan 2021 23:48:35 -1000 Subject: [PATCH 26/35] validate :productId with regex --- src/products/products.router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/products/products.router.js b/src/products/products.router.js index 08548f57..6260b429 100644 --- a/src/products/products.router.js +++ b/src/products/products.router.js @@ -15,6 +15,6 @@ router .route("/total_weight_by_product") .get(controller.listTotalWeightByProduct) .all(methodNotAllowed); -router.route("/:productId").get(controller.read).all(methodNotAllowed); +router.route("/:productId([0-9]+)").get(controller.read).all(methodNotAllowed); module.exports = router; From 0178e11d76da324bda1c2362cf91937c6323e310 Mon Sep 17 00:00:00 2001 From: kchia Date: Mon, 1 Feb 2021 09:41:48 -1000 Subject: [PATCH 27/35] use dashes instead of underscores in url path --- src/products/products.router.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/products/products.router.js b/src/products/products.router.js index 6260b429..adac04a2 100644 --- a/src/products/products.router.js +++ b/src/products/products.router.js @@ -4,15 +4,15 @@ const methodNotAllowed = require("../errors/methodNotAllowed"); router.route("/").get(controller.list).all(methodNotAllowed); router - .route("/out_of_stock_count") + .route("/out-of-stock-count") .get(controller.listOutOfStockCount) .all(methodNotAllowed); router - .route("/price_summary") + .route("/price-summary") .get(controller.listPriceSummary) .all(methodNotAllowed); router - .route("/total_weight_by_product") + .route("/total-weight-by-product") .get(controller.listTotalWeightByProduct) .all(methodNotAllowed); router.route("/:productId([0-9]+)").get(controller.read).all(methodNotAllowed); From 33dd956abd5215d12cb23798680b2ae62dea2d2e Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Wed, 14 Apr 2021 11:48:43 -0500 Subject: [PATCH 28/35] style: run prettier on code --- src/products/products.service.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/products/products.service.js b/src/products/products.service.js index db828789..2e3d5e80 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -8,7 +8,7 @@ function read(product_id) { return knex("products").select("*").where({ product_id }).first(); } -function listOutOfStockCount () { +function listOutOfStockCount() { return knex("products") .select("product_quantity_in_stock as out_of_stock") .count("product_id") @@ -16,7 +16,7 @@ function listOutOfStockCount () { .groupBy("out_of_stock"); } -function listPriceSummary () { +function listPriceSummary() { return knex("products") .select("supplier_id") .min("product_price") @@ -25,7 +25,7 @@ function listPriceSummary () { .groupBy("supplier_id"); } -function listTotalWeightByProduct () { +function listTotalWeightByProduct() { return knex("products") .select( "product_sku", From ee90b36d9f7187c64a96e3ad73e8e0c7dc03097c Mon Sep 17 00:00:00 2001 From: kchia Date: Wed, 2 Dec 2020 13:11:24 -1000 Subject: [PATCH 29/35] add join base queries and query builder functions --- src/products/products.service.js | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/products/products.service.js b/src/products/products.service.js index 2e3d5e80..7701d0d3 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -37,10 +37,59 @@ function listTotalWeightByProduct() { .groupBy("product_title", "product_sku"); } +const productsSuppliersJoin = knex("products as p").join( + "suppliers as s", + "p.supplier_id", + "s.supplier_id" +); + +const productsCategoriesJoin = knex("products as p") + .join("products_categories as pc", "p.product_id", "pc.product_id") + .join("categories as c", "pc.category_id", "c.category_id"); + +const productsCategoriesSuppliersJoin = knex("products as p") + .join("products_categories as pc", "p.product_id", "pc.product_id") + .join("categories as c", "pc.category_id", "c.category_id") + .join("suppliers as s", "p.supplier_id", "s.supplier_id"); + + +const getProductByIdWithCategories = productId => + productsCategoriesJoin + .select("p.*", "c.*") + .where({ "p.product_id": productId }) + .first(); + +const getProductByIdWithSuppliers = productId => + productsSuppliersJoin + .select("p.*", "s.*") + .where({ "p.product_id": productId }) + .first(); + +const getProductByIdWithCategoriesAndSuppliers = productId => + productsCategoriesSuppliersJoin + .select("p.*", "c.*", "s.*") + .where({ "p.product_id": productId }) + .first(); + +const getTotalWeightOfProductsByCategory = () => + productsCategoriesJoin + .select( + "c.category_name", + knex.raw( + "sum(p.product_weight_in_lbs * p.product_quantity_in_stock) as total_weight_by_category" + ) + ) + .groupBy("c.category_name") + .orderBy("total_weight_by_category"); + module.exports = { list, read, listOutOfStockCount, listPriceSummary, listTotalWeightByProduct, + getProductByIdWithCategories, + getProductByIdWithSuppliers, + getProductByIdWithCategoriesAndSuppliers, + getTotalWeightOfProductsByCategory, }; From 87b6c050bdead142ac6c1ce2edc45fc895b6a75d Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Sat, 20 Mar 2021 12:09:59 -0700 Subject: [PATCH 30/35] feat: add mapProperties --- package-lock.json | 6 +-- package.json | 1 + src/products/products.service.js | 65 ++++++++++++++++++-------------- src/utils/map-properties.js | 14 +++++++ 4 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 src/utils/map-properties.js diff --git a/package-lock.json b/package-lock.json index e5d459b1..713678c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1456,9 +1456,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + "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", diff --git a/package.json b/package.json index 53803528..777fd867 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dotenv": "^8.2.0", "express": "^4.17.1", "knex": "^0.21.12", + "lodash": "^4.17.19", "pg": "^8.5.1" }, "devDependencies": { diff --git a/src/products/products.service.js b/src/products/products.service.js index 7701d0d3..518e6bea 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -1,11 +1,24 @@ const knex = require("../db/connection"); +const mapProperties = require("../utils/properties-to-object"); + +const addCategory = mapProperties({ + category_id: "category.id", + category_name: "category.name", + category_description: "category.description", +}); function list() { return knex("products").select("*"); } function read(product_id) { - return knex("products").select("*").where({ product_id }).first(); + return knex("products as p") + .join("products_categories as pc", "p.product_id", "pc.product_id") + .join("categories as c", "pc.category_id", "c.category_id") + .select("p.*", "c.*") + .where({ "p.product_id": product_id }) + .first() + .then(addCategory); } function listOutOfStockCount() { @@ -37,42 +50,37 @@ function listTotalWeightByProduct() { .groupBy("product_title", "product_sku"); } -const productsSuppliersJoin = knex("products as p").join( - "suppliers as s", - "p.supplier_id", - "s.supplier_id" -); - -const productsCategoriesJoin = knex("products as p") - .join("products_categories as pc", "p.product_id", "pc.product_id") - .join("categories as c", "pc.category_id", "c.category_id"); - -const productsCategoriesSuppliersJoin = knex("products as p") - .join("products_categories as pc", "p.product_id", "pc.product_id") - .join("categories as c", "pc.category_id", "c.category_id") - .join("suppliers as s", "p.supplier_id", "s.supplier_id"); - - -const getProductByIdWithCategories = productId => - productsCategoriesJoin +function getProductByIdWithCategories(product_id) { + return knex("products as p") + .join("products_categories as pc", "p.product_id", "pc.product_id") + .join("categories as c", "pc.category_id", "c.category_id") .select("p.*", "c.*") - .where({ "p.product_id": productId }) + .where({ "p.product_id": product_id }) .first(); +} -const getProductByIdWithSuppliers = productId => - productsSuppliersJoin +function getProductByIdWithSuppliers(product_id) { + return knex("products as p") + .join("suppliers as s", "p.supplier_id", "s.supplier_id") .select("p.*", "s.*") - .where({ "p.product_id": productId }) + .where({ "p.product_id": product_id }) .first(); +} -const getProductByIdWithCategoriesAndSuppliers = productId => - productsCategoriesSuppliersJoin +function getProductByIdWithCategoriesAndSuppliers(product_id) { + return knex("products as p") + .join("products_categories as pc", "p.product_id", "pc.product_id") + .join("categories as c", "pc.category_id", "c.category_id") + .join("suppliers as s", "p.supplier_id", "s.supplier_id") .select("p.*", "c.*", "s.*") - .where({ "p.product_id": productId }) + .where({ "p.product_id": product_id }) .first(); +} -const getTotalWeightOfProductsByCategory = () => - productsCategoriesJoin +function getTotalWeightOfProductsByCategory() { + return knex("products as p") + .join("products_categories as pc", "p.product_id", "pc.product_id") + .join("categories as c", "pc.category_id", "c.category_id") .select( "c.category_name", knex.raw( @@ -81,6 +89,7 @@ const getTotalWeightOfProductsByCategory = () => ) .groupBy("c.category_name") .orderBy("total_weight_by_category"); +} module.exports = { list, diff --git a/src/utils/map-properties.js b/src/utils/map-properties.js new file mode 100644 index 00000000..bd49f339 --- /dev/null +++ b/src/utils/map-properties.js @@ -0,0 +1,14 @@ +const lodash = require("lodash"); + +function mapProperties(configuration) { + return (data) => { + if (data) { + return Object.entries(data).reduce((accumulator, [key, value]) => { + return lodash.set(accumulator, configuration[key] || key, value); + }, {}); + } + return data; + }; +} + +module.exports = mapProperties; From 08324481950acff6e2242bb3b903161dce0fcf65 Mon Sep 17 00:00:00 2001 From: Gabriel Sanchez Date: Tue, 13 Apr 2021 17:56:48 -0500 Subject: [PATCH 31/35] Fix map-properties import. --- src/products/products.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/products/products.service.js b/src/products/products.service.js index 518e6bea..6609c9d4 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -1,5 +1,5 @@ const knex = require("../db/connection"); -const mapProperties = require("../utils/properties-to-object"); +const mapProperties = require("../utils/map-properties"); const addCategory = mapProperties({ category_id: "category.id", From 4640a05216e53f968c95da84cd54a75e1730635a Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Wed, 14 Apr 2021 11:56:59 -0500 Subject: [PATCH 32/35] fix: remove dead code from products service --- src/products/products.service.js | 45 -------------------------------- 1 file changed, 45 deletions(-) diff --git a/src/products/products.service.js b/src/products/products.service.js index 6609c9d4..98f2101b 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -50,55 +50,10 @@ function listTotalWeightByProduct() { .groupBy("product_title", "product_sku"); } -function getProductByIdWithCategories(product_id) { - return knex("products as p") - .join("products_categories as pc", "p.product_id", "pc.product_id") - .join("categories as c", "pc.category_id", "c.category_id") - .select("p.*", "c.*") - .where({ "p.product_id": product_id }) - .first(); -} - -function getProductByIdWithSuppliers(product_id) { - return knex("products as p") - .join("suppliers as s", "p.supplier_id", "s.supplier_id") - .select("p.*", "s.*") - .where({ "p.product_id": product_id }) - .first(); -} - -function getProductByIdWithCategoriesAndSuppliers(product_id) { - return knex("products as p") - .join("products_categories as pc", "p.product_id", "pc.product_id") - .join("categories as c", "pc.category_id", "c.category_id") - .join("suppliers as s", "p.supplier_id", "s.supplier_id") - .select("p.*", "c.*", "s.*") - .where({ "p.product_id": product_id }) - .first(); -} - -function getTotalWeightOfProductsByCategory() { - return knex("products as p") - .join("products_categories as pc", "p.product_id", "pc.product_id") - .join("categories as c", "pc.category_id", "c.category_id") - .select( - "c.category_name", - knex.raw( - "sum(p.product_weight_in_lbs * p.product_quantity_in_stock) as total_weight_by_category" - ) - ) - .groupBy("c.category_name") - .orderBy("total_weight_by_category"); -} - module.exports = { list, read, listOutOfStockCount, listPriceSummary, listTotalWeightByProduct, - getProductByIdWithCategories, - getProductByIdWithSuppliers, - getProductByIdWithCategoriesAndSuppliers, - getTotalWeightOfProductsByCategory, }; From 0257902fcd3cf265a3996fdbdc10ac7da11a6b28 Mon Sep 17 00:00:00 2001 From: Dale 'Ducky' Lotts Date: Thu, 15 Apr 2021 09:07:59 -0500 Subject: [PATCH 33/35] fix(products): change product.category mapping to include category_ prefix most fields have a talbe name prefix so this is being consistent fix TFENG-452 --- src/products/products.service.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/products/products.service.js b/src/products/products.service.js index 98f2101b..0b327fcd 100644 --- a/src/products/products.service.js +++ b/src/products/products.service.js @@ -2,9 +2,9 @@ const knex = require("../db/connection"); const mapProperties = require("../utils/map-properties"); const addCategory = mapProperties({ - category_id: "category.id", - category_name: "category.name", - category_description: "category.description", + category_id: "category.category_id", + category_name: "category.category_name", + category_description: "category.category_description", }); function list() { From 735e64d790d07689b06e2c7b9b2dbff7dac973fc Mon Sep 17 00:00:00 2001 From: kchia Date: Mon, 21 Jun 2021 15:03:38 -0400 Subject: [PATCH 34/35] fix typo --- src/suppliers/suppliers.service.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/suppliers/suppliers.service.js b/src/suppliers/suppliers.service.js index 8ae82505..87d4d5d8 100644 --- a/src/suppliers/suppliers.service.js +++ b/src/suppliers/suppliers.service.js @@ -1,7 +1,10 @@ const knex = require("../db/connection"); function create(supplier) { - return knex("suppliers").insert(supplier).returning("*"); + return knex("suppliers") + .insert(supplier) + .returning("*") + .then((createdRecords) => createdRecords[0]); } function read(supplier_id) { @@ -12,7 +15,8 @@ function update(updatedSupplier) { return knex("suppliers") .select("*") .where({ supplier_id: updatedSupplier.supplier_id }) - .update(updatedSupplier, "*"); + .update(updatedSupplier, "*") + .then((updatedRecords) => updatedRecords[0]); } function destroy(supplier_id) { From 178a61a5ecabcb6f06123ae972684544cc85f061 Mon Sep 17 00:00:00 2001 From: Collin Date: Thu, 23 Nov 2023 22:38:45 -0500 Subject: [PATCH 35/35] Update knexfile.js --- knexfile.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/knexfile.js b/knexfile.js index bc97b719..cd1252ff 100644 --- a/knexfile.js +++ b/knexfile.js @@ -13,4 +13,14 @@ module.exports = { directory: path.join(__dirname, "src", "db", "seeds"), }, }, + production: { + client: "postgresql", + connection: DATABASE_URL, + migrations: { + directory: path.join(__dirname, "src", "db", "migrations"), + }, + seeds: { + directory: path.join(__dirname, "src", "db", "seeds"), + }, + }, };