Skip to content
This repository was archived by the owner on Sep 28, 2022. It is now read-only.

Add a proper mechanism for plugins to manipulate the data tree without returning a value #42

Open
pmg103 opened this issue Dec 4, 2019 · 2 comments

Comments

@pmg103
Copy link
Contributor

pmg103 commented Dec 4, 2019

Currently a plugin's get_value() method can be used to update values onto child objects which only the parent has the context to calculate.

This is a useful mechanism but unfortunately a dummy key is required since any plugin that runs must return a value into the data output tree.

Example:

class PopulateActivityRaterHasStarted(SerializationSpecPlugin):
    serialization_spec = [
        {'_activity_product_version_items': Aliased('activity_product_version_items', [
            {'activity_product_version_sessions': [
                'user',
                'rater_for'
            ]}
        ])}
    ]

    def get_value(self, instance):
        sessions = {
            session.user_id: session.rater_for_id
            for apv in instance._activity_product_version_items
            for session in apv.activity_product_version_sessions.all()
        }

        for activity_user in instance.self_users:
            for rater in activity_user.raters.all():
                rater.has_started = sessions.get(activity_user.user_id) == rater.rater_id

        return None


# Works in conjunction with PopulateActivityRaterHasStarted above
class ActivityRaterHasStarted(SerializationSpecPlugin):
    def get_value(self, instance):
        return instance.has_started


class MyActivityList(SerializationSpecMixin, generics.ListAPIView):
    queryset = Activity.objects.all()

    serialization_spec = [
        # ...
        {'UNUSED': PopulateActivityRaterHasStarted()},
        {'users': [
            {'raters': [
                {'has_started': ActivityRaterHasStarted()}
            ]}
        ]},
    ]

We need to provide some kind of mechanism to allow manipulations of the tree without the need to output a value which must be given a dummy key

@pmg103
Copy link
Contributor Author

pmg103 commented Dec 12, 2019

Maybe some way of 'wrapping' the sub-spec with the code that will apply the transformation:

class PopulateActivityRaterHasStarted(SerializationSpecTransformer):
    serialization_spec = [
        {'activity_product_version_items': [
            {'activity_product_version_sessions': [
                'user',
                'rater_for'
            ]}
        ]}
    ]

    def apply(self, instance):
        sessions = {
            session.user_id: session.rater_for_id
            for apv in instance.activity_product_version_items.all()
            for session in apv.activity_product_version_sessions.all()
        }

        for activity_user in instance.self_users:
            for rater in activity_user.raters.all():
                rater.has_started = sessions.get(activity_user.user_id) == rater.rater_id


class MyActivityList(SerializationSpecMixin, generics.ListAPIView):
    queryset = Activity.objects.all()

    serialization_spec = Transform(PopulateActivityRaterHasStarted(), [
        # ...
        {'users': [
            {'raters': [
                ... ,
                {'has_started': Populated()},
            ]}
        ]},
    ])

@pmg103
Copy link
Contributor Author

pmg103 commented Jan 13, 2020

It would be tidier if you could just list inner fields in the normal way:

    serialization_spec = With(PopulateActivityRaterHasStarted(), [
        # ...
        {'users': [
            {'raters': [
                ...
                'has_started',
            ]}
        ]},
    ])

In the current implementation, has_started would be included in only_fields which would fail. Perhaps that should just silently ignore missing fields and assume it will have been provided by serialization time, or error at that point.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant