{-# 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 :: ConfigureQuery a -> QuerySimple a
simple =  Restrictings Flat (QueryJoin ConfigureQuery) a -> QuerySimple a
forall (m :: * -> *) a c. Monad m => m a -> Orderings c m a
orderings (Restrictings Flat (QueryJoin ConfigureQuery) a -> QuerySimple a)
-> (ConfigureQuery a
    -> Restrictings Flat (QueryJoin ConfigureQuery) a)
-> ConfigureQuery a
-> QuerySimple a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QueryJoin ConfigureQuery a
-> Restrictings Flat (QueryJoin ConfigureQuery) a
forall (m :: * -> *) a c. Monad m => m a -> Restrictings c m a
restrictings (QueryJoin ConfigureQuery a
 -> Restrictings Flat (QueryJoin ConfigureQuery) a)
-> (ConfigureQuery a -> QueryJoin ConfigureQuery a)
-> ConfigureQuery a
-> Restrictings Flat (QueryJoin ConfigureQuery) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConfigureQuery a -> QueryJoin ConfigureQuery a
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 :: SimpleQuery p r
-> ConfigureQuery
     (((((PlaceHolders p, Record Flat r), [OrderingTerm]),
        [Predicate Flat]),
       JoinProduct),
      Duplication)
extract =  QueryCore ((PlaceHolders p, Record Flat r), [OrderingTerm])
-> ConfigureQuery
     (((((PlaceHolders p, Record Flat r), [OrderingTerm]),
        [Predicate Flat]),
       JoinProduct),
      Duplication)
forall a.
QueryCore a
-> ConfigureQuery
     (((a, [Predicate Flat]), JoinProduct), Duplication)
extractCore (QueryCore ((PlaceHolders p, Record Flat r), [OrderingTerm])
 -> ConfigureQuery
      (((((PlaceHolders p, Record Flat r), [OrderingTerm]),
         [Predicate Flat]),
        JoinProduct),
       Duplication))
-> (SimpleQuery p r
    -> QueryCore ((PlaceHolders p, Record Flat r), [OrderingTerm]))
-> SimpleQuery p r
-> ConfigureQuery
     (((((PlaceHolders p, Record Flat r), [OrderingTerm]),
        [Predicate Flat]),
       JoinProduct),
      Duplication)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SimpleQuery p r
-> QueryCore ((PlaceHolders p, Record Flat r), [OrderingTerm])
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 :: SimpleQuery p r -> ConfigureQuery String
toSQL =  (SubQuery -> String)
-> Qualify (QueryConfig Identity) SubQuery -> ConfigureQuery String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SubQuery -> String
Syntax.toSQL (Qualify (QueryConfig Identity) SubQuery -> ConfigureQuery String)
-> (SimpleQuery p r -> Qualify (QueryConfig Identity) SubQuery)
-> SimpleQuery p r
-> ConfigureQuery String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SimpleQuery p r -> Qualify (QueryConfig Identity) SubQuery
forall p r.
SimpleQuery p r -> Qualify (QueryConfig Identity) 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 :: SimpleQuery p r -> Qualify (QueryConfig Identity) SubQuery
toSubQuery SimpleQuery p r
q = do
   (((((PlaceHolders p
_ph, Record Flat r
pj), [OrderingTerm]
ot), [Predicate Flat]
rs), JoinProduct
pd), Duplication
da) <- SimpleQuery p r
-> ConfigureQuery
     (((((PlaceHolders p, Record Flat r), [OrderingTerm]),
        [Predicate Flat]),
       JoinProduct),
      Duplication)
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
   SubQuery -> Qualify (QueryConfig Identity) SubQuery
forall (m :: * -> *) a. Monad m => a -> m a
return (SubQuery -> Qualify (QueryConfig Identity) SubQuery)
-> SubQuery -> Qualify (QueryConfig Identity) SubQuery
forall a b. (a -> b) -> a -> b
$ Config
-> Tuple
-> Duplication
-> JoinProduct
-> [Predicate Flat]
-> [OrderingTerm]
-> SubQuery
flatSubQuery Config
c (Record Flat r -> Tuple
forall c r. Record c r -> Tuple
Record.untype Record Flat r
pj) Duplication
da JoinProduct
pd [Predicate Flat]
rs [OrderingTerm]
ot