sqel-0.0.1.0: test/Sqel/Test/QueryProjectionTest.hs
{-# options_ghc -Wno-partial-type-signatures #-}
module Sqel.Test.QueryProjectionTest where
import Hedgehog (TestT, (===))
import Prelude hiding (sum)
import Sqel.Class.MatchView (HasPath, HasField)
import Sqel.Column (pk)
import Sqel.Data.Dd (Dd, DdType, Sqel, type (:>) ((:>)))
import Sqel.Data.Order (Order (Desc))
import Sqel.Data.Sql (Sql, sql)
import Sqel.Data.Uid (Uid)
import Sqel.Merge (merge)
import Sqel.Names (named)
import Sqel.PgType (CheckedProjection, MkTableSchema, projection)
import Sqel.Prim (prim, prims)
import Sqel.Product (prod)
import Sqel.Query (checkQuery)
import qualified Sqel.Query.Combinators as Q
import Sqel.Sql.Select (selectWhereGen)
import Sqel.Sum (con, con1, sum)
import Sqel.Type (MSelect, Merge, Name, Prim, PrimUnused, Prod, type (*>), type (>))
import Sqel.Uid (uid)
data Thing =
Thing {
t_a :: Int,
t_b :: Text,
t_c :: Double
}
deriving stock (Eq, Show, Generic)
type DdThing =
Prod Thing *>
Prim "t_a" Int >
Prim "t_b" Text >
Prim "t_c" Double
ddThing :: Dd DdThing
ddThing =
prod prims
data Something =
Something {
st_a :: Int,
thing :: Thing
}
deriving stock (Eq, Show, Generic)
ddSomething :: Sqel (Uid Int64 Something) _
ddSomething =
uid (pk prim) (prod (prim :> merge ddThing))
data SomethingNest =
SomeThingNest { thing :: Thing }
|
NotAThingNest { nat_a :: Int, nat_b :: Text }
deriving stock (Eq, Show, Generic)
ddSomethingNest :: Sqel (Uid Int64 SomethingNest) _
ddSomethingNest =
uid (pk prim) (sum (con1 ddThing :> con prims))
data QThing (a :: Type) =
QThing {
t_b :: Text,
t_c :: Double
}
deriving stock (Eq, Show, Generic)
-- TODO think of something better for @order@
data QThingI d =
QThingI {
qt :: QThing d,
limit :: Int64,
order :: ()
}
deriving stock (Eq, Show, Generic)
type QThingDd d =
Prod (QThing d) *>
Prim "t_b" Text >
Prim "t_c" Double
data ThingWrap a =
ThingWrap { thing :: a }
deriving stock (Eq, Show, Generic)
type DdThingWrap d =
Prod (ThingWrap (DdType d)) *> Name "thing" d
data ThingFor d =
ThingFor { thing :: Thing }
deriving stock (Eq, Show, Generic)
type DdThingForNest d =
Prod (ThingFor d) *> Name "thing" DdThing
ddThingNest :: Dd (DdThingForNest d)
ddThingNest =
prod ddThing
-- TODO also here, the order field must be renamed to @thing@ because that's what it orders on
type DdQThingI d =
Prod (QThingI d) *>
Merge (
Prod (QThing d) *>
Prim "t_b" Text >
Prim "t_c" Double
) >
MSelect (PrimUnused Int64) >
MSelect (Prim "t_c" ())
type DdQThingINest d =
Prod (ThingWrap (QThingI d)) *>
Name "thing" (DdQThingI d)
ddDdQThingI :: Dd (DdQThingI d)
ddDdQThingI =
prod (merge (prod prims) :> Q.limit :> named @"t_c" (Q.order Desc))
qthingSql ::
∀ s .
HasField "t_b" Text s =>
HasField "t_c" Double s =>
HasField "t_c" () s =>
CheckedProjection DdThing s =>
MkTableSchema s =>
Dd s ->
Sql
qthingSql table =
selectWhereGen qs ps
where
qs = checkQuery query table
ps = projection ddThing table
query = ddDdQThingI
qthingNestSql ::
∀ s .
HasPath ["thing", "t_b"] Text s =>
HasPath ["thing", "t_c"] Double s =>
HasPath ["thing", "t_c"] () s =>
MkTableSchema s =>
CheckedProjection (DdThingForNest (DdType s)) s =>
Dd s ->
Sql
qthingNestSql table =
selectWhereGen qs ps
where
qs = checkQuery query table
ps = projection (ddThingNest @(DdType s)) table
query = prod @(ThingWrap _) ddDdQThingI
targetThing :: Sql
targetThing =
[sql|select "t_a", "t_b", "t_c" from "something" where (("t_b" = $1 and "t_c" = $2)) order by "t_c" desc limit $3|]
targetThingNest :: Sql
targetThingNest =
[sql|select ("thing").t_a, ("thing").t_b, ("thing").t_c from "something_nest" where (((("thing")."t_b" = $1 and ("thing")."t_c" = $2))) order by ("thing")."t_c" desc limit $3|]
test_queryProjection :: TestT IO ()
test_queryProjection = do
targetThing === qthingSql ddSomething
targetThingNest === qthingNestSql ddSomethingNest