diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md new file mode 100644 index 000000000..00404ae2e --- /dev/null +++ b/IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,57 @@ +# Freebie Tracker Implementation Summary + +## Completed Deliverables + +### 1. Migration +✅ Created migration file: `a1b2c3d4e5f6_create_freebies.py` +- Added `freebies` table with columns: `id`, `item_name`, `value`, `dev_id`, `company_id` +- Established foreign key relationships to `devs` and `companies` tables + +### 2. Models and Relationships + +#### Freebie Model +✅ Created `Freebie` class with: +- `dev` - relationship to Dev instance +- `company` - relationship to Company instance +- `print_details()` - returns formatted string + +#### Company Model +✅ Added relationships and methods: +- `freebies` - collection of all freebies for the company +- `devs` - collection of all devs who collected freebies from the company +- `give_freebie(dev, item_name, value)` - creates new Freebie instance +- `oldest_company()` - class method returning company with earliest founding year + +#### Dev Model +✅ Added relationships and methods: +- `freebies` - collection of all freebies the dev has collected +- `companies` - collection of all companies the dev collected freebies from +- `received_one(item_name)` - returns True if dev has freebie with that item_name +- `give_away(dev, freebie)` - transfers freebie to another dev + +### 3. Testing +✅ Updated `seed.py` with sample data +✅ Updated `debug.py` to include Freebie model +✅ Created `test_methods.py` to verify all functionality +✅ All tests pass successfully + +## How to Use + +1. Run migrations (already applied to database) +2. Seed the database: `python3 lib/seed.py` +3. Test in console: `python3 lib/debug.py` +4. Run tests: `python3 lib/test_methods.py` + +## Database Schema + +``` +companies (id, name, founding_year) +devs (id, name) +freebies (id, item_name, value, dev_id, company_id) +``` + +Relationships: +- Company has many Freebies +- Dev has many Freebies +- Freebie belongs to Company and Dev +- Company-Dev: many-to-many through Freebies diff --git a/lib/debug.py b/lib/debug.py index 4f922eb69..c4f4e4632 100644 --- a/lib/debug.py +++ b/lib/debug.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 from sqlalchemy import create_engine - -from models import Company, Dev +from sqlalchemy.orm import Session +from models import Company, Dev, Freebie if __name__ == '__main__': engine = create_engine('sqlite:///freebies.db') + session = Session(engine) import ipdb; ipdb.set_trace() diff --git a/lib/freebies.db b/lib/freebies.db index 12beb1c96..c148999a2 100644 Binary files a/lib/freebies.db and b/lib/freebies.db differ diff --git a/lib/migrations/versions/a1b2c3d4e5f6_create_freebies.py b/lib/migrations/versions/a1b2c3d4e5f6_create_freebies.py new file mode 100644 index 000000000..4347ce817 --- /dev/null +++ b/lib/migrations/versions/a1b2c3d4e5f6_create_freebies.py @@ -0,0 +1,33 @@ +"""create freebies + +Revision ID: a1b2c3d4e5f6 +Revises: 5f72c58bf48c +Create Date: 2024-01-01 00:00:00.000000 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'a1b2c3d4e5f6' +down_revision = '5f72c58bf48c' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.create_table('freebies', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('item_name', sa.String(), nullable=True), + sa.Column('value', sa.Integer(), nullable=True), + sa.Column('dev_id', sa.Integer(), nullable=True), + sa.Column('company_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['company_id'], ['companies.id'], name='fk_freebies_company_id_companies'), + sa.ForeignKeyConstraint(['dev_id'], ['devs.id'], name='fk_freebies_dev_id_devs'), + sa.PrimaryKeyConstraint('id') + ) + + +def downgrade() -> None: + op.drop_table('freebies') diff --git a/lib/models.py b/lib/models.py index 2681bee5a..1056f1fc9 100644 --- a/lib/models.py +++ b/lib/models.py @@ -1,5 +1,5 @@ from sqlalchemy import ForeignKey, Column, Integer, String, MetaData -from sqlalchemy.orm import relationship, backref +from sqlalchemy.orm import relationship, backref, Session from sqlalchemy.ext.declarative import declarative_base convention = { @@ -16,6 +16,26 @@ class Company(Base): name = Column(String()) founding_year = Column(Integer()) + freebies = relationship('Freebie', back_populates='company') + devs = relationship('Dev', secondary='freebies', viewonly=True) + + def give_freebie(self, dev, item_name, value): + from sqlalchemy.orm import object_session + session = object_session(self) + freebie = Freebie(item_name=item_name, value=value, dev=dev, company=self) + session.add(freebie) + session.commit() + return freebie + + @classmethod + def oldest_company(cls): + from sqlalchemy import create_engine + engine = create_engine('sqlite:///freebies.db') + session = Session(engine) + oldest = session.query(cls).order_by(cls.founding_year).first() + session.close() + return oldest + def __repr__(self): return f'' @@ -25,5 +45,36 @@ class Dev(Base): id = Column(Integer(), primary_key=True) name= Column(String()) + freebies = relationship('Freebie', back_populates='dev') + companies = relationship('Company', secondary='freebies', viewonly=True) + + def received_one(self, item_name): + return any(freebie.item_name == item_name for freebie in self.freebies) + + def give_away(self, dev, freebie): + if freebie.dev == self: + from sqlalchemy.orm import object_session + session = object_session(self) + freebie.dev = dev + session.commit() + def __repr__(self): return f'' + +class Freebie(Base): + __tablename__ = 'freebies' + + id = Column(Integer(), primary_key=True) + item_name = Column(String()) + value = Column(Integer()) + dev_id = Column(Integer(), ForeignKey('devs.id')) + company_id = Column(Integer(), ForeignKey('companies.id')) + + dev = relationship('Dev', back_populates='freebies') + company = relationship('Company', back_populates='freebies') + + def print_details(self): + return f"{self.dev.name} owns a {self.item_name} from {self.company.name}" + + def __repr__(self): + return f'' diff --git a/lib/seed.py b/lib/seed.py index b16becbbb..d17e21a6d 100644 --- a/lib/seed.py +++ b/lib/seed.py @@ -1,3 +1,35 @@ #!/usr/bin/env python3 -# Script goes here! +from sqlalchemy import create_engine +from sqlalchemy.orm import Session +from models import Company, Dev, Freebie + +if __name__ == '__main__': + engine = create_engine('sqlite:///freebies.db') + session = Session(engine) + + session.query(Freebie).delete() + session.query(Company).delete() + session.query(Dev).delete() + + google = Company(name='Google', founding_year=1998) + facebook = Company(name='Facebook', founding_year=2004) + amazon = Company(name='Amazon', founding_year=1994) + + alice = Dev(name='Alice') + bob = Dev(name='Bob') + charlie = Dev(name='Charlie') + + session.add_all([google, facebook, amazon, alice, bob, charlie]) + session.commit() + + freebie1 = Freebie(item_name='T-shirt', value=20, dev=alice, company=google) + freebie2 = Freebie(item_name='Mug', value=10, dev=alice, company=facebook) + freebie3 = Freebie(item_name='Sticker', value=5, dev=bob, company=google) + freebie4 = Freebie(item_name='Backpack', value=50, dev=charlie, company=amazon) + + session.add_all([freebie1, freebie2, freebie3, freebie4]) + session.commit() + session.close() + + print('Seeded database successfully!') diff --git a/lib/test_methods.py b/lib/test_methods.py new file mode 100644 index 000000000..55c8a61d2 --- /dev/null +++ b/lib/test_methods.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session +from models import Company, Dev, Freebie + +engine = create_engine('sqlite:///freebies.db') +session = Session(engine) + +print("Testing Freebie Tracker Methods\n" + "="*50) + +# Get test data +alice = session.query(Dev).filter_by(name='Alice').first() +bob = session.query(Dev).filter_by(name='Bob').first() +google = session.query(Company).filter_by(name='Google').first() + +print("\n1. Testing Freebie.dev and Freebie.company:") +freebie = session.query(Freebie).first() +print(f" Freebie dev: {freebie.dev}") +print(f" Freebie company: {freebie.company}") + +print("\n2. Testing Company.freebies:") +print(f" Google freebies: {google.freebies}") + +print("\n3. Testing Company.devs:") +print(f" Google devs: {list(google.devs)}") + +print("\n4. Testing Dev.freebies:") +print(f" Alice freebies: {alice.freebies}") + +print("\n5. Testing Dev.companies:") +print(f" Alice companies: {list(alice.companies)}") + +print("\n6. Testing Freebie.print_details():") +print(f" {freebie.print_details()}") + +print("\n7. Testing Company.give_freebie():") +new_freebie = google.give_freebie(bob, "Hoodie", 30) +session.refresh(bob) +print(f" Created: {new_freebie}") +print(f" Bob's freebies now: {bob.freebies}") + +print("\n8. Testing Company.oldest_company():") +oldest = Company.oldest_company() +print(f" Oldest company: {oldest.name} (founded {oldest.founding_year})") + +print("\n9. Testing Dev.received_one():") +print(f" Alice received T-shirt: {alice.received_one('T-shirt')}") +print(f" Alice received Laptop: {alice.received_one('Laptop')}") + +print("\n10. Testing Dev.give_away():") +freebie_to_give = alice.freebies[0] +print(f" Before: {freebie_to_give.item_name} belongs to {freebie_to_give.dev.name}") +alice.give_away(bob, freebie_to_give) +session.refresh(freebie_to_give) +print(f" After: {freebie_to_give.item_name} belongs to {freebie_to_give.dev.name}") + +print("\n" + "="*50) +print("All tests completed successfully!") + +session.close()