Получить или вставить в транзакции на Doobie в Scala
Я читаю документацию Doobie и пытаюсь выполнить простое получение или создание внутри транзакции. Я получаю опцию от первого запроса и пытаюсь сделать getOrElse
и запустить вставку в остальном, однако я продолжаю получать value map is not a member of Any
в пределах getOrElse
вызов. Как правильно получить существующую или создать новую строку в instances
и вернуть этот результат в транзакции?
import doobie._
import doobie.implicits._
import cats._
import cats.effect._
import cats.implicits._
import org.joda.time.DateTime
import scala.concurrent.ExecutionContext
case class Instance(id : Int, hostname : String)
case class User(id : Int, instanceId: Int, username : String, email : String, created : DateTime)
class Database(dbUrl : String, dbUser: String, dbPass: String) {
implicit val cs = IO.contextShift(ExecutionContext.global)
val xa = Transactor.fromDriverManager[IO](
"org.postgresql.Driver", dbUrl, dbUser, dbPass
)
def getOrCreateInstance(hostname: String) = for {
existingInstance <- sql"SELECT id, hostname FROM instances i WHERE i.hostname = $hostname".query[Instance].option
ensuredInstance <- existingInstance.getOrElse(sql"INSERT INTO instances(hostname) VALUES(?)".update.withGeneratedKeys[Instance]("id", "hostname"))
} yield ensuredInstance
}
2 ответа
Я получил следующий ответ благодаря людям в чате #scala/freenode. Я публикую это здесь для полноты, и если люди заинтересованы в том, чтобы сделать это без понимания в другом ответе.
def getOrCreateInstance(hostname: String): ConnectionIO[Instance] =
OptionT(sql"SELECT id, hostname FROM instances i WHERE i.hostname = $hostname".query[Instance].option)
.getOrElseF(sql"INSERT INTO instances(hostname) VALUES($hostname)".update.withGeneratedKeys[Instance]("id", "hostname").compile.lastOrError)
Я верю, что что-то подобное должно работать на тебя,
def getOrCreateInstance(hostname: String): ConnectionIO[Instance] = for {
existingInstance <- sql"SELECT id, hostname FROM instances i WHERE i.hostname = $hostname".query[Instance].option
ensuredInstance <- existingInstance.fold(sql"INSERT INTO instances(hostname) VALUES($hostname)".update.withGeneratedKeys[Instance]("id", "hostname").take(1).compile.lastOrError)(_.pure[ConnectionIO])
} yield ensuredInstance
где вы компилируете fs2 Stream
а также поднимая существующий экземпляр в ConnectionIO
в том случае, если он уже существует.