on ca7aaef help sign in
rel8/src/Rel8/Expr.hs
126 lines 3.5 kB history raw
1{-# language DataKinds #-}
2{-# language DerivingStrategies #-}
3{-# language FlexibleInstances #-}
4{-# language GADTs #-}
5{-# language MultiParamTypeClasses #-}
6{-# language NamedFieldPuns #-}
7{-# language RoleAnnotations #-}
8{-# language ScopedTypeVariables #-}
9{-# language StandaloneKindSignatures #-}
10{-# language TypeApplications #-}
11{-# language TypeFamilies #-}
12{-# language UndecidableInstances #-}
13{-# language UndecidableSuperClasses #-}
15module Rel8.Expr
16 ( Expr(..)
17 , Col( DB, unDB )
18 )
19where
21-- base
22import Data.Functor.Identity ( Identity )
23import Data.Kind ( Type )
24import Data.String ( IsString, fromString )
25import Prelude hiding ( null )
27-- opaleye
28import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
30-- rel8
31import Rel8.Expr.Null ( liftOpNullable, nullify )
32import Rel8.Expr.Opaleye
33 ( castExpr
34 , fromPrimExpr
35 , mapPrimExpr
36 , zipPrimExprsWith
37 )
38import Rel8.Expr.Serialize ( litExpr )
39import Rel8.Schema.Context ( Interpretation, Col )
40import Rel8.Schema.Context.Label ( Labelable, labeler, unlabeler )
41import Rel8.Schema.HTable.Type ( HType( HType ) )
42import Rel8.Schema.Nullability
43 ( Nullability( Nullable, NonNullable )
44 , Sql, nullabilization
45 )
46import Rel8.Schema.Spec ( Spec( Spec ) )
47import Rel8.Table ( Table, Columns, Context, fromColumns, toColumns )
48import Rel8.Table.Recontextualize ( Recontextualize )
49import Rel8.Type ( DBType )
50import Rel8.Type.Monoid ( DBMonoid, memptyExpr )
51import Rel8.Type.Num ( DBFractional, DBNum )
52import Rel8.Type.Semigroup ( DBSemigroup, (<>.) )
55-- | Typed SQL expressions.
56type role Expr representational
57type Expr :: Type -> Type
58newtype Expr a = Expr Opaleye.PrimExpr
59 deriving stock Show
62instance Sql DBSemigroup a => Semigroup (Expr a) where
63 (<>) = case nullabilization @a of
64 Nullable -> liftOpNullable (<>.)
65 NonNullable -> (<>.)
66 {-# INLINABLE (<>) #-}
69instance Sql DBMonoid a => Monoid (Expr a) where
70 mempty = case nullabilization @a of
71 Nullable -> nullify memptyExpr
72 NonNullable -> memptyExpr
73 {-# INLINABLE mempty #-}
76instance (Sql IsString a, Sql DBType a) => IsString (Expr a) where
77 fromString = litExpr . case nullabilization @a of
78 Nullable -> Just . fromString
79 NonNullable -> fromString
82instance Sql DBNum a => Num (Expr a) where
83 (+) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:+))
84 (*) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:*))
85 (-) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:-))
87 abs = mapPrimExpr (Opaleye.UnExpr Opaleye.OpAbs)
88 negate = mapPrimExpr (Opaleye.UnExpr Opaleye.OpNegate)
90 signum = castExpr . mapPrimExpr (Opaleye.UnExpr (Opaleye.UnOpOther "SIGN"))
92 fromInteger = castExpr . fromPrimExpr . Opaleye.ConstExpr . Opaleye.IntegerLit
95instance Sql DBFractional a => Fractional (Expr a) where
96 (/) = zipPrimExprsWith (Opaleye.BinExpr (Opaleye.:/))
98 fromRational =
99 castExpr . Expr . Opaleye.ConstExpr . Opaleye.NumericLit . realToFrac
102instance Interpretation Expr where
103 data Col Expr _spec where
104 DB :: {unDB :: Expr a} -> Col Expr ('Spec labels necessity a)
107instance Sql DBType a => Table Expr (Expr a) where
108 type Columns (Expr a) = HType a
109 type Context (Expr a) = Expr
111 toColumns a = HType (DB a)
112 fromColumns (HType (DB a)) = a
115instance Sql DBType a => Recontextualize Expr Expr (Expr a) (Expr a)
118instance Sql DBType a => Recontextualize Expr Identity (Expr a) (Identity a)
121instance Sql DBType a => Recontextualize Identity Expr (Identity a) (Expr a)
124instance Labelable Expr where
125 labeler (DB a) = DB a
126 unlabeler (DB a) = DB a