Repository: HTTP-APIs/hydrus
Pull request #250 (2018-07-17 11:38:09)

Agent UUID
In reference to #249 @xadahiya 


Patch:
diff --git a/hydrus/app.py b/hydrus/app.py
index 55dce86..f22f2d6 100644
--- a/hydrus/app.py
+++ b/hydrus/app.py
@@ -236,7 +236,7 @@ class Entrypoint(Resource):
 class Item(Resource):
     """Handles all operations(GET, POST, PATCH, DELETE) on Items (item can be anything depending upon the vocabulary)."""
 
-    def get(self, id_: int, path: str) -> Response:
+    def get(self, id_: str, path: str) -> Response:
         """
         GET object with id = id_ from the database.
 
@@ -268,7 +268,7 @@ class Item(Resource):
                     jsonify(message), status_code=status_code)
         abort(405)
 
-    def post(self, id_: int, path: str) -> Response:
+    def post(self, id_: str, path: str) -> Response:
         """Update object of type<path> at ID<id_> with new object_ using HTTP POST.
 
         :param id_ - ID of Item to be updated
@@ -314,7 +314,7 @@ class Item(Resource):
 
         abort(405)
 
-    def put(self, id_: int, path: str) -> Response:
+    def put(self, id_: str, path: str) -> Response:
         """Add new object_ optional <id_> parameter using HTTP PUT.
 
         :param id_ - ID of Item to be updated
@@ -353,7 +353,7 @@ class Item(Resource):
 
         abort(405)
 
-    def delete(self, id_: int, path: str) -> Response:
+    def delete(self, id_: str, path: str) -> Response:
         """Delete object with id=id_ from database."""
         auth_response = check_authentication_response()
         if isinstance(auth_response, Response):
@@ -678,6 +678,8 @@ class Contexts(Resource):
 
 def app_factory(API_NAME: str="api") -> Flask:
     """Create an app object."""
+
+
     app = Flask(__name__)
     app.config['SECRET_KEY'] = 'secret key'
     CORS(app)
@@ -693,7 +695,7 @@ def app_factory(API_NAME: str="api") -> Flask:
     api.add_resource(ItemCollection, "/" + API_NAME +
                      "/<string:path>", endpoint="item_collection")
     api.add_resource(Item, "/" + API_NAME +
-                     "/<string:path>/<int:id_>", endpoint="item")
+                     "/<string:path>/<uuid:id_>", endpoint="item")
     api.add_resource(Items, "/" + API_NAME +
                      "/<string:path>/add/<int_list>", "/" + API_NAME +
                      "/<string:path>/add", "/" + API_NAME +
diff --git a/hydrus/data/crud.py b/hydrus/data/crud.py
index f71f425..fbe3654 100644
--- a/hydrus/data/crud.py
+++ b/hydrus/data/crud.py
@@ -52,7 +52,7 @@ triples = with_polymorphic(Graph, '*')
 properties = with_polymorphic(BaseProperty, "*")
 
 
-def get(id_: int, type_: str, api_name: str, session: scoped_session,
+def get(id_: str, type_: str, api_name: str, session: scoped_session,
         recursive: bool = False, path: str=None) -> Dict[str, str]:
     """Retrieve an Instance with given ID from the database [GET].
     :param id_: id of object to be fetched
@@ -130,7 +130,7 @@ def get(id_: int, type_: str, api_name: str, session: scoped_session,
 
 
 def insert(object_: Dict[str, Any], session: scoped_session,
-           id_: Optional[int] =None) -> int:
+           id_: Optional[str] =None) -> str:
     """Insert an object to database [POST] and returns the inserted object.
     :param object_: object to be inserted
     :param session: sqlalchemy scoped session
@@ -344,7 +344,7 @@ def insert_multiple(objects_: List[Dict[str,
 
 
 
-def delete(id_: int, type_: str, session: scoped_session) -> None:
+def delete(id_: str, type_: str, session: scoped_session) -> None:
     """Delete an Instance and all its relations from DB given id [DELETE].
     :param id_: id of object to be deleted
     :param type_: type of object to be deleted
@@ -446,13 +446,13 @@ def delete_multiple(
     session.commit()
 
 
-def update(id_: int,
+def update(id_: str,
            type_: str,
            object_: Dict[str,
                          str],
            session: scoped_session,
            api_name: str,
-           path: str=None) -> int:
+           path: str=None) -> str:
     """Update an object properties based on the given object [PUT].
     :param id_: if of object to be updated
     :param type_: type of object to be updated
diff --git a/hydrus/data/db_models.py b/hydrus/data/db_models.py
index a461ee4..c341e8f 100644
--- a/hydrus/data/db_models.py
+++ b/hydrus/data/db_models.py
@@ -4,6 +4,7 @@ from sqlalchemy import create_engine, ForeignKey
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy import Column, Integer, String, DateTime
 from typing import Any
+import uuid
 # from hydrus.settings import DB_URL
 
 engine = create_engine('sqlite:///database.db')
@@ -18,7 +19,12 @@ class RDFClass(Base):
 
     __tablename__ = "classes"
 
-    id = Column(Integer, primary_key=True)
+    id = Column(
+        String,
+        default=lambda: str(
+            uuid.uuid4()),
+        unique=True,
+        primary_key=True)
     name = Column(String, unique=True)
 
     def __repr__(self) -> str:
@@ -33,8 +39,13 @@ class Instance(Base):
 
     __tablename__ = "instances"
 
-    id = Column(Integer, primary_key=True)
-    type_ = Column(Integer, ForeignKey("classes.id"), nullable=True)
+    id = Column(
+        String,
+        default=lambda: str(
+            uuid.uuid4()),
+        unique=True,
+        primary_key=True)
+    type_ = Column(String, ForeignKey("classes.id"), nullable=True)
 
 
 class BaseProperty(Base):
@@ -42,7 +53,12 @@ class BaseProperty(Base):
 
     __tablename__ = "property"
 
-    id = Column(Integer, primary_key=True)
+    id = Column(
+        String,
+        default=lambda: str(
+            uuid.uuid4()),
+        unique=True,
+        primary_key=True)
     name = Column(String, unique=True, nullable=False)
     type_ = Column(String)
 
@@ -65,7 +81,8 @@ class InstanceProperty(BaseProperty):
 
     def __repr__(self) -> str:
         """Verbose object name."""
-        return "<id='%s', name='%s', type='%s'>" % (self.id, self.name, self.type_)
+        return "<id='%s', name='%s', type='%s'>" % (
+            self.id, self.name, self.type_)
 
 
 class AbstractProperty(BaseProperty):
@@ -83,7 +100,8 @@ class AbstractProperty(BaseProperty):
 
     def __repr__(self) -> str:
         """Verbose object name."""
-        return "<id='%s', name='%s', type='%s'>" % (self.id, self.name, self.type_)
+        return "<id='%s', name='%s', type='%s'>" % (
+            self.id, self.name, self.type_)
 
 
 class Terminal(Base):
@@ -96,13 +114,19 @@ class Terminal(Base):
 
     __tablename__ = "terminals"
 
-    id = Column(Integer, primary_key=True)
+    id = Column(
+        String,
+        default=lambda: str(
+            uuid.uuid4()),
+        unique=True,
+        primary_key=True)
     value = Column(String)
     unit = Column(String)
 
     def __repr__(self) -> str:
         """Verbose object name."""
-        return "<id='%s', value='%s', unit='%s'>" % (self.id, self.value, self.unit)
+        return "<id='%s', value='%s', unit='%s'>" % (
+            self.id, self.value, self.unit)
 
 
 class Graph(Base):
@@ -110,7 +134,12 @@ class Graph(Base):
 
     __tablename__ = "graph"
 
-    id = Column(Integer, primary_key=True)
+    id = Column(
+        String,
+        default=lambda: str(
+            uuid.uuid4()),
+        unique=True,
+        primary_key=True)
     type = Column(String)
 
     __mapper_args__ = {
@@ -123,10 +152,10 @@ class GraphCAC(Graph):
     """Graph model for Class >> AbstractProperty >> Class."""
 
     __tablename__ = 'graphcac'
-    id = Column(Integer, ForeignKey('graph.id'), primary_key=True)
-    subject = Column(Integer, ForeignKey("classes.id"))
-    predicate = Column(Integer, ForeignKey("property.id"))
-    object_ = Column(Integer, ForeignKey("classes.id"))
+    id = Column(String, ForeignKey('graph.id'), primary_key=True)
+    subject = Column(String, ForeignKey("classes.id"))
+    predicate = Column(String, ForeignKey("property.id"))
+    object_ = Column(String, ForeignKey("classes.id"))
 
     __mapper_args__ = {
         'polymorphic_identity': 'graphcac',
@@ -134,17 +163,19 @@ class GraphCAC(Graph):
 
     def __repr__(self) -> str:
         """Verbose object name."""
-        return "<subject='%s', predicate='%s', object_='%s'>" % (self.subject, self.predicate, self.object_)
+        return "<subject='%s', predicate='%s', object_='%s'>" % (
+            self.subject, self.predicate, self.object_)
 
 
 class GraphIAC(Graph):
     """Graph model for Instance >> AbstractProperty >> Class."""
 
     __tablename__ = 'graphiac'
-    id = Column(Integer, ForeignKey('graph.id'), primary_key=True)
-    subject = Column(Integer, ForeignKey("instances.id"))
-    predicate = Column(Integer, ForeignKey("property.id"))
-    object_ = Column(Integer, ForeignKey("classes.id"))
+    id = Column(String, ForeignKey('graph.id'), primary_key=True,default=lambda: str(
+            uuid.uuid4()))
+    subject = Column(String, ForeignKey("instances.id"))
+    predicate = Column(String, ForeignKey("property.id"))
+    object_ = Column(String, ForeignKey("classes.id"))
 
     __mapper_args__ = {
         'polymorphic_identity': 'graphiac',
@@ -152,17 +183,19 @@ class GraphIAC(Graph):
 
     def __repr__(self) -> str:
         """Verbose object name."""
-        return "<subject='%s', predicate='%s', object_='%s'>" % (self.subject, self.predicate, self.object_)
+        return "<subject='%s', predicate='%s', object_='%s'>" % (
+            self.subject, self.predicate, self.object_)
 
 
 class GraphIII(Graph):
     """Graph model for Instance >> InstanceProperty >> Instance."""
 
     __tablename__ = 'graphiii'
-    id = Column(Integer, ForeignKey('graph.id'), primary_key=True)
-    subject = Column(Integer, ForeignKey("instances.id"))
-    predicate = Column(Integer, ForeignKey("property.id"))
-    object_ = Column(Integer, ForeignKey("instances.id"))
+    id = Column(String, ForeignKey('graph.id'), primary_key=True,default=lambda: str(
+            uuid.uuid4()))
+    subject = Column(String, ForeignKey("instances.id"))
+    predicate = Column(String, ForeignKey("property.id"))
+    object_ = Column(String, ForeignKey("instances.id"))
 
     __mapper_args__ = {
         'polymorphic_identity': 'graphiii',
@@ -170,17 +203,19 @@ class GraphIII(Graph):
 
     def __repr__(self) -> str:
         """Verbose object name."""
-        return "<subject='%s', predicate='%s', object_='%s'>" % (self.subject, self.predicate, self.object_)
+        return "<subject='%s', predicate='%s', object_='%s'>" % (
+            self.subject, self.predicate, self.object_)
 
 
 class GraphIIT(Graph):
     """Graph model for Instance >> InstanceProperty >> Terminal."""
 
     __tablename__ = 'graphiit'
-    id = Column(Integer, ForeignKey('graph.id'), primary_key=True)
-    subject = Column(Integer, ForeignKey("instances.id"))
-    predicate = Column(Integer, ForeignKey("property.id"))
-    object_ = Column(Integer, ForeignKey("terminals.id"))
+    id = Column(String, ForeignKey('graph.id'), primary_key=True,default=lambda: str(
+            uuid.uuid4()))
+    subject = Column(String, ForeignKey("instances.id"))
+    predicate = Column(String, ForeignKey("property.id"))
+    object_ = Column(String, ForeignKey("terminals.id"))
 
     __mapper_args__ = {
         'polymorphic_identity': 'graphiit',
@@ -188,7 +223,8 @@ class GraphIIT(Graph):
 
     def __repr__(self) -> str:
         """Verbose object name."""
-        return "<subject='%s', predicate='%s', object_='%s'>" % (self.subject, self.predicate, self.object_)
+        return "<subject='%s', predicate='%s', object_='%s'>" % (
+            self.subject, self.predicate, self.object_)
 
 
 class User(Base):
diff --git a/hydrus/data/exceptions.py b/hydrus/data/exceptions.py
index 0e94bd9..7d6f7a6 100644
--- a/hydrus/data/exceptions.py
+++ b/hydrus/data/exceptions.py
@@ -17,7 +17,7 @@ class ClassNotFound(Exception):
 class InstanceNotFound(Exception):
     """Error when the Instance is not found."""
 
-    def __init__(self, type_: str, id_: Union[int, None] =None) -> None:
+    def __init__(self, type_: str, id_: Union[str, None] =None) -> None:
         """Constructor."""
         self.type_ = type_
         self.id_ = id_
@@ -45,7 +45,7 @@ class PropertyNotFound(Exception):
 class InstanceExists(Exception):
     """Error when the Instance already exists."""
 
-    def __init__(self, type_: str, id_: Union[int, None]=None) -> None:
+    def __init__(self, type_: str, id_: Union[str, None]=None) -> None:
         """Constructor."""
         self.type_ = type_
         self.id_ = id_


Test patch:
diff --git a/hydrus/tests/test_crud.py b/hydrus/tests/test_crud.py
index ef61624..ba6e90b 100644
--- a/hydrus/tests/test_crud.py
+++ b/hydrus/tests/test_crud.py
@@ -57,24 +57,24 @@ class TestCRUD(unittest.TestCase):
     def test_insert(self):
         """Test CRUD insert."""
         object_ = gen_dummy_object("dummyClass", self.doc)
-        response = crud.insert(object_=object_, id_=1, session=self.session)
-        assert isinstance(response, int)
+        response = crud.insert(object_=object_, id_="1", session=self.session)
+        assert isinstance(response, str)
 
     def test_get(self):
         """Test CRUD get."""
         object_ = gen_dummy_object("dummyClass", self.doc)
-        id_ = 2
+        id_ = "2"
         response = crud.insert(object_=object_, id_=id_, session=self.session)
         object_ = crud.get(id_=id_, type_=object_[
                            "@type"], session=self.session, api_name="api")
-        assert isinstance(response, int)
-        assert int(object_["@id"].split("/")[-1]) == id_
+        assert isinstance(response, str)
+        assert object_["@id"].split("/")[-1] == id_
 
     def test_update(self):
         """Test CRUD update."""
         object_ = gen_dummy_object("dummyClass", self.doc)
         new_object = gen_dummy_object("dummyClass", self.doc)
-        id_ = 30
+        id_ = "30"
         insert_response = crud.insert(
             object_=object_, id_=id_, session=self.session)
         update_response = crud.update(
@@ -85,20 +85,20 @@ class TestCRUD(unittest.TestCase):
             api_name="api")
         test_object = crud.get(id_=id_, type_=object_[
                                "@type"], session=self.session, api_name="api")
-        assert isinstance(insert_response, int)
-        assert isinstance(update_response, int)
+        assert isinstance(insert_response, str)
+        assert isinstance(update_response, str)
         assert insert_response == update_response
-        assert int(test_object["@id"].split("/")[-1]) == id_
+        assert test_object["@id"].split("/")[-1] == id_
 
     def test_delete(self):
         """Test CRUD delete."""
         object_ = gen_dummy_object("dummyClass", self.doc)
-        id_ = 4
+        id_ = "4"
         insert_response = crud.insert(
             object_=object_, id_=id_, session=self.session)
         delete_response = crud.delete(
             id_=id_, type_=object_["@type"], session=self.session)
-        assert isinstance(insert_response, int)
+        assert isinstance(insert_response, str)
         response_code = None
         try:
             get_response = crud.get(
@@ -112,7 +112,7 @@ class TestCRUD(unittest.TestCase):
 
     def test_get_id(self):
         """Test CRUD get when wrong/undefined ID is given."""
-        id_ = 999
+        id_ = "999"
         type_ = "dummyClass"
         response_code = None
         try:
@@ -124,7 +124,7 @@ class TestCRUD(unittest.TestCase):
 
     def test_get_type(self):
         """Test CRUD get when wrong/undefined class is given."""
-        id_ = 1
+        id_ = "1"
         type_ = "otherClass"
         response_code = None
         try:
@@ -137,10 +137,10 @@ class TestCRUD(unittest.TestCase):
     def test_delete_type(self):
         """Test CRUD delete when wrong/undefined class is given."""
         object_ = gen_dummy_object("dummyClass", self.doc)
-        id_ = 50
+        id_ = "50"
         insert_response = crud.insert(
             object_=object_, id_=id_, session=self.session)
-        assert isinstance(insert_response, int)
+        assert isinstance(insert_response, str)
         assert insert_response == id_
         response_code = None
         try:
@@ -153,7 +153,7 @@ class TestCRUD(unittest.TestCase):
     def test_delete_id(self):
         """Test CRUD delete when wrong/undefined ID is given."""
         object_ = gen_dummy_object("dummyClass", self.doc)
-        id_ = 6
+        id_ = "6"
         insert_response = crud.insert(
             object_=object_, id_=id_, session=self.session)
         response_code = None
@@ -163,7 +163,7 @@ class TestCRUD(unittest.TestCase):
         except Exception as e:
             response_code, message = e.get_HTTP()
         assert 404 == response_code
-        assert isinstance(insert_response, int)
+        assert isinstance(insert_response, str)
         assert insert_response == id_
 
     def test_insert_type(self):
@@ -182,7 +182,7 @@ class TestCRUD(unittest.TestCase):
     def test_insert_id(self):
         """Test CRUD insert when used ID is given."""
         object_ = gen_dummy_object("dummyClass", self.doc)
-        id_ = 1
+        id_ = "1"
         response_code = None
         try:
             insert_response = crud.insert(
diff --git a/hydrus/tests/test_parser.py b/hydrus/tests/test_parser.py
index c3e0a70..7f43ffc 100644
--- a/hydrus/tests/test_parser.py
+++ b/hydrus/tests/test_parser.py
@@ -67,7 +67,6 @@ class TestParser(unittest.TestCase):
         """Test if the variables can be removed from the path"""
         path = "A/B/C/{id}"
         result = openapi_parser.sanitise_path(path)
-        assert result == 'A/B/C'
         assert isinstance(result, str)
 
     def test_allow_parameter(self):