{-# LANGUAGE FlexibleContexts #-}

module Opaleye.Values(
  values,
  -- * Explicit versions
  valuesExplicit,
  -- * Adaptors
  V.Valuesspec,
  V.valuesspecField,
  -- * Deprecated versions
  valuesSafe,
  valuesSafeExplicit,
  valuesUnsafe,
  valuesUnsafeExplicit,
  V.ValuesspecSafe,
  ) where

import qualified Opaleye.Internal.QueryArr as Q
import qualified Opaleye.Internal.Tag as Tag
import qualified Opaleye.Internal.Values as V
import qualified Opaleye.Internal.Unpackspec as U
import qualified Opaleye.Select              as S

import qualified Data.List.NonEmpty as NEL
import           Data.Profunctor.Product.Default (Default, def)

{-# DEPRECATED valuesUnsafe "Use 'values' instead.  Will be removed in 0.10." #-}
valuesUnsafe :: (Default V.ValuesspecUnsafe fields fields,
                 Default U.Unpackspec fields fields) =>
                [fields] -> S.Select fields
valuesUnsafe :: forall fields.
(Default ValuesspecUnsafe fields fields,
 Default Unpackspec fields fields) =>
[fields] -> Select fields
valuesUnsafe = forall fields fields'.
Unpackspec fields fields'
-> ValuesspecUnsafe fields fields' -> [fields] -> Select fields'
valuesUnsafeExplicit forall (p :: * -> * -> *) a b. Default p a b => p a b
def forall (p :: * -> * -> *) a b. Default p a b => p a b
def

{-# DEPRECATED valuesUnsafeExplicit "Use 'values' instead.  Will be removed in 0.10." #-}
valuesUnsafeExplicit :: U.Unpackspec fields fields'
                     -> V.ValuesspecUnsafe fields fields'
                     -> [fields] -> S.Select fields'
valuesUnsafeExplicit :: forall fields fields'.
Unpackspec fields fields'
-> ValuesspecUnsafe fields fields' -> [fields] -> Select fields'
valuesUnsafeExplicit Unpackspec fields fields'
unpack ValuesspecUnsafe fields fields'
valuesspec [fields]
fields =
  forall a. State Tag (a, PrimQuery) -> Query a
Q.productQueryArr forall a b. (a -> b) -> a -> b
$ do
  Tag
t <- State Tag Tag
Tag.fresh
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall columns columns'.
Unpackspec columns columns'
-> ValuesspecUnsafe columns columns'
-> [columns]
-> ((), Tag)
-> (columns', PrimQuery)
V.valuesU Unpackspec fields fields'
unpack ValuesspecUnsafe fields fields'
valuesspec [fields]
fields ((), Tag
t))

-- | 'values' implements Postgres's @VALUES@ construct and allows you
-- to create a @SELECT@ that consists of the given rows.
--
-- Example type specialization:
--
-- @
-- values :: [(Field a, Field b)] -> Select (Field a, Field b)
-- @
--
-- Assuming the @makeAdaptorAndInstance@ splice has been run for the
-- product type @Foo@:
--
-- @
-- values :: [Foo (Field a) (Field b) (Field c)] -> S.Select (Foo (Field a) (Field b) (Field c))
-- @
values :: Default V.Valuesspec fields fields
       => [fields] -> S.Select fields
values :: forall fields.
Default Valuesspec fields fields =>
[fields] -> Select fields
values = forall fields fields'.
Valuesspec fields fields' -> [fields] -> Select fields'
valuesExplicit forall (p :: * -> * -> *) a b. Default p a b => p a b
def

valuesExplicit :: V.Valuesspec fields fields'
               -> [fields] -> S.Select fields'
valuesExplicit :: forall fields fields'.
Valuesspec fields fields' -> [fields] -> Select fields'
valuesExplicit (V.ValuesspecSafe Nullspec fields fields'
nullspec Rowspec fields fields'
rowspec) [fields]
fields = case forall a. [a] -> Maybe (NonEmpty a)
NEL.nonEmpty [fields]
fields of
  Maybe (NonEmpty fields)
Nothing -> forall columns a. Nullspec columns a -> Select a
V.emptySelectExplicit Nullspec fields fields'
nullspec
  Just NonEmpty fields
rows -> forall columns columns'.
Rowspec columns columns' -> NonEmpty columns -> Select columns'
V.nonEmptyValues Rowspec fields fields'
rowspec NonEmpty fields
rows

{-# DEPRECATED valuesSafe "Use 'values' instead.  Will be removed in 0.10." #-}
valuesSafe :: Default V.Valuesspec fields fields
           => [fields] -> S.Select fields
valuesSafe :: forall fields.
Default Valuesspec fields fields =>
[fields] -> Select fields
valuesSafe = forall fields.
Default Valuesspec fields fields =>
[fields] -> Select fields
values

{-# DEPRECATED valuesSafeExplicit "Use 'values' instead.  Will be removed in 0.10." #-}
valuesSafeExplicit :: V.Valuesspec fields fields'
                   -> [fields] -> S.Select fields'
valuesSafeExplicit :: forall fields fields'.
Valuesspec fields fields' -> [fields] -> Select fields'
valuesSafeExplicit = forall fields fields'.
Valuesspec fields fields' -> [fields] -> Select fields'
valuesExplicit