From 688ba3518c546c2d0059c04b60f4f608a1aaf036 Mon Sep 17 00:00:00 2001 From: Edith Gatwiri Date: Sat, 1 Mar 2025 20:01:27 +0300 Subject: [PATCH 1/2] initial commit --- __pycache__/models.cpython-38.pyc | Bin 0 -> 3785 bytes alembic.ini | 107 ++++++++++++++++++ alembic/README | 1 + alembic/__pycache__/env.cpython-38.pyc | Bin 0 -> 1672 bytes alembic/env.py | 81 +++++++++++++ alembic/script.py.mako | 24 ++++ ...9699d_create_freebies_table.cpython-38.pyc | Bin 0 -> 1260 bytes ...c1086_create_freebies_table.cpython-38.pyc | Bin 0 -> 1319 bytes .../a9392bc9699d_create_freebies_table.py | 59 ++++++++++ .../d236154c1086_create_freebies_table.py | 31 +++++ freebies.db | Bin 0 -> 32768 bytes lib/freebles.db | 0 .../5f72c58bf48c_create_companies_devs.py | 43 ++++--- lib/models.py | 70 +++++++++++- lib/seed.py | 30 ++++- migrations/README | 1 + migrations/env.py | 78 +++++++++++++ migrations/script.py.mako | 26 +++++ models.py | 87 ++++++++++++++ seed.py | 29 +++++ your_database.db | 0 21 files changed, 643 insertions(+), 24 deletions(-) create mode 100644 __pycache__/models.cpython-38.pyc create mode 100644 alembic.ini create mode 100644 alembic/README create mode 100644 alembic/__pycache__/env.cpython-38.pyc create mode 100644 alembic/env.py create mode 100644 alembic/script.py.mako create mode 100644 alembic/versions/__pycache__/a9392bc9699d_create_freebies_table.cpython-38.pyc create mode 100644 alembic/versions/__pycache__/d236154c1086_create_freebies_table.cpython-38.pyc create mode 100644 alembic/versions/a9392bc9699d_create_freebies_table.py create mode 100644 alembic/versions/d236154c1086_create_freebies_table.py create mode 100644 freebies.db create mode 100644 lib/freebles.db create mode 100644 migrations/README create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako create mode 100644 models.py create mode 100644 seed.py create mode 100644 your_database.db diff --git a/__pycache__/models.cpython-38.pyc b/__pycache__/models.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..165279d87ddfdb1158618aa09e56bf3e83514a14 GIT binary patch literal 3785 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 YKj>rlB9}mxL?9=f;r-#g4( None: + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/alembic/script.py.mako b/alembic/script.py.mako new file mode 100644 index 000000000..55df2863d --- /dev/null +++ b/alembic/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade() -> None: + ${upgrades if upgrades else "pass"} + + +def downgrade() -> None: + ${downgrades if downgrades else "pass"} diff --git a/alembic/versions/__pycache__/a9392bc9699d_create_freebies_table.cpython-38.pyc b/alembic/versions/__pycache__/a9392bc9699d_create_freebies_table.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c40e8e81ddf31aa6fdf8710a46cdd3cd1347ba9 GIT binary patch literal 1260 zcma)5&1(}u6rb7eohG$tQRyjoi;yNwY9T>HNGTSfh}BCFmd(yIS>2soXE%}b?A8Ck zLvr-r@ShOo>dCtY5e47uZojC4GtArf-oDRyzj;}&69nt{`{&6Q6QQq4xV&@_9>d9= z0HJ7vD5hG3V{N2i#p{tiGN>^!sXnsc*l--GQ}ZLH7Pa3SBe#+q>Vib5evF#rlnw>+ zbJjQ!jEzHZyfFq8h*dm?~a51UcXPvKP($GNaeZ@{)0xh(|yqD z^je*r#?J0ww?F9hxA%7Tb~{}{zCq2XiKUjLN2A*1XrQzN%V&ZI%I5N_gD`}X5sXld zmYCvPd#zI~*OtZ#K{v(+z0jDTF+pRUYwXIV(kv~it?mgvi(JdT zb~QWHT)U>JU)3yaTAN_HKEW&1pH1r^-KeCpdKc!5U}hUf(hZV0^*M}7Y9T#6}ejx?#>@Pnk+{?ng5wNf~qDg;ZK#4d2t+ zd7f>MY!w5TrXw_%i>w6&bi4vFQp#)oK2XJ)^RSN2D$l6gt0FcPuXIa z@GKX8$aA@QkO&q|_!aFZByL0Wg8Y2do+dGCGaBa8cDl%?32&vnR@Fue;skG)X!{Y1 z$6?T(Godh>wJ$@=tI9mX8JyVfHbx8Y6%rdS{8b78zpxK z%%n?`cf6>*1!86aK^nmXi!I=qYtr^SngpIF?doo-xY^stkAf+S7h(e}r6a0$F6%0! zcOj02&x5H4pkh%b31uncH1iT(v|i--YiZ8IIH9wMJ%U$@GL^)zYuGUiTx@-P>kkVy BM_~W} literal 0 HcmV?d00001 diff --git a/alembic/versions/__pycache__/d236154c1086_create_freebies_table.cpython-38.pyc b/alembic/versions/__pycache__/d236154c1086_create_freebies_table.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c6a5a9f89c85374a93ebdfeb8d5f516a7db34cd GIT binary patch literal 1319 zcmZuxOK;Oa5cb-R?KnZ+D8I97;ja(T544=Q8Ph#EH!IK z$&gVuqm2Vb>By&PBXdUqHO+l`=%;=hH6H8?8qn=+ZERlmHago|#STpe4Y%LxcSl}- ztKSE+46}o=290i~yV>gWTAhu?#@3+M9cQxcLBA;UNqbYahxb+F=+qazlEgqebp@ z@h`6;w8)=wV{ym4>Sr``gy$!j*XbKS&HQNWWV3`a9ec_vhi)*X%^H)1W_dYBoSYh5 zPF=1I<6s&_Tz?Q{bW9mPdpBm(A4d=AY#2vr##}$jI62^FA2C04+3e2^%MCKhu#h6k zvpf64`*-#++}@Mjd%OFeBz6H4=i>YG_9PBzn}VNB+Q}@N#8E5hwaQ{zn96%eS=$Y0 zIP$&rA!UNMX?vMkPFcaC14Sw8$&BmMWXxQkXE0xS1%)JQWEJNcPVnJbt8mj3k3Q7L6Fil~X5pCAE z?l=&8j>Gk`r3DGh^i|*n-h_s;JUus9`9$!#2=APzBj!fl#6fn`AjQMcghr4$ag=v2 e&-3478aKljrUAW0#3@CMs%{ZORY^XTmDOKe>|784 literal 0 HcmV?d00001 diff --git a/alembic/versions/a9392bc9699d_create_freebies_table.py b/alembic/versions/a9392bc9699d_create_freebies_table.py new file mode 100644 index 000000000..884030d0e --- /dev/null +++ b/alembic/versions/a9392bc9699d_create_freebies_table.py @@ -0,0 +1,59 @@ +from alembic import op +import sqlalchemy as sa +from sqlalchemy import inspect + +# revision identifiers, used by Alembic. +revision = 'a9392bc9699d' +down_revision = None +branch_labels = None +depends_on = None + +def upgrade() -> None: + # Get the current database connection and inspector + bind = op.get_bind() + inspector = inspect(bind) + + # Check if 'companies' table already exists + if 'companies' not in inspector.get_table_names(): + op.create_table('companies', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('founding_year', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + + # Check if 'devs' table already exists + if 'devs' not in inspector.get_table_names(): + op.create_table('devs', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + + # Check if 'freebies' table already exists + if 'freebies' not in inspector.get_table_names(): + 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('company_id', sa.Integer(), nullable=True), + sa.Column('dev_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['company_id'], ['companies.id']), + sa.ForeignKeyConstraint(['dev_id'], ['devs.id']), + sa.PrimaryKeyConstraint('id') + ) + +def downgrade() -> None: + # Get the current database connection and inspector + bind = op.get_bind() + inspector = inspect(bind) + + # Only drop the table if it exists + if 'freebies' in inspector.get_table_names(): + op.drop_table('freebies') + + if 'devs' in inspector.get_table_names(): + op.drop_table('devs') + + if 'companies' in inspector.get_table_names(): + op.drop_table('companies') diff --git a/alembic/versions/d236154c1086_create_freebies_table.py b/alembic/versions/d236154c1086_create_freebies_table.py new file mode 100644 index 000000000..8f1c50dc7 --- /dev/null +++ b/alembic/versions/d236154c1086_create_freebies_table.py @@ -0,0 +1,31 @@ +from alembic import op +import sqlalchemy as sa +from sqlalchemy import inspect + +# revision identifiers, used by Alembic. +revision = 'd236154c1086' +down_revision = 'a9392bc9699d' +branch_labels = None +depends_on = None + +def upgrade() -> None: + # Use SQLAlchemy's inspection system to check if the table already exists + bind = op.get_bind() + inspector = inspect(bind) + + if 'company_dev' not in inspector.get_table_names(): + op.create_table('company_dev', + sa.Column('company_id', sa.Integer(), nullable=False), + sa.Column('dev_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['company_id'], ['companies.id'], name=op.f('fk_company_dev_company_id_companies')), + sa.ForeignKeyConstraint(['dev_id'], ['devs.id'], name=op.f('fk_company_dev_dev_id_devs')), + sa.PrimaryKeyConstraint('company_id', 'dev_id') + ) + + # Make columns in the 'freebies' table non-nullable + op.alter_column('freebies', 'item_name', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('freebies', 'value', + existing_type=sa.INTEGER(), + nullable=False) diff --git a/freebies.db b/freebies.db new file mode 100644 index 0000000000000000000000000000000000000000..5b7e283aaf2d35a84a9aa1f9ee1f81867fb9e88a GIT binary patch literal 32768 zcmeI)Z)?*)9Ki8po6XwU)jb#mVeViIRwlwW6#780mTVSl=dvp7frPY8C9HpD|KXk} z8~VVP$~P?J^2_z^mrw2jN4Fgx6@#8H>g`U`>xn(%j$xX{ z6Cn)4Sdsgp-1W933k&*09?eksy5frQVDKfGj2l+so{>tXzAk;Z{cZW<@?Ck#h5!Nx zAbY1qH27 zCsq;gQTG}*aw(!WY39Bdr~Ip?uB0mHa!~uXpt@bv$0(7Tnm)8*>B5F-1g)C?zWc5r z$DHf+d+p)*Ro<%Yols|ssUN0V@UUrtYTQb%u9_E_;n0*`UA5ne3`Q0C!*rjX>5(Bf zoB$U~i&lDl-MsKa6F^S4(UXydg-Cx_;Tv>XZ}(fZp!L>0_q~pu32JcvCYy|DrMI`u z%lI%Gui-Z)>O`Xm~GMl=n@*985ZS|Y_b+@&*n~6-q(Cccd1^4W None: # ### commands auto generated by Alembic - please adjust! ### - op.create_table('companies', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(), nullable=True), - sa.Column('founding_year', sa.Integer(), nullable=True), - sa.PrimaryKeyConstraint('id') + + # Creating companies table + op.create_table( + 'companies', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('founding_year', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('id') ) - op.create_table('devs', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(), nullable=True), - sa.PrimaryKeyConstraint('id') + + # Creating devs table + op.create_table( + 'devs', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + + # Creating freebies table with constraints + op.create_table( + 'freebies', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('item_name', sa.String(), nullable=False), # Add NOT NULL constraint + sa.Column('value', sa.Integer(), nullable=False), # Add NOT NULL constraint + sa.Column('dev_id', sa.Integer(), sa.ForeignKey('devs.id')), + sa.Column('company_id', sa.Integer(), sa.ForeignKey('companies.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..4826291ab 100644 --- a/lib/models.py +++ b/lib/models.py @@ -1,14 +1,31 @@ -from sqlalchemy import ForeignKey, Column, Integer, String, MetaData -from sqlalchemy.orm import relationship, backref +from sqlalchemy import ForeignKey, Column, Integer, String, MetaData, create_engine +from sqlalchemy.orm import relationship, backref, sessionmaker from sqlalchemy.ext.declarative import declarative_base -convention = { - "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", -} +# Defining metadata +convention = {"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s"} metadata = MetaData(naming_convention=convention) Base = declarative_base(metadata=metadata) +# Setting up the database engine +engine = create_engine('sqlite:///freebies.db') + +# Creating a session factory +Session = sessionmaker(bind=engine) +session = Session() + +# Association Table for Many-to-Many relationship +class CompanyDev(Base): + __tablename__ = 'company_dev' + + company_id = Column(Integer(), ForeignKey('companies.id'), primary_key=True) + dev_id = Column(Integer(), ForeignKey('devs.id'), primary_key=True) + + company = relationship('Company', backref=backref('company_devs')) + dev = relationship('Dev', backref=backref('company_devs')) + +# Models class Company(Base): __tablename__ = 'companies' @@ -16,6 +33,20 @@ class Company(Base): name = Column(String()) founding_year = Column(Integer()) + freebies = relationship("Freebie", backref="company") + devs = relationship("Dev", secondary="company_dev", backref="companies") + + def give_freebie(self, dev, item_name, value): + """Creates a new Freebie instance associated with this company and the given dev.""" + new_freebie = Freebie(item_name=item_name, value=value, dev=dev, company=self) + session.add(new_freebie) + session.commit() + + @classmethod + def oldest_company(cls): + """Returns the company with the earliest founding year.""" + return session.query(cls).order_by(cls.founding_year).first() + def __repr__(self): return f'' @@ -23,7 +54,34 @@ class Dev(Base): __tablename__ = 'devs' id = Column(Integer(), primary_key=True) - name= Column(String()) + name = Column(String()) + + freebies = relationship("Freebie", backref="dev") + + def received_one(self, item_name): + """Returns True if the dev has received a freebie with the given item_name.""" + return any(freebie.item_name == item_name for freebie in self.freebies) + + def give_away(self, dev, freebie): + """Transfers a freebie to another dev if the freebie belongs to this dev.""" + if freebie in self.freebies: + 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(), nullable=False) + value = Column(Integer(), nullable=False) + dev_id = Column(Integer(), ForeignKey('devs.id')) + company_id = Column(Integer(), ForeignKey('companies.id')) + + 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..3b4efb0a4 100644 --- a/lib/seed.py +++ b/lib/seed.py @@ -1,3 +1,29 @@ -#!/usr/bin/env python3 +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from models import Base, Company, Dev, Freebie, CompanyDev -# Script goes here! +engine = create_engine("sqlite:///freebies.db") +Session = sessionmaker(bind=engine) +session = Session() + +# Creating sample companies +company1 = Company(name="Google", founding_year=1998) +company2 = Company(name="Microsoft", founding_year=1975) + +# Creating sample developers +dev1 = Dev(name="Alice") +dev2 = Dev(name="Bob") + +# Creating sample freebies +freebie1 = Freebie(item_name="T-Shirt", value=10, company=company1, dev=dev1) +freebie2 = Freebie(item_name="Mug", value=5, company=company2, dev=dev2) + +# Add the dev-company relationship explicitly for many-to-many +company1.devs.append(dev1) +company2.devs.append(dev2) + +# Adding all the instances to the session +session.add_all([company1, company2, dev1, dev2, freebie1, freebie2]) +session.commit() + +print("✅ Database seeded successfully!") diff --git a/migrations/README b/migrations/README new file mode 100644 index 000000000..98e4f9c44 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 000000000..36112a3c6 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,78 @@ +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline() -> None: + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 000000000..fbc4b07dc --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,26 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision: str = ${repr(up_revision)} +down_revision: Union[str, None] = ${repr(down_revision)} +branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} +depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} + + +def upgrade() -> None: + ${upgrades if upgrades else "pass"} + + +def downgrade() -> None: + ${downgrades if downgrades else "pass"} diff --git a/models.py b/models.py new file mode 100644 index 000000000..4826291ab --- /dev/null +++ b/models.py @@ -0,0 +1,87 @@ +from sqlalchemy import ForeignKey, Column, Integer, String, MetaData, create_engine +from sqlalchemy.orm import relationship, backref, sessionmaker +from sqlalchemy.ext.declarative import declarative_base + +# Defining metadata +convention = {"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s"} +metadata = MetaData(naming_convention=convention) + +Base = declarative_base(metadata=metadata) + +# Setting up the database engine +engine = create_engine('sqlite:///freebies.db') + +# Creating a session factory +Session = sessionmaker(bind=engine) +session = Session() + +# Association Table for Many-to-Many relationship +class CompanyDev(Base): + __tablename__ = 'company_dev' + + company_id = Column(Integer(), ForeignKey('companies.id'), primary_key=True) + dev_id = Column(Integer(), ForeignKey('devs.id'), primary_key=True) + + company = relationship('Company', backref=backref('company_devs')) + dev = relationship('Dev', backref=backref('company_devs')) + +# Models +class Company(Base): + __tablename__ = 'companies' + + id = Column(Integer(), primary_key=True) + name = Column(String()) + founding_year = Column(Integer()) + + freebies = relationship("Freebie", backref="company") + devs = relationship("Dev", secondary="company_dev", backref="companies") + + def give_freebie(self, dev, item_name, value): + """Creates a new Freebie instance associated with this company and the given dev.""" + new_freebie = Freebie(item_name=item_name, value=value, dev=dev, company=self) + session.add(new_freebie) + session.commit() + + @classmethod + def oldest_company(cls): + """Returns the company with the earliest founding year.""" + return session.query(cls).order_by(cls.founding_year).first() + + def __repr__(self): + return f'' + +class Dev(Base): + __tablename__ = 'devs' + + id = Column(Integer(), primary_key=True) + name = Column(String()) + + freebies = relationship("Freebie", backref="dev") + + def received_one(self, item_name): + """Returns True if the dev has received a freebie with the given item_name.""" + return any(freebie.item_name == item_name for freebie in self.freebies) + + def give_away(self, dev, freebie): + """Transfers a freebie to another dev if the freebie belongs to this dev.""" + if freebie in self.freebies: + 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(), nullable=False) + value = Column(Integer(), nullable=False) + dev_id = Column(Integer(), ForeignKey('devs.id')) + company_id = Column(Integer(), ForeignKey('companies.id')) + + 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/seed.py b/seed.py new file mode 100644 index 000000000..3b4efb0a4 --- /dev/null +++ b/seed.py @@ -0,0 +1,29 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from models import Base, Company, Dev, Freebie, CompanyDev + +engine = create_engine("sqlite:///freebies.db") +Session = sessionmaker(bind=engine) +session = Session() + +# Creating sample companies +company1 = Company(name="Google", founding_year=1998) +company2 = Company(name="Microsoft", founding_year=1975) + +# Creating sample developers +dev1 = Dev(name="Alice") +dev2 = Dev(name="Bob") + +# Creating sample freebies +freebie1 = Freebie(item_name="T-Shirt", value=10, company=company1, dev=dev1) +freebie2 = Freebie(item_name="Mug", value=5, company=company2, dev=dev2) + +# Add the dev-company relationship explicitly for many-to-many +company1.devs.append(dev1) +company2.devs.append(dev2) + +# Adding all the instances to the session +session.add_all([company1, company2, dev1, dev2, freebie1, freebie2]) +session.commit() + +print("✅ Database seeded successfully!") diff --git a/your_database.db b/your_database.db new file mode 100644 index 000000000..e69de29bb From b69e26d046147d8c4031dbc745cf4e62d578340b Mon Sep 17 00:00:00 2001 From: Edith Gatwiri Date: Sun, 2 Mar 2025 14:11:02 +0300 Subject: [PATCH 2/2] finalcommit --- __pycache__/models.cpython-38.pyc | Bin 3785 -> 3938 bytes ...9699d_create_freebies_table.cpython-38.pyc | Bin 1260 -> 1360 bytes ...c1086_create_freebies_table.cpython-38.pyc | Bin 1319 -> 1881 bytes .../d236154c1086_create_freebies_table.py | 46 +++++++++++++++--- freebies.db | Bin 32768 -> 36864 bytes lib/__pycache__/models.cpython-38.pyc | Bin 0 -> 3940 bytes lib/debug.py | 3 +- lib/models.py | 7 +-- models.py | 7 +-- 9 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 lib/__pycache__/models.cpython-38.pyc diff --git a/__pycache__/models.cpython-38.pyc b/__pycache__/models.cpython-38.pyc index 165279d87ddfdb1158618aa09e56bf3e83514a14..efe2c48dcc779b1e42b68d9e096e7d730b9f7585 100644 GIT binary patch delta 1550 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 BM_~W} diff --git a/alembic/versions/__pycache__/d236154c1086_create_freebies_table.cpython-38.pyc b/alembic/versions/__pycache__/d236154c1086_create_freebies_table.cpython-38.pyc index 1c6a5a9f89c85374a93ebdfeb8d5f516a7db34cd..40ac303331da937222c1416b027d89275f9ed633 100644 GIT binary patch literal 1881 zcmc&#O>f&q5am+*79~55;id)JvT2h>fE_h)YE(c`6fkVSXsZOVdLarB6lX0l=2w@L z6BWs+xfbXxmmZ{J{zlPXvDcpZ7u-u{NlKP-NpB&+r=7>0nYX($)Q_!}CE@kw!C#|S zrX>9>jMb}w#<%$7j}Slt5=k*}2@zvClHCUWHX=DzTm?DBRY7$%kX;=g17y(tAfSWs zQgO}NGQmR20{K+xH2=Y^=(hI4OpG&`z7X-+2GHcAGbDh1!cM6a~ zeS%U8b*9g85up6mC>iw)2A44+pp6K6nV`=J80Aa@ROHQ?w-)>imj>!wo@+#CP@q{x zwd<%YXxDi*kZG=E-dxW-)1cOZybb1@%uyk-wdRu51Y757!L>Oa4Q6e_Rz2E)CXQus zV7TGe`@9*Xapose59kHA7DfoiuL(DjNfi0Rh;j|zdLdle)r64dcSCSLJv;Xn9%8~` z96~+Bd3Zib;>Yw-#~G#92XA;)p+)}Owa*x(Lv-^J`jpEd3{XZhV`1#GsdrAN+zbmE zdmxxeJ$gKFPWpp~&T1g%P6)fs(s9=*9e157^R9EHyR(dSdi4F# z;lTO7j?VGphd(TnmQlE|(9qdrq8_<1qJ=jM6JVl`_=YeGvA^Yda&8BV`UR~xF6Tbi z4%287CtN>C3Ob^UZy%?OhNI*=Iz3F2ykLHq6r7y#?MKxnt-sJt3l=6LZe6)?oj#+% zq@dgamS%M_n^Cc+mDQ2CB4pxbR}Gl5*An{-HDCVJ9j7tvQV5H2H=7pYG}+7c_v)4I zp`PHJvaTP|co+uV3(E2kb#_-9*sGVh*q$os-E7MBNj73W(5C3xI|vdnh|#c#Mz-+2 zfw%RqVpi4`*&#bji57xI$^HjF$|maQfj6&bZ;G;Bw~ z=*u}JGi!iRF^F2-d@{1u3fo+1J{|13hP1&>SsIFs`70-5r-1h|B5b(Z$4+VTA;9~)ffKLR70$YJw zXmS(Mr%728duZm{2$H;Z{)VOE`G1alr^)rY@Tz{Z@}DC=3dS^^RwBx_GZ?)HMOE^a z2<}~(L*^&J*uzgAjdE-cn$ZMuFHOqwDs!ypE9I6Vjj!VrCK3Gx|7WCp6T!y1wHpd4 IZ@GQ*KRFZsp#T5? literal 1319 zcmZuxOK;Oa5cb-R?KnZ+D8I97;ja(T544=Q8Ph#EH!IK z$&gVuqm2Vb>By&PBXdUqHO+l`=%;=hH6H8?8qn=+ZERlmHago|#STpe4Y%LxcSl}- ztKSE+46}o=290i~yV>gWTAhu?#@3+M9cQxcLBA;UNqbYahxb+F=+qazlEgqebp@ z@h`6;w8)=wV{ym4>Sr``gy$!j*XbKS&HQNWWV3`a9ec_vhi)*X%^H)1W_dYBoSYh5 zPF=1I<6s&_Tz?Q{bW9mPdpBm(A4d=AY#2vr##}$jI62^FA2C04+3e2^%MCKhu#h6k zvpf64`*-#++}@Mjd%OFeBz6H4=i>YG_9PBzn}VNB+Q}@N#8E5hwaQ{zn96%eS=$Y0 zIP$&rA!UNMX?vMkPFcaC14Sw8$&BmMWXxQkXE0xS1%)JQWEJNcPVnJbt8mj3k3Q7L6Fil~X5pCAE z?l=&8j>Gk`r3DGh^i|*n-h_s;JUus9`9$!#2=APzBj!fl#6fn`AjQMcghr4$ag=v2 e&-3478aKljrUAW0#3@CMs%{ZORY^XTmDOKe>|784 diff --git a/alembic/versions/d236154c1086_create_freebies_table.py b/alembic/versions/d236154c1086_create_freebies_table.py index 8f1c50dc7..f52b8c082 100644 --- a/alembic/versions/d236154c1086_create_freebies_table.py +++ b/alembic/versions/d236154c1086_create_freebies_table.py @@ -9,10 +9,10 @@ depends_on = None def upgrade() -> None: - # Use SQLAlchemy's inspection system to check if the table already exists bind = op.get_bind() inspector = inspect(bind) + # Create 'company_dev' table if it doesn't exist if 'company_dev' not in inspector.get_table_names(): op.create_table('company_dev', sa.Column('company_id', sa.Integer(), nullable=False), @@ -22,10 +22,40 @@ def upgrade() -> None: sa.PrimaryKeyConstraint('company_id', 'dev_id') ) - # Make columns in the 'freebies' table non-nullable - op.alter_column('freebies', 'item_name', - existing_type=sa.VARCHAR(), - nullable=False) - op.alter_column('freebies', 'value', - existing_type=sa.INTEGER(), - nullable=False) + # Workaround for SQLite: Recreate 'freebies' table with the correct constraints + op.create_table('freebies_new', + sa.Column('id', sa.Integer(), primary_key=True), + sa.Column('item_name', sa.String(), nullable=False), # Enforce NOT NULL + sa.Column('value', sa.Integer(), nullable=False), # Enforce NOT NULL + sa.Column('dev_id', sa.Integer(), sa.ForeignKey('devs.id')), + sa.Column('company_id', sa.Integer(), sa.ForeignKey('companies.id')) + ) + + # Copy data from old table + op.execute(""" + INSERT INTO freebies_new (id, item_name, value, dev_id, company_id) + SELECT id, item_name, value, dev_id, company_id FROM freebies + """) + + # Drop old table and rename new table + op.drop_table('freebies') + op.rename_table('freebies_new', 'freebies') + + +def downgrade() -> None: + # Reverse the process in downgrade + op.create_table('freebies_old', + sa.Column('id', sa.Integer(), primary_key=True), + sa.Column('item_name', sa.String(), nullable=True), # Allow NULL again + sa.Column('value', sa.Integer(), nullable=True), + sa.Column('dev_id', sa.Integer(), sa.ForeignKey('devs.id')), + sa.Column('company_id', sa.Integer(), sa.ForeignKey('companies.id')) + ) + + op.execute(""" + INSERT INTO freebies_old (id, item_name, value, dev_id, company_id) + SELECT id, item_name, value, dev_id, company_id FROM freebies + """) + + op.drop_table('freebies') + op.rename_table('freebies_old', 'freebies') diff --git a/freebies.db b/freebies.db index 5b7e283aaf2d35a84a9aa1f9ee1f81867fb9e88a..aab3edf8495e2e584cb7c73038b5d0d43dc777a5 100644 GIT binary patch delta 359 zcmZo@U}{*vG(lRBmw|zS6NuS>m=TCMCh8c=@-pa^b@KA;VqoXo%)rmfzmuci1F~n6N#L>yeRY3_R ztTZ{8OGik-&p$-LFVx3JM}dp8EHS4vb@C~0<;fGcq$cm-(q_&}EuTD_$8@qTw=|e- z&f~thhI;}dW5UM97)GXKmdP@Fsf^5n3I{D%E1U@0cGCvPn;k) z$$^E9k^dJ1|1YqJAOi~{GbbYx7bvU{!t4yJES!v-Oq+n#@v$*TGI4VHBo>t97qH#| E0D|savj6}9 delta 280 zcmZozz|_#dG(lQWkb!}L1BhXOd!ml9v>=0CStlk7Q<*Z=O9I%i=RrCcg(tmU2l?e#srd0W)T@50Cj~eeOO+M!}7Z zyo^lAoRekvQW-fmH}Mq-@+4XsTN))LTbfx~rfgF9!Y_m@zzgz^z-GpPU;L92SeWoK I*|-pj0i88SApigX diff --git a/lib/__pycache__/models.cpython-38.pyc b/lib/__pycache__/models.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61b58ace3e07377afa36b51373538df96d029dd9 GIT binary patch literal 3940 zcmbVPTW{RP73PrK8~37JTUOlk#zuAPMdOuGC%rhTYDB7pg*9$g0Fe%U+`1EGbDFcjuiwYz_UCvXJ*dzo3nrFb{zxH z`2GJJ{aVTV7f1JrMIn0}X5LvJjWI^7YND*Yh7s+9mh@q8tq=+-Ktl3d_~Sr{+&nm$eQ_(7&knVGtUyXs9hQehk41k#qH;o*O-sh=3`CK z;&tKh25%x5jUK?X=J=U3zAy^1NFL$=n_%ukSJK{WVPl|7!i}P2Vf+2N7zWm$V*0895t_&w<$AA_pVDGA8xVbWX+K3yNza9hf>ZU9$rjAZtsQYbTbmzr zMSgGC&6~b8DOhP?UrE&=O*+A;RDh~==;Vi7 zHfdI$-zaBu3sWx*`3}txdG%o9D2>I2;9+*OaXQV8(&XOhgL`EJ?`0AhCgesGjyIr} zh}7tGD*IS@6R)D$Z8F8krLXQ@-0YC$o17z!w2Q_HeU4;kj%I+FRTl80l<20 ze{N^&OY_2h!I*(B>xBU*GNGb1+uPO!uH3*)#8bCa%?%Tk1<6FXfl}!t1O#yRDI(-% zN1<{{9o-<|7!d9usyuO_>}Y7`E!1GFvnj8g2ho|3KY~Kq*u9}G?|{i0C0yiIz>zN4 zFAlR|Ew`134hs37(xST{UK@(}Wj-ttN3PRG9Xh(2q$P^nV3>X8u-WQ%QDviLp$Q{_ z@}X}Ful5^7D>J@?&t8zXjAIMG_6q}kVzc-DD6%t|C~a?Lf9Vn7ia)HS)q&Stn z|8qtBE=Uagf2NcO09wrGW3uMj@e;-vspKpV{3^CCa*m6%iu2< z{#F>#nj?b)(5FkFLWXvU3;=$@1+QD8La#&xUF;v=oB|JYMHD%&v4GOBz=9I53!pC{ z8(Ai)z$ZEd@IeoK6C99x6>X9ke>V;oG%}wx5pA{ubh>1^;6JJod0(ChH$2b@4OhEI zfpVpo2ow}|1GkJrRrOVo&x?C>CCf+yI-P=}HMlVT+W(wguw&yN#)Y~|N11$?GJPf5U81)`cAizrPFfi`J@xDXi; zdXhy&t`M-upMeam!a$9(zok)ar6%iO^OlCc;At@Z5NrvM4y&_Sm&}~cUJ2+GWPCGh z)Hbo)mG9A!?-ThYk*kO6Lj8!2H9-tE>(G%4m{|E{n2^7wEf+YU8w%}%AJYWcBPj~k z;{g>LDW|AqDDj{`1G`z*_wED}R~|~WM|jn@=@$qE&>fULL&>$ucG2N=)E)H>MN5ee zLh~JJ88tHK&fe?s4icqXAOV?IAj2+oa>-c~QNt{6VO-t-`C6RFKja1V0}#r@V+MF9 zm^TUL@oUk@7qtTJn{N6P7g^xW>d3}4c9B;)c{CL3I&rblo5GoQ(V8Y1I?pT!BehS5 zmVv#sTXZ#}D-zf1N-(#$il8IuY-t^Bx{}K6+*!-L`zf^%58atL+(J2P4XHDDlZHAI z{=B4DztZdfNxH>RWTpHe5puHp9g%AWvi@XHF4cKR?`B) LSbe8|yTA57;&X?C literal 0 HcmV?d00001 diff --git a/lib/debug.py b/lib/debug.py index 4f922eb69..f77096481 100644 --- a/lib/debug.py +++ b/lib/debug.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 from sqlalchemy import create_engine - -from models import Company, Dev +from models import session, Company, Dev, Freebie # Import session if __name__ == '__main__': engine = create_engine('sqlite:///freebies.db') diff --git a/lib/models.py b/lib/models.py index 4826291ab..a1c51b609 100644 --- a/lib/models.py +++ b/lib/models.py @@ -22,8 +22,8 @@ class CompanyDev(Base): company_id = Column(Integer(), ForeignKey('companies.id'), primary_key=True) dev_id = Column(Integer(), ForeignKey('devs.id'), primary_key=True) - company = relationship('Company', backref=backref('company_devs')) - dev = relationship('Dev', backref=backref('company_devs')) + company = relationship('Company', backref=backref('company_devs', overlaps="devs,company_devs")) + dev = relationship('Dev', backref=backref('company_devs', overlaps="companies,company_devs")) # Models class Company(Base): @@ -34,7 +34,7 @@ class Company(Base): founding_year = Column(Integer()) freebies = relationship("Freebie", backref="company") - devs = relationship("Dev", secondary="company_dev", backref="companies") + devs = relationship("Dev", secondary="company_dev", backref=backref("company_associations", overlaps="company_devs,devs")) def give_freebie(self, dev, item_name, value): """Creates a new Freebie instance associated with this company and the given dev.""" @@ -57,6 +57,7 @@ class Dev(Base): name = Column(String()) freebies = relationship("Freebie", backref="dev") + companies = relationship("Company", secondary="company_dev", backref=backref("dev_associations", overlaps="company_devs,companies")) def received_one(self, item_name): """Returns True if the dev has received a freebie with the given item_name.""" diff --git a/models.py b/models.py index 4826291ab..a1c51b609 100644 --- a/models.py +++ b/models.py @@ -22,8 +22,8 @@ class CompanyDev(Base): company_id = Column(Integer(), ForeignKey('companies.id'), primary_key=True) dev_id = Column(Integer(), ForeignKey('devs.id'), primary_key=True) - company = relationship('Company', backref=backref('company_devs')) - dev = relationship('Dev', backref=backref('company_devs')) + company = relationship('Company', backref=backref('company_devs', overlaps="devs,company_devs")) + dev = relationship('Dev', backref=backref('company_devs', overlaps="companies,company_devs")) # Models class Company(Base): @@ -34,7 +34,7 @@ class Company(Base): founding_year = Column(Integer()) freebies = relationship("Freebie", backref="company") - devs = relationship("Dev", secondary="company_dev", backref="companies") + devs = relationship("Dev", secondary="company_dev", backref=backref("company_associations", overlaps="company_devs,devs")) def give_freebie(self, dev, item_name, value): """Creates a new Freebie instance associated with this company and the given dev.""" @@ -57,6 +57,7 @@ class Dev(Base): name = Column(String()) freebies = relationship("Freebie", backref="dev") + companies = relationship("Company", secondary="company_dev", backref=backref("dev_associations", overlaps="company_devs,companies")) def received_one(self, item_name): """Returns True if the dev has received a freebie with the given item_name."""