Получить или вставить в транзакции на Doobie в Scala - PullRequest
0 голосов
/ 22 декабря 2018

Я читаю документацию 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 ]

0 голосов
/ 24 декабря 2018

Я получил следующий ответ благодаря людям в чате # 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)
0 голосов
/ 23 декабря 2018

Я полагаю, что что-то вроде этого должно работать для вас,

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 в случае, если он уже существует.

...