From 02c87fe62d2f9fd778f72b0e2c9ecc964e27b0ee Mon Sep 17 00:00:00 2001 From: Quddus Rahman Date: Sun, 2 Apr 2023 15:44:38 +0100 Subject: [PATCH 1/5] created databases, seeds and started rspec for items repo --- app.rb | 3 + lib/database_connection.rb | 26 ++++ repository_class_recipe_template.md | 226 ++++++++++++++++++++++++++++ spec/items_repository_spec.rb | 16 ++ spec/seeds_items.sql | 14 ++ spec/seeds_orders.sql | 14 ++ spec/shop_manager_table.sql | 35 +++++ spec/spec_helper.rb | 9 +- two_table_design_recipe_template.md | 146 ++++++++++++++++++ 9 files changed, 488 insertions(+), 1 deletion(-) create mode 100644 app.rb create mode 100644 lib/database_connection.rb create mode 100644 repository_class_recipe_template.md create mode 100644 spec/items_repository_spec.rb create mode 100644 spec/seeds_items.sql create mode 100644 spec/seeds_orders.sql create mode 100644 spec/shop_manager_table.sql create mode 100644 two_table_design_recipe_template.md diff --git a/app.rb b/app.rb new file mode 100644 index 00000000..45df0b4b --- /dev/null +++ b/app.rb @@ -0,0 +1,3 @@ +require_relative 'database_connection' + +DatabaseConnection.connect('shop_manager') diff --git a/lib/database_connection.rb b/lib/database_connection.rb new file mode 100644 index 00000000..ac9ec32a --- /dev/null +++ b/lib/database_connection.rb @@ -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 \ No newline at end of file diff --git a/repository_class_recipe_template.md b/repository_class_recipe_template.md new file mode 100644 index 00000000..935ce2fb --- /dev/null +++ b/repository_class_recipe_template.md @@ -0,0 +1,226 @@ +# {{TABLE NAME}} Model and Repository Classes Design Recipe + +_Copy this recipe template to design and implement Model and Repository classes for a database table._ + +## 1. Design and create the Table + +If the table is already created in the database, you can skip this step. + +Otherwise, [follow this recipe to design and create the SQL schema for your table](./single_table_design_recipe_template.md). + +*In this template, we'll use an example table `students`* + +``` +# EXAMPLE + +Table: students + +Columns: +id | name | cohort_name +``` + +## 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_{table_name}.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 students RESTART IDENTITY; -- 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 students (name, cohort_name) VALUES ('David', 'April 2022'); +INSERT INTO students (name, cohort_name) VALUES ('Anna', 'May 2022'); +``` + +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 your_database_name < seeds_{table_name}.sql +``` + +## 3. Define the class names + +Usually, the Model class name will be the capitalised table name (single instead of plural). The same name is then suffixed by `Repository` for the Repository class name. + +```ruby +# EXAMPLE +# Table name: students + +# Model class +# (in lib/student.rb) +class Student +end + +# Repository class +# (in lib/student_repository.rb) +class StudentRepository +end +``` + +## 4. Implement the Model class + +Define the attributes of your Model class. You can usually map the table columns to the attributes of the class, including primary and foreign keys. + +```ruby +# EXAMPLE +# Table name: students + +# Model class +# (in lib/student.rb) + +class Student + + # Replace the attributes by your own columns. + attr_accessor :id, :name, :cohort_name +end + +# The keyword attr_accessor is a special Ruby feature +# which allows us to set and get attributes on an object, +# here's an example: +# +# student = Student.new +# student.name = 'Jo' +# student.name +``` + +*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 + +Your Repository class will need to implement methods for each "read" or "write" operation you'd like to run against the database. + +Using comments, define the method signatures (arguments and return value) and what they do - write up the SQL queries that will be used by each method. + +```ruby +# EXAMPLE +# Table name: students + +# Repository class +# (in lib/student_repository.rb) + +class StudentRepository + + # Selecting all records + # No arguments + def all + # Executes the SQL query: + # SELECT id, name, cohort_name FROM students; + + # Returns an array of Student objects. + end + + # Gets a single record by its ID + # One argument: the id (number) + def find(id) + # Executes the SQL query: + # SELECT id, name, cohort_name FROM students WHERE id = $1; + + # Returns a single Student object. + end + + # Add more methods below for each operation you'd like to implement. + + # def create(student) + # end + + # def update(student) + # end + + # def delete(student) + # end +end +``` + +## 6. Write Test Examples + +Write Ruby code that defines the expected behaviour of the Repository class, following your design from the table written in step 5. + +These examples will later be encoded as RSpec tests. + +```ruby +# EXAMPLES + +# 1 +# Get all students + +repo = StudentRepository.new + +students = repo.all + +students.length # => 2 + +students[0].id # => 1 +students[0].name # => 'David' +students[0].cohort_name # => 'April 2022' + +students[1].id # => 2 +students[1].name # => 'Anna' +students[1].cohort_name # => 'May 2022' + +# 2 +# Get a single student + +repo = StudentRepository.new + +student = repo.find(1) + +student.id # => 1 +student.name # => 'David' +student.cohort_name # => 'April 2022' + +# Add more examples for each method +``` + +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/student_repository_spec.rb + +def reset_students_table + seed_sql = File.read('spec/seeds_students.sql') + connection = PG.connect({ host: '127.0.0.1', dbname: 'students' }) + connection.exec(seed_sql) +end + +describe StudentRepository do + before(:each) do + reset_students_table + end + + # (your tests will go here). +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._ + + + +--- + +**How was this resource?** +[😫](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=😫) [😕](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=😕) [😐](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=😐) [🙂](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=🙂) [😀](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=😀) +Click an emoji to tell us. + + diff --git a/spec/items_repository_spec.rb b/spec/items_repository_spec.rb new file mode 100644 index 00000000..6e49437e --- /dev/null +++ b/spec/items_repository_spec.rb @@ -0,0 +1,16 @@ +require 'rspec' +require_relative '../item_repository' +require_relative '../database_connection' + + +RSpec.describe ItemRepository do + + def reset_item_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_item_table + end \ No newline at end of file diff --git a/spec/seeds_items.sql b/spec/seeds_items.sql new file mode 100644 index 00000000..50683e06 --- /dev/null +++ b/spec/seeds_items.sql @@ -0,0 +1,14 @@ +-- 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; -- 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 (item_name, unit_price, quantity) VALUES +('Apple', 0.50, 100), +('Orange', 0.60, 80); \ No newline at end of file diff --git a/spec/seeds_orders.sql b/spec/seeds_orders.sql new file mode 100644 index 00000000..fe177b98 --- /dev/null +++ b/spec/seeds_orders.sql @@ -0,0 +1,14 @@ +-- 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 orders RESTART IDENTITY; -- 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 orders (customer_name, item_id, date) VALUES +('John Smith', 1, '2023-04-01'), +('Jane Doe', 1, '2023-04-02'); \ No newline at end of file diff --git a/spec/shop_manager_table.sql b/spec/shop_manager_table.sql new file mode 100644 index 00000000..684a9da5 --- /dev/null +++ b/spec/shop_manager_table.sql @@ -0,0 +1,35 @@ +CREATE TABLE items ( + id SERIAL PRIMARY KEY, + item_name TEXT NOT NULL, + unit_price DECIMAL NOT NULL, + quantity INTEGER NOT NULL +); + +CREATE TABLE orders ( + id SERIAL PRIMARY KEY, + customer_name TEXT NOT NULL, + item_id INTEGER, + date DATE NOT NULL, + CONSTRAINT fk_item FOREIGN KEY (item_id) + REFERENCES items(id) + ON DELETE CASCADE +); + +-- Insert data into the items table +INSERT INTO items (item_name, unit_price, quantity) VALUES +('Apple', 0.50, 100), +('Orange', 0.60, 80), +('Banana', 0.40, 120), +('Grapes', 1.20, 50), +('Strawberry', 1.50, 60); + +-- Insert data into the orders table +INSERT INTO orders (customer_name, item_id, date) VALUES +('John Smith', 1, '2023-04-01'), +('Jane Doe', 1, '2023-04-02'), +('Bon Jovi', 2, '2023-04-02'), +('Bob Brown', 3, '2023-04-03'), +('Charlie Charles', 4, '2023-04-03'), +('David Dave', 5, '2023-04-04'), +('Eva Walle', 1, '2023-04-04'); + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 252747d8..854f55cb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,10 +1,15 @@ require 'simplecov' require 'simplecov-console' +require 'database_connection' + +# Make sure this connects to your test database +# (its name should end with '_test') +DatabaseConnection.connect('shop_manager_test') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ SimpleCov::Formatter::Console, # Want a nice code coverage website? Uncomment this next line! - # SimpleCov::Formatter::HTMLFormatter + SimpleCov::Formatter::HTMLFormatter ]) SimpleCov.start @@ -15,3 +20,5 @@ puts "\e[33mTry it now! Just run: rubocop\e[0m" end end + + diff --git a/two_table_design_recipe_template.md b/two_table_design_recipe_template.md new file mode 100644 index 00000000..96b19058 --- /dev/null +++ b/two_table_design_recipe_template.md @@ -0,0 +1,146 @@ +# Two Tables Design Recipe Template + +_Copy this recipe template to design and create two related database tables from a specification._ + +## 1. Extract nouns from the user stories or specification + +``` +# EXAMPLE USER STORY: +# (analyse only the relevant part - here the final line). + +As a music lover, +So I can organise my records, +I want to keep a list of albums' titles. + +As a music lover, +So I can organise my records, +I want to keep a list of albums' release years. + +As a music lover, +So I can organise my records, +I want to keep a list of artists' names. + +As a music lover, +So I can organise my records, +I want to know each album's artist. +``` + +``` +Nouns: + +album, title, release year, artist, name +``` + +## 2. Infer the Table Name and Columns + +Put the different nouns in this table. Replace the example with your own nouns. + +| Record | Properties | +| --------------------- | ------------------ | +| album | title, release year +| artist | name + +1. Name of the first table (always plural): `albums` + + Column names: `title`, `release_year` + +2. Name of the second table (always plural): `artists` + + 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: albums +id: SERIAL +title: text +release_year: int + +Table: artists +id: SERIAL +name: text +``` + +## 4. Decide on The Tables Relationship + +Most of the time, you'll be using a **one-to-many** relationship, and will need a **foreign key** on one of the two tables. + +To decide on which one, answer 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) + +You'll then be able to say that: + +1. **[A] has many [B]** +2. And on the other side, **[B] belongs to [A]** +3. In that case, the foreign key is in the table [B] + +Replace the relevant bits in this example with your own: + +``` +# EXAMPLE + +1. Can one artist have many albums? YES +2. Can one album have many artists? NO + +-> Therefore, +-> An artist HAS MANY albums +-> An album BELONGS TO an artist + +-> Therefore, the foreign key is on the albums table. +``` + +*If you can answer YES to the two questions, you'll probably have to implement a Many-to-Many relationship, which is more complex and needs a third table (called a join table).* + +## 4. Write the SQL. + +```sql +-- EXAMPLE +-- file: albums_table.sql + +-- Replace the table name, columm names and types. + +-- Create the table without the foreign key first. +CREATE TABLE artists ( + id SERIAL PRIMARY KEY, + name text, +); + +-- Then the table with the foreign key first. +CREATE TABLE albums ( + id SERIAL PRIMARY KEY, + title text, + release_year int, +-- The foreign key name is always {other_table_singular}_id + artist_id int, + constraint fk_artist foreign key(artist_id) + references artists(id) + on delete cascade +); + +``` + +## 5. Create the tables. + +```bash +psql -h 127.0.0.1 database_name < albums_table.sql +``` + + + +--- + +**How was this resource?** +[😫](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=😫) [😕](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=😕) [😐](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=😐) [🙂](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=🙂) [😀](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=😀) +Click an emoji to tell us. + + From 66c2eea1489c7e9ee0072f1a6b33169bee943e0c Mon Sep 17 00:00:00 2001 From: Quddus Rahman Date: Sun, 2 Apr 2023 17:51:46 +0100 Subject: [PATCH 2/5] completed rspec for item repo class --- lib/item.rb | 10 +++++ lib/item_repository.rb | 56 +++++++++++++++++++++++++ lib/order.rb | 3 ++ lib/order_repository.rb | 38 +++++++++++++++++ spec/items_repository_spec.rb | 79 ++++++++++++++++++++++++++++++++--- spec/order_repository_spec.rb | 48 +++++++++++++++++++++ spec/seeds_items.sql | 2 +- spec/spec_helper.rb | 2 +- 8 files changed, 231 insertions(+), 7 deletions(-) create mode 100644 lib/item.rb create mode 100644 lib/item_repository.rb create mode 100644 lib/order.rb create mode 100644 lib/order_repository.rb create mode 100644 spec/order_repository_spec.rb diff --git a/lib/item.rb b/lib/item.rb new file mode 100644 index 00000000..d7cafa31 --- /dev/null +++ b/lib/item.rb @@ -0,0 +1,10 @@ +class Item + attr_accessor :id, :item_name, :unit_price, :quantity + + def initialize(attributes = {}) + @id = attributes[:id] + @item_name = attributes[:item_name] + @unit_price = attributes[:unit_price] + @quantity = attributes[:quantity] + end +end diff --git a/lib/item_repository.rb b/lib/item_repository.rb new file mode 100644 index 00000000..34a94a49 --- /dev/null +++ b/lib/item_repository.rb @@ -0,0 +1,56 @@ +require_relative './item' + +class ItemRepository + def all + sql = 'SELECT * FROM items' + result_set = DatabaseConnection.exec_params(sql, []) + + items = [] + + result_set.each do |record| + item = Item.new + item.id = record['id'].to_i + item.item_name = record['item_name'] + item.unit_price = record['unit_price'].to_f + item.quantity = record['quantity'].to_i + + items << item + end + + return items + end + + def find(id) + sql = 'SELECT * FROM items WHERE id = $1;' + result = DatabaseConnection.exec_params(sql, [id]) + + return nil if result.ntuples.zero? + #returns the number of rows in the result set, and zero? + # is a method that returns true if the number is equal to zero. + + record = result.first + item = Item.new + item.id = record['id'].to_i + item.item_name = record['item_name'] + item.unit_price = record['unit_price'].to_f + item.quantity = record['quantity'].to_i + + item + end + + def create(item) + sql = 'INSERT INTO items (item_name, unit_price, quantity) VALUES ($1, $2, $3) RETURNING id;' + result = DatabaseConnection.exec_params(sql, [item.item_name, item.unit_price, item.quantity]) + item.id = result.first['id'].to_i + end + + def update(id, item) + sql = 'UPDATE items SET item_name = $1, unit_price = $2, quantity = $3 WHERE id = $4' + DatabaseConnection.exec_params(sql, [item.item_name, item.unit_price, item.quantity, id]) + end + + def delete(id) + sql = 'DELETE FROM items WHERE id = $1' + DatabaseConnection.exec_params(sql, [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..29bc6030 --- /dev/null +++ b/lib/order.rb @@ -0,0 +1,3 @@ +class Order + attr_accessor :id, :customer_name, :item_id, :date +end \ No newline at end of file diff --git a/lib/order_repository.rb b/lib/order_repository.rb new file mode 100644 index 00000000..7666e82e --- /dev/null +++ b/lib/order_repository.rb @@ -0,0 +1,38 @@ +require_relative './order' + +class OrderRepository + def all + sql = 'SELECT * FROM orders' + result_set = DatabaseConnection.exec_params(sql, []) + + orders = [] + + result_set.each do |record| + order = Order.new + order.id = record['id'].to_i + order.customer_name = record['customer_name'] + order.item_id = record['item_id'].to_i + order.date = record['date'] + + orders << order + end + + return orders + end + + def find(id) + # Implement method to find an order by id + end + + def create(order) + # Implement method to create a new order + end + + def update(id, order) + # Implement method to update an existing order + end + + def delete(id) + # Implement method to delete an order by id + end +end diff --git a/spec/items_repository_spec.rb b/spec/items_repository_spec.rb index 6e49437e..083031e1 100644 --- a/spec/items_repository_spec.rb +++ b/spec/items_repository_spec.rb @@ -1,6 +1,5 @@ -require 'rspec' -require_relative '../item_repository' -require_relative '../database_connection' +require 'item_repository' +require 'database_connection' RSpec.describe ItemRepository do @@ -11,6 +10,76 @@ def reset_item_table connection.exec(seed_sql) end - before(:each) do + around(:each) do |example| + # Reset the database before running the test reset_item_table - end \ No newline at end of file + + # Run the test + example.run + + # Reset the database again after the test has completed + reset_item_table + end + + describe '#all' do + it 'returns all items' do + items = ItemRepository.new.all + expect(items.length).to eq(2) + end + end + + describe '#find' do + it 'returns the item with the given id' do + item = ItemRepository.new.find(1) + expect(item).to be_a(Item) + expect(item.id).to eq(1) + expect(item.item_name).to eq('Apple') + end + + it 'returns nil if the item is not found' do + item = ItemRepository.new.find(999) + expect(item).to be_nil + end + end + + describe '#create' do + it 'creates a new item in the items table' do + new_item = Item.new(item_name: 'Banana', unit_price: 0.70, quantity: 50) + + item_repository = ItemRepository.new + item_repository.create(new_item) + + item = item_repository.find(new_item.id) + expect(item).not_to be_nil + expect(item.item_name).to eq('Banana') + expect(item.unit_price).to eq(0.70) + expect(item.quantity).to eq(50) + end + + describe '#update' do + it 'updates the item with the given id' do + item_repository = ItemRepository.new + updated_item = Item.new(id: 1, item_name: 'Green Apple', unit_price: 0.55, quantity: 120) + + item_repository.update(updated_item.id, updated_item) + updated_item_from_db = item_repository.find(updated_item.id) + + expect(updated_item_from_db.item_name).to eq(updated_item.item_name) + expect(updated_item_from_db.unit_price).to eq(updated_item.unit_price) + expect(updated_item_from_db.quantity).to eq(updated_item.quantity) + end + end + + describe '#delete' do + it 'deletes the item with the given id' do + item_repository = ItemRepository.new + item_id_to_delete = 1 + + item_repository.delete(item_id_to_delete) + deleted_item = item_repository.find(item_id_to_delete) + + expect(deleted_item).to be_nil + end + end + end +end \ No newline at end of file diff --git a/spec/order_repository_spec.rb b/spec/order_repository_spec.rb new file mode 100644 index 00000000..66797943 --- /dev/null +++ b/spec/order_repository_spec.rb @@ -0,0 +1,48 @@ +require 'order_repository' +require 'database_connection' + +RSpec.describe OrderRepository do + def reset_order_table + seed_sql = File.read('spec/seeds_orders.sql') + connection = PG.connect({ host: '127.0.0.1', dbname: 'shop_manager_test' }) + connection.exec(seed_sql) + end + + around(:each) do |example| + reset_order_table + example.run + reset_order_table + end + + describe '#all' do + it 'returns all orders' do + order_repository = OrderRepository.new + orders = order_repository.all + expect(orders.length).to eq(2) + end + end + + describe '#find' do + it 'finds an order by id' do + # Implement test for 'find' method + end + end + + describe '#create' do + it 'creates a new order' do + # Implement test for 'create' method + end + end + + describe '#update' do + it 'updates an existing order' do + # Implement test for 'update' method + end + end + + describe '#delete' do + it 'deletes an order by id' do + # Implement test for 'delete' method + end + end +end diff --git a/spec/seeds_items.sql b/spec/seeds_items.sql index 50683e06..3641c104 100644 --- a/spec/seeds_items.sql +++ b/spec/seeds_items.sql @@ -4,7 +4,7 @@ -- so we can start with a fresh state. -- (RESTART IDENTITY resets the primary key) -TRUNCATE TABLE items RESTART IDENTITY; -- replace with your own table name. +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. diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 854f55cb..d56b7957 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,6 @@ +require 'database_connection' require 'simplecov' require 'simplecov-console' -require 'database_connection' # Make sure this connects to your test database # (its name should end with '_test') From fcb675f1070a1308d37227f8305d75da06f1b75a Mon Sep 17 00:00:00 2001 From: Quddus Rahman Date: Sun, 2 Apr 2023 18:25:31 +0100 Subject: [PATCH 3/5] completed order repo tests --- lib/order.rb | 9 +++++++- lib/order_repository.rb | 42 ++++++++++++++++++++++++----------- spec/order_repository_spec.rb | 38 ++++++++++++++++++++++++++----- 3 files changed, 70 insertions(+), 19 deletions(-) diff --git a/lib/order.rb b/lib/order.rb index 29bc6030..239b7b35 100644 --- a/lib/order.rb +++ b/lib/order.rb @@ -1,3 +1,10 @@ class Order attr_accessor :id, :customer_name, :item_id, :date -end \ No newline at end of file + + def initialize(id: nil, customer_name:, item_id:, date:) + @id = id + @customer_name = customer_name + @item_id = item_id + @date = date + end +end diff --git a/lib/order_repository.rb b/lib/order_repository.rb index 7666e82e..70b0d724 100644 --- a/lib/order_repository.rb +++ b/lib/order_repository.rb @@ -4,35 +4,51 @@ class OrderRepository def all sql = 'SELECT * FROM orders' result_set = DatabaseConnection.exec_params(sql, []) - + orders = [] - + result_set.each do |record| - order = Order.new - order.id = record['id'].to_i - order.customer_name = record['customer_name'] - order.item_id = record['item_id'].to_i - order.date = record['date'] - + order = Order.new( + id: record['id'].to_i, + customer_name: record['customer_name'], + item_id: record['item_id'].to_i, + date: record['date'] + ) + orders << order end - + return orders end def find(id) - # Implement method to find an order by id + sql = 'SELECT * FROM orders WHERE id = $1' + result_set = DatabaseConnection.exec_params(sql, [id]) + + return nil if result_set.ntuples.zero? + + record = result_set.first + Order.new( + id: record['id'].to_i, + customer_name: record['customer_name'], + item_id: record['item_id'].to_i, + date: record['date'] + ) end def create(order) - # Implement method to create a new order + sql = 'INSERT INTO orders (customer_name, item_id, date) VALUES ($1, $2, $3) RETURNING id' + result = DatabaseConnection.exec_params(sql, [order.customer_name, order.item_id, order.date]) + order.id = result[0]['id'].to_i end def update(id, order) - # Implement method to update an existing order + sql = 'UPDATE orders SET customer_name = $1, item_id = $2, date = $3 WHERE id = $4' + DatabaseConnection.exec_params(sql, [order.customer_name, order.item_id, order.date, id]) end def delete(id) - # Implement method to delete an order by id + sql = 'DELETE FROM orders WHERE id = $1' + DatabaseConnection.exec_params(sql, [id]) end end diff --git a/spec/order_repository_spec.rb b/spec/order_repository_spec.rb index 66797943..a2fe3f74 100644 --- a/spec/order_repository_spec.rb +++ b/spec/order_repository_spec.rb @@ -24,25 +24,53 @@ def reset_order_table describe '#find' do it 'finds an order by id' do - # Implement test for 'find' method + order_repository = OrderRepository.new + order = order_repository.find(1) + + expect(order).not_to be_nil + expect(order.id).to eq(1) end end describe '#create' do it 'creates a new order' do - # Implement test for 'create' method + order_repository = OrderRepository.new + new_order = Order.new(customer_name: 'John Doe', item_id: 1, date: '2023-05-01') # Update this line + order_repository.create(new_order) + + expect(new_order.id).not_to be_nil + + orders = order_repository.all + expect(orders.length).to eq(3) end - end + end describe '#update' do it 'updates an existing order' do - # Implement test for 'update' method + order_repository = OrderRepository.new + order = order_repository.find(1) + order.customer_name = 'Jane Doe' + order.item_id = 2 + order.date = '2023-06-01' + + order_repository.update(order.id, order) + updated_order = order_repository.find(1) + + expect(updated_order.customer_name).to eq('Jane Doe') + expect(updated_order.item_id).to eq(2) + expect(updated_order.date).to eq('2023-06-01') end end describe '#delete' do it 'deletes an order by id' do - # Implement test for 'delete' method + order_repository = OrderRepository.new + order_repository.delete(1) + + expect(order_repository.find(1)).to be_nil + + orders = order_repository.all + expect(orders.length).to eq(1) end end end From 96dfe30c95c2e35a4a9669df11a7bf2a43705d7d Mon Sep 17 00:00:00 2001 From: Quddus Rahman Date: Mon, 3 Apr 2023 10:08:52 +0100 Subject: [PATCH 4/5] working on the shop manager class --- lib/shop_manager.rb | 14 +++++++++ shop_manager.rb | 3 ++ spec/shop_manager_spec.rb | 63 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 lib/shop_manager.rb create mode 100644 shop_manager.rb create mode 100644 spec/shop_manager_spec.rb diff --git a/lib/shop_manager.rb b/lib/shop_manager.rb new file mode 100644 index 00000000..31305d05 --- /dev/null +++ b/lib/shop_manager.rb @@ -0,0 +1,14 @@ +require_relative './item' +require_relative './order' + +class ShopManager + def initialize + @items = [] + @orders = [] + end + + def create_item(item_name, unit_price, quantity) + item = Item.new(item_name: item_name, unit_price: unit_price, quantity: quantity) + @items << item + end +end diff --git a/shop_manager.rb b/shop_manager.rb new file mode 100644 index 00000000..45df0b4b --- /dev/null +++ b/shop_manager.rb @@ -0,0 +1,3 @@ +require_relative 'database_connection' + +DatabaseConnection.connect('shop_manager') diff --git a/spec/shop_manager_spec.rb b/spec/shop_manager_spec.rb new file mode 100644 index 00000000..b405dff9 --- /dev/null +++ b/spec/shop_manager_spec.rb @@ -0,0 +1,63 @@ +require 'shop_manager' + +RSpec.describe ShopManager do + describe '#create_item' do + it 'creates a new item and adds it to the list of items' do + shop_manager = ShopManager.new + shop_manager.create_item('Item 1', 10.99, 5) + + expect(shop_manager.list_items).to eq("Name: Item 1 | Unit price: 10.99 | Quantity: 5\n") + end + end + + describe '#update_item_quantity' do + xit 'updates the quantity of an existing item' do + shop_manager = ShopManager.new + item = Item.new('Item 1', 10.99, 5) + shop_manager.create_item(item) + + shop_manager.update_item_quantity(item, 10) + + expect(shop_manager.list_items).to eq("Name: Item 1 | Unit price: 10.99 | Quantity: 10\n") + end + end + + describe '#create_order' do + xit 'creates a new order and adds it to the list of orders' do + shop_manager = ShopManager.new + item = Item.new('Item 1', 10.99, 5) + order = Order.new('John Doe', item, '01/01/2023') + + shop_manager.create_order(order) + + expect(shop_manager.list_orders).to eq("Customer name: John Doe | Item: Item 1 | Date: 01/01/2023\n") + end + end + + describe '#list_items' do + xit 'lists all the items in the shop' do + shop_manager = ShopManager.new + item1 = Item.new('Item 1', 10.99, 5) + item2 = Item.new('Item 2', 5.99, 10) + shop_manager.create_item(item1) + shop_manager.create_item(item2) + + expect(shop_manager.list_items).to eq("Name: Item 1 | Unit price: 10.99 | Quantity: 5\nName: Item 2 | Unit price: 5.99 | Quantity: 10\n") + end + end + + describe '#list_orders' do + xit 'lists all the orders in the shop' do + shop_manager = ShopManager.new + item = Item.new('Item 1', 10.99, 5) + order1 = Order.new('John Doe', item, '01/01/2023') + order2 = Order.new('Jane Doe', item, '01/02/2023') + shop_manager.create_order(order1) + shop_manager.create_order(order2) + + expect(shop_manager.list_orders).to eq("Customer name: John Doe | Item: Item 1 | Date: 01/01/2023\nCustomer name: Jane Doe | Item: Item 1 | Date: 01/02/2023\n") + end + end +end + + From ce0a759d10dd7cfd08deddd866cebf9ad7489c9a Mon Sep 17 00:00:00 2001 From: Quddus Rahman Date: Tue, 4 Apr 2023 10:29:09 +0100 Subject: [PATCH 5/5] amended seed file and rspec for order so it's combined --- diagram shop manager.excalidraw | 1061 +++++++++++++++++++++++++++++++ spec/order_repository_spec.rb | 2 +- spec/seeds_items.sql | 8 +- 3 files changed, 1068 insertions(+), 3 deletions(-) create mode 100644 diagram shop manager.excalidraw diff --git a/diagram shop manager.excalidraw b/diagram shop manager.excalidraw new file mode 100644 index 00000000..819a16e3 --- /dev/null +++ b/diagram shop manager.excalidraw @@ -0,0 +1,1061 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "rectangle", + "version": 587, + "versionNonce": 1906452384, + "isDeleted": false, + "id": "a3XG_n_AKnfOWiRpqzRlH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 974.73828125, + "y": 233.43359375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 191.22273882460945, + "height": 132.65358549429973, + "seed": 16963388, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "VUZlIGhkgRq6QZoBwN-_U", + "type": "arrow" + } + ], + "updated": 1680515790387, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 600, + "versionNonce": 1011307104, + "isDeleted": false, + "id": "pY3OUCMxBeMkn6Iex0mP0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 982.7950629174259, + "y": 257.2777486623818, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 175.99429321289062, + "height": 80.68071057124023, + "seed": 500786364, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1680515989050, + "link": null, + "locked": false, + "fontSize": 16.136142114248045, + "fontFamily": 1, + "text": "Items\n- item_name TEXT\n- unit_price DECIMAL\n- quantity INTEGER", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Items\n- item_name TEXT\n- unit_price DECIMAL\n- quantity INTEGER", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "version": 788, + "versionNonce": 25843296, + "isDeleted": false, + "id": "cZcdXerPzZlngsFqtGAVZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1361.5896820780702, + "y": 242.38411007899697, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 172.52750542192985, + "height": 128.46512204315994, + "seed": 493649084, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "VUZlIGhkgRq6QZoBwN-_U", + "type": "arrow" + } + ], + "updated": 1680515790387, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 586, + "versionNonce": 1484201568, + "isDeleted": false, + "id": "cyCiWoU350EbPlF81HGEy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1380.9952545537772, + "y": 265.79966699267254, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 52.34181213378906, + "height": 20.17017764281006, + "seed": 784944060, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1680516006585, + "link": null, + "locked": false, + "fontSize": 16.13614211424805, + "fontFamily": 1, + "text": "Orders", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Orders", + "lineHeight": 1.25 + }, + { + "type": "text", + "version": 648, + "versionNonce": 2051588000, + "isDeleted": false, + "id": "nO1zYoK94eFrAbvmSHfwv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1374.1061864737658, + "y": 285.33813890689237, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 135.37899780273438, + "height": 60.510532928430166, + "seed": 1328155268, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "WbSq3itXP5KsHMXGAV2LX", + "type": "arrow" + }, + { + "id": "26vg19NtDMIaQjY5ILl1E", + "type": "arrow" + } + ], + "updated": 1680516000029, + "link": null, + "locked": false, + "fontSize": 16.136142114248045, + "fontFamily": 1, + "text": "- customer_name\n- item_id IN\n- posts_id", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "- customer_name\n- item_id IN\n- posts_id", + "lineHeight": 1.25 + }, + { + "type": "arrow", + "version": 1757, + "versionNonce": 1981191072, + "isDeleted": false, + "id": "VUZlIGhkgRq6QZoBwN-_U", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1166.9033455613594, + "y": 307.0566473753481, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 190.89497343791376, + "height": 1.6959209755736488, + "seed": 901225404, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1680515791999, + "link": null, + "locked": false, + "startBinding": { + "elementId": "a3XG_n_AKnfOWiRpqzRlH", + "focus": 0.12138298777853822, + "gap": 1 + }, + "endBinding": { + "elementId": "cZcdXerPzZlngsFqtGAVZ", + "focus": 0.03163127447497967, + "gap": 3.7913630787969623 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 190.89497343791376, + -1.6959209755736488 + ] + ] + }, + { + "type": "arrow", + "version": 665, + "versionNonce": 995920480, + "isDeleted": false, + "id": "WbSq3itXP5KsHMXGAV2LX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1256.2698388800347, + "y": 306.2762993528545, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 113.00550105140064, + "height": 35.05513842515254, + "seed": 1455443388, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1680516000030, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "nO1zYoK94eFrAbvmSHfwv", + "focus": 0.9054299499826416, + "gap": 9.777365993959847 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 46.86099552670981, + -35.05513842515254 + ], + [ + 113.00550105140064, + -29.438737336050053 + ] + ] + }, + { + "type": "arrow", + "version": 560, + "versionNonce": 508545952, + "isDeleted": false, + "id": "26vg19NtDMIaQjY5ILl1E", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0.021196598468603334, + "x": 1260.7482378057887, + "y": 308.48401290297073, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 103.42768272778153, + "height": 38.13295040004937, + "seed": 2109534084, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1680516000030, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "nO1zYoK94eFrAbvmSHfwv", + "focus": -1.086343660928473, + "gap": 10.515770584986512 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 41.18813306466948, + 29.14590669386054 + ], + [ + 103.42768272778153, + 38.13295040004937 + ] + ] + }, + { + "id": "yCQmpH06hBaHV4UYrTCd-", + "type": "rectangle", + "x": 217.04966517857133, + "y": 217.94029017857144, + "width": 238.72265625, + "height": 156.95703125, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 3 + }, + "seed": 1374969440, + "version": 438, + "versionNonce": 1000643488, + "isDeleted": false, + "boundElements": [ + { + "id": "jJ0hnhCssZXS1hIKe1JDF", + "type": "arrow" + }, + { + "id": "khjEAY0SgBeKiTL5itUHx", + "type": "arrow" + } + ], + "updated": 1680515954787, + "link": null, + "locked": false + }, + { + "id": "HiXWY1saGp_kX-TCESVfx", + "type": "text", + "x": 265.6110491071429, + "y": 282.99720982142856, + "width": 133.87989807128906, + "height": 25, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 546253728, + "version": 441, + "versionNonce": 1113563744, + "isDeleted": false, + "boundElements": null, + "updated": 1680515954787, + "link": null, + "locked": false, + "text": "Shop Manager", + "fontSize": 20, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Shop Manager", + "lineHeight": 1.25 + }, + { + "id": "XHhGTu2D8pnI7zqECtYfg", + "type": "rectangle", + "x": 939.92578125, + "y": 177.73046875, + "width": 632.37109375, + "height": 218.57421875, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 3 + }, + "seed": 390458976, + "version": 443, + "versionNonce": 1931350624, + "isDeleted": false, + "boundElements": [ + { + "id": "D16cYHNKSaku4SjVb8vXG", + "type": "arrow" + }, + { + "id": "Sj0Qz6WaxLELhTZ3gC5K0", + "type": "arrow" + } + ], + "updated": 1680515841945, + "link": null, + "locked": false + }, + { + "id": "COEqrpKz3D9PDc-4Q-bU2", + "type": "text", + "x": 1029.046875, + "y": 190.15234375, + "width": 446.47967529296875, + "height": 25, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 823300000, + "version": 372, + "versionNonce": 553357216, + "isDeleted": false, + "boundElements": [], + "updated": 1680515809302, + "link": null, + "locked": false, + "text": "shop_manager + test PostgreSQL Database", + "fontSize": 20, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "shop_manager + test PostgreSQL Database", + "lineHeight": 1.25 + }, + { + "id": "jJ0hnhCssZXS1hIKe1JDF", + "type": "arrow", + "x": 215.60293530008244, + "y": 297.87565229596555, + "width": 115.97531054499518, + "height": 0.32471256979943064, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 2 + }, + "seed": 65451616, + "version": 1094, + "versionNonce": 896960416, + "isDeleted": false, + "boundElements": null, + "updated": 1680515955459, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -115.97531054499518, + -0.32471256979943064 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "yCQmpH06hBaHV4UYrTCd-", + "focus": -0.02277665653752902, + "gap": 1.4467298784888953 + }, + "endBinding": { + "elementId": "MWHsXI0BFj6tP6uDu_d8c", + "focus": 0.3020274322957934, + "gap": 9.21095518198456 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "JMRU74_ig_aHRZJC900zr", + "type": "rectangle", + "x": -155.64174107142856, + "y": 244.9001116071429, + "width": 251.265625, + "height": 104.87109374999999, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 3 + }, + "seed": 1349184416, + "version": 423, + "versionNonce": 1862030944, + "isDeleted": false, + "boundElements": [ + { + "id": "jJ0hnhCssZXS1hIKe1JDF", + "type": "arrow" + } + ], + "updated": 1680515954788, + "link": null, + "locked": false + }, + { + "id": "MWHsXI0BFj6tP6uDu_d8c", + "type": "text", + "x": -148.58314732142856, + "y": 280.8141741071429, + "width": 238.99981689453125, + "height": 25, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 365500320, + "version": 363, + "versionNonce": 1315094432, + "isDeleted": false, + "boundElements": [ + { + "id": "jJ0hnhCssZXS1hIKe1JDF", + "type": "arrow" + } + ], + "updated": 1680515954788, + "link": null, + "locked": false, + "text": "Shop Manager Interface", + "fontSize": 20, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Shop Manager Interface", + "lineHeight": 1.25 + }, + { + "id": "Sj0Qz6WaxLELhTZ3gC5K0", + "type": "arrow", + "x": 832.9068080357143, + "y": 358.06026785714266, + "width": 105.45982142857156, + "height": 0.4581473214286689, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 2 + }, + "seed": 1721039776, + "version": 606, + "versionNonce": 103951968, + "isDeleted": false, + "boundElements": null, + "updated": 1680515967455, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 105.45982142857156, + 0.4581473214286689 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "elementId": "XHhGTu2D8pnI7zqECtYfg", + "focus": -0.6586006063240402, + "gap": 1.559151785714107 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "D16cYHNKSaku4SjVb8vXG", + "type": "arrow", + "x": 938.9832589285716, + "y": 212.90513392857133, + "width": 101.16238839285711, + "height": 1.0982142857142776, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 2 + }, + "seed": 2092275296, + "version": 650, + "versionNonce": 729597856, + "isDeleted": false, + "boundElements": null, + "updated": 1680515970240, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -101.16238839285711, + -1.0982142857142776 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "XHhGTu2D8pnI7zqECtYfg", + "focus": 0.6269514174267795, + "gap": 1 + }, + "endBinding": { + "elementId": "mRysVk59G6axNdaF1RyIu", + "focus": 0.5435078467019486, + "gap": 2.142299107143117 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "0bec-8ZeUb411ZrHTaF9J", + "type": "text", + "x": 856.7327008928572, + "y": 256.7438616071428, + "width": 71.17991638183594, + "height": 50, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 1019949664, + "version": 348, + "versionNonce": 1962229344, + "isDeleted": false, + "boundElements": [], + "updated": 1680515837786, + "link": null, + "locked": false, + "text": "SQL\nQueries", + "fontSize": 20, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "SQL\nQueries", + "lineHeight": 1.25 + }, + { + "id": "mRysVk59G6axNdaF1RyIu", + "type": "rectangle", + "x": 606.5212053571429, + "y": 96.60714285714295, + "width": 229.15736607142844, + "height": 146.75223214285705, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 3 + }, + "seed": 243928672, + "version": 153, + "versionNonce": 1082430368, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "0PtG5W0oOsR8n5F0IjjS-" + }, + { + "id": "fALYkWCfri2GFZb00wEVT", + "type": "arrow" + }, + { + "id": "D16cYHNKSaku4SjVb8vXG", + "type": "arrow" + } + ], + "updated": 1680515955463, + "link": null, + "locked": false + }, + { + "id": "0PtG5W0oOsR8n5F0IjjS-", + "type": "text", + "x": 647.6799665178571, + "y": 157.48325892857147, + "width": 146.83984375, + "height": 25, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 416518752, + "version": 93, + "versionNonce": 1507999328, + "isDeleted": false, + "boundElements": null, + "updated": 1680515954788, + "link": null, + "locked": false, + "text": "ItemRepository", + "fontSize": 20, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "mRysVk59G6axNdaF1RyIu", + "originalText": "ItemRepository", + "lineHeight": 1.25 + }, + { + "type": "rectangle", + "version": 177, + "versionNonce": 666033056, + "isDeleted": false, + "id": "BIRfJgjd_JKxKnhSobwWw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 607.3219866071427, + "y": 342.3828125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 229.15736607142844, + "height": 146.75223214285705, + "seed": 1134057376, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "rf5QbELId2r1G9w4SWxtt" + } + ], + "updated": 1680515967455, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 126, + "versionNonce": 1453548448, + "isDeleted": false, + "id": "rf5QbELId2r1G9w4SWxtt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 644.3607526506694, + "y": 403.25892857142856, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 155.079833984375, + "height": 25, + "seed": 577925728, + "groupIds": [], + "roundness": null, + "boundElements": null, + "updated": 1680515954788, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "OrderRepository", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "BIRfJgjd_JKxKnhSobwWw", + "originalText": "OrderRepository", + "lineHeight": 1.25 + }, + { + "id": "Y8K_tqLd9Kae5F7FyIl_A", + "type": "arrow", + "x": 428.32924107142856, + "y": 218.71093750000006, + "width": 181.37276785714278, + "height": 79.35825892857144, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 2 + }, + "seed": 1220450208, + "version": 117, + "versionNonce": 1651385952, + "isDeleted": false, + "boundElements": null, + "updated": 1680515954788, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 181.37276785714278, + -79.35825892857144 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "fALYkWCfri2GFZb00wEVT", + "type": "arrow", + "x": 604.6573660714284, + "y": 188.15848214285717, + "width": 150.53013392857133, + "height": 67.3660714285715, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 2 + }, + "seed": 801377888, + "version": 232, + "versionNonce": 350890592, + "isDeleted": false, + "boundElements": null, + "updated": 1680515955463, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -150.53013392857133, + 67.3660714285715 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "mRysVk59G6axNdaF1RyIu", + "focus": 0.2722419362177005, + "gap": 1.8638392857144481 + }, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "khjEAY0SgBeKiTL5itUHx", + "type": "arrow", + "x": 433.8537946428571, + "y": 378.06919642857144, + "width": 174.4140625, + "height": 75.10044642857144, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 2 + }, + "seed": 1432997792, + "version": 226, + "versionNonce": 636234656, + "isDeleted": false, + "boundElements": null, + "updated": 1680515955463, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 174.4140625, + 75.10044642857144 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "yCQmpH06hBaHV4UYrTCd-", + "focus": 0.3056253572386316, + "gap": 3.171875 + }, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "b-uyhbczfVp4aF1XW0zaP", + "type": "arrow", + "x": 608.2957589285713, + "y": 408.6383928571429, + "width": 158.046875, + "height": 71.43415178571433, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 2 + }, + "seed": 1819145120, + "version": 94, + "versionNonce": 1050082208, + "isDeleted": false, + "boundElements": null, + "updated": 1680515954788, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -158.046875, + -71.43415178571433 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/spec/order_repository_spec.rb b/spec/order_repository_spec.rb index a2fe3f74..2b38a5e4 100644 --- a/spec/order_repository_spec.rb +++ b/spec/order_repository_spec.rb @@ -3,7 +3,7 @@ RSpec.describe OrderRepository do def reset_order_table - seed_sql = File.read('spec/seeds_orders.sql') + seed_sql = File.read('spec/seeds_orders_items.sql') connection = PG.connect({ host: '127.0.0.1', dbname: 'shop_manager_test' }) connection.exec(seed_sql) end diff --git a/spec/seeds_items.sql b/spec/seeds_items.sql index 3641c104..9068bef7 100644 --- a/spec/seeds_items.sql +++ b/spec/seeds_items.sql @@ -4,11 +4,15 @@ -- 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. +TRUNCATE TABLE items, orders 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 (item_name, unit_price, quantity) VALUES ('Apple', 0.50, 100), -('Orange', 0.60, 80); \ No newline at end of file +('Orange', 0.60, 80); + +INSERT INTO orders (customer_name, item_id, date) VALUES +('John Smith', 1, '2023-04-01'), +('Jane Doe', 1, '2023-04-02'); \ No newline at end of file