References sites table updated so we can filter by site later, added timestamp to tunes so they can be sorted in certain contexts, enforced uniqueness on some tables that were causing issues
192 lines
7.9 KiB
Python
192 lines
7.9 KiB
Python
from sqlalchemy import Boolean, Column, Date, DateTime, ForeignKey, Integer, String, Table, UniqueConstraint
|
|
from sqlalchemy.sql import func
|
|
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, unique=True)
|
|
|
|
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, unique=True)
|
|
|
|
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)
|
|
created_at = Column(DateTime(timezone=True), server_default=func.now(), 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,
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|
"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 ReferenceSite(db.Model):
|
|
__tablename__ = "reference_sites"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
name = Column(String, nullable=False, unique=True)
|
|
|
|
references = db.relationship("Reference", back_populates="site")
|
|
|
|
def to_dict(self):
|
|
return {"id": self.id, "name": self.name}
|
|
|
|
|
|
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_id = Column(Integer, ForeignKey("reference_sites.id", ondelete="SET NULL"), nullable=True)
|
|
|
|
tune = db.relationship("Tune", back_populates="references")
|
|
site = db.relationship("ReferenceSite", 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_id": self.site_id,
|
|
"site": self.site.to_dict() if self.site else None,
|
|
"musicians": [m.to_dict() for m in self.musicians],
|
|
}
|