All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.agrest.cayenne.processor.select.ViaParentPrefetchResolver Maven / Gradle / Ivy

There is a newer version: 5.0.M19
Show newest version
package io.agrest.cayenne.processor.select;

import io.agrest.NestedResourceEntity;
import io.agrest.ResourceEntity;
import io.agrest.RootResourceEntity;
import io.agrest.cayenne.compiler.DataObjectPropertyReader;
import io.agrest.cayenne.processor.CayenneProcessor;
import io.agrest.property.PropertyReader;
import io.agrest.resolver.BaseNestedDataResolver;
import io.agrest.runtime.processor.select.SelectContext;
import org.apache.cayenne.DataObject;
import org.apache.cayenne.query.SelectQuery;

/**
 * A resolver that doesn't run its own queries, but instead amends parent node query with prefetch spec, so that the
 * objects can be read efficiently from the parent objects. Also allows to explicitly set the prefetch semantics.
 *
 * @since 3.4
 */
public class ViaParentPrefetchResolver extends BaseNestedDataResolver {

    private int prefetchSemantics;

    public ViaParentPrefetchResolver(int prefetchSemantics) {
        this.prefetchSemantics = prefetchSemantics;
    }

    @Override
    protected void doOnParentQueryAssembled(NestedResourceEntity entity, SelectContext context) {
        addPrefetch(entity, prefetchSemantics);
    }

    @Override
    protected Iterable doOnParentDataResolved(
            NestedResourceEntity entity,
            Iterable parentData,
            SelectContext context) {
        return dataIterable(entity, (Iterable) parentData);
    }

    protected void addPrefetch(NestedResourceEntity entity, int prefetchSemantics) {
        addPrefetch(entity, null, prefetchSemantics);
    }

    protected void addPrefetch(NestedResourceEntity entity, String outgoingPath, int prefetchSemantics) {

        // add prefetch to the first available (grand)parent query

        String incomingPath = entity.getIncoming().getName();
        String path = outgoingPath != null ? incomingPath + "." + outgoingPath : incomingPath;

        ResourceEntity parent = entity.getParent();
        SelectQuery parentSelect = CayenneProcessor.getQuery(parent);
        if (parentSelect != null) {
            parentSelect.addPrefetch(path).setSemantics(prefetchSemantics);
            return;
        }

        if (parent instanceof RootResourceEntity) {
            throw new IllegalStateException(
                    "Can't add prefetch to root entity that has no SelectQuery of its own. Path: " + path);
        }

        addPrefetch(((NestedResourceEntity) parent), path, prefetchSemantics);
    }

    @Override
    public PropertyReader reader(NestedResourceEntity entity) {

        // TODO: what about multi-step prefetches? How do we locate parent then?

        // assuming the parent is a DataObject. CayenneNestedDataResolverBuilder ensures that it is
        return DataObjectPropertyReader.reader(entity.getIncoming().getName());
    }

    protected Iterable dataIterable(NestedResourceEntity entity, Iterable parentData) {
        String property = entity.getIncoming().getName();
        return entity.getIncoming().isToMany()
                ? () -> new ToManyFlattenedIterator<>(parentData.iterator(), property)
                : () -> new ToOneFlattenedIterator<>(parentData.iterator(), property);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy