def test_model_database_type_simple_json(engine, sessionmaker, type_, value): """ GIVEN JSON type WHEN a specification is written for the combination and a model created and initialized with the value THEN the queried value complies with the type calculated by type_.model. """ spec = { "components": { "schemas": { "Table": { "properties": { "id": { "type": "integer", "x-primary-key": True, "x-autoincrement": True, }, "column": {"type": type_, "x-json": True}, }, "x-tablename": "table", "type": "object", "required": ["column"], } } } } # Creating model factory base = declarative.declarative_base() model_factory = open_alchemy.init_model_factory(spec=spec, base=base) model = model_factory(name="Table") # Calculate the expected type schemas_artifacts = schemas_artifacts_module.get_from_schemas( schemas=spec["components"]["schemas"], stay_within_model=False ) assert "Table" in schemas_artifacts model_schemas_artifacts = schemas_artifacts["Table"] model_models_artifacts = artifacts.calculate( artifacts=model_schemas_artifacts, name="Table" ) assert len(model_models_artifacts.sqlalchemy.columns) == 2 column_column_artifacts = model_models_artifacts.sqlalchemy.columns[1] assert column_column_artifacts.name == "column" calculated_type_str = column_column_artifacts.type calculated_type = eval(calculated_type_str) # pylint: disable=eval-used # Creating models base.metadata.create_all(engine) # Creating model instance model_instance = model(column=value) session = sessionmaker() session.add(model_instance) session.flush() # Querying session queried_model = session.query(model).first() assert queried_model.column == value typeguard.check_type("queried_model.column", queried_model.column, calculated_type)
def test_calculate_column_empty(artifacts, expected_empty): """ GIVEN artifacts WHEN calculate is called with the artifacts THEN the given expected columns are added to the artifacts. """ returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name="Model") assert returned_artifacts.sqlalchemy.empty == expected_empty
def test_calculate_description(artifacts, expected_description): """ GIVEN artifacts WHEN calculate is called with the artifacts THEN the description is added to the artifacts. """ name = "Model" returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name=name) assert returned_artifacts.sqlalchemy.description == expected_description
def test_calculate_parent(): """ GIVEN WHEN calculate is called THEN the correct parent class is set. """ artifacts = _construct_model_artifacts([], None) returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name="Model") assert returned_artifacts.sqlalchemy.parent_cls == _EXPECTED_CLS_BASE
def test_calculate_name(): """ GIVEN name WHEN calculate is called with the name THEN the name is added to the artifacts. """ artifacts = _construct_model_artifacts([], None) name = "Model" returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name=name) assert returned_artifacts.sqlalchemy.name == name
def test_calculate_td_names(artifacts, expected_required_name, expected_not_required_name): """ GIVEN artifacts WHEN calculate is called with the artifacts THEN the given expected td required and not required names are added to the artifacts. """ returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name="Model") assert returned_artifacts.typed_dict.required.name == expected_required_name assert returned_artifacts.typed_dict.not_required.name == expected_not_required_name
def test_calculate_typed_dict_column_empty(artifacts, expected_required_empty, expected_not_required_empty): """ GIVEN artifacts and expected required and not required empty WHEN calculate is called with the artifacts THEN the typed dict required and not required empty are as expected. """ returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name="Model") assert returned_artifacts.typed_dict.required.empty == expected_required_empty assert (returned_artifacts.typed_dict.not_required.empty == expected_not_required_empty)
def test_calculate_td_parent(artifacts, expected_required_parent, expected_not_required_parent): """ GIVEN artifacts WHEN calculate is called with the artifacts THEN the given expected td required and not required parents are added to the artifacts. """ returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name="Model") assert (returned_artifacts.typed_dict.required.parent_class == expected_required_parent) artifacts_not_required_parent = ( returned_artifacts.typed_dict.not_required.parent_class) assert artifacts_not_required_parent == expected_not_required_parent
def test_calculate_arg(): """ GIVEN artifacts WHEN calculate is called with the artifacts THEN the given expected args are added to the artifacts. """ artifacts = _construct_model_artifacts( [ ( "prop_1", _construct_simple_property_artifacts(False), ), ( "prop_2", _construct_simple_property_artifacts(True), ), ], None, ) returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name="Model") assert returned_artifacts.sqlalchemy.arg.not_required == [ models_types.ColumnArgArtifacts( name="prop_1", init_type="typing.Optional[int]", from_dict_type="typing.Optional[int]", default=None, read_only=None, ) ] assert returned_artifacts.sqlalchemy.arg.required == [ models_types.ColumnArgArtifacts( name="prop_2", init_type="int", from_dict_type="int", default=None, read_only=None, ) ]
def test_calculate_typed_dict_column(): """ GIVEN artifacts WHEN calculate is called with the artifacts THEN the given expected typed dict columns are added to the artifacts. """ artifacts = _construct_model_artifacts( [ ( "prop_1", _construct_simple_property_artifacts(False), ), ( "prop_2", _construct_simple_property_artifacts(True), ), ], None, ) returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name="Model") assert returned_artifacts.typed_dict.not_required.props == [ models_types.ColumnArtifacts( name="prop_1", type="int", description=None, ) ] assert returned_artifacts.typed_dict.required.props == [ models_types.ColumnArtifacts( name="prop_2", type="int", description=None, ) ]
def test_calculate_column(): """ GIVEN artifacts WHEN calculate is called with the artifacts THEN the given expected columns are added to the artifacts. """ artifacts = _construct_model_artifacts( [( "prop_1", _construct_simple_property_artifacts(False), )], None, ) returned_artifacts = models_artifacts.calculate(artifacts=artifacts, name="Model") assert returned_artifacts.sqlalchemy.columns == [ models_types.ColumnArtifacts( name="prop_1", type="int", description=None, ) ]
def test_model_database_type_many_to_many(engine, sessionmaker): """ GIVEN spec for a many to many relationship WHEN spec is constructed with model factory and queried THEN the referenced and back reference type is an array that is not nullable. """ # Defining specification spec = { "components": { "schemas": { "RefTable": { "properties": { "id": { "type": "integer", "x-primary-key": True }, "name": { "type": "string" }, }, "x-tablename": "ref_table", "x-backref": "tables", "type": "object", "x-secondary": "association", }, "Table": { "properties": { "id": { "type": "integer", "x-primary-key": True }, "name": { "type": "string" }, "ref_tables": { "type": "array", "items": { "$ref": "#/components/schemas/RefTable" }, }, }, "x-tablename": "table", "type": "object", }, } } } # Creating model factory base = declarative.declarative_base() model_factory = open_alchemy.init_model_factory(spec=spec, base=base) model = model_factory(name="Table") ref_model = model_factory(name="RefTable") # Calculate the expected type schemas_artifacts = schemas_artifacts_module.get_from_schemas( schemas=spec["components"]["schemas"], stay_within_model=False) # Expecting 3 due to association assert "RefTable" in schemas_artifacts ref_model_schemas_artifacts = schemas_artifacts["RefTable"] ref_model_models_artifacts = artifacts.calculate( artifacts=ref_model_schemas_artifacts, name="RefTable") assert len(ref_model_models_artifacts.sqlalchemy.columns) == 3 tables_column_artifacts = ref_model_models_artifacts.sqlalchemy.columns[2] assert tables_column_artifacts.name == "tables" calculated_backref_type_str = tables_column_artifacts.type assert "Table" in schemas_artifacts model_schemas_artifacts = schemas_artifacts["Table"] model_models_artifacts = artifacts.calculate( artifacts=model_schemas_artifacts, name="Table") assert len(model_models_artifacts.sqlalchemy.columns) == 3 ref_tables_column_artifacts = model_models_artifacts.sqlalchemy.columns[2] assert ref_tables_column_artifacts.name == "ref_tables" calculated_type_str = ref_tables_column_artifacts.type # Creating models base.metadata.create_all(engine) session = sessionmaker() # Creating instance of model without ref_models model_instance1 = model(id=11, name="ref table name 1") session.add(model_instance1) # Creating instance of model without empty ref_models model_instance2 = model(id=21, name="ref table name 2", ref_tables=[]) session.add(model_instance2) # Creating instance of model with single ref_model model_instance3 = model( id=31, name="ref table name 3", ref_tables=[ref_model(id=32, name="table name 3")], ) session.add(model_instance3) session.flush() # Querying session queried_models = session.query(model).all() assert len(queried_models[0].ref_tables) == 0 assert len(queried_models[1].ref_tables) == 0 assert len(queried_models[2].ref_tables) == 1 # Try constructing null for models with pytest.raises(TypeError): model(id=41, name="ref table name 4", ref_tables=None) assert calculated_type_str == 'typing.Sequence["TRefTable"]' # Creating instance of ref_model without models ref_model_instance5 = ref_model(id=51, name="ref table name 5") session.add(ref_model_instance5) # Creating instance of ref_model without empty models ref_model_instance6 = ref_model(id=61, name="ref table name 6", tables=[]) session.add(ref_model_instance6) # Creating instance of ref_model with single model ref_model_instance7 = ref_model(id=71, name="ref table name 7", tables=[model(id=72, name="table name 7")]) session.add(ref_model_instance7) session.flush() # Querying session queried_ref_models = session.query(ref_model).all() assert len(queried_ref_models[1].tables) == 0 assert len(queried_ref_models[2].tables) == 0 assert len(queried_ref_models[3].tables) == 1 # Try constructing null for models with pytest.raises(TypeError): ref_model(id=81, name="ref table name 8", tables=None) assert calculated_backref_type_str == 'typing.Sequence["TTable"]'
def test_model_database_type_one_to_one_not_nullable(engine, sessionmaker): """ GIVEN spec with one to one relationship that is not nullable WHEN models are constructed and None is passed for the object reference THEN sqlalchemy.exc.IntegrityError is raised for the relationship and not for the back reference which is still a single object that is nullable. """ # Defining specification spec = { "components": { "schemas": { "RefTable": { "properties": { "id": { "type": "integer", "x-primary-key": True }, "name": { "type": "string" }, }, "x-tablename": "ref_table", "x-backref": "table", "type": "object", "x-uselist": False, }, "Table": { "properties": { "id": { "type": "integer", "x-primary-key": True }, "name": { "type": "string" }, "ref_table": { "allOf": [ { "$ref": "#/components/schemas/RefTable" }, { "nullable": False }, ] }, }, "x-tablename": "table", "type": "object", }, } } } # Creating model factory base = declarative.declarative_base() model_factory = open_alchemy.init_model_factory(spec=spec, base=base) model = model_factory(name="Table") ref_model = model_factory(name="RefTable") # Calculate the expected type schemas_artifacts = schemas_artifacts_module.get_from_schemas( schemas=spec["components"]["schemas"], stay_within_model=False) assert "RefTable" in schemas_artifacts ref_model_schemas_artifacts = schemas_artifacts["RefTable"] ref_model_models_artifacts = artifacts.calculate( artifacts=ref_model_schemas_artifacts, name="RefTable") assert len(ref_model_models_artifacts.sqlalchemy.columns) == 3 table_column_artifacts = ref_model_models_artifacts.sqlalchemy.columns[2] assert table_column_artifacts.name == "table" calculated_backref_type_str = table_column_artifacts.type assert "Table" in schemas_artifacts model_schemas_artifacts = schemas_artifacts["Table"] model_models_artifacts = artifacts.calculate( artifacts=model_schemas_artifacts, name="Table") assert len(model_models_artifacts.sqlalchemy.columns) == 3 ref_table_column_artifacts = model_models_artifacts.sqlalchemy.columns[2] assert ref_table_column_artifacts.name == "ref_table" calculated_type_str = ref_table_column_artifacts.type # Creating models base.metadata.create_all(engine) session = sessionmaker() # Creating instance of ref_model without model ref_model_instance1 = ref_model(id=11, name="ref table name 1") session.add(ref_model_instance1) # Creating instance of ref_model with model ref_model_instance2 = ref_model(id=21, name="ref table name 2", table=model(id=22, name="table name 2")) session.add(ref_model_instance2) session.flush() # Querying session queried_ref_models = session.query(ref_model).all() assert queried_ref_models[0].table is None assert queried_ref_models[1].table is not None assert calculated_backref_type_str == 'typing.Optional["TTable"]' # Creating models base.metadata.create_all(engine) # Creating instance of model with None ref_model model_instance = model(id=32, name="table name 3", ref_table=None) session = sessionmaker() session.add(model_instance) with pytest.raises(sqlalchemy.exc.IntegrityError): session.flush() # Check that returned type is correct assert calculated_type_str == '"TRefTable"'
def test_model_database_type_one_to_one(engine, sessionmaker): """ GIVEN spec for a one to one relationship WHEN spec is constructed with model factory and queried THEN the referenced type is a single object that is nullable and the back reference is an single object that is nullable. """ # Defining specification spec = { "components": { "schemas": { "RefTable": { "properties": { "id": { "type": "integer", "x-primary-key": True }, "name": { "type": "string" }, }, "x-tablename": "ref_table", "x-backref": "table", "x-uselist": False, "type": "object", }, "Table": { "properties": { "id": { "type": "integer", "x-primary-key": True }, "name": { "type": "string" }, "ref_table": { "$ref": "#/components/schemas/RefTable" }, }, "x-tablename": "table", "type": "object", }, } } } # Creating model factory base = declarative.declarative_base() model_factory = open_alchemy.init_model_factory(spec=spec, base=base) model = model_factory(name="Table") ref_model = model_factory(name="RefTable") # Calculate the expected type schemas_artifacts = schemas_artifacts_module.get_from_schemas( schemas=spec["components"]["schemas"], stay_within_model=False) assert "RefTable" in schemas_artifacts ref_model_schemas_artifacts = schemas_artifacts["RefTable"] ref_model_models_artifacts = artifacts.calculate( artifacts=ref_model_schemas_artifacts, name="RefTable") assert len(ref_model_models_artifacts.sqlalchemy.columns) == 3 table_column_artifacts = ref_model_models_artifacts.sqlalchemy.columns[2] assert table_column_artifacts.name == "table" calculated_backref_type_str = table_column_artifacts.type assert "Table" in schemas_artifacts model_schemas_artifacts = schemas_artifacts["Table"] model_models_artifacts = artifacts.calculate( artifacts=model_schemas_artifacts, name="Table") assert len(model_models_artifacts.sqlalchemy.columns) == 3 ref_table_column_artifacts = model_models_artifacts.sqlalchemy.columns[2] assert ref_table_column_artifacts.name == "ref_table" calculated_type_str = ref_table_column_artifacts.type # Creating models base.metadata.create_all(engine) session = sessionmaker() # Creating instance of model and ref_model ref_model_instance1 = ref_model(id=11, name="ref table name 1") model_instance1 = model(id=12, name="table name 1", ref_table=ref_model_instance1) session.add(ref_model_instance1) session.add(model_instance1) session.flush() # Creating instance of model with None ref_model model_instance2 = model(id=22, name="table name 2", ref_table=None) session.add(model_instance2) session.flush() # Querying session queried_models = session.query(model).all() assert queried_models[0].ref_table is not None assert queried_models[1].ref_table is None # Check that returned type is correct assert calculated_type_str == 'typing.Optional["TRefTable"]' # Creating instance of ref_model without model ref_model_instance3 = ref_model(id=31, name="ref table name 3") session.add(ref_model_instance3) # Creating instance of ref_model with model ref_model_instance4 = ref_model(id=41, name="ref table name 4", table=model(id=42, name="table name 4")) session.add(ref_model_instance4) session.flush() # Querying session queried_ref_models = session.query(ref_model).all() assert queried_ref_models[1].table is None assert queried_ref_models[2].table is not None assert calculated_backref_type_str == 'typing.Optional["TTable"]'
def test_model_database_type_many_to_one_not_nullable(engine, sessionmaker): """ GIVEN spec with many to one relationship that is not nullable WHEN models are constructed and None is passed for the object reference THEN sqlalchemy.exc.IntegrityError is raised. """ # Defining specification spec = { "components": { "schemas": { "RefTable": { "properties": { "id": { "type": "integer", "x-primary-key": True }, "name": { "type": "string" }, }, "x-tablename": "ref_table", "x-backref": "tables", "type": "object", }, "Table": { "properties": { "id": { "type": "integer", "x-primary-key": True }, "name": { "type": "string" }, "ref_table": { "allOf": [ { "$ref": "#/components/schemas/RefTable" }, { "nullable": False }, ], }, }, "x-tablename": "table", "type": "object", }, } } } # Creating model factory base = declarative.declarative_base() model_factory = open_alchemy.init_model_factory(spec=spec, base=base) model = model_factory(name="Table") model_factory(name="RefTable") # Calculate the expected type schemas_artifacts = schemas_artifacts_module.get_from_schemas( schemas=spec["components"]["schemas"], stay_within_model=False) assert "Table" in schemas_artifacts model_schemas_artifacts = schemas_artifacts["Table"] model_models_artifacts = artifacts.calculate( artifacts=model_schemas_artifacts, name="Table") assert len(model_models_artifacts.sqlalchemy.columns) == 3 ref_table_column_artifacts = model_models_artifacts.sqlalchemy.columns[2] assert ref_table_column_artifacts.name == "ref_table" calculated_type_str = ref_table_column_artifacts.type # Creating models base.metadata.create_all(engine) session = sessionmaker() # Creating instance of model with None ref_model model_instance = model(id=12, name="table name 1", ref_table=None) session.add(model_instance) with pytest.raises(sqlalchemy.exc.IntegrityError): session.flush() # Check that returned type is correct assert calculated_type_str == '"TRefTable"'