package com.buschmais.xo.impl.query; import java.util.*; import java.util.Map.Entry; import com.buschmais.xo.api.CompositeType; import com.buschmais.xo.api.Query; import com.buschmais.xo.api.ResultIterator; import com.buschmais.xo.api.XOException; 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; import com.buschmais.xo.spi.metadata.CompositeTypeBuilder; class QueryResultIterableImpl<Entity, Relation, T> extends AbstractResultIterable<T> implements Query.Result<T> { private final SessionContext<?, Entity, ?, ?, ?, Relation, ?, ?, ?> sessionContext; private final ResultIterator<Map<String, Object>> iterator; private final SortedSet<Class<?>> returnTypes; private final RowProxyMethodService rowProxyMethodService; QueryResultIterableImpl(SessionContext<?, Entity, ?, ?, ?, Relation, ?, ?, ?> sessionContext, ResultIterator<Map<String, Object>> iterator, SortedSet<Class<?>> 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<T> iterator() { return sessionContext.getInterceptorFactory().addInterceptor(new ResultIterator<T>() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public T next() { Map<String, Object> next = iterator.next(); Map<String, Object> row = new LinkedHashMap<>(next.size(), 1); for (Map.Entry<String, Object> 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 = CompositeTypeBuilder.create(CompositeRowObject.class, returnTypes.toArray(new Class[returnTypes.size()])); return (T) 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<Object> decodeIterable(Iterable<?> iterable, Collection<Object> decodedCollection) { for (Object o : iterable) { decodedCollection.add(decodeValue(o)); } return decodedCollection; } private Map<Object, Object> decodeMap(Map<?, ?> map, Map<Object, Object> 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(); } }