def __init__(self):
     self.books = []
     self.books.append(
         Resource('book', {
             'id': '1',
             'title': 'Book Number 1'
         }))
     self.books.append(
         Resource('book', {
             'id': '2',
             'title': 'Book Number 1'
         }))
     self.books.append(
         Resource('book', {
             'id': '3',
             'title': 'Book Number 1'
         }))
 def list(self, **kwargs):
     match = []
     id = kwargs.get('id')
     detail = kwargs.get('detail')
     for book in self.books:
         if id and book['id'] != id:
             continue
         book = book.copy()
         if detail == '2':
             book['reviews'] = [
                 Resource('review', {'comment': 'Very good'})
             ]
         match.append(book)
     return match
Example #3
0
 def __init__(self,db_url=config.DATABASE_URL):
     self.resource = Resource(db_url)
     self.vertices = VertexProxy(self.resource)
     self.edges = EdgeProxy(self.resource)
     self.indices = IndexProxy(self.resource)
     self.gremlin = Gremlin(self.resource)
Example #4
0
class Graph(object):
    """
    The primary interface to graph databases on the Rexster REST server.

    Instantiates the database :class:`~bulbs.rest.Resource` object using 
    the specified database URL and sets up proxy objects to the database.
        
    :keyword db_url: The URL to the specific database on Rexster. 
    :ivar vertices: :class:`~bulbs.element.VertexProxy` object for the Resource.
    :ivar edges: :class:`~bulbs.element.EdgeProxy` object for the Resource.
    :ivar indices: :class:`~bulbs.index.IndexProxy` object for the Resource.
    :ivar gremlin: :class:`~bulbs.gremlin.Gremlin` object for the Resource.

    Example::

    >>> from bulbs.graph import Graph
    >>> g = Graph()
    >>> james = g.vertices.create({'name':'James'})
    >>> julie = g.vertices.create({'name':'Julie'})
    >>> g.edges.create(james,"knows",julie)

    """

    def __init__(self,db_url=config.DATABASE_URL):
        self.resource = Resource(db_url)
        self.vertices = VertexProxy(self.resource)
        self.edges = EdgeProxy(self.resource)
        self.indices = IndexProxy(self.resource)
        self.gremlin = Gremlin(self.resource)

    #def __rshift__(self,b):
    #    return list(self)

    @property
    def V(self):
        """
        Returns all the vertices of the graph.

        Example::
        
        >>> g = Graph()
        >>> vertices = g.V

        :rtype: List of :class:`~bulbs.element.Vertex` objects. 

        """
        vertices = self.gremlin.query("g.V",Vertex,raw=True)
        return list(vertices)
    
    @property
    def E(self):
        """
        Returns all the edges of the graph. 

        Example::
        
        >>> g = Graph()
        >>> edges = g.E

        :rtype: List of :class:`~bulbs.element.Edge` objects.

        """
        edges = self.gremlin.query("g.E",Edge,raw=True)
        return list(edges)

    def idxV(self,**kwds):
        """
        Looks up a key/value pair in the vertex index and
        returns a generator containing the vertices matching the key and value.

        :keyword pair: The key/value pair to match on.
        :keyword raw: Boolean. If True, return the raw Response object. 
                      Defaults to False.

        Example::

        >>> g = Graph()
        >>> vertices = g.idxV(name="James")

        :rtype: Generator of :class:`~bulbs.element.Vertex` objects.

        You can turn the generator into a list by doing::

        >>> vertices = g.idxV(name="James")
        >>> vertices = list(vertices)

        """
        return self._idx("vertices",**kwds)
        
    #def _initialize_results(self,results,raw):
    #    if raw is True:
    #        return (result for result in results)
    #    else:
    #        return (Vertex(self.resource,result) for result in results)
        
    def idxE(self,**kwds):
        """
        Looks up a key/value pair in the edge index and 
        returns a generator containing the edges matching the key and value.

        :keyword pair: The key/value pair to match on.
        :keyword raw: Boolean. If True, return the raw Response object. 
                      Defaults to False.

        Example::

        >>> g = Graph()
        >>> edges = g.idxE(label="knows")

        :rtype: Generator of :class:`~bulbs.element.Edge` objects.

        You can turn the generator into a list by doing::

        >>> edges = g.idxE(label="knows")
        >>> edges = list(edges)

        """
        return self._idx("edges",**kwds)

    def _idx(self,index_name,**kwds):
        """
        Returns the Rexster Response object of the index look up.
        
        :param index_name: The name of the index.

        :param pair: The key/value pair to match on. 
        :keyword raw: Boolean. If True, return the raw Response object. 
                      Defaults to False.

        """
        raw = kwds.pop("raw",False)
        key, value = kwds.popitem()
        target = "%s/indices/%s" % (self.resource.db_name,index_name)
        params = dict(key=key,value=value)
        resp = self.resource.get(target,params)
        if raw:
            return resp
        if resp.results:
            class_map = dict(vertices=Vertex,edges=Edge)
            element_class = class_map[index_name]
            return (element_class(self.resource,result) for result in resp.results)

    
    def load_graphml(self,url):
        """
        Loads a GraphML file into the database, and returns the Rexster 
        response object.

        :param url: The URL of the GraphML file to load.

        """
        script = "g.loadGraphML('%s')" % url
        params = dict(script=script)
        resp = self.resource.get(self.base_target,params)
        return resp

    def save_graphml(self):
        """
        Returns a GraphML file representing the entire database.

        """

        script = """
        g.saveGraphML('data/graphml');
        new File('data/graphml').getText();
        """
        params = dict(script=script)
        resp = self.resource.get(self.base_target,params)
        return resp.results

    def clear(self):
        """
        Deletes all the elements in the graph.

        Example::

        >>> g = Graph()
        >>> g.clear()

        .. admonition:: WARNING 

           g.clear() will delete all your data!

        """
        target = self.resource.db_name
        resp = self.resource.delete(target,params=None)
        return resp
Example #5
0
 def __init__(self, db_url=config.DATABASE_URL):
     self.resource = Resource(db_url)
     self.vertices = VertexProxy(self.resource)
     self.edges = EdgeProxy(self.resource)
     self.indices = IndexProxy(self.resource)
     self.gremlin = Gremlin(self.resource)
Example #6
0
class Graph(object):
    """
    The primary interface to graph databases on the Rexster REST server.

    Instantiates the database :class:`~bulbs.rest.Resource` object using 
    the specified database URL and sets up proxy objects to the database.
        
    :keyword db_url: The URL to the specific database on Rexster. 
    :ivar vertices: :class:`~bulbs.element.VertexProxy` object for the Resource.
    :ivar edges: :class:`~bulbs.element.EdgeProxy` object for the Resource.
    :ivar indices: :class:`~bulbs.index.IndexProxy` object for the Resource.
    :ivar gremlin: :class:`~bulbs.gremlin.Gremlin` object for the Resource.

    Example::

    >>> from bulbs.graph import Graph
    >>> g = Graph()
    >>> james = g.vertices.create({'name':'James'})
    >>> julie = g.vertices.create({'name':'Julie'})
    >>> g.edges.create(james,"knows",julie)

    """
    def __init__(self, db_url=config.DATABASE_URL):
        self.resource = Resource(db_url)
        self.vertices = VertexProxy(self.resource)
        self.edges = EdgeProxy(self.resource)
        self.indices = IndexProxy(self.resource)
        self.gremlin = Gremlin(self.resource)

    #def __rshift__(self,b):
    #    return list(self)

    @property
    def V(self):
        """
        Returns all the vertices of the graph.

        Example::
        
        >>> g = Graph()
        >>> vertices = g.V

        :rtype: List of :class:`~bulbs.element.Vertex` objects. 

        """
        vertices = self.gremlin.query("g.V", Vertex, raw=True)
        return list(vertices)

    @property
    def E(self):
        """
        Returns all the edges of the graph. 

        Example::
        
        >>> g = Graph()
        >>> edges = g.E

        :rtype: List of :class:`~bulbs.element.Edge` objects.

        """
        edges = self.gremlin.query("g.E", Edge, raw=True)
        return list(edges)

    def idxV(self, **kwds):
        """
        Looks up a key/value pair in the vertex index and
        returns a generator containing the vertices matching the key and value.

        :keyword pair: The key/value pair to match on.
        :keyword raw: Boolean. If True, return the raw Response object. 
                      Defaults to False.

        Example::

        >>> g = Graph()
        >>> vertices = g.idxV(name="James")

        :rtype: Generator of :class:`~bulbs.element.Vertex` objects.

        You can turn the generator into a list by doing::

        >>> vertices = g.idxV(name="James")
        >>> vertices = list(vertices)

        """
        return self._idx("vertices", **kwds)

    #def _initialize_results(self,results,raw):
    #    if raw is True:
    #        return (result for result in results)
    #    else:
    #        return (Vertex(self.resource,result) for result in results)

    def idxE(self, **kwds):
        """
        Looks up a key/value pair in the edge index and 
        returns a generator containing the edges matching the key and value.

        :keyword pair: The key/value pair to match on.
        :keyword raw: Boolean. If True, return the raw Response object. 
                      Defaults to False.

        Example::

        >>> g = Graph()
        >>> edges = g.idxE(label="knows")

        :rtype: Generator of :class:`~bulbs.element.Edge` objects.

        You can turn the generator into a list by doing::

        >>> edges = g.idxE(label="knows")
        >>> edges = list(edges)

        """
        return self._idx("edges", **kwds)

    def _idx(self, index_name, **kwds):
        """
        Returns the Rexster Response object of the index look up.
        
        :param index_name: The name of the index.

        :param pair: The key/value pair to match on. 
        :keyword raw: Boolean. If True, return the raw Response object. 
                      Defaults to False.

        """
        raw = kwds.pop("raw", False)
        key, value = kwds.popitem()
        target = "%s/indices/%s" % (self.resource.db_name, index_name)
        params = dict(key=key, value=value)
        resp = self.resource.get(target, params)
        if raw:
            return resp
        if resp.results:
            class_map = dict(vertices=Vertex, edges=Edge)
            element_class = class_map[index_name]
            return (element_class(self.resource, result)
                    for result in resp.results)

    def load_graphml(self, url):
        """
        Loads a GraphML file into the database, and returns the Rexster 
        response object.

        :param url: The URL of the GraphML file to load.

        """
        script = "g.loadGraphML('%s')" % url
        resp = self.gremlin.execute(script)
        return resp

    def save_graphml(self):
        """
        Returns a GraphML file representing the entire database.

        """

        script = """
        g.saveGraphML('data/graphml');
        new File('data/graphml').getText();
        """
        results = self.gremlin.execute(script)
        return results[0]

    def clear(self):
        """
        Deletes all the elements in the graph.

        Example::

        >>> g = Graph()
        >>> g.clear()

        .. admonition:: WARNING 

           g.clear() will delete all your data!

        """
        target = self.resource.db_name
        resp = self.resource.delete(target, params=None)
        return resp
Example #7
0
class Model(TypeSystem):
    """
    Abstract base class for Node and Relationship.

    It's a sublcass of TypeSystem, which provides a mechanism for type-checking
    database properties before they're saved in the database.

    To create a type-checked database property, use the Property class and
    datatype classes, which are located in the property module. Example::

        name = Property(String, nullable=False)
        age = Property(Integer)

    """

    # You can override this default resource.
    resource = Resource(config.DATABASE_URL)

    @property
    def eid(self):
        """Return the element ID. Override this to change it from eid."""
        return self._id

    #@property
    #def element_type(self):
    #    """Return the element type."""
    #    return self._data.get(config.TYPE_VAR,None)
    #return self._data[TYPE_VAR]

    @classmethod
    def get(self, _id):
        """
        Returns the element for the specified ID.

        ::param _id: The element's ID.

        """
        return self._element_proxy.get(_id)

    @classmethod
    def get_all(self):
        """Returns all the elements for the model type."""
        index_name = self._element_proxy._path()
        target = "%s/indices/%s" % (self.resource.db_name, index_name)
        params = dict(key="element_type", value=self.element_type)
        resp = self.resource.get(target, params)
        for result in resp.results:
            yield self(self.resource, result)

    @classmethod
    def remove(self, _id, params):
        """
        Removes a property from the element for the specified ID.

        ::param _id: The element's ID.

        ::param params: The element's property to remove.

        """
        return self._element_proxy.remove(_id, params)

    @classmethod
    def create_index(self, index_keys=None, index_type="automatic"):
        """
        Creates an index for the model.

        ::param index_keys: The specific keys to index. If set to None,
                            any key can be indexed. Defaults to None.

        ::param index_type: The type of index to create. Either manual
                            or automatic. Defaults to automatic. See
                            Rexster docs for definitions.
        """
        index_name = self._get_index_name()
        index_class = self._get_index_class()
        index_attributes = (index_name, index_class, index_type, index_keys)
        return self.index_proxy.create(*index_attributes)

    @classmethod
    def delete_index(self):
        """Deletes the model's index."""
        index_name = self._get_element_key()
        return self.index_proxy.delete(index_name)

    @classmethod
    def _get_element_proxy(self):
        """
        Returns the element's proxy class. The Node and Relationship classes
        override this.

        """
        raise NotImplementedError

    @classmethod
    def _get_index_proxy(self):
        """Returns the index's proxy class."""
        return IndexProxy(self.resource, self)

    @classmethod
    def _get_index_name(self):
        """Returns the model's index name."""
        return self._get_element_key()

    @classmethod
    def _get_index(self):
        """Returns the model's index."""
        index_name = self._get_index_name()
        return self.index_proxy.get(index_name)

    index = ClassProperty(_get_index)
    index_proxy = ClassProperty(_get_index_proxy)

    #def element_type_sanity_check(self,results):
    #    element_type = self.get_element_type(results)
    #    if element_type is not None:
    #        if element_type != getattr(self,TYPE_VAR):
    #            raise("DB element type (%) doesn't match class element type (%s)" % \
    #                      (element_type, getattr(self,TYPE_VAR)))

    #def get_arg(self,name,default=None):
    #    return self._kwds.get(name,default)

    def get_data(self):
        self._validate_property_data()
        data = self._get_property_data()
        if isinstance(self, Relationship):
            relationship_data = dict(_outV=self._outV,
                                     _label=self.label,
                                     _inV=self._inV)
            data.update(relationship_data)
        return data

    def _create(self, *args, **kwds):
        """
        Create a new element in the database.
        
        ::param *args: Optional dict of name/value pairs of database properties.
        ::param **kwds: name/value pairs of database properties to store.
        """
        self._set_keyword_attributes(kwds)
        self._validate_property_data()
        data = self._get_property_data()
        args = list(args)
        args.append(data)
        self.before_created()
        # Using super here b/c Vertex and Edge have different create methods
        #resp = super(self.__class__,self).create(*args,raw=True)
        # got a "mismatched input, expecting double star" in Jython so
        # passing raw as a "double star"
        kwds = dict(raw=True)
        resp = self._element_proxy.create(*args, **kwds)
        self._initialize_element(self.resource, resp.results)
        #self.set_element_data(resp.results)
        self.after_created()

    def _read(self, results):
        """
        Read an element's data that was retrieved from the DB and set its model 
        values.

        ::param results: A list containing the results returned by Rexster.

        """
        self.before_read()
        self._initialize_element(self.resource, results)
        #self.set_element_data(results)
        self._set_property_data(results)
        self.after_read()

    def _update(self, eid, kwds):
        """
        Updates the element in the database.

        ::param eid: The ID of the element to update.
        ::param **kwds: name/value pairs of database properties to store.

        """
        self.eid = eid
        self._set_keyword_attributes(kwds)
        self.save()

    def save(self):
        """
        Saves/updates the element's data in the database.
        
        """
        self._validate_property_data()
        data = self._get_property_data()
        self.before_updated()
        #resp = super(self.__class__,self).update(self.eid,data,raw=True)
        resp = self._element_proxy.update(self.eid, data, raw=True)
        self._initialize_element(self.resource, resp.results)
        #self.set_element_data(resp.results)
        self.after_updated()

    def delete(self):
        """Deletes an element from the database."""
        # Should we make this a classmethod instead?
        # Should we provide an option to set a deleted flag or just override this?
        self.before_deleted()
        #resp = super(self.__class__,self).delete(self)
        resp = self._element_proxy.delete(self)
        self.after_deleted()
        return resp

    def initialize(self, args, kwds):
        """
        Initialize the model.

        If results is passed in, that means data was retrieved from the DB
        via a get request or gremlin query so we just set the property values
        based on what is stored in the DB.

        If eid was passed in, that means we're updating the element so we
        set the model's attributes based on the keyword variables passed in,
        and we save in the DB any attributes specified as DB Properties.

        If neither results nor eid were passed in, that means we're creating a
        new element so we set the model's attributes based on the keyword
        variables that were passed in, and we save in the DB any attributes
        specified as DB Properties.

        Also, we set self.kwds so the vars are available to the before/after wrappers.
        
        ::param *args: Optional dict of name/value pairs of database properties.

        ::param **kwds: name/value pairs of database properties to store.

        """
        # We're doing a little arg dance instead of keyword mangling.
        # This avoids problems if a user wants to use the word "results" as a
        # Property name (actually, no it doesn't, b/c you're using results
        # elsewhere. Ugh -- I hate keyword mangling.
        _id = None
        results = None
        args = list(args)

        # save kwds so it's available to before/after wrappers
        self._kwds = kwds

        # in case someone wants to pass in a dict of data instead of by keywords
        _data = kwds.pop("_data", {})
        save = kwds.pop("save", True)

        # in case someone passed in a dict of data plus some data by keywords
        _data.update(**kwds)

        if args and isinstance(args[0], Resource):
            self.resource = args.pop(0)
        if args and isinstance(args[0], dict):
            results = args.pop(0)
        if args and isinstance(args[0], int):
            _id = args.pop(0)

        #print "RESULTS:", results

        self.before_initialized()
        if save is False:
            Model._set_keyword_attributes(self, kwds)
        elif results is not None:
            # must have been a get or gremlin request
            Model._read(self, results)
        elif _id is not None:
            # calling Model explicitly b/c Vertex/Edge have an update method too
            Model._update(self, _id, _data)
        elif args or kwds:
            # calling Model explicitly b/c Vertex/Edge have a create method too
            Model._create(self, *args, **_data)
        else:
            # create an empty Node (can't have an empty Relationship b/c must have label)
            Model._create(self, {})
        self.after_initialized()

    def before_initialized(self):
        """Virtual method run before the model is initialized."""
        pass

    def after_initialized(self):
        """Virtual method run after the model is initialized."""
        pass

    def before_created(self):
        """Virtual method run before an element is created in the DB."""
        pass

    def after_created(self):
        """Virtual method run after an element is created in the DB."""
        pass

    def before_read(self):
        """Virtual method run before element data is read from the DB."""
        pass

    def after_read(self):
        """Virtual method run after element data is read from the DB."""
        pass

    def before_updated(self):
        """Virtual method run before an element is updated in the DB."""
        pass

    def after_updated(self):
        """Virtual method run after an element is updated in the DB."""
        pass

    def before_deleted(self):
        """Virtual method run before an element is deleted from the DB."""
        pass

    def after_deleted(self):
        """Virtual method run after an element is deleted from the DB."""
        pass
Example #8
0
 def __init__(self, url, authrealm=None, uname=None, passwd=None):
     Resource.__init__(self, url, authrealm, uname, passwd, 'application/json')