<commit_before>/*
 * Copyright 2020, 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.aggregate;

import com.google.common.collect.ImmutableList;
import com.google.protobuf.Timestamp;
import com.google.protobuf.util.Timestamps;
import io.spine.annotation.Internal;
import io.spine.annotation.SPI;
import io.spine.base.EntityState;
import io.spine.client.ResponseFormat;
import io.spine.client.TargetFilters;
import io.spine.core.Event;
import io.spine.core.Version;
import io.spine.query.RecordQuery;
import io.spine.server.ContextSpec;
import io.spine.server.entity.EntityRecord;
import io.spine.server.entity.storage.EntityRecordStorage;
import io.spine.server.entity.storage.EntityRecordWithColumns;
import io.spine.server.storage.AbstractStorage;
import io.spine.server.storage.QueryConverter;
import io.spine.server.storage.StorageFactory;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Iterator;
import java.util.List;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.spine.server.aggregate.AggregateRecords.newEventRecord;
import static io.spine.server.aggregate.AggregateRepository.DEFAULT_SNAPSHOT_TRIGGER;
import static io.spine.server.storage.QueryConverter.convert;
import static io.spine.util.Exceptions.newIllegalStateException;

/**
 * A storage of aggregate events, snapshots and the most recent aggregate states.
 *
 * <p>The instances of this type solve two problems.
 *
 * <ol>
 *     <li>efficient loading of an Aggregate instance from its events;
 *
 *     <li>storing the latest state of an Aggregate along with its lifecycle flags to allow
 *     its further querying.
 * </ol>
 *
 * <h3>Storing Aggregate events</h3>
 *
 * <p>Each Aggregate is an event-sourced Entity. To load an Aggregate instance, one plays all
 * of the events emitted by it, eventually obtaining the last known state. While the Event Store
 * of a Bounded Context, to which some Aggregate belongs, stores all domain events, using it
 * for the sake of loading an Aggregate is inefficient in most cases. An overwhelming number of
 * the domain events emitted in a Bounded Context and the restrictions applied by an underlying
 * storage tools make searching for the events of a particular Aggregate a difficult task, given
 * that the events are constantly being appended to the respective Event Store.
 *
 * <p>This storage duplicates a portion of events emitted by the Aggregates of a certain type.
 * It dramatically narrows down the number of storage records to traverse when loading.
 * Additionally, this storage is responsible for storing the intermediate snapshots of Aggregate
 * states, incorporating them into an optimized loading routines. The history of an Aggregate
 * is being read from the most recent event till its most recent snapshot, which reduces
 * the I/O between the underlying storage and application even more and enhances the overall
 * system performance.
 *
 * <p>In order to store events and snapshots, an intermediate {@link AggregateEventStorage} is
 * created. It persists data as Protobuf message records in its pre-configured
 * {@link io.spine.server.storage.RecordStorage RecordStorage}.
 *
 * <h3>Storing and querying the latest Aggregate states</h3>
 *
 * <p>End-users of the framework are able {@linkplain #enableStateQuerying() to enable this storage}
 * to store the latest states of Aggregates and allow their
 * {@linkplain #readStates(TargetFilters, ResponseFormat) querying}. To some extent, it makes
 * this storage a part of an application's read-side. Similar to storages of other Entity types,
 * {@code AggregateStorage} supports querying the Aggregate states by the values of their declared
 * entity columns. See {@code io.spine.query} package docs for more details on the query language.
 *
 * <p>However, even if this feature is not enabled, the storage persists the essential bits of
 * Aggregate as an Entity. Namely, its identifier, its lifecycle flags and version. Such a behavior
 * allows to speed up the execution of calls such as {@linkplain #index() obtaining an index}
 * of Aggregate identifiers, which otherwise would involve major storage scans along with
 * {@code DISTINCT} group operation applied.
 *
 * <p>As long as the Aggregate states are no different in their persistence from other Entities,
 * the {@code AggregateStorage} uses an intermediate {@link EntityRecordStorage} by delegating
 * all state-related operations to it.
 *
 * @param <I>
 *         the type of IDs of aggregates served by this storage
 * @param <S>
 *         the type of states of aggregates served by this storage
 *
 */<commit_msg>Clarify the documentation.<commit_after>/*
 * Copyright 2020, 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.aggregate;

import com.google.common.collect.ImmutableList;
import com.google.protobuf.Timestamp;
import com.google.protobuf.util.Timestamps;
import io.spine.annotation.Internal;
import io.spine.annotation.SPI;
import io.spine.base.EntityState;
import io.spine.client.ResponseFormat;
import io.spine.client.TargetFilters;
import io.spine.core.Event;
import io.spine.core.Version;
import io.spine.query.RecordQuery;
import io.spine.server.ContextSpec;
import io.spine.server.entity.EntityRecord;
import io.spine.server.entity.storage.EntityRecordStorage;
import io.spine.server.entity.storage.EntityRecordWithColumns;
import io.spine.server.storage.AbstractStorage;
import io.spine.server.storage.QueryConverter;
import io.spine.server.storage.StorageFactory;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.Iterator;
import java.util.List;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.spine.server.aggregate.AggregateRecords.newEventRecord;
import static io.spine.server.aggregate.AggregateRepository.DEFAULT_SNAPSHOT_TRIGGER;
import static io.spine.server.storage.QueryConverter.convert;
import static io.spine.util.Exceptions.newIllegalStateException;

/**
 * A storage of aggregate events, snapshots and the most recent aggregate states.
 *
 * <p>The instances of this type solve two problems.
 *
 * <ol>
 *     <li>efficient loading of an Aggregate instance from its events;
 *
 *     <li>storing the latest state of an Aggregate along with its lifecycle flags to allow
 *     its further querying.
 * </ol>
 *
 * <h3>Storing Aggregate events</h3>
 *
 * <p>Each Aggregate is an event-sourced Entity. To load an Aggregate instance, one plays all
 * of the events emitted by it, eventually obtaining the last known state. While the Event Store
 * of a Bounded Context, to which some Aggregate belongs, stores all domain events, using it
 * for the sake of loading an Aggregate is inefficient in most cases. An overwhelming number of
 * the domain events emitted in a Bounded Context and the restrictions applied by an underlying
 * storage tools make searching for the events of a particular Aggregate a difficult task, given
 * that the events are constantly being appended to the respective Event Store.
 *
 * <p>This storage duplicates a portion of events emitted by the Aggregates of a certain type.
 * It dramatically narrows down the number of storage records to traverse when loading.
 * Additionally, this storage is responsible for storing the intermediate snapshots of Aggregate
 * states, incorporating them into an optimized loading routines. The history of an Aggregate
 * is being read from the most recent event till its most recent snapshot, which reduces
 * the I/O between the underlying storage and application even more and enhances the overall
 * system performance.
 *
 * <p>In order to store events and snapshots, an intermediate {@link AggregateEventStorage} is
 * created. It persists data as Protobuf message records in its pre-configured
 * {@link io.spine.server.storage.RecordStorage RecordStorage}.
 *
 * <h3>Storing and querying the latest Aggregate states</h3>
 *
 * <p>End-users of the framework are able to set the visibility level for each Aggregate state
 * by using an {@linkplain io.spine.server.entity.EntityVisibility (entity).visibility} option
 * in the Protobuf message corresponding to the Aggregate state. For those Aggregates which are
 * visible, the framework routines {@linkplain #enableStateQuerying() enable this storage}
 * to persist the latest states of Aggregates and allow their further
 * {@linkplain #readStates(TargetFilters, ResponseFormat) querying}. To some extent, it makes this
 * storage a part of an application's read-side.
 *
 * <p>Similar to storages of other Entity types, {@code AggregateStorage} supports querying
 * the Aggregate states by the values of their declared entity columns. See {@code io.spine.query}
 * package docs for more details on the query language.
 *
 * <p>However, even if the Aggregate visibility is set to
 * {@link io.spine.option.EntityOption.Visibility#NONE NONE}, the storage still persists
 * the essential bits of Aggregate as-an-Entity. Namely, its identifier, its lifecycle flags
 * and version. Such a behavior allows to speed up the execution of calls such
 * as {@linkplain #index() obtaining an index} of Aggregate identifiers, which otherwise would
 * involve major scans of event storage, with {@code DISTINCT} group operation applied.
 *
 * <p>As long as the Aggregate states are no different in their persistence from other Entities,
 * the {@code AggregateStorage} uses an intermediate {@link EntityRecordStorage} by delegating
 * all state-related operations to it.
 *
 * @param <I>
 *         the type of IDs of aggregates served by this storage
 * @param <S>
 *         the type of states of aggregates served by this storage
 *
 */
{'fraction_non_alphanumeric': 0.06853265479219678, 'fraction_numerical': 0.0013570822731128074, 'mean_word_length': 4.66875, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6615390', 'n_tokens_mistral': 3195, 'n_tokens_neox': 3033, 'n_words': 1378}