Source code for kim.pipelines.nested

# kim/pipelines/nested.py
# Copyright (C) 2014-2015 the Kim authors and contributors
# <see AUTHORS file>
#
# This module is part of Kim and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php

from kim.utils import attr_or_key

from .base import pipe
from .marshaling import MarshalPipeline
from .serialization import SerializePipeline


def _call_getter(session):
    if session.field.opts.getter:
        result = session.field.opts.getter(session)
        return result


@pipe()
[docs]def marshal_nested(session): """Marshal data using the nested mapper defined on this field. There are 6 possible scenarios, depending on the security setters and presence of a getter function * Getter function returns an object and no updates are allowed - Return the object immediately * Getter function returns an object and updates are allowed - Call the nested mapper with the object to update it * Object already exists, getter function returns None/does not exist and in place updates are allowed - Call the nested mapper with the existing object to update it * Getter function returns None/does not exist and creation of new objects is allowed - Call the nested mapper to create a new object * Getter function returns None/does not exist and creation of new objects is not allowed, nor are in place updates - Raise an exception. * Object already exists, getter function returns None/does not exist and partial updates are allowed - Call the nested mapper with the existing object to update it :param session: Kim pipeline session instance """ resolved = _call_getter(session) partial = session.mapper_session.partial parent_mapper = session.mapper if session.parent and session.parent.nested_mapper: nested_mapper_class = session.parent.nested_mapper else: nested_mapper_class = session.field.get_mapper(as_class=True) if resolved is not None: if session.field.opts.allow_updates: nested_mapper = nested_mapper_class( data=session.data, obj=resolved, partial=partial, parent=parent_mapper) session.data = nested_mapper.marshal(role=session.field.opts.role) else: session.data = resolved else: existing_value = attr_or_key(session.output, session.field.name) if (session.field.opts.allow_updates_in_place or session.field.opts.allow_partial_updates) and \ existing_value is not None: nested_mapper = nested_mapper_class( data=session.data, obj=existing_value, partial=partial, parent=parent_mapper) session.data = nested_mapper.marshal(role=session.field.opts.role) elif session.field.opts.allow_create: nested_mapper = nested_mapper_class( data=session.data, partial=partial, parent=parent_mapper) session.data = nested_mapper.marshal(role=session.field.opts.role) else: raise session.field.invalid(error_type='not_found') return session.data
@pipe(run_if_none=True)
[docs]def serialize_nested(session): """Serialize data using the nested mapper defined on this field. :param session: Kim pipeline session instance """ if session.data is None: session.data = session.field.opts.null_default return session.data # Grab the Mapper defined for the nested field and call serialize() if session.parent and session.parent.nested_mapper: nested_mapper = session.parent.nested_mapper(obj=session.data) else: nested_mapper = session.field.get_mapper(obj=session.data) session.data = nested_mapper.serialize(role=session.field.opts.role) return session.data
[docs]class NestedMarshalPipeline(MarshalPipeline): """NestedMarshalPipeline .. seealso:: :func:`kim.pipelines.nested.marshal_nested` :class:`kim.pipelines.marshaling.MarshalPipeline` """ output_pipes = [marshal_nested, ] + MarshalPipeline.output_pipes
[docs]class NestedSerializePipeline(SerializePipeline): """NestedSerializePipeline .. seealso:: :func:`kim.pipelines.nested.serialize_nested` :class:`kim.pipelines.serialization.SerializePipeline` """ process_pipes = [serialize_nested, ] + SerializePipeline.process_pipes