Esempio n. 1
0
def test_tablename():
    """
    GIVEN schemas with schema
    WHEN model_factory is called with the name of the schema
    THEN a model where __tablename__ has been set to the x-tablename value.
    """
    schemas = {
        "SingleProperty": {
            "x-tablename": "table 1",
            "type": "object",
            "properties": {"property_1": {"type": "integer"}},
        }
    }
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )

    model = model_factory.model_factory(
        name="SingleProperty",
        get_base=_mock_get_base,
        schemas=schemas,
        artifacts=artifacts,
    )

    assert model.__tablename__ == "table 1"
Esempio n. 2
0
def test_multiple_property():
    """
    GIVEN schemas with schema that has multiple item properties key
    WHEN model_factory is called with the name of the schema
    THEN a model with the properties is returned.
    """
    schemas = {
        "SingleProperty": {
            "x-tablename": "table 1",
            "type": "object",
            "properties": {
                "property_1": {"type": "integer"},
                "property_2": {"type": "integer"},
            },
        }
    }
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )

    model = model_factory.model_factory(
        name="SingleProperty",
        get_base=_mock_get_base,
        schemas=schemas,
        artifacts=artifacts,
    )

    assert hasattr(model, "property_1")
    assert hasattr(model, "property_2")
Esempio n. 3
0
def test_kwargs():
    """
    GIVEN schemas with schema that has kwargs
    WHEN model_factory is called with the name of the schema
    THEN a model with the kwargs is returned.
    """
    schemas = {
        "SingleProperty": {
            "x-tablename": "table 1",
            "type": "object",
            "properties": {"property_1": {"type": "integer"}},
            "x-kwargs": {"__mapper_args__": {"passive_deletes": True}},
        }
    }
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )

    model = model_factory.model_factory(
        name="SingleProperty",
        get_base=_mock_get_base,
        schemas=schemas,
        artifacts=artifacts,
    )

    assert model.__mapper_args__ == {"passive_deletes": True}
Esempio n. 4
0
def test_all_of():
    """
    GIVEN schemas with schema that has allOf and the referenced schema
    WHEN model_factory is called with the name of the schema
    THEN a model with the property and tablename is returned.
    """
    schemas = {
        "Schema": {
            "allOf": [
                {
                    "x-tablename": "table 1",
                    "type": "object",
                    "properties": {"property_1": {"type": "integer"}},
                }
            ]
        }
    }
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )

    model = model_factory.model_factory(
        name="Schema", get_base=_mock_get_base, schemas=schemas, artifacts=artifacts
    )

    assert hasattr(model, "property_1")
    assert model.__tablename__ == "table 1"
Esempio n. 5
0
def test_table_args_index():
    """
    GIVEN schemas with schema that has a composite index
    WHEN model_factory is called with the name of the schema
    THEN a model with a composite index is returned.
    """
    schemas = {
        "SingleProperty": {
            "x-tablename": "table 1",
            "type": "object",
            "properties": {"property_1": {"type": "integer"}},
            "x-composite-index": ["property_1"],
        }
    }
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )

    model = model_factory.model_factory(
        name="SingleProperty",
        get_base=_mock_get_base,
        schemas=schemas,
        artifacts=artifacts,
    )

    (index,) = model.__table_args__
    assert isinstance(index, sql_schema.Index)
Esempio n. 6
0
def test_inherits():
    """
    GIVEN schemas with schema that inherits
    WHEN model_factory is called with the name of the schema
    THEN a model which inherits from the parent and with only the child properties
        defined is returned.
    """
    schemas = {
        "Child": {
            "allOf": [
                {
                    "x-inherits": True,
                    "type": "object",
                    "properties": {"property_2": {"type": "integer"}},
                },
                {"$ref": "#/components/schemas/Parent"},
            ]
        },
        "Parent": {
            "x-tablename": "parent",
            "type": "object",
            "properties": {"property_1": {"type": "string"}},
        },
    }
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )

    model = model_factory.model_factory(
        name="Child", get_base=_mock_get_base, schemas=schemas, artifacts=artifacts
    )

    assert not hasattr(model, "property_1")
    assert hasattr(model, "property_2")
    assert getattr(model, "__tablename__", None) is None
Esempio n. 7
0
def test_schema_name():
    """
    GIVEN schemas with schema that has a custom name
    WHEN model_factory is called with the name of the schema
    THEN a model with a custom schema name is returned.
    """
    schemas = {
        "SchemaName": {
            "x-tablename": "table 1",
            "x-schema-name": "schema 1",
            "type": "object",
            "properties": {"property_1": {"type": "integer"}},
        }
    }
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )

    model = model_factory.model_factory(
        name="SchemaName",
        get_base=_mock_get_base,
        schemas=schemas,
        artifacts=artifacts,
    )

    assert model.__table_args__[0]["schema"] == "schema 1"
Esempio n. 8
0
def test_single_property_column_factory_call(mocked_column_factory: mock.MagicMock):
    """
    GIVEN mocked column_factory and schemas with schema that has single item properties
        key and does not have the required key
    WHEN model_factory is called with the name of the schema
    THEN column_factory is called with required as None.
    """
    model_schema = {
        "x-tablename": "table 1",
        "type": "object",
        "properties": {"id": {"type": "integer"}},
    }
    model_name = "SingleProperty"
    schemas = {model_name: model_schema}
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )
    model_factory.model_factory(
        name=model_name,
        get_base=_mock_get_base,
        schemas=copy.deepcopy(schemas),
        artifacts=artifacts,
    )

    mocked_column_factory.assert_called_once_with(
        artifacts=artifacts[model_name].properties[0][1]
    )
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)
Esempio n. 10
0
def test_get_from_schemas(schemas, stay_within_model, expected_artifacts):
    """
    GIVEN schemas and the expected artifacts
    WHEN get_from_schemas is called with the schemas
    THEN the expected artifacts is returned.
    """
    returned_artifacts = artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=stay_within_model)

    assert returned_artifacts == expected_artifacts
Esempio n. 11
0
def test_schema(schemas, expected_schema):
    """
    GIVEN schemas and expected schema
    WHEN model_factory is called with the schemas and the name of a schema
    THEN a model with _schema set to the expected schema is returned.
    """
    artifacts = schemas_artifacts.get_from_schemas(
        schemas=schemas, stay_within_model=True
    )

    model = model_factory.model_factory(
        name="Schema", get_base=_mock_get_base, schemas=schemas, artifacts=artifacts
    )

    assert model._schema == expected_schema
Esempio n. 12
0
def test_mixin(monkeypatch):
    """
    GIVEN schemas with schema that has a mixin
    WHEN model_factory is called with the name of the schema
    THEN a model with the property is returned.
    """
    # Define mixin
    mock_import_module = mock.MagicMock()
    mixin_class = type(
        "Mixin1",
        (),
        {
            "property_2": sqlalchemy.types.Column(sqlalchemy.types.Integer),
            "__abstract__": True,
        },
    )
    mock_import_module.return_value.Mixin1 = mixin_class
    monkeypatch.setattr(importlib, "import_module", mock_import_module)

    schemas = {
        "SingleProperty": {
            "x-tablename": "table 1",
            "type": "object",
            "x-mixins": "module.Mixin1",
            "properties": {
                "property_1": {
                    "type": "integer"
                }
            },
        }
    }
    artifacts = schemas_artifacts.get_from_schemas(schemas=schemas,
                                                   stay_within_model=True)

    model = model_factory.model_factory(
        name="SingleProperty",
        get_base=_mock_get_base,
        schemas=schemas,
        artifacts=artifacts,
    )

    assert hasattr(model, "property_2")
    assert model.__abstract__ is False
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"'