Skip to content

Commit

Permalink
ensure default schema appears first in search_path, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rolang committed Oct 16, 2024
1 parent 7f0f24d commit c3724d0
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 14 deletions.
29 changes: 16 additions & 13 deletions modules/core/shared/src/main/scala/dumbo/Dumbo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ final class DumboWithResourcesPartiallyApplied[F[_]](reader: ResourceReader[F])
defaultSchema: String,
schemas: Set[String],
)(implicit T: Temporal[F], C: Console[F], TRC: Tracer[F], N: Network[F]) = {
val searchPath = (schemas + defaultSchema).mkString(",")
val searchPath = Dumbo.toSearchPath(defaultSchema, schemas)
val params = Session.DefaultConnectionParameters ++ Map("search_path" -> searchPath)

Session.single[F](
Expand Down Expand Up @@ -173,7 +173,7 @@ class Dumbo[F[_]: Sync: Console](
) {
import Dumbo.*

private[dumbo] val allSchemas = Set(defaultSchema) ++ schemas
private[dumbo] val allSchemas = defaultSchema :: schemas.toList
private[dumbo] val historyTable = s"${defaultSchema}.${schemaHistoryTable}"
private val dumboHistory = History(historyTable)

Expand Down Expand Up @@ -350,27 +350,26 @@ class Dumbo[F[_]: Sync: Console](
// verify search_path
_ <- session.unique(sql"SHOW search_path".query(text)).flatMap { sp =>
val spSchemas = sp.split(",").map(_.trim).toSet
allSchemas.filterNot(spSchemas.contains(_)).toList match {
allSchemas.diff(spSchemas.toList) match {
case Nil => ().pure[F]
case missing =>
val newSearchPath = allSchemas.mkString(",")
val newSearchPath = toSearchPath(defaultSchema, schemas)
Console[F].println(
s"""|WARNING: Following schemas are not included in the search path '$sp': ${missing.mkString(", ")}.
|The search_path will be set to '${newSearchPath}'. Consider adding it to session parameters instead.""".stripMargin
) >> session.execute(sql"SET search_path = #${newSearchPath}".command).void
) >> session.execute(sql"SET search_path TO #${newSearchPath}".command).void
}
}
dbVersion <- session.unique(sql"SELECT version()".query(text))
_ <- Console[F].println(s"Starting migration on $dbVersion")
schemaRes <-
allSchemas.toList
.flatTraverse(schema =>
session.execute(initSchemaCmd(schema)).attempt.map {
case Right(Completion.CreateSchema) => List(schema)
case Left(e: skunk.exception.PostgresErrorException) if duplicateErrorCodes.contains(e.code) => Nil
case _ => Nil
}
)
allSchemas.flatTraverse(schema =>
session.execute(initSchemaCmd(schema)).attempt.map {
case Right(Completion.CreateSchema) => List(schema)
case Left(e: skunk.exception.PostgresErrorException) if duplicateErrorCodes.contains(e.code) => Nil
case _ => Nil
}
)
_ <- session.execute(dumboHistory.createTableCommand).void.recover {
case e: skunk.exception.PostgresErrorException if duplicateErrorCodes.contains(e.code) => ()
}
Expand Down Expand Up @@ -569,4 +568,8 @@ object Dumbo extends internal.DumboPlatform {
.compile
.drain
} yield crc32.getValue().toInt

// need to ensure that default schema appears first in the search_path
private[dumbo] def toSearchPath(defaultSchema: String, schemas: Set[String]) =
(defaultSchema :: schemas.toList).mkString(",")
}
5 changes: 4 additions & 1 deletion modules/tests/shared/src/main/scala/ffstest/FFramework.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ trait FTest extends CatsEffectSuite with FTestPlatform {

def dbTest(name: String)(f: => IO[Unit]): Unit = test(name)(dropSchemas >> f)

def someSchemaName = s"schema_${Random.alphanumeric.take(10).mkString}"
def someSchemaName: String = {
val chars = "abcdefghijklmnopqrstuvwxyz"
LazyList.continually(chars.charAt(Random.nextInt(chars.length))).take(15).mkString
}

lazy val connectionConfig: ConnectionConfig = ConnectionConfig(
host = "localhost",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE TABLE test_default_schema();
33 changes: 33 additions & 0 deletions modules/tests/shared/src/test/scala/DumboMigrationSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import scala.concurrent.duration.*
import cats.data.Validated.Invalid
import cats.implicits.*
import ffstest.TestConsole
import skunk.codec.all.*
import skunk.implicits.*

trait DumboMigrationSpec extends ffstest.FTest {
def db: Db
Expand Down Expand Up @@ -208,6 +210,37 @@ trait DumboMigrationSpec extends ffstest.FTest {
} yield ()
}

dbTest("default schema is used when no schema is specified in migration sripts") {
val withResources = dumboWithResources("db/test_default_schema")

(1 to 5).toList.traverse_ { _ =>
val schemaDefault = someSchemaName
val schemas = List.fill(scala.util.Random.nextInt(10))(someSchemaName)

def assertDefaultSchemaHasTable =
session()
.use(
_.execute(sql"""|SELECT table_schema::text
|FROM information_schema.tables
|WHERE table_name = 'test_default_schema'""".stripMargin.query(text))
)
.map { schemas =>
assertEquals(schemas, List(schemaDefault))
}

for {
_ <- dropSchemas
// migrate by connection config
_ <- dumboMigrate(schemaDefault, withResources, schemas)
_ <- assertDefaultSchemaHasTable
_ <- dropSchemas
// migrate by custom session
_ <- dumboMigrateWithSession(schemaDefault, withResources, session(), schemas)
_ <- assertDefaultSchemaHasTable
} yield ()
}
}

{
val withResources = dumboWithResources("db/test_long_running")
def logMatch(s: String): Boolean = s.startsWith("Awaiting query with pid")
Expand Down

0 comments on commit c3724d0

Please sign in to comment.