Skip to content

Instantly share code, notes, and snippets.

@ricky-lim
Last active December 19, 2020 09:39
Show Gist options
  • Save ricky-lim/9da923663417cfebf6a9c745b6a0d09c to your computer and use it in GitHub Desktop.
Save ricky-lim/9da923663417cfebf6a9c745b6a0d09c to your computer and use it in GitHub Desktop.
club-member
import pytest
from sqlalchemy import (
create_engine,
Column,
Integer,
String,
Table,
ForeignKey,
PrimaryKeyConstraint,
)
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine("sqlite:///:memory:")
# engine = create_engine("sqlite:///clubs.sqlite")
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()
member_club = Table(
"member_club",
Base.metadata,
Column("member_id", Integer, ForeignKey("members.id"), nullable=False),
Column("club_id", Integer, ForeignKey("clubs.id")),
PrimaryKeyConstraint("member_id", "club_id"),
)
class Member(Base):
__tablename__ = "members"
id = Column(Integer, primary_key=True)
name = Column(String, unique=True, index=True)
clubs = relationship("Club", secondary=member_club, back_populates="members")
def __repr__(self):
return f"Member({self.name})"
class Club(Base):
__tablename__ = "clubs"
id = Column(Integer, primary_key=True)
name = Column(String, unique=True, index=True)
members = relationship("Member", secondary=member_club, back_populates="clubs")
member_names = association_proxy("members", "name")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.members:
raise ValueError("Club needs at least one member")
def remove_member(self, member_name):
if member_name not in self.member_names:
raise ValueError(f"{member_name} is not a member")
if member_name in self.member_names and len(self.member_names) == 1:
raise ValueError(f"{member_name} is the only member in the club!")
if member_name in self.member_names and len(self.member_names) >= 2:
self.members = [member for member in self.members if member.name != member]
print(f"{member_name} has been removed")
def __repr__(self):
return f"Club({self.name})"
Base.metadata.create_all(bind=engine)
m1 = Member(name="m1")
m2 = Member(name="m2")
m3 = Member(name="m3")
session.add_all([m1, m2, m3])
session.commit()
with pytest.raises(ValueError) as e:
c1 = Club(name="c1")
assert "Club needs at least one member" in str(e)
c1 = Club(name="c1", members=[m1])
session.add(c1)
session.commit()
with pytest.raises(ValueError) as e:
c1.remove_member("m1")
assert "m1 is the only member in the club" in str(e)
c2 = Club(name="c2", members=[m1, m2])
session.add(c2)
session.commit()
c2.remove_member("m1")
c3 = Club(name="c3", members=[m2, m3])
session.add(c3)
session.commit()
with pytest.raises(ValueError) as e:
c3.remove_member("m1")
assert "m1 is not a member" in str(e)
# Adding duplicated members
c4 = Club(name="c4", members=[m1, m2, m3, m3])
try:
session.add(c4)
session.commit()
except IntegrityError as e:
session.rollback()
if "UNIQUE constraint failed" in str(e):
print("Adding duplicated members are not allowed")
print(f"{c4} not addedd")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment