packages feed

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