From 10ceab3b35fc36299876b4336825cf46d56d16f5 Mon Sep 17 00:00:00 2001 From: Manuela Iacobovici Date: Sun, 2 Apr 2023 15:33:49 +0100 Subject: [PATCH 1/7] finished classes --- lib/item.rb | 24 +++++++ lib/order.rb | 19 ++++++ lib/shop_manager.rb | 132 +++++++++++++++++++++++++++++++++++++++ recipe.md | 149 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 324 insertions(+) create mode 100644 lib/item.rb create mode 100644 lib/order.rb create mode 100644 lib/shop_manager.rb create mode 100644 recipe.md diff --git a/lib/item.rb b/lib/item.rb new file mode 100644 index 00000000..8198292c --- /dev/null +++ b/lib/item.rb @@ -0,0 +1,24 @@ +class Item + def initialize(name, unit_price, quantity, item_id = 0) + @name = name + @unit_price = unit_price + @quantity = quantity + @item_id = item_id + end + + def name + @name + end + + def unit_price + @unit_price + end + + def quantity + @quantity + end + + def item_id + @item_id + end +end \ No newline at end of file diff --git a/lib/order.rb b/lib/order.rb new file mode 100644 index 00000000..94813ae2 --- /dev/null +++ b/lib/order.rb @@ -0,0 +1,19 @@ +class Order + def initialize(customer_name, item, order_id = 0) + @customer_name = customer_name + @item = item + @order_id = order_id + end + + def customer_name + @customer_name + end + + def item + @item + end + + def order_id + @order_id + end +end \ No newline at end of file diff --git a/lib/shop_manager.rb b/lib/shop_manager.rb new file mode 100644 index 00000000..31035386 --- /dev/null +++ b/lib/shop_manager.rb @@ -0,0 +1,132 @@ +class ShopManager + WHAT_TO_DO = ' What do you want to do? + 1 = list all shop items + 2 = create a new item + 3 = list all orders + 4 = create a new order' + + def initialize + @conn_db = psql -h 127.0.0.1 shop_manager + print ' + Welcome to the shop management program! + + ${WHAT_TO_DO} + ' + answer = gets.chomp + case answer + when '1' + all_items + when '2' + new_item_collect_data + when '3' + all_orders + when '4' + new_order_collect_data + else + print(WHAT_TO_DO) + end + end + + def new_item_collect_data + while true do + puts 'Enter the name for the new Item' + name = gets.chomp + break if name.count("a-zA-Z") > 0 + end + while true do + puts 'Enter the price for the ${name}' + unit_price = gets.chomp + break if unit_price.is_a? Integer + end + while true do + puts 'Enter the quantity for the ${name}' + quantity = gets.chomp + break if quantity.is_a? Integer + end + item = Item.new(name, unit_price, quantity) + new_item(item) + end + + def new_item(item) + # add item to items table + query = "INSERT INTO items(name, unit_price, quantity) + VALUES('${item.name}', '${item.unit_price}', '${item.quantity}');" + @conn_db.exec(query) + if @@ROWCOUNT > 0 + puts "Your item has been added succesfully" + end + end + + def new_order_collect_data + while true do + puts 'New Order, please enter your name' + customer_name = gets.chomp + break if customer_name.count("a-zA-Z") > 4 && customer_name.split(' ').count >= 2 + end + items = all_items + while true do + puts "Please select you item's id" + item_id = gets.chomp + if item_id.is_a? Integer + return_item = items.find { |curr_item| curr_item.item_id == item_id } + if !return_item.nil? + item = Item.new(return_item.name, return_item.unit_price, return_item.quantity, return_item.item_id) + order = Order.new(customer_name, item) + new_order(order) + end + end + break unless return_item.nil? + end + end + + def new_order(order) + # add order to orders table + query = "INSERT INTO orders(customer_name, item_id) + VALUES('${order.customer_name}', '${order.item_id}');" + @conn_db.exec(query) + if @@ROWCOUNT > 0 + puts "Your order has been placed succesfully, thank you!" + end + end + + private + def get_select_query(table) + "SELECT * FROM ${table};" + end + + def all_items + query = get_select_query('items') + items = @conn_db.exec(query) + items = items.map do |item| + Item.new(item.name, item.unit_price, item.quantity, item.item_id) + end + print_all_items(items) + items + end + + def all_orders + items = all_items + query = get_select_query('orders') + orders = @conn_db.exec(query) + orders = orders.map do |order| + item = items.find { |curr_item| curr_item.item_id == order.item_id } + Order.new(order.customer_name, item, order.order_id) + end + print_all_orders(orders) + orders + end + + def print_all_items(items) + #1 Super Shark Vacuum Cleaner - Unit price: 99 - Quantity: 30 + items.each do |item| + puts "${item.item_id} ${item.name} - Unit price: ${item.unit_price} - Quantity: ${item.quantity}" + end + end + + def print_all_orders(orders) + #1 Super Shark Vacuum Cleaner - Unit price: 99 - Quantity: 30 + orders.each do |order| + puts "${order.order_id} ${order.customer_name} - Item: ${order.item.name} - Price: ${order.item.unit_price}" + end + end +end \ No newline at end of file diff --git a/recipe.md b/recipe.md new file mode 100644 index 00000000..d42e5c0d --- /dev/null +++ b/recipe.md @@ -0,0 +1,149 @@ +# Two Tables (Many-to-Many) Design Recipe Template + +_Copy this recipe template to design and create two related database tables having a Many-to-Many relationship._ + +## 1. Extract nouns from the user stories or specification + +```ruby +As a shop manager +So I can know which items I have in stock +I want to keep a list of my shop items with their name and unit price. + +As a shop manager +So I can know which items I have in stock +I want to know which quantity (a number) I have for each item. + +As a shop manager +So I can manage items +I want to be able to create a new item. + +As a shop manager +So I can know which orders were made +I want to keep a list of orders with their customer name. + +As a shop manager +So I can know which orders were made +I want to assign each order to their corresponding item. + +As a shop manager +So I can know which orders were made +I want to know on which date an order was placed. + +As a shop manager +So I can manage orders +I want to be able to create a new order. + +``` +Nouns: + +items, item_name, unit_price +``` + +## 2. Infer the Table Name and Columns + +Put the different nouns in this table. Replace the example with your own nouns. + +| Record | Properties | +| --------------------- | ------------------ | +| posts | title, content +| tags | name + +1. Name of the first table (always plural): `posts` + + Column names: `title`, `content` + +2. Name of the second table (always plural): `tags` + + Column names: `name` + +## 3. Decide the column types. + +[Here's a full documentation of PostgreSQL data types](https://www.postgresql.org/docs/current/datatype.html). + +Most of the time, you'll need either `text`, `int`, `bigint`, `numeric`, or `boolean`. If you're in doubt, do some research or ask your peers. + +Remember to **always** have the primary key `id` as a first column. Its type will always be `SERIAL`. + +``` +# EXAMPLE: + +Table: posts +id: SERIAL +title: text +content: text + +Table: tags +id: SERIAL +name: text +``` + +## 4. Design the Many-to-Many relationship + +Make sure you can answer YES to these two questions: + +1. Can one [TABLE ONE] have many [TABLE TWO]? (Yes/No) +2. Can one [TABLE TWO] have many [TABLE ONE]? (Yes/No) + +``` +# EXAMPLE + +1. Can one tag have many posts? YES +2. Can one post have many tags? YES +``` + +_If you would answer "No" to one of these questions, you'll probably have to implement a One-to-Many relationship, which is simpler. Use the relevant design recipe in that case._ + +## 5. Design the Join Table + +The join table usually contains two columns, which are two foreign keys, each one linking to a record in the two other tables. + +The naming convention is `table1_table2`. + +``` +# EXAMPLE + +Join table for tables: posts and tags +Join table name: posts_tags +Columns: post_id, tag_id +``` + +## 4. Write the SQL. + +```sql +-- EXAMPLE +-- file: posts_tags.sql + +-- Replace the table name, columm names and types. + +-- Create the first table. +CREATE TABLE items ( + item_id SERIAL PRIMARY KEY, + name text, + unit_price int, + quantity int +); + +-- Create the second table. +CREATE TABLE orders ( + order_id SERIAL PRIMARY KEY, + custumer_name text, + date TIMESTAMP not null defaul now(), + item_id int +); + +-- Create the join table. +CREATE TABLE items_orders ( + item_id int, + order_id int, + constraint fk_item foreign key(item_id) references items(id) on delete cascade, + constraint fk_order foreign key(order_id) references orders(id) on delete cascade, + PRIMARY KEY (item_id, order_id) +); + +``` + +## 5. Create the tables. + +```bash +psql -h 127.0.0.1 database_name < posts_tags.sql +``` From bea9b760ba3eba032dd8f42b428f222051a94cc1 Mon Sep 17 00:00:00 2001 From: Manuela Iacobovici Date: Sun, 2 Apr 2023 19:33:03 +0100 Subject: [PATCH 2/7] add and print items work --- lib/shop_manager.rb | 68 +++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/lib/shop_manager.rb b/lib/shop_manager.rb index 31035386..cd7b8adc 100644 --- a/lib/shop_manager.rb +++ b/lib/shop_manager.rb @@ -1,17 +1,26 @@ +require_relative './item' +require_relative './order' +require 'pg' + class ShopManager - WHAT_TO_DO = ' What do you want to do? + WHAT_TO_DO = 'What do you want to do? 1 = list all shop items 2 = create a new item 3 = list all orders 4 = create a new order' def initialize - @conn_db = psql -h 127.0.0.1 shop_manager - print ' - Welcome to the shop management program! + db_connect + initiate_menu + end - ${WHAT_TO_DO} - ' + def initiate_menu(initial = true) + puts " + Welcome to the shop management program! + " if initial == true + puts " + #{WHAT_TO_DO} + " answer = gets.chomp case answer when '1' @@ -23,7 +32,7 @@ def initialize when '4' new_order_collect_data else - print(WHAT_TO_DO) + initiate_menu(false) end end @@ -34,14 +43,14 @@ def new_item_collect_data break if name.count("a-zA-Z") > 0 end while true do - puts 'Enter the price for the ${name}' + puts "Enter the price for the #{name}" unit_price = gets.chomp - break if unit_price.is_a? Integer + break if unit_price.to_i.is_a? Integer end while true do - puts 'Enter the quantity for the ${name}' + puts "Enter the quantity for the #{name}" quantity = gets.chomp - break if quantity.is_a? Integer + break if quantity.to_i.is_a? Integer end item = Item.new(name, unit_price, quantity) new_item(item) @@ -50,11 +59,13 @@ def new_item_collect_data def new_item(item) # add item to items table query = "INSERT INTO items(name, unit_price, quantity) - VALUES('${item.name}', '${item.unit_price}', '${item.quantity}');" - @conn_db.exec(query) - if @@ROWCOUNT > 0 - puts "Your item has been added succesfully" - end + VALUES('#{item.name}', #{item.unit_price.to_i}, #{item.quantity.to_i});" + result = @conn_db.exec(query) + puts "Your item has been added succesfully" + end + + def db_connect() + @conn_db = PG.connect({ host: '127.0.0.1', dbname: 'shop_manager' }) end def new_order_collect_data @@ -82,23 +93,23 @@ def new_order_collect_data def new_order(order) # add order to orders table query = "INSERT INTO orders(customer_name, item_id) - VALUES('${order.customer_name}', '${order.item_id}');" - @conn_db.exec(query) - if @@ROWCOUNT > 0 - puts "Your order has been placed succesfully, thank you!" - end + VALUES('#{order.customer_name}', '#{order.item_id}') RETURNING *;" + p @conn_db.exec(query) + # if @@ROWCOUNT > 0 + # puts "Your order has been placed succesfully, thank you!" + # end end private def get_select_query(table) - "SELECT * FROM ${table};" + "SELECT * FROM #{table};" end def all_items query = get_select_query('items') items = @conn_db.exec(query) items = items.map do |item| - Item.new(item.name, item.unit_price, item.quantity, item.item_id) + Item.new(item['name'], item['unit_price'], item['quantity'], item['item_id']) end print_all_items(items) items @@ -110,7 +121,7 @@ def all_orders orders = @conn_db.exec(query) orders = orders.map do |order| item = items.find { |curr_item| curr_item.item_id == order.item_id } - Order.new(order.customer_name, item, order.order_id) + Order.new(order["customer_name"], item, order["order_id"]) end print_all_orders(orders) orders @@ -119,14 +130,17 @@ def all_orders def print_all_items(items) #1 Super Shark Vacuum Cleaner - Unit price: 99 - Quantity: 30 items.each do |item| - puts "${item.item_id} ${item.name} - Unit price: ${item.unit_price} - Quantity: ${item.quantity}" + puts "#{item.item_id} #{item.name} - Unit price: #{item.unit_price} - Quantity: #{item.quantity}" end end def print_all_orders(orders) #1 Super Shark Vacuum Cleaner - Unit price: 99 - Quantity: 30 orders.each do |order| - puts "${order.order_id} ${order.customer_name} - Item: ${order.item.name} - Price: ${order.item.unit_price}" + puts order#"#{order.order_id} #{order.customer_name} - Item: #{order.item['name']} - Price: #{order.item.unit_price}" end end -end \ No newline at end of file +end + +ShopManager.new + From 92f79d07c5f296d6848c9db0a7df75a80435334a Mon Sep 17 00:00:00 2001 From: Manuela Iacobovici Date: Sun, 2 Apr 2023 19:58:59 +0100 Subject: [PATCH 3/7] all works --- lib/shop_manager.rb | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/shop_manager.rb b/lib/shop_manager.rb index cd7b8adc..6bebc75e 100644 --- a/lib/shop_manager.rb +++ b/lib/shop_manager.rb @@ -24,7 +24,7 @@ def initiate_menu(initial = true) answer = gets.chomp case answer when '1' - all_items + print_all_items(all_items) when '2' new_item_collect_data when '3' @@ -78,7 +78,7 @@ def new_order_collect_data while true do puts "Please select you item's id" item_id = gets.chomp - if item_id.is_a? Integer + if item_id.to_i.is_a? Integer return_item = items.find { |curr_item| curr_item.item_id == item_id } if !return_item.nil? item = Item.new(return_item.name, return_item.unit_price, return_item.quantity, return_item.item_id) @@ -93,11 +93,9 @@ def new_order_collect_data def new_order(order) # add order to orders table query = "INSERT INTO orders(customer_name, item_id) - VALUES('#{order.customer_name}', '#{order.item_id}') RETURNING *;" - p @conn_db.exec(query) - # if @@ROWCOUNT > 0 - # puts "Your order has been placed succesfully, thank you!" - # end + VALUES('#{order.customer_name}', '#{order.item.item_id}') RETURNING *;" + @conn_db.exec(query) + puts "Your order has been placed succesfully, thank you!" end private @@ -111,33 +109,36 @@ def all_items items = items.map do |item| Item.new(item['name'], item['unit_price'], item['quantity'], item['item_id']) end - print_all_items(items) + items end + def orders_all + query = get_select_query('orders') + @conn_db.exec(query) + end + def all_orders items = all_items - query = get_select_query('orders') - orders = @conn_db.exec(query) + orders = orders_all orders = orders.map do |order| - item = items.find { |curr_item| curr_item.item_id == order.item_id } + item = items.find { |curr_item| curr_item.item_id == order['item_id'] } Order.new(order["customer_name"], item, order["order_id"]) end print_all_orders(orders) - orders end def print_all_items(items) #1 Super Shark Vacuum Cleaner - Unit price: 99 - Quantity: 30 items.each do |item| - puts "#{item.item_id} #{item.name} - Unit price: #{item.unit_price} - Quantity: #{item.quantity}" + puts "Item id: #{item.item_id} - #{item.name} - Unit price: £#{item.unit_price}.00 - Quantity: #{item.quantity}" end end def print_all_orders(orders) #1 Super Shark Vacuum Cleaner - Unit price: 99 - Quantity: 30 orders.each do |order| - puts order#"#{order.order_id} #{order.customer_name} - Item: #{order.item['name']} - Price: #{order.item.unit_price}" + puts "Order id: #{order.order_id} - #{order.customer_name} - Item: #{order.item.name} - Price: £#{order.item.unit_price}.00" end end end From ae7da5852a4f39bed50dc7855f656fe52a5713a4 Mon Sep 17 00:00:00 2001 From: Manuela Iacobovici Date: Sun, 2 Apr 2023 20:02:17 +0100 Subject: [PATCH 4/7] add message for lists --- lib/shop_manager.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/shop_manager.rb b/lib/shop_manager.rb index 6bebc75e..acc45db8 100644 --- a/lib/shop_manager.rb +++ b/lib/shop_manager.rb @@ -129,6 +129,7 @@ def all_orders end def print_all_items(items) + puts "Here's a list of all shop items:" #1 Super Shark Vacuum Cleaner - Unit price: 99 - Quantity: 30 items.each do |item| puts "Item id: #{item.item_id} - #{item.name} - Unit price: £#{item.unit_price}.00 - Quantity: #{item.quantity}" @@ -136,6 +137,7 @@ def print_all_items(items) end def print_all_orders(orders) + puts "Here's a list of all shop orders:" #1 Super Shark Vacuum Cleaner - Unit price: 99 - Quantity: 30 orders.each do |order| puts "Order id: #{order.order_id} - #{order.customer_name} - Item: #{order.item.name} - Price: £#{order.item.unit_price}.00" From 79e01981ee28fb4889f46e6d8aa4c4d771cd35be Mon Sep 17 00:00:00 2001 From: Manuela Iacobovici Date: Sun, 2 Apr 2023 20:09:44 +0100 Subject: [PATCH 5/7] updated README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 242f94be..5420baec 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +Notes: +I did not get to TDD this project as I wished for due to lack of time, it just seemed more important to me at this time to imagine and put in practice a whole shop_manager with the relevant classes, methods and DB access. I will definatly do a lot more on the testing next time. What a lovely jouney it has been to see it work in the end so close to what a real app would do. + + + + Shop Manager Project ================= From ac344e334b80a69feda6d7d3f184a10b5cc66a18 Mon Sep 17 00:00:00 2001 From: ManuelaIacobovici <124523759+ManuelaIacobovici@users.noreply.github.com> Date: Sun, 2 Apr 2023 20:12:17 +0100 Subject: [PATCH 6/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5420baec..3f243362 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ Notes: -I did not get to TDD this project as I wished for due to lack of time, it just seemed more important to me at this time to imagine and put in practice a whole shop_manager with the relevant classes, methods and DB access. I will definatly do a lot more on the testing next time. What a lovely jouney it has been to see it work in the end so close to what a real app would do. +I did not get to TDD this project as I wished for due to lack of time, it just seemed more important to me at this time to imagine and put in practice a whole shop_manager with the relevant classes, methods and DB access. I will definetly do a lot more on the testing next time. What a lovely jouney it has been to see it work in the end so close to what a real app would do. From 63e12eba89156c234e7caadcb42904f588757beb Mon Sep 17 00:00:00 2001 From: ManuelaIacobovici <124523759+ManuelaIacobovici@users.noreply.github.com> Date: Sun, 2 Apr 2023 20:13:56 +0100 Subject: [PATCH 7/7] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f243362..6cac17bf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -Notes: +Note: +------- I did not get to TDD this project as I wished for due to lack of time, it just seemed more important to me at this time to imagine and put in practice a whole shop_manager with the relevant classes, methods and DB access. I will definetly do a lot more on the testing next time. What a lovely jouney it has been to see it work in the end so close to what a real app would do.