io.agrest.cayenne.processor.select.ViaParentPrefetchResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of agrest-cayenne Show documentation
Show all versions of agrest-cayenne Show documentation
Cayenne backend for Agrest
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 extends DataObject> parentData) {
String property = entity.getIncoming().getName();
return entity.getIncoming().isToMany()
? () -> new ToManyFlattenedIterator<>(parentData.iterator(), property)
: () -> new ToOneFlattenedIterator<>(parentData.iterator(), property);
}
}