/* * Copyright 2016 requery.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.requery.query; import io.requery.meta.Attribute; import io.requery.meta.Type; import io.requery.proxy.EntityProxy; import io.requery.util.CloseableIterable; import io.requery.util.CloseableIterator; import io.requery.util.function.Consumer; import io.requery.util.function.Supplier; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Spliterator; import java.util.Spliterators; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; import java.util.stream.StreamSupport; /** * Provides a base {@link Result} implementation. * * @param <E> entity type being selected. * * @author Nikhil Purushe */ public abstract class BaseResult<E> implements Result<E>, CloseableIterable<E> { private final Integer maxSize; private final Queue<CloseableIterator<E>> iterators; private final AtomicBoolean closed; protected BaseResult() { this(null); } protected BaseResult(Integer maxSize) { this.maxSize = maxSize; this.iterators = new ConcurrentLinkedQueue<>(); this.closed = new AtomicBoolean(); } public abstract CloseableIterator<E> iterator(int skip, int take); @Override public List<E> toList() { List<E> list = maxSize == null ? new ArrayList<E>() : new ArrayList<E>(maxSize); collect(list); return Collections.unmodifiableList(list); } @Override public <C extends Collection<E>> C collect(C collection) { try (CloseableIterator<E> iterator = iterator()) { while (iterator.hasNext()) { collection.add(iterator.next()); } } return collection; } @Override public E first() { try (CloseableIterator<E> iterator = iterator()) { return iterator.next(); } } @Override public E firstOr(E defaultElement) { try (CloseableIterator<E> iterator = iterator()) { if (iterator.hasNext()) { return iterator.next(); } } return defaultElement; } @Override public E firstOr(Supplier<E> supplier) { try (CloseableIterator<E> iterator = iterator()) { if (iterator.hasNext()) { return iterator.next(); } } return supplier.get(); } @Override public E firstOrNull() { return firstOr((E)null); } @Override public CloseableIterator<E> iterator() { // check closed if (closed.get()) { throw new IllegalStateException(); } CloseableIterator<E> iterator = iterator(0, Integer.MAX_VALUE); iterators.add(iterator); return iterator; } @Override public Stream<E> stream() { final CloseableIterator<E> iterator = iterator(); Spliterator<E> spliterator = maxSize == null ? Spliterators.spliteratorUnknownSize(iterator, 0) : Spliterators.spliterator(iterator, maxSize, 0); return StreamSupport.stream(spliterator, false).onClose(new Runnable() { @Override public void run() { iterator.close(); } }); } @Override public void each(Consumer<? super E> action) { try (CloseableIterator<E> iterator = iterator()) { while (iterator.hasNext()) { action.accept(iterator.next()); } } } @Override public <K> Map<K, E> toMap(Expression<K> key) { return toMap(key, new HashMap<K, E>()); } @Override @SuppressWarnings("unchecked") public <K> Map<K, E> toMap(Expression<K> key, Map<K, E> map) { try (CloseableIterator<E> iterator = iterator()) { while (iterator.hasNext()) { E value = iterator.next(); Type<E> type = null; if (key instanceof Attribute) { Attribute attribute = (Attribute) key; type = (Type<E>) attribute.getDeclaringType(); } if (type != null) { EntityProxy<E> proxy = type.getProxyProvider().apply(value); map.put(proxy.get((Attribute<E, K>) key), value); } else if (value instanceof Tuple) { map.put(((Tuple) value).get(key), value); } else { throw new UnsupportedOperationException(); } } } return map; } @Override public void close() { if (closed.compareAndSet(false, true)) { CloseableIterator<E> iterator = iterators.poll(); while (iterator != null) { iterator.close(); iterator = iterators.poll(); } } } }