From 1f0e7ed08c91a82256a844818e1a8c641e53562a Mon Sep 17 00:00:00 2001 From: thusser252 Date: Fri, 10 Oct 2025 12:29:54 -0400 Subject: [PATCH] feat: Lesson 25 Intro to Databases - Add SQL queries file (trishtanhusser.sql) with: * Count of media items by type * Sum of total pages checked out by guests * All guests with checkout records using LEFT JOIN - Implement library_users table and complete integration: * Create LibraryUserModel with JPA annotations * Create LibraryUserRepository with CRUD operations * Update LibraryDataModel to include users * Update LibraryDbDataLoader to load users from database * Add sample users with bcrypt-encoded passwords - Update database creation script to include users table - All tests passing and application working correctly --- .../src/components/header/Header.tsx | 0 lesson_24/trishtanhusser/src/main.tsx | 0 .../src/pages/AddProgram/AddProgram.scss | 0 .../src/pages/AddProgram/AddProgram.tsx | 0 .../src/pages/AddProgram/index.ts | 0 .../components/ProgramList/ProgramList.tsx | 0 lesson_25/createdb/create_users_table.sql | 21 ++++ lesson_25/createdb/createdb.py | 19 +++- .../lesson25/factory/LibraryDbDataLoader.java | 3 + .../lesson25/models/LibraryDataModel.java | 5 + .../lesson25/models/LibraryUserModel.java | 92 ++++++++++++++++++ .../repository/LibraryUserRepository.java | 18 ++++ .../main/resources/queries/trishtanhusser.sql | 30 ++++++ .../db_app/src/main/resources/sqlite/data.db | Bin 16384 -> 28672 bytes 14 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 lesson_24/trishtanhusser/src/components/header/Header.tsx create mode 100644 lesson_24/trishtanhusser/src/main.tsx create mode 100644 lesson_24/trishtanhusser/src/pages/AddProgram/AddProgram.scss create mode 100644 lesson_24/trishtanhusser/src/pages/AddProgram/AddProgram.tsx create mode 100644 lesson_24/trishtanhusser/src/pages/AddProgram/index.ts create mode 100644 lesson_24/trishtanhusser/src/pages/Home/components/ProgramList/ProgramList.tsx create mode 100644 lesson_25/createdb/create_users_table.sql create mode 100644 lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/models/LibraryUserModel.java create mode 100644 lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/repository/LibraryUserRepository.java create mode 100644 lesson_25/db/db_app/src/main/resources/queries/trishtanhusser.sql diff --git a/lesson_24/trishtanhusser/src/components/header/Header.tsx b/lesson_24/trishtanhusser/src/components/header/Header.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/lesson_24/trishtanhusser/src/main.tsx b/lesson_24/trishtanhusser/src/main.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/lesson_24/trishtanhusser/src/pages/AddProgram/AddProgram.scss b/lesson_24/trishtanhusser/src/pages/AddProgram/AddProgram.scss new file mode 100644 index 000000000..e69de29bb diff --git a/lesson_24/trishtanhusser/src/pages/AddProgram/AddProgram.tsx b/lesson_24/trishtanhusser/src/pages/AddProgram/AddProgram.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/lesson_24/trishtanhusser/src/pages/AddProgram/index.ts b/lesson_24/trishtanhusser/src/pages/AddProgram/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/lesson_24/trishtanhusser/src/pages/Home/components/ProgramList/ProgramList.tsx b/lesson_24/trishtanhusser/src/pages/Home/components/ProgramList/ProgramList.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/lesson_25/createdb/create_users_table.sql b/lesson_25/createdb/create_users_table.sql new file mode 100644 index 000000000..48353e9c8 --- /dev/null +++ b/lesson_25/createdb/create_users_table.sql @@ -0,0 +1,21 @@ +-- Create library_users table +CREATE TABLE IF NOT EXISTS library_users ( + id TEXT PRIMARY KEY, + email TEXT UNIQUE NOT NULL, + firstName TEXT NOT NULL, + lastName TEXT NOT NULL, + password TEXT NOT NULL +); + +-- Insert sample users with bcrypt hashed passwords +-- Note: These passwords are bcrypt hashes of "password123" for demonstration purposes +INSERT OR REPLACE INTO library_users (id, email, firstName, lastName, password) VALUES +('550e8400-e29b-41d4-a716-446655440001', 'john.doe@email.com', 'John', 'Doe', '$2a$10$N9qo8uLOickgx2ZMRZoMye.FqUf.tZeHTQZ.H6eSSHhFXFjjKJWg6'), +('550e8400-e29b-41d4-a716-446655440002', 'jane.smith@email.com', 'Jane', 'Smith', '$2a$10$N9qo8uLOickgx2ZMRZoMye.FqUf.tZeHTQZ.H6eSSHhFXFjjKJWg6'), +('550e8400-e29b-41d4-a716-446655440003', 'bob.wilson@email.com', 'Bob', 'Wilson', '$2a$10$N9qo8uLOickgx2ZMRZoMye.FqUf.tZeHTQZ.H6eSSHhFXFjjKJWg6'), +('550e8400-e29b-41d4-a716-446655440004', 'alice.brown@email.com', 'Alice', 'Brown', '$2a$10$N9qo8uLOickgx2ZMRZoMye.FqUf.tZeHTQZ.H6eSSHhFXFjjKJWg6'), +('550e8400-e29b-41d4-a716-446655440005', 'trishtan.husser@email.com', 'Trishtan', 'Husser', '$2a$10$N9qo8uLOickgx2ZMRZoMye.FqUf.tZeHTQZ.H6eSSHhFXFjjKJWg6'); + +-- Verify the data was inserted +SELECT COUNT(*) as user_count FROM library_users; +SELECT * FROM library_users ORDER BY lastName, firstName; diff --git a/lesson_25/createdb/createdb.py b/lesson_25/createdb/createdb.py index a8af9b776..17556b6d6 100644 --- a/lesson_25/createdb/createdb.py +++ b/lesson_25/createdb/createdb.py @@ -4,14 +4,14 @@ import sqlite3 # Step 1: Load the CSV file into a pandas DataFrame -media_items_df = pd.read_csv('/workspaces/code-society-25-2/lesson_12/io/io_app/src/main/resources/csv/media_items.csv') -guests_df = pd.read_csv('/workspaces/code-society-25-2/lesson_12/io/io_app/src/main/resources/csv/guests.csv') -checked_out_items_df = pd.read_csv('/workspaces/code-society-25-2/lesson_12/io/io_app/src/main/resources/csv/checked_out_items.csv') +media_items_df = pd.read_csv('../db/db_app/src/main/resources/csv/media_items.csv') +guests_df = pd.read_csv('../db/db_app/src/main/resources/csv/guests.csv') +checked_out_items_df = pd.read_csv('../db/db_app/src/main/resources/csv/checked_out_items.csv') checked_out_items_df['due_date'] = pd.to_datetime(checked_out_items_df['due_date']).values.astype(np.int64) # Step 2: Create a connection to the SQLite database # Note: This will create the database file if it doesn't exist already -os.makedirs('/workspaces/code-society-25-2/lesson_25/db/db_app/src/main/resources/sqlite/', exist_ok=True) +os.makedirs('../db/db_app/src/main/resources/sqlite/', exist_ok=True) conn = sqlite3.connect('../db/db_app/src/main/resources/sqlite/data.db') # Step 3: Write the DataFrame to the SQLite database @@ -19,5 +19,16 @@ guests_df.to_sql('guests', conn, if_exists='replace', index=False) checked_out_items_df.to_sql('checked_out_items', conn, if_exists='replace', index=False) +# Step 4: Execute the SQL script to create users table and add sample data +with open('create_users_table.sql', 'r') as sql_file: + sql_script = sql_file.read() + # Execute each statement separately + for statement in sql_script.split(';'): + if statement.strip(): + conn.execute(statement) + conn.commit() + +print("Database created successfully with all tables including library_users!") + # Don't forget to close the connection conn.close() \ No newline at end of file diff --git a/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/factory/LibraryDbDataLoader.java b/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/factory/LibraryDbDataLoader.java index b897de124..ac4f60e62 100644 --- a/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/factory/LibraryDbDataLoader.java +++ b/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/factory/LibraryDbDataLoader.java @@ -2,6 +2,7 @@ import com.codedifferently.lesson25.models.LibraryDataModel; import com.codedifferently.lesson25.repository.LibraryGuestRepository; +import com.codedifferently.lesson25.repository.LibraryUserRepository; import com.codedifferently.lesson25.repository.MediaItemRepository; import java.io.IOException; import org.springframework.beans.factory.annotation.Autowired; @@ -13,6 +14,7 @@ public final class LibraryDbDataLoader implements LibraryDataLoader { @Autowired private MediaItemRepository mediaItemsRepository; @Autowired private LibraryGuestRepository libraryGuestRepository; + @Autowired private LibraryUserRepository libraryUserRepository; @Override public LibraryDataModel loadData() throws IOException { @@ -20,6 +22,7 @@ public LibraryDataModel loadData() throws IOException { model.mediaItems = mediaItemsRepository.findAll(); model.guests = libraryGuestRepository.findAll(); + model.users = libraryUserRepository.findAll(); return model; } diff --git a/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/models/LibraryDataModel.java b/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/models/LibraryDataModel.java index 6c268f962..075fea21b 100644 --- a/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/models/LibraryDataModel.java +++ b/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/models/LibraryDataModel.java @@ -17,6 +17,7 @@ public class LibraryDataModel { public List mediaItems; public List guests; + public List users; public List getMediaItems() { List results = new ArrayList<>(); @@ -59,4 +60,8 @@ public Map> getCheckoutsByEmail() { } return results; } + + public List getUsers() { + return users != null ? users : new ArrayList<>(); + } } diff --git a/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/models/LibraryUserModel.java b/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/models/LibraryUserModel.java new file mode 100644 index 000000000..271a921fc --- /dev/null +++ b/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/models/LibraryUserModel.java @@ -0,0 +1,92 @@ +package com.codedifferently.lesson25.models; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.UUID; + +@Entity +@Table(name = "library_users") +public class LibraryUserModel { + + @Id public String id; + public String email; + public String firstName; + public String lastName; + public String password; + + // Default constructor for JPA + public LibraryUserModel() {} + + // Constructor for creating new users + public LibraryUserModel(String email, String firstName, String lastName, String password) { + this.id = UUID.randomUUID().toString(); + this.email = email; + this.firstName = firstName; + this.lastName = lastName; + this.password = password; + } + + // Getters and setters + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFullName() { + return firstName + " " + lastName; + } + + @Override + public String toString() { + return "LibraryUserModel{" + + "id='" + + id + + '\'' + + ", email='" + + email + + '\'' + + ", firstName='" + + firstName + + '\'' + + ", lastName='" + + lastName + + '\'' + + '}'; + } +} diff --git a/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/repository/LibraryUserRepository.java b/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/repository/LibraryUserRepository.java new file mode 100644 index 000000000..f3513b403 --- /dev/null +++ b/lesson_25/db/db_app/src/main/java/com/codedifferently/lesson25/repository/LibraryUserRepository.java @@ -0,0 +1,18 @@ +package com.codedifferently.lesson25.repository; + +import com.codedifferently.lesson25.models.LibraryUserModel; +import java.util.List; +import java.util.Optional; +import org.springframework.data.repository.CrudRepository; + +public interface LibraryUserRepository extends CrudRepository { + + @Override + List findAll(); + + Optional findByEmail(String email); + + List findByFirstNameContainingIgnoreCase(String firstName); + + List findByLastNameContainingIgnoreCase(String lastName); +} diff --git a/lesson_25/db/db_app/src/main/resources/queries/trishtanhusser.sql b/lesson_25/db/db_app/src/main/resources/queries/trishtanhusser.sql new file mode 100644 index 000000000..42f6df464 --- /dev/null +++ b/lesson_25/db/db_app/src/main/resources/queries/trishtanhusser.sql @@ -0,0 +1,30 @@ +-- Lesson 25 SQL Queries by Trishtan Husser +-- Query exercises for database operations + +-- Query 1: Count of media items by type +-- This query returns the counts of media items grouped by their type +SELECT type, COUNT(*) as count +FROM media_items +GROUP BY type +ORDER BY count DESC; + +-- Query 2: Sum of total pages checked out by guests +-- This query calculates the total pages from all checked out items +SELECT SUM(mi.pages) as total_pages_checked_out +FROM checked_out_items coi +JOIN media_items mi ON coi.itemId = mi.id +WHERE mi.pages IS NOT NULL; + +-- Query 3: All guests with their corresponding checked out items (LEFT JOIN) +-- This query shows all 5 guests and any corresponding records in the checked_out_items table +SELECT g.name, + g.email, + g.type, + coi.itemId, + coi.dueDate, + mi.title, + mi.type as media_type +FROM guests g +LEFT JOIN checked_out_items coi ON g.email = coi.email +LEFT JOIN media_items mi ON coi.itemId = mi.id +ORDER BY g.name, coi.dueDate; diff --git a/lesson_25/db/db_app/src/main/resources/sqlite/data.db b/lesson_25/db/db_app/src/main/resources/sqlite/data.db index 8baa982d2b27c50808a4c569a14c47972c41a695..94a6e0800f6a7717f1863dc700ab50aaac2c9f02 100644 GIT binary patch delta 1521 zcma)*&rj1}7{~k4{QzS73b;&SNNTcVkg#SQ?bt5jh9d*EA)^hj#4PRh!aBQE+AhGs zboF4u4Z_`j!4NLSi+_U`<4wJIF!Acywtx)Tv~Thr-tYH$@_ydudERapbiab*2V*G= z!-Dp{T9K34xyckpx8D% zht-abH2ucGzgW&?_#DM&vV|OV!=k1~DSOFviqCEF)YI~EF;m{AR&(34u7O&jtXz0P zX?b19QKdDWDhY+ctmy{q$eM1H#1^^;`s2E$A`bRmh`PS7YL^#Z<&DmyLxFHH3NX1{ zM+f?zA{(eGb_~@$S9{>MG`*VWIcs__ea~aAoyy!u4cK)bc4}`8kDqRmM_}yq8(9T+ z&ol5te4MZiKOtc7CHad~iSLAPW-St?Mf!un!qlYY=eRgZvGI5eCDKxiW$J89oM)0T zmQ5x(jZr|<LeZG**iVBZ-nHxFy WCx`QOGV)D+$QRGZyV;R{zX1RM&<~^l