{-# LANGUAGE GeneralizedNewtypeDeriving #-}

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

@since 1.0.0.0
-}
module Orville.PostgreSQL.Expr.GroupBy
  ( GroupByClause
  , groupByClause
  , GroupByExpr
  , appendGroupByExpr
  , groupByColumnsExpr
  )
where

import Data.List.NonEmpty (NonEmpty)

import Orville.PostgreSQL.Expr.Name (ColumnName)
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql

{- |
Type to represent a SQL group by clause. E.G.

> GROUP BY team_name

'GroupByClause' 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 GroupByClause
  = GroupByClause RawSql.RawSql
  deriving
    ( -- | @since 1.0.0.0
      RawSql -> GroupByClause
GroupByClause -> RawSql
(GroupByClause -> RawSql)
-> (RawSql -> GroupByClause) -> SqlExpression GroupByClause
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: GroupByClause -> RawSql
toRawSql :: GroupByClause -> RawSql
$cunsafeFromRawSql :: RawSql -> GroupByClause
unsafeFromRawSql :: RawSql -> GroupByClause
RawSql.SqlExpression
    )

{- | Create a full SQL GROUP BY clause with the given expression.

@since 1.0.0.0
-}
groupByClause :: GroupByExpr -> GroupByClause
groupByClause :: GroupByExpr -> GroupByClause
groupByClause GroupByExpr
expr = RawSql -> GroupByClause
GroupByClause (String -> RawSql
RawSql.fromString String
"GROUP BY " RawSql -> RawSql -> RawSql
forall a. Semigroup a => a -> a -> a
<> GroupByExpr -> RawSql
forall a. SqlExpression a => a -> RawSql
RawSql.toRawSql GroupByExpr
expr)

{- |
Type to represent a SQL group by expression (the part that follows the
@GROUP BY@ in SQL). E.G.

> team_name

'GroupByExpr' 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 GroupByExpr
  = GroupByExpr RawSql.RawSql
  deriving
    ( -- | @since 1.0.0.0
      RawSql -> GroupByExpr
GroupByExpr -> RawSql
(GroupByExpr -> RawSql)
-> (RawSql -> GroupByExpr) -> SqlExpression GroupByExpr
forall a. (a -> RawSql) -> (RawSql -> a) -> SqlExpression a
$ctoRawSql :: GroupByExpr -> RawSql
toRawSql :: GroupByExpr -> RawSql
$cunsafeFromRawSql :: RawSql -> GroupByExpr
unsafeFromRawSql :: RawSql -> GroupByExpr
RawSql.SqlExpression
    )

{- |
@since 1.0.0.0
-}
instance Semigroup GroupByExpr where
  <> :: GroupByExpr -> GroupByExpr -> GroupByExpr
(<>) = GroupByExpr -> GroupByExpr -> GroupByExpr
appendGroupByExpr

{- | Combines two 'GroupByExpr's with a comma between them.

@since 1.0.0.0
-}
appendGroupByExpr :: GroupByExpr -> GroupByExpr -> GroupByExpr
appendGroupByExpr :: GroupByExpr -> GroupByExpr -> GroupByExpr
appendGroupByExpr (GroupByExpr RawSql
a) (GroupByExpr RawSql
b) =
  RawSql -> GroupByExpr
GroupByExpr (RawSql
a RawSql -> RawSql -> RawSql
forall a. Semigroup a => a -> a -> a
<> RawSql
RawSql.commaSpace RawSql -> RawSql -> RawSql
forall a. Semigroup a => a -> a -> a
<> RawSql
b)

{- | Create a 'GroupByExpr' from the given 'ColumnName's.

@since 1.0.0.0
-}
groupByColumnsExpr :: NonEmpty ColumnName -> GroupByExpr
groupByColumnsExpr :: NonEmpty ColumnName -> GroupByExpr
groupByColumnsExpr =
  RawSql -> GroupByExpr
GroupByExpr (RawSql -> GroupByExpr)
-> (NonEmpty ColumnName -> RawSql)
-> NonEmpty ColumnName
-> GroupByExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RawSql -> NonEmpty ColumnName -> RawSql
forall sql (f :: * -> *).
(SqlExpression sql, Foldable f) =>
RawSql -> f sql -> RawSql
RawSql.intercalate RawSql
RawSql.commaSpace