on 00a36f5 help sign in
rel8/src/Rel8/Expr/Eq.hs
132 lines 3.9 kB history raw
1{-# language FlexibleContexts #-}
2{-# language GADTs #-}
3{-# language LambdaCase #-}
4{-# language ViewPatterns #-}
6{-# options_ghc -fno-warn-redundant-constraints #-}
8module Rel8.Expr.Eq
9 ( seq, sne
10 , (==.), (/=.)
11 , (==?), (/=?)
12 , in_
13 )
14where
16-- base
17import Data.Foldable ( toList )
18import Data.List.NonEmpty ( nonEmpty )
19import Prelude hiding ( seq, sin )
21-- opaleye
22import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
24-- rel8
25import Rel8.Expr ( Expr )
26import Rel8.Expr.Bool ( (&&.), (||.), false, or_, coalesce )
27import Rel8.Expr.Null ( isNull, unsafeLiftOpNullable )
28import Rel8.Expr.Opaleye ( fromPrimExpr, toPrimExpr, zipPrimExprsWith )
29import Rel8.Schema.Nullability
30 ( Nullability( NonNullable, Nullable )
31 , Sql, nullabilization
32 )
33import Rel8.Type.Eq ( DBEq )
36eq :: DBEq a => Expr a -> Expr a -> Expr Bool
37eq = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:==))
40ne :: DBEq a => Expr a -> Expr a -> Expr Bool
41ne = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:<>))
44seq :: DBEq db => Nullability db a -> Expr a -> Expr a -> Expr Bool
45seq = \case
46 Nullable -> \ma mb -> isNull ma &&. isNull mb ||. ma ==? mb
47 NonNullable -> eq
50sne :: DBEq db => Nullability db a -> Expr a -> Expr a -> Expr Bool
51sne = \case
52 Nullable -> \ma mb -> isNull ma `ne` isNull mb ||. ma /=? mb
53 NonNullable -> ne
56sin :: (DBEq db, Foldable f)
57 => Nullability db a -> f (Expr a) -> Expr a -> Expr Bool
58sin nullability (toList -> as) a = case nullability of
59 Nullable -> or_ $ map (seq Nullable a) as
60 NonNullable -> case nonEmpty as of
61 Nothing -> false
62 Just xs ->
63 fromPrimExpr $
64 Opaleye.BinExpr Opaleye.OpIn
65 (toPrimExpr a)
66 (Opaleye.ListExpr (toPrimExpr <$> xs))
69-- | Compare two expressions for equality.
70--
71-- This corresponds to the SQL @IS NOT DISTINCT FROM@ operator, and will equate
72-- @null@ values as @true@. This differs from @=@ which would return @null@.
73-- This operator matches Haskell's '==' operator. For an operator identical to
74-- SQL @=@, see '==?'.
75(==.) :: Sql DBEq a => Expr a -> Expr a -> Expr Bool
76(==.) = seq nullabilization
77infix 4 ==.
80-- | Test if two expressions are different (not equal).
81--
82-- This corresponds to the SQL @IS DISTINCT FROM@ operator, and will return
83-- @false@ when comparing two @null@ values. This differs from ordinary @=@
84-- which would return @null@. This operator is closer to Haskell's '=='
85-- operator. For an operator identical to SQL @=@, see '/=?'.
86(/=.) :: Sql DBEq a => Expr a -> Expr a -> Expr Bool
87(/=.) = sne nullabilization
88infix 4 /=.
91-- | Test if two expressions are equal. This operator is usually the best
92-- choice when forming join conditions, as PostgreSQL has a much harder time
93-- optimizing a join that has multiple 'True' conditions.
94--
95-- This corresponds to the SQL @=@ operator, though it will always return a
96-- 'Bool'.
97--
98-- >>> select c $ pure $ lit Nothing ==? lit True
99-- False
100--
101-- >>> select c $ pure $ lit Nothing ==? lit Nothing
102-- False
103(==?) :: DBEq a => Expr (Maybe a) -> Expr (Maybe a) -> Expr Bool
104a ==? b = coalesce $ unsafeLiftOpNullable eq a b
105infix 4 ==?
108-- | Test if two expressions are different.
109--
110-- This corresponds to the SQL @<>@ operator, though it will always return a
111-- 'Bool'.
112--
113-- >>> select c $ pure $ lit Nothing /=? lit True
114-- True
115--
116-- >>> select c $ pure $ lit Nothing /=? lit Nothing
117-- False
118(/=?) :: DBEq a => Expr (Maybe a) -> Expr (Maybe a) -> Expr Bool
119a /=? b = coalesce $ unsafeLiftOpNullable ne a b
120infix 4 /=?
123-- | Like the SQL @IN@ operator, but implemented by folding over a list with
124-- '==.' and '||.'.
125--
126-- >>> select c $ return $ lit (5 :: Int32) `in_` [ lit x | x <- [1..5] ]
127-- [True]
128--
129-- >>> select c $ return $ lit (42 :: Int32) `in_` [ lit x | x <- [1..5] ]
130-- [False]
131in_ :: (Sql DBEq a, Foldable f) => f (Expr a) -> Expr a -> Expr Bool
132in_ = sin nullabilization