{-|
This module contains the evaluator of a lsql-csv program.
-}
module Lsql.Csv.Core.Evaluator (evaluate) where

import Lsql.Csv.Core.BlockOps
import Lsql.Csv.Core.Symbols
import Lsql.Csv.Core.Functions
import Lsql.Csv.Core.Tables

import Data.List



-- | Evaluates the program in parsed [`Block`] over the input in `SymbolMap`.
evaluate :: SymbolMap -> [Block] -> [Printable]
evaluate :: SymbolMap -> [Block] -> [Printable]
evaluate SymbolMap
symbol_map [Block]
blocks =
  Table -> [Printable]
printTable Table
sorted

  where 
    selects :: [Arg]
    selects :: [Arg]
selects = [[Arg]] -> [Arg]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Arg]] -> [Arg]) -> [[Arg]] -> [Arg]
forall a b. (a -> b) -> a -> b
$ [Block] -> [[Arg]]
getSelects [Block]
blocks

    cond :: Arg
    cond :: Arg
cond = [Block] -> Arg
getIf [Block]
blocks
  
    cross_table :: Table
    cross_table :: Table
cross_table = (Table -> Table -> Table) -> [Table] -> Table
forall a. (a -> a -> a) -> [a] -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 Table -> Table -> Table
crossJoinTable([Table] -> Table) -> [Table] -> Table
forall a b. (a -> b) -> a -> b
$ SymbolMap -> [Table]
getTables SymbolMap
symbol_map

    cross_symbol_map :: SymbolMap
    cross_symbol_map :: SymbolMap
cross_symbol_map = [Table] -> SymbolMap
getSymbolMap [Table
cross_table]

    filtered_table :: Table
    filtered_table :: Table
filtered_table = Printable -> Table
doFilter(Printable -> Table) -> Printable -> Table
forall a b. (a -> b) -> a -> b
$ SymbolMap -> Arg -> Printable
eval SymbolMap
cross_symbol_map Arg
cond
      where
        
        doFilter :: Printable -> Table
        doFilter :: Printable -> Table
doFilter (ValueP Value
val) 
          | Value -> Bool
forall a. Boolable a => a -> Bool
getBool Value
val = Table
cross_table 
          | Bool
otherwise = Table -> Table
emptyTable Table
cross_table

        doFilter (ColumnP Column
col) = Column -> Table -> Table
filterTable Column
col Table
cross_table


    filtered_symbol_map :: SymbolMap
filtered_symbol_map = [Table] -> SymbolMap
getSymbolMap [Table
filtered_table]

    
    aggregated_tables :: [Table]
    aggregated_tables :: [Table]
aggregated_tables
      | [Arg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Arg]
by_stmt = [Table
filtered_table]
      | Bool
otherwise = [Column] -> Table -> [Table]
byTable ([Printable] -> [Column]
by_col([Printable] -> [Column]) -> [Printable] -> [Column]
forall a b. (a -> b) -> a -> b
$ (Arg -> Printable) -> [Arg] -> [Printable]
forall a b. (a -> b) -> [a] -> [b]
map (SymbolMap -> Arg -> Printable
eval SymbolMap
filtered_symbol_map) [Arg]
by_stmt) 
          Table
filtered_table
    
      where
        by_stmt :: [Arg]
        by_stmt :: [Arg]
by_stmt = [Block] -> [Arg]
getBy [Block]
blocks

        by_printable :: [Printable]
        by_printable :: [Printable]
by_printable = (Arg -> Printable) -> [Arg] -> [Printable]
forall a b. (a -> b) -> [a] -> [b]
map (SymbolMap -> Arg -> Printable
eval SymbolMap
filtered_symbol_map) [Arg]
by_stmt

        by_col :: [Printable] -> [Column]
        by_col :: [Printable] -> [Column]
by_col [] = []
        by_col ((ColumnP Column
col) : [Printable]
rest) = Column
col Column -> [Column] -> [Column]
forall a. a -> [a] -> [a]
: ([Printable] -> [Column]
by_col [Printable]
rest)
        by_col (Printable
_ : [Printable]
rest) = [Printable] -> [Column]
by_col [Printable]
rest

     
    aggregated :: Bool
    aggregated :: Bool
aggregated 
      | [Arg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Arg]
selects = Bool
False
      | Bool
otherwise = (Bool -> Bool -> Bool) -> [Bool] -> Bool
forall a. (a -> a -> a) -> [a] -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 Bool -> Bool -> Bool
(||)([Bool] -> Bool) -> [Bool] -> Bool
forall a b. (a -> b) -> a -> b
$ (Arg -> Bool) -> [Arg] -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
map Arg -> Bool
containsAggregateF [Arg]
selects

    sort_by :: [Arg]
    sort_by :: [Arg]
sort_by = [Block] -> [Arg]
getSort [Block]
blocks

    post_aggregated :: ([Column], Table)
    post_aggregated :: ([Column], Table)
post_aggregated
     | Bool -> Bool
not Bool
aggregated = 
         let evaluator :: [Arg] -> [Printable]
evaluator = (Arg -> Printable) -> [Arg] -> [Printable]
forall a b. (a -> b) -> [a] -> [b]
map (SymbolMap -> Arg -> Printable
eval SymbolMap
filtered_symbol_map) in
         (([Printable] -> [Column]
getCols([Printable] -> [Column]) -> [Printable] -> [Column]
forall a b. (a -> b) -> a -> b
$ [Arg] -> [Printable]
evaluator [Arg]
sort_by), ([String] -> [Printable] -> Table
getTable []([Printable] -> Table) -> [Printable] -> Table
forall a b. (a -> b) -> a -> b
$ [Arg] -> [Printable]
evaluator [Arg]
selects))

     | Bool
otherwise = 
        let evaluator :: [Arg] -> [Printable]
evaluator [Arg]
x = ([[Printable]] -> [Printable]
unionAggCols([[Printable]] -> [Printable]) -> [[Printable]] -> [Printable]
forall a b. (a -> b) -> a -> b
$ (Table -> [Printable]) -> [Table] -> [[Printable]]
forall a b. (a -> b) -> [a] -> [b]
map ([Arg] -> Table -> [Printable]
aggEval [Arg]
x) [Table]
aggregated_tables) in
        (([Printable] -> [Column]
getCols([Printable] -> [Column]) -> [Printable] -> [Column]
forall a b. (a -> b) -> a -> b
$ [Arg] -> [Printable]
evaluator [Arg]
sort_by), ([String] -> [Printable] -> Table
getTable []([Printable] -> Table) -> [Printable] -> Table
forall a b. (a -> b) -> a -> b
$ [Arg] -> [Printable]
evaluator [Arg]
selects))

     where
       aggEval :: [Arg] -> Table -> [Printable]
       aggEval :: [Arg] -> Table -> [Printable]
aggEval [Arg]
to_eval Table
table =
         let symbols :: SymbolMap
symbols = [Table] -> SymbolMap
getSymbolMap [Table
table] in
         (Arg -> Printable) -> [Arg] -> [Printable]
forall a b. (a -> b) -> [a] -> [b]
map (SymbolMap -> Arg -> Printable
eval SymbolMap
symbols)([Arg] -> [Printable]) -> [Arg] -> [Printable]
forall a b. (a -> b) -> a -> b
$ (Arg -> Arg) -> [Arg] -> [Arg]
forall a b. (a -> b) -> [a] -> [b]
map (SymbolMap -> Arg -> Arg
evalAggregateFunctions SymbolMap
symbols) [Arg]
to_eval

    sorted :: Table
    sorted :: Table
sorted = [Column] -> Table -> Table
sortTable (([Column], Table) -> [Column]
forall a b. (a, b) -> a
fst ([Column], Table)
post_aggregated) (([Column], Table) -> Table
forall a b. (a, b) -> b
snd ([Column], Table)
post_aggregated)