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

skunk.tables.Insert.scala Maven / Gradle / Ivy

/*
 * Copyright 2023 Foldables
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package skunk.tables

import skunk.{Query as _, *}
import skunk.data.Completion
import skunk.implicits.*

/** `Insert` is an `Action` with `INSERT INTO` statement underneath It returns no values as is (just
  * `Completion`), but can be transformed into a `Query` if `RETURNING` clause is added
  */
sealed trait Insert[F[_], A] extends Action[F, "none", Completion]:
  self =>

  def run(session: Session[F]): F[Completion] =
    session
      .execute[Input](fragment.command)(input)

  /** All original table columns */
  type Columns <: NonEmptyTuple

  /** Add `RETURNING` clause to transform this `Insert` into `Query`
    *
    * @param columns
    *   a tuple of literals, matching the column names
    * @param ft
    *   given evidence that `columns` are present in the original table
    * @return
    *   plain `Query` with `single` cardinality
    */
  transparent inline def returning[RL <: NonEmptyTuple](columns: RL)(using ft: FromTable[Columns, RL]) =
    new Query[F, "single", ft.Out]:
      type Input = self.Input
      val input   = self.input
      val decoder = ft.decoder
      // I don't know why `Fragment` interpolation needs casting when the method is transparent
      val fragment: Fragment[Input] =
        self.fragment <~ sql" RETURNING ${ft.columnsFragment}"
          .asInstanceOf[Fragment[Void]]

object Insert:

  def insert[F[_], T, A, C <: NonEmptyTuple](table: Table.Name, a: A, ci: CanInsert[A, T]) =
    new Insert[F, A]:
      type Columns = C
      type Input   = ci.Twiddled

      def input: Input =
        ci.transform(a)
      def fragment: Fragment[Input] =
        sql"INSERT INTO ${table.toFragment} (${ci.columnsFragment}) VALUES (${ci.encoder})"




© 2015 - 2025 Weber Informatics LLC | Privacy Policy