{-|
This module contains the `Block` definition representing a command block and functions for getting a specific type of blocks from a list of `Block`.
-}

module Lsql.Csv.Core.BlockOps 
  (
    Block(Select, If, Sort, By),
    getSelects, getIf, getSort, getBy
  ) 
where

import Lsql.Csv.Core.Functions
import Lsql.Csv.Core.Tables

import Data.List

-- | This data structure represents a command block.
data Block = Select [Arg] | If Arg | Sort [Arg] | By [Arg]

-- | Returns all select blocks.
getSelects :: [Block] -> [[Arg]]
getSelects :: [Block] -> [[Arg]]
getSelects [] = []
getSelects ((Select [Arg]
a) : [Block]
rest) = [Arg]
a [Arg] -> [[Arg]] -> [[Arg]]
forall a. a -> [a] -> [a]
: [Block] -> [[Arg]]
getSelects [Block]
rest
getSelects (Block
_ : [Block]
rest) = [Block] -> [[Arg]]
getSelects [Block]
rest

-- | Makes conjunction of all if blocks (if none, simple `True` is returned) and returns it.
getIf :: [Block] -> Arg
getIf :: [Block] -> Arg
getIf [Block]
blocks = 
  (Arg -> Arg -> Arg) -> Arg -> [Arg] -> Arg
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\Arg
x Arg
y -> Function -> Arg
Function(Function -> Arg) -> Function -> Arg
forall a b. (a -> b) -> a -> b
$ LogicF -> Function
LogicF(LogicF -> Function) -> LogicF -> Function
forall a b. (a -> b) -> a -> b
$ Arg -> Arg -> LogicF
And Arg
x Arg
y) 
    (Value -> Arg
Value(Value -> Arg) -> Value -> Arg
forall a b. (a -> b) -> a -> b
$ Bool -> Value
BoolValue(Bool -> Value) -> Bool -> Value
forall a b. (a -> b) -> a -> b
$ Bool
True) ([Arg] -> Arg) -> [Arg] -> Arg
forall a b. (a -> b) -> a -> b
$ [Block] -> [Arg]
getIfBlocks [Block]
blocks

  where
    getIfBlocks :: [Block] -> [Arg]
    getIfBlocks :: [Block] -> [Arg]
getIfBlocks [] = []
    getIfBlocks ((If Arg
a) : [Block]
rest) = Arg
a Arg -> [Arg] -> [Arg]
forall a. a -> [a] -> [a]
: [Block] -> [Arg]
getIfBlocks [Block]
rest
    getIfBlocks (Block
_ : [Block]
rest) = [Block] -> [Arg]
getIfBlocks [Block]
rest

-- | Finds a sort block, if exists, and returns it. If there is none, [] is returned.
-- If there is more than one sort block, fails.
getSort :: [Block] -> [Arg]
getSort :: [Block] -> [Arg]
getSort [] = []
getSort ((Sort [Arg]
a) : [Block]
rest) 
  | [Arg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null([Arg] -> Bool) -> [Arg] -> Bool
forall a b. (a -> b) -> a -> b
$ [Block] -> [Arg]
getSort [Block]
rest = [Arg]
a
  | Bool
otherwise = [Char] -> [Arg]
forall a. HasCallStack => [Char] -> a
error [Char]
"There can be only one sort statement."

getSort (Block
_ : [Block]
rest) = [Block] -> [Arg]
getSort [Block]
rest

-- | Finds a by block, if exists, and returns it. If there is none, [] is returned.
-- If there is more than one by block, fails.
getBy :: [Block] -> [Arg]
getBy :: [Block] -> [Arg]
getBy [] = []
getBy ((By [Arg]
a) : [Block]
rest)
  | [Arg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null([Arg] -> Bool) -> [Arg] -> Bool
forall a b. (a -> b) -> a -> b
$ [Block] -> [Arg]
getBy [Block]
rest = [Arg]
a
  | Bool
otherwise = [Char] -> [Arg]
forall a. HasCallStack => [Char] -> a
error [Char]
"There can be only one by statement."

getBy (Block
_ : [Block]
rest) = [Block] -> [Arg]
getBy [Block]
rest