# Path: aiohttp_json_api/abc/field.py
# class FieldABC(abc.ABC):
#     @property
#     @abc.abstractmethod
#     def key(self) -> str:
#         raise NotImplementedError
# 
#     @property
#     @abc.abstractmethod
#     def sp(self) -> JSONPointer:
#         raise NotImplementedError
# 
#     @property
#     @abc.abstractmethod
#     def name(self) -> Optional[str]:
#         raise NotImplementedError
# 
#     @name.setter
#     @abc.abstractmethod
#     def name(self, value: Optional[str]):
#         pass
# 
#     @property
#     @abc.abstractmethod
#     def mapped_key(self) -> Optional[str]:
#         raise NotImplementedError
# 
#     @mapped_key.setter
#     @abc.abstractmethod
#     def mapped_key(self, value: Optional[str]):
#         pass
# 
#     @abc.abstractmethod
#     def serialize(self, schema, data, **kwargs):
#         """
#         Serialize the passed *data*.
#         """
#         raise NotImplementedError
# 
#     @abc.abstractmethod
#     def deserialize(self, schema, data, sp, **kwargs):
#         """
#         Deserialize the raw *data* from the JSON API input document
#         and returns it.
#         """
#         raise NotImplementedError
# 
#     @abc.abstractmethod
#     def pre_validate(self, schema, data, sp):
#         """
#         Validates the raw JSON API input for this field. This method is
#         called before :meth:`deserialize`.
# 
#         :arg ~aiohttp_json_api.schema.BaseSchema schema:
#             The schema this field has been defined on.
#         :arg data:
#             The raw input data
#         :arg ~aiohttp_json_api.jsonpointer.JSONPointer sp:
#             A JSON pointer to the source of *data*.
#         :arg ~aiohttp_json_api.context.JSONAPIContext context:
#             A JSON API request context instance
#         """
#         raise NotImplementedError
# 
#     @abc.abstractmethod
#     def post_validate(self, schema, data, sp):
#         """
#         Validates the decoded input *data* for this field. This method is
#         called after :meth:`deserialize`.
# 
#         :arg ~aiohttp_json_api.schema.BaseSchema schema:
#             The schema this field has been defined on.
#         :arg data:
#             The decoded input data
#         :arg ~aiohttp_json_api.jsonpointer.JSONPointer sp:
#             A JSON pointer to the source of *data*.
#         :arg ~aiohttp_json_api.context.JSONAPIContext context:
#             A JSON API request context instance
#         """
#         raise NotImplementedError
# 
# Path: aiohttp_json_api/common.py
# ALLOWED_MEMBER_NAME_REGEX = re.compile('^' + ALLOWED_MEMBER_NAME_RULE + '$')
# 
# class Event(Flag):
#     """Request event enumeration."""
# 
#     GET = auto()
#     POST = auto()
#     PATCH = auto()
#     DELETE = auto()
#     NEVER = auto()
#     ALWAYS = GET | POST | PATCH | DELETE
#     CREATE = POST
#     UPDATE = PATCH
# 
# JSONAPI = 'jsonapi'
# 
# 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
#     """
# 
# class InvalidValue(ValidationError):
#     """
#     JSON API invalid value error. HTTP 400 Bad request.
# 
#     Raised if an input value (part of a JSON API document) has an invalid
#     value.
# 
#     :seealso: http://jsonapi.org/format/#document-structure
#     """
# 
# Path: aiohttp_json_api/jsonpointer.py
# class JSONPointer(BaseJsonPointer):
#     def __truediv__(self,
#                     path: typing.Union['JSONPointer', str]) -> 'JSONPointer':
#         parts = self.parts.copy()
# 
#         if isinstance(path, int):
#             path = str(path)
# 
#         if isinstance(path, str):
#             if not path.startswith('/'):
#                 path = f'/{path}'
#             new_parts = JSONPointer(path).parts.pop(0)
#             parts.append(new_parts)
#         else:
#             new_parts = path.parts
#             parts.extend(new_parts)
#         return JSONPointer.from_parts(parts)


import urllib.parse
from collections import Mapping
from typing import Optional, Sequence
from ..abc.field import FieldABC
from ..common import ALLOWED_MEMBER_NAME_REGEX, Event, JSONAPI
from ..errors import InvalidType, InvalidValue
from ..jsonpointer import JSONPointer
            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.'

# Path: aiohttp_json_api/abc/field.py
# class FieldABC(abc.ABC):
#     @property
#     @abc.abstractmethod
#     def key(self) -> str:
#         raise NotImplementedError
# 
#     @property
#     @abc.abstractmethod
#     def sp(self) -> JSONPointer:
#         raise NotImplementedError
# 
#     @property
#     @abc.abstractmethod
#     def name(self) -> Optional[str]:
#         raise NotImplementedError
# 
#     @name.setter
#     @abc.abstractmethod
#     def name(self, value: Optional[str]):
#         pass
# 
#     @property
#     @abc.abstractmethod
#     def mapped_key(self) -> Optional[str]:
#         raise NotImplementedError
# 
#     @mapped_key.setter
#     @abc.abstractmethod
#     def mapped_key(self, value: Optional[str]):
#         pass
# 
#     @abc.abstractmethod
#     def serialize(self, schema, data, **kwargs):
#         """
#         Serialize the passed *data*.
#         """
#         raise NotImplementedError
# 
#     @abc.abstractmethod
#     def deserialize(self, schema, data, sp, **kwargs):
#         """
#         Deserialize the raw *data* from the JSON API input document
#         and returns it.
#         """
#         raise NotImplementedError
# 
#     @abc.abstractmethod
#     def pre_validate(self, schema, data, sp):
#         """
#         Validates the raw JSON API input for this field. This method is
#         called before :meth:`deserialize`.
# 
#         :arg ~aiohttp_json_api.schema.BaseSchema schema:
#             The schema this field has been defined on.
#         :arg data:
#             The raw input data
#         :arg ~aiohttp_json_api.jsonpointer.JSONPointer sp:
#             A JSON pointer to the source of *data*.
#         :arg ~aiohttp_json_api.context.JSONAPIContext context:
#             A JSON API request context instance
#         """
#         raise NotImplementedError
# 
#     @abc.abstractmethod
#     def post_validate(self, schema, data, sp):
#         """
#         Validates the decoded input *data* for this field. This method is
#         called after :meth:`deserialize`.
# 
#         :arg ~aiohttp_json_api.schema.BaseSchema schema:
#             The schema this field has been defined on.
#         :arg data:
#             The decoded input data
#         :arg ~aiohttp_json_api.jsonpointer.JSONPointer sp:
#             A JSON pointer to the source of *data*.
#         :arg ~aiohttp_json_api.context.JSONAPIContext context:
#             A JSON API request context instance
#         """
#         raise NotImplementedError
# 
# Path: aiohttp_json_api/common.py
# ALLOWED_MEMBER_NAME_REGEX = re.compile('^' + ALLOWED_MEMBER_NAME_RULE + '$')
# 
# class Event(Flag):
#     """Request event enumeration."""
# 
#     GET = auto()
#     POST = auto()
#     PATCH = auto()
#     DELETE = auto()
#     NEVER = auto()
#     ALWAYS = GET | POST | PATCH | DELETE
#     CREATE = POST
#     UPDATE = PATCH
# 
# JSONAPI = 'jsonapi'
# 
# 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
#     """
# 
# class InvalidValue(ValidationError):
#     """
#     JSON API invalid value error. HTTP 400 Bad request.
# 
#     Raised if an input value (part of a JSON API document) has an invalid
#     value.
# 
#     :seealso: http://jsonapi.org/format/#document-structure
#     """
# 
# Path: aiohttp_json_api/jsonpointer.py
# class JSONPointer(BaseJsonPointer):
#     def __truediv__(self,
#                     path: typing.Union['JSONPointer', str]) -> 'JSONPointer':
#         parts = self.parts.copy()
# 
#         if isinstance(path, int):
#             path = str(path)
# 
#         if isinstance(path, str):
#             if not path.startswith('/'):
#                 path = f'/{path}'
#             new_parts = JSONPointer(path).parts.pop(0)
#             parts.append(new_parts)
#         else:
#             new_parts = path.parts
#             parts.extend(new_parts)
#         return JSONPointer.from_parts(parts)


# Path: aiohttp_json_api/fields/base.py
import urllib.parse
from collections import Mapping
from typing import Optional, Sequence
from ..abc.field import FieldABC
from ..common import ALLOWED_MEMBER_NAME_REGEX, Event, JSONAPI
from ..errors import InvalidType, InvalidValue
from ..jsonpointer import JSONPointer

            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)