def test_resolve_ref_not_defined():
    """
    GIVEN schema that references a schema that doesn't exist
    WHEN resolve_ref is called with the schema
    THEN SchemaNotFoundError is raised.
    """
    schema = {"$ref": "#/components/schemas/RefSchema"}
    schemas = {}

    with pytest.raises(exceptions.SchemaNotFoundError):
        helpers.resolve_ref(name="name 1", schema=schema, schemas=schemas)
def test_resolve_ref_not_schema():
    """
    GIVEN schema that references something that is not a schema
    WHEN resolve_ref is called with the schema
    THEN SchemaNotFoundError is raised.
    """
    schema = {"$ref": "#/components/not/schema"}
    schemas = {}

    with pytest.raises(exceptions.SchemaNotFoundError):
        helpers.resolve_ref(name="name 1", schema=schema, schemas=schemas)
def test_resolve_ref_single():
    """
    GIVEN schema that references another schema and schemas
    WHEN resolve_ref is called with the schema and schemas
    THEN the referenced schema and logical name is returned.
    """
    ref_schema = {"type": "boolean"}
    ref_name = "RefSchema"
    schema = {"$ref": f"#/components/schemas/{ref_name}"}
    schemas = {ref_name: copy.deepcopy(ref_schema)}

    (return_name, return_schema) = helpers.resolve_ref(name="name 1",
                                                       schema=schema,
                                                       schemas=schemas)

    assert return_name == ref_name
    assert return_schema == ref_schema
def test_resolve_ref_not_ref_schema():
    """
    GIVEN schema that does not have $ref and name
    WHEN resolve_ref is called with the schema and name
    THEN the schema and name are returned.
    """
    name = "name 1"
    schema = {"type": "integer"}
    schemas = {}

    (return_name,
     return_schema) = helpers.resolve_ref(name=name,
                                          schema=copy.deepcopy(schema),
                                          schemas=schemas)

    assert return_name == name
    assert return_schema == schema
Exemple #5
0
def _handle_object(
    *,
    spec: types.Schema,
    schemas: types.Schemas,
    required: typing.Optional[bool] = None,
    logical_name: str,
) -> typing.List[typing.Tuple[str, typing.Union[
        sqlalchemy.Column, sqlalchemy.orm.properties.RelationshipProperty,  # pylint: disable=no-member
], ]]:
    """
    Generate properties for a reference to another object.

    Assume that, when any $ref and allOf are resolved, the schema is an object.

    Args:
        spec: The schema for the column.
        schemas: Used to resolve any $ref.
        required: Whether the object property is required.
        logical_name: The logical name in the specification for the schema.

    Returns:
        The logical name and the SQLAlchemy column for the foreign key and the logical
        name and relationship for the reference to the object.

    """
    # Default backref
    backref = None

    # Checking for $ref and allOf
    ref = spec.get("$ref")
    all_of = spec.get("allOf")

    if ref is not None:
        # Handling $ref
        ref_logical_name, spec = helpers.resolve_ref(name=logical_name,
                                                     schema=spec,
                                                     schemas=schemas)
        backref = spec.get("x-backref")
    elif all_of is not None:
        # Checking for $ref and x-backref counts
        ref_count = 0
        backref_count = 0
        for sub_spec in all_of:
            if sub_spec.get("$ref") is not None:
                ref_count += 1
            if sub_spec.get("x-backref") is not None:
                backref_count += 1
        if ref_count != 1:
            raise exceptions.MalformedManyToOneRelationship(
                "Many to One relationships defined with allOf must have exactly one "
                "$ref in the allOf list.")
        if backref_count > 1:
            raise exceptions.MalformedManyToOneRelationship(
                "Many to One relationships may have at most 1 x-backref defined."
            )

        # Handling allOf
        for sub_spec in all_of:
            backref = sub_spec.get("x-backref")
            if sub_spec.get("$ref") is not None:
                ref_logical_name, spec = helpers.resolve_ref(name=logical_name,
                                                             schema=sub_spec,
                                                             schemas=schemas)
    else:
        raise exceptions.MalformedManyToOneRelationship(
            "Many to One relationships are defined using either $ref or allOf."
        )

    # Handling object
    foreign_key_spec = _handle_object_reference(spec=spec, schemas=schemas)
    return_value = _handle_column(logical_name=f"{logical_name}_id",
                                  spec=foreign_key_spec,
                                  required=required)

    # Creating relationship
    return_value.append((logical_name,
                         sqlalchemy.orm.relationship(ref_logical_name,
                                                     backref=backref)))
    return return_value