# Path: invenio_records/dictutils.py
# def dict_lookup(source, lookup_key, parent=False):
#     """Make a lookup into a dict based on a dot notation.
# 
#     Examples of the supported dot notation:
# 
#     - ``'a'`` - Equivalent to ``source['a']``
#     - ``'a.b'`` - Equivalent to ``source['a']['b']``
#     - ``'a.b.0'`` - Equivalent to ``source['a']['b'][0]`` (for lists)
# 
#     List notation is also supported:
# 
#     - `['a']``
#     - ``['a','b']``
#     - ``['a','b', 0]``
# 
#     :param source: The dictionary object to perform the lookup in.
#     :param parent: If parent argument is True, returns the parent node of
#                    matched object.
#     :param lookup_key: A string using dot notation, or a list of keys.
#     """
#     # Copied from dictdiffer (CERN contributed part) and slightly modified.
#     keys = parse_lookup_key(lookup_key)
# 
#     if parent:
#         keys = keys[:-1]
# 
#     # Lookup the key
#     value = source
#     for key in keys:
#         try:
#             if isinstance(value, list):
#                 key = int(key)
#             value = value[key]
#         except (TypeError, IndexError, ValueError) as exc:
#             raise KeyError(lookup_key) from exc
#     return value
# 
# def dict_set(source, key, value):
#     """Set a value into a dict via a dot-notated key.
# 
#     This also creates missing key "paths".
# 
#     Examples of the supported dot notation:
# 
#     - ``'a'`` - Equivalent to ``source['a'] = value``
#     - ``'a.b'`` - Equivalent to ``source['a']['b'] = value``
#     - ``'a.b.0'`` - Equivalent to ``source['a']['b'][0] = value`` (for lists)
# 
#     List notation is also supported:
# 
#     - `['a']``
#     - ``['a','b']``
#     - ``['a','b', 0]``
# 
#     :param source: The dictionary object to set the value in.
#     :param key: A string using dot notation, or a list of keys.
#     :param value: The value to be set.
#     """
#     keys = parse_lookup_key(key)
#     parent = source
#     for key in keys[:-1]:
#         if isinstance(key, int):
#             parent = parent[key]
#         else:
#             parent = parent.setdefault(key, {})
#     parent[keys[-1]] = value
# 
# def parse_lookup_key(lookup_key):
#     """Parse a lookup key."""
#     if not lookup_key:
#         raise KeyError("No lookup key specified")
# 
#     # Parse the list of keys
#     if isinstance(lookup_key, str):
#         keys = lookup_key.split('.')
#     elif isinstance(lookup_key, list):
#         keys = lookup_key
#     else:
#         raise TypeError('lookup must be string or list')
# 
#     return keys
# 
# Path: invenio_records/systemfields/relations/errors.py
# class InvalidCheckValue(RelationError):
#     """Invalid check value."""
# 
# class InvalidRelationValue(RelationError):
#     """Invalid relation value."""


from ...dictutils import dict_lookup, dict_set, parse_lookup_key
from .errors import InvalidCheckValue, InvalidRelationValue

    def __call__(self, force=True):
        """Resolve the relation."""
        try:
            values = self._lookup_data()
            parent_iter = []
            for inner_values in values:
                inner_iter = []
                for v in inner_values:
                    try:
                        inner_iter.append(
                            self.resolve(v[self._value_key_suffix])
                        )
                    except KeyError:
                        continue
                parent_iter.append(iter(inner_iter))
            return iter(parent_iter)
        except KeyError:
            return None

    def validate(self):
        """Validate the field."""
        try:
            values = self._lookup_data()
            if values and not isinstance(values, list):
                raise InvalidRelationValue(
                    f'Invalid value {values}, should be list.')

            for outter_v in values:
                if outter_v and not isinstance(outter_v, list):

# Path: invenio_records/dictutils.py
# def dict_lookup(source, lookup_key, parent=False):
#     """Make a lookup into a dict based on a dot notation.
# 
#     Examples of the supported dot notation:
# 
#     - ``'a'`` - Equivalent to ``source['a']``
#     - ``'a.b'`` - Equivalent to ``source['a']['b']``
#     - ``'a.b.0'`` - Equivalent to ``source['a']['b'][0]`` (for lists)
# 
#     List notation is also supported:
# 
#     - `['a']``
#     - ``['a','b']``
#     - ``['a','b', 0]``
# 
#     :param source: The dictionary object to perform the lookup in.
#     :param parent: If parent argument is True, returns the parent node of
#                    matched object.
#     :param lookup_key: A string using dot notation, or a list of keys.
#     """
#     # Copied from dictdiffer (CERN contributed part) and slightly modified.
#     keys = parse_lookup_key(lookup_key)
# 
#     if parent:
#         keys = keys[:-1]
# 
#     # Lookup the key
#     value = source
#     for key in keys:
#         try:
#             if isinstance(value, list):
#                 key = int(key)
#             value = value[key]
#         except (TypeError, IndexError, ValueError) as exc:
#             raise KeyError(lookup_key) from exc
#     return value
# 
# def dict_set(source, key, value):
#     """Set a value into a dict via a dot-notated key.
# 
#     This also creates missing key "paths".
# 
#     Examples of the supported dot notation:
# 
#     - ``'a'`` - Equivalent to ``source['a'] = value``
#     - ``'a.b'`` - Equivalent to ``source['a']['b'] = value``
#     - ``'a.b.0'`` - Equivalent to ``source['a']['b'][0] = value`` (for lists)
# 
#     List notation is also supported:
# 
#     - `['a']``
#     - ``['a','b']``
#     - ``['a','b', 0]``
# 
#     :param source: The dictionary object to set the value in.
#     :param key: A string using dot notation, or a list of keys.
#     :param value: The value to be set.
#     """
#     keys = parse_lookup_key(key)
#     parent = source
#     for key in keys[:-1]:
#         if isinstance(key, int):
#             parent = parent[key]
#         else:
#             parent = parent.setdefault(key, {})
#     parent[keys[-1]] = value
# 
# def parse_lookup_key(lookup_key):
#     """Parse a lookup key."""
#     if not lookup_key:
#         raise KeyError("No lookup key specified")
# 
#     # Parse the list of keys
#     if isinstance(lookup_key, str):
#         keys = lookup_key.split('.')
#     elif isinstance(lookup_key, list):
#         keys = lookup_key
#     else:
#         raise TypeError('lookup must be string or list')
# 
#     return keys
# 
# Path: invenio_records/systemfields/relations/errors.py
# class InvalidCheckValue(RelationError):
#     """Invalid check value."""
# 
# class InvalidRelationValue(RelationError):
#     """Invalid relation value."""


# Path: invenio_records/systemfields/relations/results.py
from ...dictutils import dict_lookup, dict_set, parse_lookup_key
from .errors import InvalidCheckValue, InvalidRelationValue


    def __call__(self, force=True):
        """Resolve the relation."""
        try:
            values = self._lookup_data()
            parent_iter = []
            for inner_values in values:
                inner_iter = []
                for v in inner_values:
                    try:
                        inner_iter.append(
                            self.resolve(v[self._value_key_suffix])
                        )
                    except KeyError:
                        continue
                parent_iter.append(iter(inner_iter))
            return iter(parent_iter)
        except KeyError:
            return None

    def validate(self):
        """Validate the field."""
        try:
            values = self._lookup_data()
            if values and not isinstance(values, list):
                raise InvalidRelationValue(
                    f'Invalid value {values}, should be list.')

            for outter_v in values:
                if outter_v and not isinstance(outter_v, list):

                    raise InvalidRelationValue(