def test_IsA_and_InstanceOf_type_relationships(temporary_static_types): """ Testing type hierarchy creation. We don't want to test all the types in their relationships, but only the set of types which are persisted with IsA and InstanceOf relationships. """ class Foo(Entity): pass result = list(get_type_relationships(Entity)) assert result == [ (object, (InstanceOf, 0), type), (type, (IsA, 0), object), (type, (InstanceOf, 0), type), (PersistableType, (IsA, 0), type), (Persistable, (IsA, 0), object), (Persistable, (InstanceOf, 0), type), (PersistableType, (IsA, 1), Persistable), (PersistableType, (InstanceOf, 0), type), (AttributedBase, (IsA, 0), Persistable), (AttributedBase, (InstanceOf, 0), PersistableType), (Entity, (IsA, 0), AttributedBase), (Entity, (InstanceOf, 0), PersistableType), ] pers = Entity() result = list(get_type_relationships(pers)) assert result == [ (object, (InstanceOf, 0), type), (type, (IsA, 0), object), (type, (InstanceOf, 0), type), (PersistableType, (IsA, 0), type), (Persistable, (IsA, 0), object), (Persistable, (InstanceOf, 0), type), (PersistableType, (IsA, 1), Persistable), (PersistableType, (InstanceOf, 0), type), (AttributedBase, (IsA, 0), Persistable), (AttributedBase, (InstanceOf, 0), PersistableType), (Entity, (IsA, 0), AttributedBase), (Entity, (InstanceOf, 0), PersistableType), (pers, (InstanceOf, 0), Entity), ] foo = Foo() result = list(get_type_relationships(foo)) assert result == [ (object, (InstanceOf, 0), type), (type, (IsA, 0), object), (type, (InstanceOf, 0), type), (PersistableType, (IsA, 0), type), (Persistable, (IsA, 0), object), (Persistable, (InstanceOf, 0), type), (PersistableType, (IsA, 1), Persistable), (PersistableType, (InstanceOf, 0), type), (AttributedBase, (IsA, 0), Persistable), (AttributedBase, (InstanceOf, 0), PersistableType), (Entity, (IsA, 0), AttributedBase), (Entity, (InstanceOf, 0), PersistableType), (Foo, (IsA, 0), Entity), (Foo, (InstanceOf, 0), PersistableType), (foo, (InstanceOf, 0), Foo), ]
def get_create_types_query(cls, type_system_id, type_registry): """ Returns a CREATE UNIQUE query for an entire type hierarchy. Includes statements that create each type's attributes. Args: cls: An object to create a type hierarchy for. Returns: A tuple containing: (cypher query, classes to create nodes for, the object names). """ hierarchy_lines = [] set_lines = [] classes = {} query_args = { 'type_system_id': type_system_id, } # filter type relationships that we want to persist type_relationships = [] for cls1, rel_cls_idx, cls2 in get_type_relationships(cls): if issubclass(cls2, AttributedBase): type_relationships.append((cls1, rel_cls_idx, cls2)) # process type relationships is_first = True isa_props_counter = 0 for cls1, (rel_cls, base_idx), cls2 in type_relationships: name1 = cls1.__name__ type1 = type(cls1).__name__ node_for_create = ( '(`%(name)s`:%(type)s {' '__type__: {%(name)s__type}, ' 'id: {%(name)s__id}' '})' ) % { 'name': name1, 'type': type1, } create_statement = 'MERGE %s' % node_for_create node_for_ref = '(`%s`)' % name1 if name1 not in classes: classes[name1] = cls1 hierarchy_lines.append(create_statement) if is_first: is_first = False ln = 'MERGE (ts) -[:DEFINES]-> %s' % node_for_ref else: name2 = cls2.__name__ classes[name2] = cls2 rel_name = get_type_id(rel_cls) rel_type = rel_name.upper() prop_name = '%s_%d' % (rel_name, isa_props_counter) isa_props_counter += 1 props = type_registry.object_to_dict(IsA(base_index=base_idx)) query_args[prop_name] = props ln = 'MERGE %s -[%s:%s]-> (`%s`)' % ( node_for_ref, prop_name, rel_type, name2) set_lines.append('SET `%s` = {%s}' % (prop_name, prop_name)) hierarchy_lines.append(ln) # process attributes for name, cls in classes.items(): descriptor = type_registry.get_descriptor(cls) attributes = descriptor.declared_attributes for attr_name, attr in attributes.iteritems(): attr_dict = type_registry.object_to_dict( attr, for_db=True) attr_dict['name'] = attr_name node_contents = [] for entry, value in attr_dict.iteritems(): key = "%s_%s__%s" % (name, attr_name, entry) node_contents.append('%s: {%s}' % (entry, key)) query_args[key] = value ln = 'MERGE ({%s}) -[:DECLAREDON]-> (`%s`)' % ( ', '.join(node_contents), name) hierarchy_lines.append(ln) # processing class attributes for key, cls in classes.iteritems(): # all attributes of the class to be set via the query cls_props = type_registry.object_to_dict(cls, for_db=True) query_args['%s_props' % key] = cls_props set_lines.append('SET `%s` = {%s_props}' % (key, key)) # attributes which uniquely identify the class itself # these are used in the CREATE UNIQUE part of the query query_args['%s__id' % key] = cls_props['id'] query_args['%s__type' % key] = cls_props['__type__'] quoted_names = ('`{}`'.format(cls) for cls in classes.keys()) query = join_lines( 'MATCH (ts:TypeSystem) WHERE ts.id = {type_system_id}', (hierarchy_lines, ''), (set_lines, ''), 'RETURN %s' % ', '.join(quoted_names) ) return query, classes.values(), query_args