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
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)
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
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)
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
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
def __init__(self, url, authrealm=None, uname=None, passwd=None): Resource.__init__(self, url, authrealm, uname, passwd, 'application/json')