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

skunk-core_3.0.0-RC1.0.1.0.source-code.Fragment.scala Maven / Gradle / Ivy

// Copyright (c) 2018-2021 by Rob Norris
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT

package skunk

import cats.ContravariantSemigroupal
import cats.data.State
import cats.syntax.all._
import skunk.util.Origin

/**
 * A composable, embeddable hunk of SQL and typed parameters (common precursor to `Command` and
 * `Query`). Although it is possible to construct a `Fragment` directly it is more typical to use
 * the `sql` interpolator.
 * @group Statements
 */
final case class Fragment[A](
  parts:   List[Either[String, State[Int, String]]],
  encoder: Encoder[A],
  origin:  Origin
) extends (A => AppliedFragment) {

  lazy val sql: String =
    parts.traverse {
      case Left(s)  => s.pure[State[Int, *]]
      case Right(s) => s
    } .runA(1).value.combineAll

  def query[B](decoder: Decoder[B]): Query[A, B] =
    Query(sql, origin, encoder, decoder)

  def command: Command[A] =
    Command(sql, origin, encoder)

  def contramap[B](f: B => A): Fragment[B] =
    Fragment(parts, encoder.contramap(f), origin)

  def product[B](fb: Fragment[B]): Fragment[(A, B)] =
    Fragment(parts <+> fb.parts, encoder ~ fb.encoder, origin)

  def ~[B](fb: Fragment[B]): Fragment[A ~ B] =
    product(fb)

  def apply(a: A): AppliedFragment =
    AppliedFragment(this, a)

  override def toString: String =
    s"Fragment($sql, $encoder)"

}

/** @group Companions */
object Fragment {

  implicit val FragmentContravariantSemigroupal: ContravariantSemigroupal[Fragment] =
    new ContravariantSemigroupal[Fragment] {
      override def contramap[A, B](fa: Fragment[A])(f: B => A): Fragment[B] = fa.contramap(f)
      override def product[A, B](fa: Fragment[A], fb: Fragment[B]): Fragment[(A, B)] = fa product fb
    }

  private[skunk] def apply(sql: String): Fragment[Void] =
    Fragment(List(Left(sql)), Void.codec, Origin.unknown)


  val empty: Fragment[Void] =
    apply("")

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy