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
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