{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

-- |
-- Module      : Database.Relational.Monad.Simple
-- Copyright   : 2013-2017 Kei Hibino
-- License     : BSD3
--
-- Maintainer  : ex8k.hibino@gmail.com
-- Stability   : experimental
-- Portability : unknown
--
-- This module contains definitions about simple (not-aggregated) query type.
module Database.Relational.Monad.Simple (
  -- * Simple query
  QuerySimple, SimpleQuery,

  simple,

  toSQL,
  toSubQuery,
  ) where

import Database.Relational.Internal.ContextType (Flat)
import Database.Relational.SqlSyntax
  (Duplication, OrderingTerm, JoinProduct, Predicate,  Record,
   SubQuery, flatSubQuery, )
import qualified Database.Relational.SqlSyntax as Syntax

import qualified Database.Relational.Record as Record
import Database.Relational.Monad.Trans.Join (join')
import Database.Relational.Monad.Trans.Restricting (restrictings)
import Database.Relational.Monad.Trans.Ordering
  (Orderings, orderings, extractOrderingTerms)
import Database.Relational.Monad.BaseType (ConfigureQuery, askConfig)
import Database.Relational.Monad.Type (QueryCore, extractCore, OrderedQuery)
import Database.Relational.Projectable (PlaceHolders)


-- | Simple (not-aggregated) query monad type.
type QuerySimple = Orderings Flat QueryCore

-- | Simple (not-aggregated) query type. 'SimpleQuery'' p r == 'QuerySimple' ('PlaceHolders' p, 'Record' r).
type SimpleQuery p r = OrderedQuery Flat QueryCore p r

-- | Lift from qualified table forms into 'QuerySimple'.
simple :: ConfigureQuery a -> QuerySimple a
simple :: forall a. ConfigureQuery a -> QuerySimple a
simple =  forall (m :: * -> *) a c. Monad m => m a -> Orderings c m a
orderings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a c. Monad m => m a -> Restrictings c m a
restrictings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => m a -> QueryJoin m a
join'

extract :: SimpleQuery p r
        -> ConfigureQuery (((((PlaceHolders p, Record Flat r), [OrderingTerm]), [Predicate Flat]),
                           JoinProduct), Duplication)
extract :: forall p r.
SimpleQuery p r
-> ConfigureQuery
     (((((PlaceHolders p, Record Flat r), [OrderingTerm]),
        [Predicate Flat]),
       JoinProduct),
      Duplication)
extract =  forall a.
QueryCore a
-> ConfigureQuery
     (((a, [Predicate Flat]), JoinProduct), Duplication)
extractCore forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) c a.
(Monad m, Functor m) =>
Orderings c m a -> m (a, [OrderingTerm])
extractOrderingTerms

-- | Run 'SimpleQuery' to get SQL string with 'Qualify' computation.
toSQL :: SimpleQuery p r         -- ^ 'SimpleQuery' to run
      -> ConfigureQuery String -- ^ Result SQL string with 'Qualify' computation
toSQL :: forall p r. SimpleQuery p r -> ConfigureQuery String
toSQL =  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SubQuery -> String
Syntax.toSQL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall p r. SimpleQuery p r -> ConfigureQuery SubQuery
toSubQuery

-- | Run 'SimpleQuery' to get 'SubQuery' with 'Qualify' computation.
toSubQuery :: SimpleQuery p r        -- ^ 'SimpleQuery'' to run
           -> ConfigureQuery SubQuery -- ^ Result 'SubQuery' with 'Qualify' computation
toSubQuery :: forall p r. SimpleQuery p r -> ConfigureQuery SubQuery
toSubQuery SimpleQuery p r
q = do
   (((((PlaceHolders p
_ph, Record Flat r
pj), [OrderingTerm]
ot), [Predicate Flat]
rs), JoinProduct
pd), Duplication
da) <- forall p r.
SimpleQuery p r
-> ConfigureQuery
     (((((PlaceHolders p, Record Flat r), [OrderingTerm]),
        [Predicate Flat]),
       JoinProduct),
      Duplication)
extract SimpleQuery p r
q
   Config
c <- ConfigureQuery Config
askConfig
   forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Config
-> Tuple
-> Duplication
-> JoinProduct
-> [Predicate Flat]
-> [OrderingTerm]
-> SubQuery
flatSubQuery Config
c (forall c r. Record c r -> Tuple
Record.untype Record Flat r
pj) Duplication
da JoinProduct
pd [Predicate Flat]
rs [OrderingTerm]
ot