/*
 * Copyright 2019, TeamDev. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.server.storage.datastore;

import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.EntityQuery;
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.Query;
import com.google.common.collect.Streams;
import io.spine.string.Stringifiers;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Iterator;
import java.util.function.Function;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * A utility for generating the
 * {@linkplain io.spine.server.storage.Storage#index() storage ID indexes}.
 *
 * @see io.spine.server.storage.Storage#index()
 */
final class Indexes {

    /**
     * Prevents the utility class instantiation.
     */
    private Indexes() {
    }

    /**
     * Retrieves the ID index for the given {@code kind} or the storage records.
     *
     * @param datastore
     *         datastore to get the indexes for
     * @param kind
     *         the kind if the records in the datastore
     * @param <I>
     *         type of the IDs to retrieve
     * @return an {@link Iterator} of the IDs matching given record kind
     */
    static <I> Iterator<I> indexIterator(DatastoreWrapper datastore, Kind kind, Class<I> idType) {
        checkNotNull(datastore);
        checkNotNull(kind);
        checkNotNull(idType);

        EntityQuery.Builder query = Query.newEntityQueryBuilder()
                                         .setKind(kind.getValue());
        Iterator<Entity> allEntities = datastore.read(query.build());
        Iterator<I> idIterator = Streams.stream(allEntities)
                                        .map(idExtractor(idType))
                                        .iterator();
        return idIterator;
    }

    private static <I> Function<Entity, @Nullable I> idExtractor(Class<I> idType) {
        return input -> {
            checkNotNull(input);
            Key key = input.getKey();
            String stringId = key.getName();
            I id = Stringifiers.fromString(stringId, idType);
            return id;
        };
    }
}

@@ -1084,21 +1084,18 @@
 tastore.
-Entit
+Ke
 y;%0Aimpor
@@ -1123,22 +1123,16 @@
 tastore.
-Entity
 Query;%0Ai
@@ -1168,47 +1168,18 @@
 ore.
-Key;%0Aimport com.google.cloud.datastore.
+Structured
 Quer
@@ -2325,27 +2325,28 @@
     
-EntityQuery.Builder
+StructuredQuery%3CKey%3E
  que
@@ -2359,21 +2359,18 @@
 uery.new
-Entit
+Ke
 yQueryBu
@@ -2377,16 +2377,17 @@
 ilder()%0A
+ 
         
@@ -2444,16 +2444,67 @@
 Value())
+%0A                                          .build()
 ;%0A      
@@ -2514,21 +2514,18 @@
 terator%3C
-Entit
+Ke
 y%3E allEn
@@ -2553,24 +2553,16 @@
 ad(query
-.build()
 );%0A     
@@ -2802,21 +2802,18 @@
 unction%3C
-Entit
+Ke
 y, @Null
@@ -2819,16 +2819,20 @@
 lable I%3E
+%0A   
  idExtra
@@ -2870,21 +2870,19 @@
  return 
-input
+key
  -%3E %7B%0A  
@@ -2908,51 +2908,11 @@
 ull(
-input);%0A            Key key = input.getKey(
+key
 );%0A 

Migrate `indexIterator` to key-only datastore query