repertory-api/app/models.py
2026-06-09 15:07:08 -04:00

175 lines
7.1 KiB
Python

from sqlalchemy import Boolean, Column, Date, ForeignKey, Integer, String, Table, UniqueConstraint
from app.extensions import db
# ── Many-to-many: references ↔ musicians ─────────────────────
reference_musicians = Table(
"reference_musicians",
db.metadata,
Column("reference_id", Integer, ForeignKey("references.id", ondelete="CASCADE"), primary_key=True),
Column("musician_id", Integer, ForeignKey("musicians.id", ondelete="CASCADE"), primary_key=True),
)
class Musician(db.Model):
__tablename__ = "musicians"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=False)
references = db.relationship("Reference", secondary=reference_musicians, back_populates="musicians")
instrument_entries = db.relationship("TuneByInstrument", back_populates="learned_from_musician")
def to_dict(self):
return {"id": self.id, "name": self.name}
class Source(db.Model):
__tablename__ = "sources"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=False)
tunes = db.relationship("Tune", back_populates="source")
def to_dict(self):
return {"id": self.id, "name": self.name}
class Instrument(db.Model):
__tablename__ = "instruments"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=False, unique=True)
entries = db.relationship("TuneByInstrument", back_populates="instrument")
def to_dict(self):
return {"id": self.id, "name": self.name}
class Tuning(db.Model):
__tablename__ = "tunings"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=False, unique=True)
entries = db.relationship("TuneByInstrument", back_populates="tuning")
def to_dict(self):
return {"id": self.id, "name": self.name}
class Tune(db.Model):
__tablename__ = "tunes"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=True)
key = Column(String, nullable=True)
modal = Column(Boolean, nullable=True)
source_id = Column(Integer, ForeignKey("sources.id", ondelete="SET NULL"), nullable=True)
source = db.relationship("Source", back_populates="tunes")
instruments = db.relationship("TuneByInstrument", back_populates="tune", cascade="all, delete-orphan")
notes = db.relationship("TuneNote", back_populates="tune", cascade="all, delete-orphan")
references = db.relationship("Reference", back_populates="tune", cascade="all, delete-orphan")
def to_dict(self):
return {
"id": self.id,
"name": self.name,
"key": self.key,
"modal": self.modal,
"source_id": self.source_id,
"source": self.source.to_dict() if self.source else None,
"instruments": [i.to_dict() for i in self.instruments],
"notes": [n.to_dict() for n in self.notes],
"references": [r.to_dict() for r in self.references],
}
class TuneByInstrument(db.Model):
__tablename__ = "tune_by_instrument"
__table_args__ = (UniqueConstraint("tune_id", "instrument_id", name="uq_tune_instrument"),)
id = Column(Integer, primary_key=True, autoincrement=True)
tune_id = Column(Integer, ForeignKey("tunes.id", ondelete="CASCADE"), nullable=False)
instrument_id = Column(Integer, ForeignKey("instruments.id", ondelete="CASCADE"), nullable=False)
learned_from_id = Column(Integer, ForeignKey("musicians.id", ondelete="SET NULL"), nullable=True)
tuning_id = Column(Integer, ForeignKey("tunings.id", ondelete="SET NULL"), nullable=True)
date_learned = Column(Date, nullable=True)
callable = Column(Boolean, nullable=True)
review = Column(Boolean, nullable=True)
to_learn = Column(Boolean, nullable=True, default=False)
difficulty = Column(String, nullable=True)
tune = db.relationship("Tune", back_populates="instruments")
instrument = db.relationship("Instrument", back_populates="entries")
tuning = db.relationship("Tuning", back_populates="entries")
learned_from_musician = db.relationship("Musician", back_populates="instrument_entries")
notes = db.relationship("TuneByInstrumentNote", back_populates="entry", cascade="all, delete-orphan")
def to_dict(self):
return {
"id": self.id,
"tune_id": self.tune_id,
"instrument_id": self.instrument_id,
"instrument_name": self.instrument.name if self.instrument else None,
"learned_from_id": self.learned_from_id,
"learned_from": self.learned_from_musician.name if self.learned_from_musician else None,
"date_learned": self.date_learned.isoformat() if self.date_learned else None,
"tuning_id": self.tuning_id,
"tuning": self.tuning.name if self.tuning else None,
"callable": self.callable,
"review": self.review,
"to_learn": self.to_learn,
"difficulty": self.difficulty,
"notes": [n.to_dict() for n in self.notes],
}
class TuneNote(db.Model):
__tablename__ = "tune_notes"
id = Column(Integer, primary_key=True, autoincrement=True)
tune_id = Column(Integer, ForeignKey("tunes.id", ondelete="CASCADE"), nullable=False)
note = Column(String, nullable=True)
tune = db.relationship("Tune", back_populates="notes")
def to_dict(self):
return {"id": self.id, "tune_id": self.tune_id, "note": self.note}
class TuneByInstrumentNote(db.Model):
__tablename__ = "tune_by_instrument_notes"
id = Column(Integer, primary_key=True, autoincrement=True)
tune_by_instrument_id = Column(Integer, ForeignKey("tune_by_instrument.id", ondelete="CASCADE"), nullable=False)
note = Column(String, nullable=True)
entry = db.relationship("TuneByInstrument", back_populates="notes")
def to_dict(self):
return {"id": self.id, "tune_by_instrument_id": self.tune_by_instrument_id, "note": self.note}
class Reference(db.Model):
__tablename__ = "references"
id = Column(Integer, primary_key=True, autoincrement=True)
tune_id = Column(Integer, ForeignKey("tunes.id", ondelete="CASCADE"), nullable=True)
link = Column(String, nullable=True)
site = Column(String, nullable=True)
tune = db.relationship("Tune", back_populates="references")
musicians = db.relationship("Musician", secondary=reference_musicians, back_populates="references")
def to_dict(self):
return {
"id": self.id,
"tune_id": self.tune_id,
"link": self.link,
"site": self.site,
"musicians": [m.to_dict() for m in self.musicians],
}