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

@since 1.0.0.0
-}
module Orville.PostgreSQL.Schema.SequenceDefinition
  ( SequenceDefinition
  , mkSequenceDefinition
  , setSequenceSchema
  , sequenceIdentifier
  , sequenceName
  , sequenceIncrement
  , setSequenceIncrement
  , sequenceMinValue
  , setSequenceMinValue
  , sequenceMaxValue
  , setSequenceMaxValue
  , sequenceStart
  , setSequenceStart
  , sequenceCache
  , setSequenceCache
  , sequenceCycle
  , setSequenceCycle
  , mkCreateSequenceExpr
  )
where

import Data.Int (Int64)

import qualified Orville.PostgreSQL.Expr as Expr
import Orville.PostgreSQL.Schema.SequenceIdentifier (SequenceIdentifier, sequenceIdQualifiedName, setSequenceIdSchema, unqualifiedNameToSequenceId)

{- |
  Contains the definition of a SQL sequence for Orville to use when creating
  the sequence and fetching values from it. You can create a
  'SequenceDefinition' with default values via 'mkSequenceDefinition' and then
  use the various set functions that are provided if you need to set specific
  attributes on the sequence.

@since 1.0.0.0
-}
data SequenceDefinition = SequenceDefinition
  { SequenceDefinition -> SequenceIdentifier
i_sequenceIdentifier :: SequenceIdentifier
  , SequenceDefinition -> Int64
i_sequenceIncrement :: Int64
  , SequenceDefinition -> Maybe Int64
i_sequenceMinValue :: Maybe Int64
  , SequenceDefinition -> Maybe Int64
i_sequenceMaxValue :: Maybe Int64
  , SequenceDefinition -> Maybe Int64
i_sequenceStart :: Maybe Int64
  , SequenceDefinition -> Int64
i_sequenceCache :: Int64
  , SequenceDefinition -> Bool
i_sequenceCycle :: Bool
  }
  deriving (SequenceDefinition -> SequenceDefinition -> Bool
(SequenceDefinition -> SequenceDefinition -> Bool)
-> (SequenceDefinition -> SequenceDefinition -> Bool)
-> Eq SequenceDefinition
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SequenceDefinition -> SequenceDefinition -> Bool
== :: SequenceDefinition -> SequenceDefinition -> Bool
$c/= :: SequenceDefinition -> SequenceDefinition -> Bool
/= :: SequenceDefinition -> SequenceDefinition -> Bool
Eq, Int -> SequenceDefinition -> ShowS
[SequenceDefinition] -> ShowS
SequenceDefinition -> String
(Int -> SequenceDefinition -> ShowS)
-> (SequenceDefinition -> String)
-> ([SequenceDefinition] -> ShowS)
-> Show SequenceDefinition
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SequenceDefinition -> ShowS
showsPrec :: Int -> SequenceDefinition -> ShowS
$cshow :: SequenceDefinition -> String
show :: SequenceDefinition -> String
$cshowList :: [SequenceDefinition] -> ShowS
showList :: [SequenceDefinition] -> ShowS
Show)

{- |
  Constructs an ascending 'SequenceDefinition' with increment 1 and cache
  1 that does not cycle. The sequence will start at 1 and count to the
  largest 'Int64' value.

@since 1.0.0.0
-}
mkSequenceDefinition :: String -> SequenceDefinition
mkSequenceDefinition :: String -> SequenceDefinition
mkSequenceDefinition String
name =
  SequenceDefinition
    { i_sequenceIdentifier :: SequenceIdentifier
i_sequenceIdentifier = String -> SequenceIdentifier
unqualifiedNameToSequenceId String
name
    , i_sequenceIncrement :: Int64
i_sequenceIncrement = Int64
1
    , i_sequenceMinValue :: Maybe Int64
i_sequenceMinValue = Maybe Int64
forall a. Maybe a
Nothing
    , i_sequenceMaxValue :: Maybe Int64
i_sequenceMaxValue = Maybe Int64
forall a. Maybe a
Nothing
    , i_sequenceStart :: Maybe Int64
i_sequenceStart = Maybe Int64
forall a. Maybe a
Nothing
    , i_sequenceCache :: Int64
i_sequenceCache = Int64
1
    , i_sequenceCycle :: Bool
i_sequenceCycle = Bool
False
    }

{- |
  Sets the sequence's schema to the name in the given 'String', which will be
  treated as a SQL identifier. If a sequence has a schema name set, it will be
  included as a qualifier on the sequence name for all queries involving the
  sequence.

@since 1.0.0.0
-}
setSequenceSchema ::
  String ->
  SequenceDefinition ->
  SequenceDefinition
setSequenceSchema :: String -> SequenceDefinition -> SequenceDefinition
setSequenceSchema String
schemaName SequenceDefinition
sequenceDef =
  SequenceDefinition
sequenceDef
    { i_sequenceIdentifier :: SequenceIdentifier
i_sequenceIdentifier = String -> SequenceIdentifier -> SequenceIdentifier
setSequenceIdSchema String
schemaName (SequenceDefinition -> SequenceIdentifier
i_sequenceIdentifier SequenceDefinition
sequenceDef)
    }

{- |
  Retrieves the 'SequenceIdentifier' for this sequence, which is set by the
  name provided to 'mkSequenceDefinition' and any calls made to
  'setSequenceSchema' thereafter.

@since 1.0.0.0
-}
sequenceIdentifier :: SequenceDefinition -> SequenceIdentifier
sequenceIdentifier :: SequenceDefinition -> SequenceIdentifier
sequenceIdentifier = SequenceDefinition -> SequenceIdentifier
i_sequenceIdentifier

{- |
  Retrieves the 'Expr.Qualified' 'Expr.SequenceName' for the sequence that
  should be used to build SQL expressions involving it.

@since 1.0.0.0
-}
sequenceName :: SequenceDefinition -> Expr.Qualified Expr.SequenceName
sequenceName :: SequenceDefinition -> Qualified SequenceName
sequenceName =
  SequenceIdentifier -> Qualified SequenceName
sequenceIdQualifiedName (SequenceIdentifier -> Qualified SequenceName)
-> (SequenceDefinition -> SequenceIdentifier)
-> SequenceDefinition
-> Qualified SequenceName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SequenceDefinition -> SequenceIdentifier
i_sequenceIdentifier

{- |
  Retrieves the increment value for the sequence.

@since 1.0.0.0
-}
sequenceIncrement :: SequenceDefinition -> Int64
sequenceIncrement :: SequenceDefinition -> Int64
sequenceIncrement = SequenceDefinition -> Int64
i_sequenceIncrement

{- |
  Sets the increment value for the sequence. The increment cannot be set to
  @0@ (PostgreSQL will raise an error when trying to create or modify the
  sequence in this case).

  If the increment is negative, the sequence will be descending. When no
  explicit start is set, a descending sequence begins at the max value.

@since 1.0.0.0
-}
setSequenceIncrement :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceIncrement :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceIncrement Int64
n SequenceDefinition
sequenceDef =
  SequenceDefinition
sequenceDef {i_sequenceIncrement :: Int64
i_sequenceIncrement = Int64
n}

{- |
  Retrieves the min value of the sequence. If no explicit minimum has been set,
  this returns @1@ for ascending sequences and 'minBound' for 'Int64' for
  descending sequences.

@since 1.0.0.0
-}
sequenceMinValue :: SequenceDefinition -> Int64
sequenceMinValue :: SequenceDefinition -> Int64
sequenceMinValue SequenceDefinition
sequenceDef =
  case SequenceDefinition -> Maybe Int64
i_sequenceMinValue SequenceDefinition
sequenceDef of
    Just Int64
minValue -> Int64
minValue
    Maybe Int64
Nothing ->
      if SequenceDefinition -> Int64
sequenceIncrement SequenceDefinition
sequenceDef Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
0
        then Int64
1
        else Int64
forall a. Bounded a => a
minBound

{- |
  Sets the min value for the sequence.

@since 1.0.0.0
-}
setSequenceMinValue :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceMinValue :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceMinValue Int64
n SequenceDefinition
sequenceDef =
  SequenceDefinition
sequenceDef {i_sequenceMinValue :: Maybe Int64
i_sequenceMinValue = Int64 -> Maybe Int64
forall a. a -> Maybe a
Just Int64
n}

{- |
  Retrieves the max value of the sequence. If no explicit maximum has been set,
  this returns 'maxBound' for 'Int64' for ascending sequences and @-1@ for
  descending sequences.

@since 1.0.0.0
-}
sequenceMaxValue :: SequenceDefinition -> Int64
sequenceMaxValue :: SequenceDefinition -> Int64
sequenceMaxValue SequenceDefinition
sequenceDef =
  case SequenceDefinition -> Maybe Int64
i_sequenceMaxValue SequenceDefinition
sequenceDef of
    Just Int64
maxValue -> Int64
maxValue
    Maybe Int64
Nothing ->
      if SequenceDefinition -> Int64
sequenceIncrement SequenceDefinition
sequenceDef Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
0
        then Int64
forall a. Bounded a => a
maxBound
        else -Int64
1

{- |
  Sets the max value for the sequence.

@since 1.0.0.0
-}
setSequenceMaxValue :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceMaxValue :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceMaxValue Int64
n SequenceDefinition
sequenceDef =
  SequenceDefinition
sequenceDef {i_sequenceMaxValue :: Maybe Int64
i_sequenceMaxValue = Int64 -> Maybe Int64
forall a. a -> Maybe a
Just Int64
n}

{- |
  Retrieves the start value for the sequence. If no explicit start value has
  been set, this returns 'sequenceMinValue' for ascending sequences and
  'sequenceMaxValue' for descending sequences.

@since 1.0.0.0
-}
sequenceStart :: SequenceDefinition -> Int64
sequenceStart :: SequenceDefinition -> Int64
sequenceStart SequenceDefinition
sequenceDef =
  case SequenceDefinition -> Maybe Int64
i_sequenceStart SequenceDefinition
sequenceDef of
    Just Int64
start -> Int64
start
    Maybe Int64
Nothing ->
      if SequenceDefinition -> Int64
sequenceIncrement SequenceDefinition
sequenceDef Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
0
        then SequenceDefinition -> Int64
sequenceMinValue SequenceDefinition
sequenceDef
        else SequenceDefinition -> Int64
sequenceMaxValue SequenceDefinition
sequenceDef

{- |
  Sets the sequence start value. The start value must be at least the
  minimum value and no greater than the maximum value.

@since 1.0.0.0
-}
setSequenceStart :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceStart :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceStart Int64
n SequenceDefinition
sequenceDef =
  SequenceDefinition
sequenceDef {i_sequenceStart :: Maybe Int64
i_sequenceStart = Int64 -> Maybe Int64
forall a. a -> Maybe a
Just Int64
n}

{- |
  Retrieves the number of sequence values that will be pre-allocated by
  PostgreSQL.

@since 1.0.0.0
-}
sequenceCache :: SequenceDefinition -> Int64
sequenceCache :: SequenceDefinition -> Int64
sequenceCache = SequenceDefinition -> Int64
i_sequenceCache

{- |
  Sets the number of sequence values that will be pre-allocated by PostgreSQL.

@since 1.0.0.0
-}
setSequenceCache :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceCache :: Int64 -> SequenceDefinition -> SequenceDefinition
setSequenceCache Int64
n SequenceDefinition
sequenceDef =
  SequenceDefinition
sequenceDef {i_sequenceCache :: Int64
i_sequenceCache = Int64
n}

{- |
  Indicates whether the sequence will wrap around when it reaches the maximum
  value (for ascending sequences) or minimum value (for descending sequences).
  When 'False', any attempts to get the next value of the sequence while at the
  limit will result in an error.

@since 1.0.0.0
-}
sequenceCycle :: SequenceDefinition -> Bool
sequenceCycle :: SequenceDefinition -> Bool
sequenceCycle = SequenceDefinition -> Bool
i_sequenceCycle

{- |
  Sets the 'sequenceCycle' value for the sequence. 'True' indicates that the
  sequence will cycle. 'False' will cause an error to be raised if the next
  sequence value is requested while already at the limit.

@since 1.0.0.0
-}
setSequenceCycle :: Bool -> SequenceDefinition -> SequenceDefinition
setSequenceCycle :: Bool -> SequenceDefinition -> SequenceDefinition
setSequenceCycle Bool
b SequenceDefinition
sequenceDef =
  SequenceDefinition
sequenceDef {i_sequenceCycle :: Bool
i_sequenceCycle = Bool
b}

{- |
  Builds a 'Expr.CreateSequenceExpr' that will create a SQL sequence matching
  the given 'SequenceDefinition' when it is executed.

@since 1.0.0.0
-}
mkCreateSequenceExpr :: SequenceDefinition -> Expr.CreateSequenceExpr
mkCreateSequenceExpr :: SequenceDefinition -> CreateSequenceExpr
mkCreateSequenceExpr SequenceDefinition
sequenceDef =
  Qualified SequenceName
-> Maybe IncrementByExpr
-> Maybe MinValueExpr
-> Maybe MaxValueExpr
-> Maybe StartWithExpr
-> Maybe CacheExpr
-> Maybe CycleExpr
-> CreateSequenceExpr
Expr.createSequenceExpr
    (SequenceDefinition -> Qualified SequenceName
sequenceName SequenceDefinition
sequenceDef)
    (IncrementByExpr -> Maybe IncrementByExpr
forall a. a -> Maybe a
Just (IncrementByExpr -> Maybe IncrementByExpr)
-> (SequenceDefinition -> IncrementByExpr)
-> SequenceDefinition
-> Maybe IncrementByExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> IncrementByExpr
Expr.incrementBy (Int64 -> IncrementByExpr)
-> (SequenceDefinition -> Int64)
-> SequenceDefinition
-> IncrementByExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SequenceDefinition -> Int64
sequenceIncrement (SequenceDefinition -> Maybe IncrementByExpr)
-> SequenceDefinition -> Maybe IncrementByExpr
forall a b. (a -> b) -> a -> b
$ SequenceDefinition
sequenceDef)
    (MinValueExpr -> Maybe MinValueExpr
forall a. a -> Maybe a
Just (MinValueExpr -> Maybe MinValueExpr)
-> (SequenceDefinition -> MinValueExpr)
-> SequenceDefinition
-> Maybe MinValueExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> MinValueExpr
Expr.minValue (Int64 -> MinValueExpr)
-> (SequenceDefinition -> Int64)
-> SequenceDefinition
-> MinValueExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SequenceDefinition -> Int64
sequenceMinValue (SequenceDefinition -> Maybe MinValueExpr)
-> SequenceDefinition -> Maybe MinValueExpr
forall a b. (a -> b) -> a -> b
$ SequenceDefinition
sequenceDef)
    (MaxValueExpr -> Maybe MaxValueExpr
forall a. a -> Maybe a
Just (MaxValueExpr -> Maybe MaxValueExpr)
-> (SequenceDefinition -> MaxValueExpr)
-> SequenceDefinition
-> Maybe MaxValueExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> MaxValueExpr
Expr.maxValue (Int64 -> MaxValueExpr)
-> (SequenceDefinition -> Int64)
-> SequenceDefinition
-> MaxValueExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SequenceDefinition -> Int64
sequenceMaxValue (SequenceDefinition -> Maybe MaxValueExpr)
-> SequenceDefinition -> Maybe MaxValueExpr
forall a b. (a -> b) -> a -> b
$ SequenceDefinition
sequenceDef)
    (StartWithExpr -> Maybe StartWithExpr
forall a. a -> Maybe a
Just (StartWithExpr -> Maybe StartWithExpr)
-> (SequenceDefinition -> StartWithExpr)
-> SequenceDefinition
-> Maybe StartWithExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> StartWithExpr
Expr.startWith (Int64 -> StartWithExpr)
-> (SequenceDefinition -> Int64)
-> SequenceDefinition
-> StartWithExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SequenceDefinition -> Int64
sequenceStart (SequenceDefinition -> Maybe StartWithExpr)
-> SequenceDefinition -> Maybe StartWithExpr
forall a b. (a -> b) -> a -> b
$ SequenceDefinition
sequenceDef)
    (CacheExpr -> Maybe CacheExpr
forall a. a -> Maybe a
Just (CacheExpr -> Maybe CacheExpr)
-> (SequenceDefinition -> CacheExpr)
-> SequenceDefinition
-> Maybe CacheExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> CacheExpr
Expr.cache (Int64 -> CacheExpr)
-> (SequenceDefinition -> Int64) -> SequenceDefinition -> CacheExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SequenceDefinition -> Int64
sequenceCache (SequenceDefinition -> Maybe CacheExpr)
-> SequenceDefinition -> Maybe CacheExpr
forall a b. (a -> b) -> a -> b
$ SequenceDefinition
sequenceDef)
    (CycleExpr -> Maybe CycleExpr
forall a. a -> Maybe a
Just (CycleExpr -> Maybe CycleExpr)
-> (SequenceDefinition -> CycleExpr)
-> SequenceDefinition
-> Maybe CycleExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> CycleExpr
Expr.cycleIfTrue (Bool -> CycleExpr)
-> (SequenceDefinition -> Bool) -> SequenceDefinition -> CycleExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SequenceDefinition -> Bool
sequenceCycle (SequenceDefinition -> Maybe CycleExpr)
-> SequenceDefinition -> Maybe CycleExpr
forall a b. (a -> b) -> a -> b
$ SequenceDefinition
sequenceDef)