packages feed

orville-postgresql-1.0.0.0: src/Orville/PostgreSQL/Expr/Update.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

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

@since 1.0.0.0
-}
module Orville.PostgreSQL.Expr.Update
  ( UpdateExpr
  , updateExpr
  , SetClauseList
  , setClauseList
  , SetClause
  , setColumn
  )
where

import Data.List.NonEmpty (NonEmpty)
import Data.Maybe (catMaybes)

import Orville.PostgreSQL.Expr.Name (ColumnName, Qualified, TableName)
import Orville.PostgreSQL.Expr.ReturningExpr (ReturningExpr)
import Orville.PostgreSQL.Expr.WhereClause (WhereClause)
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
import qualified Orville.PostgreSQL.Raw.SqlValue as SqlValue

{- |
Type to represent a SQL @UPDATE@ statement. E.G.

> UPDATE foo
> SET id = 1
> WHERE id <> 1

'UpdateExpr' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype UpdateExpr
  = UpdateExpr RawSql.RawSql
  deriving (RawSql.SqlExpression)

{- |
  Constructs an 'UpdateExpr' with the given options.

  @since 1.0.0.0
-}
updateExpr ::
  -- | The name of the table to be updated.
  Qualified TableName ->
  -- | The updates to be made to the table.
  SetClauseList ->
  -- | An optional where clause to limit the rows updated.
  Maybe WhereClause ->
  -- | An optional returning clause to return data from the updated rows.
  Maybe ReturningExpr ->
  UpdateExpr
updateExpr tableName setClause maybeWhereClause maybeReturningExpr =
  UpdateExpr $
    RawSql.intercalate RawSql.space $
      catMaybes
        [ Just $ RawSql.fromString "UPDATE"
        , Just $ RawSql.toRawSql tableName
        , Just $ RawSql.fromString "SET"
        , Just $ RawSql.toRawSql setClause
        , fmap RawSql.toRawSql maybeWhereClause
        , fmap RawSql.toRawSql maybeReturningExpr
        ]

{- |
Type to represent the list of updates to be made in an @UPDATE@ statement. E.G.

> foo = 1,
> bar = 2

'SetClauseList' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype SetClauseList
  = SetClauseList RawSql.RawSql
  deriving (RawSql.SqlExpression)

{- |
  Constructs a 'SetClauseList' with the specified set clauses.

  @since 1.0.0.0
-}
setClauseList :: NonEmpty SetClause -> SetClauseList
setClauseList =
  SetClauseList . RawSql.intercalate RawSql.comma

{- |
Type to represent a single update to be made in an @UPDATE@ statement. E.G.

> foo = 1

'SetClause' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.

@since 1.0.0.0
-}
newtype SetClause
  = SetClause RawSql.RawSql
  deriving (RawSql.SqlExpression)

{- |
  Constructs a 'SetClause' that will set the specified column to the specified
  value.

  @since 1.0.0.0
-}
setColumn :: ColumnName -> SqlValue.SqlValue -> SetClause
setColumn columnName value =
  SetClause $
    RawSql.toRawSql columnName
      <> RawSql.fromString "="
      <> RawSql.parameter value