Add routes to fetch relationships

* Add routes to fetch relationships for a given paper.
* Add backrefs in relationships to be able to get the reversed
relationship.
* Update some doc.
This commit is contained in:
Lucas Verney 2015-12-25 21:38:59 +01:00
parent 48a4b0d8b0
commit e7332e3b91
5 changed files with 103 additions and 25 deletions

View File

@ -3,7 +3,7 @@ Metadata for arXiv
The goal of this repository is to provide a minimal API to put metadata on arXiv papers.
TODO: Better description.
TODO: Better description + API description.
## Installation

View File

@ -30,17 +30,29 @@ class Association(Base):
relationship_id = Column(Integer,
ForeignKey("relationships.id",
ondelete="CASCADE"))
right_paper = sqlalchemy_relationship("Paper", foreign_keys=right_id)
right_paper = sqlalchemy_relationship("Paper",
foreign_keys=right_id,
back_populates="related_by")
relationship = sqlalchemy_relationship("Relationship")
left_paper = sqlalchemy_relationship("Paper",
foreign_keys=left_id,
back_populates="related_to")
class Paper(Base):
__tablename__ = "papers"
id = Column(Integer, primary_key=True)
doi = Column(String(), nullable=True, unique=True)
arxiv_id = Column(String(25), nullable=True, unique=True)
related = sqlalchemy_relationship("Association",
foreign_keys="Association.left_id")
# related_to are papers related to this paper (this_paper R …)
related_to = sqlalchemy_relationship("Association",
foreign_keys="Association.left_id",
back_populates="left_paper")
# related_by are papers referenced by this paper (… R this_paper)
related_by = sqlalchemy_relationship("Association",
foreign_keys="Association.right_id",
back_populates="right_paper")
def __repr__(self):
return "<Paper(id='%d', doi='%s', arxiv_id='%s')>" % (
@ -53,6 +65,7 @@ class Paper(Base):
"""
Dict to dump for the JSON API.
"""
relationships = [a.relationship.name for a in self.related_to]
return {
"types": self.__tablename__,
"id": self.id,
@ -64,7 +77,15 @@ class Paper(Base):
"self": "/papers/%d" % (self.id,)
},
"relationships": {
# TODO
k: {
"links": {
"related": (
"/papers/%d/relationships/%s?reverse={reverse}" %
(self.id, k)
)
}
}
for k in relationships
}
}

View File

@ -45,8 +45,8 @@ app.get("/papers", callback=routes.get.fetch_papers)
app.get("/papers/<id:int>", callback=routes.get.fetch_by_id)
app.get("/papers/<id:int>/relationships/<name>",
callback=routes.get.fetch_relationship)
# TODO: Fetch relationships
app.get("/papers/<id:int>/<name>",
callback=routes.get.fetch_relationship)
app.post("/papers", callback=routes.post.create_paper)

View File

@ -36,7 +36,12 @@ def fetch_papers(db):
"self": "/papers/1"
},
"relationships": {
TODO
"cite": {
"links": {
"related": "/papers/1/relationships/cite"
}
},
}
}
]
@ -62,7 +67,7 @@ def fetch_by_id(id, db):
.. code-block:: bash
GET /id/<id>
GET /papers/1
Accept: application/vnd.api+json
@ -70,24 +75,27 @@ def fetch_by_id(id, db):
{
"data": {
{
"type": "papers",
"id": 1,
"attributes": {
"doi": "10.1126/science.1252319",
"arxiv_id": "1401.2910"
"type": "papers",
"id": 1,
"attributes": {
"doi": "10.1126/science.1252319",
"arxiv_id": "1401.2910"
},
"links": {
"self": "/papers/1"
},
"relationships": {
"cite": {
"links": {
"related": "/papers/1/relationships/cite"
}
},
"links": {
"self": "/papers/1"
},
"relationships": {
TODO
}
}
}
}
:param id: The id of the requested article.
:param id: The id of the requested paper.
:param db: A database session, injected by the ``Bottle`` plugin.
:returns: An ``HTTPResponse``.
"""
@ -101,6 +109,55 @@ def fetch_by_id(id, db):
def fetch_relationship(id, name, db):
"""
TODO
Fetch relationships of the given type associated with the given paper.
.. code-block:: bash
GET /papers/1/relationships/cite
Accept: application/vnd.api+json
.. code-block:: json
{
"links": {
"self": "/papers/1/relationships/cite",
"related": "/papers/1/cite"
},
"data": [
{
"type": "papers",
"id": 2,
},
]
}
:param id: The id of the requested paper.
:param name: The name of the requested relationship for this paper.
:param db: A database session, injected by the ``Bottle`` plugin.
:returns: An ``HTTPResponse``.
"""
pass
reversed = (
"reverse" in bottle.request.params and
bottle.request.params["reverse"] != 0
)
resource = db.query(database.Paper).filter_by(id=id).first()
if resource:
response = {
"links": {
"self": "/papers/%d/relationships/%s" % (id, name),
"related": "/papers/%d/%s" % (id, name),
},
"data": [
]
}
if reversed:
relationships = resource.related_by
else:
relationships = resource.related_to
for r in relationships:
if r.relationship.name == name:
response["data"].append({"type": name, "id": r.right_id})
return tools.APIResponse(tools.pretty_json(response))
return bottle.HTTPError(404, "Not found")

View File

@ -193,7 +193,7 @@ def update_relationship_backend(left_id, right_id, name, db):
# Update the relationship
a = database.Association(relationship_id=relationship.id)
a.right_paper = right_paper
left_paper.related.append(a)
left_paper.related_to.append(a)
try:
db.add(a)
db.add(left_paper)