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

org.deephacks.graphene.ResultSet Maven / Gradle / Ivy

There is a newer version: 0.2.2
Show newest version
/**
 * 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 org.deephacks.graphene;

import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import org.deephacks.graphene.internal.BytesUtils;
import org.deephacks.graphene.internal.FastKeyComparator;
import org.deephacks.graphene.internal.RowKey;
import org.deephacks.graphene.internal.Serializer;

import java.io.Closeable;
import java.util.Iterator;

/**
 * A lazy evaluated result set iterator matching a certain query that created this
 * result set. Items that are not iterated are not evaluated.
 *
 * @param  type of instances
 */
public abstract class ResultSet implements Iterable, Closeable {

    public abstract Iterator iterator();

    public abstract void close();

    static class DefaultResultSet extends ResultSet {
        private static final Handle graphene = Graphene.get();
        private int maxResult = Integer.MAX_VALUE;
        private int matches = 0;
        private final Cursor cursor;
        private final Optional criteria;
        private final Serializer serializer;
        private DatabaseEntry key;
        private DatabaseEntry value;
        private byte[] first;
        private byte[] last;
        private boolean lastReached = false;

        public DefaultResultSet(Class entityClass, Object first, Object last, int maxResult, Optional criteria, Cursor cursor) {
            this.maxResult = maxResult;
            this.key = new DatabaseEntry();
            this.serializer = graphene.get().getSerializer(entityClass);
            if (first != null) {
                this.first = serializer.serializeRowKey(new RowKey(entityClass, first));
                this.key.setData(this.first);
                value = new DatabaseEntry();
            } else {
                this.first = serializer.serializeRowKey(RowKey.getMinId(entityClass));
                this.key.setData(this.first);
                value = new DatabaseEntry();
            }
            cursor.getSearchKeyRange(key, value, LockMode.RMW);
            if (last != null) {
                this.last = serializer.serializeRowKey(new RowKey(entityClass, last));
            } else {
                this.last = serializer.serializeRowKey(RowKey.getMaxId(entityClass));
            }
            this.cursor = cursor;
            this.criteria = criteria;

        }

        @Override
        public Iterator iterator() {
            final Iterator iterator;
            if (criteria.isPresent()) {
                iterator = Iterables.filter(new ByteIterator(), criteria.get()).iterator();

            } else {
                iterator = Iterables.filter(new ByteIterator(), byte[][].class).iterator();
            }
            return new ByteIteratorWrapper(iterator, serializer);
        }

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

        class ByteIterator implements Iterable {

            @Override
            public Iterator iterator() {

                return new Iterator() {
                    @Override
                    public boolean hasNext() {
                        if (matches == 0 && value != null && value.getData() != null) {
                            // the first value may already be fetched if
                            // cursor.getSearchKeyRange found a key
                            return true;
                        }
                        value = new DatabaseEntry();
                        boolean success = cursor.getNextNoDup(key, value, LockMode.RMW) == OperationStatus.SUCCESS;
                        if (!FastKeyComparator.withinKeyRange(key.getData(), first, last)) {
                            return false;
                        }
                        if (!success) {
                            return false;
                        }
                        if (last != null && BytesUtils.compareTo(key.getData(), 0, key.getData().length, last, 0, last.length) > 0) {
                            lastReached = true;
                        }
                        return matches < maxResult && !lastReached;
                    }

                    @Override
                    public byte[][] next() {
                        byte[] valueData = value.getData();
                        byte[] keyData = key.getData();
                        value = null;
                        return new byte[][]{ keyData, valueData };
                    }

                    @Override
                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        }

        class ByteIteratorWrapper implements Iterator {

            private final Iterator iterator;
            private final Serializer serializer;

            public ByteIteratorWrapper(Iterator iterator, Serializer serializer) {
                this.iterator = iterator;
                this.serializer = serializer;
            }

            @Override
            public boolean hasNext() {
                return iterator.hasNext() && matches++ < maxResult;
            }

            @Override
            public T next() {
                byte[][] data = iterator.next();
                return (T) serializer.deserializeEntity(data);
            }

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy