on ba684c0 help sign in
rel8/src/Rel8/Expr.hs
122 lines 3.4 kB history raw
1{-# language DataKinds #-}
2{-# language DerivingStrategies #-}
3{-# language FlexibleInstances #-}
4{-# language GADTs #-}
5{-# language MultiParamTypeClasses #-}
6{-# language RoleAnnotations #-}
7{-# language ScopedTypeVariables #-}
8{-# language StandaloneKindSignatures #-}
9{-# language TypeApplications #-}
10{-# language TypeFamilies #-}
11{-# language UndecidableInstances #-}
12{-# language UndecidableSuperClasses #-}
14module Rel8.Expr
15 ( Expr(..)
16 , Col( DB, unDB )
17 )
18where
20-- base
21import Data.Functor.Identity ( Identity )
22import Data.Kind ( Type )
23import Data.String ( IsString, fromString )
24import Prelude hiding ( null )
26-- opaleye
27import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
29-- rel8
30import Rel8.Expr.Null ( liftOpNull, nullify )
31import Rel8.Expr.Opaleye
32 ( castExpr
33 , fromPrimExpr
34 , mapPrimExpr
35 , zipPrimExprsWith
36 )
37import Rel8.Expr.Serialize ( litExpr )
38import Rel8.Schema.Context ( Interpretation, Col )
39import Rel8.Schema.Context.Label ( Labelable, labeler, unlabeler )
40import Rel8.Schema.HTable.Type ( HType( HType ) )
41import Rel8.Schema.Null ( Nullity( Null, NotNull ), Sql, nullable )
42import Rel8.Schema.Spec ( Spec( Spec ) )
43import Rel8.Table ( Table, Columns, Context, fromColumns, toColumns )
44import Rel8.Table.Recontextualize ( Recontextualize )
45import Rel8.Type ( DBType )
46import Rel8.Type.Monoid ( DBMonoid, memptyExpr )
47import Rel8.Type.Num ( DBFractional, DBNum )
48import Rel8.Type.Semigroup ( DBSemigroup, (<>.) )
51-- | Typed SQL expressions.
52type role Expr representational
53type Expr :: Type -> Type
54newtype Expr a = Expr Opaleye.PrimExpr
55 deriving stock Show
58instance Sql DBSemigroup a => Semigroup (Expr a) where
59 (<>) = case nullable @a of
60 Null -> liftOpNull (<>.)
61 NotNull -> (<>.)
62 {-# INLINABLE (<>) #-}
65instance Sql DBMonoid a => Monoid (Expr a) where
66 mempty = case nullable @a of
67 Null -> nullify memptyExpr
68 NotNull -> memptyExpr
69 {-# INLINABLE mempty #-}
72instance (Sql IsString a, Sql DBType a) => IsString (Expr a) where
73 fromString = litExpr . case nullable @a of
74 Null -> Just . fromString
75 NotNull -> fromString
78instance Sql DBNum a => Num (Expr a) where
79 (+) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:+))
80 (*) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:*))
81 (-) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:-))
83 abs = mapPrimExpr (Opaleye.UnExpr Opaleye.OpAbs)
84 negate = mapPrimExpr (Opaleye.UnExpr Opaleye.OpNegate)
86 signum = castExpr . mapPrimExpr (Opaleye.UnExpr (Opaleye.UnOpOther "SIGN"))
88 fromInteger = castExpr . fromPrimExpr . Opaleye.ConstExpr . Opaleye.IntegerLit
91instance Sql DBFractional a => Fractional (Expr a) where
92 (/) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:/))
94 fromRational =
95 castExpr . Expr . Opaleye.ConstExpr . Opaleye.NumericLit . realToFrac
98instance Interpretation Expr where
99 data Col Expr _spec where
100 DB :: {unDB :: Expr a} -> Col Expr ('Spec labels necessity a)
103instance Sql DBType a => Table Expr (Expr a) where
104 type Columns (Expr a) = HType a
105 type Context (Expr a) = Expr
107 toColumns a = HType (DB a)
108 fromColumns (HType (DB a)) = a
111instance Sql DBType a => Recontextualize Expr Expr (Expr a) (Expr a)
114instance Sql DBType a => Recontextualize Expr Identity (Expr a) (Identity a)
117instance Sql DBType a => Recontextualize Identity Expr (Identity a) (Expr a)
120instance Labelable Expr where
121 labeler (DB a) = DB a
122 unlabeler (DB a) = DB a