module Sqel.Query where
import qualified Data.Map.Strict as Map
import Generics.SOP (NP (Nil))
import Sqel.Class.MatchView (MatchQuery)
import Sqel.Data.Codec (Encoder)
import Sqel.Data.Dd (
Comp (Prod),
CompInc (Nest),
Dd (Dd),
DdInc (DdNest),
DdK (DdK),
DdSort (DdProd),
DdStruct (DdComp),
DdType,
ProdType (Reg),
Struct (Comp, Prim),
)
import Sqel.Data.FragType (FragType)
import Sqel.Data.Mods (pattern NoMods, NoMods)
import Sqel.Data.QuerySchema (QuerySchema (QuerySchema))
import Sqel.Data.Sel (MkTSel (mkTSel), Sel (SelSymbol), SelPrefix (DefaultPrefix), SelW (SelWSymbol), TSel (TSel))
import Sqel.Data.SelectExpr (
SelectExpr (SelectExprAtom, SelectExprIgnore, SelectExprList, SelectExprNot, SelectExprSum),
SelectFragment (SelectFragment),
)
import Sqel.Data.Sql (Sql)
import Sqel.Prim (primAs)
import Sqel.ReifyCodec (ReifyCodec (reifyCodec))
import Sqel.SOP.Error (Quoted)
import Type.Errors (ErrorMessage)
import Sqel.Query.Fragments (ColumnPrefix (NoPrefix), joinFrag, joinSum)
import Sqel.Query.SelectExpr (ToSelectExpr (toSelectExpr))
class SelectExprUnlessError (check :: Maybe k) (s :: DdK) where
selectExprUnlessError :: Dd s -> SelectExpr
instance ToSelectExpr s => SelectExprUnlessError 'Nothing s where
selectExprUnlessError :: Dd s -> SelectExpr
selectExprUnlessError = forall (query :: DdK).
ToSelectExpr query =>
ColumnPrefix -> Dd query -> SelectExpr
toSelectExpr ColumnPrefix
NoPrefix
class CheckedQuery (qs :: DdK) (ts :: DdK) where
checkedQ :: Dd qs -> SelectExpr
type CheckQueryStuck :: ErrorMessage
type CheckQueryStuck =
"Could not validate query fields since there is not enough type information available." %
"You are most likely missing a constraint for " <> Quoted "CheckedQuery" <> "."
instance (
MatchQuery query table match,
SelectExprUnlessError match query
) => CheckedQuery query table where
checkedQ :: Dd query -> SelectExpr
checkedQ = forall k (check :: Maybe k) (s :: DdK).
SelectExprUnlessError check s =>
Dd s -> SelectExpr
selectExprUnlessError @_ @match
compileSelectExpr ::
SelectExpr ->
[SelectFragment]
compileSelectExpr :: SelectExpr -> [SelectFragment]
compileSelectExpr SelectExpr
expr =
forall k a. Map k a -> [a]
Map.elems (forall k a b. (k -> a -> b) -> Map k a -> Map k b
Map.mapWithKey FragType -> Sql -> SelectFragment
SelectFragment (forall a b. (a, b) -> b
snd (Int -> SelectExpr -> (Int, Map FragType Sql)
spin Int
1 SelectExpr
expr)))
where
spin :: Int -> SelectExpr -> (Int, Map FragType Sql)
spin :: Int -> SelectExpr -> (Int, Map FragType Sql)
spin Int
i = \case
SelectExprAtom FragType
tpe Int -> Sql
code -> (Int
i forall a. Num a => a -> a -> a
+ Int
1, [(FragType
tpe, Int -> Sql
code Int
i)])
SelectExprList QOp
op [SelectExpr]
sub -> forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (forall k a b. (k -> a -> b) -> Map k a -> Map k b
Map.mapWithKey (QOp -> FragType -> [Sql] -> Sql
joinFrag QOp
op)) (forall {f :: * -> *} {f :: * -> *}.
(Semigroup (f Sql), Applicative f, Traversable f) =>
Int -> f SelectExpr -> (Int, Map FragType (f Sql))
prod Int
i [SelectExpr]
sub)
SelectExprSum [SelectExpr]
sub -> forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (forall k a b. (k -> a -> b) -> Map k a -> Map k b
Map.mapWithKey (Int -> FragType -> [Sql] -> Sql
joinSum Int
i)) (forall {f :: * -> *} {f :: * -> *}.
(Semigroup (f Sql), Applicative f, Traversable f) =>
Int -> f SelectExpr -> (Int, Map FragType (f Sql))
prod (Int
i forall a. Num a => a -> a -> a
+ Int
1) [SelectExpr]
sub)
SelectExprNot SelectExpr
_ -> forall a. HasCallStack => a
undefined
SelectExpr
SelectExprIgnore -> (Int
i, forall a. Monoid a => a
mempty)
prod :: Int -> f SelectExpr -> (Int, Map FragType (f Sql))
prod Int
i f SelectExpr
sub =
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
(a -> a -> a) -> f (Map k a) -> Map k a
Map.unionsWith forall a. Semigroup a => a -> a -> a
(<>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (f :: * -> *) a. Applicative f => a -> f a
pure)) (forall (t :: * -> *) s a b.
Traversable t =>
(s -> a -> (s, b)) -> s -> t a -> (s, t b)
mapAccumL Int -> SelectExpr -> (Int, Map FragType Sql)
spin Int
i f SelectExpr
sub)
querySchemaWith ::
∀ q query a .
ReifyCodec Encoder query q =>
Dd query ->
SelectExpr ->
QuerySchema q a
querySchemaWith :: forall {k} q (query :: DdK) (a :: k).
ReifyCodec Encoder query q =>
Dd query -> SelectExpr -> QuerySchema q a
querySchemaWith Dd query
query SelectExpr
expr =
forall {k} q (a :: k).
[SelectFragment] -> Encoder q -> QuerySchema q a
QuerySchema (SelectExpr -> [SelectFragment]
compileSelectExpr SelectExpr
expr) (forall (b :: * -> *) (s :: DdK) a. ReifyCodec b s a => Dd s -> b a
reifyCodec @Encoder Dd query
query)
unsafeQuerySchema ::
∀ q query a .
ToSelectExpr query =>
ReifyCodec Encoder query q =>
Dd query ->
QuerySchema q a
unsafeQuerySchema :: forall {k} q (query :: DdK) (a :: k).
(ToSelectExpr query, ReifyCodec Encoder query q) =>
Dd query -> QuerySchema q a
unsafeQuerySchema Dd query
query =
forall {k} q (query :: DdK) (a :: k).
ReifyCodec Encoder query q =>
Dd query -> SelectExpr -> QuerySchema q a
querySchemaWith Dd query
query (forall (query :: DdK).
ToSelectExpr query =>
ColumnPrefix -> Dd query -> SelectExpr
toSelectExpr ColumnPrefix
NoPrefix Dd query
query)
type CheckQuery :: DdK -> DdK -> Constraint
class CheckQuery query table where
checkQuery ::
Dd query ->
Dd table ->
QuerySchema (DdType query) (DdType table)
instance (
CheckedQuery query table,
ReifyCodec Encoder query (DdType query)
) => CheckQuery query table where
checkQuery :: Dd query -> Dd table -> QuerySchema (DdType query) (DdType table)
checkQuery Dd query
query Dd table
_ =
forall {k} q (query :: DdK) (a :: k).
ReifyCodec Encoder query q =>
Dd query -> SelectExpr -> QuerySchema q a
querySchemaWith Dd query
query (forall (qs :: DdK) (ts :: DdK).
CheckedQuery qs ts =>
Dd qs -> SelectExpr
checkedQ @query @table Dd query
query)
type EmptyQuery =
'DdK ('SelSymbol "") NoMods () ('Comp ('TSel 'DefaultPrefix "") ('Prod 'Reg) 'Nest '[])
emptyQuery :: Dd EmptyQuery
emptyQuery :: Dd EmptyQuery
emptyQuery =
forall (sel :: Sel) (mods :: [*]) (s1 :: Struct) a.
SelW sel -> Mods mods -> DdStruct s1 -> Dd ('DdK sel mods a s1)
Dd (forall (name :: Symbol).
KnownSymbol name =>
Proxy name -> SelW ('SelSymbol name)
SelWSymbol forall {k} (t :: k). Proxy t
Proxy) forall (ps :: [*]). (ps ~ NoMods) => Mods ps
NoMods (forall (sel :: TSel) (c :: Comp) (i :: CompInc) (sub :: [DdK]).
TSelW sel
-> DdSort c -> DdInc i -> NP Dd sub -> DdStruct ('Comp sel c i sub)
DdComp forall (sel :: TSel). MkTSel sel => TSelW sel
mkTSel DdSort ('Prod 'Reg)
DdProd DdInc 'Nest
DdNest forall {k} (a :: k -> *). NP a '[]
Nil)
primIdQuery :: Dd ('DdK ('SelSymbol "id") NoMods a 'Prim)
primIdQuery :: forall a. Dd ('DdK ('SelSymbol "id") NoMods a 'Prim)
primIdQuery =
forall (name :: Symbol) a.
KnownSymbol name =>
Dd ('DdK ('SelSymbol name) NoMods a 'Prim)
primAs @"id"