Пример #1
0
def test_commit(app_empty, field_type, AttributeClass, value):
    app = app_empty
    with app.app_context():
        field = Field(name="field1", type_=field_type)
        assoc = TypeFieldAssociation(field=field)
        product_type = ProductType(name="map")
        product_type.fields = [assoc]
        sa.session.add(product_type)
        sa.session.commit()

    with app.app_context():
        product_type = ProductType.query.filter_by(name="map").one()
        assoc = product_type.fields[0]
        field = assoc.field
        product = Product(name="product1", type_=product_type)
        attr = AttributeClass(
            product=product,
            type_field_association=assoc,
            field=field,
            value=value,
        )
        sa.session.add(attr)
        sa.session.commit()

    with app.app_context():
        attr = AttributeClass.query.one()
        assert attr.__class__ is AttributeClass
        assert attr.type_field_association.field.name == "field1"
        assert attr.type_field_association.field.type_ is field_type
        assert attr.field.name == "field1"
        assert attr.field.type_ is field_type
        assert attr.value == value
        assert getattr(attr.product, AttributeClass.backref_column) == [attr]
        assert getattr(attr.field, AttributeClass.backref_column) == [attr]
Пример #2
0
def test_git_hub_user(app_empty):
    app = app_empty

    user1 = GitHubUser(login="******", git_hub_id="04:User1")
    user2 = GitHubUser(login="******", git_hub_id="04:User2")

    type_map = ProductType(name="map")
    map1 = Product(name="map1", type_=type_map, posting_git_hub_user=user1)

    with app.app_context():
        sa.session.add(user1)
        sa.session.add(user2)
        sa.session.add(map1)
        sa.session.commit()

    with app.app_context():
        map1 = Product.query.filter_by(name="map1").one()
        user1 = GitHubUser.query.filter_by(login="******").one()
        assert user1 == map1.posting_git_hub_user
        assert [map1] == user1.posted_products

    with app.app_context():
        map1 = Product.query.filter_by(name="map1").one()
        user2 = GitHubUser.query.filter_by(login="******").one()
        map1.updating_git_hub_user = user2
        sa.session.commit()

    with app.app_context():
        map1 = Product.query.filter_by(name="map1").one()
        user2 = GitHubUser.query.filter_by(login="******").one()
        assert user2 == map1.updating_git_hub_user
        assert [map1] == user2.updated_products
Пример #3
0
def test_relation(app):
    """A simple test of adding an object with relation"""

    type1 = ProductType(name="type1")
    product1 = Product(name="product1", type_=type1)

    # The relation has been already established
    assert type1 is product1.type_
    assert [product1] == type1.products

    # The primary and foreign keys are still None
    assert type1.type_id is None
    assert product1.product_id is None
    assert product1.type_id is None

    with app.app_context():
        sa.session.add(product1)
        sa.session.commit()

        # The primary keys are assigned
        assert type1.type_id is not None
        assert product1.product_id is not None

        # The foreign key is correctly set
        assert product1.type_id == type1.type_id

    with app.app_context():
        product1 = Product.query.filter_by(name="product1").first()

        # The relation is preserved in a different app context
        type1 = product1.type_
        assert "type1" == type1.name
        assert product1 is type1.products[0]
        assert product1.type_id == type1.type_id
Пример #4
0
def test_column(app_empty):
    app = app_empty

    with app.app_context():
        model = ProductType(
            name="map",
            order=2,
            indef_article="a",
            singular="map",
            plural="maps",
            icon="mdi-map",
        )
        sa.session.add(model)
        sa.session.commit()
        assert model.type_id
        type_id = model.type_id

    with app.app_context():
        model = ProductType.query.filter_by(type_id=type_id).one()
        assert model.type_id == type_id
        assert model.name == "map"
        assert model.order == 2
        assert model.indef_article == "a"
        assert model.singular == "map"
        assert model.plural == "maps"
        assert model.icon == "mdi-map"
Пример #5
0
def test_id(app_empty):

    # This test doesn't pass because the "set" events to the
    # relationships won't be triggered when the foreign keys are set.

    # It might be possible to pass this test with before_flush().
    # Useful links about before_flush():
    # https://docs.sqlalchemy.org/en/14/orm/session_events.html#persistence-events
    # https://stackoverflow.com/questions/36731020/sqlalchemy-orm-event-hook-for-attribute-persisted

    app = app_empty

    #
    # +---------+                 +--------+
    # |         |  --(child)-->   |        |
    # | parent1 |       |         | child1 |
    # |         |  <-(parent)--   |        |
    # +---------+                 +--------+
    #

    type_ = ProductType(name="robot")
    parent1 = Product(product_id=1, name="parent1", type_=type_)
    child1 = Product(product_id=2, name="child1", type_=type_)

    relation_type_parent = ProductRelationType(type_id=1, name="parent")
    relation_type_child = ProductRelationType(type_id=2, name="child")
    relation_type_parent.reverse = relation_type_child

    relation_parent1_to_child1 = ProductRelation(type_id=2,
                                                 self_product_id=1,
                                                 other_product_id=2)

    with app.app_context():
        sa.session.add(parent1)
        sa.session.add(child1)
        sa.session.add(relation_type_parent)
        sa.session.add(relation_parent1_to_child1)
        sa.session.flush()
        sa.session.commit()

    with app.app_context():
        parent1 = Product.query.filter_by(name="parent1").first()
        child1 = Product.query.filter_by(name="child1").first()

        assert 1 == len(parent1.relations)
        assert 1 == len(child1.relations)

        assert "child" == parent1.relations[0].type_.name
        assert "parent" == child1.relations[0].type_.name

        assert child1 is parent1.relations[0].other

        assert parent1 is child1.relations[0].other

        assert parent1.relations[0] is child1.relations[0].reverse
        assert parent1.relations[0].reverse is child1.relations[0]
Пример #6
0
def test_unique_constraint(app_empty):
    # A type cannot have multiple same field.
    app = app_empty
    with app.app_context():
        field1 = Field(name="field1", type_=FieldType.UnicodeText)
        assoc1 = TypeFieldAssociation(field=field1)
        assoc2 = TypeFieldAssociation(field=field1)
        type1 = ProductType(name="type1", fields=[assoc1, assoc2])
        sa.session.add(type1)
        with pytest.raises(exc.IntegrityError):
            sa.session.commit()
Пример #7
0
def test_repr(app_empty):
    app = app_empty  # noqa: F841

    model = TypeFieldAssociation()
    repr(model)

    field1 = Field(name="field1", type_=FieldType.UnicodeText)
    type1 = ProductType(name="type1")

    model.type_ = type1
    model.field = field1
    repr(model)
Пример #8
0
def test_self_reverse_type(app_empty, perm):

    app = app_empty

    #
    # +----------+                 +----------+
    # |          |  --(sibling)--> |          |
    # | sibling1 |       |         | sibling2 |
    # |          |  <-(sibling)--  |          |
    # +----------+                 +----------+
    #

    type_ = ProductType(name="robot")
    sibling1 = Product(name="sibling1", type_=type_)
    sibling2 = Product(name="sibling2", type_=type_)

    relation_type_sibling = ProductRelationType(name="sibling")
    relation_type_sibling.reverse = relation_type_sibling

    relation_sibling1_to_sibling2 = ProductRelation()

    # set 'type_', 'self_', 'other' in different orders
    # each triggers an event in which a reverse is automatically set
    for p in perm:
        if p == 1:
            relation_sibling1_to_sibling2.type_ = relation_type_sibling
        elif p == 2:
            relation_sibling1_to_sibling2.self_ = sibling1
        elif p == 3:
            relation_sibling1_to_sibling2.other = sibling2

    with app.app_context():
        sa.session.add(sibling1)
        sa.session.commit()

    with app.app_context():
        sibling1 = Product.query.filter_by(name="sibling1").first()
        sibling2 = Product.query.filter_by(name="sibling2").first()

        assert 1 == len(sibling1.relations)
        assert 1 == len(sibling2.relations)

        assert "sibling" == sibling1.relations[0].type_.name
        assert "sibling" == sibling2.relations[0].type_.name

        assert sibling1.relations[0].type_ is sibling2.relations[0].type_

        assert sibling2 is sibling1.relations[0].other

        assert sibling1 is sibling2.relations[0].other

        assert sibling1.relations[0] is sibling2.relations[0].reverse
        assert sibling1.relations[0].reverse is sibling2.relations[0]
Пример #9
0
def test_permutations(app_empty, perm):

    app = app_empty

    #
    # +---------+                 +--------+
    # |         |  --(child)-->   |        |
    # | parent1 |       |         | child1 |
    # |         |  <-(parent)--   |        |
    # +---------+                 +--------+
    #

    type_ = ProductType(name="robot")
    parent1 = Product(name="parent1", type_=type_)
    child1 = Product(name="child1", type_=type_)

    relation_type_parent = ProductRelationType(name="parent")
    relation_type_child = ProductRelationType(name="child")
    relation_type_parent.reverse = relation_type_child
    relation_type_child.reverse = relation_type_parent

    relation_parent1_to_child1 = ProductRelation()

    # set 'type_', 'self_', 'other' in different orders
    # each triggers an event in which a reverse is automatically set
    for p in perm:
        if p == 1:
            relation_parent1_to_child1.type_ = relation_type_child
        elif p == 2:
            relation_parent1_to_child1.self_ = parent1
        elif p == 3:
            relation_parent1_to_child1.other = child1

    with app.app_context():
        sa.session.add(parent1)
        sa.session.commit()

    with app.app_context():
        parent1 = Product.query.filter_by(name="parent1").first()
        child1 = Product.query.filter_by(name="child1").first()

        assert 1 == len(parent1.relations)
        assert 1 == len(child1.relations)

        assert "child" == parent1.relations[0].type_.name
        assert "parent" == child1.relations[0].type_.name

        assert child1 is parent1.relations[0].other

        assert parent1 is child1.relations[0].other

        assert parent1.relations[0] is child1.relations[0].reverse
        assert parent1.relations[0].reverse is child1.relations[0]
Пример #10
0
def app(app):
    y = app

    type_map = ProductType(name="map")
    map1 = Product(name="map1", type_=type_map)  # noqa: F841
    map2 = Product(name="map2", type_=type_map)  # noqa: F841
    map3 = Product(name="map3", type_=type_map)  # noqa: F841

    with y.app_context():
        sa.session.add(type_map)
        sa.session.commit()

    yield y
Пример #11
0
def test_repr(app_empty):
    app = app_empty

    model = ProductType(name="map")
    repr(model)

    with app.app_context():
        sa.session.add(model)
        sa.session.commit()
        type_id = model.type_id

    with app.app_context():
        model = ProductType.query.filter_by(type_id=type_id).one()
        repr(model)
Пример #12
0
def test_attach_to_self(app_empty):

    app = app_empty

    #
    # +---------+                 +--------+
    # |         |  --(child)-->   |        |
    # | parent1 |       |         | child1 |
    # |         |  <-(parent)--   |        |
    # +---------+                 +--------+
    #

    type_ = ProductType(name="robot")
    parent1 = Product(product_id=1, name="parent1", type_=type_)
    child1 = Product(product_id=2, name="child1", type_=type_)

    relation_type_parent = ProductRelationType(type_id=1, name="parent")
    relation_type_child = ProductRelationType(type_id=2, name="child")
    relation_type_parent.reverse = relation_type_child

    relation_parent1_to_child1 = ProductRelation(type_=relation_type_child,
                                                 other=child1)

    parent1.relations = [relation_parent1_to_child1]

    with app.app_context():
        sa.session.add(parent1)
        sa.session.add(child1)
        sa.session.add(relation_type_parent)
        sa.session.add(relation_parent1_to_child1)
        sa.session.flush()
        sa.session.commit()

    with app.app_context():
        parent1 = Product.query.filter_by(name="parent1").first()
        child1 = Product.query.filter_by(name="child1").first()

        assert 1 == len(parent1.relations)
        assert 1 == len(child1.relations)

        assert "child" == parent1.relations[0].type_.name
        assert "parent" == child1.relations[0].type_.name

        assert child1 is parent1.relations[0].other

        assert parent1 is child1.relations[0].other

        assert parent1.relations[0] is child1.relations[0].reverse
        assert parent1.relations[0].reverse is child1.relations[0]
Пример #13
0
def app(app_empty):

    y = app_empty

    #                              +--------+
    #               --(child)-->   |        |
    #                    |         | child1 |
    #  +---------+  <-(parent)--   |        |
    #  |         |                 +--------+
    #  | parent1 |
    #  |         |                 +--------+
    #  +---------+  --(child)-->   |        |
    #                    |         | child2 |
    #               <-(parent)--   |        |
    #                              +--------+

    type_ = ProductType(name="robot")
    parent1 = Product(name="parent1", type_=type_)
    child1 = Product(name="child1", type_=type_)
    child2 = Product(name="child2", type_=type_)

    relation_type_parent = ProductRelationType(name="parent")
    relation_type_child = ProductRelationType(name="child")
    relation_type_parent.reverse = relation_type_child

    # parent1 --(child)--> child1
    relation_parent1_to_child1 = ProductRelation()
    relation_parent1_to_child1.type_ = relation_type_child
    relation_parent1_to_child1.self_ = parent1
    relation_parent1_to_child1.other = child1

    ## the reverse relation child1 --(parent)--> parent1 will be
    ## automatically set

    # parent1 --(child)--> child2
    relation_parent1_to_child2 = ProductRelation()
    relation_parent1_to_child2.type_ = relation_type_child
    relation_parent1_to_child2.self_ = parent1
    relation_parent1_to_child2.other = child2

    ## the reverse relation child2 --(parent)--> parent1 will be
    ## automatically set

    # commit
    with y.app_context():
        sa.session.add(parent1)
        sa.session.commit()
    yield y
Пример #14
0
def test_product(app_empty):
    app = app_empty

    type_map = ProductType(name="map")
    map1 = Product(name="map1", type_=type_map)

    with app.app_context():
        sa.session.add(map1)
        sa.session.commit()

    with app.app_context():
        map1 = Product.query.filter_by(name="map1").one_or_none()
        assert map1 is not None
        type_map = map1.type_
        assert "map" == type_map.name
        assert [map1] == type_map.products
Пример #15
0
def app(app_empty):

    y = app_empty

    # product --- path1
    #          |
    #          +- path2
    type1 = ProductType(name="type1")
    product = Product(name="product", type_=type1)
    path1 = ProductFilePath(path="/path1")
    path2 = ProductFilePath(path="/path2")
    product.paths = [path1, path2]

    # commit
    with y.app_context():
        sa.session.add(product)
        sa.session.commit()
    yield y
Пример #16
0
def test_add_raise(app):
    """A simple test of adding an object with a wrong type"""

    type1 = ProductType(name="type1")

    # It is not impossible to instnaiate a date field with a wrong
    # type, e.g, str
    product1 = Product(name="product1",
                       time_posted="2019-02-13 10:15:21",
                       type_=type1)

    with app.app_context():

        # It is also possible to add
        sa.session.add(product1)

        # However, it is not possible to commit
        with pytest.raises(sqlalchemy.exc.StatementError):
            sa.session.commit()
Пример #17
0
def test_python_object(app):
    """A simple test about Python object"""

    type1 = ProductType(name="type1")

    with app.app_context():
        sa.session.add(type1)
        sa.session.commit()

        type1_ = ProductType.query.filter_by(name="type1").first()

        # the query returns the same Python object
        assert type1 is type1_

    with app.app_context():
        type1_ = ProductType.query.filter_by(name="type1").first()

        # In a different app context, no longer the same Python object
        assert type1 is not type1_
Пример #18
0
def test_column(app_empty):
    app = app_empty

    with app.app_context():
        field1 = Field(name="field1", type_=FieldType.UnicodeText)
        type1 = ProductType(name="type1")
        model = TypeFieldAssociation(
            order=123,
            type_=type1,
            field=field1,
        )
        sa.session.add(model)
        sa.session.commit()
        iid = model.iid

    with app.app_context():
        model = TypeFieldAssociation.query.filter_by(iid=iid).one()
        assert model.iid == iid
        assert model.order == 123
Пример #19
0
def test_constraint_type_required_delete(app_empty):
    app = app_empty

    type_map = ProductType(name="map")
    map1 = Product(name="map1", type_=type_map)

    with app.app_context():
        sa.session.add(map1)
        sa.session.commit()

    # fail to delete a type with a product
    with app.app_context():
        type_map = ProductType.query.filter_by(name="map").one()
        sa.session.delete(type_map)
        with pytest.raises(exc.IntegrityError):
            sa.session.commit()

    # assert the type and the product are still there
    with app.app_context():
        map1 = Product.query.filter_by(name="map1").one()
        assert map1 is not None
        type_map = map1.type_
        assert "map" == type_map.name
        assert [map1] == type_map.products

    # delete the product
    with app.app_context():
        map1 = Product.query.filter_by(name="map1").one()
        sa.session.delete(map1)
        sa.session.commit()

    # assert the type still exists
    with app.app_context():
        type_map = ProductType.query.filter_by(name="map").one()
        assert type_map is not None
        assert [] == type_map.products

    # delete the type
    with app.app_context():
        type_map = ProductType.query.filter_by(name="map").one()
        sa.session.delete(type_map)
        sa.session.commit()
Пример #20
0
def test_add(app):
    """A simple test of adding an object with a date field"""

    type1 = ProductType(name="type1")

    # time_posted needs to be initialized with a datetime.date
    time_posted = datetime.datetime(2019, 2, 23, 9, 10, 25)
    product1 = Product(name="product1", time_posted=time_posted, type_=type1)

    with app.app_context():
        sa.session.add(product1)
        sa.session.commit()

    with app.app_context():
        product1 = Product.query.filter_by(name="product1").first()

        # The type of the field "time_posted" of Product is "datetime.date"
        assert isinstance(product1.time_posted, datetime.date)

        assert (datetime.datetime(2019, 2, 23, 9, 10,
                                  25) == product1.time_posted)
Пример #21
0
def test_primary_key(app):
    """A simple test about the primary key"""

    type1 = ProductType(name="type1")

    # The primary key (type_id) is None at this point
    assert type1.type_id is None

    with app.app_context():
        sa.session.add(type1)
        sa.session.commit()

        # After the commit, type_id is automatically assigned
        type_id = type1.type_id
        assert type_id is not None

    with app.app_context():

        # The object can be retrived by the product_id in another context
        type1 = ProductType.query.filter_by(type_id=type_id).first()
        assert "type1" == type1.name
Пример #22
0
def app(app_empty):

    y = app_empty

    field1 = Field(name="field1", type_=FieldType.UnicodeText)
    field2 = Field(name="field2", type_=FieldType.Integer)

    assoc1 = TypeFieldAssociation(iid=1, field=field1)
    assoc2 = TypeFieldAssociation(iid=2, field=field2)

    type1 = ProductType(
        name="type1",
        fields=[assoc1, assoc2],
    )

    with y.app_context():
        sa.session.add(field1)
        sa.session.add(field2)
        sa.session.add(type1)
        sa.session.commit()

    yield y
Пример #23
0
def test_delte_orphan_type_field_association_and_field(app_empty):
    app = app_empty

    with app.app_context():
        field1 = Field(name="field1", type_=FieldType.UnicodeText)
        assoc1 = TypeFieldAssociation(field=field1)
        type1 = ProductType(type_id=1, name="type1", fields=[assoc1])

        product1 = Product(name="product1", type_=type1)
        field1_attribute_class = field1.type_.attribute_class
        attr1 = field1_attribute_class(
            product=product1,
            type_field_association=assoc1,
            field=field1,
            value="value1",
        )

        sa.session.add(product1)
        sa.session.commit()

        field1_id = field1.field_id
        assoc1_id = assoc1.iid
        product1_id = product1.product_id
        attr1_id = attr1.iid

    with app.app_context():
        assoc1 = TypeFieldAssociation.query.filter_by(iid=assoc1_id).one()
        field1 = Field.query.filter_by(field_id=field1_id).one()
        sa.session.delete(assoc1)
        sa.session.delete(field1)
        sa.session.commit()

    with app.app_context():
        product1 = Product.query.filter_by(product_id=product1_id).one()
        attr1 = field1_attribute_class.query.filter_by(
            iid=attr1_id
        ).one_or_none()
        assert attr1 is None
Пример #24
0
def test_simple(app):
    """A simple test of adding an object"""

    with app.app_context():

        # the number of the product types is zero initially
        assert 0 == len(ProductType.query.all())

    # this instantiation doesn't need be within a app context
    type1 = ProductType(name="type1")

    with app.app_context():
        sa.session.add(type1)
        sa.session.commit()

    with app.app_context():

        # the number of the product types is increased by one
        assert 1 == len(ProductType.query.all())

        # the new product type can be retrieved in a different app context
        type1_ = ProductType.query.filter_by(name="type1").one_or_none()
        assert isinstance(type1_, ProductType)
Пример #25
0
def test_order_nested(app_empty):
    app = app_empty

    field_attr1 = Field(name="attr1", type_=FieldType.UnicodeText)
    field_attr2 = Field(name="attr2", type_=FieldType.UnicodeText)
    Map = ProductType(type_id=1, name="map")
    assoc1 = TypeFieldAssociation(field=field_attr1)
    assoc2 = TypeFieldAssociation(field=field_attr2)
    Map.fields = [assoc1, assoc2]

    map1 = Product(product_id=1, name="map1", type_=Map)
    map2 = Product(product_id=2, name="map2", type_=Map)
    map3 = Product(product_id=3, name="map3", type_=Map)
    map4 = Product(product_id=4, name="map4", type_=Map)
    map5 = Product(product_id=5, name="map5", type_=Map)

    AttributeUnicodeText(
        product=map1,
        type_field_association=assoc1,
        field=field_attr1,
        value="1",
    )
    AttributeUnicodeText(
        product=map2,
        type_field_association=assoc1,
        field=field_attr1,
        value="2",
    )
    AttributeUnicodeText(
        product=map3,
        type_field_association=assoc1,
        field=field_attr1,
        value="1",
    )
    AttributeUnicodeText(
        product=map4,
        type_field_association=assoc1,
        field=field_attr1,
        value="2",
    )
    AttributeUnicodeText(
        product=map5,
        type_field_association=assoc1,
        field=field_attr1,
        value="1",
    )

    AttributeUnicodeText(
        product=map1,
        type_field_association=assoc2,
        field=field_attr2,
        value="b",
    )
    AttributeUnicodeText(
        product=map2,
        type_field_association=assoc2,
        field=field_attr2,
        value="a",
    )
    AttributeUnicodeText(
        product=map3,
        type_field_association=assoc2,
        field=field_attr2,
        value="c",
    )
    AttributeUnicodeText(
        product=map4,
        type_field_association=assoc2,
        field=field_attr2,
        value="b",
    )
    AttributeUnicodeText(
        product=map5,
        type_field_association=assoc2,
        field=field_attr2,
        value="a",
    )

    with app.app_context():
        sa.session.add(Map)
        sa.session.commit()

    with app.app_context():

        map1 = Product.query.filter_by(product_id=1).one()
        map2 = Product.query.filter_by(product_id=2).one()
        map3 = Product.query.filter_by(product_id=3).one()
        map4 = Product.query.filter_by(product_id=4).one()
        map5 = Product.query.filter_by(product_id=5).one()

        expected = [map2, map4, map5, map1, map3]

        # ORM Alias: https://docs.sqlalchemy.org/en/14/tutorial/data_select.html#orm-entity-aliases
        # refer to the same table multiple times
        AliasedAttributeUnicodeText1 = aliased(AttributeUnicodeText)
        AliasedAttributeUnicodeText2 = aliased(AttributeUnicodeText)

        AliasedTypeFieldAssociation1 = aliased(TypeFieldAssociation)
        AliasedTypeFieldAssociation2 = aliased(TypeFieldAssociation)

        AliasedField1 = aliased(Field)
        AliasedField2 = aliased(Field)

        # sort descending order of attr1 then ascending order of attr2
        query = (
            Product.query.join(ProductType)
            .filter_by(name="map")
            .join(AliasedAttributeUnicodeText1)
            .join(AliasedTypeFieldAssociation1)
            .join(AliasedField1)
            .filter_by(name="attr1")
            .order_by(AliasedAttributeUnicodeText1.value.desc())
            .join(
                AliasedAttributeUnicodeText2, Product.attributes_unicode_text
            )
            .join(AliasedTypeFieldAssociation2)
            .join(AliasedField2)
            .filter_by(name="attr2")
            .order_by(AliasedAttributeUnicodeText2.value)
        )

        # print(sqlparse.format(str(query), reindent=True))

        actual = query.all()

        assert actual == expected
Пример #26
0
def app(app_empty):

    y = app_empty

    # create fields
    field1 = Field(name="attr1", type_=FieldType.UnicodeText)
    field2 = Field(name="date_produced", type_=FieldType.Date)
    field3 = Field(name="time_posted", type_=FieldType.DateTime)
    fields = [field1, field2, field3]

    # create product types
    Map = ProductType(
        type_id=1,
        name="map",
        order=2,
        indef_article="a",
        singular="map",
        plural="maps",
        icon="mdi-map",
        fields=[TypeFieldAssociation(field=f) for f in fields],
    )
    Beam = ProductType(
        type_id=2,
        name="beam",
        order=1,
        indef_article="a",
        singular="beam",
        plural="beams",
        icon="mdi-spotlight-beam",
        fields=[TypeFieldAssociation(field=f) for f in fields],
    )

    # create products
    map1 = Product(product_id=1, name="map1", type_=Map)
    values = (
        "value1",
        datetime.date(2020, 2, 1),
        datetime.datetime(2020, 2, 1, 9, 10, 25),
    )
    for assoc, value in zip(Map.fields, values):
        assoc.field.type_.attribute_class(
            product=map1,
            type_field_association=assoc,
            field=assoc.field,
            value=value,
        )

    map2 = Product(product_id=2, name="map2", type_=Map)
    values = (
        "value2",
        datetime.date(2020, 2, 10),
        datetime.datetime(2020, 2, 10, 13, 20, 2),
    )
    for assoc, value in zip(Map.fields, values):
        assoc.field.type_.attribute_class(
            product=map2,
            type_field_association=assoc,
            field=assoc.field,
            value=value,
        )

    map3 = Product(product_id=3, name="map3", type_=Map)
    values = (
        "value3",
        datetime.date(2020, 3, 19),
        datetime.datetime(2020, 3, 20, 8, 45, 30),
    )
    for assoc, value in zip(Map.fields, values):
        assoc.field.type_.attribute_class(
            product=map3,
            type_field_association=assoc,
            field=assoc.field,
            value=value,
        )

    beam1 = Product(product_id=4, name="beam1", type_=Beam)
    values = (
        "value4",
        datetime.date(2020, 2, 5),
        datetime.datetime(2020, 2, 5, 12, 3, 48),
    )
    for assoc, value in zip(Map.fields, values):
        assoc.field.type_.attribute_class(
            product=beam1,
            type_field_association=assoc,
            field=assoc.field,
            value=value,
        )

    beam2 = Product(product_id=5, name="beam2", type_=Beam)
    values = (
        "value5",
        datetime.date(2020, 3, 4),
        datetime.datetime(2020, 3, 4, 19, 22, 5),
    )
    for assoc, value in zip(Map.fields, values):
        assoc.field.type_.attribute_class(
            product=beam2,
            type_field_association=assoc,
            field=assoc.field,
            value=value,
        )

    with y.app_context():
        sa.session.add(Map)
        sa.session.add(Beam)
        sa.session.commit()

    yield y