2015-12-24 20:34:34 +01:00
|
|
|
"""
|
|
|
|
This file contains the database schema in SQLAlchemy format.
|
|
|
|
"""
|
2015-12-25 22:07:06 +01:00
|
|
|
import sqlite3
|
|
|
|
|
2015-12-25 20:09:56 +01:00
|
|
|
from sqlalchemy import event
|
2015-12-26 01:25:38 +01:00
|
|
|
from sqlalchemy import Column, ForeignKey, Integer, String, Table
|
2015-12-25 01:43:49 +01:00
|
|
|
from sqlalchemy.engine import Engine
|
2015-12-24 20:34:34 +01:00
|
|
|
from sqlalchemy.ext.declarative import declarative_base
|
2015-12-25 20:09:56 +01:00
|
|
|
from sqlalchemy.orm import relationship as sqlalchemy_relationship
|
2015-12-24 20:34:34 +01:00
|
|
|
|
|
|
|
Base = declarative_base()
|
|
|
|
|
|
|
|
|
2015-12-25 01:43:49 +01:00
|
|
|
@event.listens_for(Engine, "connect")
|
|
|
|
def set_sqlite_pragma(dbapi_connection, connection_record):
|
|
|
|
"""
|
|
|
|
Auto enable foreign keys for SQLite.
|
|
|
|
"""
|
2015-12-25 22:07:06 +01:00
|
|
|
# Play well with other DB backends
|
|
|
|
if type(dbapi_connection) is sqlite3.Connection:
|
|
|
|
cursor = dbapi_connection.cursor()
|
|
|
|
cursor.execute("PRAGMA foreign_keys=ON")
|
|
|
|
cursor.close()
|
2015-12-25 01:43:49 +01:00
|
|
|
|
|
|
|
|
2015-12-26 01:25:38 +01:00
|
|
|
class RelationshipAssociation(Base):
|
2015-12-25 20:09:56 +01:00
|
|
|
# Relationships are to be read "left RELATION right"
|
2015-12-26 01:25:38 +01:00
|
|
|
__tablename__ = "relationship_association"
|
2015-12-25 20:09:56 +01:00
|
|
|
id = Column(Integer, primary_key=True)
|
|
|
|
left_id = Column(Integer, ForeignKey("papers.id", ondelete="CASCADE"))
|
|
|
|
right_id = Column(Integer, ForeignKey("papers.id", ondelete="CASCADE"))
|
|
|
|
relationship_id = Column(Integer,
|
|
|
|
ForeignKey("relationships.id",
|
|
|
|
ondelete="CASCADE"))
|
2015-12-25 21:38:59 +01:00
|
|
|
right_paper = sqlalchemy_relationship("Paper",
|
|
|
|
foreign_keys=right_id,
|
2015-12-25 22:07:06 +01:00
|
|
|
back_populates="related_by",
|
|
|
|
passive_deletes=True)
|
|
|
|
relationship = sqlalchemy_relationship("Relationship",
|
|
|
|
passive_deletes=True)
|
2015-12-25 20:09:56 +01:00
|
|
|
|
2015-12-25 21:38:59 +01:00
|
|
|
left_paper = sqlalchemy_relationship("Paper",
|
|
|
|
foreign_keys=left_id,
|
2015-12-25 22:07:06 +01:00
|
|
|
back_populates="related_to",
|
|
|
|
passive_deletes=True)
|
2015-12-25 21:38:59 +01:00
|
|
|
|
2015-12-26 01:25:38 +01:00
|
|
|
tag_association_table = Table(
|
|
|
|
'tag_association', Base.metadata,
|
|
|
|
Column('paper_id', Integer, ForeignKey('papers.id', ondelete="CASCADE")),
|
|
|
|
Column('tag_id', Integer, ForeignKey('tags.id', ondelete="CASCADE"))
|
|
|
|
)
|
|
|
|
|
2015-12-25 20:09:56 +01:00
|
|
|
|
2015-12-24 20:34:34 +01:00
|
|
|
class Paper(Base):
|
2015-12-25 20:09:56 +01:00
|
|
|
__tablename__ = "papers"
|
2015-12-24 20:34:34 +01:00
|
|
|
id = Column(Integer, primary_key=True)
|
|
|
|
doi = Column(String(), nullable=True, unique=True)
|
|
|
|
arxiv_id = Column(String(25), nullable=True, unique=True)
|
2015-12-25 21:38:59 +01:00
|
|
|
# related_to are papers related to this paper (this_paper R …)
|
2015-12-26 01:25:38 +01:00
|
|
|
related_to = sqlalchemy_relationship("RelationshipAssociation",
|
|
|
|
foreign_keys="RelationshipAssociation.left_id",
|
2015-12-25 22:07:06 +01:00
|
|
|
back_populates="left_paper",
|
|
|
|
passive_deletes=True)
|
2015-12-25 21:38:59 +01:00
|
|
|
# related_by are papers referenced by this paper (… R this_paper)
|
2015-12-26 01:25:38 +01:00
|
|
|
related_by = sqlalchemy_relationship("RelationshipAssociation",
|
|
|
|
foreign_keys="RelationshipAssociation.right_id",
|
2015-12-25 22:07:06 +01:00
|
|
|
back_populates="right_paper",
|
|
|
|
passive_deletes=True)
|
2015-12-26 01:25:38 +01:00
|
|
|
# Tags relationship
|
|
|
|
tags = sqlalchemy_relationship("Tag",
|
|
|
|
secondary=tag_association_table,
|
|
|
|
backref="papers")
|
2015-12-24 20:34:34 +01:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "<Paper(id='%d', doi='%s', arxiv_id='%s')>" % (
|
|
|
|
self.id,
|
|
|
|
self.doi,
|
|
|
|
self.arxiv_id,
|
|
|
|
)
|
|
|
|
|
2015-12-26 01:25:38 +01:00
|
|
|
def json_api_repr(self, db):
|
2015-12-24 20:34:34 +01:00
|
|
|
"""
|
|
|
|
Dict to dump for the JSON API.
|
|
|
|
"""
|
2015-12-26 01:25:38 +01:00
|
|
|
relationships = [i.name for i in db.query(Relationship).all()]
|
|
|
|
relationships_dict = {
|
|
|
|
k: {
|
|
|
|
"links": {
|
|
|
|
"related": (
|
|
|
|
"/papers/%d/relationships/%s?reverse={reverse}" %
|
|
|
|
(self.id, k)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for k in relationships
|
|
|
|
}
|
|
|
|
relationships_dict["tags"] = {
|
|
|
|
"links": {
|
|
|
|
"related": "/papers/%d/relationships/tags" % (self.id,)
|
|
|
|
}
|
|
|
|
}
|
2015-12-24 20:34:34 +01:00
|
|
|
return {
|
|
|
|
"types": self.__tablename__,
|
|
|
|
"id": self.id,
|
|
|
|
"attributes": {
|
|
|
|
"doi": self.doi,
|
|
|
|
"arxiv_id": self.arxiv_id,
|
|
|
|
},
|
|
|
|
"links": {
|
|
|
|
"self": "/papers/%d" % (self.id,)
|
|
|
|
},
|
2015-12-26 01:25:38 +01:00
|
|
|
"relationships": relationships_dict
|
2015-12-24 20:34:34 +01:00
|
|
|
}
|
2015-12-25 20:09:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
class Relationship(Base):
|
|
|
|
__tablename__ = "relationships"
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
|
|
name = Column(String(), unique=True)
|
2015-12-26 01:25:38 +01:00
|
|
|
associations = sqlalchemy_relationship("RelationshipAssociation",
|
2015-12-25 22:07:06 +01:00
|
|
|
back_populates="relationship",
|
|
|
|
passive_deletes=True)
|
2015-12-26 01:25:38 +01:00
|
|
|
|
|
|
|
|
|
|
|
class Tag(Base):
|
|
|
|
__tablename__ = "tags"
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
|
|
name = Column(String(), unique=True)
|
|
|
|
|
|
|
|
def json_api_repr(self):
|
|
|
|
"""
|
|
|
|
Dict to dump for the JSON API.
|
|
|
|
"""
|
|
|
|
return {
|
|
|
|
"types": self.__tablename__,
|
|
|
|
"id": self.id,
|
|
|
|
"attributes": {
|
|
|
|
"name": self.name,
|
|
|
|
},
|
|
|
|
"links": {
|
|
|
|
"self": "/tags/%d" % (self.id,)
|
|
|
|
}
|
|
|
|
}
|