All Downloads are FREE. Search and download functionalities are using the official Maven repository.

harness.sql.PreparedStatement.scala Maven / Gradle / Ivy

package harness.sql

import harness.sql.error.QueryError
import harness.sql.query.*
import harness.sql.typeclass.*
import harness.zio.*
import zio.*

final class PreparedStatement private (
    queryName: String,
    fragment: Fragment,
    ps: java.sql.PreparedStatement,
) {

  private inline def attemptGeneric[A](hint: String)(thunk: => A): IO[QueryError, A] =
    QueryError.attempt(queryName, fragment.sql) { thunk }(QueryError.Cause.Generic(hint, _))

  def writeSingle[I, V](
      i: I,
      input: Input[I, V],
  ): ZIO[Logger, QueryError, Unit] =
    for {
      unmappedInputs <- attemptGeneric("Unable to create unmapped inputs") { input.buildUnmappedInputs(i) }
      encodedInputs <- attemptGeneric("Unable to encode inputs") { fragment.qim.prepare(unmappedInputs) }
      _ <- attemptGeneric("Unable to write inputs to prepared statement") {
        encodedInputs.zipWithIndexFrom(1).foreach { case (value, i) =>
          ps.setObject(i, value.value)
        }
      }
      // TODO (KR) : log?
    } yield ()

  def writeBatched[I](
      is: Chunk[I],
      input: Input[I, ?],
  ): ZIO[Logger, QueryError, Unit] =
    ZIO.foreachDiscard(is) { i =>
      writeSingle(i, input) *>
        attemptGeneric("Unable to add batch") { ps.addBatch(); ps.clearParameters() }
    }

  def executeQuery[O](decoder: QueryDecoderMany[O]): ZIO[Scope, QueryError, ResultSet[O]] =
    ZIO
      .acquireAutoClosable(QueryError.attempt(queryName, fragment.sql) { ps.executeQuery() }(QueryError.Cause.UnableToExecuteQuery(_)))
      .map(new ResultSet(queryName, fragment, _, decoder))

  def executeUpdate: IO[QueryError, Int] =
    QueryError.attempt(queryName, fragment.sql) { ps.executeUpdate() }(QueryError.Cause.UnableToExecuteQuery(_))

  def executeBatch: IO[QueryError, Chunk[Int]] =
    QueryError.attempt(queryName, fragment.sql) { Chunk.fromArray { ps.executeBatch() } }(QueryError.Cause.UnableToExecuteQuery(_))

}
object PreparedStatement {

  def make(queryName: String, fragment: Fragment): ZIO[JDBCConnection & Scope, QueryError, PreparedStatement] =
    ZIO
      .acquireAutoClosable[JDBCConnection, QueryError, java.sql.PreparedStatement] {
        ZIO.serviceWithZIO[JDBCConnection] { con =>
          QueryError.attempt(queryName, fragment.sql) {
            con.jdbcConnection.prepareStatement(fragment.sql)
          }(QueryError.Cause.Generic("Unable to create prepared statement", _))
        }
      }
      .map(PreparedStatement(queryName, fragment, _))

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy