{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DefaultSignatures #-} -- | -- Module : Database.Relational.Query.ProjectableClass -- Copyright : 2017 Kei Hibino -- License : BSD3 -- -- Maintainer : ex8k.hibino@gmail.com -- Stability : experimental -- Portability : unknown -- -- This module provides interfaces to preserve constraints of -- direct product projections. module Database.Relational.Query.ProjectableClass ( -- * Interface to specify record constructors. ProductConstructor (..), -- * ProjectableFunctor and ProjectableApplicative ProjectableFunctor (..), ProjectableApplicative (..), ipfmap, -- * Literal SQL terms ShowConstantTermsSQL (..), showConstantTermsSQL, StringSQL, ) where import GHC.Generics (Generic, Rep, U1 (..), K1 (..), M1 (..), (:*:)(..), from) import Data.Monoid (mempty, (<>)) import Data.DList (DList, toList) import Database.Relational.Query.Internal.SQL (StringSQL) -- | Specify tuple like record constructors which are allowed to define 'ProjectableFunctor'. class ProductConstructor r where -- | The constructor which has type 'r'. productConstructor :: r -- | Weaken functor on projections. class ProjectableFunctor p where -- | Method like 'fmap'. (|$|) :: ProductConstructor (a -> b) => (a -> b) -> p a -> p b -- | Same as '|$|' other than using inferred record constructor. ipfmap :: (ProjectableFunctor p, ProductConstructor (a -> b)) => p a -> p b ipfmap = (|$|) productConstructor -- | Weaken applicative functor on projections. class ProjectableFunctor p => ProjectableApplicative p where -- | Method like '<*>'. (|*|) :: p (a -> b) -> p a -> p b infixl 4 |$|, |*| showConstantTermsSQL :: ShowConstantTermsSQL a => a -> [StringSQL] showConstantTermsSQL = toList . showConstantTermsSQL' {- | 'ShowConstantTermsSQL' 'a' is implicit rule to derive function to convert from haskell record type 'a' into constant SQL terms. Generic programming () with default signature is available for 'ShowConstantTermsSQL' class, so you can make instance like below: @ \{\-\# LANGUAGE DeriveGeneric \#\-\} import GHC.Generics (Generic) -- data Foo = Foo { ... } deriving Generic instance ShowConstantTermsSQL Foo @ -} class ShowConstantTermsSQL a where showConstantTermsSQL' :: a -> DList StringSQL default showConstantTermsSQL' :: (Generic a, GShowConstantTermsSQL (Rep a)) => a -> DList StringSQL showConstantTermsSQL' = gShowConstantTermsSQL . from class GShowConstantTermsSQL f where gShowConstantTermsSQL :: f a -> DList StringSQL instance GShowConstantTermsSQL U1 where gShowConstantTermsSQL U1 = mempty instance (GShowConstantTermsSQL a, GShowConstantTermsSQL b) => GShowConstantTermsSQL (a :*: b) where gShowConstantTermsSQL (a :*: b) = gShowConstantTermsSQL a <> gShowConstantTermsSQL b instance GShowConstantTermsSQL a => GShowConstantTermsSQL (M1 i c a) where gShowConstantTermsSQL (M1 a) = gShowConstantTermsSQL a instance ShowConstantTermsSQL a => GShowConstantTermsSQL (K1 i a) where gShowConstantTermsSQL (K1 a) = showConstantTermsSQL' a