on 11bcbbb help sign in
rel8/src/Rel8/Type/Eq.hs
114 lines 3.2 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, DiffTime, NominalDiffTime )
43import Data.Time.LocalTime ( TimeOfDay, LocalTime )
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 DiffTime
99instance DBEq NominalDiffTime
100instance DBEq Text
101instance DBEq Lazy.Text
102instance DBEq (CI Text)
103instance DBEq (CI Lazy.Text)
104instance DBEq ByteString
105instance DBEq Lazy.ByteString
106instance DBEq UUID
107instance DBEq Value
108instance Sql DBEq a => DBEq [a]
109instance Sql DBEq a => DBEq (NonEmpty a)
110instance DBEq Opaque
113instance {-# INCOHERENT #-} (HasNullability a, DBEq (Unnullify a)) =>
114 Sql DBEq a