From 0d907a5b462982d522f427a22a26dd2f7c8fa78d Mon Sep 17 00:00:00 2001 From: Enock Tangus Date: Sat, 24 May 2025 21:44:29 +0300 Subject: [PATCH 1/3] freebie tracker --- lib/__pycache__/models.cpython-38.pyc | Bin 0 -> 3760 bytes lib/debug.py | 68 +++++++++++++++++- lib/freebies.db | Bin 20480 -> 24576 bytes .../0a8c798ff248_create_freebies_table.py | 37 ++++++++++ lib/models.py | 68 +++++++++++++++++- lib/seed.py | 43 ++++++++++- 6 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 lib/__pycache__/models.cpython-38.pyc create mode 100644 lib/migrations/versions/0a8c798ff248_create_freebies_table.py diff --git a/lib/__pycache__/models.cpython-38.pyc b/lib/__pycache__/models.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..519be4f875be541ad52acdda1c74ab5ad182d838 GIT binary patch literal 3760 zcmcgv%WoUU8Q+;*E|)8kqWnnPqz}4DA8aAfhzqny6xFR=HEj@GC#bUKHlxXdP znqAo?A)jO*z4*{`8o)a0Uz%%AJ@*zAXn)`AQX~x-@F_#g$9d29{C%^ZcRId>@*nU0 zqfgNK7j>44gU)@_;-4VG5-hP&7O<2DJhcNmbpj`C1dY@UTt@ReX{KJ_rLCZq`hkxz zTR3ADtjUI46O9)vXiHzVg^N~4x}tf`g05`IuJACjF4xbkp!a)Aw1ofM629!5+rb9< zYod*Q+w^as-w|E(yQY6rtnXWc-oL@2HE^}Rn=3g!%s!P;X??mdU4KEum3RMZQOi+K1%W_2kCn>%lo-F=0o4qv`VRg}p5afba zLVO#Y(khu?fJCqMvcbm5n4l`R+cd(cvLB{M9E}A6x(6C(eH5oC9X;bjdZ} zx~rS7F^j*QjEj<_*x955i6z(K)~r950WMN(Z6|pgCB+UJ^W~SecBrH6LYCUA&o30& z_El{;bjZ)?eB;x6)?Pk+Z*YS=p8_llwI7BEh*JPwsM}$9avCM|Oed`Ht?DXLf+Bu3 z9}7h>p}s@pXGA` z;w=!5IlRk!=JPi9Y_H9k?{H?;#F$;xi^|4Kyn~jL9~omt;kEy$Wo>x$ZRB!x7J*3tykp)AhWgPWBCJ2uV zoYxp*5C-^Sd$ywa7uWql`FScHdL>r<5vve!OAv~xMXx0>zGR9)oUW6JDnwV9DNfllaG|UUN$wiDy zyzV`=TfOmWa58RqU7Ql${~7hl8S8zo2Pk)ba~}1p&Uw8(=XGTT z^5Yx3p}F}ET~8sVU6>*qi@>ieF-5ydjfPi)oF+ehLOZT=&6}9`BWgiw7wNCZdc4gj z2^#C~4Q^>49}`g$AIWrT?p}%#6Ck8z)dbPq#mcQ*r4>Uhnx-#C4PNJ8E2={S&Tr{+ z$gMu3)bD7aiET>Fl~)m$*Rij??dmPDLmp-jwa;$Z+~WUpY@hqwqu^(~JH2=Q4`|vR ADgXcg literal 0 HcmV?d00001 diff --git a/lib/debug.py b/lib/debug.py index 4f922eb69..9a11a12b4 100644 --- a/lib/debug.py +++ b/lib/debug.py @@ -1,9 +1,73 @@ #!/usr/bin/env python3 from sqlalchemy import create_engine - -from models import Company, Dev +from sqlalchemy.orm import sessionmaker +from models import Base, Company, Dev, Freebie if __name__ == '__main__': engine = create_engine('sqlite:///freebies.db') + Base.metadata.create_all(engine) + Session = sessionmaker(bind=engine) + session = Session() + + companies = session.query(Company).all() + devs = session.query(Dev).all() + freebies = session.query(Freebie).all() + + print("---Testing Freebie Tracker---") + + print(f"Companies: {len(companies)}") + print(f"Devs: {len(devs)}") + print(f"Freebies: {len(freebies)}") + + print(f"\nFirst company: {companies[0].name}") + print(f" First company's freebies: {[freebie.item_name for freebie in companies[0].freebies]}") + print(f" First company's devs: {[dev.name for dev in companies[0].devs]}") + + print(f"\nFirst dev: {devs[0].name}") + print(f" First dev's freebies: {[freebie.item_name for freebie in devs[0].freebies]}") + print(f" First dev's companies: {[company.name for company in devs[0].companies]}") + + print(f"\nFirst freebie details: {freebies[0].print_details()}") + + print(f"\nOldest company: {Company.oldest_company().name} (founded {Company.oldest_company().founding_year})") + print(f"Does {devs[0].name} have a T-shirt? {devs[0].received_one('T-shirt')}") + print(f"Does {devs[0].name} have a Laptop? {devs[0].received_one('Laptop')}") + + + moringa = session.query(Company).filter_by(name="Moringa").first() + anne = session.query(Dev).filter_by(name="Anne").first() + + print(f"\nGive freebie: {moringa.name} giving 'Notebook' to {anne.name}") + print(f" Anne's freebies before: {[freebie.item_name for freebie in anne.freebies]}") + + new_freebie = moringa.give_freebie(anne, "Water Bottle", 300, session) + + session.refresh(anne) + print(f" Anne's freebies after: {[freebie.item_name for freebie in anne.freebies]}") + print(f" New freebie added: {new_freebie.print_details()}") + session.commit() + + + andrew = session.query(Dev).filter_by(name="Andrew").first() + frank = session.query(Dev).filter_by(name="Frank").first() + + andrew_freebie = session.query(Freebie).filter_by(dev_id=andrew.id).first() + + print(f"\nGive Away: {andrew.name} giving '{andrew_freebie.item_name}' to {frank.name}") + print(f" Andrew's freebies before: {[freebie.item_name for freebie in andrew.freebies]}") + print(f" Frank's freebies before: {[freebie.item_name for freebie in frank.freebies]}") + print(f" Freebie owner before: {andrew_freebie.dev.name}") + + result = andrew.give_away(frank, andrew_freebie) + + session.refresh(andrew) + session.refresh(frank) + session.refresh(andrew_freebie) + + print(f"\n Andrew's freebies after: {[freebie.item_name for freebie in andrew.freebies]}") + print(f" frank's freebies after: {[freebie.item_name for freebie in frank.freebies]}") + print(f" Freebie new owner: {andrew_freebie.dev.name}") + session.commit() + import ipdb; ipdb.set_trace() diff --git a/lib/freebies.db b/lib/freebies.db index 12beb1c963e832db481e7a7493e3029e691ac4dc..ddf8034e914d48f425cd59f9eb68ba0d06114bd7 100644 GIT binary patch delta 690 zcmaJ-L2DC16rS1L?7B6(&nP9dO>mA41QA;>o@A45+D5aHO;kKcm}F4h&IPiGyee=EVeKVUc@#Z`HY$j1c z2+2IgM|z%}OP0{3yCn_&qF8(%fd+5%4ShPkzx#M0KL6x?Oi8BG_^H;XjSh1|#u^^$ zjk8>^O`~R#nvuV0k|T86&{KJ@&$@M=b{V;2*o7s-&XNgrjdoTUS+;8CqB#T{wpRC? zlSnh@KA`?ON4J0Jsf}o=P_e2t+u&owZP&-E>&MKalKUdXift}0TI7a#Z}ymwA+}jG zZPO~4RWgDj@~r1%{ne3= z=n;jcS82?j3A<9 zF{FN5!6KS8e4j<*3T#E5zQad&3p?-vwz$Y62z5n9Ndc?3Rsx?{MABp#T@WzN)0X%{ z67`sjCV9IQ1P&gE(s@ZnY2I5wpEZJ@jkAK75Qmt0yW0p^r$g~TI4f`!tm5)&%Mmmj Ntx(kkkA~|w`wvt0xvl^J delta 120 zcmZoTz}T>Wae}lUD+2=q2*UvLL>*&MRtCLzSzi7h3@m(74E((OJNfGQq&5o*EaTlQ r#dk}P$285{DB08^Db2(pd6U8yej#K5UXW1&K-Ks8Cr*%NL*)VhkJ1_o diff --git a/lib/migrations/versions/0a8c798ff248_create_freebies_table.py b/lib/migrations/versions/0a8c798ff248_create_freebies_table.py new file mode 100644 index 000000000..7f02e8afb --- /dev/null +++ b/lib/migrations/versions/0a8c798ff248_create_freebies_table.py @@ -0,0 +1,37 @@ +"""Create freebies table + +Revision ID: 0a8c798ff248 +Revises: 5f72c58bf48c +Create Date: 2025-05-24 16:16:06.410337 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '0a8c798ff248' +down_revision = '5f72c58bf48c' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + 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=op.f('fk_freebies_company_id_companies')), + sa.ForeignKeyConstraint(['dev_id'], ['devs.id'], name=op.f('fk_freebies_dev_id_devs')), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('freebies') + # ### end Alembic commands ### diff --git a/lib/models.py b/lib/models.py index 2681bee5a..b26fd49fd 100644 --- a/lib/models.py +++ b/lib/models.py @@ -1,6 +1,5 @@ -from sqlalchemy import ForeignKey, Column, Integer, String, MetaData -from sqlalchemy.orm import relationship, backref -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import ForeignKey, Column, Integer, String, MetaData, create_engine +from sqlalchemy.orm import relationship, sessionmaker, declarative_base convention = { "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", @@ -9,21 +8,84 @@ Base = declarative_base(metadata=metadata) +engine = create_engine('sqlite:///freebies.db') +Session = sessionmaker(bind=engine) +session = Session() class Company(Base): __tablename__ = 'companies' id = Column(Integer(), primary_key=True) name = Column(String()) founding_year = Column(Integer()) + + freebies = relationship('Freebie', back_populates='company') def __repr__(self): return f'' + + def give_freebie(self, dev, item_name, value, session): + + new_freebie = Freebie( + dev=dev, + company=self, + item_name=item_name, + value=value + ) + session.add(new_freebie) + session.commit() + return new_freebie + + @classmethod + def oldest_company(cls): + result = session.query(cls).order_by(cls.founding_year.asc()).first() + return result + + @property + def devs(self): + return list(set([freebie.dev for freebie in self.freebies])) class Dev(Base): __tablename__ = 'devs' id = Column(Integer(), primary_key=True) name= Column(String()) + + freebies = relationship('Freebie', back_populates='dev') def __repr__(self): return f'' + + @property + def companies(self): + return list(set([freebie.company for freebie in self.freebies])) + + 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 in self.freebies: + session = Session() + + freebie.dev = dev + session.commit() + return True + return False + +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 __repr__(self): + return f'' + + def print_details(self): + return f"{self.dev.name} owns a {self.item_name} from {self.company.name}." diff --git a/lib/seed.py b/lib/seed.py index b16becbbb..80c2f7822 100644 --- a/lib/seed.py +++ b/lib/seed.py @@ -1,3 +1,44 @@ #!/usr/bin/env python3 -# Script goes here! +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from models import Base, Company, Dev, Freebie + +engine = create_engine('sqlite:///freebies.db') +Base.metadata.create_all(engine) +Session = sessionmaker(bind=engine) +session = Session() + +session.query(Company).delete() +session.query(Dev).delete() +session.query(Freebie).delete() +session.commit() + +moringa = Company(name="Moringa", founding_year=2014) +safaricom = Company(name="Safaricom", founding_year=1997) +britam = Company(name="Britam", founding_year=1965) +microsoft = Company(name="Microsoft", founding_year=1975) + +session.add_all([moringa, safaricom, britam, microsoft]) +session.commit() + +anne = Dev(name="Anne") +frank = Dev(name="Frank") +andrew = Dev(name="Andrew") +thomas = Dev(name="Thomas") + +session.add_all([anne, frank, andrew, thomas]) +session.commit() + +freebies = [ + Freebie(dev_id=anne.id, company_id=moringa.id, item_name="Diary", value=300), + Freebie(dev_id=anne.id, company_id=safaricom.id, item_name="Mug", value=100), + Freebie(dev_id=frank.id, company_id=moringa.id, item_name="Umbrella", value=500), + Freebie(dev_id=frank.id, company_id=britam.id, item_name="Notebook", value=300), + Freebie(dev_id=andrew.id, company_id=microsoft.id, item_name="Hood", value=500), + Freebie(dev_id=thomas.id, company_id=britam.id, item_name="Bag", value=1000), + Freebie(dev_id=thomas.id, company_id=moringa.id, item_name="Phone", value=20000) +] +session.add_all(freebies) +session.commit() +session.close() From 745dc6c52b6c602437351df8a4181e4000943a1d Mon Sep 17 00:00:00 2001 From: Enock Tangus Date: Sun, 25 May 2025 13:29:02 +0300 Subject: [PATCH 2/3] fix session handling --- lib/__pycache__/models.cpython-38.pyc | Bin 3760 -> 3648 bytes lib/alembic.ini | 2 +- lib/debug.py | 20 ++++++++++---------- lib/freebies.db | Bin 24576 -> 24576 bytes lib/models.py | 13 +++---------- lib/seed.py | 2 +- 6 files changed, 15 insertions(+), 22 deletions(-) diff --git a/lib/__pycache__/models.cpython-38.pyc b/lib/__pycache__/models.cpython-38.pyc index 519be4f875be541ad52acdda1c74ab5ad182d838..73fa6c066a8a915ef177713f05a07fdde1c1d4b6 100644 GIT binary patch delta 1509 zcma)*&ubGw6vuaFH=AUWjZuqQ+r;{#;#Lf`Vrw-1H~ ze;m|b@8_rLl;3_=FvM|z3$$z%FB$;ytNor{1IEjmV^Gu{y!VcQ_?ws^hVsML87=~QZM z?ohD-4SIz!#}r#(EV3xuP=-K)sLy@h^%_Bhk5V_grq8r3K!MG^TbOZZ}Czp&Z2lPO%)_k!8)(K3({dTRjI`x!S zW880*t6^r_i)a%L;G9Tf7&bX` zBauT{$pi@y`#~n;qu6M645w=?whjyj<-6G9y~8kCA|YgIv11tX`$R!Jf0Z}*?WQOk zmQUi7Ijj<(s_;}~DpwU0;wN~O1A(mUHTb0b7SGHfL(312kt@X%ve2Wzl6J!s*&gZ9 zGU@3HK+_^28Y3l*0auP*JU8v=VSm((*bZ@y@y8Vzg%66XRiy~x0QVd(S8i3hdGPVo zl_wT4;Wfyt4RsIsM~|YD78AJAA(Tm!!zh@qz{JH7ln9DqXB9R_(SVf|$5HTzn9rua z8dLzwh}@qTAO(3Q@qA1nfrSkbnT;Z&IhV~Q!<*o8oCypQ2n|4$Nfvf0UR34RYB7?0 zR^CmvCsfT;!m444n>8W=yD8j8tIT+-;@13<9I=OU|632W@{qh^@7SldQ=6#EbP^L* zkgSNp6i+=R-`JTbj*8BD`PIIBT3w;=sH!Y0L29HJi{wL^xG~KcHMWazX4L!G$Xlyf-$s6#2kf^YhHSH*em@@6D^l zmrLmnQYl-5?=S26m+kv?WpxMtWzuv>$F;*W0{KPW_v&Xo_jhQeA4tnzEvm`J`$YodOXOpU6(}0 zuIIBxZ|dSt-w}h5MfoHBkerv6ev_=p9eufC^y!I4v~CP+(XwkqI^zdo2E2|EV6j#6 z>n$F|4(iQ)?&{(k3iLW-k=basT3+ayVgdHVC4?NpitOw2Hy3fLU6Sx@ZBU|g8X)e? z%*kI&HiyO@h$%o-%t7I1ADK3ZPSbL^-Ntf1WSMTfC z7YsVRAAV1P6yIFAy&u$^yMkpd+I0EAkZz04G6uHjuY6k_7=v7VJ#c2s) zT&huu#oHh#$Up3b7|!sukkiS}9qe@#FwjMQn_NhuRLmk|fG;=liDGH+*yMzwjw-^W zY9q}b$~9+yQ#}*P*&NzY6q;}%N_B+ihc(8-y4MV<@;7HS|9^9#EU(Db)aCcpb?Oq; zY4`EYNg2RU--8jL?zoY%BugEF?WB68?9Rv+sYj0@llyy~&&55ohp&z5GL^?cQ%$%d jvWl%X+i&u1f)`<%<;aXqHTsXC+tj8OGJ#}QvJ3wLB!(v% diff --git a/lib/alembic.ini b/lib/alembic.ini index 953863ddd..a76567e6c 100644 --- a/lib/alembic.ini +++ b/lib/alembic.ini @@ -55,7 +55,7 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne # are written from script.py.mako # output_encoding = utf-8 -sqlalchemy.url = sqlite:///freebies.db +sqlalchemy.url = sqlite:///lib/freebies.db [post_write_hooks] diff --git a/lib/debug.py b/lib/debug.py index 9a11a12b4..5611d23db 100644 --- a/lib/debug.py +++ b/lib/debug.py @@ -5,7 +5,7 @@ from models import Base, Company, Dev, Freebie if __name__ == '__main__': - engine = create_engine('sqlite:///freebies.db') + engine = create_engine('sqlite:///lib/freebies.db') Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() @@ -14,11 +14,11 @@ devs = session.query(Dev).all() freebies = session.query(Freebie).all() - print("---Testing Freebie Tracker---") + print("-----Testing Freebie Tracker-----") - print(f"Companies: {len(companies)}") - print(f"Devs: {len(devs)}") - print(f"Freebies: {len(freebies)}") + print(f"Total Companies: {len(companies)}") + print(f"Total Devs: {len(devs)}") + print(f"Total Freebies: {len(freebies)}") print(f"\nFirst company: {companies[0].name}") print(f" First company's freebies: {[freebie.item_name for freebie in companies[0].freebies]}") @@ -30,9 +30,9 @@ print(f"\nFirst freebie details: {freebies[0].print_details()}") - print(f"\nOldest company: {Company.oldest_company().name} (founded {Company.oldest_company().founding_year})") - print(f"Does {devs[0].name} have a T-shirt? {devs[0].received_one('T-shirt')}") - print(f"Does {devs[0].name} have a Laptop? {devs[0].received_one('Laptop')}") + print(f"\nOldest company: {Company.oldest_company(session).name} (founded {Company.oldest_company(session).founding_year})") + print(f"Does {devs[0].name} have a Diary? {devs[0].received_one('Diary')}") + print(f"Does {devs[0].name} have a Umbrella? {devs[0].received_one('Umbrella')}") moringa = session.query(Company).filter_by(name="Moringa").first() @@ -59,13 +59,13 @@ print(f" Frank's freebies before: {[freebie.item_name for freebie in frank.freebies]}") print(f" Freebie owner before: {andrew_freebie.dev.name}") - result = andrew.give_away(frank, andrew_freebie) + result = andrew.give_away(frank, andrew_freebie, session) session.refresh(andrew) session.refresh(frank) session.refresh(andrew_freebie) - print(f"\n Andrew's freebies after: {[freebie.item_name for freebie in andrew.freebies]}") + print(f"\n Andrew's freebies after: {[freebie.item_name for freebie in andrew.freebies]}") print(f" frank's freebies after: {[freebie.item_name for freebie in frank.freebies]}") print(f" Freebie new owner: {andrew_freebie.dev.name}") session.commit() diff --git a/lib/freebies.db b/lib/freebies.db index ddf8034e914d48f425cd59f9eb68ba0d06114bd7..d33e94dfc826e61652adb57f31b293f7b2f75e52 100644 GIT binary patch delta 19 acmZoTz}Rqrae_2s$V3@u#*mE(3*rGqR0h}p delta 19 acmZoTz}Rqrae_3X*F+g-Mz4(t3*rGpz6Qhq diff --git a/lib/models.py b/lib/models.py index b26fd49fd..3bc6df0cd 100644 --- a/lib/models.py +++ b/lib/models.py @@ -8,9 +8,6 @@ Base = declarative_base(metadata=metadata) -engine = create_engine('sqlite:///freebies.db') -Session = sessionmaker(bind=engine) -session = Session() class Company(Base): __tablename__ = 'companies' @@ -24,7 +21,6 @@ def __repr__(self): return f'' def give_freebie(self, dev, item_name, value, session): - new_freebie = Freebie( dev=dev, company=self, @@ -32,11 +28,10 @@ def give_freebie(self, dev, item_name, value, session): value=value ) session.add(new_freebie) - session.commit() return new_freebie @classmethod - def oldest_company(cls): + def oldest_company(cls, session): result = session.query(cls).order_by(cls.founding_year.asc()).first() return result @@ -62,12 +57,10 @@ def companies(self): def received_one(self, item_name): return any(freebie.item_name == item_name for freebie in self.freebies) - def give_away(self, dev, freebie): + def give_away(self, dev, freebie, session): if freebie in self.freebies: - session = Session() - freebie.dev = dev - session.commit() + session.add(freebie) return True return False diff --git a/lib/seed.py b/lib/seed.py index 80c2f7822..583a25a09 100644 --- a/lib/seed.py +++ b/lib/seed.py @@ -4,7 +4,7 @@ from sqlalchemy.orm import sessionmaker from models import Base, Company, Dev, Freebie -engine = create_engine('sqlite:///freebies.db') +engine = create_engine('sqlite:///lib/freebies.db') Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() From 569ec00a7926f37c8a3b5c574b71b8774375c4e0 Mon Sep 17 00:00:00 2001 From: Enock Tangus Date: Sun, 25 May 2025 17:45:41 +0300 Subject: [PATCH 3/3] remove unused imports --- lib/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/models.py b/lib/models.py index 3bc6df0cd..bdf0d19b0 100644 --- a/lib/models.py +++ b/lib/models.py @@ -1,5 +1,5 @@ -from sqlalchemy import ForeignKey, Column, Integer, String, MetaData, create_engine -from sqlalchemy.orm import relationship, sessionmaker, declarative_base +from sqlalchemy import ForeignKey, Column, Integer, String, MetaData +from sqlalchemy.orm import relationship, declarative_base convention = { "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",