def _add(self, obj): """ Adds an object to the data store. It will automatically generate the type relationships for the the object as required and store the object itself. """ type_registry = self.type_registry query_args = {} invalidates_types = False if isinstance(obj, PersistableType): # object is a type; create the type and its hierarchy return self._update_types(obj) elif isinstance(obj, Relationship): # object is a relationship obj_type = type(obj) if obj_type in (IsA, DeclaredOn): invalidates_types = True query = get_create_relationship_query(obj, type_registry) else: # object is an instance obj_type = type(obj) type_id = get_type_id(obj_type) if type_id not in type_registry._types_in_db: raise TypeNotPersistedError(type_id) labels = type_registry.get_labels_for_type(obj_type) if labels: node_declaration = 'n:' + ':'.join(labels) else: node_declaration = 'n' query = """ MATCH (cls:PersistableType) WHERE cls.id = {type_id} CREATE (%s {props})-[:INSTANCEOF {rel_props}]->(cls) RETURN n """ % node_declaration query_args = { 'type_id': get_type_id(obj_type), 'rel_props': type_registry.object_to_dict( InstanceOf(None, None), for_db=True), } query_args['props'] = type_registry.object_to_dict( obj, for_db=True) (node_or_rel,) = next(self._execute(query, **query_args)) if invalidates_types: self.invalidate_type_system() set_store_for_object(obj, self) return obj
def _index_object(self, obj, node_or_rel): indexes = self.type_registry.get_index_entries(obj) for index_name, key, value in indexes: if isinstance(obj, Relationship): index_type = neo4j.Relationship else: index_type = neo4j.Node log.debug( 'indexing %s for %s using index %s', obj, node_or_rel, index_name) index = self._conn.get_or_create_index(index_type, index_name) index.add(key, value, node_or_rel) if not isinstance(obj, Relationship): set_store_for_object(obj, self)
def _convert_value(self, value): """ Converts a py2neo primitive(Node, Relationship, basic object) to an equvalent python object. Any value which cannot be converted, will be returned as is. Args: value: The value to convert. Returns: The converted value. """ if isinstance(value, (neo4j.Node, neo4j.Relationship)): properties = value._properties.copy() if isinstance(value, neo4j.Relationship): # inject __type__ based on the relationship type in case it's # missing. makes it easier to add relationship with cypher neo4j_rel_name = value.type type_id = self.type_registry.get_relationship_type_id( neo4j_rel_name) properties['__type__'] = type_id obj = self.type_registry.dict_to_object(properties) if isinstance(value, neo4j.Relationship): # prefetching start and end-nodes as they don't have # their properties loaded yet value.start_node.get_properties() value.end_node.get_properties() obj.start = self._convert_value(value.start_node) obj.end = self._convert_value(value.end_node) else: set_store_for_object(obj, self) return obj elif isinstance(value, list): return [self._convert_value(v) for v in value] return value
def _convert_value(self, value): """ Converts a py2neo primitive(Node, Relationship, basic object) to an equvalent python object. Any value which cannot be converted, will be returned as is. Args: value: The value to convert. Returns: The converted value. """ if isinstance(value, (neo4j.Node, neo4j.Relationship)): properties = value.get_properties() obj = self.type_registry.dict_to_object(properties) if isinstance(value, neo4j.Relationship): obj.start = self._convert_value(value.start_node) obj.end = self._convert_value(value.end_node) else: set_store_for_object(obj, self) return obj return value
def change_instance_type(self, obj, type_id, updated_values=None): if updated_values is None: updated_values = {} type_registry = self.type_registry if type_id not in type_registry._types_in_db: raise TypeNotPersistedError(type_id) properties = self.serialize(obj, for_db=True) properties['__type__'] = type_id properties.update(updated_values) # get rid of any attributes not supported by the new type properties = self.serialize(self.deserialize(properties), for_db=True) old_type = type(obj) new_type = type_registry.get_class_by_id(type_id) rel_props = type_registry.object_to_dict(InstanceOf(), for_db=True) old_labels = set(type_registry.get_labels_for_type(old_type)) new_labels = set(type_registry.get_labels_for_type(new_type)) removed_labels = old_labels - new_labels added_labels = new_labels - old_labels if removed_labels: remove_labels_statement = 'REMOVE obj:' + ':'.join(removed_labels) else: remove_labels_statement = '' if added_labels: add_labels_statement = 'SET obj :' + ':'.join(added_labels) else: add_labels_statement = '' match_clauses = ( get_match_clause(obj, 'obj', type_registry), get_match_clause(new_type, 'type', type_registry) ) query = join_lines( 'MATCH', (match_clauses, ','), ', (obj)-[old_rel:INSTANCEOF]->()', 'DELETE old_rel', 'CREATE (obj)-[new_rel:INSTANCEOF {rel_props}]->(type)', 'SET obj={properties}', remove_labels_statement, add_labels_statement, 'RETURN obj', ) new_obj = self.query_single( query, properties=properties, rel_props=rel_props) if new_obj is None: raise NoResultFound( "{} not found in db".format(repr(obj)) ) set_store_for_object(new_obj, self) return new_obj