pjfanning commented on code in PR #664:
URL: https://github.com/apache/pekko-projection/pull/664#discussion_r4382784690


##########
r2dbc/src/main/scala/org/apache/pekko/projection/r2dbc/javadsl/R2dbcSession.scala:
##########
@@ -25,10 +26,45 @@ import org.apache.pekko
 import pekko.actor.typed.ActorSystem
 import pekko.annotation.ApiMayChange
 import pekko.persistence.r2dbc.internal.R2dbcExecutor
+import pekko.projection.r2dbc.scaladsl
 import io.r2dbc.spi.Connection
 import io.r2dbc.spi.Row
 import io.r2dbc.spi.Statement
 
+object R2dbcSession {
+
+  /**
+   * Runs the passed function using a R2dbcSession with a new transaction. The 
connection is closed and the
+   * transaction is committed at the end or rolled back in case of failures.
+   *
+   * The connection factory is the one configured by 
`pekko.projection.r2dbc.use-connection-factory`.
+   *
+   * @since 2.0.0
+   */
+  def withSession[A](system: ActorSystem[?], fun: JFunction[R2dbcSession, 
CompletionStage[A]]): CompletionStage[A] =
+    withSession(system, 
scaladsl.R2dbcSession.connectionFactoryConfigPath(system), fun)
+
+  /**
+   * Runs the passed function using a R2dbcSession with a new transaction. The 
connection is closed and the
+   * transaction is committed at the end or rolled back in case of failures.
+   *
+   * @param connectionFactoryConfigPath config path of the connection factory 
to use, for example
+   *   `pekko.persistence.r2dbc.connection-factory`
+   * @since 2.0.0
+   */
+  def withSession[A](
+      system: ActorSystem[?],
+      connectionFactoryConfigPath: String,
+      fun: JFunction[R2dbcSession, CompletionStage[A]]): CompletionStage[A] =
+    scaladsl.R2dbcSession
+      .withSession(system, connectionFactoryConfigPath) { scaladslSession =>
+        val javadslSession = new 
R2dbcSession(scaladslSession.connection)(system.executionContext, system)
+        fun(javadslSession).asScala
+      }
+      .asJava

Review Comment:
   Added a Java usage in e56bbc84: a `#withSession` snippet in 
`R2dbcProjectionDocExample.java` that calls `R2dbcSession.withSession(system, 
session -> ...)` through the static forwarders, so `r2dbc/Test/compile` breaks 
if they go away. A matching Scala snippet is in 
`R2dbcProjectionDocExample.scala`.



##########
docs/src/main/paradox/r2dbc.md:
##########
@@ -14,6 +14,10 @@ The target database operations can be run in the same 
transaction as the storage
 that @ref:[exactly-once](#exactly-once) processing semantics is supported. It 
also offers
 @ref:[at-least-once](#at-least-once) semantics.
 
+An `R2dbcSession` can also be used outside of a projection handler, for 
example to query the projected data.
+`R2dbcSession.withSession` runs the given function with a new transaction that 
is committed when the returned
+@scala[`Future`]@java[`CompletionStage`] completes successfully, and rolled 
back if it fails.

Review Comment:
   Done in e56bbc84. The intro paragraph is now its own section, "Using 
R2dbcSession outside a handler", under Handler. It has `@apidoc[R2dbcSession$]` 
and Scala/Java `@@snip` tabs.



##########
r2dbc/src/main/scala/org/apache/pekko/projection/r2dbc/scaladsl/R2dbcSession.scala:
##########
@@ -19,10 +19,55 @@ import scala.concurrent.Future
 
 import org.apache.pekko
 import pekko.actor.typed.ActorSystem
+import pekko.annotation.InternalApi
+import pekko.persistence.r2dbc.ConnectionFactoryProvider
 import pekko.persistence.r2dbc.internal.R2dbcExecutor
+import pekko.projection.r2dbc.R2dbcProjectionSettings
 import io.r2dbc.spi.Connection
 import io.r2dbc.spi.Row
 import io.r2dbc.spi.Statement
+import org.slf4j.LoggerFactory
+
+object R2dbcSession {
+  private val log = LoggerFactory.getLogger(classOf[R2dbcSession])
+
+  /**
+   * Runs the passed function using a R2dbcSession with a new transaction. The 
connection is closed and the
+   * transaction is committed at the end or rolled back in case of failures.
+   *
+   * The connection factory is the one configured by 
`pekko.projection.r2dbc.use-connection-factory`.
+   *
+   * @since 2.0.0
+   */
+  def withSession[A](system: ActorSystem[?])(fun: R2dbcSession => Future[A]): 
Future[A] =
+    withSession(system, connectionFactoryConfigPath(system))(fun)
+
+  /**
+   * Runs the passed function using a R2dbcSession with a new transaction. The 
connection is closed and the
+   * transaction is committed at the end or rolled back in case of failures.
+   *
+   * @param connectionFactoryConfigPath config path of the connection factory 
to use, for example
+   *   `pekko.persistence.r2dbc.connection-factory`
+   * @since 2.0.0
+   */
+  def withSession[A](system: ActorSystem[?], connectionFactoryConfigPath: 
String)(
+      fun: R2dbcSession => Future[A]): Future[A] = {
+    val connectionFactory = 
ConnectionFactoryProvider(system).connectionFactoryFor(connectionFactoryConfigPath)
+    val r2dbcExecutor =
+      new R2dbcExecutor(connectionFactory, log, 
R2dbcProjectionSettings(system).logDbCallsExceeding)(

Review Comment:
   Done in e56bbc84. The settings and connection factory lookup are wrapped in 
`try`/`NonFatal`, so the error comes back as a failed 
`Future`/`CompletionStage`. New `R2dbcSessionSpec` cases for an unknown config 
path in both DSLs fail if the error is rethrown.



##########
r2dbc/src/main/scala/org/apache/pekko/projection/r2dbc/scaladsl/R2dbcSession.scala:
##########
@@ -19,10 +19,55 @@ import scala.concurrent.Future
 
 import org.apache.pekko
 import pekko.actor.typed.ActorSystem
+import pekko.annotation.InternalApi
+import pekko.persistence.r2dbc.ConnectionFactoryProvider
 import pekko.persistence.r2dbc.internal.R2dbcExecutor
+import pekko.projection.r2dbc.R2dbcProjectionSettings
 import io.r2dbc.spi.Connection
 import io.r2dbc.spi.Row
 import io.r2dbc.spi.Statement
+import org.slf4j.LoggerFactory
+
+object R2dbcSession {
+  private val log = LoggerFactory.getLogger(classOf[R2dbcSession])
+
+  /**
+   * Runs the passed function using a R2dbcSession with a new transaction. The 
connection is closed and the
+   * transaction is committed at the end or rolled back in case of failures.
+   *
+   * The connection factory is the one configured by 
`pekko.projection.r2dbc.use-connection-factory`.
+   *
+   * @since 2.0.0
+   */
+  def withSession[A](system: ActorSystem[?])(fun: R2dbcSession => Future[A]): 
Future[A] =
+    withSession(system, connectionFactoryConfigPath(system))(fun)
+
+  /**
+   * Runs the passed function using a R2dbcSession with a new transaction. The 
connection is closed and the
+   * transaction is committed at the end or rolled back in case of failures.
+   *
+   * @param connectionFactoryConfigPath config path of the connection factory 
to use, for example
+   *   `pekko.persistence.r2dbc.connection-factory`
+   * @since 2.0.0
+   */
+  def withSession[A](system: ActorSystem[?], connectionFactoryConfigPath: 
String)(
+      fun: R2dbcSession => Future[A]): Future[A] = {
+    val connectionFactory = 
ConnectionFactoryProvider(system).connectionFactoryFor(connectionFactoryConfigPath)
+    val r2dbcExecutor =
+      new R2dbcExecutor(connectionFactory, log, 
R2dbcProjectionSettings(system).logDbCallsExceeding)(
+        system.executionContext,
+        system)
+    r2dbcExecutor.withConnection("R2dbcSession") { connection =>
+      fun(new R2dbcSession(connection)(system.executionContext, system))
+    }
+  }
+
+  /**
+   * INTERNAL API
+   */
+  @InternalApi private[pekko] def connectionFactoryConfigPath(system: 
ActorSystem[?]): String =
+    
system.settings.config.getConfig(R2dbcProjectionSettings.DefaultConfigPath).getString("use-connection-factory")

Review Comment:
   Done in e56bbc84. Settings are parsed once per call, 
`settings.useConnectionFactory` is used, and the `connectionFactoryConfigPath` 
helper is removed. It was only added in this PR, so nothing released changes.



##########
r2dbc/src/main/scala/org/apache/pekko/projection/r2dbc/javadsl/R2dbcSession.scala:
##########
@@ -25,10 +26,45 @@ import org.apache.pekko
 import pekko.actor.typed.ActorSystem
 import pekko.annotation.ApiMayChange
 import pekko.persistence.r2dbc.internal.R2dbcExecutor
+import pekko.projection.r2dbc.scaladsl
 import io.r2dbc.spi.Connection
 import io.r2dbc.spi.Row
 import io.r2dbc.spi.Statement
 
+object R2dbcSession {
+
+  /**
+   * Runs the passed function using a R2dbcSession with a new transaction. The 
connection is closed and the
+   * transaction is committed at the end or rolled back in case of failures.
+   *
+   * The connection factory is the one configured by 
`pekko.projection.r2dbc.use-connection-factory`.
+   *
+   * @since 2.0.0
+   */
+  def withSession[A](system: ActorSystem[?], fun: JFunction[R2dbcSession, 
CompletionStage[A]]): CompletionStage[A] =
+    withSession(system, 
scaladsl.R2dbcSession.connectionFactoryConfigPath(system), fun)
+
+  /**
+   * Runs the passed function using a R2dbcSession with a new transaction. The 
connection is closed and the
+   * transaction is committed at the end or rolled back in case of failures.
+   *
+   * @param connectionFactoryConfigPath config path of the connection factory 
to use, for example
+   *   `pekko.persistence.r2dbc.connection-factory`
+   * @since 2.0.0
+   */
+  def withSession[A](
+      system: ActorSystem[?],
+      connectionFactoryConfigPath: String,
+      fun: JFunction[R2dbcSession, CompletionStage[A]]): CompletionStage[A] =
+    scaladsl.R2dbcSession
+      .withSession(system, connectionFactoryConfigPath) { scaladslSession =>
+        val javadslSession = new 
R2dbcSession(scaladslSession.connection)(system.executionContext, system)
+        fun(javadslSession).asScala
+      }
+      .asJava
+
+}
+
 @ApiMayChange

Review Comment:
   Annotated both the scaladsl and javadsl `object R2dbcSession` with 
`@ApiMayChange` in e56bbc84. That matches `R2dbcProjection` and `R2dbcHandler`, 
which have it in both DSLs. Stabilising the javadsl can be a separate decision.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to