packages feed

orville-postgresql-1.1.0.0: src/Orville/PostgreSQL/Execution/Sequence.hs

{- |
Copyright : Flipstone Technology Partners 2023
License   : MIT
Stability : Stable

Interactions to work with database sequence values on the Haskell side,
including inspection of the current and next values in the sequence as well as
updating a sequence to a given value.

@since 1.0.0.0
-}
module Orville.PostgreSQL.Execution.Sequence
  ( sequenceNextValue
  , sequenceCurrentValue
  , sequenceSetValue
  )
where

import Data.Int (Int64)

import qualified Orville.PostgreSQL.Execution.Execute as Execute
import qualified Orville.PostgreSQL.Execution.QueryType as QueryType
import qualified Orville.PostgreSQL.Expr as Expr
import qualified Orville.PostgreSQL.Internal.RowCountExpectation as RowCountExpectation
import qualified Orville.PostgreSQL.Marshall as Marshall
import qualified Orville.PostgreSQL.Monad as Monad
import Orville.PostgreSQL.Schema (SequenceDefinition, sequenceName)

{- | Fetches the next value from a sequence via the PostgreSQL @nextval@ function.

@since 1.0.0.0
-}
sequenceNextValue :: Monad.MonadOrville m => SequenceDefinition -> m Int64
sequenceNextValue sequenceDef =
  selectInt64Value
    "sequenceNextValue"
    (Expr.nextVal (sequenceName sequenceDef))

{- | Fetches the current value from a sequence via the PostgreSQL @currval@ function.

@since 1.0.0.0
-}
sequenceCurrentValue :: Monad.MonadOrville m => SequenceDefinition -> m Int64
sequenceCurrentValue sequenceDef =
  selectInt64Value
    "sequenceCurrentValue"
    (Expr.currVal (sequenceName sequenceDef))

{- | Sets the current value from a sequence via the PostgreSQL @setval@ function.

@since 1.0.0.0
-}
sequenceSetValue :: Monad.MonadOrville m => SequenceDefinition -> Int64 -> m Int64
sequenceSetValue sequenceDef newValue =
  selectInt64Value
    "sequenceSetValue"
    (Expr.setVal (sequenceName sequenceDef) newValue)

selectInt64Value :: Monad.MonadOrville m => String -> Expr.ValueExpression -> m Int64
selectInt64Value caller valueExpression = do
  let
    queryExpr =
      Expr.queryExpr
        (Expr.selectClause (Expr.selectExpr Nothing))
        ( Expr.selectDerivedColumns
            [Expr.deriveColumnAs valueExpression (Expr.columnName "result")]
        )
        Nothing

    marshaller =
      Marshall.annotateSqlMarshallerEmptyAnnotation
        . Marshall.marshallField id
        $ Marshall.bigIntegerField "result"
  values <- Execute.executeAndDecode QueryType.SelectQuery queryExpr marshaller
  RowCountExpectation.expectExactlyOneRow caller values