Example #1
0
def test_multi_default_1(init_world, get_client):
    '''
    friends - always childred 1 & 2
    '''
    init_world(family.dm)
    client = get_client()

    #   1.  Add best_friend field.
    child = dm().object('child')
    child.add_field(Rel('friends', stores=child, multi=True, default=[1, 2]))

    #   If this is PG storage, we need to update database schema
    if issubclass(type(world().storage), PGStorage):
        conn = world().storage._conn
        conn.cursor().execute('ALTER TABLE child ADD COLUMN friends integer[]')
        conn.commit()

    #   2.  Post a child without friends
    data, status, headers = client.post('child', {'name': 'c'})
    assert status == 201
    assert data['friends'] == [1, 2]

    #   3.  Post a child with friends
    data, status, headers = client.post('child', {
        'name': 'c',
        'friends': [2, 3]
    })
    assert status == 201
    assert data['friends'] == [2, 3]
Example #2
0
def test_single_default_1(init_world, get_client):
    '''
    Best Friend - always child 1
    '''
    init_world(family.dm)
    client = get_client()

    #   1.  Add best_friend field.
    child = dm().object('child')
    child.add_field(Rel('best_friend', stores=child, multi=False, default=1))

    #   If this is PG storage, we need to update database schema
    if issubclass(type(world().storage), PGStorage):
        conn = world().storage._conn
        conn.cursor().execute(
            'ALTER TABLE child ADD COLUMN best_friend integer REFERENCES child(id) DEFERRABLE'
        )
        conn.commit()

    #   2.  Post a child without best friend
    data, status, headers = client.post('child', {'name': 'c'})
    assert status == 201
    assert data['best_friend'] == 1

    #   3.  Post a child with best friend
    data, status, headers = client.post('child', {
        'name': 'c',
        'best_friend': 2
    })
    assert status == 201
    assert data['best_friend'] == 2
Example #3
0
def init_cookies_with_shelf_1(init_world):
    '''Add shelf to cookies datamodel. 
    Shelf knows it's jars, jar has no idea about shelf
    '''
    dm = deepcopy(cookies.dm)
    shelf = dm.create_object('shelf')
    shelf.add_field(Scalar('id', pkey=True, type_=int))
    shelf.add_field(Rel('jars', stores=dm.object('jar'), multi=True))

    init_world(dm)

    #   If this is PG storage, we need to update database schema
    if issubclass(type(world().storage), PGStorage):
        conn = world().storage._conn
        conn.cursor().execute('CREATE TABLE shelf (id serial PRIMARY KEY, jars integer[])')
        conn.commit()
Example #4
0
def init_cookies_with_shelf_2(init_world):
    '''Add shelf to cookies datamodel. 
    Jar knows it's shelf, shelf has no idea about jars.
    '''
    dm = deepcopy(cookies.dm)
    shelf = dm.create_object('shelf')
    shelf.add_field(Scalar('id', pkey=True, type_=int))
    jar = dm.object('jar')
    jar.add_field(Rel('shelf', stores=shelf, multi=False))
    init_world(dm)

    #   If this is PG storage, we need to update database schema
    if issubclass(type(world().storage), PGStorage):
        conn = world().storage._conn
        conn.cursor().execute('CREATE TABLE shelf (id serial PRIMARY KEY)')
        conn.cursor().execute('ALTER TABLE jar ADD COLUMN shelf integer REFERENCES shelf(id)')
        conn.commit()
Example #5
0
def test_single_multi_2(init_world, get_client):
    '''
    Best Friend - new female named BLARGH (note: new anonymous child creates infinite recursion)
    '''
    init_world(family.dm)
    client = get_client()

    #   1.  Add best_friend field. New child's best friend is always child no 1.
    child = dm().object('child')
    child.add_field(
        Rel('best_friend',
            stores=dm().object('female'),
            multi=False,
            default={'name': 'BLARGH'}))

    #   If this is PG storage, we need to update database schema
    if issubclass(type(world().storage), PGStorage):
        conn = world().storage._conn
        conn.cursor().execute(
            'ALTER TABLE child ADD COLUMN best_friend integer REFERENCES child(id) DEFERRABLE'
        )
        conn.commit()

    #   2.  Post a child without best friend
    data, status, headers = client.post('child', {'name': 'c'})
    assert status == 201
    assert data['best_friend'] == 3

    #   3.  Check if name was saved
    data, status, headers = client.get('female', 3)
    assert status == 200
    assert data['name'] == 'BLARGH'

    #   4.  Post a child with best friend
    data, status, headers = client.post('child', {
        'name': 'c',
        'best_friend': 2
    })
    assert status == 201
    assert data['best_friend'] == 2
Example #6
0
def test_multi_default_2(init_world, get_client):
    '''
    Friends - females named BLARGH and BLERGH
    '''
    init_world(family.dm)
    client = get_client()

    #   1.  Add friends field - two fresh females, BLARGH and BLERGH
    child = dm().object('child')
    child.add_field(
        Rel('friends',
            stores=dm().object('female'),
            multi=True,
            default=[{
                'name': 'BLARGH'
            }, {
                'name': 'BLERGH'
            }]))

    #   If this is PG storage, we need to update database schema
    if issubclass(type(world().storage), PGStorage):
        conn = world().storage._conn
        conn.cursor().execute('ALTER TABLE child ADD COLUMN friends integer[]')
        conn.commit()

    #   2.  Post a child without best friend
    data, status, headers = client.post('child', {'name': 'c'})
    assert status == 201
    assert data['friends'] == [3, 4]

    #   3.  Post a child with best friend
    data, status, headers = client.post('child', {
        'name': 'c',
        'friends': [1, 2]
    })
    assert status == 201
    assert data['friends'] == [1, 2]
Example #7
0
#   Create 'cookie' object. Each cookie has
#   *   id, which is an integer primary key
#   *   type, which is a string
cookie = dm.create_object('cookie')
cookie.add_field(Scalar('id', pkey=True, type_=int))
cookie.add_field(Scalar('type', type_=str))

#   Create 'jar' object. The only field is id,
#   which is also an integer primary key
jar = dm.create_object('jar')
jar.add_field(Scalar('id', pkey=True, type_=int))

#   Add a relational field to cookie.
#   This field ('jar') can hold at most one jar (and nothing else)
cookie.add_field(Rel('jar', stores=jar, multi=False))

#   Jar gets 'cookies' field, where any number of cookies can be held.
jar.add_field(Rel('cookies', stores=cookie, multi=True))

#   Until now, fields cookie.jar and jar.cookie could mean totally different things,
#   e.g. cookie.jar could be a jar with ingredients required to bake this cookie,
#   and jar.cookies could be a list of all cookies that could fit in the jar.
#
#   Now we declare that this is the same relationship: if certain cookie has certain
#   jar on its 'jar' field, this jar also has this cookie among its 'cookies'.
dm.connect(jar, 'cookies', cookie, 'jar')

#   dm object contains whole data model definition
__all__ = [dm]
Example #8
0
    def _create_relationships(self):
        '''Create all relationships

        Note: Columns that are simultaneously PRIMARY KEY and FOREIGN KEY are forbidden.
              This simplification is requred by current DataModel, where relationship fields
              are not allowed to be primary keys. This might change in the future.
        Note 2: Each relationship is between "two tables", but table might reference itself,
                so this are not necesary two different tables.

        Possible relationships could be divided into two groups:

        A) Without 'join' table

        Relationships without additional 'join table' are defined by single
        FOREIGN KEY column. Owner of this column will be called 'child', table
        pointed by FK constraint - 'parent'. Possible relationships:
            CHILD       PARENT      CONSTRAINT
            0 .. n      0 .. 1      FOREIGN KEY
            0 .. n      1 .. 1      FOREIGN KEY NOT NULL
            0 .. 1      0 .. 1      FOREIGN KEY UNIQUE
            0 .. 1      1 .. 1      FOREIGN KEY NOT NULL UNIQUE

        B) With 'join' table

        All other relationships that could be clearly defined by database structure require
        additional join table (reminder: PRIMARY KEY FOREIGN KEY columns are forbidden).

        Such relationships are not handled it any clever way. Join table representes additional object,
        referenced in a "simple" way (described in A) by both other tables.
        '''

        #   For each foreign key field we create two Rel fields and connect them.
        #   "Child" is - as above - object with FK field.
        for child_name, column_names in self._fk_columns.items():
            for child_column_name in column_names:
                #   relationship data, check Query.get_rel_data for description
                parent_name, child_card, parent_card, child_cascade = \
                        self._q.get_rel_data(self._name, child_name, child_column_name)

                #   objects
                child = self._dm.object(child_name)
                parent = self._dm.object(parent_name)

                #   "multi" fields are '*'/'+', single are '?' and '1'
                child_multi = child_card in ('*', '+')
                parent_multi = parent_card in ('*', '+')

                #   name of the other side virtual (-> not a column) field
                parent_column_name = self._default_parent_field_name(
                    child, parent, child_card, child_column_name)

                #   create fields
                child.add_field(
                    Rel(child_column_name,
                        stores=parent,
                        multi=parent_multi,
                        cascade=child_cascade))
                parent.add_field(
                    Rel(parent_column_name,
                        stores=child,
                        multi=child_multi,
                        cascade=False))

                #   and connect them
                self._dm.connect(child, child_column_name, parent,
                                 parent_column_name)
Example #9
0
#   OBJECTS & SCALAR FIELDS
male = dm.create_object('male')
male.add_field(Scalar('id', pkey=True, type_=int))
male.add_field(Scalar('name', type_=str))

female = dm.create_object('female')
female.add_field(Scalar('id', pkey=True, type_=int))
female.add_field(Scalar('name', type_=str))

child = dm.create_object('child')
child.add_field(Scalar('id', pkey=True, type_=int))
child.add_field(Scalar('name', type_=str))

#   REL FIELDS
male.add_field(Rel('wife', stores=female, multi=False))  # noqa: E241
male.add_field(Rel('children', stores=child, multi=True))  # noqa: E241
female.add_field(Rel('husband', stores=male, multi=False))  # noqa: E241
female.add_field(Rel('children', stores=child, multi=True))  # noqa: E241
child.add_field(Rel('father', stores=male, multi=False))  # noqa: E241
child.add_field(Rel('mother', stores=female, multi=False))  # noqa: E241

#   CONNECTIONS
dm.connect(male, 'wife', female, 'husband')  # noqa: E241
dm.connect(child, 'father', male, 'children')  # noqa: E241
dm.connect(child, 'mother', female, 'children')  # noqa: E241


#   CALC FIELDS
def url(instance):
    id_ = instance.id()