Cleanup the rest of the Values, fix the example code and update to use Esqueleto.Experimental

This commit is contained in:
belevy 2021-02-13 20:35:21 -06:00
parent 6b12edbd8c
commit 1f52363407
15 changed files with 190 additions and 189 deletions

View File

@ -10,6 +10,7 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
@ -19,15 +20,14 @@ module Main
) where
import Blog
import Control.Monad (void)
import Control.Monad (forM_)
import Control.Monad (forM_, void)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.IO.Unlift (MonadUnliftIO)
import Control.Monad.Logger (MonadLogger)
import Control.Monad.Reader (MonadReader(..), runReaderT)
import Control.Monad.Trans.Control (MonadBaseControl)
import Data.Monoid ((<>))
import Database.Esqueleto
import Database.Esqueleto.Experimental
import Database.Persist.Postgresql (ConnectionString, withPostgresqlConn)
import Database.Persist.TH
( AtLeastOneUniqueKey(..)
@ -62,9 +62,9 @@ putPersons :: (MonadIO m, MonadLogger m)
=> SqlPersistT m ()
putPersons = do
-- | Select all values from the `person` table
people <- select $
from $ \person -> do
return person
people <- select $ do
person <- from $ table @Person
return person
-- | entityVal extracts the Person value, which we then extract
-- | the person name from the record and print it
@ -75,8 +75,8 @@ getJohns :: (MonadIO m, MonadLogger m)
=> SqlReadT m [Entity Person]
getJohns =
-- | Select all persons where their name is equal to "John"
select $
from $ \p -> do
select $ do
p <- from $ table @Person
where_ (p ^. PersonName ==. val "John")
return p
@ -85,8 +85,8 @@ getAdults :: (MonadIO m, MonadLogger m)
=> SqlReadT m [Entity Person]
getAdults =
-- | Select any Person where their age is >= 18 and NOT NULL
select $
from $ \p -> do
select $ do
p <- from $ table @Person
where_ (p ^. PersonAge >=. just (val 18))
return p
@ -95,8 +95,10 @@ getBlogPostsByAuthors :: (MonadIO m, MonadLogger m)
=> SqlReadT m [(Entity BlogPost, Entity Person)]
getBlogPostsByAuthors =
-- | Select all persons and their blogposts, ordering by title
select $
from $ \(b, p) -> do
select $ do
p :& b <-
from $ table @Person
`crossJoin` table @BlogPost
where_ (b ^. BlogPostAuthorId ==. p ^. PersonId)
orderBy [asc (b ^. BlogPostTitle)]
return (b, p)
@ -108,9 +110,11 @@ getAuthorMaybePosts =
-- | Select all persons doing a left outer join on blogposts
-- | Since a person may not have any blogposts the BlogPost Entity is wrapped
-- | in a Maybe
select $
from $ \(p `LeftOuterJoin` mb) -> do
on (just (p ^. PersonId) ==. mb ?. BlogPostAuthorId)
select $ do
(p :& mb) <-
from $ table @Person
`leftJoin` table @BlogPost
`on` (\(p :& mb) -> (just (p ^. PersonId) ==. mb ?. BlogPostAuthorId))
orderBy [asc (p ^. PersonName), asc (mb ?. BlogPostTitle)]
return (p, mb)
@ -122,10 +126,13 @@ followers =
-- | Note carefully that the order of the ON clauses is reversed!
-- | You're required to write your ons in reverse order because that helps composability
-- | (see the documentation of on for more details).
select $
from $ \(p1 `InnerJoin` f `InnerJoin` p2) -> do
on (p2 ^. PersonId ==. f ^. FollowFollowed)
on (p1 ^. PersonId ==. f ^. FollowFollower)
select $ do
(p1 :& f :& p2) <-
from $ table @Person
`innerJoin` table @Follow
`on` (\(p1 :& f) -> p1 ^. PersonId ==. f ^. FollowFollower)
`innerJoin` table @Person
`on` (\(_ :& f :& p2) -> p2 ^. PersonId ==. f ^. FollowFollowed)
return (p1, f, p2)
@ -146,8 +153,8 @@ deleteYoungsters = do
-- | In this case where `ON DELETE CASCADE` is not generated by migration
-- | we select all the entities we want to delete and then for each one
-- | one we extract the key and use Persistent's `deleteCascade`
youngsters <- select $
from $ \p -> do
youngsters <- select $ do
p <- from $ table @Person
where_ (p ^. PersonAge <. just (val 14))
pure p
forM_ youngsters (deleteCascade . entityKey)
@ -157,7 +164,8 @@ insertBlogPosts :: (MonadIO m, MonadLogger m)
=> SqlWriteT m ()
insertBlogPosts =
-- | Insert a new blogpost for every person
insertSelect $ from $ \p ->
insertSelect $ do
p <- from $ table @Person
return $ BlogPost <# (val "Group Blog Post") <&> (p ^. PersonId)

View File

@ -1,8 +1,8 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
-- | The @esqueleto@ EDSL (embedded domain specific language).
-- This module replaces @Database.Persist@, so instead of
-- importing that module you should just import this one:
@ -126,13 +126,13 @@ module Database.Esqueleto
, module Database.Esqueleto.Internal.PersistentImport
) where
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Trans.Reader (ReaderT)
import Data.Int (Int64)
import qualified Data.Map.Strict as Map
import Database.Esqueleto.Internal.Language
import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Sql
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Trans.Reader (ReaderT)
import Data.Int (Int64)
import qualified Data.Map.Strict as Map
import Database.Esqueleto.Internal.Language
import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Sql
import qualified Database.Persist

View File

@ -219,19 +219,16 @@ module Database.Esqueleto.Experimental
, module Database.Esqueleto.Internal.PersistentImport
) where
import Database.Esqueleto.Internal.Internal hiding
(From,
from,
on)
import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Internal hiding (From, from, on)
import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Experimental.From
import Database.Esqueleto.Experimental.From.CommonTableExpression
import Database.Esqueleto.Experimental.From.Join
import Database.Esqueleto.Experimental.From.SqlSetOperation
import Database.Esqueleto.Experimental.ToAlias
import Database.Esqueleto.Experimental.ToAliasReference
import Database.Esqueleto.Experimental.ToMaybe
import Database.Esqueleto.Experimental.From
import Database.Esqueleto.Experimental.From.CommonTableExpression
import Database.Esqueleto.Experimental.From.Join
import Database.Esqueleto.Experimental.From.SqlSetOperation
import Database.Esqueleto.Experimental.ToAlias
import Database.Esqueleto.Experimental.ToAliasReference
import Database.Esqueleto.Experimental.ToMaybe
-- $setup
--

View File

@ -1,37 +1,32 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Database.Esqueleto.Experimental.From.Join
where
import Data.Bifunctor (first)
import Data.Kind (Constraint)
import Data.Proxy
import qualified Data.Text.Lazy.Builder as TLB
import Database.Esqueleto.Experimental.From
import Database.Esqueleto.Experimental.From.SqlSetOperation
import Database.Esqueleto.Experimental.ToAlias
import Database.Esqueleto.Experimental.ToAliasReference
import Database.Esqueleto.Experimental.ToMaybe
import Database.Esqueleto.Internal.Internal hiding
(From (..),
from,
fromJoin,
on)
import Database.Esqueleto.Internal.PersistentImport (Entity (..),
EntityField,
PersistEntity,
PersistField)
import GHC.TypeLits
import Data.Bifunctor (first)
import Data.Kind (Constraint)
import Data.Proxy
import qualified Data.Text.Lazy.Builder as TLB
import Database.Esqueleto.Experimental.From
import Database.Esqueleto.Experimental.From.SqlSetOperation
import Database.Esqueleto.Experimental.ToAlias
import Database.Esqueleto.Experimental.ToAliasReference
import Database.Esqueleto.Experimental.ToMaybe
import Database.Esqueleto.Internal.Internal hiding
(From(..), from, fromJoin, on)
import Database.Esqueleto.Internal.PersistentImport
(Entity(..), EntityField, PersistEntity, PersistField)
import GHC.TypeLits
-- | A left-precedence pair. Pronounced \"and\". Used to represent expressions
-- that have been joined together.
@ -65,7 +60,7 @@ instance ValidOnClause (a -> SqlQuery b)
-- \`on\` (\\(p :& bP) ->
-- p ^. PersonId ==. bP ^. BlogPostAuthorId)
-- @
on :: ValidOnClause a => a -> (b -> SqlExpr (Value Bool)) -> (a, b -> SqlExpr (Value Bool))
on :: ValidOnClause a => a -> (b -> SqlExpr Bool) -> (a, b -> SqlExpr Bool)
on = (,)
infix 9 `on`
@ -73,7 +68,7 @@ type family ErrorOnLateral a :: Constraint where
ErrorOnLateral (a -> SqlQuery b) = TypeError ('Text "LATERAL can only be used for INNER, LEFT, and CROSS join kinds.")
ErrorOnLateral _ = ()
fromJoin :: TLB.Builder -> RawFn -> RawFn -> Maybe (SqlExpr (Value Bool)) -> RawFn
fromJoin :: TLB.Builder -> RawFn -> RawFn -> Maybe (SqlExpr Bool) -> RawFn
fromJoin joinKind lhs rhs monClause =
\paren info ->
first (parensM paren) $
@ -86,14 +81,14 @@ fromJoin joinKind lhs rhs monClause =
makeOnClause info (ERaw _ f) = first (" ON " <>) (f Never info)
type family HasOnClause actual expected :: Constraint where
HasOnClause (a, b -> SqlExpr (Value Bool)) c = () -- Let the compiler handle the type mismatch
HasOnClause (a, b -> SqlExpr Bool) c = () -- Let the compiler handle the type mismatch
HasOnClause a expected =
TypeError ( 'Text "Missing ON clause for join with"
':$$: 'ShowType a
':$$: 'Text ""
':$$: 'Text "Expected: "
':$$: 'ShowType a
':$$: 'Text "`on` " ':<>: 'ShowType (expected -> SqlExpr (Value Bool))
':$$: 'Text "`on` " ':<>: 'ShowType (expected -> SqlExpr Bool)
':$$: 'Text ""
)
@ -114,7 +109,7 @@ type family HasOnClause actual expected :: Constraint where
innerJoin :: ( ToFrom a a'
, ToFrom b b'
, HasOnClause rhs (a' :& b')
, rhs ~ (b, (a' :& b') -> SqlExpr (Value Bool))
, rhs ~ (b, (a' :& b') -> SqlExpr Bool)
) => a -> rhs -> From (a' :& b')
innerJoin lhs (rhs, on') = From $ do
(leftVal, leftFrom) <- unFrom (toFrom lhs)
@ -138,7 +133,7 @@ innerJoinLateral :: ( ToFrom a a'
, SqlSelect b r
, ToAlias b
, ToAliasReference b
, rhs ~ (a' -> SqlQuery b, (a' :& b) -> SqlExpr (Value Bool))
, rhs ~ (a' -> SqlQuery b, (a' :& b) -> SqlExpr Bool)
)
=> a -> rhs -> From (a' :& b)
innerJoinLateral lhs (rhsFn, on') = From $ do
@ -210,7 +205,7 @@ leftJoin :: ( ToFrom a a'
, ToFrom b b'
, ToMaybe b'
, HasOnClause rhs (a' :& ToMaybeT b')
, rhs ~ (b, (a' :& ToMaybeT b') -> SqlExpr (Value Bool))
, rhs ~ (b, (a' :& ToMaybeT b') -> SqlExpr Bool)
) => a -> rhs -> From (a' :& ToMaybeT b')
leftJoin lhs (rhs, on') = From $ do
(leftVal, leftFrom) <- unFrom (toFrom lhs)
@ -236,7 +231,7 @@ leftJoinLateral :: ( ToFrom a a'
, ToAlias b
, ToAliasReference b
, ToMaybe b
, rhs ~ (a' -> SqlQuery b, (a' :& ToMaybeT b) -> SqlExpr (Value Bool))
, rhs ~ (a' -> SqlQuery b, (a' :& ToMaybeT b) -> SqlExpr Bool)
)
=> a -> rhs -> From (a' :& ToMaybeT b)
leftJoinLateral lhs (rhsFn, on') = From $ do
@ -266,7 +261,7 @@ rightJoin :: ( ToFrom a a'
, ToFrom b b'
, ToMaybe a'
, HasOnClause rhs (ToMaybeT a' :& b')
, rhs ~ (b, (ToMaybeT a' :& b') -> SqlExpr (Value Bool))
, rhs ~ (b, (ToMaybeT a' :& b') -> SqlExpr Bool)
) => a -> rhs -> From (ToMaybeT a' :& b')
rightJoin lhs (rhs, on') = From $ do
(leftVal, leftFrom) <- unFrom (toFrom lhs)
@ -295,7 +290,7 @@ fullOuterJoin :: ( ToFrom a a'
, ToMaybe a'
, ToMaybe b'
, HasOnClause rhs (ToMaybeT a' :& ToMaybeT b')
, rhs ~ (b, (ToMaybeT a' :& ToMaybeT b') -> SqlExpr (Value Bool))
, rhs ~ (b, (ToMaybeT a' :& ToMaybeT b') -> SqlExpr Bool)
) => a -> rhs -> From (ToMaybeT a' :& ToMaybeT b')
fullOuterJoin lhs (rhs, on') = From $ do
(leftVal, leftFrom) <- unFrom (toFrom lhs)
@ -329,7 +324,7 @@ class DoInnerJoin lateral lhs rhs res | lateral rhs lhs -> res where
instance ( ToFrom a a'
, ToFrom b b'
, HasOnClause rhs (a' :& b')
, rhs ~ (b, (a' :& b') -> SqlExpr (Value Bool))
, rhs ~ (b, (a' :& b') -> SqlExpr Bool)
) => DoInnerJoin NotLateral a rhs (a' :& b') where
doInnerJoin _ = innerJoin
@ -338,7 +333,7 @@ instance ( ToFrom a a'
, ToAlias b
, ToAliasReference b
, d ~ (a' :& b)
) => DoInnerJoin Lateral a (a' -> SqlQuery b, d -> SqlExpr (Value Bool)) d where
) => DoInnerJoin Lateral a (a' -> SqlQuery b, d -> SqlExpr Bool) d where
doInnerJoin _ = innerJoinLateral
instance ( DoInnerJoin lateral lhs rhs r, lateral ~ IsLateral rhs )
@ -353,7 +348,7 @@ instance ( ToFrom a a'
, ToMaybe b'
, ToMaybeT b' ~ mb
, HasOnClause rhs (a' :& mb)
, rhs ~ (b, (a' :& mb) -> SqlExpr (Value Bool))
, rhs ~ (b, (a' :& mb) -> SqlExpr Bool)
) => DoLeftJoin NotLateral a rhs (a' :& mb) where
doLeftJoin _ = leftJoin
@ -363,7 +358,7 @@ instance ( ToFrom a a'
, SqlSelect b r
, ToAlias b
, ToAliasReference b
) => DoLeftJoin Lateral a (a' -> SqlQuery b, d -> SqlExpr (Value Bool)) d where
) => DoLeftJoin Lateral a (a' -> SqlQuery b, d -> SqlExpr Bool) d where
doLeftJoin _ = leftJoinLateral
instance ( DoLeftJoin lateral lhs rhs r, lateral ~ IsLateral rhs )
@ -389,7 +384,7 @@ instance ( ToFrom a a'
, ToMaybeT a' ~ ma
, HasOnClause rhs (ma :& b')
, ErrorOnLateral b
, rhs ~ (b, (ma :& b') -> SqlExpr (Value Bool))
, rhs ~ (b, (ma :& b') -> SqlExpr Bool)
) => ToFrom (RightOuterJoin a rhs) (ma :& b') where
toFrom (RightOuterJoin a b) = rightJoin a b
@ -401,7 +396,7 @@ instance ( ToFrom a a'
, ToMaybeT b' ~ mb
, HasOnClause rhs (ma :& mb)
, ErrorOnLateral b
, rhs ~ (b, (ma :& mb) -> SqlExpr (Value Bool))
, rhs ~ (b, (ma :& mb) -> SqlExpr Bool)
) => ToFrom (FullOuterJoin a rhs) (ma :& mb) where
toFrom (FullOuterJoin a b) = fullOuterJoin a b

View File

@ -1,13 +1,12 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilies #-}
module Database.Esqueleto.Experimental.ToAlias
where
import Database.Esqueleto.Internal.Internal hiding (From,
from, on)
import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Internal hiding (From, from, on)
import Database.Esqueleto.Internal.PersistentImport
{-# DEPRECATED ToAliasT "This type alias doesn't do anything. Please delete it. Will be removed in the next release." #-}
type ToAliasT a = a

View File

@ -1,14 +1,13 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilies #-}
module Database.Esqueleto.Experimental.ToAliasReference
where
import Data.Coerce
import Database.Esqueleto.Internal.Internal hiding (From,
from, on)
import Database.Esqueleto.Internal.PersistentImport
import Data.Coerce
import Database.Esqueleto.Internal.Internal hiding (From, from, on)
import Database.Esqueleto.Internal.PersistentImport
{-# DEPRECATED ToAliasReferenceT "This type alias doesn't do anything. Please delete it. Will be removed in the next release." #-}
type ToAliasReferenceT a = a

View File

@ -1,12 +1,11 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilies #-}
module Database.Esqueleto.Experimental.ToMaybe
where
import Database.Esqueleto.Internal.Internal hiding (From (..),
from, on)
import Database.Esqueleto.Internal.PersistentImport (Entity (..))
import Database.Esqueleto.Internal.Internal hiding (From(..), from, on)
import Database.Esqueleto.Internal.PersistentImport (Entity(..))
type family Nullable a where
Nullable (Maybe a) = a

View File

@ -132,7 +132,7 @@ fromFinish (PreprocessedFrom ret f') = Q $ do
return ret
-- | @WHERE@ clause: restrict the query's result.
where_ :: SqlExpr (Bool) -> SqlQuery ()
where_ :: SqlExpr Bool -> SqlQuery ()
where_ expr = Q $ W.tell mempty { sdWhereClause = Where expr }
-- | An @ON@ clause, useful to describe how two tables are related. Cross joins
@ -191,7 +191,7 @@ where_ expr = Q $ W.tell mempty { sdWhereClause = Where expr }
-- 'on' (baz '^.' BazId '==.' bar '^.' BarBazId)
-- ...
-- @
on :: SqlExpr (Bool) -> SqlQuery ()
on :: SqlExpr Bool -> SqlQuery ()
on expr = Q $ W.tell mempty { sdFromClause = [OnClause expr] }
-- | @GROUP BY@ clause. You can enclose multiple columns
@ -377,7 +377,7 @@ rand = ERaw noMeta $ \_ _ -> ("RANDOM()", [])
-- | @HAVING@.
--
-- @since 1.2.2
having :: SqlExpr (Bool) -> SqlQuery ()
having :: SqlExpr Bool -> SqlQuery ()
having expr = Q $ W.tell mempty { sdHavingClause = Where expr }
-- | Add a locking clause to the query. Please read
@ -617,7 +617,7 @@ val v = ERaw noMeta $ \_ _ -> ("?", [toPersistValue v])
-- > - error: {lhs: v ==. val Nothing, rhs: Database.Esqueleto.isNothing v, name: Use Esqueleto's isNothing}
-- > - error: {lhs: v !=. nothing, rhs: not_ (Database.Esqueleto.isNothing v), name: Use Esqueleto's not isNothing}
-- > - error: {lhs: v !=. val Nothing, rhs: not_ (Database.Esqueleto.isNothing v), name: Use Esqueleto's not isNothing}
isNothing :: PersistField typ => SqlExpr ((Maybe typ)) -> SqlExpr (Bool)
isNothing :: PersistField typ => SqlExpr ((Maybe typ)) -> SqlExpr Bool
isNothing v =
case v of
ERaw m f ->
@ -673,7 +673,7 @@ count = countHelper "" ""
countDistinct :: Num a => SqlExpr typ -> SqlExpr a
countDistinct = countHelper "(DISTINCT " ")"
not_ :: SqlExpr (Bool) -> SqlExpr (Bool)
not_ :: SqlExpr Bool -> SqlExpr Bool
not_ v = ERaw noMeta $ \p info -> first ("NOT " <>) $ x p info
where
x p info =
@ -685,27 +685,28 @@ not_ v = ERaw noMeta $ \p info -> first ("NOT " <>) $ x p info
let (b, vals) = f Never info
in (parensM p b, vals)
(==.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr (Bool)
(==.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr Bool
(==.) = unsafeSqlBinOpComposite " = " " AND "
(>=.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr (Bool)
(>=.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr Bool
(>=.) = unsafeSqlBinOp " >= "
(>.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr (Bool)
(>.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr Bool
(>.) = unsafeSqlBinOp " > "
(<=.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr (Bool)
(<=.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr Bool
(<=.) = unsafeSqlBinOp " <= "
(<.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr (Bool)
(<.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr Bool
(<.) = unsafeSqlBinOp " < "
(!=.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr (Bool)
(!=.) :: PersistField typ => SqlExpr typ -> SqlExpr typ -> SqlExpr Bool
(!=.) = unsafeSqlBinOpComposite " != " " OR "
(&&.) :: SqlExpr (Bool) -> SqlExpr (Bool) -> SqlExpr (Bool)
(&&.) :: SqlExpr Bool -> SqlExpr Bool -> SqlExpr Bool
(&&.) = unsafeSqlBinOp " AND "
(||.) :: SqlExpr (Bool) -> SqlExpr (Bool) -> SqlExpr (Bool)
(||.) :: SqlExpr Bool -> SqlExpr Bool -> SqlExpr Bool
(||.) = unsafeSqlBinOp " OR "
(+.) :: PersistField a => SqlExpr a -> SqlExpr a -> SqlExpr a
@ -723,7 +724,7 @@ not_ v = ERaw noMeta $ \p info -> first ("NOT " <>) $ x p info
-- | @BETWEEN@.
--
-- @since: 3.1.0
between :: PersistField a => SqlExpr a -> (SqlExpr a, SqlExpr a) -> SqlExpr (Bool)
between :: PersistField a => SqlExpr a -> (SqlExpr a, SqlExpr a) -> SqlExpr Bool
a `between` (b, c) = a >=. b &&. a <=. c
random_ :: (PersistField a, Num a) => SqlExpr a
@ -831,7 +832,7 @@ right_ :: (SqlString s, Num a) => (SqlExpr s, SqlExpr a) -> SqlExpr s
right_ = unsafeSqlFunction "RIGHT"
-- | @LIKE@ operator.
like :: SqlString s => SqlExpr s -> SqlExpr s -> SqlExpr (Bool)
like :: SqlString s => SqlExpr s -> SqlExpr s -> SqlExpr Bool
like = unsafeSqlBinOp " LIKE "
-- | @ILIKE@ operator (case-insensitive @LIKE@).
@ -839,7 +840,7 @@ like = unsafeSqlBinOp " LIKE "
-- Supported by PostgreSQL only.
--
-- @since 2.2.3
ilike :: SqlString s => SqlExpr s -> SqlExpr s -> SqlExpr (Bool)
ilike :: SqlString s => SqlExpr s -> SqlExpr s -> SqlExpr Bool
ilike = unsafeSqlBinOp " ILIKE "
-- | The string @'%'@. May be useful while using 'like' and
@ -915,7 +916,7 @@ justList (ERaw m f) = ERaw m f
-- @
--
-- Where @personIds@ is of type @[Key Person]@.
in_ :: PersistField typ => SqlExpr typ -> SqlExpr (ValueList typ) -> SqlExpr (Bool)
in_ :: PersistField typ => SqlExpr typ -> SqlExpr (ValueList typ) -> SqlExpr Bool
(ERaw _ v) `in_` (ERaw _ list) =
ERaw noMeta $ \p info ->
let (b1, vals1) = v Parens info
@ -927,7 +928,7 @@ in_ :: PersistField typ => SqlExpr typ -> SqlExpr (ValueList typ) -> SqlExpr (Bo
(b1 <> " IN " <> b2, vals1 <> vals2)
-- | @NOT IN@ operator.
notIn :: PersistField typ => SqlExpr typ -> SqlExpr (ValueList typ) -> SqlExpr (Bool)
notIn :: PersistField typ => SqlExpr typ -> SqlExpr (ValueList typ) -> SqlExpr Bool
(ERaw _ v) `notIn` (ERaw _ list) =
ERaw noMeta $ \p info ->
let (b1, vals1) = v Parens info
@ -944,14 +945,14 @@ notIn :: PersistField typ => SqlExpr typ -> SqlExpr (ValueList typ) -> SqlExpr (
-- 'where_' (post '^.' BlogPostAuthorId '==.' person '^.' PersonId)
-- return person
-- @
exists :: SqlQuery () -> SqlExpr (Bool)
exists :: SqlQuery () -> SqlExpr Bool
exists q = ERaw noMeta $ \p info ->
let ERaw _ f = existsHelper q
(b, vals) = f Never info
in ( parensM p $ "EXISTS " <> b, vals)
-- | @NOT EXISTS@ operator.
notExists :: SqlQuery () -> SqlExpr (Bool)
notExists :: SqlQuery () -> SqlExpr Bool
notExists q = ERaw noMeta $ \p info ->
let ERaw _ f = existsHelper q
(b, vals) = f Never info
@ -1033,7 +1034,7 @@ field /=. expr = setAux field (\ent -> ent ^. field /. expr)
-- reproduce this via 'nothing'.
--
-- @since 2.1.2
case_ :: PersistField a => [(SqlExpr (Bool), SqlExpr a)] -> SqlExpr a -> SqlExpr a
case_ :: PersistField a => [(SqlExpr Bool, SqlExpr a)] -> SqlExpr a -> SqlExpr a
case_ = unsafeSqlCase
-- | Convert an entity's key into another entity's.
@ -1092,7 +1093,7 @@ infixl 2 `InnerJoin`, `CrossJoin`, `LeftOuterJoin`, `RightOuterJoin`, `FullOuter
-- | Syntax sugar for 'case_'.
--
-- @since 2.1.2
when_ :: expr (Bool) -> () -> expr a -> (expr (Bool), expr a)
when_ :: expr Bool -> () -> expr a -> (expr Bool, expr a)
when_ cond _ expr = (cond, expr)
-- | Syntax sugar for 'case_'.
@ -1733,8 +1734,8 @@ instance Monoid DistinctClause where
-- | A part of a @FROM@ clause.
data FromClause
= FromStart Ident EntityDef
| FromJoin FromClause JoinKind FromClause (Maybe (SqlExpr (Bool)))
| OnClause (SqlExpr (Bool))
| FromJoin FromClause JoinKind FromClause (Maybe (SqlExpr Bool))
| OnClause (SqlExpr Bool)
| FromRaw (NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue]))
data CommonTableExpressionKind
@ -1795,7 +1796,7 @@ newtype SetClause = SetClause (SqlExpr Update)
collectOnClauses
:: SqlBackend
-> [FromClause]
-> Either (SqlExpr (Bool)) [FromClause]
-> Either (SqlExpr Bool) [FromClause]
collectOnClauses sqlBackend = go Set.empty []
where
go is [] (f@(FromStart i _) : fs) =
@ -1811,8 +1812,8 @@ collectOnClauses sqlBackend = go Set.empty []
findMatching
:: Set Ident
-> [FromClause]
-> SqlExpr (Bool)
-> Either (SqlExpr (Bool)) (Set Ident, [FromClause])
-> SqlExpr Bool
-> Either (SqlExpr Bool) (Set Ident, [FromClause])
findMatching idents fromClauses expr =
case fromClauses of
f : acc ->
@ -1841,7 +1842,7 @@ collectOnClauses sqlBackend = go Set.empty []
tryMatch
:: Set Ident
-> SqlExpr (Bool)
-> SqlExpr Bool
-> FromClause
-> Maybe (Set Ident, FromClause)
tryMatch idents expr fromClause =
@ -1906,7 +1907,7 @@ collectOnClauses sqlBackend = go Set.empty []
$ renderedExpr
-- | A complete @WHERE@ clause.
data WhereClause = Where (SqlExpr (Bool))
data WhereClause = Where (SqlExpr Bool)
| NoWhere
instance Semigroup WhereClause where
@ -2058,6 +2059,9 @@ hasCompositeKeyMeta = Maybe.isJust . sqlExprMetaCompositeFields
-- interpolated by the SQL backend.
data SqlExpr a = ERaw SqlExprMeta (NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue]))
instance Num a => Num (SqlExpr a) where
-- | Data type to support from hack
data PreprocessedFrom a = PreprocessedFrom a FromClause
@ -2098,16 +2102,16 @@ sub mode query = ERaw noMeta $ \_ info -> first parens $ toRawSql mode info quer
fromDBName :: IdentInfo -> DBName -> TLB.Builder
fromDBName (conn, _) = TLB.fromText . connEscapeName conn
existsHelper :: SqlQuery () -> SqlExpr (Bool)
existsHelper :: SqlQuery () -> SqlExpr Bool
existsHelper = sub SELECT . (>> return true)
where
true :: SqlExpr (Bool)
true :: SqlExpr Bool
true = val True
-- | (Internal) Create a case statement.
--
-- Since: 2.1.1
unsafeSqlCase :: PersistField a => [(SqlExpr (Bool), SqlExpr a)] -> SqlExpr a -> SqlExpr a
unsafeSqlCase :: PersistField a => [(SqlExpr Bool, SqlExpr a)] -> SqlExpr a -> SqlExpr a
unsafeSqlCase when v = ERaw noMeta buildCase
where
buildCase :: NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue])
@ -2116,11 +2120,11 @@ unsafeSqlCase when v = ERaw noMeta buildCase
(whenText, whenVals) = mapWhen when Parens info
in ( "CASE" <> whenText <> " ELSE " <> elseText <> " END", whenVals <> elseVals)
mapWhen :: [(SqlExpr (Bool), SqlExpr a)] -> NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue])
mapWhen :: [(SqlExpr Bool, SqlExpr a)] -> NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue])
mapWhen [] _ _ = throw (UnexpectedCaseErr UnsafeSqlCaseError)
mapWhen when' p info = foldl (foldHelp p info) (mempty, mempty) when'
foldHelp :: NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue]) -> (SqlExpr (Bool), SqlExpr a) -> (TLB.Builder, [PersistValue])
foldHelp :: NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue]) -> (SqlExpr Bool, SqlExpr a) -> (TLB.Builder, [PersistValue])
foldHelp p info (b0, vals0) (v1, v2) =
let (b1, vals1) = valueToSql v1 p info
(b2, vals2) = valueToSql v2 p info
@ -2135,7 +2139,7 @@ unsafeSqlCase when v = ERaw noMeta buildCase
-- signature. For example:
--
-- @
-- (==.) :: SqlExpr a -> SqlExpr a -> SqlExpr (Bool)
-- (==.) :: SqlExpr a -> SqlExpr a -> SqlExpr Bool
-- (==.) = unsafeSqlBinOp " = "
-- @
--
@ -2176,7 +2180,7 @@ unsafeSqlBinOp op a b = unsafeSqlBinOp op (construct a) (construct b)
-- Usage example:
--
-- @
-- (==.) :: SqlExpr a -> SqlExpr a -> SqlExpr (Bool)
-- (==.) :: SqlExpr a -> SqlExpr a -> SqlExpr Bool
-- (==.) = unsafeSqlBinOpComposite " = " " AND "
-- @
--
@ -2832,7 +2836,7 @@ makeFrom info mode fs = ret
makeOnClause (ERaw _ f) = first (" ON " <>) (f Never info)
mkExc :: SqlExpr (Bool) -> OnClauseWithoutMatchingJoinException
mkExc :: SqlExpr Bool -> OnClauseWithoutMatchingJoinException
mkExc (ERaw _ f) =
OnClauseWithoutMatchingJoinException $
TL.unpack $ TLB.toLazyText $ fst (f Never info)
@ -3545,7 +3549,7 @@ insertSelectCount = rawEsqueleto INSERT_INTO
-- representation of the clauses passed to an "On" clause.
--
-- @since 3.2.0
renderExpr :: SqlBackend -> SqlExpr (Bool) -> T.Text
renderExpr :: SqlBackend -> SqlExpr Bool -> T.Text
renderExpr sqlBackend e = case e of
ERaw _ mkBuilderValues ->
let (builder, _) = mkBuilderValues Never (sqlBackend, initialIdentState)

View File

@ -1,13 +1,13 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-- | This is an internal module, anything exported by this module
-- may change without a major version bump. Please use only
@ -139,5 +139,5 @@ module Database.Esqueleto.Internal.Language
, subSelectUnsafe
) where
import Database.Esqueleto.Internal.Internal
import Database.Esqueleto.Internal.PersistentImport
import Database.Esqueleto.Internal.Internal
import Database.Esqueleto.Internal.PersistentImport

View File

@ -151,6 +151,7 @@ import Database.Persist.Sql hiding
, delete
, deleteCascadeWhere
, deleteWhereCount
, exists
, getPersistMap
, limitOffsetOrder
, listToJSON
@ -174,5 +175,4 @@ import Database.Persist.Sql hiding
, (>.)
, (>=.)
, (||.)
, exists
)

View File

@ -14,5 +14,5 @@ import Database.Esqueleto.Internal.PersistentImport
-- because MySQL uses `rand()`.
--
-- /Since: 2.6.0/
random_ :: (PersistField a, Num a) => SqlExpr (Value a)
random_ :: (PersistField a, Num a) => SqlExpr a
random_ = unsafeSqlValue "RAND()"

View File

@ -52,18 +52,18 @@ import Database.Persist.Class (OnlyOneUniqueKey)
-- because MySQL uses `rand()`.
--
-- @since 2.6.0
random_ :: (PersistField a, Num a) => SqlExpr (Value a)
random_ :: (PersistField a, Num a) => SqlExpr a
random_ = unsafeSqlValue "RANDOM()"
-- | Empty array literal. (@val []@) does unfortunately not work
emptyArray :: SqlExpr (Value [a])
emptyArray :: SqlExpr [a]
emptyArray = unsafeSqlValue "'{}'"
-- | Coalesce an array with an empty default value
maybeArray ::
(PersistField a, PersistField [a])
=> SqlExpr (Value (Maybe [a]))
-> SqlExpr (Value [a])
=> SqlExpr (Maybe [a])
-> SqlExpr [a]
maybeArray x = coalesceDefault [x] (emptyArray)
-- | Aggregate mode
@ -82,7 +82,7 @@ unsafeSqlAggregateFunction
-> AggMode
-> a
-> [OrderByClause]
-> SqlExpr (Value b)
-> SqlExpr b
unsafeSqlAggregateFunction name mode args orderByClauses = ERaw noMeta $ \_ info ->
let (orderTLB, orderVals) = makeOrderByNoNewline info orderByClauses
-- Don't add a space if we don't have order by clauses
@ -106,14 +106,14 @@ unsafeSqlAggregateFunction name mode args orderByClauses = ERaw noMeta $ \_ info
--- into an array.
arrayAggWith
:: AggMode
-> SqlExpr (Value a)
-> SqlExpr a
-> [OrderByClause]
-> SqlExpr (Value (Maybe [a]))
-> SqlExpr (Maybe [a])
arrayAggWith = unsafeSqlAggregateFunction "array_agg"
--- | (@array_agg@) Concatenate input values, including @NULL@s,
--- into an array.
arrayAgg :: (PersistField a) => SqlExpr (Value a) -> SqlExpr (Value (Maybe [a]))
arrayAgg :: (PersistField a) => SqlExpr a -> SqlExpr (Maybe [a])
arrayAgg x = arrayAggWith AggModeAll x []
-- | (@array_agg@) Concatenate distinct input values, including @NULL@s, into
@ -122,19 +122,19 @@ arrayAgg x = arrayAggWith AggModeAll x []
-- @since 2.5.3
arrayAggDistinct
:: (PersistField a, PersistField [a])
=> SqlExpr (Value a)
-> SqlExpr (Value (Maybe [a]))
=> SqlExpr a
-> SqlExpr (Maybe [a])
arrayAggDistinct x = arrayAggWith AggModeDistinct x []
-- | (@array_remove@) Remove all elements equal to the given value from the
-- array.
--
-- @since 2.5.3
arrayRemove :: SqlExpr (Value [a]) -> SqlExpr (Value a) -> SqlExpr (Value [a])
arrayRemove :: SqlExpr [a] -> SqlExpr a -> SqlExpr [a]
arrayRemove arr elem' = unsafeSqlFunction "array_remove" (arr, elem')
-- | Remove @NULL@ values from an array
arrayRemoveNull :: SqlExpr (Value [Maybe a]) -> SqlExpr (Value [a])
arrayRemoveNull :: SqlExpr [Maybe a] -> SqlExpr [a]
-- This can't be a call to arrayRemove because it changes the value type
arrayRemoveNull x = unsafeSqlFunction "array_remove" (x, unsafeSqlValue "NULL")
@ -144,10 +144,10 @@ arrayRemoveNull x = unsafeSqlFunction "array_remove" (x, unsafeSqlValue "NULL")
stringAggWith ::
SqlString s
=> AggMode -- ^ Aggregate mode (ALL or DISTINCT)
-> SqlExpr (Value s) -- ^ Input values.
-> SqlExpr (Value s) -- ^ Delimiter.
-> SqlExpr s -- ^ Input values.
-> SqlExpr s -- ^ Delimiter.
-> [OrderByClause] -- ^ ORDER BY clauses
-> SqlExpr (Value (Maybe s)) -- ^ Concatenation.
-> SqlExpr (Maybe s) -- ^ Concatenation.
stringAggWith mode expr delim os =
unsafeSqlAggregateFunction "string_agg" mode (expr, delim) os
@ -157,19 +157,19 @@ stringAggWith mode expr delim os =
-- @since 2.2.8
stringAgg ::
SqlString s
=> SqlExpr (Value s) -- ^ Input values.
-> SqlExpr (Value s) -- ^ Delimiter.
-> SqlExpr (Value (Maybe s)) -- ^ Concatenation.
=> SqlExpr s -- ^ Input values.
-> SqlExpr s -- ^ Delimiter.
-> SqlExpr (Maybe s) -- ^ Concatenation.
stringAgg expr delim = stringAggWith AggModeAll expr delim []
-- | (@chr@) Translate the given integer to a character. (Note the result will
-- depend on the character set of your database.)
--
-- @since 2.2.11
chr :: SqlString s => SqlExpr (Value Int) -> SqlExpr (Value s)
chr :: SqlString s => SqlExpr Int -> SqlExpr s
chr = unsafeSqlFunction "chr"
now_ :: SqlExpr (Value UTCTime)
now_ :: SqlExpr UTCTime
now_ = unsafeSqlFunction "NOW" ()
upsert
@ -350,11 +350,11 @@ insertSelectWithConflictCount unique query conflictQuery = do
--
-- @since 3.3.3.3
filterWhere
:: SqlExpr (Value a)
:: SqlExpr a
-- ^ Aggregate function
-> SqlExpr (Value Bool)
-> SqlExpr Bool
-- ^ Filter clause
-> SqlExpr (Value a)
-> SqlExpr a
filterWhere aggExpr clauseExpr = ERaw noMeta $ \_ info ->
let (aggBuilder, aggValues) = case aggExpr of
ERaw _ aggF -> aggF Never info

View File

@ -189,7 +189,7 @@ infixl 6 ||., -., --., #-.
-- @
--
-- @since 3.1.0
(->>.) :: JSONBExpr a -> JSONAccessor -> SqlExpr (Value (Maybe Text))
(->>.) :: JSONBExpr a -> JSONAccessor -> SqlExpr (Maybe Text)
(->>.) value (JSONKey txt) = unsafeSqlBinOp " ->> " value $ val txt
(->>.) value (JSONIndex i) = unsafeSqlBinOp " ->> " value $ val i
@ -253,7 +253,7 @@ infixl 6 ||., -., --., #-.
-- @
--
-- @since 3.1.0
(#>>.) :: JSONBExpr a -> [Text] -> SqlExpr (Value (Maybe Text))
(#>>.) :: JSONBExpr a -> [Text] -> SqlExpr (Maybe Text)
(#>>.) value = unsafeSqlBinOp " #>> " value . mkTextArray
-- | /Requires PostgreSQL version >= 9.4/
@ -275,7 +275,7 @@ infixl 6 ||., -., --., #-.
-- @
--
-- @since 3.1.0
(@>.) :: JSONBExpr a -> JSONBExpr b -> SqlExpr (Value Bool)
(@>.) :: JSONBExpr a -> JSONBExpr b -> SqlExpr Bool
(@>.) = unsafeSqlBinOp " @> "
-- | /Requires PostgreSQL version >= 9.4/
@ -297,7 +297,7 @@ infixl 6 ||., -., --., #-.
-- @
--
-- @since 3.1.0
(<@.) :: JSONBExpr a -> JSONBExpr b -> SqlExpr (Value Bool)
(<@.) :: JSONBExpr a -> JSONBExpr b -> SqlExpr Bool
(<@.) = unsafeSqlBinOp " <@ "
-- | /Requires PostgreSQL version >= 9.4/
@ -320,7 +320,7 @@ infixl 6 ||., -., --., #-.
-- @
--
-- @since 3.1.0
(?.) :: JSONBExpr a -> Text -> SqlExpr (Value Bool)
(?.) :: JSONBExpr a -> Text -> SqlExpr Bool
(?.) value = unsafeSqlBinOp " ?? " value . val
-- | /Requires PostgreSQL version >= 9.4/
@ -343,7 +343,7 @@ infixl 6 ||., -., --., #-.
-- @
--
-- @since 3.1.0
(?|.) :: JSONBExpr a -> [Text] -> SqlExpr (Value Bool)
(?|.) :: JSONBExpr a -> [Text] -> SqlExpr Bool
(?|.) value = unsafeSqlBinOp " ??| " value . mkTextArray
-- | /Requires PostgreSQL version >= 9.4/
@ -366,7 +366,7 @@ infixl 6 ||., -., --., #-.
-- @
--
-- @since 3.1.0
(?&.) :: JSONBExpr a -> [Text] -> SqlExpr (Value Bool)
(?&.) :: JSONBExpr a -> [Text] -> SqlExpr Bool
(?&.) value = unsafeSqlBinOp " ??& " value . mkTextArray
-- | /Requires PostgreSQL version >= 9.5/
@ -579,5 +579,5 @@ infixl 6 ||., -., --., #-.
(#-.) :: JSONBExpr a -> [Text] -> JSONBExpr b
(#-.) value = unsafeSqlBinOp " #- " value . mkTextArray
mkTextArray :: [Text] -> SqlExpr (Value PersistValue)
mkTextArray :: [Text] -> SqlExpr PersistValue
mkTextArray = val . PersistArray . fmap toPersistValue

View File

@ -2,13 +2,13 @@
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# language DerivingStrategies #-}
module Database.Esqueleto.PostgreSQL.JSON.Instances where
import Data.Aeson (FromJSON(..), ToJSON(..), encode, eitherDecodeStrict)
import Data.Aeson (FromJSON(..), ToJSON(..), eitherDecodeStrict, encode)
import Data.Bifunctor (first)
import qualified Data.ByteString.Lazy as BSL (toStrict)
import Data.String (IsString(..))
@ -42,7 +42,7 @@ newtype JSONB a = JSONB { unJSONB :: a }
-- | 'SqlExpr' of a NULL-able 'JSONB' value. Hence the 'Maybe'.
--
-- Note: NULL here is a PostgreSQL NULL, not a JSON 'null'
type JSONBExpr a = SqlExpr (Value (Maybe (JSONB a)))
type JSONBExpr a = SqlExpr (Maybe (JSONB a))
-- | Convenience function to lift a regular value into
-- a 'JSONB' expression.

View File

@ -14,5 +14,5 @@ import Database.Esqueleto.Internal.PersistentImport
-- because MySQL uses `rand()`.
--
-- /Since: 2.6.0/
random_ :: (PersistField a, Num a) => SqlExpr (Value a)
random_ :: (PersistField a, Num a) => SqlExpr a
random_ = unsafeSqlValue "RANDOM()"