{-# OPTIONS_GHC -fno-warn-orphans #-}

-- | Convert the simple AST to an SQL query, ready to be passed
-- to the mysql package's query/exec functions.
module Hasura.Backends.MySQL.ToQuery
  ( Printer,
    toQueryPretty,
    fromSelect,
    toQueryFlat,
    Query (..),
    renderBuilderPretty,
    runBuilderPretty,
  )
where

import Data.ByteString (ByteString)
import Data.HashMap.Strict.InsOrd qualified as OMap
import Data.List (intersperse)
import Data.String
import Data.Text qualified as T
import Data.Text.Encoding qualified as T
import Data.Text.Lazy.Builder qualified as LT
import Data.Tuple (swap)
import Hasura.Backends.MySQL.Types
import Hasura.Prelude hiding (GT, LT)

newtype Query = Query {Query -> ByteString
unQuery :: ByteString} deriving (Int -> Query -> ShowS
[Query] -> ShowS
Query -> String
(Int -> Query -> ShowS)
-> (Query -> String) -> ([Query] -> ShowS) -> Show Query
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Query] -> ShowS
$cshowList :: [Query] -> ShowS
show :: Query -> String
$cshow :: Query -> String
showsPrec :: Int -> Query -> ShowS
$cshowsPrec :: Int -> Query -> ShowS
Show, Query -> Query -> Bool
(Query -> Query -> Bool) -> (Query -> Query -> Bool) -> Eq Query
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Query -> Query -> Bool
$c/= :: Query -> Query -> Bool
== :: Query -> Query -> Bool
$c== :: Query -> Query -> Bool
Eq, Semigroup Query
Query
Semigroup Query
-> Query
-> (Query -> Query -> Query)
-> ([Query] -> Query)
-> Monoid Query
[Query] -> Query
Query -> Query -> Query
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [Query] -> Query
$cmconcat :: [Query] -> Query
mappend :: Query -> Query -> Query
$cmappend :: Query -> Query -> Query
mempty :: Query
$cmempty :: Query
$cp1Monoid :: Semigroup Query
Monoid, b -> Query -> Query
NonEmpty Query -> Query
Query -> Query -> Query
(Query -> Query -> Query)
-> (NonEmpty Query -> Query)
-> (forall b. Integral b => b -> Query -> Query)
-> Semigroup Query
forall b. Integral b => b -> Query -> Query
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: b -> Query -> Query
$cstimes :: forall b. Integral b => b -> Query -> Query
sconcat :: NonEmpty Query -> Query
$csconcat :: NonEmpty Query -> Query
<> :: Query -> Query -> Query
$c<> :: Query -> Query -> Query
Semigroup)

data Printer
  = SeqPrinter [Printer]
  | SepByPrinter Printer [Printer]
  | NewlinePrinter
  | QueryPrinter Query
  | IndentPrinter Int Printer
  deriving (Int -> Printer -> ShowS
[Printer] -> ShowS
Printer -> String
(Int -> Printer -> ShowS)
-> (Printer -> String) -> ([Printer] -> ShowS) -> Show Printer
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Printer] -> ShowS
$cshowList :: [Printer] -> ShowS
show :: Printer -> String
$cshow :: Printer -> String
showsPrec :: Int -> Printer -> ShowS
$cshowsPrec :: Int -> Printer -> ShowS
Show, Printer -> Printer -> Bool
(Printer -> Printer -> Bool)
-> (Printer -> Printer -> Bool) -> Eq Printer
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Printer -> Printer -> Bool
$c/= :: Printer -> Printer -> Bool
== :: Printer -> Printer -> Bool
$c== :: Printer -> Printer -> Bool
Eq)

instance IsString Printer where
  fromString :: String -> Printer
fromString = Query -> Printer
QueryPrinter (Query -> Printer) -> (String -> Query) -> String -> Printer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Query
Query (ByteString -> Query) -> (String -> ByteString) -> String -> Query
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
forall a. IsString a => String -> a
fromString

(<+>) :: Printer -> Printer -> Printer
<+> :: Printer -> Printer -> Printer
(<+>) Printer
x Printer
y = [Printer] -> Printer
SeqPrinter [Printer
x, Printer
y]

-- Printer generators

fromExpression :: Expression -> Printer
fromExpression :: Expression -> Printer
fromExpression =
  \case
    ValueExpression ScalarValue
value -> Query -> Printer
QueryPrinter (ScalarValue -> Query
fromScalarType ScalarValue
value)
    AndExpression [Expression]
xs ->
      case [Expression]
xs of
        [] -> Printer
truePrinter
        [Expression]
_ ->
          Printer -> [Printer] -> Printer
SepByPrinter
            (Printer
NewlinePrinter Printer -> Printer -> Printer
<+> Printer
"AND ")
            ((Expression -> Printer) -> [Expression] -> [Printer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Expression
x -> Printer
"(" Printer -> Printer -> Printer
<+> Expression -> Printer
fromExpression Expression
x Printer -> Printer -> Printer
<+> Printer
")") ([Expression] -> [Expression]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList [Expression]
xs))
    OrExpression [Expression]
xs ->
      case [Expression]
xs of
        [] -> Printer
falsePrinter
        [Expression]
_ ->
          Printer -> [Printer] -> Printer
SepByPrinter
            (Printer
NewlinePrinter Printer -> Printer -> Printer
<+> Printer
"OR ")
            ((Expression -> Printer) -> [Expression] -> [Printer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Expression
x -> Printer
"(" Printer -> Printer -> Printer
<+> Expression -> Printer
fromExpression Expression
x Printer -> Printer -> Printer
<+> Printer
")") ([Expression] -> [Expression]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList [Expression]
xs))
    NotExpression Expression
expression -> Printer
"NOT " Printer -> Printer -> Printer
<+> Expression -> Printer
fromExpression Expression
expression
    ExistsExpression Select
sel -> Printer
"EXISTS (" Printer -> Printer -> Printer
<+> Select -> Printer
fromSelect Select
sel Printer -> Printer -> Printer
<+> Printer
")"
    InExpression Expression
x [Expression]
xs ->
      Expression -> Printer
fromExpression Expression
x Printer -> Printer -> Printer
<+> Printer
" IN " Printer -> Printer -> Printer
<+> [Printer] -> Printer
SeqPrinter ((Expression -> Printer) -> [Expression] -> [Printer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Expression -> Printer
fromExpression [Expression]
xs)
    ColumnExpression FieldName
fieldName -> FieldName -> Printer
fromFieldName FieldName
fieldName
    MethodExpression Expression
field Text
method [Expression]
args ->
      Expression -> Printer
fromExpression Expression
field Printer -> Printer -> Printer
<+> Printer
"."
        Printer -> Printer -> Printer
<+> String -> Printer
forall a. IsString a => String -> a
fromString (Text -> String
T.unpack Text
method)
        Printer -> Printer -> Printer
<+> Printer
"("
        Printer -> Printer -> Printer
<+> [Printer] -> Printer
SeqPrinter ((Expression -> Printer) -> [Expression] -> [Printer]
forall a b. (a -> b) -> [a] -> [b]
map Expression -> Printer
fromExpression [Expression]
args)
        Printer -> Printer -> Printer
<+> Printer
")"
    OpExpression Op
op Expression
x Expression
y ->
      Printer
"("
        Printer -> Printer -> Printer
<+> Expression -> Printer
fromExpression Expression
x
        Printer -> Printer -> Printer
<+> Printer
") "
        Printer -> Printer -> Printer
<+> Op -> Printer
fromOp Op
op
        Printer -> Printer -> Printer
<+> Printer
" ("
        Printer -> Printer -> Printer
<+> Expression -> Printer
fromExpression Expression
y
        Printer -> Printer -> Printer
<+> Printer
")"

fromScalarType :: ScalarValue -> Query
fromScalarType :: ScalarValue -> Query
fromScalarType = \case
  BigValue Int32
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Int32 -> String
forall a. Show a => a -> String
show Int32
v
  BinaryValue ByteString
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> String
forall a. Show a => a -> String
show ByteString
v
  BitValue Bool
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Bool -> String
forall a. Show a => a -> String
show Bool
v
  BlobValue ByteString
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> String
forall a. Show a => a -> String
show ByteString
v
  CharValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  DatetimeValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  DateValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  DecimalValue Double
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Double -> String
forall a. Show a => a -> String
show Double
v
  DoubleValue Double
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Double -> String
forall a. Show a => a -> String
show Double
v
  EnumValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  FloatValue Double
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Double -> String
forall a. Show a => a -> String
show Double
v
  GeometrycollectionValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  GeometryValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  IntValue Int32
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Int32 -> String
forall a. Show a => a -> String
show Int32
v
  JsonValue Value
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Value -> String
forall a. Show a => a -> String
show Value
v
  LinestringValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  MediumValue Int32
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Int32 -> String
forall a. Show a => a -> String
show Int32
v
  MultilinestringValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  MultipointValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  MultipolygonValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  ScalarValue
NullValue -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString String
"NULL"
  NumericValue Double
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Double -> String
forall a. Show a => a -> String
show Double
v
  PointValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  PolygonValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  SmallValue Int32
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Int32 -> String
forall a. Show a => a -> String
show Int32
v
  TextValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  TimestampValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  TimeValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  TinyValue Int32
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Int32 -> String
forall a. Show a => a -> String
show Int32
v
  VarbinaryValue ByteString
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> String
forall a. Show a => a -> String
show ByteString
v
  VarcharValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  YearValue Text
v -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
v
  ScalarValue
other -> String -> Query
forall a. HasCallStack => String -> a
error (String -> Query) -> String -> Query
forall a b. (a -> b) -> a -> b
$ String
"fromscalartype: not implemented " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> ScalarValue -> String
forall a. Show a => a -> String
show ScalarValue
other

fromOp :: Op -> Printer
fromOp :: Op -> Printer
fromOp =
  \case
    Op
LT -> Printer
"<"
    Op
GT -> Printer
">"
    Op
GTE -> Printer
">="
    Op
LTE -> Printer
"<="
    Op
IN -> Printer
"IN"
    Op
NIN -> Printer
"NOT IN"
    Op
LIKE -> Printer
"LIKE"
    Op
NLIKE -> Printer
"NOT LIKE"
    Op
EQ' -> Printer
"="
    Op
NEQ' -> Printer
"!="

fromFieldName :: FieldName -> Printer
fromFieldName :: FieldName -> Printer
fromFieldName (FieldName {Text
fNameEntity :: FieldName -> Text
fName :: FieldName -> Text
fNameEntity :: Text
fName :: Text
..}) =
  Text -> Printer
fromNameText Text
fNameEntity Printer -> Printer -> Printer
<+> Printer
"." Printer -> Printer -> Printer
<+> Text -> Printer
fromNameText Text
fName

fromSelect :: Select -> Printer
fromSelect :: Select -> Printer
fromSelect Select {[Join]
[FieldName]
Maybe Int
Maybe [Text]
Maybe (NonEmpty OrderBy)
InsOrdHashSet Projection
Where
From
Top
selectFinalWantedFields :: Select -> Maybe [Text]
selectGroupBy :: Select -> [FieldName]
selectSqlTop :: Select -> Top
selectSqlOffset :: Select -> Maybe Int
selectOrderBy :: Select -> Maybe (NonEmpty OrderBy)
selectWhere :: Select -> Where
selectJoins :: Select -> [Join]
selectFrom :: Select -> From
selectProjections :: Select -> InsOrdHashSet Projection
selectFinalWantedFields :: Maybe [Text]
selectGroupBy :: [FieldName]
selectSqlTop :: Top
selectSqlOffset :: Maybe Int
selectOrderBy :: Maybe (NonEmpty OrderBy)
selectWhere :: Where
selectJoins :: [Join]
selectFrom :: From
selectProjections :: InsOrdHashSet Projection
..} =
  Printer -> [Printer] -> Printer
SepByPrinter
    Printer
NewlinePrinter
    ([Printer] -> Printer) -> [Printer] -> Printer
forall a b. (a -> b) -> a -> b
$ [ Printer
"SELECT "
          Printer -> Printer -> Printer
<+> Int -> Printer -> Printer
IndentPrinter
            Int
7
            ( Printer -> [Printer] -> Printer
SepByPrinter
                (Printer
"," Printer -> Printer -> Printer
<+> Printer
NewlinePrinter)
                ((Projection -> Printer) -> [Projection] -> [Printer]
forall a b. (a -> b) -> [a] -> [b]
map Projection -> Printer
fromProjection (InsOrdHashSet Projection -> [Projection]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList InsOrdHashSet Projection
selectProjections))
            ),
        Printer
"FROM " Printer -> Printer -> Printer
<+> Int -> Printer -> Printer
IndentPrinter Int
5 (From -> Printer
fromFrom From
selectFrom),
        Where -> Printer
fromWhere Where
selectWhere,
        Maybe (NonEmpty OrderBy) -> Printer
fromOrderBys Maybe (NonEmpty OrderBy)
selectOrderBy,
        Top -> Maybe Int -> Printer
fromOffsetAndLimit Top
selectSqlTop Maybe Int
selectSqlOffset
      ]

-- https://dev.mysql.com/doc/refman/5.7/en/select.html
fromOffsetAndLimit :: Top -> Maybe Int -> Printer
fromOffsetAndLimit :: Top -> Maybe Int -> Printer
fromOffsetAndLimit Top
NoTop Maybe Int
Nothing = Printer
""
fromOffsetAndLimit Top
NoTop (Just Int
offset) =
  [Printer] -> Printer
SeqPrinter
    [ Printer
"LIMIT " Printer -> Printer -> Printer
<+> String -> Printer
forall a. IsString a => String -> a
fromString (Int -> String
forall a. Show a => a -> String
show (Int
forall a. Bounded a => a
maxBound :: Int)),
      Int -> Printer -> Printer
IndentPrinter Int
9 (Printer -> [Printer] -> Printer
SepByPrinter Printer
NewlinePrinter [Printer
" OFFSET " Printer -> Printer -> Printer
<+> String -> Printer
forall a. IsString a => String -> a
fromString (Int -> String
forall a. Show a => a -> String
show Int
offset)])
    ]
fromOffsetAndLimit (Top Int
val) Maybe Int
Nothing = [Printer] -> Printer
SeqPrinter [Printer
"LIMIT " Printer -> Printer -> Printer
<+> String -> Printer
forall a. IsString a => String -> a
fromString (Int -> String
forall a. Show a => a -> String
show Int
val)]
fromOffsetAndLimit (Top Int
val) (Just Int
offset) =
  [Printer] -> Printer
SeqPrinter
    [ Printer
"LIMIT " Printer -> Printer -> Printer
<+> String -> Printer
forall a. IsString a => String -> a
fromString (Int -> String
forall a. Show a => a -> String
show Int
val),
      Int -> Printer -> Printer
IndentPrinter Int
9 (Printer -> [Printer] -> Printer
SepByPrinter Printer
NewlinePrinter [Printer
" OFFSET " Printer -> Printer -> Printer
<+> String -> Printer
forall a. IsString a => String -> a
fromString (Int -> String
forall a. Show a => a -> String
show Int
offset)])
    ]

fromOrderBys ::
  Maybe (NonEmpty OrderBy) -> Printer
fromOrderBys :: Maybe (NonEmpty OrderBy) -> Printer
fromOrderBys Maybe (NonEmpty OrderBy)
Nothing = Printer
""
fromOrderBys (Just NonEmpty OrderBy
orderBys) =
  [Printer] -> Printer
SeqPrinter
    [ Printer
"ORDER BY ",
      Int -> Printer -> Printer
IndentPrinter
        Int
9
        ( Printer -> [Printer] -> Printer
SepByPrinter
            Printer
NewlinePrinter
            [ Printer -> [Printer] -> Printer
SepByPrinter
                (Printer
"," Printer -> Printer -> Printer
<+> Printer
NewlinePrinter)
                ((OrderBy -> [Printer]) -> [OrderBy] -> [Printer]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap OrderBy -> [Printer]
fromOrderBy (NonEmpty OrderBy -> [OrderBy]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty OrderBy
orderBys))
            ]
        )
    ]

fromOrderBy :: OrderBy -> [Printer]
fromOrderBy :: OrderBy -> [Printer]
fromOrderBy OrderBy {Maybe ScalarType
NullsOrder
Order
FieldName
orderByType :: OrderBy -> Maybe ScalarType
orderByNullsOrder :: OrderBy -> NullsOrder
orderByOrder :: OrderBy -> Order
orderByFieldName :: OrderBy -> FieldName
orderByType :: Maybe ScalarType
orderByNullsOrder :: NullsOrder
orderByOrder :: Order
orderByFieldName :: FieldName
..} =
  [ FieldName -> NullsOrder -> Printer
fromNullsOrder FieldName
orderByFieldName NullsOrder
orderByNullsOrder,
    -- Above: This doesn't do anything when using text, ntext or image
    -- types. See below on CAST commentary.
    Printer -> Printer
forall p. p -> p
wrapNullHandling (FieldName -> Printer
fromFieldName FieldName
orderByFieldName)
      Printer -> Printer -> Printer
<+> Printer
" "
      Printer -> Printer -> Printer
<+> Order -> Printer
fromOrder Order
orderByOrder
  ]
  where
    wrapNullHandling :: p -> p
wrapNullHandling p
inner = p
inner

fromOrder :: Order -> Printer
fromOrder :: Order -> Printer
fromOrder =
  \case
    Order
Asc -> Printer
"ASC"
    Order
Desc -> Printer
"DESC"

-- Source <https://gregrs-uk.github.io/2011-02-02/mysql-order-by-with-nulls-first-or-last/>
fromNullsOrder :: FieldName -> NullsOrder -> Printer
fromNullsOrder :: FieldName -> NullsOrder -> Printer
fromNullsOrder FieldName
fieldName =
  \case
    NullsOrder
NullsAnyOrder -> Printer
""
    -- ISNULL(NULL)=1, ISNULL(_) = 0 -- therefore we need DESC to put
    -- nulls first.
    NullsOrder
NullsFirst -> Printer
"ISNULL(" Printer -> Printer -> Printer
<+> FieldName -> Printer
fromFieldName FieldName
fieldName Printer -> Printer -> Printer
<+> Printer
") DESC"
    NullsOrder
NullsLast -> Printer
"ISNULL(" Printer -> Printer -> Printer
<+> FieldName -> Printer
fromFieldName FieldName
fieldName Printer -> Printer -> Printer
<+> Printer
") ASC"

fromProjection :: Projection -> Printer
fromProjection :: Projection -> Printer
fromProjection =
  \case
    ExpressionProjection Aliased Expression
aliasedExpression ->
      Aliased Printer -> Printer
fromAliased ((Expression -> Printer) -> Aliased Expression -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Expression -> Printer
fromExpression Aliased Expression
aliasedExpression)
    FieldNameProjection Aliased FieldName
aliasedFieldName ->
      Aliased Printer -> Printer
fromAliased ((FieldName -> Printer) -> Aliased FieldName -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FieldName -> Printer
fromFieldName Aliased FieldName
aliasedFieldName)
    AggregateProjection Aliased Aggregate
aliasedAggregate ->
      Aliased Printer -> Printer
fromAliased ((Aggregate -> Printer) -> Aliased Aggregate -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Aggregate -> Printer
fromAggregate Aliased Aggregate
aliasedAggregate)
    AggregateProjections Aliased (NonEmpty (Aliased Aggregate))
aliasedAggregates ->
      Aliased Printer -> Printer
fromAliased
        ( (NonEmpty (Aliased Aggregate) -> Printer)
-> Aliased (NonEmpty (Aliased Aggregate)) -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
            ( \NonEmpty (Aliased Aggregate)
aggs ->
                Printer
"STRUCT("
                  Printer -> Printer -> Printer
<+> Int -> Printer -> Printer
IndentPrinter
                    Int
7
                    ( Printer -> [Printer] -> Printer
SepByPrinter
                        Printer
", "
                        ((Aliased Aggregate -> Printer) -> [Aliased Aggregate] -> [Printer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Aliased Printer -> Printer
fromAliased (Aliased Printer -> Printer)
-> (Aliased Aggregate -> Aliased Printer)
-> Aliased Aggregate
-> Printer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Aggregate -> Printer) -> Aliased Aggregate -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Aggregate -> Printer
fromAggregate) (NonEmpty (Aliased Aggregate) -> [Aliased Aggregate]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty (Aliased Aggregate)
aggs))
                    )
                  Printer -> Printer -> Printer
<+> Printer
")"
            )
            Aliased (NonEmpty (Aliased Aggregate))
aliasedAggregates
        )
    Projection
StarProjection -> Printer
"*"
    EntityProjection Aliased [(FieldName, FieldOrigin)]
aliasedEntity ->
      Aliased Printer -> Printer
fromAliased
        ( ([(FieldName, FieldOrigin)] -> Printer)
-> Aliased [(FieldName, FieldOrigin)] -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
            ( \([(FieldName, FieldOrigin)]
fields :: [(FieldName, FieldOrigin)]) ->
                -- Example:
                --   STRUCT(
                --     IFNULL(
                --       `aa_articles1`.`aggregate`,
                --       STRUCT(0 as count, struct(null as id) as sum)
                --     ) as aggregate
                --   ) AS `articles_aggregate`
                --
                -- The (AS `articles_aggregate`) part at the end is rendered by 'fromAliased' evaluating
                -- at the root of this branch, and not by anything below
                Printer
"STRUCT("
                  Printer -> Printer -> Printer
<+> ( Printer -> [Printer] -> Printer
SepByPrinter
                          Printer
", "
                          ( [(FieldName, FieldOrigin)]
fields
                              [(FieldName, FieldOrigin)]
-> ((FieldName, FieldOrigin) -> Printer) -> [Printer]
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(fieldName :: FieldName
fieldName@FieldName {Text
fNameEntity :: Text
fName :: Text
fNameEntity :: FieldName -> Text
fName :: FieldName -> Text
..}, FieldOrigin
fieldOrigin :: FieldOrigin) ->
                                Printer
"IFNULL(" Printer -> Printer -> Printer
<+> FieldName -> Printer
fromFieldName FieldName
fieldName Printer -> Printer -> Printer
<+> Printer
", " Printer -> Printer -> Printer
<+> FieldOrigin -> Printer
fromFieldOrigin FieldOrigin
fieldOrigin
                                  Printer -> Printer -> Printer
<+> Printer
") AS "
                                  Printer -> Printer -> Printer
<+> Text -> Printer
fromNameText Text
fName
                          )
                      )
                  Printer -> Printer -> Printer
<+> Printer
")"
            )
            Aliased [(FieldName, FieldOrigin)]
aliasedEntity
        )
    ArrayEntityProjection EntityAlias
entityAlias Aliased [FieldName]
aliasedEntity ->
      Aliased Printer -> Printer
fromAliased
        ( ([FieldName] -> Printer) -> Aliased [FieldName] -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
            ( \[FieldName]
aggs ->
                Printer
"ARRAY(SELECT AS STRUCT "
                  Printer -> Printer -> Printer
<+> Int -> Printer -> Printer
IndentPrinter
                    Int
7
                    (Printer -> [Printer] -> Printer
SepByPrinter Printer
", " ((FieldName -> Printer) -> [FieldName] -> [Printer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FieldName -> Printer
fromFieldNameNaked ([FieldName] -> [FieldName]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList [FieldName]
aggs)))
                  Printer -> Printer -> Printer
<+> Printer
" FROM "
                  Printer -> Printer -> Printer
<+> Text -> Printer
fromNameText (EntityAlias -> Text
entityAliasText EntityAlias
entityAlias)
                  Printer -> Printer -> Printer
<+> Printer
".agg)"
            )
            Aliased [FieldName]
aliasedEntity
        )
      where
        fromFieldNameNaked :: FieldName -> Printer
        fromFieldNameNaked :: FieldName -> Printer
fromFieldNameNaked (FieldName {Text
fNameEntity :: Text
fName :: Text
fNameEntity :: FieldName -> Text
fName :: FieldName -> Text
..}) =
          Text -> Printer
fromNameText Text
fName

fromAggregate :: Aggregate -> Printer
fromAggregate :: Aggregate -> Printer
fromAggregate =
  \case
    CountAggregate Countable FieldName
countable -> Printer
"COUNT(" Printer -> Printer -> Printer
<+> Countable FieldName -> Printer
fromCountable Countable FieldName
countable Printer -> Printer -> Printer
<+> Printer
")"
    OpAggregate Text
text [Expression]
args ->
      Query -> Printer
QueryPrinter (ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show Text
text)
        Printer -> Printer -> Printer
<+> Printer
"("
        Printer -> Printer -> Printer
<+> Printer -> [Printer] -> Printer
SepByPrinter Printer
", " ((Expression -> Printer) -> [Expression] -> [Printer]
forall a b. (a -> b) -> [a] -> [b]
map Expression -> Printer
fromExpression ([Expression] -> [Expression]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList [Expression]
args))
        Printer -> Printer -> Printer
<+> Printer
")"
    TextAggregate Text
text -> Expression -> Printer
fromExpression (ScalarValue -> Expression
ValueExpression (Text -> ScalarValue
TextValue Text
text))

fromCountable :: Countable FieldName -> Printer
fromCountable :: Countable FieldName -> Printer
fromCountable =
  \case
    Countable FieldName
StarCountable -> Printer
"*"
    NonNullFieldCountable NonEmpty FieldName
fields ->
      Printer -> [Printer] -> Printer
SepByPrinter Printer
", " ((FieldName -> Printer) -> [FieldName] -> [Printer]
forall a b. (a -> b) -> [a] -> [b]
map FieldName -> Printer
fromFieldName (NonEmpty FieldName -> [FieldName]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty FieldName
fields))
    DistinctCountable NonEmpty FieldName
fields ->
      Printer
"DISTINCT "
        Printer -> Printer -> Printer
<+> Printer -> [Printer] -> Printer
SepByPrinter Printer
", " ((FieldName -> Printer) -> [FieldName] -> [Printer]
forall a b. (a -> b) -> [a] -> [b]
map FieldName -> Printer
fromFieldName (NonEmpty FieldName -> [FieldName]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty FieldName
fields))

fromWhere :: Where -> Printer
fromWhere :: Where -> Printer
fromWhere =
  \case
    Where [] -> Printer
""
    Where [Expression]
expressions ->
      Printer
"WHERE "
        Printer -> Printer -> Printer
<+> Int -> Printer -> Printer
IndentPrinter Int
6 (Expression -> Printer
fromExpression ([Expression] -> Expression
AndExpression [Expression]
expressions))

fromFrom :: From -> Printer
fromFrom :: From -> Printer
fromFrom =
  \case
    FromQualifiedTable Aliased TableName
aliasedQualifiedTableName ->
      Aliased Printer -> Printer
fromAliased ((TableName -> Printer) -> Aliased TableName -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TableName -> Printer
fromTableName Aliased TableName
aliasedQualifiedTableName)
    FromSelect Aliased Select
select -> Aliased Printer -> Printer
fromAliased ((Select -> Printer) -> Aliased Select -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Printer -> Printer
parens (Printer -> Printer) -> (Select -> Printer) -> Select -> Printer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Select -> Printer
fromSelect) Aliased Select
select)

parens :: Printer -> Printer
parens :: Printer -> Printer
parens Printer
x = Printer
"(" Printer -> Printer -> Printer
<+> Int -> Printer -> Printer
IndentPrinter Int
1 Printer
x Printer -> Printer -> Printer
<+> Printer
")"

fromTableName :: TableName -> Printer
fromTableName :: TableName -> Printer
fromTableName TableName {Text
name :: TableName -> Text
name :: Text
name, Maybe Text
schema :: TableName -> Maybe Text
schema :: Maybe Text
schema} =
  Printer -> (Text -> Printer) -> Maybe Text -> Printer
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Printer
"" ((Printer -> Printer -> Printer
<+> Printer
".") (Printer -> Printer) -> (Text -> Printer) -> Text -> Printer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Printer
fromNameText) Maybe Text
schema Printer -> Printer -> Printer
<+> Text -> Printer
fromNameText Text
name

fromAliased :: Aliased Printer -> Printer
fromAliased :: Aliased Printer -> Printer
fromAliased Aliased {Text
Printer
aliasedAlias :: forall a. Aliased a -> Text
aliasedThing :: forall a. Aliased a -> a
aliasedAlias :: Text
aliasedThing :: Printer
..} =
  Printer
aliasedThing
    Printer -> Printer -> Printer
<+> ((Printer
" AS " Printer -> Printer -> Printer
<+>) (Printer -> Printer) -> (Text -> Printer) -> Text -> Printer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Printer
fromNameText) Text
aliasedAlias

fromNameText :: Text -> Printer
fromNameText :: Text -> Printer
fromNameText Text
t = Query -> Printer
QueryPrinter (ByteString -> Query
Query (ByteString -> Query) -> (Text -> ByteString) -> Text -> Query
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> (Text -> String) -> Text -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack (Text -> Query) -> Text -> Query
forall a b. (a -> b) -> a -> b
$ Text
t)

truePrinter :: Printer
truePrinter :: Printer
truePrinter = Printer
"TRUE"

falsePrinter :: Printer
falsePrinter :: Printer
falsePrinter = Printer
"FALSE"

--------------------------------------------------------------------------------
-- Basic printing API

toQueryFlat :: Printer -> Query
toQueryFlat :: Printer -> Query
toQueryFlat = Int -> Printer -> Query
go Int
0
  where
    go :: Int -> Printer -> Query
go Int
level =
      \case
        QueryPrinter Query
q -> Query
q
        SeqPrinter [Printer]
xs -> [Query] -> Query
forall a. Monoid a => [a] -> a
mconcat ((Query -> Bool) -> [Query] -> [Query]
forall a. (a -> Bool) -> [a] -> [a]
filter Query -> Bool
notEmpty ((Printer -> Query) -> [Printer] -> [Query]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Printer -> Query
go Int
level) [Printer]
xs))
        SepByPrinter Printer
x [Printer]
xs ->
          [Query] -> Query
forall a. Monoid a => [a] -> a
mconcat
            (Query -> [Query] -> [Query]
forall a. a -> [a] -> [a]
intersperse (Int -> Printer -> Query
go Int
level Printer
x) ((Query -> Bool) -> [Query] -> [Query]
forall a. (a -> Bool) -> [a] -> [a]
filter Query -> Bool
notEmpty ((Printer -> Query) -> [Printer] -> [Query]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Printer -> Query
go Int
level) [Printer]
xs)))
        Printer
NewlinePrinter -> ByteString -> Query
Query ByteString
" "
        IndentPrinter Int
n Printer
p -> Int -> Printer -> Query
go (Int
level Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n) Printer
p
    notEmpty :: Query -> Bool
notEmpty = (Query -> Query -> Bool
forall a. Eq a => a -> a -> Bool
/= Query
forall a. Monoid a => a
mempty)

toQueryPretty :: Printer -> Query
toQueryPretty :: Printer -> Query
toQueryPretty = Int -> Printer -> Query
go Int
0
  where
    go :: Int -> Printer -> Query
go Int
level =
      \case
        QueryPrinter Query
q -> Query
q
        SeqPrinter [Printer]
xs -> [Query] -> Query
forall a. Monoid a => [a] -> a
mconcat ((Query -> Bool) -> [Query] -> [Query]
forall a. (a -> Bool) -> [a] -> [a]
filter Query -> Bool
notEmpty ((Printer -> Query) -> [Printer] -> [Query]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Printer -> Query
go Int
level) [Printer]
xs))
        SepByPrinter Printer
x [Printer]
xs ->
          [Query] -> Query
forall a. Monoid a => [a] -> a
mconcat
            (Query -> [Query] -> [Query]
forall a. a -> [a] -> [a]
intersperse (Int -> Printer -> Query
go Int
level Printer
x) ((Query -> Bool) -> [Query] -> [Query]
forall a. (a -> Bool) -> [a] -> [a]
filter Query -> Bool
notEmpty ((Printer -> Query) -> [Printer] -> [Query]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Printer -> Query
go Int
level) [Printer]
xs)))
        Printer
NewlinePrinter -> ByteString -> Query
Query (ByteString -> Query) -> ByteString -> Query
forall a b. (a -> b) -> a -> b
$ String -> ByteString
forall a. IsString a => String -> a
fromString (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a. Show a => a -> String
show (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Text
"\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
indentation Int
level
        IndentPrinter Int
n Printer
p -> Int -> Printer -> Query
go (Int
level Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n) Printer
p
    indentation :: Int -> Text
indentation Int
n = Int -> Text -> Text
T.replicate Int
n Text
" "
    notEmpty :: Query -> Bool
notEmpty = (Query -> Query -> Bool
forall a. Eq a => a -> a -> Bool
/= Query
forall a. Monoid a => a
mempty)

-- | Produces a query with holes, and a mapping for each
renderBuilderPretty :: Printer -> (LT.Builder, InsOrdHashMap Int ScalarValue)
renderBuilderPretty :: Printer -> (Builder, InsOrdHashMap Int ScalarValue)
renderBuilderPretty =
  (InsOrdHashMap ScalarValue Int -> InsOrdHashMap Int ScalarValue)
-> (Builder, InsOrdHashMap ScalarValue Int)
-> (Builder, InsOrdHashMap Int ScalarValue)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second ([(Int, ScalarValue)] -> InsOrdHashMap Int ScalarValue
forall k v. (Eq k, Hashable k) => [(k, v)] -> InsOrdHashMap k v
OMap.fromList ([(Int, ScalarValue)] -> InsOrdHashMap Int ScalarValue)
-> (InsOrdHashMap ScalarValue Int -> [(Int, ScalarValue)])
-> InsOrdHashMap ScalarValue Int
-> InsOrdHashMap Int ScalarValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ScalarValue, Int) -> (Int, ScalarValue))
-> [(ScalarValue, Int)] -> [(Int, ScalarValue)]
forall a b. (a -> b) -> [a] -> [b]
map (ScalarValue, Int) -> (Int, ScalarValue)
forall a b. (a, b) -> (b, a)
swap ([(ScalarValue, Int)] -> [(Int, ScalarValue)])
-> (InsOrdHashMap ScalarValue Int -> [(ScalarValue, Int)])
-> InsOrdHashMap ScalarValue Int
-> [(Int, ScalarValue)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. InsOrdHashMap ScalarValue Int -> [(ScalarValue, Int)]
forall k v. InsOrdHashMap k v -> [(k, v)]
OMap.toList) ((Builder, InsOrdHashMap ScalarValue Int)
 -> (Builder, InsOrdHashMap Int ScalarValue))
-> (Printer -> (Builder, InsOrdHashMap ScalarValue Int))
-> Printer
-> (Builder, InsOrdHashMap Int ScalarValue)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (State (InsOrdHashMap ScalarValue Int) Builder
 -> InsOrdHashMap ScalarValue Int
 -> (Builder, InsOrdHashMap ScalarValue Int))
-> InsOrdHashMap ScalarValue Int
-> State (InsOrdHashMap ScalarValue Int) Builder
-> (Builder, InsOrdHashMap ScalarValue Int)
forall a b c. (a -> b -> c) -> b -> a -> c
flip State (InsOrdHashMap ScalarValue Int) Builder
-> InsOrdHashMap ScalarValue Int
-> (Builder, InsOrdHashMap ScalarValue Int)
forall s a. State s a -> s -> (a, s)
runState InsOrdHashMap ScalarValue Int
forall a. Monoid a => a
mempty
    (State (InsOrdHashMap ScalarValue Int) Builder
 -> (Builder, InsOrdHashMap ScalarValue Int))
-> (Printer -> State (InsOrdHashMap ScalarValue Int) Builder)
-> Printer
-> (Builder, InsOrdHashMap ScalarValue Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Printer -> State (InsOrdHashMap ScalarValue Int) Builder
runBuilderPretty

runBuilderPretty :: Printer -> State (InsOrdHashMap ScalarValue Int) LT.Builder
runBuilderPretty :: Printer -> State (InsOrdHashMap ScalarValue Int) Builder
runBuilderPretty = Int -> Printer -> State (InsOrdHashMap ScalarValue Int) Builder
go Int
0
  where
    go :: Int -> Printer -> State (InsOrdHashMap ScalarValue Int) Builder
go Int
level =
      \case
        SeqPrinter [Printer]
xs -> ([Builder] -> Builder)
-> StateT (InsOrdHashMap ScalarValue Int) Identity [Builder]
-> State (InsOrdHashMap ScalarValue Int) Builder
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder)
-> ([Builder] -> [Builder]) -> [Builder] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder -> Bool) -> [Builder] -> [Builder]
forall a. (a -> Bool) -> [a] -> [a]
filter Builder -> Bool
notEmpty) ((Printer -> State (InsOrdHashMap ScalarValue Int) Builder)
-> [Printer]
-> StateT (InsOrdHashMap ScalarValue Int) Identity [Builder]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Int -> Printer -> State (InsOrdHashMap ScalarValue Int) Builder
go Int
level) [Printer]
xs)
        SepByPrinter Printer
x [Printer]
xs -> do
          Builder
i <- Int -> Printer -> State (InsOrdHashMap ScalarValue Int) Builder
go Int
level Printer
x
          ([Builder] -> Builder)
-> StateT (InsOrdHashMap ScalarValue Int) Identity [Builder]
-> State (InsOrdHashMap ScalarValue Int) Builder
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder)
-> ([Builder] -> [Builder]) -> [Builder] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
intersperse Builder
i ([Builder] -> [Builder])
-> ([Builder] -> [Builder]) -> [Builder] -> [Builder]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder -> Bool) -> [Builder] -> [Builder]
forall a. (a -> Bool) -> [a] -> [a]
filter Builder -> Bool
notEmpty) ((Printer -> State (InsOrdHashMap ScalarValue Int) Builder)
-> [Printer]
-> StateT (InsOrdHashMap ScalarValue Int) Identity [Builder]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Int -> Printer -> State (InsOrdHashMap ScalarValue Int) Builder
go Int
level) [Printer]
xs)
        Printer
NewlinePrinter -> Builder -> State (InsOrdHashMap ScalarValue Int) Builder
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Builder
"\n" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
indentation Int
level)
        IndentPrinter Int
n Printer
p -> Int -> Printer -> State (InsOrdHashMap ScalarValue Int) Builder
go (Int
level Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n) Printer
p
        QueryPrinter Query {unQuery :: Query -> ByteString
unQuery = ByteString
q} -> Builder -> State (InsOrdHashMap ScalarValue Int) Builder
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Builder -> State (InsOrdHashMap ScalarValue Int) Builder)
-> (ByteString -> Builder)
-> ByteString
-> State (InsOrdHashMap ScalarValue Int) Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Builder
LT.fromText (Text -> Builder) -> (ByteString -> Text) -> ByteString -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
T.decodeUtf8 (ByteString -> State (InsOrdHashMap ScalarValue Int) Builder)
-> ByteString -> State (InsOrdHashMap ScalarValue Int) Builder
forall a b. (a -> b) -> a -> b
$ ByteString
q
    indentation :: Int -> Builder
indentation Int
n = Text -> Builder
LT.fromText (Int -> Text -> Text
T.replicate Int
n Text
" ")
    notEmpty :: Builder -> Bool
notEmpty = (Builder -> Builder -> Bool
forall a. Eq a => a -> a -> Bool
/= Builder
forall a. Monoid a => a
mempty)

fromFieldOrigin :: FieldOrigin -> Printer
fromFieldOrigin :: FieldOrigin -> Printer
fromFieldOrigin = \case
  FieldOrigin
NoOrigin -> Printer
"NULL"
  AggregateOrigin [Aliased Aggregate]
aliasedAggregates ->
    Printer
"STRUCT("
      Printer -> Printer -> Printer
<+>
      -- Example: "0 AS count, STRUCT(NULL AS id) AS sum"
      Printer -> [Printer] -> Printer
SepByPrinter Printer
", " (Aliased Printer -> Printer
fromAliased (Aliased Printer -> Printer)
-> (Aliased Aggregate -> Aliased Printer)
-> Aliased Aggregate
-> Printer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Aggregate -> Printer) -> Aliased Aggregate -> Aliased Printer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Aggregate -> Printer
fromNullAggregate (Aliased Aggregate -> Printer) -> [Aliased Aggregate] -> [Printer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Aliased Aggregate]
aliasedAggregates)
      Printer -> Printer -> Printer
<+> Printer
")"

fromNullAggregate :: Aggregate -> Printer
fromNullAggregate :: Aggregate -> Printer
fromNullAggregate = \case
  CountAggregate Countable FieldName
_ -> Printer
"0"
  OpAggregate Text
_text [Expression]
_exp -> Printer
"NULL"
  TextAggregate Text
_text -> Printer
"NULL"