Skip to content

Relationships

Simple relationship

from corm import Storage, Entity, Nested


class Address(Entity):
    street: str
    number: int


class User(Entity):
    name: str
    address: Address = Nested(entity_type=Address)


storage = Storage()
john = User(
    data={
        'name': 'John',
        'address': {
            'street': 'First',
            'number': 1,
        },
    },
    storage=storage,
)

assert john.address.street == 'First'
assert john.address.number == 1

Bidirectional relationships

from corm import Storage, Entity, Relationship, Nested


class Address(Entity):
    street: str
    number: int
    user: 'User' = Relationship(entity_type='User')


class User(Entity):
    name: str
    address: Address = Nested(
        entity_type=Address,
        back_relation=True,
    )


storage = Storage()
john = User(
    data={
        'name': 'John',
        'address': {
            'street': 'First',
            'number': 1,
        },
    },
    storage=storage,
)

assert john.address.user == john

Self-nested

import typing as t

from corm import Storage, Entity, Relationship, Nested


class Item(Entity):
    id: int
    items: t.List['Item'] = Nested(
        entity_type='Item',
        back_relation=True,
        many=True,
        default=list,
    )
    parent: 'Item' = Relationship(entity_type='Item')


storage = Storage()
item1 = Item({'id': 1, 'items': [{'id': 2}, {'id': 3}]}, storage)
item2, item3 = item1.items

assert item1.id == 1
assert item1.parent is None

assert item2.id == 2
assert item2.parent == item1
assert item2.items == []

assert item3.id == 3
assert item3.parent == item1
assert item3.items == []

Change relationships between entities

from corm import Entity, Relationship, Nested, Storage


class Address(Entity):
    street: str
    user: 'User' = Relationship(entity_type='User')


class User(Entity):
    id: int
    address: Address = Nested(
        entity_type=Address,
        back_relation=True,
    )


storage = Storage()
john = User(
    data={
        'id': 1,
        'name': 'John',
        'description': 'john smith',
        'address': {
            'street': 'kirova',
        },
    },
    storage=storage,
)

old_address = john.address

assert old_address.user is john

address = Address(data={'street': 'lenina'}, storage=storage)
john.address = address

assert old_address.user is None
assert address.user == john
assert john.address is address

Also it works with many=True

import typing as t

from corm import Entity, Relationship, Nested, Storage


class Address(Entity):
    street: str
    user: 'User' = Relationship(entity_type='User')


class User(Entity):
    id: int
    addresses: t.List[Address] = Nested(
        entity_type=Address,
        back_relation=True,
        many=True,
    )


storage = Storage()
john = User(
    data={
        'id': 1,
        'name': 'John',
        'description': 'john smith',
        'addresses': [
            {
                'street': 'kirova 1',
            },
            {
                'street': 'kirova 2',
            },
        ],
    },
    storage=storage,
)

old_address1, old_address2 = john.addresses

# you can change existing list
john.addresses.remove(old_address1)

assert old_address1.user is None
assert old_address2.user is john

john.addresses.clear()

assert old_address1.user is None
assert old_address2.user is None
assert john.addresses == []

new_address1 = Address(data={'street': 'lenina 1'}, storage=storage)
new_address2 = Address(data={'street': 'lenina 2'}, storage=storage)

john.addresses.append(new_address1)

assert new_address1.user is john
assert john.addresses == [new_address1]

john.addresses.extend([new_address2])

assert new_address2.user is john
assert john.addresses == [new_address1, new_address2]

# or completely replace it
john.addresses = [old_address1]

assert new_address1.user is None
assert new_address2.user is None
assert old_address1.user is john

Note

As you can see it changes both user and address, but keep in mind it is possible to change relationship through Nested but not through Relationship. In this example address.user = user will raise ValueError

It is not common case but is is able to use this way

from corm import Storage, Entity, Relationship, RelationType

storage = Storage()


class Address(Entity):
    street: str
    number: int


class User(Entity):
    name: str
    address: Address = Relationship(
        entity_type=Address,
        relation_type=RelationType.PARENT,
    )


address = Address({'street': 'First', 'number': 1}, storage)
john = User({'name': 'John'}, storage)

storage.make_relation(
    from_=john,
    to_=address,
    relation_type=RelationType.PARENT,
)

assert john.address == address