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. 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 ## Installation

View File

@ -30,17 +30,29 @@ class Association(Base):
relationship_id = Column(Integer, relationship_id = Column(Integer,
ForeignKey("relationships.id", ForeignKey("relationships.id",
ondelete="CASCADE")) 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") relationship = sqlalchemy_relationship("Relationship")
left_paper = sqlalchemy_relationship("Paper",
foreign_keys=left_id,
back_populates="related_to")
class Paper(Base): class Paper(Base):
__tablename__ = "papers" __tablename__ = "papers"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
doi = Column(String(), nullable=True, unique=True) doi = Column(String(), nullable=True, unique=True)
arxiv_id = Column(String(25), nullable=True, unique=True) arxiv_id = Column(String(25), nullable=True, unique=True)
related = sqlalchemy_relationship("Association", # related_to are papers related to this paper (this_paper R …)
foreign_keys="Association.left_id") 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): def __repr__(self):
return "<Paper(id='%d', doi='%s', arxiv_id='%s')>" % ( return "<Paper(id='%d', doi='%s', arxiv_id='%s')>" % (
@ -53,6 +65,7 @@ class Paper(Base):
""" """
Dict to dump for the JSON API. Dict to dump for the JSON API.
""" """
relationships = [a.relationship.name for a in self.related_to]
return { return {
"types": self.__tablename__, "types": self.__tablename__,
"id": self.id, "id": self.id,
@ -64,7 +77,15 @@ class Paper(Base):
"self": "/papers/%d" % (self.id,) "self": "/papers/%d" % (self.id,)
}, },
"relationships": { "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>", callback=routes.get.fetch_by_id)
app.get("/papers/<id:int>/relationships/<name>", app.get("/papers/<id:int>/relationships/<name>",
callback=routes.get.fetch_relationship) callback=routes.get.fetch_relationship)
app.get("/papers/<id:int>/<name>",
# TODO: Fetch relationships callback=routes.get.fetch_relationship)
app.post("/papers", callback=routes.post.create_paper) app.post("/papers", callback=routes.post.create_paper)

View File

@ -36,7 +36,12 @@ def fetch_papers(db):
"self": "/papers/1" "self": "/papers/1"
}, },
"relationships": { "relationships": {
TODO "cite": {
"links": {
"related": "/papers/1/relationships/cite"
}
},
} }
} }
] ]
@ -62,7 +67,7 @@ def fetch_by_id(id, db):
.. code-block:: bash .. code-block:: bash
GET /id/<id> GET /papers/1
Accept: application/vnd.api+json Accept: application/vnd.api+json
@ -70,24 +75,27 @@ def fetch_by_id(id, db):
{ {
"data": { "data": {
{ "type": "papers",
"type": "papers", "id": 1,
"id": 1, "attributes": {
"attributes": { "doi": "10.1126/science.1252319",
"doi": "10.1126/science.1252319", "arxiv_id": "1401.2910"
"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. :param db: A database session, injected by the ``Bottle`` plugin.
:returns: An ``HTTPResponse``. :returns: An ``HTTPResponse``.
""" """
@ -101,6 +109,55 @@ def fetch_by_id(id, db):
def fetch_relationship(id, name, 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 # Update the relationship
a = database.Association(relationship_id=relationship.id) a = database.Association(relationship_id=relationship.id)
a.right_paper = right_paper a.right_paper = right_paper
left_paper.related.append(a) left_paper.related_to.append(a)
try: try:
db.add(a) db.add(a)
db.add(left_paper) db.add(left_paper)