module Opaleye.SQLite.Internal.Optimize where

import           Prelude hiding (product)

import qualified Opaleye.SQLite.Internal.PrimQuery as PQ

import qualified Data.List.NonEmpty as NEL

optimize :: PQ.PrimQuery -> PQ.PrimQuery
optimize :: PrimQuery -> PrimQuery
optimize = PrimQuery -> PrimQuery
mergeProduct (PrimQuery -> PrimQuery)
-> (PrimQuery -> PrimQuery) -> PrimQuery -> PrimQuery
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrimQuery -> PrimQuery
removeUnit

removeUnit :: PQ.PrimQuery -> PQ.PrimQuery
removeUnit :: PrimQuery -> PrimQuery
removeUnit = PrimQueryFold PrimQuery -> PrimQuery -> PrimQuery
forall p. PrimQueryFold p -> PrimQuery -> p
PQ.foldPrimQuery (PrimQuery
PQ.Unit, String -> [(Symbol, PrimExpr)] -> PrimQuery
PQ.BaseTable, NonEmpty PrimQuery -> [PrimExpr] -> PrimQuery
product, [(Symbol, (Maybe AggrOp, PrimExpr))] -> PrimQuery -> PrimQuery
PQ.Aggregate,
                                [OrderExpr] -> PrimQuery -> PrimQuery
PQ.Order, LimitOp -> PrimQuery -> PrimQuery
PQ.Limit, JoinType -> PrimExpr -> PrimQuery -> PrimQuery -> PrimQuery
PQ.Join, [Symbol] -> [[PrimExpr]] -> PrimQuery
PQ.Values,
                                BinOp
-> [(Symbol, (PrimExpr, PrimExpr))]
-> (PrimQuery, PrimQuery)
-> PrimQuery
PQ.Binary)
  where product :: NonEmpty PrimQuery -> [PrimExpr] -> PrimQuery
product NonEmpty PrimQuery
pqs [PrimExpr]
pes = NonEmpty PrimQuery -> [PrimExpr] -> PrimQuery
PQ.Product NonEmpty PrimQuery
pqs' [PrimExpr]
pes
          where pqs' :: NonEmpty PrimQuery
pqs' = case (PrimQuery -> Bool) -> NonEmpty PrimQuery -> [PrimQuery]
forall a. (a -> Bool) -> NonEmpty a -> [a]
NEL.filter (Bool -> Bool
not (Bool -> Bool) -> (PrimQuery -> Bool) -> PrimQuery -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrimQuery -> Bool
PQ.isUnit) NonEmpty PrimQuery
pqs of
                         [] -> PrimQuery -> NonEmpty PrimQuery
forall (m :: * -> *) a. Monad m => a -> m a
return PrimQuery
PQ.Unit
                         [PrimQuery]
xs -> [PrimQuery] -> NonEmpty PrimQuery
forall a. [a] -> NonEmpty a
NEL.fromList [PrimQuery]
xs

mergeProduct :: PQ.PrimQuery -> PQ.PrimQuery
mergeProduct :: PrimQuery -> PrimQuery
mergeProduct = PrimQueryFold PrimQuery -> PrimQuery -> PrimQuery
forall p. PrimQueryFold p -> PrimQuery -> p
PQ.foldPrimQuery (PrimQuery
PQ.Unit, String -> [(Symbol, PrimExpr)] -> PrimQuery
PQ.BaseTable, NonEmpty PrimQuery -> [PrimExpr] -> PrimQuery
product, [(Symbol, (Maybe AggrOp, PrimExpr))] -> PrimQuery -> PrimQuery
PQ.Aggregate,
                                [OrderExpr] -> PrimQuery -> PrimQuery
PQ.Order, LimitOp -> PrimQuery -> PrimQuery
PQ.Limit, JoinType -> PrimExpr -> PrimQuery -> PrimQuery -> PrimQuery
PQ.Join, [Symbol] -> [[PrimExpr]] -> PrimQuery
PQ.Values,
                                BinOp
-> [(Symbol, (PrimExpr, PrimExpr))]
-> (PrimQuery, PrimQuery)
-> PrimQuery
PQ.Binary)
  where product :: NonEmpty PrimQuery -> [PrimExpr] -> PrimQuery
product NonEmpty PrimQuery
pqs [PrimExpr]
pes = NonEmpty PrimQuery -> [PrimExpr] -> PrimQuery
PQ.Product NonEmpty PrimQuery
pqs' ([PrimExpr]
pes [PrimExpr] -> [PrimExpr] -> [PrimExpr]
forall a. [a] -> [a] -> [a]
++ [PrimExpr]
pes')
          where pqs' :: NonEmpty PrimQuery
pqs' = NonEmpty PrimQuery
pqs NonEmpty PrimQuery
-> (PrimQuery -> NonEmpty PrimQuery) -> NonEmpty PrimQuery
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= PrimQuery -> NonEmpty PrimQuery
queries
                queries :: PrimQuery -> NonEmpty PrimQuery
queries (PQ.Product NonEmpty PrimQuery
qs [PrimExpr]
_) = NonEmpty PrimQuery
qs
                queries PrimQuery
q = PrimQuery -> NonEmpty PrimQuery
forall (m :: * -> *) a. Monad m => a -> m a
return PrimQuery
q
                pes' :: [PrimExpr]
pes' = NonEmpty PrimQuery -> [PrimQuery]
forall a. NonEmpty a -> [a]
NEL.toList NonEmpty PrimQuery
pqs [PrimQuery] -> (PrimQuery -> [PrimExpr]) -> [PrimExpr]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= PrimQuery -> [PrimExpr]
conds
                conds :: PrimQuery -> [PrimExpr]
conds (PQ.Product NonEmpty PrimQuery
_ [PrimExpr]
cs) = [PrimExpr]
cs
                conds PrimQuery
_ = []