diff --git a/lib/.tables b/lib/.tables new file mode 100644 index 000000000..e69de29bb diff --git a/lib/__pycache__/database.cpython-38.pyc b/lib/__pycache__/database.cpython-38.pyc new file mode 100644 index 000000000..adaedb143 Binary files /dev/null and b/lib/__pycache__/database.cpython-38.pyc differ diff --git a/lib/__pycache__/models.cpython-312.pyc b/lib/__pycache__/models.cpython-312.pyc new file mode 100644 index 000000000..408648a93 Binary files /dev/null and b/lib/__pycache__/models.cpython-312.pyc differ diff --git a/lib/__pycache__/models.cpython-38.pyc b/lib/__pycache__/models.cpython-38.pyc new file mode 100644 index 000000000..69ed5da63 Binary files /dev/null and b/lib/__pycache__/models.cpython-38.pyc differ diff --git a/lib/database.py b/lib/database.py new file mode 100644 index 000000000..181385972 --- /dev/null +++ b/lib/database.py @@ -0,0 +1,22 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.declarative import declarative_base + +DATABASE_URL = "sqlite:///freebies.db" + +engine = create_engine(DATABASE_URL, echo=True) + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +session = SessionLocal() + +Base = declarative_base() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + + diff --git a/lib/debug.py b/lib/debug.py index 4f922eb69..634568b54 100644 --- a/lib/debug.py +++ b/lib/debug.py @@ -1,9 +1,17 @@ -#!/usr/bin/env python3 - from sqlalchemy import create_engine - +from sqlalchemy.orm import sessionmaker from models import Company, Dev if __name__ == '__main__': - engine = create_engine('sqlite:///freebies.db') - import ipdb; ipdb.set_trace() + engine = create_engine('sqlite:///freebies.db') + Session = sessionmaker(bind=engine) + session = Session() + +import ipdb; ipdb.set_trace() + +companies = session.query(Company).all() +print(companies) + + #!/usr/bin/env python3 + + diff --git a/lib/freebies.db b/lib/freebies.db index 12beb1c96..34b41acf4 100644 Binary files a/lib/freebies.db and b/lib/freebies.db differ diff --git a/lib/migrations/README b/lib/migrations/README index 98e4f9c44..b5c5e93de 100644 --- a/lib/migrations/README +++ b/lib/migrations/README @@ -1 +1,126 @@ -Generic single-database configuration. \ No newline at end of file +A SQLAlchemy-based application that models companies giving out freebies to developers. This project demonstrates relational modeling, CRUD operations, database seeding, migrations, and querying with SQLAlchemy. + +## Project Structure + +freebie-tracker/ +│ +├── lib/ +│ ├── alembic/ # Alembic configuration +│ ├── migrations/ # Alembic migration scripts +│ ├── alembic.ini # Alembic settings file +│ ├── models.py # SQLAlchemy models: Company, Dev, Freebie +│ ├── seed.py # Script to populate database with sample data +│ ├── debug.py # Interactive debug script using ipdb +│ ├── query_data.py # Custom queries and data fetch logic +│ ├── database.py # Database setup and session configuration +│ ├── freebies.db # SQLite database (main data store) + + +## Models Overview + +### Company + +- Columns: `id`, `name`, `founding_year` +- Relationships: has many `freebies` + +### Dev + +- Columns: `id`, `name` +- Relationships: has many `freebies` + +### Freebie + +- Columns: `id`, `item_name`, `value`, `company_id`, `dev_id` +- Relationships: belongs to `company`, belongs to `dev` + +## Setup Instructions + +1. **Clone the repository** + +```bash +git clone https://github.com/your-username/freebie-tracker.git +cd freebie-tracker/lib +(Optional) Create a virtual environment + +bash +Always show details + +Copy code +python3 -m venv venv +source venv/bin/activate +Install dependencies + +bash +Always show details + +Copy code +pip install -r ../requirements.txt +Run database migrations + +bash +Always show details + +Copy code +alembic upgrade head +Seed the database with sample data + +bash +Always show details + +Copy code +python seed.py +Run debug console + +bash +Always show details + +Copy code +python debug.py +Features +SQLAlchemy ORM relationships + +Alembic migrations + +Data seeding with clear logs + +Custom querying in query_data.py + +Centralized session handling in database.py + +Debugging with ipdb + +Sample Output +Running seed.py will clear the database and insert: + +Companies: Devs Square, Legicomp, tarakideal + +Developers: crocs, Susan, Santos + +Freebies: Cap, Pen, Mug, Water Bottle + +Example debug output: + +python +Always show details + +Copy code +[, None: - pass - - -def downgrade() -> None: - pass diff --git a/lib/migrations/versions/__pycache__/5f72c58bf48c_create_companies_devs.cpython-312.pyc b/lib/migrations/versions/__pycache__/5f72c58bf48c_create_companies_devs.cpython-312.pyc new file mode 100644 index 000000000..32b98b65d Binary files /dev/null and b/lib/migrations/versions/__pycache__/5f72c58bf48c_create_companies_devs.cpython-312.pyc differ diff --git a/lib/migrations/versions/__pycache__/5f72c58bf48c_create_companies_devs.cpython-38.pyc b/lib/migrations/versions/__pycache__/5f72c58bf48c_create_companies_devs.cpython-38.pyc new file mode 100644 index 000000000..ce49fc8b6 Binary files /dev/null and b/lib/migrations/versions/__pycache__/5f72c58bf48c_create_companies_devs.cpython-38.pyc differ diff --git a/lib/migrations/versions/__pycache__/7a71dbf71c64_create_db.cpython-312.pyc b/lib/migrations/versions/__pycache__/7a71dbf71c64_create_db.cpython-312.pyc new file mode 100644 index 000000000..c8e080d34 Binary files /dev/null and b/lib/migrations/versions/__pycache__/7a71dbf71c64_create_db.cpython-312.pyc differ diff --git a/lib/migrations/versions/__pycache__/7a71dbf71c64_create_db.cpython-38.pyc b/lib/migrations/versions/__pycache__/7a71dbf71c64_create_db.cpython-38.pyc new file mode 100644 index 000000000..bf88b15bc Binary files /dev/null and b/lib/migrations/versions/__pycache__/7a71dbf71c64_create_db.cpython-38.pyc differ diff --git a/lib/migrations/versions/__pycache__/c9c6b699e446_create_freebies_table.cpython-312.pyc b/lib/migrations/versions/__pycache__/c9c6b699e446_create_freebies_table.cpython-312.pyc new file mode 100644 index 000000000..72895b64f Binary files /dev/null and b/lib/migrations/versions/__pycache__/c9c6b699e446_create_freebies_table.cpython-312.pyc differ diff --git a/lib/migrations/versions/__pycache__/c9c6b699e446_create_freebies_table.cpython-38.pyc b/lib/migrations/versions/__pycache__/c9c6b699e446_create_freebies_table.cpython-38.pyc new file mode 100644 index 000000000..89feab1d4 Binary files /dev/null and b/lib/migrations/versions/__pycache__/c9c6b699e446_create_freebies_table.cpython-38.pyc differ diff --git a/lib/migrations/versions/__pycache__/d0fde98209cf_initial_migration_with_all_tables.cpython-38.pyc b/lib/migrations/versions/__pycache__/d0fde98209cf_initial_migration_with_all_tables.cpython-38.pyc new file mode 100644 index 000000000..8424aba6f Binary files /dev/null and b/lib/migrations/versions/__pycache__/d0fde98209cf_initial_migration_with_all_tables.cpython-38.pyc differ diff --git a/lib/migrations/versions/5f72c58bf48c_create_companies_devs.py b/lib/migrations/versions/d0fde98209cf_initial_migration_with_all_tables.py similarity index 56% rename from lib/migrations/versions/5f72c58bf48c_create_companies_devs.py rename to lib/migrations/versions/d0fde98209cf_initial_migration_with_all_tables.py index c191bb2f9..ec7babb17 100644 --- a/lib/migrations/versions/5f72c58bf48c_create_companies_devs.py +++ b/lib/migrations/versions/d0fde98209cf_initial_migration_with_all_tables.py @@ -1,8 +1,8 @@ -"""create companies, devs +"""Initial migration with all tables -Revision ID: 5f72c58bf48c -Revises: 7a71dbf71c64 -Create Date: 2023-03-15 15:06:20.944586 +Revision ID: d0fde98209cf +Revises: +Create Date: 2025-05-26 17:10:12.764692 """ from alembic import op @@ -10,8 +10,8 @@ # revision identifiers, used by Alembic. -revision = '5f72c58bf48c' -down_revision = '7a71dbf71c64' +revision = 'd0fde98209cf' +down_revision = None branch_labels = None depends_on = None @@ -29,11 +29,22 @@ def upgrade() -> None: sa.Column('name', sa.String(), nullable=True), sa.PrimaryKeyConstraint('id') ) + 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'], ), + sa.ForeignKeyConstraint(['dev_id'], ['devs.id'], ), + sa.PrimaryKeyConstraint('id') + ) # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('freebies') op.drop_table('devs') op.drop_table('companies') # ### end Alembic commands ### diff --git a/lib/models.py b/lib/models.py index 2681bee5a..9b06689b8 100644 --- a/lib/models.py +++ b/lib/models.py @@ -1,29 +1,56 @@ -from sqlalchemy import ForeignKey, Column, Integer, String, MetaData -from sqlalchemy.orm import relationship, backref -from sqlalchemy.ext.declarative import declarative_base -convention = { - "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", -} -metadata = MetaData(naming_convention=convention) +from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy.orm import declarative_base, relationship, sessionmaker -Base = declarative_base(metadata=metadata) +from sqlalchemy import create_engine +engine = create_engine('sqlite:///freebies.db') +Base = declarative_base() class Company(Base): - __tablename__ = 'companies' + __tablename__="companies" + id = Column(Integer, primary_key=True) + name = Column(String) + founding_year = Column(Integer) - id = Column(Integer(), primary_key=True) - name = Column(String()) - founding_year = Column(Integer()) - - def __repr__(self): - return f'' + company_freebies = relationship("Freebie", back_populates="company") + def __repr__(self): + return f"" + class Dev(Base): - __tablename__ = 'devs' + __tablename__= "devs" + id = Column(Integer, primary_key=True) + name = Column(String) - id = Column(Integer(), primary_key=True) - name= Column(String()) + dev_freebies = relationship("Freebie", back_populates="dev") def __repr__(self): - return f'' + 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')) + + + + def __repr__(self): + return (f"") + + + dev = relationship("Dev", back_populates="dev_freebies") + company = relationship("Company", back_populates="company_freebies") + + + + + + + + + + diff --git a/lib/query_data.py b/lib/query_data.py new file mode 100644 index 000000000..f5eadb38c --- /dev/null +++ b/lib/query_data.py @@ -0,0 +1,20 @@ +from models import Dev, Company, Freebie +from database import session + +print("\n---- Deveopers----") +devs = session.query(Dev).all() +for dev in devs: + print(f"Dev ID: {dev.id}, Name: {dev.name}") + +print("\n--- Companies ---") +companies = session.query(Company).all( +) +for company in companies: + print(f"Company ID: {company.id,} Name: {company.name},Founding Year: {company.founding_year}") + + print("\n--- Freebies ---") + freebies = session.query(Freebie).all() + for freebie in freebies: + print(f"Freebie.ID: {freebie.id}, Item: {freebie.item_name}, Value: {freebie.value}, Dev: {freebie.dev.name}, Company: {freebies.company}") + + session.close() \ No newline at end of file diff --git a/lib/seed.py b/lib/seed.py index b16becbbb..abfc240ed 100644 --- a/lib/seed.py +++ b/lib/seed.py @@ -1,3 +1,32 @@ -#!/usr/bin/env python3 +from models import Dev, Company, Freebie +from database import session + +from models import engine + +session.query(Freebie).delete() +session.query(Dev).delete() +session.query(Company).delete() +session.commit() + +dev1 = Dev(name= "crocs") +dev2 = Dev(name= "Susan") +dev3 = Dev(name= "Santos") + +company1 = Company(name="Devs Square", founding_year=2007) +company2 = Company(name="Legicomp", founding_year=2016) +company3 = Company(name="tarakideal", founding_year=2022) + +session.add_all([dev1, dev2, dev3, company1, company2, company3]) +session.commit() + +freebie1 = Freebie(item_name="Cap", value=2, dev=dev1, company=company1) +freebie2 = Freebie(item_name="pen", value=12, dev=dev2, company = company2) +freebie3 =Freebie(item_name="mug", value=6, dev=dev3, company=company1) +freebie4 = Freebie(item_name="Water Bottle", value=2, dev=dev3, company = company2 ) + +session.add_all([freebie1, freebie2, freebie3, freebie4]) +session.commit() + +print("Seed added successsfully!") + -# Script goes here!