Exemplo n.º 1
0
    def _initialize_element(self, resource, results):
        """
        Initialize the element's resource, _data, and Gremlin proxy. This is
        called explicitly by Element.__init__ and Model.__init__

        :param resource: The Resource object for the database.

        :param results: The results list returned by Rexster.

        """
        self._data = {}
        self.resource = resource
        self._set_element_data(results)
        self._gremlin = Gremlin(self.resource)
Exemplo n.º 2
0
 def rebuild(self,raw=False):
     # need class_map b/c the Blueprints need capitalized class names, 
     # but Rexster returns lower-case class names for index_class
     class_map = dict(vertex='Vertex',edge='Edge')
     klass = class_map[self.index_class]
     script = "index = g.getIndex('%s',%s);" % (self.index_name,klass)
     script = script + "AutomaticIndexHelper.reIndexElements(g, index, g.getVertices())"
     resp = Gremlin(self.resource).execute(script,raw=True)
     if raw or not resp.results:
         return resp
     return list(resp.results)
Exemplo n.º 3
0
    def _initialize_element(self,resource,results):
        """
        Initialize the element's resource, _data, and Gremlin proxy. This is
        called explicitly by Element.__init__ and Model.__init__

        :param resource: The Resource object for the database.

        :param results: The results list returned by Rexster.

        """
        self.resource = resource
        self._set_element_data(results)
        self._gremlin = Gremlin(self.resource)
Exemplo n.º 4
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)
Exemplo n.º 5
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
Exemplo n.º 6
0
class Element(object):
    """This is an abstract base class for Vertex and Edge"""
    def __init__(self, resource, results):
        """
        Initializes an element after it is added, updated, or retrieved from 
        the database.

        :param resource: The Resource object for the database.

        :param results: The results list returned by Rexster.
        
        """
        # NOTE: Put all the init stuff in initialize_element() because
        # Model() calls it explicitly instead of super().__init__()
        self._initialize_element(resource, results)

    def _initialize_element(self, resource, results):
        """
        Initialize the element's resource, _data, and Gremlin proxy. This is
        called explicitly by Element.__init__ and Model.__init__

        :param resource: The Resource object for the database.

        :param results: The results list returned by Rexster.

        """
        self._data = {}
        self.resource = resource
        self._set_element_data(results)
        self._gremlin = Gremlin(self.resource)

    def _set_element_data(self, results):
        """ 
        Set the elements data returned by the DB.

        :param results: The results list returned by Rexster.
     
        """
        self._data = results

    def __getattr__(self, attribute):
        """
        Returns the value stored in the DB if the property hasn't been 
        set explicitly. 

        If you explicitly set/change the values of an element's properties,
        make sure you call save() to updated the values in the DB.
        
        """
        try:
            return self._data[attribute]
        except:
            raise AttributeError("%s not found and not in self._data" \
                                     % (attribute))

    def __len__(self):
        """Returns the number of items stored in the DB results"""
        return len(self._data)

    def __contains__(self, item):
        """Returns True if attribute is a key that has been stored in the DB"""
        return item in self._data

    def __eq__(self, obj):
        """Returns True if the elements are equal"""
        return (hasattr(obj, "_id") and self._id == obj._id
                and hasattr(obj, "_data") and self._data == obj._data
                and hasattr(obj, "__class__")
                and self.__class__ == obj.__class__)

    def __ne__(self, obj):
        """Returns True if the elements are not equal."""
        return not self.__eq__(obj)

    def __repr__(self):
        """Returns the string representation of the attribute."""
        return self.__unicode__()

    def __str__(self):
        """Returns the string representation of the attribute."""
        return self.__unicode__()

    def __unicode__(self):
        """Returns the unicode representation of the attribute."""
        #return u"<Rexster %s %s: %s>" % \
        #    (self.resource.db_name, self.__class__.__name__, self._id)
        return u"<%s: %s>" % (self.__class__.__name__,
                              self._proxy(self.resource)._uri(self._id))

    @property
    def _id(self):
        """
        Returns the element ID. This is the element's "primary key"; however,
        some DBs (such as neo4j) reuse IDs if they are deleted so 
        be careful with how you use them. If you want to guarantee
        they are unique across the DB's lifetime either don't 
        physically delete elements and just set a deleted flag, or
        use some other mechanism, such as an external sequence or 
        a hash.
        
        """
        #int(self._data['_id'])
        return utils.coerce_id(self._data['_id'])

    @property
    def _type(self):
        """Returns the _type set by Rexster: either vertex, edge, or index."""
        return self._data['_type']

    @property
    def _proxy(self):
        """Returns the element's proxy to Rexster."""
        proxy_map = dict(vertex=VertexProxy, edge=EdgeProxy)
        return proxy_map[self._type]

    @property
    def map(self):
        """Returns a dict of the element's data that's stored in the DB."""
        private_keys = ['_id', '_type', '_outV', '_inV', '_label']
        map_ = dict()
        for key, value in self._data.items():
            if key not in private_keys:
                map_.update({key: value})
        return map_

    def gremlin(self, script, *classes, **kwds):
        """
        Returns a generator containing the results of the Gremlin script. 
        Remember you can always use the list() function to turn an iterator or 
        a generator into a list. Sometimes it's useful to turn a generator into
        a list when doing unittests or when you want to check how many items 
        are in the results.
       
        :param script: Gremlin script to send to Rexster. Since this begins 
                       from the context of an element instead of a graph, the 
                       script should begin with the reference to itself 
                       (v or e) instead of a reference to the graph (g). 
                       Example:

                       .. code-block:: groovy

                       // do this... 
                       v.outE('created') 
                        
                       // instead of... 
                       g.v(1).outE('created')
        :param classes: Zero or more subclasses of Element to use when 
                          initializing the the elements returned by the query. 
                          For example, if Person is a subclass of Node (which 
                          is defined in model.py and is a subclass of Vertex), 
                          and the query returns person elements, pass in the 
                          Person class and the method will use the element_type
                          defined in the class to initialize the returned items
                          to a Person object.
        :keyword return_keys: Optional keyword param. A comma-separated list of
                              keys (DB properties) to return. If set to None, it
                              returns all properties. Defaults to None.
        :keyword raw: Optional keyword param. If set to True, it won't try to 
                      initialize data. Defaults to False. 

        :rtype: Generator of items. The data types of the items returned vary 
                depending on the query.

        Example::
       
        >>> from bulbs.graph import Graph()
        >>> g = Graph()
        >>> james = g.vertices.get(3) 
        >>> script = "v.outE('knows').inV"
        >>> results = james.gremlin(script)


        """
        # TODO: now that we're using a proxy, should we always include the
        # calling class in the class_map?
        return_keys = kwds.pop('return_keys', None)
        raw = kwds.pop('raw', False)
        class_map = dict(vertex=Vertex, edge=Edge)
        kwds = dict(default_class_map=class_map,
                    return_keys=return_keys,
                    raw=raw)
        return self._gremlin._element_query(self, script, *classes, **kwds)
Exemplo n.º 7
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)
Exemplo n.º 8
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
Exemplo n.º 9
0
class Element(object):
    """This is an abstract base class for Vertex and Edge"""
    
    def __init__(self,resource,results):
        """
        Initializes an element after it is added, updated, or retrieved from 
        the database.

        :param resource: The Resource object for the database.

        :param results: The results list returned by Rexster.
        
        """
        # NOTE: Put all the init stuff in initialize_element() because 
        # Model() calls it explicitly instead of super().__init__()
        self._initialize_element(resource,results)

    def _initialize_element(self,resource,results):
        """
        Initialize the element's resource, _data, and Gremlin proxy. This is
        called explicitly by Element.__init__ and Model.__init__

        :param resource: The Resource object for the database.

        :param results: The results list returned by Rexster.

        """
        self._data = {}
        self.resource = resource
        self._set_element_data(results)
        self._gremlin = Gremlin(self.resource)

    def _set_element_data(self,results):
        """ 
        Set the elements data returned by the DB.

        :param results: The results list returned by Rexster.
     
        """
        self._data = results
 
    def __getattr__(self,attribute):
        """
        Returns the value stored in the DB if the property hasn't been 
        set explicitly. 

        If you explicitly set/change the values of an element's properties,
        make sure you call save() to updated the values in the DB.
        
        """
        try:
            return self._data[attribute]
        except:
            raise AttributeError("%s not found and not in self._data" \
                                     % (attribute))

    def __len__(self):
        """Returns the number of items stored in the DB results"""
        return len(self._data)

    def __contains__(self, item):
        """Returns True if attribute is a key that has been stored in the DB"""
        return item in self._data

    def __eq__(self, obj):
        """Returns True if the elements are equal"""
        return (hasattr(obj, "_id")
                and self._id == obj._id
                and hasattr(obj, "_data")
                and self._data == obj._data
                and hasattr(obj, "__class__")
                and self.__class__ == obj.__class__
                )

    def __ne__(self, obj):
        """Returns True if the elements are not equal."""
        return not self.__eq__(obj)

    def __repr__(self):
        """Returns the string representation of the attribute."""
        return self.__unicode__()
    
    def __str__(self):
        """Returns the string representation of the attribute."""
        return self.__unicode__()
    
    def __unicode__(self):
        """Returns the unicode representation of the attribute."""
        #return u"<Rexster %s %s: %s>" % \
        #    (self.resource.db_name, self.__class__.__name__, self._id)
        return u"<%s: %s>" % (self.__class__.__name__,
                              self._proxy(self.resource)._uri(self._id))

    @property
    def _id(self):
        """
        Returns the element ID. This is the element's "primary key"; however,
        some DBs (such as neo4j) reuse IDs if they are deleted so 
        be careful with how you use them. If you want to guarantee
        they are unique across the DB's lifetime either don't 
        physically delete elements and just set a deleted flag, or
        use some other mechanism, such as an external sequence or 
        a hash.
        
        """
        #int(self._data['_id'])
        return utils.coerce_id(self._data['_id'])

    @property
    def _type(self):
        """Returns the _type set by Rexster: either vertex, edge, or index."""
        return self._data['_type']

    @property
    def _proxy(self):
        """Returns the element's proxy to Rexster."""
        proxy_map = dict(vertex=VertexProxy,edge=EdgeProxy)
        return proxy_map[self._type]

    @property
    def map(self):
        """Returns a dict of the element's data that's stored in the DB."""
        private_keys = ['_id','_type','_outV','_inV','_label']
        map_ = dict()
        for key, value in self._data.items():
            if key not in private_keys:
                map_.update({key:value})
        return map_

    def gremlin(self,script,*classes,**kwds):
        """
        Returns a generator containing the results of the Gremlin script. 
        Remember you can always use the list() function to turn an iterator or 
        a generator into a list. Sometimes it's useful to turn a generator into
        a list when doing unittests or when you want to check how many items 
        are in the results.
       
        :param script: Gremlin script to send to Rexster. Since this begins 
                       from the context of an element instead of a graph, the 
                       script should begin with the reference to itself 
                       (v or e) instead of a reference to the graph (g). 
                       Example:

                       .. code-block:: groovy

                       // do this... 
                       v.outE('created') 
                        
                       // instead of... 
                       g.v(1).outE('created')
        :param classes: Zero or more subclasses of Element to use when 
                          initializing the the elements returned by the query. 
                          For example, if Person is a subclass of Node (which 
                          is defined in model.py and is a subclass of Vertex), 
                          and the query returns person elements, pass in the 
                          Person class and the method will use the element_type
                          defined in the class to initialize the returned items
                          to a Person object.
        :keyword return_keys: Optional keyword param. A comma-separated list of
                              keys (DB properties) to return. If set to None, it
                              returns all properties. Defaults to None.
        :keyword raw: Optional keyword param. If set to True, it won't try to 
                      initialize data. Defaults to False. 

        :rtype: Generator of items. The data types of the items returned vary 
                depending on the query.

        Example::
       
        >>> from bulbs.graph import Graph()
        >>> g = Graph()
        >>> james = g.vertices.get(3) 
        >>> script = "v.outE('knows').inV"
        >>> results = james.gremlin(script)


        """
        # TODO: now that we're using a proxy, should we always include the 
        # calling class in the class_map?
        return_keys = kwds.pop('return_keys',None)
        raw = kwds.pop('raw',False)
        class_map = dict(vertex=Vertex,edge=Edge)
        kwds = dict(default_class_map=class_map,return_keys=return_keys,raw=raw)
        return self._gremlin._element_query(self,script,*classes,**kwds)