on b97cd4e help sign in
rel8/src/Rel8/Type/Eq.hs
113 lines 3.1 kB history raw
1{-# language FlexibleContexts #-}
2{-# language FlexibleInstances #-}
3{-# language MultiParamTypeClasses #-}
4{-# language StandaloneKindSignatures #-}
5{-# language UndecidableInstances #-}
7module Rel8.Type.Eq
8 ( DBEq
9 )
10where
12-- aeson
13import Data.Aeson ( Value )
15-- base
16import Data.List.NonEmpty ( NonEmpty )
17import Data.Int ( Int16, Int32, Int64 )
18import Data.Kind ( Constraint, Type )
19import Prelude
21-- bytestring
22import Data.ByteString ( ByteString )
23import qualified Data.ByteString.Lazy as Lazy ( ByteString )
25-- case-insensitive
26import Data.CaseInsensitive ( CI )
28-- rel8
29import Rel8.Opaque ( Opaque )
30import Rel8.Schema.Nullability ( Unnullify, HasNullability, Sql )
31import Rel8.Type ( DBType )
33-- scientific
34import Data.Scientific ( Scientific )
36-- text
37import Data.Text ( Text )
38import qualified Data.Text.Lazy as Lazy ( Text )
40-- time
41import Data.Time.Calendar ( Day )
42import Data.Time.Clock ( UTCTime )
43import Data.Time.LocalTime ( CalendarDiffTime, LocalTime, TimeOfDay )
45-- uuid
46import Data.UUID ( UUID )
49-- | Database types that can be compared for equality in queries. If a type is
50-- an instance of 'DBEq', it means we can compare expressions for equality
51-- using the SQL @=@ operator.
52--
53-- [ @DBEq@ with @newtype@s ]
54--
55-- Like with 'Rel8.DBType', @DBEq@ plays well with generalized newtype
56-- deriving. The example given for @DBType@ added a @UserId@ @newtype@, but
57-- without a @DBEq@ instance won't actually be able to use that in joins or
58-- where-clauses, because it lacks equality. We can add this by changing our
59-- @newtype@ definition to:
60--
61-- >>> newtype UserId = UserId { toInt32 :: Int32 } deriving newtype (DBType, DBEq)
62--
63-- This will re-use the equality logic for @Int32@, which is to just use the
64-- @=@ operator.
65--
66-- [ @DBEq@ with @DeriveAnyType@ ]
67--
68-- You can also use @DBEq@ with the @DeriveAnyType@ extension to easily add
69-- equality to your type, assuming that @=@ is sufficient on @DBType@ encoded
70-- values. Extending the example from 'Rel8.ReadShow''s 'Rel8.DBType' instance,
71-- we could add equality to @Color@ by writing:
72--
73-- >>> :{
74-- data Color = Red | Green | Blue | Purple | Gold
75-- deriving (Generic, Show, Read, DBEq)
76-- deriving DBType via ReadShow Color
77-- :}
78--
79-- This means @Color@s will be treated as the literal strings @"Red"@,
80-- @"Green"@, etc, in the database, and they can be compared for equality by
81-- just using @=@.
82type DBEq :: Type -> Constraint
83class DBType a => DBEq a
86instance DBEq Bool
87instance DBEq Char
88instance DBEq Int16
89instance DBEq Int32
90instance DBEq Int64
91instance DBEq Float
92instance DBEq Double
93instance DBEq Scientific
94instance DBEq UTCTime
95instance DBEq Day
96instance DBEq LocalTime
97instance DBEq TimeOfDay
98instance DBEq CalendarDiffTime
99instance DBEq Text
100instance DBEq Lazy.Text
101instance DBEq (CI Text)
102instance DBEq (CI Lazy.Text)
103instance DBEq ByteString
104instance DBEq Lazy.ByteString
105instance DBEq UUID
106instance DBEq Value
107instance Sql DBEq a => DBEq [a]
108instance Sql DBEq a => DBEq (NonEmpty a)
109instance DBEq Opaque
112instance {-# INCOHERENT #-} (HasNullability a, DBEq (Unnullify a)) =>
113 Sql DBEq a