예제 #1
0
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),
    ]
예제 #2
0
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