diff --git a/Week1/Hadidreem17/setup_meetup_db.js b/Week1/Hadidreem17/setup_meetup_db.js new file mode 100644 index 000000000..9d8f424e9 --- /dev/null +++ b/Week1/Hadidreem17/setup_meetup_db.js @@ -0,0 +1,94 @@ +const { Client } = require("pg"); + +async function main() { +const client = new Client({ + user: "hyfuser", + host: "localhost", + database: "postgres", + password: "hyfpassword", + port: 5432, +}); + + await client.connect(); + + console.log("Dropping database if exists..."); + await client.query("DROP DATABASE IF EXISTS meetup"); + + console.log("Creating database meetup..."); + await client.query("CREATE DATABASE meetup"); + + await client.end(); + + + const meetupClient = new Client({ + user: "hyfuser", + host: "localhost", + database: "meetup", + password: "hyfpassword", + port: 5432, +}); + + await meetupClient.connect(); + + console.log("Creating tables..."); + + await meetupClient.query(` + CREATE TABLE Invitee ( + invitee_no SERIAL PRIMARY KEY, + invitee_name VARCHAR(100), + invited_by VARCHAR(100) + ); + `); + + await meetupClient.query(` + CREATE TABLE Room ( + room_no SERIAL PRIMARY KEY, + room_name VARCHAR(100), + floor_number INT + ); + `); + + await meetupClient.query(` + CREATE TABLE Meeting ( + meeting_no SERIAL PRIMARY KEY, + meeting_title VARCHAR(200), + starting_time TIMESTAMP, + ending_time TIMESTAMP, + room_no INT REFERENCES Room(room_no) + ); + `); + + console.log("Inserting sample data..."); + + await meetupClient.query(` + INSERT INTO Invitee (invitee_name, invited_by) VALUES + ('Sara', 'Ali'), + ('John', 'Lina'), + ('Maya', 'Omar'), + ('Noor', 'Samir'), + ('Adam', 'Lara');ssss + `); + + await meetupClient.query(` + INSERT INTO Room (room_name, floor_number) VALUES + ('Blue Room', 1), + ('Red Room', 2), + ('Green Room', 1), + ('Orange Room', 3), + ('VIP Room', 5); + `); + + await meetupClient.query(` + INSERT INTO Meeting (meeting_title, starting_time, ending_time, room_no) VALUES + ('Tech Meetup', NOW(), NOW() + INTERVAL '2 hours', 1), + ('Startup Pitch', NOW(), NOW() + INTERVAL '1 hour', 2), + ('Workshop JS', NOW(), NOW() + INTERVAL '3 hours', 3), + ('Design Basics', NOW(), NOW() + INTERVAL '4 hours', 4), + ('AI Conference', NOW(), NOW() + INTERVAL '5 hours', 5); + `); + + console.log("All done"); + await meetupClient.end(); +} + +main(); diff --git a/Week1/Hadidreem17/world_queries.js b/Week1/Hadidreem17/world_queries.js new file mode 100644 index 000000000..6dc696214 --- /dev/null +++ b/Week1/Hadidreem17/world_queries.js @@ -0,0 +1,83 @@ +const { Client } = require("pg"); + +async function main() { + const client = new Client({ + user: "hyfuser", + host: "localhost", + database: "world", + password: "hyfpassword", + port: 5432, + }); + + try { + await client.connect(); + + console.log("\n1. Countries with population > 8 million:"); + let result = await client.query(` + SELECT name FROM country WHERE population > 8000000; + `); + console.log(result.rows); + + console.log("\n2. Countries that contain 'land' in their names:"); + result = await client.query(` + SELECT name FROM country WHERE name ILIKE '%land%'; + `); + console.log(result.rows); + + console.log("\n3. Cities with population between 500k and 1 million:"); + result = await client.query(` + SELECT name FROM city + WHERE population BETWEEN 500000 AND 1000000; + `); + console.log(result.rows); + + console.log("\n4. Countries in Europe:"); + result = await client.query(` + SELECT name FROM country WHERE continent = 'Europe'; + `); + console.log(result.rows); + + console.log("\n5. Countries ordered by surface area DESC:"); + result = await client.query(` + SELECT name, surfacearea FROM country ORDER BY surfacearea DESC; + `); + console.log(result.rows); + + console.log("\n6. All cities in the Netherlands:"); + result = await client.query(` + SELECT name FROM city WHERE countrycode = 'NLD'; + `); + console.log(result.rows); + + console.log("\n7. Population of Rotterdam:"); + result = await client.query(` + SELECT population FROM city WHERE name = 'Rotterdam'; + `); + console.log(result.rows); + + console.log("\n8. Top 10 countries by surface area:"); + result = await client.query(` + SELECT name, surfacearea FROM country ORDER BY surfacearea DESC LIMIT 10; + `); + console.log(result.rows); + + console.log("\n9. Top 10 most populated cities:"); + result = await client.query(` + SELECT name, population FROM city ORDER BY population DESC LIMIT 10; + `); + console.log(result.rows); + + console.log("\n10. Total population of the world:"); + result = await client.query(` + SELECT SUM(population) AS world_population FROM country; + `); + console.log(result.rows); + + } catch (err) { + console.error("Error while running queries:", err); + } finally { + await client.end(); + } +} + +main(); diff --git a/Week2/3_1.sql b/Week2/3_1.sql new file mode 100644 index 000000000..cd2e70acb --- /dev/null +++ b/Week2/3_1.sql @@ -0,0 +1,15 @@ +CREATE TABLE authors ( + author_id SERIAL PRIMARY KEY, + author_name VARCHAR(100), + university VARCHAR(100), + date_of_birth DATE, + h_index INT, + gender VARCHAR(20) +); + +ALTER TABLE authors +ADD COLUMN mentor INT; + +ALTER TABLE authors +ADD CONSTRAINT fk_mentor +FOREIGN KEY (mentor) REFERENCES authors(author_id); \ No newline at end of file diff --git a/Week2/3_2.sql b/Week2/3_2.sql new file mode 100644 index 000000000..0da1d9ff6 --- /dev/null +++ b/Week2/3_2.sql @@ -0,0 +1,106 @@ +CREATE TABLE research_papers ( + paper_id SERIAL PRIMARY KEY, + paper_title VARCHAR(200), + conference VARCHAR(200), + publish_date DATE, + field VARCHAR(100) +); + +CREATE TABLE author_papers ( + author_id INT, + paper_id INT, + author_order INT, + PRIMARY KEY (author_id, paper_id), + FOREIGN KEY (author_id) REFERENCES authors(author_id), + FOREIGN KEY (paper_id) REFERENCES research_papers(paper_id) +); + +INSERT INTO authors (author_name, university, date_of_birth, h_index, gender, mentor) VALUES +('Alice Johnson', 'University of Amsterdam', '1980-04-12', 25, 'female', NULL), +('Bob Smith', 'Delft University of Technology','1975-09-03', 35, 'male', 1), +('Clara Nguyen', 'Erasmus University', '1985-01-22', 18, 'female', 1), +('David Lee', 'Utrecht University', '1990-07-15', 12, 'male', 2), +('Emma Rossi', 'Leiden University', '1982-11-05', 28, 'female', 2), +('Faisal Khan', 'TU Eindhoven', '1978-03-19', 40, 'male', NULL), +('Giulia Bianchi', 'University of Milan', '1988-09-30', 21, 'female', 6), +('Hassan Ali', 'Cairo University', '1983-02-10', 30, 'male', 6), +('Irene Müller', 'TU Berlin', '1986-06-25', 24, 'female', 1), +('Jamal Rahman', 'KU Leuven', '1991-12-01', 10, 'male', 8), +('Khadija Noor', 'Qatar University', '1989-04-09', 16, 'female', 6), +('Lars Jensen', 'Copenhagen University', '1977-08-14', 33, 'male', NULL), +('Maria Gonzalez', 'University of Barcelona', '1984-10-27', 27, 'female', 12), +('Nabil Hassan', 'American University of Beirut','1987-05-03', 19, 'male', 8), +('Olivia Brown', 'Oxford University', '1981-09-18', 38, 'female', 12); + +INSERT INTO research_papers (paper_title, conference, publish_date, field) VALUES +('Efficient Database Indexing', 'ICDE', '2022-04-10', 'Databases'), +('Scalable Join Algorithms', 'VLDB', '2021-09-15', 'Databases'), +('Machine Learning for Query Optimization', 'NeurIPS', '2020-12-05', 'ML'), +('Graph Databases in Social Networks', 'SIGMOD', '2019-06-20', 'Databases'), +('Privacy in Distributed Systems', 'IEEE Security', '2018-03-11', 'Security'), +('Blockchain for Secure Storage', 'CryptoConf', '2022-07-02', 'Security'), +('Natural Language Interfaces to SQL', 'ACL', '2023-05-18', 'NLP'), +('Reinforcement Learning for Index Tuning', 'ICLR', '2021-04-27', 'ML'), +('Data Cleaning at Scale', 'KDD', '2019-08-22', 'Data Mining'), +('Approximate Query Processing', 'SIGMOD', '2020-06-17', 'Databases'), +('Time-Series Forecasting in Finance', 'ICDM', '2021-11-09', 'Data Mining'), +('Real-time Analytics on Streams', 'ICDE', '2023-04-03', 'Databases'), +('Energy-Efficient Data Centers', 'GreenIT', '2018-10-01', 'Systems'), +('Fault-Tolerant Replication', 'USENIX ATC', '2019-07-25', 'Systems'), +('Secure Multi-Party Computation', 'CryptoConf', '2020-09-30', 'Security'), +('Explainable AI for Healthcare', 'NeurIPS', '2022-12-10', 'ML'), +('Image Recognition with Deep CNNs', 'CVPR', '2019-06-15', 'CV'), +('Federated Learning on Edge Devices', 'MobiSys', '2021-06-08', 'ML'), +('Text Summarization with Transformers', 'ACL', '2020-07-06', 'NLP'), +('Question Answering over Knowledge Graphs', 'ISWC', '2022-10-19', 'NLP'), +('Anomaly Detection in Sensor Networks', 'ICDM', '2018-11-12', 'Data Mining'), +('Clustering High-Dimensional Data', 'KDD', '2017-08-18', 'Data Mining'), +('Optimization of Cloud Costs', 'SoCC', '2020-10-05', 'Cloud'), +('Container Orchestration at Scale', 'KubeCon', '2021-05-21', 'Systems'), +('Scheduling in Real-Time Systems', 'RTSS', '2019-12-03', 'Systems'), +('Knowledge Distillation Techniques', 'ICLR', '2022-04-15', 'ML'), +('Domain Modeling for Enterprise Apps', 'DDDConf', '2018-09-07', 'Software Eng'), +('Testing Microservices Architectures', 'ICSE', '2020-05-02', 'Software Eng'), +('CI/CD Pipelines in Large Organizations', 'DevOpsDays', '2021-03-29', 'DevOps'), +('Monitoring and Observability Best Practices','SREConf', '2023-01-13', 'DevOps'); + +INSERT INTO author_papers (author_id, paper_id, author_order) VALUES +(1, 1, 1), +(1, 2, 1), +(2, 2, 2), +(2, 5, 1), +(3, 7, 1), +(3, 19, 1), +(4, 8, 1), +(4, 10, 2), +(5, 4, 1), +(5, 10, 1), +(5, 12, 2), +(6, 5, 2), +(6, 6, 1), +(6, 15, 1), +(7, 9, 1), +(7, 21, 1), +(8, 11, 1), +(8, 20, 2), +(9, 3, 2), +(9, 12, 1), +(9, 16, 2), +(10, 13, 1), +(10, 14, 2), +(11, 16, 1), +(11, 18, 1), +(12, 17, 1), +(12, 24, 2), +(13, 22, 1), +(13, 27, 1), +(14, 18, 2), +(14, 23, 1), +(14, 25, 2), +(15, 26, 1), +(15, 28, 1), +(15, 29, 1), +(1, 30, 2), +(2, 30, 1), +(3, 11, 2), +(4, 1, 2); diff --git a/Week2/3_3.sql b/Week2/3_3.sql new file mode 100644 index 000000000..5b53fca7b --- /dev/null +++ b/Week2/3_3.sql @@ -0,0 +1,16 @@ +SELECT + a.author_name AS author, + m.author_name AS mentor +FROM authors a +LEFT JOIN authors m + ON a.mentor = m.author_id; + +SELECT + a.*, + rp.paper_title +FROM authors a +LEFT JOIN author_papers ap + ON a.author_id = ap.author_id +LEFT JOIN research_papers rp + ON ap.paper_id = rp.paper_id; + diff --git a/Week2/3_4.sql b/Week2/3_4.sql new file mode 100644 index 000000000..6668e9122 --- /dev/null +++ b/Week2/3_4.sql @@ -0,0 +1,37 @@ +SELECT + rp.paper_id, + rp.paper_title, + COUNT(ap.author_id) AS number_of_authors +FROM research_papers rp +LEFT JOIN author_papers ap + ON rp.paper_id = ap.paper_id +GROUP BY rp.paper_id, rp.paper_title +ORDER BY rp.paper_id; + +SELECT + COUNT(DISTINCT ap.paper_id) AS total_papers_by_female_authors +FROM authors a +JOIN author_papers ap + ON a.author_id = ap.author_id +WHERE a.gender = 'female'; + +SELECT + university, + AVG(h_index) AS avg_h_index +FROM authors +GROUP BY university; + +SELECT + a.university, + COUNT(DISTINCT ap.paper_id) AS total_papers +FROM authors a +LEFT JOIN author_papers ap + ON a.author_id = ap.author_id +GROUP BY a.university; + +SELECT + university, + MIN(h_index) AS min_h_index, + MAX(h_index) AS max_h_index +FROM authors +GROUP BY university; diff --git a/Week3/Hadidreem17/exe3.1.md b/Week3/Hadidreem17/exe3.1.md new file mode 100644 index 000000000..8023f8597 --- /dev/null +++ b/Week3/Hadidreem17/exe3.1.md @@ -0,0 +1,133 @@ +# Exercise 3.1 – SQL Normalization + +## Dinner Club Database + +# 1. Columns that violate First Normal Form (1NF) + +In the original table, the following columns contain **multiple values inside a single cell**: + +- `food_code` +- `food_description` + +Examples: + +C1, C2 +Curry, Cake + +P1, T1, M1 +Pie, Tea, Mousse + +yaml +Copy code + +This violates **1NF**, which requires: + +- Each cell must contain only **one atomic value** +- No repeating groups or lists inside a single cell + +> Note: The date column (`dinner_date`) has inconsistent formats, but this is a **data quality issue**, not a violation of 1NF (each cell still holds one date). + + +# 2. Entities Identified in the Table + +The original table mixes multiple concepts. After analyzing it, we identify the following entities: + +### Member + +- member_id +- member_name +- member_address + +### Venue + +- venue_code +- venue_description + +### Food + +- food_code +- food_description + +### Dinner + +- dinner_id +- dinner_date +- venue_code (each dinner happens at one venue) + +### DinnerMembers + +A **Many-to-Many** relationship between Members and Dinners. + +### DinnerFoods + +A **Many-to-Many** relationship between Dinners and Foods. + + +# 3. 3NF-Compliant Table Structure + +Below are all tables needed for a fully normalized **Third Normal Form (3NF)** database. + + +## 3.1 Members Table + +```sql +CREATE TABLE Members ( + member_id INT PRIMARY KEY, + member_name VARCHAR(100) NOT NULL, + member_address VARCHAR(255) NOT NULL +); + +Venues Table + +CREATE TABLE Venues ( + venue_code VARCHAR(10) PRIMARY KEY, + venue_description VARCHAR(100) NOT NULL +); + +Foods Table + +CREATE TABLE Foods ( + food_code VARCHAR(10) PRIMARY KEY, + food_description VARCHAR(100) NOT NULL +); + +Dinners Table + +CREATE TABLE Dinners ( + dinner_id VARCHAR(20) PRIMARY KEY, + dinner_date DATE NOT NULL, + venue_code VARCHAR(10) NOT NULL, + FOREIGN KEY (venue_code) REFERENCES Venues(venue_code) +); + + +DinnerMembers + +CREATE TABLE DinnerMembers ( + dinner_id VARCHAR(20) NOT NULL, + member_id INT NOT NULL, + PRIMARY KEY (dinner_id, member_id), + FOREIGN KEY (dinner_id) REFERENCES Dinners(dinner_id), + FOREIGN KEY (member_id) REFERENCES Members(member_id) +); + + +DinnerFoods Table + +CREATE TABLE DinnerFoods ( + dinner_id VARCHAR(20) NOT NULL, + food_code VARCHAR(10) NOT NULL, + PRIMARY KEY (dinner_id, food_code), + FOREIGN KEY (dinner_id) REFERENCES Dinners(dinner_id), + FOREIGN KEY (food_code) REFERENCES Foods(food_code) +); + + +Final 3NF Schema Overview + +Members (1) ----< DinnerMembers >---- (M) Dinners + +Dinners (1) ----< DinnerFoods >---- (M) Foods + +Venues (1) ----< Dinners (M) + diff --git a/Week3/Hadidreem17/exe3.2.md/exe3.3.md b/Week3/Hadidreem17/exe3.2.md/exe3.3.md new file mode 100644 index 000000000..0779cc943 --- /dev/null +++ b/Week3/Hadidreem17/exe3.2.md/exe3.3.md @@ -0,0 +1,32 @@ +Exercise 3.3 – SQL Injection + + 1. Example values that exploit SQL Injection + +A malicious user can inject SQL code by passing the following values: + +- **name:** +' OR '1'='1 + +- **code:** +abc + +These values modify the SQL query so that the condition becomes always true: +Name = '' OR '1'='1' + +Because `'1'='1'` is always TRUE, the query will return **all records in the database**, demonstrating SQL injection. + + +2. Secure version of the function (protected from SQL injection) + +We fix the vulnerability by using **prepared statements** instead of string concatenation: + +```js +function getPopulation(Country, name, code, cb) { + const sql = "SELECT Population FROM ?? WHERE Name = ? AND code = ?"; + + conn.query(sql, [Country, 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); + }); +} \ No newline at end of file diff --git a/Week3/Hadidreem17/exe3.2.md/package-lock.json b/Week3/Hadidreem17/exe3.2.md/package-lock.json new file mode 100644 index 000000000..24258abff --- /dev/null +++ b/Week3/Hadidreem17/exe3.2.md/package-lock.json @@ -0,0 +1,147 @@ +{ + "name": "database-assignment-week3", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "database-assignment-week3", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "mysql2": "^3.15.3" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/lru.min": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.3.tgz", + "integrity": "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q==", + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, + "node_modules/mysql2": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", + "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", + "license": "MIT", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.7.0", + "long": "^5.2.1", + "lru.min": "^1.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "license": "MIT", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + } + } +} diff --git a/Week3/Hadidreem17/exe3.2.md/package.json b/Week3/Hadidreem17/exe3.2.md/package.json new file mode 100644 index 000000000..8571817b7 --- /dev/null +++ b/Week3/Hadidreem17/exe3.2.md/package.json @@ -0,0 +1,16 @@ +{ + "name": "database-assignment-week3", + "version": "1.0.0", + "description": "", + "main": "transactions-create-tables.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "mysql2": "^3.15.3" + } +} diff --git a/Week3/Hadidreem17/exe3.2.md/transaction.js b/Week3/Hadidreem17/exe3.2.md/transaction.js new file mode 100644 index 000000000..cbde4d7d0 --- /dev/null +++ b/Week3/Hadidreem17/exe3.2.md/transaction.js @@ -0,0 +1,67 @@ +const mysql = require('mysql2/promise'); + +async function transferAmount(fromAccount, toAccount, amount) { + const connection = await mysql.createConnection({ + host: 'localhost', + user: 'root', + password: '', + database: 'bank_db' + }); + + try { + await connection.beginTransaction(); + + const [rows] = await connection.execute( + 'SELECT balance FROM account WHERE account_number = ? FOR UPDATE', + [fromAccount] + ); + + if (rows.length === 0) { + throw new Error(`Source account ${fromAccount} does not exist.`); + } + + const currentBalance = parseFloat(rows[0].balance); + if (currentBalance < amount) { + throw new Error(`Insufficient funds in account ${fromAccount}.`); + } + + await connection.execute( + 'UPDATE account SET balance = balance - ? WHERE account_number = ?', + [amount, fromAccount] + ); + + const [toRows] = await connection.execute( + 'SELECT balance FROM account WHERE account_number = ? FOR UPDATE', + [toAccount] + ); + + if (toRows.length === 0) { + throw new Error(`Destination account ${toAccount} does not exist.`); + } + + await connection.execute( + 'UPDATE account SET balance = balance + ? WHERE account_number = ?', + [amount, toAccount] + ); + + await connection.execute( + 'INSERT INTO account_changes (account_number, amount, remark) VALUES (?, ?, ?)', + [fromAccount, -amount, `Transfer to account ${toAccount}`] + ); + + await connection.execute( + 'INSERT INTO account_changes (account_number, amount, remark) VALUES (?, ?, ?)', + [toAccount, amount, `Transfer from account ${fromAccount}`] + ); + + await connection.commit(); + console.log(`Successfully transferred ${amount} from ${fromAccount} to ${toAccount}.`); + } catch (err) { + console.error('Error during transaction, rolling back...', err.message); + await connection.rollback(); + } finally { + await connection.end(); + } +} + +transferAmount(101, 102, 1000.00); diff --git a/Week3/Hadidreem17/exe3.2.md/transactions-create-tables.js b/Week3/Hadidreem17/exe3.2.md/transactions-create-tables.js new file mode 100644 index 000000000..f7338f45e --- /dev/null +++ b/Week3/Hadidreem17/exe3.2.md/transactions-create-tables.js @@ -0,0 +1,43 @@ +const mysql = require('mysql2/promise'); + +async function main() { + const connection = await mysql.createConnection({ + host: 'localhost', + user: 'root', + password: '', + database: 'bank_db' + }); + + try { + const createAccountTable = ` + CREATE TABLE IF NOT EXISTS account ( + account_number INT PRIMARY KEY, + balance DECIMAL(15, 2) NOT NULL + ) ENGINE=InnoDB; + `; + + const createAccountChangesTable = ` + CREATE TABLE IF NOT EXISTS account_changes ( + change_number BIGINT AUTO_INCREMENT PRIMARY KEY, + account_number INT NOT NULL, + amount DECIMAL(15, 2) NOT NULL, + changed_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + remark VARCHAR(255), + FOREIGN KEY (account_number) REFERENCES account(account_number) + ON UPDATE CASCADE + ON DELETE RESTRICT + ) ENGINE=InnoDB; + `; + + await connection.execute(createAccountTable); + await connection.execute(createAccountChangesTable); + + console.log('Tables "account" and "account_changes" created successfully.'); + } catch (err) { + console.error('Error creating tables:', err); + } finally { + await connection.end(); + } +} + +main(); diff --git a/Week3/Hadidreem17/exe3.2.md/transactions-insert-values.js b/Week3/Hadidreem17/exe3.2.md/transactions-insert-values.js new file mode 100644 index 000000000..8f0eee588 --- /dev/null +++ b/Week3/Hadidreem17/exe3.2.md/transactions-insert-values.js @@ -0,0 +1,42 @@ +const mysql = require('mysql2/promise'); + +async function main() { + const connection = await mysql.createConnection({ + host: 'localhost', + user: 'root', + password: '', + database: 'bank_db' + }); + + try { + const insertAccounts = ` + INSERT INTO account (account_number, balance) + VALUES + (101, 5000.00), + (102, 2000.00), + (103, 7500.00) + ON DUPLICATE KEY UPDATE + balance = VALUES(balance); + `; + + await connection.execute(insertAccounts); + + const insertChanges = ` + INSERT INTO account_changes (account_number, amount, remark) + VALUES + (101, 5000.00, 'Initial deposit'), + (102, 2000.00, 'Initial deposit'), + (103, 7500.00, 'Initial deposit'); + `; + + await connection.execute(insertChanges); + + console.log('Sample data inserted into "account" and "account_changes".'); + } catch (err) { + console.error('Error inserting sample data:', err); + } finally { + await connection.end(); + } +} + +main(); diff --git a/Week3/Hadidreem17/exe3.4.md/index.js b/Week3/Hadidreem17/exe3.4.md/index.js new file mode 100644 index 000000000..cb7f25823 --- /dev/null +++ b/Week3/Hadidreem17/exe3.4.md/index.js @@ -0,0 +1,32 @@ +require("dotenv").config(); +const { MongoClient } = require("mongodb"); + +const uri = process.env.MONGODB_URI; +const client = new MongoClient(uri); + +async function main() { + await client.connect(); + const db = client.db(process.env.DB_NAME); + const collection = db.collection("bob_ross_episodes"); + + const allEpisodes = await collection.find().toArray(); + console.log("Total:", allEpisodes.length); + + const newEpisode = await collection.insertOne({ + title: "My Episode", + season: 99, + episode: 1, + }); + console.log("Inserted:", newEpisode.insertedId); + + await collection.updateOne( + { _id: newEpisode.insertedId }, + { $set: { title: "Updated Episode Title" } } + ); + + await collection.deleteOne({ _id: newEpisode.insertedId }); + + await client.close(); +} + +main(); diff --git a/Week3/Hadidreem17/package-lock.json b/Week3/Hadidreem17/package-lock.json new file mode 100644 index 000000000..fa126dbc7 --- /dev/null +++ b/Week3/Hadidreem17/package-lock.json @@ -0,0 +1,175 @@ +{ + "name": "Database-Assignment-week3", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "dotenv": "^17.2.3", + "mongodb": "^7.0.0" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.2.tgz", + "integrity": "sha512-QgA5AySqB27cGTXBFmnpifAi7HxoGUeezwo6p9dI03MuDB6Pp33zgclqVb6oVK3j6I9Vesg0+oojW2XxB59SGg==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/bson": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-7.0.0.tgz", + "integrity": "sha512-Kwc6Wh4lQ5OmkqqKhYGKIuELXl+EPYSCObVE6bWsp1T/cGkOCBN0I8wF/T44BiuhHyNi1mmKVPXk60d41xZ7kw==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/mongodb": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.0.0.tgz", + "integrity": "sha512-vG/A5cQrvGGvZm2mTnCSz1LUcbOPl83hfB6bxULKQ8oFZauyox/2xbZOoGNl+64m8VBrETkdGCDBdOsCr3F3jg==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^7.0.0", + "mongodb-connection-string-url": "^7.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.806.0", + "@mongodb-js/zstd": "^7.0.0", + "gcp-metadata": "^7.0.1", + "kerberos": "^7.0.0", + "mongodb-client-encryption": ">=7.0.0 <7.1.0", + "snappy": "^7.3.2", + "socks": "^2.8.6" + }, + "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": "7.0.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.0.tgz", + "integrity": "sha512-irhhjRVLE20hbkRl4zpAYLnDMM+zIZnp0IDB9akAFFUZp/3XdOfwwddc7y6cNvF2WCEtfTYRwYbIfYa2kVY0og==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^13.0.0", + "whatwg-url": "^14.1.0" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "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==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/Week3/Hadidreem17/package.json b/Week3/Hadidreem17/package.json new file mode 100644 index 000000000..76fdea618 --- /dev/null +++ b/Week3/Hadidreem17/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "dotenv": "^17.2.3", + "mongodb": "^7.0.0" + } +}