com.cloudant.sync.indexing.BasicQueryResult.java Source code

Java tutorial

Introduction

Here is the source code for com.cloudant.sync.indexing.BasicQueryResult.java

Source

/**
 * Copyright (c) 2013 Cloudant, Inc. All rights reserved.
 *
 * 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 com.cloudant.sync.indexing;

import com.cloudant.sync.datastore.Datastore;
import com.cloudant.sync.datastore.DocumentRevision;
import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

class BasicQueryResult implements QueryResult {

    private final static int DEFAULT_BATCH_SIZE = 50;
    private final List<String> documentIds;
    private final Datastore datastore;
    private final int batchSize;

    public BasicQueryResult(List<String> documentIds, Datastore datastore) {
        this(documentIds, datastore, DEFAULT_BATCH_SIZE);
    }

    public BasicQueryResult(List<String> documentIds, Datastore datastore, int batchSize) {
        this.documentIds = documentIds;
        this.datastore = datastore;
        this.batchSize = batchSize;
    }

    @Override
    public long size() {
        return documentIds.size();
    }

    @Override
    public List<String> documentIds() {
        return documentIds;
    }

    @Override
    public Iterator<DocumentRevision> iterator() {

        /**
         * Partitions a set of document IDs into batches of DocumentRevision
         * objects, and provides an iterator over the whole, un-partitioned set
         * of revision objects (as if they were not batched).
         */
        return new Iterator<DocumentRevision>() {

            /** List containing lists of partitions document IDs */
            private final List<List<String>> subLists = this.partition(documentIds, batchSize);
            /** The current partition's iterator of document objects */
            private Iterator<DocumentRevision> subIterator = null;

            @Override
            public boolean hasNext() {
                if (subIterator == null) {
                    return subLists.size() > 0;
                } else {
                    return this.subIterator.hasNext() || subLists.size() > 0;
                }
            }

            @Override
            public DocumentRevision next() {
                if (subIterator == null || !subIterator.hasNext()) {
                    List<String> ids = subLists.remove(0);
                    subIterator = this.nextSubIterator(ids);
                }

                return subIterator.next();
            }

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

            /**
             * Partition a list of document IDs into batches of batchSize.
             *
             * Return a mutable list of consecutive sublists.
             * Same as Guava's "Lists.partition" except the result list is mutable.
             * It is needed because this iterator removes sublist from the partitions
             * as it goes.
             *
             * @See http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Lists.html#partition(java.util.List, int)
             */
            private List<List<String>> partition(List<String> documentIds, int batchSize) {
                List<List<String>> partitions = Lists.partition(documentIds, batchSize);
                List<List<String>> res = new LinkedList<List<String>>();
                for (List<String> p : partitions) {
                    res.add(p);
                }
                return res;
            }

            /**
             * Load the next partition of DocumentRevision objects for the
             * iterator.
             *
             * @param ids the IDs of the revisions to load.
             * @return an iterator over the DocumentRevision objects for `ids`.
             */
            private Iterator<DocumentRevision> nextSubIterator(List<String> ids) {
                HashMap<String, DocumentRevision> map = new HashMap<String, DocumentRevision>();
                for (DocumentRevision revision : datastore.getDocumentsWithIds(ids)) {
                    map.put(revision.getId(), revision);
                }
                List<DocumentRevision> revisions = new ArrayList<DocumentRevision>(ids.size());
                // return list of DocumentRevision that in the same order as input "ids"
                for (String id : ids) {
                    DocumentRevision revision = map.get(id);
                    if (revision != null) {
                        revisions.add(revision);
                    }
                }
                return revisions.iterator();
            }
        };
    }
}