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

kalix.scalasdk.view.View.scala Maven / Gradle / Ivy

/*
 * Copyright 2024 Lightbend Inc.
 *
 * 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 kalix.scalasdk.view

import kalix.scalasdk.impl.view.ViewUpdateEffectImpl

object View {

  /**
   * @tparam S
   *   The type of the state for this view.
   */
  trait UpdateEffect[+S]

  /**
   * An UpdateEffect is a description of what Kalix needs to do after the command is handled. You can think of it as a
   * set of instructions you are passing to Kalix. Kalix will process the instructions on your behalf and ensure that
   * any data that needs to be persisted will be persisted.
   *
   * Each Kalix component defines its own effects, which are a set of predefined operations that match the capabilities
   * of that component.
   *
   * A View UpdateEffect can either:
   *
   *   - update the view state
   *   - delete the view state
   *   - ignore the event or state change notification (and not update the view state)
   *
   * Construct the effect that is returned by the command handler. The effect describes next processing actions, such as
   * emitting events and sending a reply.
   */
  object UpdateEffect {

    sealed trait Builder[S] {

      def updateState(newState: S): View.UpdateEffect[S]

      def deleteState(): View.UpdateEffect[S]

      /** Ignore this event (and continue to process the next). */
      def ignore(): View.UpdateEffect[S]

      /**
       * Trigger an error for the event. Returning this effect is equivalent to throwing an exception from the handler
       * and will lead to retrying processing of the same event until it is handled successfully.
       *
       * @param description
       *   The description of the error.
       */
      def error(description: String): View.UpdateEffect[S]
    }

    def builder[S](): Builder[S] =
      _builder.asInstanceOf[Builder[S]]

    private[scalasdk] val _builder = new Builder[Any] {

      override def updateState(newState: Any): View.UpdateEffect[Any] =
        ViewUpdateEffectImpl.Update(newState)

      override def deleteState(): View.UpdateEffect[Any] = ViewUpdateEffectImpl.Delete

      override def ignore(): View.UpdateEffect[Any] =
        ViewUpdateEffectImpl.Ignore

      override def error(description: String): View.UpdateEffect[Any] =
        ViewUpdateEffectImpl.Error(description)
    }
  }
}

/**
 * Kalix applications follow the Command Query Responsibility Segregation (CQRS) pattern (see
 * https://developer.lightbend.com/docs/akka-guide/concepts/cqrs.html).
 *
 * Kalix' Entities represent the command side where you change the state of your model in a strictly consistent and
 * isolated manner. Kalix' Views represent the query side of your application. Views are optimized for reads and allow
 * you to query your model by fields other than the entity identifier.
 *
 * When implementing a View, you define what will be its internal state (your view model) and how you want to query it.
 * The Query string defines which fields will be indexed and how the query will be executed.
 *
 * The query is executed by the Kalix when a request is made to the View.
 *
 * Views are updated in response to Event Sourced Entity events, Value Entity state changes or messages from a Topic.
 *
 * Each incoming change is handled by a command handler. Command handlers are methods returning an
 * [[kalix.scalasdk.view.View.UpdateEffect]]. The command handler is responsible for updating the View state.
 *
 * @tparam S
 *   The type of the state for this view.
 */
abstract class View[S] {

  private var _updateContext: Option[UpdateContext] = None

  /**
   * Additional context and metadata for an update handler.
   *
   * It will throw an exception if accessed from constructor.
   */
  protected final def updateContext(): UpdateContext =
    _updateContext.getOrElse(
      throw new IllegalStateException("UpdateContext is only available when handling an update."))

  /** INTERNAL API */
  private[scalasdk] def _internalSetUpdateContext(context: Option[UpdateContext]): Unit =
    _updateContext = context

  protected final def effects: View.UpdateEffect.Builder[S] =
    View.UpdateEffect.builder()

  /**
   * @return
   *   an empty state object to hand to the process method when an event for a previously unknown subject id is seen.
   */
  def emptyState: S

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy