def save(self, *args, **kwargs): """ Save this edge to the graph database. """ super(Edge, self).save() future = connection.get_future(kwargs) future_result = self._save_edge(self._outV, self._inV, self.get_label(), self.as_save_params(), exclusive=self.__exclusive__, **kwargs) def on_read(f2): try: result = f2.result()[0] except Exception as e: future.set_exception(e) else: future.set_result(result) def on_save(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_save) return future
def delete(self, **kwargs): """ Delete the current edge from the graph. """ if self.__abstract__: # pragma: no cover raise GoblinQueryError('cant delete abstract elements') if self._id is None: return self future = connection.get_future(kwargs) future_result = self._delete_edge() def on_read(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: future.set_result(result) def on_delete(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_delete) return future
def _reload_values(self, *args, **kwargs): """ Method for reloading the current vertex by reading its current values from the database. """ reloaded_values = {} future = connection.get_future(kwargs) future_result = connection.execute_query( 'g.V(vid)', {'vid': self._id}, **kwargs) def on_read(f2): try: result = f2.result() result = result.data[0] except Exception as e: future.set_exception(e) else: # del result['type'] # don't think I need this reloaded_values['id'] = result['id'] for name, value in result.get('properties', {}).items(): # This is a hack until decide how to deal with props reloaded_values[name] = value[0]['value'] future.set_result(reloaded_values) def on_reload_values(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_reload_values) return future
def _get_simple(self, deserialize, **kwargs): script = "g.V(vid)" future_results = self._get_stream(script, deserialize, **kwargs) future = connection.get_future(kwargs) def on_read(f): try: result = f.result() except Exception as e: future.set_exception(e) else: if not result: future.set_exception(GoblinQueryError("Does not exist")) future.set_result(result[0]) def on_stream(f2): try: stream = f2.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_results.add_done_callback(on_stream) return future
def outV(self, *args, **kwargs): """ Return the vertex that this edge goes into. :rtype: Vertex """ from goblin.models.vertex import Vertex future = connection.get_future(kwargs) if self._inV is None: future_results = self._simple_traversal('outV', **kwargs) def on_traversal(f): try: result = f.result() except Exception as e: future.set_exception(e) else: self._outV = result[0] if isinstance(self._outV, string_types + integer_types): future_results = Vertex.get(self._outV, **kwargs) def on_get(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: self._outV = result future_results.add_done_callback(on_get) future.set_result(self._outV) future_results.add_done_callback(on_traversal) elif isinstance(self._outV, string_types + integer_types): future_results = Vertex.get(self._outV, **kwargs) def on_get(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: self._outV = result future.set_result(self._outV) future_results.add_done_callback(on_get) else: future.set_result(self._outV) return future
def get(cls, id, *args, **kwargs): """ Look up edge by titan assigned ID. Raises a DoesNotExist exception if an edge with the given edge id was not found. Raises a MultipleObjectsReturned exception if the edge_id corresponds to more than one edge in the graph. :param id: The titan assigned ID :type id: str | basestring :rtype: goblin.models.Edge """ if not id: raise cls.DoesNotExist future = connection.get_future(kwargs) future_result = cls.all([id], **kwargs) def on_read(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: if len(result) > 1: # pragma: no cover # This requires titan to be broken. e = cls.MultipleObjectsReturned future.set_exception(e) else: result = result[0] if not isinstance(result, cls): e = cls.WrongElementType( '%s is not an instance or subclass of %s' % ( result.__class__.__name__, cls.__name__)) future.set_exception(e) else: future.set_result(result) def on_get(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_get) return future
def _simple_deletion(self, operation, labels, **kwargs): """ Perform simple bulk graph deletion operation. :param operation: The operation to be performed :type operation: str :param labels: The edge label to be used :type labels: str or Edge """ from goblin.models.edge import Edge label_strings = [] for label in labels: if inspect.isclass(label) and issubclass(label, Edge): label_string = label.get_label() elif isinstance(label, Edge): label_string = label.get_label() elif isinstance(label, string_types): label_string = label else: raise GoblinException("traversal labels must be edge " + "classes, instances, or strings") label_strings.append(label_string) future = connection.get_future(kwargs) future_result = self._delete_related(operation, label_strings) def on_read(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: future.set_result(result) def on_save(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_save) return future
def get(cls, id, *args, **kwargs): """ Look up edge by titan assigned ID. Raises a DoesNotExist exception if an edge with the given edge id was not found. Raises a MultipleObjectsReturned exception if the edge_id corresponds to more than one edge in the graph. :param id: The titan assigned ID :type id: str | basestring :rtype: goblin.models.Edge """ if not id: raise cls.DoesNotExist future = connection.get_future(kwargs) future_result = cls.all([id], **kwargs) def on_read(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: if len(result) > 1: # pragma: no cover # This requires titan to be broken. e = cls.MultipleObjectsReturned future.set_exception(e) else: result = result[0] if not isinstance(result, cls): e = cls.WrongElementType( '%s is not an instance or subclass of %s' % (result.__class__.__name__, cls.__name__)) future.set_exception(e) else: future.set_result(result) def on_get(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_get) return future
def find_by_value(cls, field, value, as_dict=False, **kwargs): """ Returns edges that match the given field/value pair. :param field: The field to search :type field: str :param value: The value of the field :type value: str :param as_dict: Return results as a dictionary :type as_dict: boolean :rtype: [goblin.models.Edge] """ _field = cls.get_property_by_name(field) _label = cls.get_label() value_type = False if isinstance(value, integer_types + float_types): value_type = True future = connection.get_future(kwargs) future_results = cls._find_edge_by_value( value_type=value_type, elabel=_label, field=_field, val=value ) def by_value_handler(data): if data is None: data = [] if as_dict: # pragma: no cover data = {v._id: v for v in data} return data def on_find_by_value(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: stream.add_handler(by_value_handler) future.set_result(stream) future_results.add_done_callback(on_find_by_value) return future
def __call__(self, instance, *args, **kwargs): future_results = super(GremlinMethod, self).__call__( instance, *args, **kwargs) deserialize = kwargs.get('deserialize', True) if deserialize: future = connection.get_future(kwargs) def on_call(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: stream.add_handler(GremlinMethod._deserialize) future.set_result(stream) future_results.add_done_callback(on_call) return future return future_results
def find_by_value(cls, field, value, as_dict=False, **kwargs): """ Returns edges that match the given field/value pair. :param field: The field to search :type field: str :param value: The value of the field :type value: str :param as_dict: Return results as a dictionary :type as_dict: boolean :rtype: [goblin.models.Edge] """ _field = cls.get_property_by_name(field) _label = cls.get_label() value_type = False if isinstance(value, integer_types + float_types): value_type = True future = connection.get_future(kwargs) future_results = cls._find_edge_by_value(value_type=value_type, elabel=_label, field=_field, val=value) def by_value_handler(data): if data is None: data = [] if as_dict: # pragma: no cover data = {v._id: v for v in data} return data def on_find_by_value(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: stream.add_handler(by_value_handler) future.set_result(stream) future_results.add_done_callback(on_find_by_value) return future
def __call__(self, instance, *args, **kwargs): future = connection.get_future(kwargs) future_result = super(GremlinValue, self).__call__(instance, *args, **kwargs) def on_read(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: from goblin.models.element import Element if result is None: # pragma: no cover future.set_result(None) # we have to make a special case for dictionaries, python # len returns number of keys, even though it is one # object. Don't do the same for lists or tuples, since # they arevGremlin Methods not GremlinValues. elif isinstance(result, dict): future.set_result(result) elif isinstance(result, integer_types + float_types + string_types): future.set_result(result) elif isinstance(result, Element): future.set_result(result) elif len(result) != 1: e = GoblinGremlinException( '''GremlinValue requires a single value is returned (%s returned)''' % len(result)) future.set_exception(e) else: future.set_result(result[0]) def on_call(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_call) return future
def save(self, *args, **kwargs): """ Save the current vertex using the configured save strategy, the default save strategy is to re-save all fields every time the object is saved. """ super(Vertex, self).save() params = self.as_save_params() label = self.get_label() # params['element_type'] = self.get_element_type() don't think we need # Here this is a future, have to set handler in callback future = connection.get_future(kwargs) future_result = self._save_vertex(label, params, **kwargs) deserialize = kwargs.pop('deserialize', True) def on_read(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: if deserialize: result = result[0] self._id = result._id for k, v in self._values.items(): v.previous_value = result._values[k].previous_value else: result = result.data future.set_result(result) def on_save(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_save) return future
def _property_handler(script, graph_name, **kwargs): future = connection.get_future(kwargs) future_response = connection.execute_query(script, graph_name=graph_name) def on_read(f2): try: result = f2.result() except Exception as e: future.set_exception(e) else: future.set_result(result) def on_key(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_response.add_done_callback(on_key) return future
def _reload_values(self, *args, **kwargs): """ Re-read the values for this edge from the graph database. """ reloaded_values = {} future = connection.get_future(kwargs) future_result = connection.execute_query( 'g.E(eid)', {'eid': self._id}, **kwargs) def on_read(f2): try: result = f2.result() result = result.data[0] except Exception as e: future.set_exception(e) else: if result: # del result['type'] reloaded_values['id'] = result['id'] for name, value in result.get('properties', {}).items(): reloaded_values[name] = value if result['id']: setattr(self, 'id', result['id']) future.set_result(reloaded_values) else: future.set_result({}) def on_reload(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_reload) return future
def _reload_values(self, *args, **kwargs): """ Re-read the values for this edge from the graph database. """ reloaded_values = {} future = connection.get_future(kwargs) future_result = connection.execute_query('g.E(eid)', {'eid': self._id}, **kwargs) def on_read(f2): try: result = f2.result() result = result.data[0] except Exception as e: future.set_exception(e) else: if result: # del result['type'] reloaded_values['id'] = result['id'] for name, value in result.get('properties', {}).items(): reloaded_values[name] = value if result['id']: setattr(self, 'id', result['id']) future.set_result(reloaded_values) else: future.set_result({}) def on_reload(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: future_read = stream.read() future_read.add_done_callback(on_read) future_result.add_done_callback(on_reload) return future
def reload(self, *args, **kwargs): """ Reload the given element from the database. """ future = connection.get_future(kwargs) future_values = self._reload_values(**kwargs) def on_reload(f): try: values = f.result() except Exception as e: future.set_exception(e) else: for name, prop in self._properties.items(): value = values.get(prop.db_field_name, None) if value is not None: value = prop.to_python(value) setattr(self, name, value) future.set_result(self) future_values.add_done_callback(on_reload) return future
def all(cls, ids=[], as_dict=False, match_length=True, *args, **kwargs): """ Load all vertices with the given ids from the graph. By default this will return a list of vertices but if as_dict is True then it will return a dictionary containing ids as keys and vertices found as values. :param ids: A list of titan ids :type ids: list :param as_dict: Toggle whether to return a dictionary or list :type as_dict: boolean :rtype: dict | list """ if not isinstance(ids, array_types): raise GoblinQueryError("ids must be of type list or tuple") deserialize = kwargs.pop('deserialize', True) handlers = [] future = connection.get_future(kwargs) if len(ids) == 0: future_results = connection.execute_query( 'g.V.hasLabel(x)', bindings={"x": cls.get_label()}, **kwargs) else: strids = [str(i) for i in ids] # Need to test sending complex bindings with client vids = ", ".join(strids) future_results = connection.execute_query( 'g.V(%s)' % vids, **kwargs) def id_handler(results): try: results = list(filter(None, results)) except TypeError: raise cls.DoesNotExist if len(results) != len(ids) and match_length: raise GoblinQueryError( "the number of results don't match the number of " + "ids requested") return results handlers.append(id_handler) def result_handler(results): objects = [] for r in results: if deserialize: try: objects += [Element.deserialize(r)] except KeyError: # pragma: no cover raise GoblinQueryError( 'Vertex type "%s" is unknown' % r.get('label', '')) else: objects = results if as_dict: # pragma: no cover return {v._id: v for v in objects} return objects handlers.append(result_handler) def on_all(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: [stream.add_handler(h) for h in handlers] future.set_result(stream) future_results.add_done_callback(on_all) return future
def _simple_traversal(self, operation, labels, limit=None, offset=None, types=None, **kwargs): """ Perform simple graph database traversals with ubiquitous pagination. :param operation: The operation to be performed :type operation: str :param labels: The edge labels to be used :type labels: list of Edges or strings :param start: The starting offset :type start: int :param max_results: The maximum number of results to return :type max_results: int :param types: The list of allowed result elements :type types: list """ from goblin.models.edge import Edge label_strings = [] for label in labels: if inspect.isclass(label) and issubclass(label, Edge): label_string = label.get_label() elif isinstance(label, Edge): label_string = label.get_label() elif isinstance(label, string_types): label_string = label else: raise GoblinException("traversal labels must be edge " + "classes, instances, or strings") label_strings.append(label_string) allowed_elts = None if types is not None: allowed_elts = [] for e in types: if issubclass(e, Vertex): allowed_elts += [e.get_label()] elif issubclass(e, Edge): allowed_elts += [e.get_label()] if limit is not None and offset is not None: start = offset end = offset + limit else: start = end = None future = connection.get_future(kwargs) future_result = self._traversal(operation, label_strings, start, end, allowed_elts) def traversal_handler(data): if data is None: data = [] return data def on_traversal(f): try: stream = f.result() except Exception as e: future.set_exception(e) else: stream.add_handler(traversal_handler) future.set_result(stream) future_result.add_done_callback(on_traversal) return future