on 29cdfdb help sign in
rel8/src/Rel8/Table/Ord.hs
154 lines 4.8 kB history raw
1{-# language AllowAmbiguousTypes #-}
2{-# language DataKinds #-}
3{-# language DefaultSignatures #-}
4{-# language DisambiguateRecordFields #-}
5{-# language FlexibleContexts #-}
6{-# language FlexibleInstances #-}
7{-# language ScopedTypeVariables #-}
8{-# language StandaloneKindSignatures #-}
9{-# language TypeApplications #-}
10{-# language TypeFamilies #-}
11{-# language TypeOperators #-}
12{-# language UndecidableInstances #-}
13{-# language ViewPatterns #-}
15module Rel8.Table.Ord
16 ( OrdTable( ordTable ), (<:), (<=:), (>:), (>=:), least, greatest
17 )
18where
20-- base
21import Data.Functor.Const ( Const( Const ), getConst )
22import Data.Kind ( Constraint, Type )
23import GHC.Generics ( Rep )
24import Prelude hiding ( seq )
26-- rel8
27import Rel8.Expr ( Expr )
28import Rel8.Expr.Bool ( (||.), (&&.), false, true )
29import Rel8.Expr.Eq ( (==.) )
30import Rel8.Expr.Ord ( (<.), (>.) )
31import Rel8.FCF ( Eval, Exp )
32import Rel8.Generic.Record ( Record )
33import Rel8.Generic.Table.Record ( GTable, GColumns, gtable )
34import Rel8.Schema.Dict ( Dict( Dict ) )
35import Rel8.Schema.HTable ( htabulateA, hfield )
36import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
37import Rel8.Schema.Null (Sql)
38import Rel8.Table ( Columns, toColumns, TColumns )
39import Rel8.Table.Bool ( bool )
40import Rel8.Table.Eq ( EqTable )
41import Rel8.Type.Ord ( DBOrd )
44-- | The class of 'Table's that can be ordered. Ordering on tables is defined
45-- by their lexicographic ordering of all columns, so this class means "all
46-- columns in a 'Table' have an instance of 'DBOrd'".
47type OrdTable :: Type -> Constraint
48class EqTable a => OrdTable a where
49 ordTable :: Columns a (Dict (Sql DBOrd))
51 default ordTable ::
52 ( GTable TOrdTable TColumns (Rep (Record a))
53 , Columns a ~ GColumns TColumns (Rep (Record a))
54 )
55 => Columns a (Dict (Sql DBOrd))
56 ordTable = gtable @TOrdTable @TColumns @(Rep (Record a)) table
57 where
58 table (_ :: proxy x) = ordTable @x
61data TOrdTable :: Type -> Exp Constraint
62type instance Eval (TOrdTable a) = OrdTable a
65instance Sql DBOrd a => OrdTable (Expr a) where
66 ordTable = HIdentity Dict
69instance (OrdTable a, OrdTable b) => OrdTable (a, b)
72instance (OrdTable a, OrdTable b, OrdTable c) => OrdTable (a, b, c)
75instance (OrdTable a, OrdTable b, OrdTable c, OrdTable d) => OrdTable (a, b, c, d)
78instance (OrdTable a, OrdTable b, OrdTable c, OrdTable d, OrdTable e) =>
79 OrdTable (a, b, c, d, e)
82instance
83 ( OrdTable a, OrdTable b, OrdTable c, OrdTable d, OrdTable e, OrdTable f
84 )
85 => OrdTable (a, b, c, d, e, f)
88instance
89 ( OrdTable a, OrdTable b, OrdTable c, OrdTable d, OrdTable e, OrdTable f
90 , OrdTable g
91 )
92 => OrdTable (a, b, c, d, e, f, g)
95-- | Test if one 'Table' sorts before another. Corresponds to comparing all
96-- columns with '<'.
97(<:) :: forall a. OrdTable a => a -> a -> Expr Bool
98(toColumns -> as) <: (toColumns -> bs) =
99 foldr @[] go false $ getConst $ htabulateA $ \field ->
100 case (hfield as field, hfield bs field) of
101 (a, b) -> case hfield (ordTable @a) field of
102 Dict -> Const [(a <. b, a ==. b)]
103 where
104 go (lt, eq) a = lt ||. (eq &&. a)
105infix 4 <:
108-- | Test if one 'Table' sorts before, or is equal to, another. Corresponds to
109-- comparing all columns with '<='.
110(<=:) :: forall a. OrdTable a => a -> a -> Expr Bool
111(toColumns -> as) <=: (toColumns -> bs) =
112 foldr @[] go true $ getConst $ htabulateA $ \field ->
113 case (hfield as field, hfield bs field) of
114 (a, b) -> case hfield (ordTable @a) field of
115 Dict -> Const [(a <. b, a ==. b)]
116 where
117 go (lt, eq) a = lt ||. (eq &&. a)
118infix 4 <=:
121-- | Test if one 'Table' sorts after another. Corresponds to comparing all
122-- columns with '>'.
123(>:) :: forall a. OrdTable a => a -> a -> Expr Bool
124(toColumns -> as) >: (toColumns -> bs) =
125 foldr @[] go false $ getConst $ htabulateA $ \field ->
126 case (hfield as field, hfield bs field) of
127 (a, b) -> case hfield (ordTable @a) field of
128 Dict -> Const [(a >. b, a ==. b)]
129 where
130 go (gt, eq) a = gt ||. (eq &&. a)
131infix 4 >:
134-- | Test if one 'Table' sorts after another. Corresponds to comparing all
135-- columns with '>='.
136(>=:) :: forall a. OrdTable a => a -> a -> Expr Bool
137(toColumns -> as) >=: (toColumns -> bs) =
138 foldr @[] go true $ getConst $ htabulateA $ \field ->
139 case (hfield as field, hfield bs field) of
140 (a, b) -> case hfield (ordTable @a) field of
141 Dict -> Const [(a >. b, a ==. b)]
142 where
143 go (gt, eq) a = gt ||. (eq &&. a)
144infix 4 >=:
147-- | Given two 'Table's, return the table that sorts before the other.
148least :: OrdTable a => a -> a -> a
149least a b = bool a b (a <: b)
152-- | Given two 'Table's, return the table that sorts after the other.
153greatest :: OrdTable a => a -> a -> a
154greatest a b = bool a b (a >: b)