Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slick: factory method SlickSession.forDbAndProfile #1996

Merged
merged 3 commits into from
Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/src/main/paradox/slick.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ SQL Server

Of course these are just examples. Please visit the @extref[Slick documentation for `DatabaseConfig.fromConfig`](slick:api/index.html#slick.jdbc.JdbcBackend$DatabaseFactoryDef@forConfig(String,Config,Driver,ClassLoader%29:Database) for the full list of things to configure.

You also have the option to create a SlickSession from Slick Database and Profile objects.

Scala
: @@snip [snip](/slick/src/test/scala/docs/scaladsl/SlickSpec.scala) { #init-session-from-db-and-profile }

This can be useful if you need to share you configurations with code using Slick directly, or in cases where you first get the database information at runtime, as the Slicks Database class offer factory methods for that. This method is only available in the scaladsl, as Slick has no Java API and as such no easy way of creating a Database instance from Java.

## Closing a Database Session

Slick requires you to eventually close your database session to free up connection pool resources. You would usually do this when terminating the `ActorSystem`, by registering a termination handler like this:
Expand Down
3 changes: 3 additions & 0 deletions slick/src/main/mima-filters/1.1.x.backwards.excludes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# New classes introduced for adding an extra factory method for SlickSession in #1509
ProblemFilters.exclude[MissingClassProblem]("akka.stream.alpakka.slick.javadsl.SlickSession$SlickSessionImpl")
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.stream.alpakka.slick.scaladsl.package.SlickSession")
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import slick.basic.DatabaseConfig
import slick.jdbc.JdbcBackend
import slick.jdbc.JdbcProfile
import slick.jdbc.PositionedResult

import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory

Expand All @@ -28,27 +27,32 @@ sealed abstract class SlickSession {
def close(): Unit = db.close()
}

/**
* Java API: Methods for "opening" Slick databases for use.
*
* <b>NOTE</b>: databases created through these methods will need to be
* closed after creation to avoid leaking database resources like active
* connection pools, etc.
*/
object SlickSession {
private final class SlickSessionImpl(val slick: DatabaseConfig[JdbcProfile]) extends SlickSession {
private[slick] abstract class SlickSessionFactory {
protected final class SlickSessionConfigBackedImpl(val slick: DatabaseConfig[JdbcProfile]) extends SlickSession {
val db: JdbcBackend#Database = slick.db
val profile: JdbcProfile = slick.profile
}
protected final class SlickSessionDbAndProfileBackedImpl(val db: JdbcBackend#Database, val profile: JdbcProfile)
extends SlickSession

def forConfig(path: String): SlickSession = forConfig(path, ConfigFactory.load())
def forConfig(config: Config): SlickSession = forConfig("", config)
def forConfig(path: String, config: Config): SlickSession = forConfig(
DatabaseConfig.forConfig[JdbcProfile](path, config)
)
def forConfig(databaseConfig: DatabaseConfig[JdbcProfile]): SlickSession = new SlickSessionImpl(databaseConfig)
def forConfig(databaseConfig: DatabaseConfig[JdbcProfile]): SlickSession =
new SlickSessionConfigBackedImpl(databaseConfig)
}

/**
* Java API: Methods for "opening" Slick databases for use.
*
* <b>NOTE</b>: databases created through these methods will need to be
* closed after creation to avoid leaking database resources like active
* connection pools, etc.
*/
object SlickSession extends SlickSessionFactory

/**
* Java API: A class representing a slick resultset row, which is used
* in SlickSource to map result set rows back to Java objects.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package akka.stream.alpakka.slick

import slick.jdbc.{JdbcBackend, JdbcProfile}

package object scaladsl {

/**
Expand All @@ -21,5 +23,8 @@ package object scaladsl {
* closed after creation to avoid leaking database resources like active
* connection pools, etc.
*/
val SlickSession = javadsl.SlickSession
object SlickSession extends javadsl.SlickSessionFactory {
def forDbAndProfile(db: JdbcBackend#Database, profile: JdbcProfile): SlickSession =
new SlickSessionDbAndProfileBackedImpl(db, profile)
}
}
22 changes: 21 additions & 1 deletion slick/src/test/scala/docs/scaladsl/SlickSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class SlickSpec extends WordSpec with ScalaFutures with BeforeAndAfterEach with
//#init-mat

//#init-session
implicit val session = SlickSession.forConfig("slick-h2")
implicit val session: SlickSession = SlickSession.forConfig("slick-h2")
//#init-session

import session.profile.api._
Expand Down Expand Up @@ -77,6 +77,26 @@ class SlickSpec extends WordSpec with ScalaFutures with BeforeAndAfterEach with
TestKit.shutdownActorSystem(system)
}

"SlickSession.forDbAndProfile" must {
"create a slick session able to talk to the db" in {
//#init-session-from-db-and-profile
val db = Database.forConfig("slick-h2.db")
val profile = slick.jdbc.H2Profile
val slickSessionCreatedForDbAndProfile: SlickSession = SlickSession.forDbAndProfile(db, profile)
//#init-session-from-db-and-profile
try {
val q = sql"select true".as[Boolean]
val result = Slick
.source(q)(slickSessionCreatedForDbAndProfile)
.runWith(Sink.head)
.futureValue
assert(result === true)
} finally {
slickSessionCreatedForDbAndProfile.close()
}
}
}

"Slick.source(...)" must {
def tupleToUser(columns: (Int, String)): User = User(columns._1, columns._2)

Expand Down