commit 60559728d3292449bb736a5cea2be198307b32f2 Author: Adrien Burgun Date: Fri Mar 17 10:22:56 2023 +0100 :tada: First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a40e17 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +secret.json +node_modules/ +build/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..2a41676 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# ds52-tp (and at the same time ds53-tp) + +My answers to the DS52 and DS53 practical sessions (resp. "Database Optimization" and "Business Intelligence Big Data"). + +I chose to avoid using Oracle SQL as much as possible, because I believe that it is a piece of software whose entire purpose is to lock people into the Oracle ecosystem. + +## Running the code + +You will need to run a local version of the databases; [you can find docker images for those here](https://git.shadamethyst.xyz/amethyst/ds52-db). +You can then copy `secret.json.example` to `secret.json`, and fill in the credentials accordingly. + +*TODO: clean this up to automatically use docker* diff --git a/ds53-tp1/analytic/query-1.sql b/ds53-tp1/analytic/query-1.sql new file mode 100644 index 0000000..703a1b7 --- /dev/null +++ b/ds53-tp1/analytic/query-1.sql @@ -0,0 +1,23 @@ +-- Query 1: "2 last columns with the sum() analytic function" (?) +-- From the screenshots, this query should be a copy of the query 1 of the group-by part, +-- with two new columns that add a running sum, one global and one partitionned by year. + +SELECT + calendar_year_lookup.year, + outlet_lookup.shop_name, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold, + SUM(SUM(shop_facts.amount_sold)) + OVER (ORDER BY calendar_year_lookup.year, outlet_lookup.shop_name) + AS total_amount_sold_global_running_sum, + SUM(SUM(shop_facts.amount_sold)) + OVER ( + PARTITION BY calendar_year_lookup.year + ORDER BY calendar_year_lookup.year, outlet_lookup.shop_name + ) + AS total_amount_sold_yearly_running_sum +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +GROUP BY outlet_lookup.shop_code, calendar_year_lookup.year +ORDER BY calendar_year_lookup.year, outlet_lookup.shop_name; diff --git a/ds53-tp1/analytic/query-2.sql b/ds53-tp1/analytic/query-2.sql new file mode 100644 index 0000000..5799760 --- /dev/null +++ b/ds53-tp1/analytic/query-2.sql @@ -0,0 +1,20 @@ +-- Query 2: "rank() by amount sold and quantity sold" +-- From the screenshots, the query should be the same as query 1 of the group-by part, +-- without grouping by year, and with two new columns that rank each shop: +-- - once by turnover (??, assuming that turnover is equal to amount_sold) +-- - once by quantity + +SELECT + outlet_lookup.shop_name, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold, + RANK() + OVER (ORDER BY total_amount_sold DESC) + AS amount_rank, + RANK() + OVER (ORDER BY total_quantity_sold DESC) + AS quantity_rank +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +GROUP BY outlet_lookup.shop_code +ORDER BY amount_rank; diff --git a/ds53-tp1/analytic/query-3.sql b/ds53-tp1/analytic/query-3.sql new file mode 100644 index 0000000..18ee7d4 --- /dev/null +++ b/ds53-tp1/analytic/query-3.sql @@ -0,0 +1,26 @@ +-- Query 3: "" (sic) +-- From the screenshots, the query should be the same as query 2, +-- but with years introduced + +SELECT + calendar_year_lookup.year, + outlet_lookup.shop_name, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold, + RANK() + OVER ( + PARTITION BY calendar_year_lookup.year + ORDER BY total_amount_sold DESC + ) + AS amount_rank, + RANK() + OVER ( + PARTITION BY calendar_year_lookup.year + ORDER BY total_quantity_sold DESC + ) + AS quantity_rank +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +GROUP BY calendar_year_lookup.year, outlet_lookup.shop_code +ORDER BY calendar_year_lookup.year, amount_rank; diff --git a/ds53-tp1/analytic/query-4.sql b/ds53-tp1/analytic/query-4.sql new file mode 100644 index 0000000..e32bbe7 --- /dev/null +++ b/ds53-tp1/analytic/query-4.sql @@ -0,0 +1,40 @@ +-- Query 4: amount sold for shop_code 351 + +( + SELECT + calendar_year_lookup.year, + calendar_year_lookup.month, + SUM(shop_facts.amount_sold) AS "amount sold", + SUM(SUM(shop_facts.amount_sold)) + OVER(ORDER BY calendar_year_lookup.week_key) + AS "running amount sold", + SUM(SUM(shop_facts.amount_sold)) + OVER( + PARTITION BY calendar_year_lookup.year + ORDER BY calendar_year_lookup.week_key + ) + AS "running year amount sold" + FROM shop_facts + INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key + WHERE shop_facts.shop_code = 351 + GROUP BY calendar_year_lookup.year, calendar_year_lookup.month + ORDER BY calendar_year_lookup.year, calendar_year_lookup.month +) UNION ( + SELECT + NULL AS "year", + NULL AS "month", + SUM(shop_facts.amount_sold) AS "amount sold", + -- Because we are computing the last row by hand (grouping sets being unavailable in MySQL), + -- the last row's running amount is defined manually here. I have chosen to set it to the total sum + SUM(shop_facts.amount_sold) AS "running amount sold", + SUM(shop_facts.amount_sold) AS "running year amount sold" + FROM shop_facts + WHERE shop_facts.shop_code = 351 +); + +/* == TEST == +assert(result[12]["running amount sold"] === 807190.1); +assert(result[12]["running year amount sold"] === 85616.4); +assert(result.length === 37); +assert(result[36]["amount sold"] === 3258640.5); +*/ diff --git a/ds53-tp1/analytic/query-5.sql b/ds53-tp1/analytic/query-5.sql new file mode 100644 index 0000000..b160a72 --- /dev/null +++ b/ds53-tp1/analytic/query-5.sql @@ -0,0 +1,2 @@ +/* TODO: windowing */ +SELECT * FROM shop_facts; diff --git a/ds53-tp1/group-by/query-1.sql b/ds53-tp1/group-by/query-1.sql new file mode 100644 index 0000000..f23e326 --- /dev/null +++ b/ds53-tp1/group-by/query-1.sql @@ -0,0 +1,12 @@ +-- Query 1: Total amount sold and total quantity for each shop name by year. + +SELECT + outlet_lookup.shop_name, + calendar_year_lookup.year, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +GROUP BY outlet_lookup.shop_code, calendar_year_lookup.year +ORDER BY calendar_year_lookup.year, outlet_lookup.shop_name; diff --git a/ds53-tp1/group-by/query-2.sql b/ds53-tp1/group-by/query-2.sql new file mode 100644 index 0000000..d2137cb --- /dev/null +++ b/ds53-tp1/group-by/query-2.sql @@ -0,0 +1,13 @@ +-- Query 2: Filtered version of query 1, to only show "e-Fashion San Francisco" and with descending years + +SELECT + outlet_lookup.shop_name, + calendar_year_lookup.year, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +WHERE outlet_lookup.shop_name = "e-Fashion San Francisco" +GROUP BY calendar_year_lookup.year +ORDER BY calendar_year_lookup.year DESC; diff --git a/ds53-tp1/group-by/query-3.sql b/ds53-tp1/group-by/query-3.sql new file mode 100644 index 0000000..43da0ee --- /dev/null +++ b/ds53-tp1/group-by/query-3.sql @@ -0,0 +1,12 @@ +-- Query 3: Total amount sold and total quantity for each shop name in 2001. + +SELECT + outlet_lookup.shop_name, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +WHERE calendar_year_lookup.year = 2001 +GROUP BY outlet_lookup.shop_code, calendar_year_lookup.year +ORDER BY total_amount_sold DESC; diff --git a/ds53-tp1/group-by/query-4.sql b/ds53-tp1/group-by/query-4.sql new file mode 100644 index 0000000..f97cfa3 --- /dev/null +++ b/ds53-tp1/group-by/query-4.sql @@ -0,0 +1,13 @@ +-- Query 4: Filtered version of query 3, to only show shops with at least 1M in sales + +SELECT + outlet_lookup.shop_name, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +WHERE calendar_year_lookup.year = 2001 +GROUP BY outlet_lookup.shop_code, calendar_year_lookup.year +HAVING total_amount_sold >= 1000000 +ORDER BY total_amount_sold DESC; diff --git a/ds53-tp1/group-by/query-5-2.sql b/ds53-tp1/group-by/query-5-2.sql new file mode 100644 index 0000000..8018924 --- /dev/null +++ b/ds53-tp1/group-by/query-5-2.sql @@ -0,0 +1,16 @@ +-- Query 5-2: same as query 5, but with the "grouping" columns + +SELECT + calendar_year_lookup.year, + outlet_lookup.shop_name, + (calendar_year_lookup.year IS NULL) as niveau_annee, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold, + (outlet_lookup.shop_name IS NULL) as niveau_magasin, + -- Note: GROUPING_ID is only available on Oracle SQL and MSSQL, so we recreate it here + (outlet_lookup.shop_name IS NULL) + (calendar_year_lookup.year IS NULL) * 2 as niveau_global +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +-- Note: shop_name must be used here instead of shop_code for NULL to be handled properly. +GROUP BY calendar_year_lookup.year ASC, outlet_lookup.shop_name ASC WITH ROLLUP; diff --git a/ds53-tp1/group-by/query-5.sql b/ds53-tp1/group-by/query-5.sql new file mode 100644 index 0000000..cc26527 --- /dev/null +++ b/ds53-tp1/group-by/query-5.sql @@ -0,0 +1,12 @@ +-- Query 5: same as query 1, but with the "rollup" option. + +SELECT + calendar_year_lookup.year, + outlet_lookup.shop_name, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +-- Note: shop_name must be used here instead of shop_code for NULL to be handled properly. +GROUP BY calendar_year_lookup.year ASC, outlet_lookup.shop_name ASC WITH ROLLUP; diff --git a/ds53-tp1/group-by/query-6-2.sql b/ds53-tp1/group-by/query-6-2.sql new file mode 100644 index 0000000..05d93d3 --- /dev/null +++ b/ds53-tp1/group-by/query-6-2.sql @@ -0,0 +1,14 @@ +-- Query 6-2: same as query 6, but with a "grouping_id" column. + +SELECT + calendar_year_lookup.year, + outlet_lookup.state, + outlet_lookup.shop_name, + (calendar_year_lookup.year IS NULL) * 4 + (outlet_lookup.state IS NULL) * 2 + (outlet_lookup.shop_name IS NULL) AS niveau_global, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +-- Note: "Grouping sets" is only available on Oracle SQL, so it is manually recreated here +GROUP BY calendar_year_lookup.year ASC, outlet_lookup.state, outlet_lookup.shop_name ASC WITH ROLLUP; diff --git a/ds53-tp1/group-by/query-6.sql b/ds53-tp1/group-by/query-6.sql new file mode 100644 index 0000000..cb2bae2 --- /dev/null +++ b/ds53-tp1/group-by/query-6.sql @@ -0,0 +1,13 @@ +-- Query 6: same as query 5, but with a "grouping sets" option. + +SELECT + calendar_year_lookup.year, + outlet_lookup.state, + outlet_lookup.shop_name, + SUM(shop_facts.amount_sold) AS total_amount_sold, + SUM(shop_facts.quantity_sold) AS total_quantity_sold +FROM outlet_lookup +INNER JOIN shop_facts ON shop_facts.shop_code = outlet_lookup.shop_code +INNER JOIN calendar_year_lookup ON shop_facts.week_key = calendar_year_lookup.week_key +-- Note: "Grouping sets" is only available on Oracle SQL, so it is manually recreated here +GROUP BY calendar_year_lookup.year ASC, outlet_lookup.state, outlet_lookup.shop_name ASC WITH ROLLUP; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a9c2333 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1146 @@ +{ + "name": "ds52-tp", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "ds52-tp", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "chalk": "^5.2.0", + "csv-string": "^4.1.1", + "deep-equal": "^2.2.0", + "mkdirp": "^2.1.5", + "mysql": "^2.18.1" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/csv-string": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/csv-string/-/csv-string-4.1.1.tgz", + "integrity": "sha512-KGvaJEZEdh2O/EVvczwbPLqJZtSQaWQ4cEJbiOJEG4ALq+dBBqNmBkRXTF4NV79V25+XYtiqbco1IWrmHLm5FQ==", + "engines": { + "node": ">=12.0" + } + }, + "node_modules/deep-equal": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", + "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "dependencies": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/mkdirp": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.5.tgz", + "integrity": "sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + } + }, + "dependencies": { + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "csv-string": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/csv-string/-/csv-string-4.1.1.tgz", + "integrity": "sha512-KGvaJEZEdh2O/EVvczwbPLqJZtSQaWQ4cEJbiOJEG4ALq+dBBqNmBkRXTF4NV79V25+XYtiqbco1IWrmHLm5FQ==" + }, + "deep-equal": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", + "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "requires": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + } + } + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + } + } + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "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-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" + }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "mkdirp": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.5.tgz", + "integrity": "sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w==" + }, + "mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "requires": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + } + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "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==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==" + }, + "stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "requires": { + "internal-slot": "^1.0.4" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..dcc4792 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "ds52-tp", + "version": "1.0.0", + "description": "", + "main": "src/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "type": "module", + "author": "", + "license": "ISC", + "dependencies": { + "chalk": "^5.2.0", + "csv-string": "^4.1.1", + "deep-equal": "^2.2.0", + "mkdirp": "^2.1.5", + "mysql": "^2.18.1" + } +} diff --git a/secret.json.example b/secret.json.example new file mode 100644 index 0000000..1489468 --- /dev/null +++ b/secret.json.example @@ -0,0 +1,5 @@ +{ + "host": "localhost", + "user": "your_user", + "password": "your_password" +} diff --git a/src/build.js b/src/build.js new file mode 100644 index 0000000..3ba94e9 --- /dev/null +++ b/src/build.js @@ -0,0 +1,43 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import mkdirp from "mkdirp"; + +const TRANSFORMS = [ + (str) => str.replace(/,\n( +)/g, (_, spaces) => `\n${spaces},`), + (str) => str.replace(/(?<=\s)AS\s+([a-z].*?),?(?=\n)/gi, (_, label) => "AS `" + label + "`"), + (str) => str.replace(/(?<=\s)AS\s+["'`](.*?)["'`]/gi, (_, label) => "AS `" + label + "`"), + (str) => str.replace( + /^( *)FROM ([a-z0-9]+(?: [a-z0-9]+)?;?)$/gmi, + (_, spaces, label) => `${spaces}FROM\n${spaces} ${label}` + ) +]; + +async function generate(folder) { + let res = ""; + + for (const file of sortFiles(await fs.readdir(folder))) { + const rawQuery = await fs.readFile(path.join(folder, file), "utf8"); + let sql = rawQuery.split(/\/\*|\*\//g).filter((_, i) => i % 2 === 0); + + for (const transform of TRANSFORMS) { + sql = transform(sql); + } + + res += "\n\n" + sql.trim(); + } + + return res.trim(); +} + +await mkdirp("./build"); + +await fs.writeFile("./build/tp1.sql", await generate("./tp1")); + +function sortFiles(files) { + const collator = new Intl.Collator(undefined, { + numeric: true, + sensitivity: "base" + }); + + return files.sort(collator.compare); +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..efd643d --- /dev/null +++ b/src/index.js @@ -0,0 +1,169 @@ +import mysql from "mysql"; +import fs from "node:fs/promises"; +import path from "node:path"; +import assert from "node:assert"; +import { parse } from "csv-string"; +import deepEqual from "deep-equal"; +import chalk from "chalk"; + +const secret = JSON.parse(await fs.readFile('./secret.json', 'utf8')); + +await runTests({ + database: 'cafe', +}, './tp1'); + +await runTests({ + database: 'course', +}, './tp2/'); + +await runTests({ + database: 'emode', +}, './ds53-tp1/group-by'); + +await runTests({ + database: 'emode', +}, './ds53-tp1/analytic'); + +async function runTests(mysqlSettings, folder) { + const connection = mysql.createConnection({ + ...secret, + ...mysqlSettings, + }); + + connection.connect(); + + for (const file of sortFiles(await fs.readdir(folder))) { + const rawQuery = await fs.readFile(path.join(folder, file), "utf8"); + + let sql = rawQuery.split(/\/\*|\*\//g).filter((_, i) => i % 2 === 0).join("\n"); + let comments = rawQuery.split(/\/\*|\*\//g).filter((_, i) => i % 2 === 1); + + let res = await query(sql.trim()); + if ( + process.argv.includes(file) + || process.argv.includes(file.replace(".sql", "")) + || path.join(folder, file).replace(".sql", "").endsWith(process.argv[process.argv.length - 1]) + ) { + console.table(res); + } + + const result = runTest(res, comments, file); + if (result === undefined) { + console.log(chalk.yellow("NO TEST ") + file); + } else if (result) { + console.log(chalk.green("SUCCESS ") + file); + } else { + console.log(chalk.red("FAIL ") + file); + } + } + + connection.end(); + + function query(query) { + return new Promise((resolve, reject) => { + connection.query(query, (error, results, fields) => { + if (error) return reject(error); + resolve(results); + }); + }); + } +} + +function checkEqual(actual, expected, name) { + // Build diff of missing and superfluous items in actual + const missing = new Set(); + const superfluous = new Set(); + + for (const row of actual) { + if (!expected.find((value) => deepEqual(value, row))) { + superfluous.add(row); + } + } + + for (const row of expected) { + if (!actual.find((value) => deepEqual(value, row))) { + missing.add(row); + } + } + + if (missing.size > 0 || superfluous.size > 0) { + console.error("Mismatch: there are rows missing or superfluous!"); + console.error("Expected:", expected); + console.error("Actual:", actual); + console.error("Missing rows in actual:"); + console.error([...missing.values()].map(row => `- ${JSON.stringify(row)}`).join("\n")); + console.error("Superfluous rows in actual"); + console.error([...superfluous.values()].map(row => `- ${JSON.stringify(row)}`).join("\n")); + return false; + } + + // Then, check for order + const misordered = new Set(); + for (let n = 0; n < expected.length; n++) { + if (!deepEqual(actual[n], expected[n])) { + misordered.add(n); + } + } + + if (misordered.size > 0) { + console.error("Mismatch: rows do not have the same order!"); + console.error("Expected:", expected); + console.error("Actual:"); + for (let n = 0; n < actual.length; n++) { + if (misordered.has(n)) { + console.error(`- ${chalk.red(JSON.stringify(actual[n]))}`); + } else { + console.error(` ${JSON.stringify(actual[n])}`); + } + } + return false; + } + + return true; +} + +function lowercaseFirstLine(str) { + const [firstLine, ...rest] = str.split("\n"); + + return firstLine.toLowerCase() + "\n" + rest.join("\n"); +} + +function sortFiles(files) { + const collator = new Intl.Collator(undefined, { + numeric: true, + sensitivity: "base" + }); + + return files.sort(collator.compare); +} + +function runTest(queryResult, comments, file) { + let checked = false; + for (let comment of comments) { + let [, title, ...rest] = comment.split("=="); + if (!rest.length || !title) continue; + title = title.trim(); + rest = rest.join("=="); + if (title === "RESULT") { + const csv = parse(lowercaseFirstLine(rest.trim()), { output: "objects" }); + + const res = queryResult.map((x) => Object.entries(x).reduce((acc, [key, value]) => { + acc[key] = String(value); + return acc; + }, {})); + + if (!checkEqual(res, csv, file)) return false; + checked = true; + } else if (title === "TEST") { + const result = queryResult; + eval(rest); + checked = true; + } + } + + if (!checked) { + return undefined; + } else { + return true; + } +} diff --git a/tp1/1.sql b/tp1/1.sql new file mode 100644 index 0000000..7b34b9d --- /dev/null +++ b/tp1/1.sql @@ -0,0 +1,10 @@ +-- Query 1: Liste des serveurs +SELECT nomserveur, villeserveur FROM serveur; +/* == RESULT == +"NOMSERVEUR","VILLESERVEUR" +"Durant Pierre", "BELFORT" +"Duchemin Paul", "DELLE" +"Martin Cathy", "BAVILLIERS" +"Pillot Alain", "BELFORT" +"Séré Alain", "DIJON" +*/ diff --git a/tp1/10.sql b/tp1/10.sql new file mode 100644 index 0000000..ae97753 --- /dev/null +++ b/tp1/10.sql @@ -0,0 +1,17 @@ +-- Query 10: Liste des 3 consommations de type bière avec le prix le plus élevé + +SELECT + cns.numcons as 'numéro', + cns.libcons as 'libellé', + cns.prixcons as 'prix' +FROM consommation cns +WHERE cns.libcons LIKE "Bière%" +ORDER BY cns.prixcons DESC, cns.libcons ASC +FETCH FIRST 3 ROWS ONLY; + +/* == RESULT == +"Numéro","Libellé","Prix" +110,"Bière 50 Cl",4.5 +200,"Bière Blonde",4.5 +108,"Bière 33 Cl",3 +*/ diff --git a/tp1/11.sql b/tp1/11.sql new file mode 100644 index 0000000..cefbb83 --- /dev/null +++ b/tp1/11.sql @@ -0,0 +1,19 @@ +-- Query 11 + +SELECT + facture.numfacture, + facture.numtable, + tables.nomtable +FROM facture +INNER JOIN serveur ON serveur.numserveur = facture.numserveur +INNER JOIN tables ON tables.numtable = facture.numtable +WHERE + facture.datefacture = "20060222" + AND serveur.nomserveur = "Martin Cathy" +ORDER BY facture.numtable; + +/* == RESULT == +"numfacture","numtable","nomtable" +1206,3,"Fenetre1" +1204,4,"Fenetre2" +*/ diff --git a/tp1/12.sql b/tp1/12.sql new file mode 100644 index 0000000..b9e02a1 --- /dev/null +++ b/tp1/12.sql @@ -0,0 +1,24 @@ +-- Query 12 + +SELECT + consommation.numcons, + consommation.libcons, + consommation.prixcons, + comprend.qte AS quantite, + comprend.qte * consommation.prixcons AS "prixcons*quantite", + serveur.nomserveur +FROM + comprend +INNER JOIN facture ON facture.numfacture = comprend.numfacture +INNER JOIN serveur ON serveur.numserveur = facture.numserveur +INNER JOIN consommation ON consommation.numcons = comprend.numcons +WHERE facture.numfacture = 1203; + +/* == RESULT == +"numcons","libcons","prixcons","quantite","prixcons*quantite","nomserveur" +101,"Café double",2,1,2,"Durant Pierre" +102,"Café crème",1.6,1,1.6,"Durant Pierre" +108,"Bière 33 Cl",3,1,3,"Durant Pierre" +121,"Fruit pressé",3,1,3,"Durant Pierre" +130,"Coca Cola",2,1,2,"Durant Pierre" +*/ diff --git a/tp1/13.sql b/tp1/13.sql new file mode 100644 index 0000000..4d33b0b --- /dev/null +++ b/tp1/13.sql @@ -0,0 +1,16 @@ +-- Query 13 + +SELECT + srv2.numserveur, + srv2.nomserveur, + srv2.villeserveur +FROM serveur srv1 +INNER JOIN serveur srv2 ON srv1.villeserveur = srv2.villeserveur +WHERE + srv1.nomserveur = "Durant Pierre" + AND srv1.numserveur != srv2.numserveur; + +/* == RESULT == +"numserveur","nomserveur","villeserveur" +53,"Pillot Alain","BELFORT" +*/ diff --git a/tp1/14.sql b/tp1/14.sql new file mode 100644 index 0000000..22acedb --- /dev/null +++ b/tp1/14.sql @@ -0,0 +1,10 @@ +-- Query 14 + +SELECT + COUNT(tables.numtable) AS "nb tables" +FROM tables; + +/* == RESULT == +"nb tables" +6 +*/ diff --git a/tp1/15.sql b/tp1/15.sql new file mode 100644 index 0000000..0e8e5b6 --- /dev/null +++ b/tp1/15.sql @@ -0,0 +1,11 @@ +-- Query 15 + +SELECT + COUNT(serveur.numserveur) AS "nb serveur" +FROM serveur +WHERE serveur.villeserveur = "BELFORT"; + +/* == RESULT == +"nb serveur" +2 +*/ diff --git a/tp1/16.sql b/tp1/16.sql new file mode 100644 index 0000000..c08d863 --- /dev/null +++ b/tp1/16.sql @@ -0,0 +1,13 @@ +-- Query 16 + +SELECT + COUNT(facture.numfacture) AS "nb facture" +FROM + facture +INNER JOIN serveur ON serveur.numserveur = facture.numserveur +WHERE serveur.nomserveur = "Martin Cathy"; + +/* == RESULT == +"nb facture" +12 +*/ diff --git a/tp1/17.sql b/tp1/17.sql new file mode 100644 index 0000000..c0b6b29 --- /dev/null +++ b/tp1/17.sql @@ -0,0 +1,11 @@ +-- Query 17 + +SELECT + ROUND(AVG(consommation.prixcons), 2) AS "prix moyen" +FROM + consommation; + +/* == RESULT == +"prix moyen" +2.86 +*/ diff --git a/tp1/18.sql b/tp1/18.sql new file mode 100644 index 0000000..84827e2 --- /dev/null +++ b/tp1/18.sql @@ -0,0 +1,11 @@ +-- Query 18 + +SELECT + ROUND(AVG(consommation.prixcons), 2) AS "prix moyen" +FROM consommation +WHERE REGEXP_INSTR(consommation.libcons, "^Café"); + +/* == RESULT == +"prix moyen" +1.53 +*/ diff --git a/tp1/19.sql b/tp1/19.sql new file mode 100644 index 0000000..9af383a --- /dev/null +++ b/tp1/19.sql @@ -0,0 +1,18 @@ +-- Query 19 + +SELECT + serveur.numserveur, + serveur.nomserveur, + COUNT(facture.numfacture) AS "nb factures" +FROM + facture +INNER JOIN serveur ON serveur.numserveur = facture.numserveur +GROUP BY serveur.numserveur +HAVING COUNT(facture.numfacture) >= 5 +ORDER BY serveur.numserveur DESC; + +/* == RESULT == +"numserveur","nomserveur","nb factures" +53,"Pillot Alain",16 +52,"Martin Cathy",12 +*/ diff --git a/tp1/2.sql b/tp1/2.sql new file mode 100644 index 0000000..e8aa323 --- /dev/null +++ b/tp1/2.sql @@ -0,0 +1,13 @@ +-- Query 2: Liste des villes des serveurs +SELECT DISTINCT + serveur.villeserveur +FROM + serveur +ORDER BY serveur.villeserveur; +/* == RESULT == +"VILLESERVEUR" +"BAVILLIERS" +"BELFORT" +"DELLE" +"DIJON" +*/ diff --git a/tp1/20-1.sql b/tp1/20-1.sql new file mode 100644 index 0000000..bde7102 --- /dev/null +++ b/tp1/20-1.sql @@ -0,0 +1,48 @@ +-- Query 20 + +SELECT + comprend.numfacture, + SUM(comprend.qte) AS 'nb conso' +FROM + comprend +GROUP BY comprend.numfacture; + +/* == RESULT == +"numfacture","nb conso" +1000,4 +1001,5 +1002,2 +1003,6 +1004,5 +1005,7 +1006,2 +1007,4 +1008,5 +1009,4 +1010,4 +1011,1 +1012,3 +1013,5 +1014,2 +1015,4 +1016,1 +1017,5 +1100,2 +1101,4 +1102,3 +1103,5 +1104,7 +1105,5 +1106,3 +1107,3 +1108,2 +1200,6 +1201,4 +1202,3 +1203,5 +1204,7 +1205,5 +1206,3 +1207,5 +1208,2 +*/ diff --git a/tp1/20-2.sql b/tp1/20-2.sql new file mode 100644 index 0000000..d001503 --- /dev/null +++ b/tp1/20-2.sql @@ -0,0 +1,8 @@ +-- Query 20-2: with sort +SELECT + comprend.numfacture, + SUM(comprend.qte) AS 'nb conso' +FROM + comprend +GROUP BY comprend.numfacture +ORDER BY SUM(comprend.qte) DESC, comprend.numfacture; diff --git a/tp1/21.sql b/tp1/21.sql new file mode 100644 index 0000000..693a411 --- /dev/null +++ b/tp1/21.sql @@ -0,0 +1,16 @@ +-- Query 21 + +SELECT + serveur.villeserveur as 'ville', + COUNT(serveur.numserveur) as 'nb serveurs' +FROM + serveur +GROUP BY serveur.villeserveur; + +/* == RESULT == +"Ville","Nb Serveurs" +"BAVILLIERS",1 +"BELFORT",2 +"DELLE",1 +"DIJON",1 +*/ diff --git a/tp1/22.sql b/tp1/22.sql new file mode 100644 index 0000000..8b54b9a --- /dev/null +++ b/tp1/22.sql @@ -0,0 +1,27 @@ +-- Query 22: nombre de factures établies chaque jour + +SELECT + DATE_FORMAT(facture.datefacture, "%d/%m/%y") AS 'date', + COUNT(facture.numfacture) AS 'nb factures' +FROM facture +GROUP BY facture.datefacture +ORDER BY facture.datefacture; + +/* == RESULT == +"Date","Nb factures" +"01/12/05",1 +"02/12/05",2 +"04/12/05",2 +"05/12/05",1 +"06/12/05",1 +"07/12/05",1 +"08/12/05",1 +"09/12/05",4 +"10/12/05",1 +"11/12/05",2 +"12/12/05",2 +"21/01/06",4 +"22/01/06",5 +"21/02/06",4 +"22/02/06",5 +*/ diff --git a/tp1/23.sql b/tp1/23.sql new file mode 100644 index 0000000..8a73258 --- /dev/null +++ b/tp1/23.sql @@ -0,0 +1,20 @@ +-- Query 23 + +SELECT + facture.numfacture AS 'facture', + DATE_FORMAT(facture.datefacture, "%d/%m/%y") AS 'date', + COUNT(comprend.numcons) AS 'nb conso' +FROM comprend +INNER JOIN facture ON comprend.numfacture = facture.numfacture +WHERE facture.datefacture < "20060222" +GROUP BY facture.numfacture +HAVING `nb conso` > 3 +ORDER BY SUM(comprend.numcons) DESC; + +/* == RESULT == +"Facture","Date","Nb conso" +1003,"04/12/05",6 +1203,"21/02/06",5 +1103,"21/01/06",5 +1200,"21/02/06",4 +*/ diff --git a/tp1/24.sql b/tp1/24.sql new file mode 100644 index 0000000..9535318 --- /dev/null +++ b/tp1/24.sql @@ -0,0 +1,27 @@ +-- Query 24 + +SELECT + consommation.numcons, + consommation.libcons, + ( + SELECT COUNT(comprend.numfacture) + FROM comprend + WHERE comprend.numcons = consommation.numcons + ) AS `nb factures` +FROM consommation +HAVING `nb factures` >= 2; + +/* == RESULT == +"NUMCONS","LIBCONS","Nb factures" +100,"Café",10 +101,"Café double",13 +102,"Café crème",11 +105,"Chocolat",5 +106,"Bière pression",6 +107,"Bière 25 Cl",5 +108,"Bière 33 Cl",13 +110,"Bière 50 Cl",3 +122,"Perrier",7 +124,"Orangina",8 +130,"Coca Cola",6 +*/ diff --git a/tp1/25.sql b/tp1/25.sql new file mode 100644 index 0000000..7cf7968 --- /dev/null +++ b/tp1/25.sql @@ -0,0 +1,19 @@ +-- Query 25: same as query 13, but using a subrequest + +SELECT + srv2.numserveur, + srv2.nomserveur, + srv2.villeserveur +FROM serveur srv2 +WHERE + srv2.villeserveur IN ( + SELECT srv1.villeserveur + FROM serveur srv1 + WHERE srv1.nomserveur = "Durant Pierre" + ) + AND srv2.nomserveur != "Durant Pierre"; + +/* == RESULT == +"numserveur","nomserveur","villeserveur" +53,"Pillot Alain","BELFORT" +*/ diff --git a/tp1/26.sql b/tp1/26.sql new file mode 100644 index 0000000..ea6ba1b --- /dev/null +++ b/tp1/26.sql @@ -0,0 +1,17 @@ +-- Query 26 + +SELECT + serveur.numserveur, + serveur.nomserveur +FROM serveur +WHERE + NOT EXISTS ( + SELECT * + FROM facture + WHERE facture.numserveur = serveur.numserveur + ); + +/* == RESULT == +"numserveur","nomserveur" +54,"Séré Alain" +*/ diff --git a/tp1/27.sql b/tp1/27.sql new file mode 100644 index 0000000..e5e7950 --- /dev/null +++ b/tp1/27.sql @@ -0,0 +1,22 @@ +-- Query 27 + +SELECT + serveur.numserveur, + serveur.nomserveur +FROM serveur +WHERE + NOT EXISTS ( + SELECT * + FROM facture + WHERE + facture.numserveur = serveur.numserveur + AND facture.numtable = 1 + ); + +/* == RESULT == +"numserveur","nomserveur" +50,"Durant Pierre" +51,"Duchemin Paul" +52,"Martin Cathy" +54,"Séré Alain" +*/ diff --git a/tp1/28.sql b/tp1/28.sql new file mode 100644 index 0000000..abf40c5 --- /dev/null +++ b/tp1/28.sql @@ -0,0 +1,17 @@ +-- Query 28 + +SELECT + consommation.numcons AS 'numéro', + consommation.libcons AS 'libellé consommation' +FROM consommation +WHERE NOT EXISTS ( + SELECT comprend.numcons + FROM comprend + WHERE comprend.numcons = consommation.numcons +); + +/* == RESULT == +"Numéro","Libellé Consommation" +150,"Jus de tomate" +300,"Cocktail" +*/ diff --git a/tp1/29.sql b/tp1/29.sql new file mode 100644 index 0000000..b4ff0d6 --- /dev/null +++ b/tp1/29.sql @@ -0,0 +1,18 @@ +-- Query 29 + +SELECT + serveur.numserveur AS 'numéro serveur', + serveur.nomserveur AS 'nom serveur', + COUNT(facture.numfacture) AS 'nb factures' +FROM serveur +LEFT OUTER JOIN facture ON facture.numserveur = serveur.numserveur +GROUP BY serveur.numserveur; + +/* == RESULT == +"Numéro Serveur","Nom Serveur","Nb factures" +50,"Durant Pierre",4 +51,"Duchemin Paul",4 +52,"Martin Cathy",12 +53,"Pillot Alain",16 +54,"Séré Alain",0 +*/ diff --git a/tp1/3.sql b/tp1/3.sql new file mode 100644 index 0000000..6f7a5c3 --- /dev/null +++ b/tp1/3.sql @@ -0,0 +1,17 @@ +-- Query 3: Liste classée des serveurs par ville +SELECT + serveur.nomserveur, + serveur.villeserveur +FROM + serveur +ORDER BY + serveur.villeserveur, + serveur.nomserveur DESC; +/* == RESULT == +"NOMSERVEUR","VILLESERVEUR" +"Martin Cathy","BAVILLIERS" +"Pillot Alain","BELFORT" +"Durant Pierre","BELFORT" +"Duchemin Paul","DELLE" +"Séré Alain","DIJON" +*/ diff --git a/tp1/30.sql b/tp1/30.sql new file mode 100644 index 0000000..672e213 --- /dev/null +++ b/tp1/30.sql @@ -0,0 +1,17 @@ +-- Query 30: Consommation la moins chère + +SELECT + cns1.numcons AS 'numéro', + cns1.libcons AS 'libellé consommation', + cns1.prixcons AS 'prix le moins élevé' +FROM consommation cns1 +WHERE + cns1.prixcons = ( + SELECT MIN(cns2.prixcons) + FROM consommation cns2 + ); + +/* == RESULT == +"Numéro","Libellé Consommation","Prix le moins élevé" +100,"Café",1 +*/ diff --git a/tp1/31.sql b/tp1/31.sql new file mode 100644 index 0000000..8b6600e --- /dev/null +++ b/tp1/31.sql @@ -0,0 +1,24 @@ +-- Query 31: Consommations les plus chères servies par Pillot Alain + +SELECT + cns1.numcons AS 'numéro', + cns1.libcons AS 'libellé consommation', + cns1.prixcons AS 'prix' +FROM + consommation cns1 +WHERE + cns1.prixcons = ( + SELECT MAX(cns2.prixcons) + FROM consommation cns2 + INNER JOIN comprend ON comprend.numcons = cns2.numcons + INNER JOIN facture ON facture.numfacture = comprend.numfacture + INNER JOIN serveur ON facture.numserveur = serveur.numserveur + WHERE + serveur.nomserveur = "Pillot Alain" + ); + +/* == RESULT == +"Numéro","Libellé Consommation","Prix" +110,"Bière 50 Cl",4.5 +200,"Bière Blonde",4.5 +*/ diff --git a/tp1/32.sql b/tp1/32.sql new file mode 100644 index 0000000..b6310a6 --- /dev/null +++ b/tp1/32.sql @@ -0,0 +1,27 @@ +-- Query 32 + +SELECT + tables.numtable, + SUM(comprend.qte * consommation.prixcons) AS prix +FROM tables +INNER JOIN facture ON facture.numtable = tables.numtable +INNER JOIN comprend ON comprend.numfacture = facture.numfacture +INNER JOIN consommation ON consommation.numcons = comprend.numcons +GROUP BY tables.numtable +HAVING prix = ( + SELECT MAX(prix.prix) + FROM ( + SELECT + SUM(comprend.qte * consommation.prixcons) AS prix + FROM tables + INNER JOIN facture ON facture.numtable = tables.numtable + INNER JOIN comprend ON comprend.numfacture = facture.numfacture + INNER JOIN consommation ON consommation.numcons = comprend.numcons + GROUP BY tables.numtable + ) AS prix +); + +/* == RESULT == +"numtable","prix" +5,126.9 +*/ diff --git a/tp1/4.sql b/tp1/4.sql new file mode 100644 index 0000000..17a164c --- /dev/null +++ b/tp1/4.sql @@ -0,0 +1,28 @@ +-- Query 4: Liste des consommations dont le prix unitaire > 1.5€, classée par libéllé +SELECT + cns.numcons as 'numéro', + cns.libcons as 'libellé', + cns.prixcons as 'prix' +FROM + consommation cns +WHERE + cns.prixcons > 1.5 +ORDER BY cns.libcons; +/* == RESULT == +"Numéro","Libellé","Prix" +107,"Bière 25 Cl",2.5 +108,"Bière 33 Cl",3 +110,"Bière 50 Cl",4.5 +200,"Bière Blonde",4.5 +106,"Bière pression",2.5 +102,"Café crème",1.6 +101,"Café double",2 +105,"Chocolat",2 +130,"Coca Cola",2 +300,"Cocktail",8 +121,"Fruit pressé",3 +120,"Jus de fruit",2 +150,"Jus de tomate",2 +124,"Orangina",2.7 +122,"Perrier",2.5 +*/ diff --git a/tp1/5.sql b/tp1/5.sql new file mode 100644 index 0000000..d8ae712 --- /dev/null +++ b/tp1/5.sql @@ -0,0 +1,16 @@ +-- Query 5: Liste des factures du 22/02/06 +SELECT + facture.numfacture, + facture.numtable, + facture.numserveur, + DATE_FORMAT(facture.datefacture, '%d/%m/%y') as 'datefact' +FROM facture +WHERE facture.datefacture = '2006-02-22'; +/* == RESULT == +"NUMFACTURE","NUMTABLE","NUMSERVEUR","DATEFACT" +1204,4,52,"22/02/06" +1205,1,53,"22/02/06" +1206,3,52,"22/02/06" +1207,5,53,"22/02/06" +1208,7,51,"22/02/06" +*/ diff --git a/tp1/6.sql b/tp1/6.sql new file mode 100644 index 0000000..1a80c71 --- /dev/null +++ b/tp1/6.sql @@ -0,0 +1,11 @@ +-- Query 6: Liste des serveurs dont le nom contient un i en deuxième position. +SELECT serveur.nomserveur +FROM serveur +WHERE REGEXP_INSTR(serveur.nomserveur, "^.i"); +-- Alternativement: +-- WHERE serveur.nomserveur LIKE "_i%"; + +/* == RESULT == +"NOMSERVEUR" +"Pillot Alain" +*/ diff --git a/tp1/7.sql b/tp1/7.sql new file mode 100644 index 0000000..87c7ca2 --- /dev/null +++ b/tp1/7.sql @@ -0,0 +1,13 @@ +-- Query 7: Liste des serveurs dont le nom commence par un D. +SELECT + numserveur, + nomserveur +FROM serveur +WHERE serveur.nomserveur LIKE "D%" +ORDER BY serveur.nomserveur; + +/* == RESULT == +"NUMSERVEUR","NOMSERVEUR" +51,"Duchemin Paul" +50,"Durant Pierre" +*/ diff --git a/tp1/8.sql b/tp1/8.sql new file mode 100644 index 0000000..7fe448c --- /dev/null +++ b/tp1/8.sql @@ -0,0 +1,27 @@ +-- Query 8: Liste des consommations classées par ordre alphabétique sur le libellé +SELECT + cns.libcons as 'libellé', + cns.numcons as 'numéro', + cns.prixcons as 'prix' +FROM consommation cns +ORDER BY cns.libcons; + +/* == RESULT == +"Libellé","Numéro","Prix" +"Bière 25 Cl",107,2.5 +"Bière 33 Cl",108,3 +"Bière 50 Cl",110,4.5 +"Bière Blonde",200,4.5 +"Bière pression",106,2.5 +"Café",100,1 +"Café crème",102,1.6 +"Café double",101,2 +"Chocolat",105,2 +"Coca Cola",130,2 +"Cocktail",300,8 +"Fruit pressé",121,3 +"Jus de fruit",120,2 +"Jus de tomate",150,2 +"Orangina",124,2.7 +"Perrier",122,2.5 +*/ diff --git a/tp1/9.sql b/tp1/9.sql new file mode 100644 index 0000000..bc4c637 --- /dev/null +++ b/tp1/9.sql @@ -0,0 +1,18 @@ +-- Query 9: Liste des consommations de type bière par prix décroissant et libellé croissant + +SELECT + cns.numcons as 'numéro', + cns.libcons as 'libellé', + cns.prixcons as 'prix' +FROM consommation cns +WHERE cns.libcons LIKE "Bière%" +ORDER BY cns.prixcons DESC, cns.libcons ASC; + +/* == RESULT == +"Numéro","Libellé","Prix" +110,"Bière 50 Cl",4.5 +200,"Bière Blonde",4.5 +108,"Bière 33 Cl",3 +107,"Bière 25 Cl",2.5 +106,"Bière pression",2.5 +*/ diff --git a/tp2/1.sql b/tp2/1.sql new file mode 100644 index 0000000..d0895ee --- /dev/null +++ b/tp2/1.sql @@ -0,0 +1 @@ +SELECT * FROM coureur;