diff --git a/.gitignore b/.gitignore index 2f49144f0..708374c22 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ node_modules/ +/*/.env +*/node_modules */node_modules/ **/*.DS_Store **/*-secret.json diff --git a/Week1/.gitignore b/Week1/.gitignore index 7df420767..b756fed36 100644 --- a/Week1/.gitignore +++ b/Week1/.gitignore @@ -1,3 +1,6 @@ package.json package-lock.json -create-table.js \ No newline at end of file +create-table.js + + +Week1/node_modules/ \ No newline at end of file diff --git a/Week1/exercise_1.js b/Week1/exercise_1.js new file mode 100644 index 000000000..965a3ca5d --- /dev/null +++ b/Week1/exercise_1.js @@ -0,0 +1,76 @@ +const mysql = require('mysql'); + +const connection = mysql.createConnection({ + host: 'localhost', + user: 'hyfuser', + password: 'hyfpassword', + multipleStatements: true +}); + + +/*Connect to SQL server*/ +connection.connect(err => { + if (err) { + return console.error('Connection error: ' + err.stack); + } + console.log('Connected!'); +}); + + +/*SQL queries*/ +const createDatabaseAndTables = + `DROP DATABASE IF EXISTS meetup; + CREATE DATABASE meetup; + USE meetup; + + CREATE TABLE Invitee ( + invitee_no INT AUTO_INCREMENT PRIMARY KEY, + invitee_name VARCHAR(100), + invited_by VARCHAR(100) + ); + + CREATE TABLE Room ( + room_no INT AUTO_INCREMENT PRIMARY KEY, + room_name VARCHAR(50), + floor_number INT + ); + + CREATE TABLE Meeting ( + meeting_no INT AUTO_INCREMENT PRIMARY KEY, + meeting_title VARCHAR(100), + starting_time DATETIME, + ending_time DATETIME, + room_no INT, + FOREIGN KEY (room_no) REFERENCES Room(room_no) + ); + + INSERT INTO Room (room_name, floor_number) VALUES + ('Paris', 1), + ('New York', 2), + ('Tokyo', 3), + ('London', 4), + ('Berlin', 5); + + INSERT INTO Invitee (invitee_name, invited_by) VALUES + ('Victor Hugo', 'Alexandre Dumas'), + ('Mark Twain', 'Henry James'), + ('Haruki Murakami', 'Kenzaburo Oe'), + ('Charles Dickens', 'Wilkie Collins'), + ('Albert Einstein', 'Niels Bohr'); + + INSERT INTO Meeting (meeting_title, starting_time, ending_time, room_no) VALUES + ('Literary Classics Discussion', '2024-08-01 09:00:00', '2024-08-01 10:00:00', 1), + ('American Literature Seminar', '2024-08-02 11:00:00', '2024-08-02 12:00:00', 2), + ('Japanese Fiction Workshop', '2024-08-03 14:00:00', '2024-08-03 15:00:00', 3), + ('Victorian Literature Symposium', '2024-08-04 16:00:00', '2024-08-04 17:00:00', 4), + ('Scientific Innovations Forum', '2024-08-05 13:00:00', '2024-08-05 14:00:00', 5);`; + + +// Execute the queries +connection.query(createDatabaseAndTables, (error, results, fields) => { + if (error) throw error; + console.log('Database and tables created, and data inserted'); +}); + +// Close the connection +connection.end(); \ No newline at end of file diff --git a/Week1/exercise_2.js b/Week1/exercise_2.js new file mode 100644 index 000000000..f4b24fecf --- /dev/null +++ b/Week1/exercise_2.js @@ -0,0 +1,44 @@ +const mysql = require('mysql'); + +const connection = mysql.createConnection({ + host: 'localhost', + user: 'hyfuser', + password: 'hyfpassword', + database: 'world' +}); + +/*Connect to SQL server*/ +connection.connect(err => { + if (err) { + return console.error('Connection error: ' + err.stack); + } + console.log('Connected!'); +}); + + +// Queries +const queries = [ + "SELECT Name FROM country WHERE Population > 8000000;", + "SELECT Name FROM country WHERE Name LIKE '%land%';", + "SELECT Name FROM city WHERE Population BETWEEN 500000 AND 1000000;", + "SELECT Name FROM country WHERE Continent = 'Europe';", + "SELECT Name FROM country ORDER BY SurfaceArea DESC;", + "SELECT Name FROM city WHERE CountryCode = 'NLD';", + "SELECT Population FROM city WHERE Name = 'Rotterdam';", + "SELECT Name FROM country ORDER BY SurfaceArea DESC LIMIT 10;", + "SELECT Name FROM city ORDER BY Population DESC LIMIT 10;", + "SELECT SUM(Population) AS WorldPopulation FROM country;" +]; + + +// Execute each query +queries.forEach((query, index) => { + connection.query(query, (error, results) => { + if (error) throw error; + console.log(`Query ${index + 1}:`); + console.log(results); + }); +}); + +// End the connection +connection.end(); \ No newline at end of file diff --git a/Week2/connection_query.js b/Week2/connection_query.js new file mode 100644 index 000000000..60e0cdc7b --- /dev/null +++ b/Week2/connection_query.js @@ -0,0 +1,29 @@ +//C:\Users\knowl\Documents\hyf\databases\Week2\connection_query.js +import mysql from 'mysql'; + +export const createNewConnection = () => { + return mysql.createConnection({ + host: 'localhost', + user: 'hyfuser', + password: 'hyfpassword', + multipleStatements: true, + }); +}; + +export const useDatabase = (connection) => { + return new Promise((resolve, reject) => { + const createDatabaseAndUse = ` + CREATE DATABASE IF NOT EXISTS w2_research; + USE w2_research; + `; + connection.query(createDatabaseAndUse, (err, results) => { + if (err) { + console.error('Error creating or selecting database:', err.stack); + reject(err); + return; + } + console.log('Database selected successfully.'); + resolve(); + }); + }); +}; \ No newline at end of file diff --git a/Week2/exercise_1.js b/Week2/exercise_1.js new file mode 100644 index 000000000..b5f052265 --- /dev/null +++ b/Week2/exercise_1.js @@ -0,0 +1,99 @@ +//C:\Users\knowl\Documents\hyf\databases\Week2\exercise_1.js +import {createNewConnection, useDatabase} from './connection_query.js'; + + +const createAuthorsTable = (connection) => { + return new Promise((resolve, reject) => { + const createAuthorsTableQuery = ` + CREATE TABLE IF NOT EXISTS authors ( + author_id INT AUTO_INCREMENT PRIMARY KEY, + author_name VARCHAR(100) NOT NULL, + university VARCHAR(100), + date_of_birth DATE, + h_index INT, + gender ENUM('Male', 'Female', 'Other') + ); + `; + connection.query(createAuthorsTableQuery, (err, results) => { + if (err) { + console.error('Error creating authors table:', err.stack); + reject(err); + return; + } + console.log('Authors table created.'); + resolve(); + }); + }); +}; + +const addMentorColumn = (connection) => { + return new Promise((resolve, reject) => { + const checkColumnExistsQuery = ` + SELECT COUNT(*) AS columnExists + FROM information_schema.columns + WHERE table_name = 'authors' + AND column_name = 'mentor'; + `; + + connection.query(checkColumnExistsQuery, (err, results) => { + if (err) { + console.error('Error checking for mentor column:', err.stack); + reject(err); + return; + } + + const columnExists = results[0].columnExists; + + if (columnExists) { + console.log('Mentor column already exists. No changes made.'); + resolve(); + } else { + const addMentorColumnQuery = ` + ALTER TABLE authors + ADD COLUMN mentor INT, + ADD CONSTRAINT fk_mentor + FOREIGN KEY (mentor) REFERENCES authors(author_id) + ON DELETE SET NULL + ON UPDATE CASCADE; + `; + + connection.query(addMentorColumnQuery, (err, results) => { + if (err) { + console.error('Error adding mentor column:', err.stack); + reject(err); + return; + } + console.log('Mentor column added with foreign key constraint.'); + resolve(); + }); + } + }); + }); +}; + + +const exerciseOne = async () => { + const connection = createNewConnection(); + connection.connect(err => { + if (err) { + return console.error('Connection error: ' + err.stack); + } + console.log('exercise_1: Connected!'); + }); + + + try { + await useDatabase(connection) ; // Select the database + await createAuthorsTable(connection) ; // Create the authors table + await addMentorColumn(connection) ; // Add the mentor column with foreign key + + } catch (err) { + console.error('Failed to set up the database:', err); + } finally { + connection.end(); + } +}; + + +exerciseOne(); + diff --git a/Week2/exercise_2.js b/Week2/exercise_2.js new file mode 100644 index 000000000..18d1168b1 --- /dev/null +++ b/Week2/exercise_2.js @@ -0,0 +1,202 @@ +//C:\Users\knowl\Documents\hyf\databases\Week2\exercise_2.js +import {createNewConnection, useDatabase} from './connection_query.js'; + + +const createResearchPapersTable = async (connection) => { + const createResearchPapersTableQuery = ` + CREATE TABLE IF NOT EXISTS research_papers ( + paper_id INT AUTO_INCREMENT PRIMARY KEY, + paper_title VARCHAR(255) NOT NULL, + conference VARCHAR(255), + publish_date DATE + ); + `; + await new Promise((resolve, reject) => { + connection.query(createResearchPapersTableQuery, (err, results) => { + if (err) { + console.error('Error creating research_papers table:', err.stack); + reject(err); + return; + } + console.log('Research papers table created.'); + resolve(); + }); + }); +}; + +const createAuthorPapersTable = async (connection) => { + const createAuthorPapersTableQuery = ` + CREATE TABLE IF NOT EXISTS author_papers ( + author_id INT, + paper_id INT, + PRIMARY KEY (author_id, paper_id), + FOREIGN KEY (author_id) REFERENCES authors(author_id) + ON DELETE CASCADE + ON UPDATE CASCADE, + FOREIGN KEY (paper_id) REFERENCES research_papers(paper_id) + ON DELETE CASCADE + ON UPDATE CASCADE + ); + `; + await new Promise((resolve, reject) => { + connection.query(createAuthorPapersTableQuery, (err, results) => { + if (err) { + console.error('Error creating author_papers table:', err.stack); + reject(err); + return; + } + console.log('Author papers table created.'); + resolve(); + }); + }); +}; + + +const authors = [ + ['Alan Turing', 'University of Cambridge', '1912-06-23', 67, 'Male', null], + ['Ada Lovelace', 'University of London', '1815-12-10', 45, 'Female', null], + ['John von Neumann', 'Princeton University', '1903-12-28', 86, 'Male', null], + ['Grace Hopper', 'Yale University', '1906-12-09', 60, 'Female', 1], + ['Donald Knuth', 'Stanford University', '1938-01-10', 127, 'Male', 3], + ['Edsger Dijkstra', 'University of Texas', '1930-05-11', 87, 'Male', null], + ['Tim Berners-Lee', 'MIT', '1955-06-08', 70, 'Male', 4], + ['Claude Shannon', 'MIT', '1916-04-30', 80, 'Male', null], + ['Barbara Liskov', 'MIT', '1939-11-07', 85, 'Female', null], + ['John McCarthy', 'Stanford University', '1927-09-04', 75, 'Male', 3], + ['Marvin Minsky', 'MIT', '1927-08-09', 76, 'Male', 9], + ['Larry Page', 'Stanford University', '1973-03-26', 64, 'Male', 12], + ['Sergey Brin', 'Stanford University', '1973-08-21', 63, 'Male', 11], + ['Don Norman', 'UC San Diego', '1935-12-25', 55, 'Male', null], + ['Brenda Laurel', 'UC Santa Cruz', '1950-11-20', 40, 'Female', 13] +]; + + +const papers = [ + ['On Computable Numbers, with an Application to the Entscheidungsproblem', 'Proceedings of the London Mathematical Society', '1936-11-12'], + ['The Analytical Engine', 'University of London', '1842-01-01'], + ['Theory of Games and Economic Behavior', 'Princeton University Press', '1944-03-01'], + ['The First Compiler', 'Harvard University', '1952-01-01'], + ['The Art of Computer Programming', 'Addison-Wesley', '1968-01-01'], + ['A Note on Two Problems in Connexion with Graphs', 'Numerische Mathematik', '1959-01-01'], + ['Information Management: A Proposal', 'CERN', '1989-03-01'], + ['A Mathematical Theory of Communication', 'Bell System Technical Journal', '1948-07-01'], + ['A Design Methodology for Reliable Software Systems', 'MIT', '1972-01-01'], + ['LISP: A Programming Language for Artificial Intelligence', 'Communications of the ACM', '1960-01-01'], + ['Steps Toward Artificial Intelligence', 'Proceedings of the IRE', '1961-01-01'], + ['The PageRank Citation Ranking: Bringing Order to the Web', 'Stanford University', '1998-01-01'], + ['The Anatomy of a Large-Scale Hypertextual Web Search Engine', 'Stanford University', '1999-01-01'], + ['The Design of Everyday Things', 'Basic Books', '1988-01-01'], + ['Computers as Theatre', 'Addison-Wesley', '1991-01-01'], + ['Quantum Mechanics and Path Integrals', 'Dover Publications', '1965-01-01'], + ['Reflections on Trusting Trust', 'Communications of the ACM', '1984-01-01'], + ['The Complexity of Theorem-Proving Procedures', 'ACM Symposium on Theory of Computing', '1971-01-01'], + ['Sketchpad: A Man-Machine Graphical Communication System', 'Spring Joint Computer Conference', '1963-01-01'], + ['No Silver Bullet: Essence and Accidents of Software Engineering', 'IFIP Congress', '1986-01-01'], + ['Introduction to Automata Theory, Languages, and Computation', 'Addison-Wesley', '1979-01-01'], + ['The Conceptual Framework of Computing', 'MIT', '1973-01-01'], + ['Design Patterns: Elements of Reusable Object-Oriented Software', 'Addison-Wesley', '1994-01-01'], + ['Computing Machinery and Intelligence', 'Mind', '1950-01-01'], + ['The CRISP-DM Process Model', 'IBM Research', '1999-01-01'], + ['As We May Think', 'The Atlantic', '1945-01-01'], + ['The Feynman Lectures on Physics', 'Addison-Wesley', '1964-01-01'], + ['The Mathematical Theory of Computation', 'Prentice Hall', '1972-01-01'], + ['The Structure of Scientific Revolutions', 'University of Chicago Press', '1962-01-01'], + ['Patterns of Software: Tales from the Software Community', 'Oxford University Press', '1996-01-01'] +]; + +const authorPapers = [ + [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], + [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], + [11, 11], [12, 12], [13, 13], [14, 14], [15, 15], + [1, 16], [2, 17], [3, 18], [4, 19], [5, 20], + [6, 21], [7, 22], [8, 23], [9, 24], [10, 25], + [11, 26], [12, 27], [13, 28], [14, 29], [15, 30] +]; + +const insertAuthors = async (connection) => { + const insertAuthorQuery = ` + INSERT INTO authors (author_name, university, date_of_birth, h_index, gender, mentor) + VALUES ? + `; + await new Promise((resolve, reject) => { + connection.query(insertAuthorQuery, [authors], (err, results) => { + if (err) { + console.error('Error inserting authors:', err.stack); + reject(err); + return; + } + console.log('Authors inserted.'); + resolve(); + }); + }); +}; + +const insertResearchPapers = async (connection) => { + const insertPaperQuery = ` + INSERT INTO research_papers (paper_title, conference, publish_date) + VALUES ? + `; + await new Promise((resolve, reject) => { + connection.query(insertPaperQuery, [papers], (err, results) => { + if (err) { + console.error('Error inserting research papers:', err.stack); + reject(err); + return; + } + console.log('Research papers inserted.'); + resolve(); + }); + }); +}; + +// Insert data into author_papers junction table +const linkAuthorsToPapers = async (connection) => { + const insertAuthorPapersQuery = ` + INSERT INTO author_papers (author_id, paper_id) + VALUES ? + `; + await new Promise((resolve, reject) => { + connection.query(insertAuthorPapersQuery, [authorPapers], (err, results) => { + if (err) { + console.error('Error inserting author_papers:', err.stack); + reject(err); + return; + } + console.log('Author papers relationships inserted.'); + resolve(); + }); + }); +}; + + + +const exerciseTwo = async () => { + + const connection = createNewConnection(); + + connection.connect(err => { + if (err) { + return console.error('Connection error: ' + err.stack); + } + console.log('exercise_2: Connected!'); + }); + + try { + await useDatabase(connection) ; // Ensure the database is selected + await createResearchPapersTable(connection) ; // Create the research_papers table + await createAuthorPapersTable(connection) ; // Create the author_papers table + await insertAuthors(connection) ; // Insert authors into the authors table + await insertResearchPapers(connection) ; // Insert research papers + await linkAuthorsToPapers(connection) ; // Insert author-paper relationships + + console.log('Exercise steps completed.'); + } catch (err) { + console.error('Failed to set up the database:', err); + } finally { + connection.end(); + }; + }; + + + +exerciseTwo(); \ No newline at end of file diff --git a/Week2/exercise_3.js b/Week2/exercise_3.js new file mode 100644 index 000000000..e465a7b35 --- /dev/null +++ b/Week2/exercise_3.js @@ -0,0 +1,82 @@ +//C:\Users\knowl\Documents\hyf\databases\Week2\exercise_3.js +import {createNewConnection, useDatabase} from './connection_query.js'; + +const connection = createNewConnection(); + +const getAuthorsAndMentors = (connection) => { + return new Promise((resolve, reject) => { + const query = ` + SELECT + a1.author_name AS Author, + a2.author_name AS Mentor + FROM + authors a1 + LEFT JOIN + authors a2 ON a1.mentor = a2.author_id; + `; + connection.query(query, (err, results) => { + if (err) { + console.error('Error fetching authors and mentors:', err.stack); + reject(err); + return; + } + console.log('Authors and their mentors:'); + console.table(results); + resolve(); + }); + }); +}; + + +const getAuthorsAndPapers = (connection) => { + return new Promise((resolve, reject) => { + const query = ` + SELECT + authors.*, + research_papers.paper_title + FROM + authors + LEFT JOIN + author_papers ON authors.author_id = author_papers.author_id + LEFT JOIN + research_papers ON author_papers.paper_id = research_papers.paper_id; + `; + connection.query(query, (err, results) => { + if (err) { + console.error('Error fetching authors and their papers:', err.stack); + reject(err); + return; + } + console.log('Authors and their published papers:'); + console.table(results); + resolve(); + }); + }); +}; + + +const exerciseThree = async () => { + /*Prevents the connection from running twice*/ +// Check if connect() has already been called on this instance + if (!connection._connectCalled) { + connection.connect(err => { + if (err) { + return console.error('Connection error: ' + err.stack); + } + console.log('Connected!'); + }); + } + try { + await useDatabase(connection); // Ensure the database is selected + await getAuthorsAndMentors(connection); // Get authors and their mentors + await getAuthorsAndPapers(connection); // Get authors and their published papers + } catch (err) { + console.error('An error occurred:', err); + } finally { + connection.end(); // Close the connection after all operations + } +}; + + +exerciseThree(); + diff --git a/Week2/exercise_4.js b/Week2/exercise_4.js new file mode 100644 index 000000000..1e8976738 --- /dev/null +++ b/Week2/exercise_4.js @@ -0,0 +1,186 @@ +//C:\Users\knowl\Documents\hyf\databases\Week2\exercise_4.js +import {createNewConnection, useDatabase} from './connection_query.js'; +import path from 'path'; + +console.log(`running the file exercise_4.js`); +const connection = createNewConnection(); + +const getPapersAndAuthorCount = (connection) => { + return new Promise((resolve, reject) => { + const query = ` + SELECT + research_papers.paper_title, + COUNT(author_papers.author_id) AS author_count + FROM + research_papers + LEFT JOIN + author_papers ON research_papers.paper_id = author_papers.paper_id + GROUP BY + research_papers.paper_id; + `; + connection.query(query, (err, results) => { + if (err) { + console.error('Error fetching papers and author count:', err.stack); + reject(err); + return; + } + console.log('Research papers and number of authors:'); + console.table(results); + resolve(); + }); + }); +}; + + +const getSumOfPapersByFemaleAuthors = (connection) => { + return new Promise((resolve, reject) => { + const query = ` + SELECT + SUM(IF(authors.gender = 'Female', 1, 0)) AS female_author_paper_count + FROM + author_papers + LEFT JOIN + authors ON author_papers.author_id = authors.author_id; + `; + connection.query(query, (err, results) => { + if (err) { + console.error('Error fetching sum of papers by female authors:', err.stack); + reject(err); + return; + } + console.log('Sum of research papers published by all female authors:'); + console.table(results); + resolve(); + }); + }); +}; + + + +const getAverageHIndexPerUniversity = (connection) => { + return new Promise((resolve, reject) => { + const query = ` + SELECT + university, + AVG(h_index) AS average_h_index + FROM + authors + GROUP BY + university; + `; + connection.query(query, (err, results) => { + if (err) { + console.error('Error fetching average h-index per university:', err.stack); + reject(err); + return; + } + console.log('Average h-index of all authors per university:'); + console.table(results); + resolve(); + }); + }); +}; + + +const getSumOfPapersPerUniversity = (connection) => { + return new Promise((resolve, reject) => { + const query = ` + SELECT + authors.university, + COUNT(author_papers.paper_id) AS total_papers + FROM + authors + LEFT JOIN + author_papers ON authors.author_id = author_papers.author_id + GROUP BY + authors.university; + `; + connection.query(query, (err, results) => { + if (err) { + console.error('Error fetching sum of papers per university:', err.stack); + reject(err); + return; + } + console.log('Sum of research papers of the authors per university:'); + console.table(results); + resolve(); + }); + }); +}; + + + +const getMinMaxHIndexPerUniversity = (connection) => { + return new Promise((resolve, reject) => { + const query = ` + SELECT + university, + MIN(h_index) AS min_h_index, + MAX(h_index) AS max_h_index + FROM + authors + GROUP BY + university; + `; + connection.query(query, (err, results) => { + if (err) { + console.error('Error fetching min and max h-index per university:', err.stack); + reject(err); + return; + } + console.log('Minimum and maximum h-index of all authors per university:'); + console.table(results); + resolve(); + }); + }); +}; + + +const exerciseFour = async (connection) => { + /*Prevents the connection from running twice*/ +// Check if connect() has already been called on this instance + console.log('Attempting to connect to the database...'); + if (!connection._connectCalled) { + connection.connect(err => { + if (err) { + return console.error('Connection error: ' + err.stack); + } + console.log('Connected!'); + }); + } else { + console.log('Connection already established.'); + } + try { + await useDatabase(connection); // Ensure the database is selected + await getPapersAndAuthorCount(connection) ; // Get all research papers and number of authors + await getSumOfPapersByFemaleAuthors(connection) ;// Get sum of research papers by female authors + await getAverageHIndexPerUniversity(connection) ;// Get average h-index per university + await getSumOfPapersPerUniversity(connection) ; // Get sum of research papers per university + await getMinMaxHIndexPerUniversity(connection) ; // Get min and max h-index per university + } catch (err) { + console.error('An error occurred:', err); + } finally { + connection.end(); // Close the connection after all operations + } +}; + + +// console.log(`import.meta.url: ${import.meta.url}`); +// console.log(`file://${process.argv[1]}`); +// const filePath = `file://${path.resolve(process.argv[1]).replace(/\\/g, '/')}`; +// console.log(`Normalized file path: ${filePath}`); + +// Only run this script if it's executed directly (not imported)~ +// ~because running the script on import causes duplicated connections + +/* `file://${process.argv[1]}` is used to get the full path to the script that is being executed +* `file://${process.argv[1]}` is compared to import.meta.url to determine if the current module is the main module*/ +// if (import.meta.url === filePath) { +// console.log('Executing exerciseFour function.'); +// exerciseFour(connection); +// } else { +// console.log('Condition not met, not executing exerciseFour.'); +// } + + +exerciseFour(connection); diff --git a/Week2/package-lock.json b/Week2/package-lock.json new file mode 100644 index 000000000..0378743a1 --- /dev/null +++ b/Week2/package-lock.json @@ -0,0 +1,94 @@ +{ + "name": "Week2", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "mysql": "^2.18.1" + } + }, + "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/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/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "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/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/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/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/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/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==" + } + } +} diff --git a/Week2/package.json b/Week2/package.json new file mode 100644 index 000000000..ede26e1f0 --- /dev/null +++ b/Week2/package.json @@ -0,0 +1,6 @@ +{ + "type": "module", + "dependencies": { + "mysql": "^2.18.1" + } +} diff --git a/Week3/DinnerClubERD.drawio b/Week3/DinnerClubERD.drawio new file mode 100644 index 000000000..ac1654ed1 --- /dev/null +++ b/Week3/DinnerClubERD.drawio @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Week3/assignment/.$DinnerClubERD.drawio.bkp b/Week3/assignment/.$DinnerClubERD.drawio.bkp new file mode 100644 index 000000000..cca04a713 --- /dev/null +++ b/Week3/assignment/.$DinnerClubERD.drawio.bkp @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Week3/assignment/.$DinnerClubERD.drawio.dtmp b/Week3/assignment/.$DinnerClubERD.drawio.dtmp new file mode 100644 index 000000000..b34d99eee --- /dev/null +++ b/Week3/assignment/.$DinnerClubERD.drawio.dtmp @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Week3/assignment/DinnerClubERD.drawio b/Week3/assignment/DinnerClubERD.drawio new file mode 100644 index 000000000..b34d99eee --- /dev/null +++ b/Week3/assignment/DinnerClubERD.drawio @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Week3/assignment/connection_query.js b/Week3/assignment/connection_query.js new file mode 100644 index 000000000..45c6bb19b --- /dev/null +++ b/Week3/assignment/connection_query.js @@ -0,0 +1,30 @@ +//C:\Users\knowl\Documents\hyf\databases\Week3\assignment\connection_query.js +import mysql from 'mysql'; + + +export const createNewConnection = () => { + return mysql.createConnection({ + host: 'localhost', + user: 'hyfuser', + password: 'hyfpassword', + multipleStatements: true, + }); +}; + +export const useDatabase = (connection) => { + return new Promise((resolve, reject) => { + const createDatabaseAndUse = ` + CREATE DATABASE IF NOT EXISTS transactions; + USE transactions; + `; + connection.query(createDatabaseAndUse, (err, results) => { + if (err) { + console.error('Error creating or selecting database:', err.stack); + reject(err); + return; + } + console.log('Database selected successfully.'); + resolve(); + }); + }); +}; \ No newline at end of file diff --git a/Week3/assignment/exercise_1.md b/Week3/assignment/exercise_1.md new file mode 100644 index 000000000..1ae40da44 --- /dev/null +++ b/Week3/assignment/exercise_1.md @@ -0,0 +1,17 @@ +## 1. What columns violate 1NF? +- columns `food_code` and `food_description`. They contain multiple values, which violates atomic value rule of 1NF +## 2. What entities do you recognize that could be extracted? +- member +- dinner +- venue +- food +- dinner_food + +## 3. Name all the tables and columns that would make a 3NF compliant solution. +- member +- dinner +- venue +- food +- dinner_food +- member_dinner +![img.png](../img.png) \ No newline at end of file diff --git a/Week3/assignment/exercise_3.js b/Week3/assignment/exercise_3.js new file mode 100644 index 000000000..7398b007c --- /dev/null +++ b/Week3/assignment/exercise_3.js @@ -0,0 +1,28 @@ + +// given function: +// function getPopulation(Country, name, code, cb) { +// // assuming that connection to the database is established and stored as conn +// conn.query( +// `SELECT Population FROM ${Country} WHERE Name = '${name}' and code = '${code}'`, +// function (err, result) { +// if (err) cb(err); +// if (result.length == 0) cb(new Error("Not found")); +// cb(null, result[0].name); +// } +// ); +// } +// code that would take advantage of SQL-injection: +// getPopulation("Netherlands", "'; --", "' OR '1'='1") +//SQL query: +// SELECT Population FROM Country WHERE Name = ''; -- ' and code = ' OR '1'='1' + +//Rewritten function +function getPopulation(Country, name, code, cb) { + // assuming that connection to the database is established and stored as conn + const query = `SELECT Population FROM ${Country} WHERE Name = ? and code = ?`; + conn.query(query, [name, code], function (err, result) { + if (err) return cb(err); + if (result.length == 0) return cb(new Error("Not found")); + cb(null, result[0].Population); + }); +} diff --git a/Week3/assignment/transaction.js b/Week3/assignment/transaction.js new file mode 100644 index 000000000..795c116e8 --- /dev/null +++ b/Week3/assignment/transaction.js @@ -0,0 +1,97 @@ +import {createNewConnection, useDatabase} from "./connection_query.js"; + +const connection = createNewConnection(); + +const transferAmount = (fromAccount, toAccount, amount) => { + return new Promise((resolve, reject) => { + connection.beginTransaction(err => { + if (err) return reject(err); + + // Deduct amount from the source account + const deductAmountQuery = ` + UPDATE account + SET balance = balance - ${connection.escape(amount)} + WHERE account_number = ${connection.escape(fromAccount)} + `; + + connection.query(deductAmountQuery, (err, result) => { + if (err) { + return connection.rollback(() => { + reject(err); + }); + } + + // Add amount to the destination account + const addAmountQuery = ` + UPDATE account + SET balance = balance + ${connection.escape(amount)} + WHERE account_number = ${connection.escape(toAccount)} + `; + + connection.query(addAmountQuery, (err, result) => { + if (err) { + return connection.rollback(() => { + reject(err); + }); + } + + // Log the change in the account_changes table for the source account + const logChangeFromAccount = ` + INSERT INTO account_changes (account_number, amount, changed_date, remark) + VALUES (${connection.escape(fromAccount)}, -${connection.escape(amount)}, NOW(), 'Transfer to account ${connection.escape(toAccount)}') + `; + + connection.query(logChangeFromAccount, (err, result) => { + if (err) { + return connection.rollback(() => { + reject(err); + }); + } + + // Log the change in the account_changes table for the destination account + const logChangeToAccount = ` + INSERT INTO account_changes (account_number, amount, changed_date, remark) + VALUES (${connection.escape(toAccount)}, ${connection.escape(amount)}, NOW(), 'Transfer from account ${connection.escape(fromAccount)}') + `; + + connection.query(logChangeToAccount, (err, result) => { + if (err) { + return connection.rollback(() => { + reject(err); + }); + } + + // Commit the transaction if everything is successful + connection.commit(err => { + if (err) { + return connection.rollback(() => { + reject(err); + }); + } + console.log('Transaction completed successfully.'); + resolve(); + }); + }); + }); + }); + }); + }); + }); +}; + + +connection.connect((err) => { + if (err) throw err; + console.log('Connected to the database.'); + + useDatabase(connection) + .then(() => { + return transferAmount(101, 102, 1000); + }) + .catch((error) => { + console.error('Error during transaction:', error); + }) + .finally(() => { + connection.end(); + }); +}); \ No newline at end of file diff --git a/Week3/assignment/transactions-create-tables.js b/Week3/assignment/transactions-create-tables.js new file mode 100644 index 000000000..bf29653e4 --- /dev/null +++ b/Week3/assignment/transactions-create-tables.js @@ -0,0 +1,50 @@ +//C:\Users\knowl\Documents\hyf\databases\Week3\assignment\transactions-create-tables.js +import {createNewConnection,useDatabase} from "./connection_query.js"; + +// Schema for the tables +const accountTable = { + account_number: 'INT PRIMARY KEY', + balance: 'DECIMAL(10, 2) NOT NULL' +}; + +const accountChangesTable = { + change_number: 'INT AUTO_INCREMENT PRIMARY KEY', + account_number: 'INT NOT NULL', + amount: 'DECIMAL(10, 2) NOT NULL', + changed_date: 'DATETIME NOT NULL', + remark: 'VARCHAR(255)' +}; + + +// Function to create a table +const createTable = (tableName, schema, foreignKeys='') => { + const columns = Object.entries(schema).map(([key, type]) => `${key} ${type}`).join(', '); + const query = `CREATE TABLE IF NOT EXISTS ${tableName} (${columns}${foreignKeys ? `, ${foreignKeys}` : ''})`; + + connection.query(query, (error, results, fields) => { + if (error) throw error; + console.log(`Table ${tableName} created successfully!`); + }); +}; + +const connection = createNewConnection(); + +// Connect to the database and create the tables +connection.connect((err) => { + if (err) throw err; + console.log('Connected to the database.'); + + + useDatabase(connection) + .then(() => { + createTable('account', accountTable); + createTable('account_changes', accountChangesTable, 'FOREIGN KEY (account_number) REFERENCES account(account_number)'); + }) + .catch((error) => { + console.error('Error setting up the database:', error); + }) + .finally(() => { + connection.end(); + }) + +}); \ No newline at end of file diff --git a/Week3/assignment/transactions-insert-values.js b/Week3/assignment/transactions-insert-values.js new file mode 100644 index 000000000..31223f57b --- /dev/null +++ b/Week3/assignment/transactions-insert-values.js @@ -0,0 +1,47 @@ +import {createNewConnection, useDatabase} from "./connection_query.js"; + +const connection = createNewConnection(); + +const accountData = [ + { account_number: 101, balance: 1000.00 }, + { account_number: 102, balance: 1500.50 }, + { account_number: 103, balance: 500.75 }, +]; + +const accountChangesData = [ + { account_number: 101, amount: -100.00, changed_date: '2024-08-01 10:00:00', remark: 'ATM Withdrawal' }, + { account_number: 102, amount: 200.00, changed_date: '2024-08-01 12:00:00', remark: 'Direct Deposit' }, + { account_number: 103, amount: -50.25, changed_date: '2024-08-02 09:30:00', remark: 'Online Purchase' }, + { account_number: 101, amount: 300.00, changed_date: '2024-08-02 14:00:00', remark: 'Salary Deposit' }, +]; + +// Function to insert data into a table +const insertData = (tableName, data) => { + const keys = Object.keys(data[0]); + const columns = keys.join(', '); + const values = data.map(row => keys.map(key => connection.escape(row[key])).join(', ')).join('), ('); + const query = `INSERT INTO ${tableName} (${columns}) VALUES (${values})`; + + connection.query(query, (error, results, fields) => { + if (error) throw error; + console.log(`Data inserted into table ${tableName} successfully!`); + }); +}; + + +connection.connect((err) => { + if (err) throw err; + console.log('Connected to the database.'); + + useDatabase(connection) + .then(() => { + insertData('account', accountData); + insertData('account_changes', accountChangesData); + }) + .catch((error) => { + console.error('Error inserting data into the database:', error); + }) + .finally(() => { + connection.end(); + }); +}); \ No newline at end of file diff --git a/Week3/homework/mongodb/index.js b/Week3/homework/mongodb/index.js index 41ee8b618..1a7be1117 100644 --- a/Week3/homework/mongodb/index.js +++ b/Week3/homework/mongodb/index.js @@ -1,8 +1,13 @@ +//C:\Users\knowl\Documents\hyf\databases\Week3\homework\mongodb\index.js const { MongoClient, ServerApiVersion } = require("mongodb"); - const { seedDatabase } = require("./seedDatabase.js"); +const dotenv = require('dotenv'); +dotenv.config(); + + async function createEpisodeExercise(client) { + /** * We forgot to add the last episode of season 9. It has this information: * @@ -13,8 +18,17 @@ async function createEpisodeExercise(client) { // Write code that will add this to the collection! + const bobRossCollection = client.db("databaseWeek3").collection("bob_ross_episodes"); + + const newEpisode = { + episode: "S09E13", + title: "MOUNTAIN HIDE-AWAY", + elements: ["CIRRUS", "CLOUDS", "CONIFER", "DECIDIOUS", "GRASS", "MOUNTAIN", "MOUNTAINS", "RIVER", "SNOWY_MOUNTAIN", "TREE", "TREES"], + }; + + const result = await bobRossCollection.insertOne(newEpisode); console.log( - `Created season 9 episode 13 and the document got the id ${"TODO: fill in variable here"}` + `Created season 9 episode 13 and the document got the id ${result.insertedId}` ); } @@ -23,29 +37,33 @@ async function findEpisodesExercises(client) { * Complete the following exercises. * The comments indicate what to do and what the result should be! */ - + const bobRossCollection = client.db("databaseWeek3").collection("bob_ross_episodes"); // Find the title of episode 2 in season 2 [Should be: WINTER SUN] - + const episode2S2 = await bobRossCollection.findOne({ episode: "S02E02" }); console.log( - `The title of episode 2 in season 2 is ${"TODO: fill in variable here"}` + `The title of episode 2 in season 2 is ${episode2S2.title}` ); // Find the season and episode number of the episode called "BLACK RIVER" [Should be: S02E06] - + const blackRiverEpisode = await bobRossCollection.findOne({ title: "BLACK RIVER" }); console.log( - `The season and episode number of the "BLACK RIVER" episode is ${"TODO: fill in variable here"}` + `The season and episode number of the "BLACK RIVER" episode is ${blackRiverEpisode.episode}` ); // Find all of the episode titles where Bob Ross painted a CLIFF [Should be: NIGHT LIGHT, EVENING SEASCAPE, SURF'S UP, CLIFFSIDE, BY THE SEA, DEEP WILDERNESS HOME, CRIMSON TIDE, GRACEFUL WATERFALL] - + const cliffEpisodes = await bobRossCollection.find({ elements: "CLIFF" }).toArray(); + const cliffTitles = cliffEpisodes.map(ep => ep.title).join(", "); console.log( - `The episodes that Bob Ross painted a CLIFF are ${"TODO: fill in variable here"}` + `The episodes that Bob Ross painted a CLIFF are ${cliffTitles}` ); // Find all of the episode titles where Bob Ross painted a CLIFF and a LIGHTHOUSE [Should be: NIGHT LIGHT] - + const cliffAndLighthouseEpisodes = await bobRossCollection.find({ + elements: { $all: ["CLIFF", "LIGHTHOUSE"] }, + }).toArray(); + const cliffAndLighthouseTitles = cliffAndLighthouseEpisodes.map(ep => ep.title).join(", "); console.log( - `The episodes that Bob Ross painted a CLIFF and a LIGHTHOUSE are ${"TODO: fill in variable here"}` + `The episodes that Bob Ross painted a CLIFF and a LIGHTHOUSE are ${cliffAndLighthouseTitles}` ); } @@ -56,19 +74,25 @@ async function updateEpisodeExercises(client) { * * Note: do NOT change the data.json file */ - + const bobRossCollection = client.db("databaseWeek3").collection("bob_ross_episodes"); // Episode 13 in season 30 should be called BLUE RIDGE FALLS, yet it is called BLUE RIDGE FALLERS now. Fix that - + const updateResult = await bobRossCollection.updateOne( + { episode: "S30E13" }, + { $set: { title: "BLUE RIDGE FALLS" } } + ); console.log( - `Ran a command to update episode 13 in season 30 and it updated ${"TODO: fill in variable here"} episodes` + `Ran a command to update episode 13 in season 30 and it updated ${updateResult.modifiedCount} episodes` ); // Unfortunately we made a mistake in the arrays and the element type called 'BUSHES' should actually be 'BUSH' as sometimes only one bush was painted. // Update all of the documents in the collection that have `BUSHES` in the elements array to now have `BUSH` // It should update 120 episodes! - + const updateBushesResult = await bobRossCollection.updateMany( + { elements: "BUSHES" }, + { $set: { "elements.$": "BUSH" } } + ); console.log( - `Ran a command to update all the BUSHES to BUSH and it updated ${"TODO: fill in variable here"} episodes` + `Ran a command to update all the BUSHES to BUSH and it updated ${updateBushesResult.modifiedCount} episodes` ); } @@ -77,9 +101,10 @@ async function deleteEpisodeExercise(client) { * It seems an errand episode has gotten into our data. * This is episode 14 in season 31. Please remove it and verify that it has been removed! */ - + const bobRossCollection = client.db("databaseWeek3").collection("bob_ross_episodes"); + const deleteResult = await bobRossCollection.deleteOne({ episode: "S31E14" }); console.log( - `Ran a command to delete episode and it deleted ${"TODO: fill in variable here"} episodes` + `Ran a command to delete episode and it deleted ${deleteResult.deletedCount} episodes` ); } @@ -89,11 +114,7 @@ async function main() { `You did not set up the environment variables correctly. Did you create a '.env' file and add a package to create it?` ); } - const client = new MongoClient(process.env.MONGODB_URL, { - useNewUrlParser: true, - useUnifiedTopology: true, - serverApi: ServerApiVersion.v1, - }); + const client = new MongoClient(process.env.MONGODB_URL); try { await client.connect(); diff --git a/Week3/homework/mongodb/package-lock.json b/Week3/homework/mongodb/package-lock.json new file mode 100644 index 000000000..fc7c30d42 --- /dev/null +++ b/Week3/homework/mongodb/package-lock.json @@ -0,0 +1,242 @@ +{ + "name": "mongodb", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "dotenv": "^16.4.5", + "mongodb": "^6.8.0", + "mysql": "^2.18.1" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "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/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "engines": { + "node": ">=16.20.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/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "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/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, + "node_modules/mongodb": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", + "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "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/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/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "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/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/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "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/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/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "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/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + } + } +} diff --git a/Week3/homework/mongodb/package.json b/Week3/homework/mongodb/package.json new file mode 100644 index 000000000..bd7156aea --- /dev/null +++ b/Week3/homework/mongodb/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "dotenv": "^16.4.5", + "mongodb": "^6.8.0", + "mysql": "^2.18.1" + } +} diff --git a/Week3/homework/mongodb/seedDatabase.js b/Week3/homework/mongodb/seedDatabase.js index 99be6b3d8..5c8336225 100644 --- a/Week3/homework/mongodb/seedDatabase.js +++ b/Week3/homework/mongodb/seedDatabase.js @@ -1,4 +1,8 @@ +//C:\Users\knowl\Documents\hyf\databases\Week3\homework\mongodb\seedDatabase.js const data = require("./data.json"); +const dotenv = require('dotenv'); +dotenv.config(); + /** * This function will drop and recreate the collection of sample data in our csv file. @@ -7,15 +11,21 @@ const data = require("./data.json"); * @param {MongoClient} client - The client that is connected to your database */ const seedDatabase = async (client) => { + const db = client.db("databaseWeek3"); // Define the db variable + const collectionName = "bob_ross_episodes"; + const hasCollection = await client .db("databaseWeek3") .listCollections({ name: "bob_ross_episodes" }) .hasNext(); - if (hasCollection) { - const bobRossCollection = await client - .db("databaseWeek3") - .collection("bob_ross_episodes"); + if (!hasCollection) { + // Create the collection if it doesn't exist + await db.createCollection(collectionName); + } + + const bobRossCollection = db.collection(collectionName); + // Remove all the documents await bobRossCollection.deleteMany({}); @@ -41,9 +51,7 @@ const seedDatabase = async (client) => { // Add our documents await bobRossCollection.insertMany(documents); - } else { - throw Error("The collection `bob_ross_episodes` does not exist!"); - } + }; module.exports = { diff --git a/Week3/img.png b/Week3/img.png new file mode 100644 index 000000000..9acb4e51b Binary files /dev/null and b/Week3/img.png differ