Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
require_relative 'lib/database_connection'
require_relative 'lib/order_repository'
require_relative 'lib/item_repository'

class Application
def initialize(database_name, io, order_repository, item_repository)
DatabaseConnection.connect(database_name)
@io = io
@order_repository = order_repository
@item_repository = item_repository
end

def run
@io.puts "Welcome to the shop management program!\n \nWhat would you like to do?\n1 = list all shop items\n2 = create a new item\n3 = list all orders\n4 = create a new order\n\n\n\nEnter your choice:"
result = @io.gets.chomp.to_i
case result
when 1
@io.puts "\nHere's a list of all shop items:\n"
@item_repository.all.each do |item|
@io.puts "##{item.id} #{item.name} - Unit price: #{item.unit_price} - Quantity: #{item.stock_quantity}"
end
when 2
@io.puts "\nPlease enter the NAME of the item and hit enter"
new_name = @io.gets.chomp.to_s
@io.puts "\nPlease enter the UNIT PRICE of the item and hit enter"
new_unit_price = @io.gets.chomp.to_i
@io.puts "\nPlease enter the STOCK QUANTITY of the item and hit enter"
new_stock_quantity = @io.gets.chomp.to_i
@io.puts "\nHere's a list of all shop items:\n"
new_item = Item.new
new_item.name, new_item.unit_price, new_item.stock_quantity = new_name, new_unit_price, new_stock_quantity
@item_repository.create(new_item)
@item_repository.all.each do |item|
@io.puts "##{item.id} #{item.name} - Unit price: #{item.unit_price} - Quantity: #{item.stock_quantity}"
end
when 3
@io.puts "\nHere's a list of all orders:\n"
@order_repository.all.each do |order|
@io.puts "##{order.id} Customer: #{order.customer_name} - Order date: #{order.order_date} - Item id: #{order.item_id}"
end
when 4
@io.puts "\nPlease enter the CUSTOMER NAME of the order and hit enter"
new_customer_name = @io.gets.chomp.to_s
@io.puts "\nPlease enter the DATE of the order and hit enter (YYYY-MM-DD)"
new_order_date = @io.gets.chomp.to_s
@io.puts "\nPlease enter the ITEM ID of the order and hit enter"
new_item_id = @io.gets.chomp.to_i
@io.puts "\nHere's a list of all orders:\n"
new_order = Order.new
new_order.customer_name, new_order.order_date, new_order.item_id = new_customer_name, new_order_date, new_item_id
@order_repository.create(new_order)
@order_repository.all.each do |order|
@io.puts "##{order.id} Customer: #{order.customer_name} - Order date: #{order.order_date} - Item id: #{order.item_id}"
end
end
end

end

if __FILE__ == $0
app = Application.new(
'shop_manager',
Kernel,
OrderRepository.new,
ItemRepository.new
)
app.run
end
212 changes: 212 additions & 0 deletions items_class_design_recipe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# Items Model and Repository Classes Design Recipe


## 1. Design and create the Table


```
# EXAMPLE

Table: items

| Record | Properties |
| --------------------- | ---------------------------------- |
| item | name, unit_price, stock_quantity |
```

## 2. Create Test SQL seeds

Your tests will depend on data stored in PostgreSQL to run.

If seed data is provided (or you already created it), you can skip this step.

```sql
-- EXAMPLE
-- (file: spec/seeds_items.sql)

-- Write your SQL seed here.

-- First, you'd need to truncate the table - this is so our table is emptied between each test run,
-- so we can start with a fresh state.
-- (RESTART IDENTITY resets the primary key)

TRUNCATE TABLE items RESTART IDENTITY CASCADE; -- replace with your own table name.

-- Below this line there should only be `INSERT` statements.
-- Replace these statements with your own seed data.

INSERT INTO items (name, unit_price, stock_quantity ) VALUES ('Super Shark Vacuum Cleaner', 99, 30 );
INSERT INTO items (name, unit_price, stock_quantity ) VALUES ('Makerspresso Coffee Machine', 69, 15);
```

Run this SQL file on the database to truncate (empty) the table, and insert the seed data. Be mindful of the fact any existing records in the table will be deleted.

```bash
psql -h 127.0.0.1 shop_manager_test < spec/seeds_items.sql;
```
This was created from the terminal within the directory containing the database file

## 3. Define the class names

```ruby
# EXAMPLE
# Table name: items

# Model class
# (in lib/item.rb)
class Item
end

# Repository class
# (in lib/item_repository.rb)
class ItemRepository
end
```

## 4. Implement the Model class


```ruby
# Table name: items

# Model class
# (in lib/item.rb)

class Item

attr_accessor :id, :name, :unit_price, :stock_quantity
end


```

*You may choose to test-drive this class, but unless it contains any more logic than the example above, it is probably not needed.*

## 5. Define the Repository Class interface


```ruby
# Table name: items

# Repository class
# (in lib/item_repository.rb)

class ItemRepository


def all

end

def find(id)

end

def create(item)

end

def delete(id)

end

def update(item)

end
end
```

## 6. Write Test Examples


```ruby
# 1
# Get all items
repo = ItemRepository.new

items = repo.all
expect(items.size).to eq 2
expect(items.first.id).to eq '1'
expect(items.first.name).to eq 'Super Shark Vacuum Cleaner'
expect(items.first.unit_price).to eq '99'
expect(items.first.stock_quantity).to eq '30'

# 2
# Find item by id

repo = ItemRepository.new
item = repo.find(1)
expect(item.id).to eq '1'
expect(item.name).to eq 'Super Shark Vacuum Cleaner'
expect(item.unit_price).to eq '99'
expect(item.stock_quantity).to eq '30'

# 3
# Create a new item

repo = ItemRepository.new
add_item = Item.new
add_item.name, add_item.unit_price, add_item.stock_quantity = 'Fight Milk', 19, 2
repo.create(add_item)
items = repo.all
new_item = items.last
expect(new_item.id).to eq '3'
expect(new_item.name).to eq 'Fight Milk'
expect(new_item.unit_price).to eq '19'
expect(new_item.stock_quantity).to eq '200'

# 4
# Delete an item with the id as input

repo = ItemRepository.new
repo.delete(1)
items = repo.all
first_item = items.first
expect(first_item.id).to eq '2'
expect(first_item.name).to eq 'Makerspresso Coffee Machine'
expect(first_item.unit_price).to eq '69'
expect(first_item.stock_quantity).to eq '15'

# 5
# Update an item with the id as input

repo = ItemRepository.new
original_item = repo.find(1)
original_item.name, original_item.unit_price, original_item.stock_quantity =
'New Hoover', 149, 100
repo.update(original_item)
updated_item = repo.find(1)
expect(updated_item.id).to eq '1'
expect(updated_item.name).to eq 'New Hoover'
expect(updated_item.unit_price).to eq '149'
expect(updated_item.stock_quantity).to eq '100'
```

Encode this example as a test.

## 7. Reload the SQL seeds before each test run

Running the SQL code present in the seed file will empty the table and re-insert the seed data.

This is so you get a fresh table contents every time you run the test suite.

```ruby
# EXAMPLE

# file: spec/BLANK_repository_spec.rb

RSpec.describe ItemRepository do
def reset_items_table
seed_sql = File.read('spec/seeds_items.sql')
connection = PG.connect({ host: '127.0.0.1', dbname: 'shop_manager_test' })
connection.exec(seed_sql)
end

before(:each) do
reset_items_table
end
```

## 8. Test-drive and implement the Repository class behaviour

_After each test you write, follow the test-driving process of red, green, refactor to implement the behaviour._
26 changes: 26 additions & 0 deletions lib/database_connection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require 'pg'

# This class is a thin "wrapper" around the
# PG library. We'll use it in our project to interact
# with the database using SQL.

class DatabaseConnection
# This method connects to PostgreSQL using the
# PG gem. We connect to 127.0.0.1, and select
# the database name given in argument.
def self.connect(database_name)
@connection = PG.connect({ host: '127.0.0.1', dbname: database_name })
end

# This method executes an SQL query
# on the database, providing some optional parameters
# (you will learn a bit later about when to provide these parameters).
def self.exec_params(query, params)
if @connection.nil?
raise 'DatabaseConnection.exec_params: Cannot run a SQL query as the connection to'\
'the database was never opened. Did you make sure to call first the method '\
'`DatabaseConnection.connect` in your app.rb file (or in your tests spec_helper.rb)?'
end
@connection.exec_params(query, params)
end
end
4 changes: 4 additions & 0 deletions lib/item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Item

attr_accessor :id, :name, :unit_price, :stock_quantity
end
52 changes: 52 additions & 0 deletions lib/item_repository.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require_relative 'item'

class ItemRepository
def all
sql = 'SELECT id, name, unit_price, stock_quantity FROM items;'
result = DatabaseConnection.exec_params(sql, [])
items_array = []
result.each do |row|
item = Item.new
item.id, item.name, item.unit_price, item.stock_quantity =
row['id'], row['name'], row['unit_price'], row['stock_quantity']
items_array << item
end
return items_array
end

def find(id)
sql = 'SELECT id, name, unit_price, stock_quantity FROM items WHERE id = $1'
param = [id]
result = DatabaseConnection.exec_params(sql, param)
row = result.first

item = Item.new
item.id, item.name, item.unit_price, item.stock_quantity =
row['id'], row['name'], row['unit_price'], row['stock_quantity']
return item
end

def create(item)
sql = 'INSERT INTO items (name, unit_price, stock_quantity) VALUES ($1, $2, $3)'
params = [item.name, item.unit_price, item.stock_quantity]
DatabaseConnection.exec_params(sql, params)

return nil
end

def delete(id)
sql = "DELETE FROM items WHERE id = $1"
param = [id]
DatabaseConnection.exec_params(sql, param)

return nil
end

def update(item)
sql = "UPDATE items SET name = $1, unit_price = $2, stock_quantity = $3 WHERE id = $4"
params = [item.name, item.unit_price, item.stock_quantity, item.id]
DatabaseConnection.exec_params(sql, params)

return nil
end
end
4 changes: 4 additions & 0 deletions lib/order.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Order

attr_accessor :id, :customer_name, :order_date, :item_id
end
Loading