# Path: aiohttp_json_api/fields/base.py
# class Relationship(BaseField):
#     """
#     .. seealso::
# 
#         http://jsonapi.org/format/#document-resource-object-relationships
# 
#     Additionally to attributes and basic fields, we must know how to *include*
#     the related resources in the case of relationships. This class defines
#     the common interface of *to-one* and *to-many* relationships (links object,
#     meta object, *self* link, *related* link, validation, ...).
# 
#     Relationships are always part of the resource's JSON API relationships
#     object.
# 
#     .. seealso::
# 
#         * :class:`~aiohttp_json_api.schema.relationships.ToOne`
#         * :class:`~aiohttp_json_api.schema.relationships.ToMany`
# 
#     :arg Event require_data:
#         If true, the JSON API relationship object must contain the *data*
#         member. Must be a :class:`~aiohttp_json_api.schema.common.Event`
#         instance.
#     :arg bool dereference:
#         If true, the relationship linkage is dereferenced automatic when
#         decoded. (Implicitly sets *require_data* to Event.ALWAYS)
#     :arg Sequence[str] foreign_types:
#         A set with all foreign types. If given, this list is used to validate
#         the input data. Leave it empty to allow all types.
#     """
#     relation = None
# 
#     def __init__(self, *, dereference: bool = True,
#                  require_data: Event = Event.ALWAYS,
#                  foreign_types: Sequence[str] = None,
#                  links: Sequence[Link] = None,
#                  id_field: Attribute = None,
#                  **kwargs):
#         BaseField.__init__(self, **kwargs)
#         self.links = {link.name: link for link in links} if links else {}
# 
#         # NOTE: The related resources are loaded by the schema class for
#         #       performance reasons (one big query vs many small ones).
#         self.dereference = dereference
# 
#         self.foreign_types = frozenset(foreign_types or [])
# 
#         assert isinstance(require_data, Event)
#         self.require_data = require_data
#         self.id_field = id_field
# 
#     def add_link(self, link: Link):
#         """
#         Adds a new link to the links object.
#         """
#         self.links[link.name] = link
#         return self
# 
#     def validate_resource_identifier(self, schema, data, sp):
#         """
#         .. seealso::
# 
#             http://jsonapi.org/format/#document-resource-identifier-objects
# 
#         Asserts that *data* is a JSON API resource identifier with the correct
#         *type* value.
#         """
#         if not isinstance(data, Mapping):
#             detail = 'Must be an object.'
#             raise InvalidType(detail=detail, source_pointer=sp)
# 
#         if not ('type' in data and 'id' in data):
#             detail = 'Must contain a "type" and an "id" member.'
#             raise InvalidValue(detail=detail, source_pointer=sp)
# 
#         if self.foreign_types and not data['type'] in self.foreign_types:
#             detail = f'Unexpected type: "{data["type"]}".'
#             raise InvalidValue(detail=detail, source_pointer=sp / 'type')
# 
#         if self.id_field is not None:
#             self.id_field.pre_validate(self, data['id'], sp / 'id')
# 
#     def validate_relationship_object(self, schema, data, sp):
#         """
#         Asserts that *data* is a JSON API relationship object.
# 
#         *   *data* is a dictionary
#         *   *data* must be not empty
#         *   *data* may only have the members *data*, *links* or *meta*.
#         *   *data* must contain a *data* member, if :attr:`dereference` or
#             :attr:`require_data` is true.
#         """
#         if not isinstance(data, Mapping):
#             detail = 'Must be an object.'
#             raise InvalidType(detail=detail, source_pointer=sp)
# 
#         if not data:
#             detail = 'Must contain at least a "data", "links" or "meta" member.'
#             raise InvalidValue(detail=detail, source_pointer=sp)
# 
#         if not (data.keys() <= {'links', 'data', 'meta'}):
#             unexpected = (data.keys() - {'links', 'data', 'meta'}).pop()
#             detail = f"Unexpected member: '{unexpected}'."
#             raise InvalidValue(detail=detail, source_pointer=sp)
# 
#         if (self.dereference or self.require_data) and 'data' not in data:
#             detail = 'The "data" member is required.'
#             raise InvalidValue(detail=detail, source_pointer=sp)
# 
#     def pre_validate(self, schema, data, sp):
#         self.validate_relationship_object(schema, data, sp)
#         super(Relationship, self).pre_validate(schema, data, sp)
# 
# Path: aiohttp_json_api/common.py
# class Relation(Enum):
#     """Types of relations enumeration."""
# 
#     TO_ONE = auto()
#     TO_MANY = auto()
# 
# Path: aiohttp_json_api/errors.py
# class InvalidType(ValidationError):
#     """
#     JSON API invalid type error. HTTP 400 Bad request.
# 
#     Raised if an input value (part of a JSON API document) has the wrong type.
# 
#     This type of exception is often raised during decoding.
# 
#     :seealso: http://jsonapi.org/format/#document-structure
#     """
# 
# Path: aiohttp_json_api/helpers.py
# def is_collection(obj, exclude=()):
#     """Return True if ``obj`` is a collection type."""
#     return (not isinstance(obj, (Mapping,) + exclude) and
#             is_iterable_but_not_string(obj))


import typing
from collections import Mapping, OrderedDict
from .base import Relationship
from ..common import Relation
from ..errors import InvalidType
from ..helpers import is_collection
"""
Relationships
=============
"""



__all__ = (
    'ToOne',
    'ToMany',
)



# Path: aiohttp_json_api/fields/base.py
# class Relationship(BaseField):
#     """
#     .. seealso::
# 
#         http://jsonapi.org/format/#document-resource-object-relationships
# 
#     Additionally to attributes and basic fields, we must know how to *include*
#     the related resources in the case of relationships. This class defines
#     the common interface of *to-one* and *to-many* relationships (links object,
#     meta object, *self* link, *related* link, validation, ...).
# 
#     Relationships are always part of the resource's JSON API relationships
#     object.
# 
#     .. seealso::
# 
#         * :class:`~aiohttp_json_api.schema.relationships.ToOne`
#         * :class:`~aiohttp_json_api.schema.relationships.ToMany`
# 
#     :arg Event require_data:
#         If true, the JSON API relationship object must contain the *data*
#         member. Must be a :class:`~aiohttp_json_api.schema.common.Event`
#         instance.
#     :arg bool dereference:
#         If true, the relationship linkage is dereferenced automatic when
#         decoded. (Implicitly sets *require_data* to Event.ALWAYS)
#     :arg Sequence[str] foreign_types:
#         A set with all foreign types. If given, this list is used to validate
#         the input data. Leave it empty to allow all types.
#     """
#     relation = None
# 
#     def __init__(self, *, dereference: bool = True,
#                  require_data: Event = Event.ALWAYS,
#                  foreign_types: Sequence[str] = None,
#                  links: Sequence[Link] = None,
#                  id_field: Attribute = None,
#                  **kwargs):
#         BaseField.__init__(self, **kwargs)
#         self.links = {link.name: link for link in links} if links else {}
# 
#         # NOTE: The related resources are loaded by the schema class for
#         #       performance reasons (one big query vs many small ones).
#         self.dereference = dereference
# 
#         self.foreign_types = frozenset(foreign_types or [])
# 
#         assert isinstance(require_data, Event)
#         self.require_data = require_data
#         self.id_field = id_field
# 
#     def add_link(self, link: Link):
#         """
#         Adds a new link to the links object.
#         """
#         self.links[link.name] = link
#         return self
# 
#     def validate_resource_identifier(self, schema, data, sp):
#         """
#         .. seealso::
# 
#             http://jsonapi.org/format/#document-resource-identifier-objects
# 
#         Asserts that *data* is a JSON API resource identifier with the correct
#         *type* value.
#         """
#         if not isinstance(data, Mapping):
#             detail = 'Must be an object.'
#             raise InvalidType(detail=detail, source_pointer=sp)
# 
#         if not ('type' in data and 'id' in data):
#             detail = 'Must contain a "type" and an "id" member.'
#             raise InvalidValue(detail=detail, source_pointer=sp)
# 
#         if self.foreign_types and not data['type'] in self.foreign_types:
#             detail = f'Unexpected type: "{data["type"]}".'
#             raise InvalidValue(detail=detail, source_pointer=sp / 'type')
# 
#         if self.id_field is not None:
#             self.id_field.pre_validate(self, data['id'], sp / 'id')
# 
#     def validate_relationship_object(self, schema, data, sp):
#         """
#         Asserts that *data* is a JSON API relationship object.
# 
#         *   *data* is a dictionary
#         *   *data* must be not empty
#         *   *data* may only have the members *data*, *links* or *meta*.
#         *   *data* must contain a *data* member, if :attr:`dereference` or
#             :attr:`require_data` is true.
#         """
#         if not isinstance(data, Mapping):
#             detail = 'Must be an object.'
#             raise InvalidType(detail=detail, source_pointer=sp)
# 
#         if not data:
#             detail = 'Must contain at least a "data", "links" or "meta" member.'
#             raise InvalidValue(detail=detail, source_pointer=sp)
# 
#         if not (data.keys() <= {'links', 'data', 'meta'}):
#             unexpected = (data.keys() - {'links', 'data', 'meta'}).pop()
#             detail = f"Unexpected member: '{unexpected}'."
#             raise InvalidValue(detail=detail, source_pointer=sp)
# 
#         if (self.dereference or self.require_data) and 'data' not in data:
#             detail = 'The "data" member is required.'
#             raise InvalidValue(detail=detail, source_pointer=sp)
# 
#     def pre_validate(self, schema, data, sp):
#         self.validate_relationship_object(schema, data, sp)
#         super(Relationship, self).pre_validate(schema, data, sp)
# 
# Path: aiohttp_json_api/common.py
# class Relation(Enum):
#     """Types of relations enumeration."""
# 
#     TO_ONE = auto()
#     TO_MANY = auto()
# 
# Path: aiohttp_json_api/errors.py
# class InvalidType(ValidationError):
#     """
#     JSON API invalid type error. HTTP 400 Bad request.
# 
#     Raised if an input value (part of a JSON API document) has the wrong type.
# 
#     This type of exception is often raised during decoding.
# 
#     :seealso: http://jsonapi.org/format/#document-structure
#     """
# 
# Path: aiohttp_json_api/helpers.py
# def is_collection(obj, exclude=()):
#     """Return True if ``obj`` is a collection type."""
#     return (not isinstance(obj, (Mapping,) + exclude) and
#             is_iterable_but_not_string(obj))


# Path: aiohttp_json_api/fields/relationships.py
import typing
from collections import Mapping, OrderedDict
from .base import Relationship
from ..common import Relation
from ..errors import InvalidType
from ..helpers import is_collection

"""
Relationships
=============
"""



__all__ = (
    'ToOne',
    'ToMany',
)



class ToOne(Relationship):