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

com.buschmais.xo.impl.query.QueryResultIterableImpl Maven / Gradle / Ivy

The newest version!
package com.buschmais.xo.impl.query;

import java.util.*;
import java.util.Map.Entry;

import com.buschmais.xo.api.Query;
import com.buschmais.xo.api.ResultIterator;
import com.buschmais.xo.api.XOException;
import com.buschmais.xo.api.metadata.type.CompositeType;
import com.buschmais.xo.impl.AbstractResultIterable;
import com.buschmais.xo.impl.SessionContext;
import com.buschmais.xo.impl.proxy.query.RowInvocationHandler;
import com.buschmais.xo.impl.proxy.query.RowProxyMethodService;

class QueryResultIterableImpl extends AbstractResultIterable implements Query.Result {

    private final SessionContext sessionContext;
    private final ResultIterator> iterator;
    private final SortedSet> returnTypes;
    private final RowProxyMethodService rowProxyMethodService;

    QueryResultIterableImpl(SessionContext sessionContext, ResultIterator> iterator,
        SortedSet> returnTypes) {
        this.sessionContext = sessionContext;
        this.iterator = iterator;
        this.returnTypes = returnTypes;
        if (returnTypes.isEmpty() || returnTypes.size() > 1 || sessionContext.getMetadataProvider()
            .getQuery(returnTypes.first()) != null) {
            this.rowProxyMethodService = new RowProxyMethodService(returnTypes);
        } else {
            this.rowProxyMethodService = null;
        }
    }

    @Override
    public ResultIterator iterator() {
        return sessionContext.getInterceptorFactory()
            .addInterceptor(new ResultIterator() {

                @Override
                public boolean hasNext() {
                    return iterator.hasNext();
                }

                @Override
                public T next() {
                    Map next = iterator.next();
                    Map row = new LinkedHashMap<>(next.size(), 1);
                    for (Map.Entry entry : next.entrySet()) {
                        String column = entry.getKey();
                        Object value = entry.getValue();
                        Object decodedValue = decodeValue(value);
                        row.put(column, decodedValue);
                    }
                    if (rowProxyMethodService != null) {
                        RowInvocationHandler invocationHandler = new RowInvocationHandler(row, rowProxyMethodService);
                        CompositeType compositeType = CompositeType.builder()
                            .type(CompositeRowObject.class)
                            .types(returnTypes)
                            .build();
                        return sessionContext.getProxyFactory()
                            .createInstance(invocationHandler, compositeType);
                    }
                    if (row.size() != 1) {
                        throw new XOException("Only single columns per row can be returned.");
                    }
                    return (T) row.values()
                        .iterator()
                        .next();
                }

                @Override
                public void remove() {
                    iterator.remove();
                }

                private Object decodeValue(Object value) {
                    if (value == null) {
                        return null;
                    }
                    Object decodedValue;
                    if (sessionContext.getDatastoreSession()
                        .getDatastoreEntityManager()
                        .isEntity(value)) {
                        return sessionContext.getEntityInstanceManager()
                            .readInstance((Entity) value);
                    } else if (sessionContext.getDatastoreSession()
                        .getDatastoreRelationManager()
                        .isRelation(value)) {
                        return sessionContext.getRelationInstanceManager()
                            .readInstance((Relation) value);
                    } else if (value instanceof List) {
                        decodedValue = decodeIterable((Iterable) value, new ArrayList<>());
                    } else if (value instanceof Set) {
                        decodedValue = decodeIterable((Iterable) value, new HashSet<>());
                    } else if (value instanceof Map) {
                        decodedValue = decodeMap((Map) value, new HashMap<>());
                    } else if (value instanceof Iterable) {
                        decodedValue = decodeIterable((Iterable) value, new ArrayList<>());
                    } else {
                        decodedValue = value;
                    }
                    return decodedValue;
                }

                private Collection decodeIterable(Iterable iterable, Collection decodedCollection) {
                    for (Object o : iterable) {
                        decodedCollection.add(decodeValue(o));
                    }
                    return decodedCollection;
                }

                private Map decodeMap(Map map, Map decodedMap) {
                    for (Entry entry : map.entrySet()) {
                        decodedMap.put(decodeValue(entry.getKey()), decodeValue(entry.getValue()));
                    }

                    return decodedMap;
                }

                @Override
                public void close() {
                    iterator.close();
                }
            }, ResultIterator.class);
    }

    @Override
    public void close() {
        iterator.close();
    }
}