relational-query 0.10.0.1 → 0.10.1.0
raw patch · 23 files changed
+810/−419 lines, 23 filesdep ~names-th
Dependency ranges changed: names-th
Files
- ChangeLog.md +3/−2
- relational-query.cabal +12/−3
- src/Database/Relational.hs +2/−2
- src/Database/Relational/BaseTH.hs +0/−76
- src/Database/Relational/Compat.hs +2/−0
- src/Database/Relational/Derives.hs +1/−2
- src/Database/Relational/Internal/Config.hs +21/−15
- src/Database/Relational/InternalTH/Base.hs +76/−0
- src/Database/Relational/InternalTH/Overloaded.hs +103/−0
- src/Database/Relational/OverloadedInstances.hs +45/−0
- src/Database/Relational/OverloadedProjection.hs +51/−0
- src/Database/Relational/Pi.hs +2/−18
- src/Database/Relational/Pi/Unsafe.hs +2/−2
- src/Database/Relational/Projectable.hs +152/−43
- src/Database/Relational/Projectable/Instances.hs +65/−0
- src/Database/Relational/Projectable/Unsafe.hs +35/−0
- src/Database/Relational/ProjectableExtended.hs +0/−168
- src/Database/Relational/Sequence.hs +118/−0
- src/Database/Relational/TH.hs +93/−65
- src/Database/Relational/Table.hs +14/−7
- src/Database/Relational/TupleInstances.hs +12/−1
- test/Model.hs +1/−0
- test/sqlsEq.hs +0/−15
ChangeLog.md view
@@ -1,8 +1,9 @@ <!-- -*- Markdown -*- --> -## 0.10.0.1+## 0.10.1.0 -- backport fix of fromMaybe record width.+- add overloaded projections.+- add a portable sequence number operation. ## 0.10.0.0
relational-query.cabal view
@@ -1,5 +1,5 @@ name: relational-query-version: 0.10.0.1+version: 0.10.1.0 synopsis: Typeful, Modular, Relational, algebraic query engine description: This package contiains typeful relation structure and relational-algebraic query building DSL which can@@ -43,7 +43,8 @@ Database.Relational.Record Database.Relational.ProjectableClass Database.Relational.Projectable- Database.Relational.ProjectableExtended+ Database.Relational.Projectable.Unsafe+ Database.Relational.Projectable.Instances Database.Relational.TupleInstances Database.Relational.Monad.BaseType Database.Relational.Monad.Class@@ -62,17 +63,21 @@ Database.Relational.Monad.Register Database.Relational.Relation Database.Relational.Set+ Database.Relational.Sequence Database.Relational.Effect Database.Relational.Scalar Database.Relational.Type Database.Relational.Derives- Database.Relational.BaseTH Database.Relational.TH Database.Relational.Compat Database.Relational.Query Database.Relational.Query.Arrow + -- for GHC version equal or more than 8.0+ Database.Relational.OverloadedProjection+ Database.Relational.OverloadedInstances+ other-modules: Database.Relational.Internal.ContextType Database.Relational.Internal.Config@@ -86,6 +91,10 @@ Database.Relational.SqlSyntax.Updates Database.Relational.Monad.Trans.JoinState Database.Relational.Monad.Trans.Qualify+ Database.Relational.InternalTH.Base++ -- for GHC version equal or more than 8.0+ Database.Relational.InternalTH.Overloaded build-depends: base <5 , array
src/Database/Relational.hs view
@@ -19,7 +19,6 @@ module Database.Relational.Record, module Database.Relational.ProjectableClass, module Database.Relational.Projectable,- module Database.Relational.ProjectableExtended, module Database.Relational.TupleInstances, module Database.Relational.Monad.BaseType, module Database.Relational.Monad.Class,@@ -35,6 +34,7 @@ module Database.Relational.Monad.Register, module Database.Relational.Relation, module Database.Relational.Set,+ module Database.Relational.Sequence, module Database.Relational.Scalar, module Database.Relational.Type, module Database.Relational.Effect,@@ -59,7 +59,6 @@ import Database.Relational.Record (RecordList, list) import Database.Relational.ProjectableClass import Database.Relational.Projectable-import Database.Relational.ProjectableExtended import Database.Relational.TupleInstances import Database.Relational.Monad.BaseType import Database.Relational.Monad.Class@@ -83,6 +82,7 @@ import Database.Relational.Monad.Register (Register) import Database.Relational.Relation import Database.Relational.Set+import Database.Relational.Sequence import Database.Relational.Scalar (ScalarDegree) import Database.Relational.Type hiding (unsafeTypedKeyUpdate, unsafeTypedDelete,
− src/Database/Relational/BaseTH.hs
@@ -1,76 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE ConstraintKinds #-}---- |--- Module : Database.Relational.BaseTH--- Copyright : 2017 Kei Hibino--- License : BSD3------ Maintainer : ex8k.hibino@gmail.com--- Stability : experimental--- Portability : unknown------ This module defines templates for internally using.-module Database.Relational.BaseTH (- defineTupleShowConstantInstance,- defineTuplePi,-- defineRecordProjections,- ) where--import Control.Applicative ((<$>))-import Data.List (foldl', inits)-import Language.Haskell.TH- (Q, Name, mkName, normalB, classP, varP,- TypeQ, forallT, varT, tupleT, appT,- Dec, sigD, valD, instanceD,- TyVarBndr (PlainTV), )-import Database.Record.Persistable- (PersistableWidth, persistableWidth,- PersistableRecordWidth, runPersistableRecordWidth)--import Database.Relational.ProjectableClass (ShowConstantTermsSQL (..))-import Database.Relational.Pi.Unsafe (Pi, definePi)---tupleN :: Int -> (([Name], [TypeQ]), TypeQ)-tupleN n = ((ns, vs), foldl' appT (tupleT n) vs)- where- ns = [ mkName $ "a" ++ show j | j <- [1 .. n] ]- vs = map varT ns---- | Make template of 'ShowConstantTermsSQL' instance of tuple type.-defineTupleShowConstantInstance :: Int -> Q [Dec]-defineTupleShowConstantInstance n = do- let ((_, vs), tty) = tupleN n- (:[]) <$> instanceD- -- in template-haskell 2.8 or older, Pred is not Type- (mapM (classP ''ShowConstantTermsSQL . (:[])) vs)- [t| ShowConstantTermsSQL $tty |]- []---- | Make polymorphic projection templates.-defineRecordProjections :: TypeQ -> [Name] -> [Name] -> [TypeQ] -> Q [Dec]-defineRecordProjections tyRec avs sels cts =- fmap concat . sequence $ zipWith3 template cts (inits cts) sels- where- template :: TypeQ -> [TypeQ] -> Name -> Q [Dec]- template ct pcts selN = do- sig <- sigD selN $- forallT (map PlainTV avs)- (mapM (classP ''PersistableWidth . (:[]) . varT) avs)- [t| Pi $tyRec $ct |]- let runPW t = [| runPersistableRecordWidth (persistableWidth :: PersistableRecordWidth $t) |]- val <- valD (varP selN)- (normalB [| definePi $(foldl' (\e t -> [| $e + $(runPW t) |]) [| 0 :: Int |] pcts) |]) []- return [sig, val]---- | Make templates of projection paths for tuple types.-defineTuplePi :: Int -> Q [Dec]-defineTuplePi n =- defineRecordProjections tyRec avs sels cts- where- ((avs, cts), tyRec) = tupleN n- sels = [ mkName $ "tuplePi" ++ show n ++ "_" ++ show i ++ "'"- | i <- [ 0 .. n - 1] ]
src/Database/Relational/Compat.hs view
@@ -104,6 +104,7 @@ unsafeProjectSqlTerms = Projectable.unsafeProjectSqlTerms {-# DEPRECATED unsafeProjectSql "Use Database.Relational.unsafeProjectSql instead of this." #-}+-- | Deprecated. Use Database.Relational.unsafeProjectSql instead of this. unsafeProjectSql :: SqlProjectable p => String -> p a unsafeProjectSql = unsafeProjectSqlTerms . (:[]) . stringSQL @@ -117,5 +118,6 @@ unsafeShowSql' = Record.unsafeStringSql {-# DEPRECATED unsafeShowSql "Use Database.Relational.unsafeShowSql instead of this." #-}+-- | Deprecated. Use Database.Relational.unsafeShowSql instead of this. unsafeShowSql :: ProjectableShowSql p => p a -> String unsafeShowSql = showStringSQL . unsafeShowSql'
src/Database/Relational/Derives.hs view
@@ -36,8 +36,7 @@ import Database.Relational.Table (Table, TableDerivable) import Database.Relational.Pi.Unsafe (Pi, unsafeExpandIndexes) import qualified Database.Relational.Record as Record-import Database.Relational.Projectable (placeholder, (.=.))-import Database.Relational.ProjectableExtended ((!))+import Database.Relational.Projectable (placeholder, (.=.), (!)) import Database.Relational.Monad.Class (wheres) import Database.Relational.Monad.BaseType (Relation, relationWidth) import Database.Relational.Relation
src/Database/Relational/Internal/Config.hs view
@@ -16,6 +16,8 @@ , schemaNameMode , normalizedTableName , verboseAsCompilerWarning+ , disableOverloadedProjection+ , disableSpecializedProjection , identifierQuotation , nameConfig), defaultConfig,@@ -50,25 +52,29 @@ -- | Configuration type. data Config = Config- { productUnitSupport :: !ProductUnitSupport- , chunksInsertSize :: !Int- , schemaNameMode :: !SchemaNameMode- , normalizedTableName :: !Bool- , verboseAsCompilerWarning :: !Bool- , identifierQuotation :: !IdentifierQuotation- , nameConfig :: !NameConfig+ { productUnitSupport :: !ProductUnitSupport+ , chunksInsertSize :: !Int+ , schemaNameMode :: !SchemaNameMode+ , normalizedTableName :: !Bool+ , verboseAsCompilerWarning :: !Bool+ , disableOverloadedProjection :: !Bool+ , disableSpecializedProjection :: !Bool+ , identifierQuotation :: !IdentifierQuotation+ , nameConfig :: !NameConfig } deriving Show -- | Default configuration. defaultConfig :: Config defaultConfig =- Config { productUnitSupport = PUSupported- , chunksInsertSize = 256- , schemaNameMode = SchemaQualified- , normalizedTableName = True- , verboseAsCompilerWarning = False- , identifierQuotation = NoQuotation- , nameConfig = NameConfig { recordConfig = RecordTH.defaultNameConfig- , relationVarName = const varCamelcaseName+ Config { productUnitSupport = PUSupported+ , chunksInsertSize = 256+ , schemaNameMode = SchemaQualified+ , normalizedTableName = True+ , verboseAsCompilerWarning = False+ , disableOverloadedProjection = False+ , disableSpecializedProjection = False+ , identifierQuotation = NoQuotation+ , nameConfig = NameConfig { recordConfig = RecordTH.defaultNameConfig+ , relationVarName = const varCamelcaseName } }
+ src/Database/Relational/InternalTH/Base.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ConstraintKinds #-}++-- |+-- Module : Database.Relational.InternalTH.Base+-- Copyright : 2017 Kei Hibino+-- License : BSD3+--+-- Maintainer : ex8k.hibino@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- This module defines templates for internally using.+module Database.Relational.InternalTH.Base (+ defineTupleShowConstantInstance,+ defineTuplePi,++ defineRecordProjections,+ ) where++import Control.Applicative ((<$>))+import Data.List (foldl', inits)+import Language.Haskell.TH+ (Q, Name, mkName, normalB, classP, varP,+ TypeQ, forallT, varT, tupleT, appT,+ Dec, sigD, valD, instanceD,+ TyVarBndr (PlainTV), )+import Database.Record.Persistable+ (PersistableWidth, persistableWidth,+ PersistableRecordWidth, runPersistableRecordWidth)++import Database.Relational.ProjectableClass (ShowConstantTermsSQL (..))+import Database.Relational.Pi.Unsafe (Pi, definePi)+++tupleN :: Int -> (([Name], [TypeQ]), TypeQ)+tupleN n = ((ns, vs), foldl' appT (tupleT n) vs)+ where+ ns = [ mkName $ "a" ++ show j | j <- [1 .. n] ]+ vs = map varT ns++-- | Make template of 'ShowConstantTermsSQL' instance of tuple type.+defineTupleShowConstantInstance :: Int -> Q [Dec]+defineTupleShowConstantInstance n = do+ let ((_, vs), tty) = tupleN n+ (:[]) <$> instanceD+ -- in template-haskell 2.8 or older, Pred is not Type+ (mapM (classP ''ShowConstantTermsSQL . (:[])) vs)+ [t| ShowConstantTermsSQL $tty |]+ []++-- | Make polymorphic projection templates.+defineRecordProjections :: TypeQ -> [Name] -> [Name] -> [TypeQ] -> Q [Dec]+defineRecordProjections tyRec avs sels cts =+ fmap concat . sequence $ zipWith3 template cts (inits cts) sels+ where+ template :: TypeQ -> [TypeQ] -> Name -> Q [Dec]+ template ct pcts selN = do+ sig <- sigD selN $+ forallT (map PlainTV avs)+ (mapM (classP ''PersistableWidth . (:[]) . varT) avs)+ [t| Pi $tyRec $ct |]+ let runPW t = [| runPersistableRecordWidth (persistableWidth :: PersistableRecordWidth $t) |]+ val <- valD (varP selN)+ (normalB [| definePi $(foldl' (\e t -> [| $e + $(runPW t) :: Int |]) [| 0 :: Int |] pcts) |]) []+ return [sig, val]++-- | Make templates of projection paths for tuple types.+defineTuplePi :: Int -> Q [Dec]+defineTuplePi n =+ defineRecordProjections tyRec avs sels cts+ where+ ((avs, cts), tyRec) = tupleN n+ sels = [ mkName $ "tuplePi" ++ show n ++ "_" ++ show i ++ "'"+ | i <- [ 0 .. n - 1] ]
+ src/Database/Relational/InternalTH/Overloaded.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Module : Database.Relational.InternalTH.Overloaded+-- Copyright : 2017 Kei Hibino+-- License : BSD3+--+-- Maintainer : ex8k.hibino@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- This module defines overloaded projection templates for internally using.+module Database.Relational.InternalTH.Overloaded (+ monomorphicProjection,+ polymorphicProjections,+ tupleProjection,+ ) where++#if __GLASGOW_HASKELL__ >= 800+import Language.Haskell.TH+ (Name, mkName, Q, TypeQ, Dec, instanceD, funD, classP,+ appT, tupleT, varT, litT, strTyLit, clause, normalB)+import Language.Haskell.TH.Lib.Extra (integralE)+import Language.Haskell.TH.Name.CamelCase+ (ConName, conName, toVarExp, toTypeCon)+import Data.List (foldl', inits)+import Data.Array ((!))+import Database.Record.Persistable+ (PersistableWidth, persistableWidth,+ PersistableRecordWidth, runPersistableRecordWidth)+import Database.Record.TH (columnOffsetsVarNameDefault)++import Database.Relational.Pi.Unsafe (definePi)+import Database.Relational.OverloadedProjection (HasProjection (projection))+#else+import Language.Haskell.TH (Name, mkName, Q, TypeQ, appT, tupleT, varT, Dec)+import Language.Haskell.TH.Name.CamelCase (ConName)+import Data.List (foldl')+#endif++-- | Projection template for monomorphic record type.+monomorphicProjection :: ConName+ -> String+ -> Int+ -> TypeQ+ -> Q [Dec]+#if __GLASGOW_HASKELL__ >= 800+monomorphicProjection recName colStr ix colType =+ [d| instance HasProjection $(litT $ strTyLit colStr) $(toTypeCon recName) $colType where+ projection _ = definePi $ $offsetsExp ! $(integralE ix)+ |]+ where+ offsetsExp = toVarExp . columnOffsetsVarNameDefault $ conName recName+#else+monomorphicProjection _ _ _ _ = [d| |]+#endif++-- | Projection templates for record type with type variable.+polymorphicProjections :: TypeQ+ -> [Name]+ -> [String]+ -> [TypeQ]+ -> Q [Dec]+#if __GLASGOW_HASKELL__ >= 800+polymorphicProjections recType avs sels cts =+ sequence $ zipWith3 template sels cts (inits cts)+ where+ template colStr colType pcts =+ instanceD+ (mapM (classP ''PersistableWidth . (:[]) . varT) avs)+ [t| HasProjection $(litT $ strTyLit colStr) $recType $colType |]+ [projectionDec pcts]++projectionDec :: [TypeQ] -> Q Dec+projectionDec cts =+ funD+ (mkName "projection")+ [clause [[p| _ |]]+ (normalB [| definePi $(foldl' (\e t -> [| $e + $(runPW t) |]) [| 0 :: Int |] cts) |])+ []]+ --- In sub-tree, newName "projection" is called by [d| projection .. = |]?+ --- head <$> [d| projection _ = definePi $(foldl' (\e t -> [| $e + $(runPW t) |]) [| 0 :: Int |] cts) |]+ where+ runPW t = [| runPersistableRecordWidth (persistableWidth :: PersistableRecordWidth $t) |]+#else+polymorphicProjections _ _ _ _ = [d| |]+#endif++-- | Projection templates for tuple type.+tupleProjection :: Int -> Q [Dec]+tupleProjection n =+ polymorphicProjections tyRec avs sels cts+ where+ sels = [ "tuplePi" ++ show n ++ "_" ++ show i+ | i <- [ 0 .. n - 1] ]+ ((avs, cts), tyRec) = tupleN+ tupleN :: (([Name], [TypeQ]), TypeQ)+ --- same as tupleN of InternalTH.Base, merge after dropping GHC 7.x+ tupleN = ((ns, vs), foldl' appT (tupleT n) vs)+ where+ ns = [ mkName $ "a" ++ show j | j <- [1 .. n] ]+ vs = map varT ns
+ src/Database/Relational/OverloadedInstances.hs view
@@ -0,0 +1,45 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DataKinds #-}++-- |+-- Module : Database.Relational.OverloadedInstances+-- Copyright : 2017 Kei Hibino+-- License : BSD3+--+-- Maintainer : ex8k.hibino@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- This module provides basic instances of overloaded projections like tuples..+module Database.Relational.OverloadedInstances () where++import Control.Applicative ((<$>))+#if __GLASGOW_HASKELL__ >= 800+import Database.Record.Persistable+ (PersistableWidth, persistableWidth,+ PersistableRecordWidth, runPersistableRecordWidth)++import Database.Relational.Pi.Unsafe (definePi)+import Database.Relational.OverloadedProjection (HasProjection (projection))+#endif+import Database.Relational.InternalTH.Overloaded (tupleProjection)+++$(concat <$> mapM tupleProjection [2 .. 7])+-- Generic instances of tuple types are generated from 2 to 7 in GHC.Generics.++#if __GLASGOW_HASKELL__ >= 800+instance PersistableWidth a =>+ HasProjection "fst" (a, b) a where+ projection _ = definePi 0++instance (PersistableWidth a, PersistableWidth b) =>+ HasProjection "snd" (a, b) b where+ projection _ = definePi $ runPersistableRecordWidth (persistableWidth :: PersistableRecordWidth b)+#endif
+ src/Database/Relational/OverloadedProjection.hs view
@@ -0,0 +1,51 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}++#if __GLASGOW_HASKELL__ >= 800+-- |+-- Module : Database.Relational.OverloadedProjection+-- Copyright : 2017 Kei Hibino+-- License : BSD3+--+-- Maintainer : ex8k.hibino@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- This module provides interfaces of overloaded projections.+module Database.Relational.OverloadedProjection (+ HasProjection (..),+ ) where++import GHC.OverloadedLabels (IsLabel(..))+import GHC.TypeLits (Symbol)++import Database.Record (PersistableWidth)+import Database.Relational.SqlSyntax (PI)+import Database.Relational.Pi (Pi)+import Database.Relational.Projectable ((!))+++data PiLabel (l :: Symbol) = GetPi++-- | Projection interface to implement Pi with row polymorphism.+class HasProjection l a b | l a -> b where+ projection :: PiLabel l -> Pi a b++-- | Derive 'IsLabel' instance from 'HasProjection'.+instance HasProjection l a b => IsLabel l (Pi a b) where+ fromLabel _ = projection (GetPi :: PiLabel l)++-- | Derive 'PI' label.+instance (PersistableWidth a, IsLabel l (Pi a b))+ => IsLabel l (PI c a b) where+ fromLabel s = (! fromLabel s)+#else+module Database.Relational.OverloadedProjection () where+#endif
src/Database/Relational/Pi.hs view
@@ -13,30 +13,14 @@ -- * Projection path Pi, (<.>), (<?.>), (<?.?>), - id', fst', snd'+ id', ) where import qualified Control.Category as Category-import Database.Record- (PersistableWidth, persistableWidth, PersistableRecordWidth)-import Database.Record.Persistable- (runPersistableRecordWidth) -import Database.Relational.Pi.Unsafe- (Pi, (<.>), (<?.>), (<?.?>), definePi)+import Database.Relational.Pi.Unsafe (Pi, (<.>), (<?.>), (<?.?>)) -- | Identity projection path. id' :: Pi a a id' = Category.id---- | Projection path for fst of tuple.-fst' :: PersistableWidth a => Pi (a, b) a -- ^ Projection path of fst.-fst' = definePi 0--snd'' :: PersistableWidth b => PersistableRecordWidth a -> Pi (a, b) b-snd'' wa = definePi (runPersistableRecordWidth wa)---- | Projection path for snd of tuple.-snd' :: (PersistableWidth a, PersistableWidth b) => Pi (a, b) b -- ^ Projection path of snd.-snd' = snd'' persistableWidth
src/Database/Relational/Pi/Unsafe.hs view
@@ -68,14 +68,14 @@ (pbc, wc) = g $ wbf wb in (pab `unsafePiAppend'` pbc, wcf wc) --- | Unsafely untype key to expand indexes.+-- | Unsafely expand indexes from key. unsafeExpandIndexes' :: PersistableRecordWidth a -> Pi a b -> [Int] unsafeExpandIndexes' wa (Pi f) = d $ f wa where d (Map is, _) = is d (Leftest i, w) = [ i .. i + w' - 1 ] where w' = runPersistableRecordWidth w --- | Unsafely untype key to expand indexes.+-- | Unsafely expand indexes from key. Infered width version. unsafeExpandIndexes :: PersistableWidth a => Pi a b -> [Int] unsafeExpandIndexes = unsafeExpandIndexes' persistableWidth
src/Database/Relational/Projectable.hs view
@@ -59,14 +59,28 @@ -- * 'Maybe' type projecitoins ProjectableMaybe (just, flattenMaybe),++ -- * Projection for nested 'Maybe's+ ProjectableFlattenMaybe (flatten),++ flattenPiMaybe,++ -- * Get narrower records+ (!), (?), (??), (?!), (?!?), (!??),++ -- * Aggregate functions+ unsafeAggregateOp,+ count,+ sum', sumMaybe, avg, avgMaybe,+ max', maxMaybe, min', minMaybe,+ every, any', some', ) where import Prelude hiding (pi) import Data.String (IsString) import Data.Functor.ProductIsomorphic- (ProductIsoFunctor, (|$|), ProductIsoApplicative, pureP, (|*|),- ProductIsoEmpty, pureE, peRight, peLeft, )+ ((|$|), ProductIsoApplicative, pureP, (|*|), ) import Language.SQL.Keyword (Keyword) import qualified Language.SQL.Keyword as SQL@@ -76,41 +90,21 @@ HasColumnConstraint, NotNull) import Database.Record.Persistable (runPersistableRecordWidth) -import Database.Relational.Internal.ContextType- (Flat, Aggregated, Exists, OverWindow)+import Database.Relational.Internal.ContextType (Flat, Exists, OverWindow) import Database.Relational.Internal.String (StringSQL, stringSQL, showStringSQL) import Database.Relational.SqlSyntax (Record, Predicate) import qualified Database.Relational.SqlSyntax as Syntax import Database.Relational.Pure () import Database.Relational.TupleInstances ()+import Database.Relational.Pi (Pi) import Database.Relational.ProjectableClass (ShowConstantTermsSQL, showConstantTermsSQL, ) import Database.Relational.Record (RecordList) import qualified Database.Relational.Record as Record----- | Interface to project SQL terms unsafely.-class SqlContext c where- -- | Unsafely project from SQL expression terms.- unsafeProjectSqlTerms :: [StringSQL]- -> Record c t---- | Unsafely make 'Record' from SQL terms.-instance SqlContext Flat where- unsafeProjectSqlTerms = Record.unsafeFromSqlTerms---- | Unsafely make 'Record' from SQL terms.-instance SqlContext Aggregated where- unsafeProjectSqlTerms = Record.unsafeFromSqlTerms---- | Unsafely make 'Record' from SQL terms.-instance SqlContext OverWindow where- unsafeProjectSqlTerms = Record.unsafeFromSqlTerms--class SqlContext c => OperatorContext c-instance OperatorContext Flat-instance OperatorContext Aggregated+import Database.Relational.Projectable.Unsafe+ (SqlContext (..), OperatorContext, AggregatedContext, PlaceHolders (..))+import Database.Relational.Projectable.Instances () -- | Unsafely Project single SQL term.@@ -306,7 +300,7 @@ unsafeCastProjectable :: SqlContext c => Record c a -> Record c b-unsafeCastProjectable = Syntax.record . Syntax.untypeRecord+unsafeCastProjectable = unsafeProjectSql' . unsafeShowSql' -- | Number fromIntegral uni-operator. fromIntegral' :: (SqlContext c, Integral a, Num b)@@ -443,9 +437,6 @@ cumeDist :: Record OverWindow Double cumeDist = unsafeUniTermFunction SQL.CUME_DIST --- | Placeholder parameter type which has real parameter type arguemnt 'p'.-data PlaceHolders p = PlaceHolders- -- | Unsafely add placeholder parameter to queries. unsafeAddPlaceHolders :: Functor f => f a -> f (PlaceHolders p, a) unsafeAddPlaceHolders = fmap ((,) PlaceHolders)@@ -515,21 +506,139 @@ just = Record.just flattenMaybe = Record.flattenMaybe --- | Zipping except for identity element laws against placeholder parameter type.-instance ProductIsoEmpty PlaceHolders () where- pureE = unsafePlaceHolders- peRight = unsafeCastPlaceHolders- peLeft = unsafeCastPlaceHolders --- | Compose seed of record type 'PlaceHolders'.-instance ProductIsoFunctor PlaceHolders where- _ |$| PlaceHolders = PlaceHolders+-- | Unsafely make aggregation uni-operator from SQL keyword.+unsafeAggregateOp :: (AggregatedContext ac, SqlContext ac)+ => SQL.Keyword -> Record Flat a -> Record ac b+unsafeAggregateOp op = unsafeUniOp ((op SQL.<++>) . SQL.paren) --- | Compose record type 'PlaceHolders' using applicative style.-instance ProductIsoApplicative PlaceHolders where- pureP _ = unsafeCastPlaceHolders unitPH- pf |*| pa = unsafeCastPlaceHolders (pf >< pa)+-- | Aggregation function COUNT.+count :: (Integral b, AggregatedContext ac, SqlContext ac)+ => Record Flat a -> Record ac b+count = unsafeAggregateOp SQL.COUNT +-- | Aggregation function SUM.+sumMaybe :: (Num a, AggregatedContext ac, SqlContext ac)+ => Record Flat (Maybe a) -> Record ac (Maybe a)+sumMaybe = unsafeAggregateOp SQL.SUM++-- | Aggregation function SUM.+sum' :: (Num a, AggregatedContext ac, SqlContext ac)+ => Record Flat a -> Record ac (Maybe a)+sum' = sumMaybe . Record.just++-- | Aggregation function AVG.+avgMaybe :: (Num a, Fractional b, AggregatedContext ac, SqlContext ac)+ => Record Flat (Maybe a) -> Record ac (Maybe b)+avgMaybe = unsafeAggregateOp SQL.AVG++-- | Aggregation function AVG.+avg :: (Num a, Fractional b, AggregatedContext ac, SqlContext ac)+ => Record Flat a -> Record ac (Maybe b)+avg = avgMaybe . Record.just++-- | Aggregation function MAX.+maxMaybe :: (Ord a, AggregatedContext ac, SqlContext ac)+ => Record Flat (Maybe a) -> Record ac (Maybe a)+maxMaybe = unsafeAggregateOp SQL.MAX++-- | Aggregation function MAX.+max' :: (Ord a, AggregatedContext ac, SqlContext ac)+ => Record Flat a -> Record ac (Maybe a)+max' = maxMaybe . Record.just++-- | Aggregation function MIN.+minMaybe :: (Ord a, AggregatedContext ac, SqlContext ac)+ => Record Flat (Maybe a) -> Record ac (Maybe a)+minMaybe = unsafeAggregateOp SQL.MIN++-- | Aggregation function MIN.+min' :: (Ord a, AggregatedContext ac, SqlContext ac)+ => Record Flat a -> Record ac (Maybe a)+min' = minMaybe . Record.just++-- | Aggregation function EVERY.+every :: (AggregatedContext ac, SqlContext ac)+ => Predicate Flat -> Record ac (Maybe Bool)+every = unsafeAggregateOp SQL.EVERY++-- | Aggregation function ANY.+any' :: (AggregatedContext ac, SqlContext ac)+ => Predicate Flat -> Record ac (Maybe Bool)+any' = unsafeAggregateOp SQL.ANY++-- | Aggregation function SOME.+some' :: (AggregatedContext ac, SqlContext ac)+ => Predicate Flat -> Record ac (Maybe Bool)+some' = unsafeAggregateOp SQL.SOME++-- | Get narrower record along with projection path.+(!) :: PersistableWidth a+ => Record c a -- ^ Source 'Record'+ -> Pi a b -- ^ Record path+ -> Record c b -- ^ Narrower projected object+(!) = Record.pi++-- | Get narrower record along with projection path+-- 'Maybe' phantom functor is 'map'-ed.+(?!) :: PersistableWidth a+ => Record c (Maybe a) -- ^ Source 'Record'. 'Maybe' type+ -> Pi a b -- ^ Record path+ -> Record c (Maybe b) -- ^ Narrower projected object. 'Maybe' type result+(?!) = Record.piMaybe++-- | Get narrower record along with projection path+-- and project into result record type.+-- Source record 'Maybe' phantom functor and projection path leaf 'Maybe' functor are 'join'-ed.+(?!?) :: PersistableWidth a+ => Record c (Maybe a) -- ^ Source 'Record'. 'Maybe' phantom type+ -> Pi a (Maybe b) -- ^ Record path. 'Maybe' type leaf+ -> Record c (Maybe b) -- ^ Narrower projected object. 'Maybe' phantom type result+(?!?) = Record.piMaybe'+++-- | Interface to compose phantom 'Maybe' nested type.+class ProjectableFlattenMaybe a b where+ flatten :: ProjectableMaybe p => p a -> p b++-- | Compose 'Maybe' type in record phantom type.+instance ProjectableFlattenMaybe (Maybe a) b+ => ProjectableFlattenMaybe (Maybe (Maybe a)) b where+ flatten = flatten . flattenMaybe++-- | Not 'Maybe' type is not processed.+instance ProjectableFlattenMaybe (Maybe a) (Maybe a) where+ flatten = id++-- | Get narrower record with flatten leaf phantom Maybe types along with projection path.+flattenPiMaybe :: (PersistableWidth a, ProjectableMaybe (Record cont), ProjectableFlattenMaybe (Maybe b) c)+ => Record cont (Maybe a) -- ^ Source 'Record'. 'Maybe' phantom type+ -> Pi a b -- ^ Projection path+ -> Record cont c -- ^ Narrower 'Record'. Flatten 'Maybe' phantom type+flattenPiMaybe p = flatten . Record.piMaybe p++-- | Get narrower record with flatten leaf phantom Maybe types along with projection path.+(!??) :: (PersistableWidth a, ProjectableMaybe (Record cont), ProjectableFlattenMaybe (Maybe b) c)+ => Record cont (Maybe a) -- ^ Source 'Record'. 'Maybe' phantom type+ -> Pi a b -- ^ Projection path+ -> Record cont c -- ^ Narrower flatten and projected object.+(!??) = flattenPiMaybe++-- | Same as '(?!)'. Use this operator like '(? #foo) mayX'.+(?) :: PersistableWidth a+ => Record c (Maybe a) -- ^ Source 'Record'. 'Maybe' type+ -> Pi a b -- ^ Record path+ -> Record c (Maybe b) -- ^ Narrower projected object. 'Maybe' type result+(?) = (?!)++-- | Same as '(?!?)'. Use this operator like '(?? #foo) mayX'.+(??) :: PersistableWidth a+ => Record c (Maybe a) -- ^ Source 'Record'. 'Maybe' phantom type+ -> Pi a (Maybe b) -- ^ Record path. 'Maybe' type leaf+ -> Record c (Maybe b) -- ^ Narrower projected object. 'Maybe' phantom type result+(??) = (?!?)++infixl 8 !, ?, ??, ?!, ?!?, !?? infixl 7 .*., ./., ?*?, ?/? infixl 6 .+., .-., ?+?, ?-? infixl 5 .||., ?||?
+ src/Database/Relational/Projectable/Instances.hs view
@@ -0,0 +1,65 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE MultiParamTypeClasses #-}++-- |+-- Module : Database.Relational.Projectable.Instances+-- Copyright : 2017 Kei Hibino+-- License : BSD3+--+-- Maintainer : ex8k.hibino@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- This module provides instances between projected terms and SQL terms.+module Database.Relational.Projectable.Instances () where++import Data.Functor.ProductIsomorphic+ (ProductIsoFunctor, (|$|), ProductIsoApplicative, pureP, (|*|),+ ProductIsoEmpty, pureE, peRight, peLeft, )++import Database.Relational.Internal.ContextType+ (Flat, Aggregated, OverWindow)+import qualified Database.Relational.Record as Record+import Database.Relational.Projectable.Unsafe+ (SqlContext (..), OperatorContext, AggregatedContext, PlaceHolders (..))++-- context++-- | Unsafely make 'Record' from SQL terms.+instance SqlContext Flat where+ unsafeProjectSqlTerms = Record.unsafeFromSqlTerms++-- | Unsafely make 'Record' from SQL terms.+instance SqlContext Aggregated where+ unsafeProjectSqlTerms = Record.unsafeFromSqlTerms++-- | Unsafely make 'Record' from SQL terms.+instance SqlContext OverWindow where+ unsafeProjectSqlTerms = Record.unsafeFromSqlTerms++-- | full SQL expression is availabe in Flat context+instance OperatorContext Flat+-- | full SQL expression is availabe in Aggregated context+instance OperatorContext Aggregated++-- | 'Aggregated' context is aggregated context+instance AggregatedContext Aggregated+-- | 'OverWindow' context is aggregated context+instance AggregatedContext OverWindow++-- placeholders++-- | Zipping except for identity element laws against placeholder parameter type.+instance ProductIsoEmpty PlaceHolders () where+ pureE = PlaceHolders+ peRight _ = PlaceHolders+ peLeft _ = PlaceHolders++-- | Compose seed of record type 'PlaceHolders'.+instance ProductIsoFunctor PlaceHolders where+ _ |$| PlaceHolders = PlaceHolders++-- | Compose record type 'PlaceHolders' using applicative style.+instance ProductIsoApplicative PlaceHolders where+ pureP _ = PlaceHolders+ _pf |*| _pa = PlaceHolders
+ src/Database/Relational/Projectable/Unsafe.hs view
@@ -0,0 +1,35 @@+-- |+-- Module : Database.Relational.Projectable.Unsafe+-- Copyright : 2017 Kei Hibino+-- License : BSD3+--+-- Maintainer : ex8k.hibino@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- This module provides unsafe interfaces between projected terms and SQL terms.+module Database.Relational.Projectable.Unsafe (+ SqlContext (..), OperatorContext, AggregatedContext,+ PlaceHolders (..)+ ) where++import Database.Relational.Internal.String (StringSQL)+import Database.Relational.SqlSyntax (Record)++-- | Interface to project SQL terms unsafely.+class SqlContext c where+ -- | Unsafely project from SQL expression terms.+ unsafeProjectSqlTerms :: [StringSQL]+ -> Record c t++-- | Constraint to restrict context of full SQL expressions.+-- For example, the expression at the left of OVER clause+-- is not allowed using full SQL expression.+class SqlContext c => OperatorContext c++-- | Constraint to restrict context of aggregated SQL context.+class AggregatedContext ac+++-- | Placeholder parameter type which has real parameter type arguemnt 'p'.+data PlaceHolders p = PlaceHolders
− src/Database/Relational/ProjectableExtended.hs
@@ -1,168 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}---- |--- Module : Database.Relational.ProjectableExtended--- Copyright : 2013-2017 Kei Hibino--- License : BSD3------ Maintainer : ex8k.hibino@gmail.com--- Stability : experimental--- Portability : unknown------ This module defines operators on various projected records.-module Database.Relational.ProjectableExtended (- -- * Projection for nested 'Maybe's- ProjectableFlattenMaybe (flatten),-- flattenPiMaybe,-- -- * Get narrower records- (!), (?!), (?!?), (!??),-- -- * Aggregate functions- unsafeAggregateOp,- count,- sum', sumMaybe, avg, avgMaybe,- max', maxMaybe, min', minMaybe,- every, any', some',- ) where--import Prelude hiding (pi)--import qualified Language.SQL.Keyword as SQL-import Database.Record (PersistableWidth)--import Database.Relational.Internal.ContextType (Flat, Aggregated, OverWindow)-import Database.Relational.SqlSyntax (Predicate, Record, )--import qualified Database.Relational.Record as Record-import Database.Relational.Projectable- (unsafeUniOp, ProjectableMaybe (flattenMaybe), SqlContext)-import Database.Relational.Pi (Pi)---class AggregatedContext ac-instance AggregatedContext Aggregated-instance AggregatedContext OverWindow---- | Unsafely make aggregation uni-operator from SQL keyword.-unsafeAggregateOp :: (AggregatedContext ac, SqlContext ac)- => SQL.Keyword -> Record Flat a -> Record ac b-unsafeAggregateOp op = unsafeUniOp ((op SQL.<++>) . SQL.paren)---- | Aggregation function COUNT.-count :: (Integral b, AggregatedContext ac, SqlContext ac)- => Record Flat a -> Record ac b-count = unsafeAggregateOp SQL.COUNT---- | Aggregation function SUM.-sumMaybe :: (Num a, AggregatedContext ac, SqlContext ac)- => Record Flat (Maybe a) -> Record ac (Maybe a)-sumMaybe = unsafeAggregateOp SQL.SUM---- | Aggregation function SUM.-sum' :: (Num a, AggregatedContext ac, SqlContext ac)- => Record Flat a -> Record ac (Maybe a)-sum' = sumMaybe . Record.just---- | Aggregation function AVG.-avgMaybe :: (Num a, Fractional b, AggregatedContext ac, SqlContext ac)- => Record Flat (Maybe a) -> Record ac (Maybe b)-avgMaybe = unsafeAggregateOp SQL.AVG---- | Aggregation function AVG.-avg :: (Num a, Fractional b, AggregatedContext ac, SqlContext ac)- => Record Flat a -> Record ac (Maybe b)-avg = avgMaybe . Record.just---- | Aggregation function MAX.-maxMaybe :: (Ord a, AggregatedContext ac, SqlContext ac)- => Record Flat (Maybe a) -> Record ac (Maybe a)-maxMaybe = unsafeAggregateOp SQL.MAX---- | Aggregation function MAX.-max' :: (Ord a, AggregatedContext ac, SqlContext ac)- => Record Flat a -> Record ac (Maybe a)-max' = maxMaybe . Record.just---- | Aggregation function MIN.-minMaybe :: (Ord a, AggregatedContext ac, SqlContext ac)- => Record Flat (Maybe a) -> Record ac (Maybe a)-minMaybe = unsafeAggregateOp SQL.MIN---- | Aggregation function MIN.-min' :: (Ord a, AggregatedContext ac, SqlContext ac)- => Record Flat a -> Record ac (Maybe a)-min' = minMaybe . Record.just---- | Aggregation function EVERY.-every :: (AggregatedContext ac, SqlContext ac)- => Predicate Flat -> Record ac (Maybe Bool)-every = unsafeAggregateOp SQL.EVERY---- | Aggregation function ANY.-any' :: (AggregatedContext ac, SqlContext ac)- => Predicate Flat -> Record ac (Maybe Bool)-any' = unsafeAggregateOp SQL.ANY---- | Aggregation function SOME.-some' :: (AggregatedContext ac, SqlContext ac)- => Predicate Flat -> Record ac (Maybe Bool)-some' = unsafeAggregateOp SQL.SOME---- | Get narrower record along with projection path.-(!) :: PersistableWidth a- => Record c a -- ^ Source 'Record'- -> Pi a b -- ^ Record path- -> Record c b -- ^ Narrower projected object-(!) = Record.pi---- | Get narrower record along with projection path--- 'Maybe' phantom functor is 'map'-ed.-(?!) :: PersistableWidth a- => Record c (Maybe a) -- ^ Source 'Record'. 'Maybe' type- -> Pi a b -- ^ Record path- -> Record c (Maybe b) -- ^ Narrower projected object. 'Maybe' type result-(?!) = Record.piMaybe---- | Get narrower record along with projection path--- and project into result record type.--- Source record 'Maybe' phantom functor and projection path leaf 'Maybe' functor are 'join'-ed.-(?!?) :: PersistableWidth a- => Record c (Maybe a) -- ^ Source 'Record'. 'Maybe' phantom type- -> Pi a (Maybe b) -- ^ Record path. 'Maybe' type leaf- -> Record c (Maybe b) -- ^ Narrower projected object. 'Maybe' phantom type result-(?!?) = Record.piMaybe'----- | Interface to compose phantom 'Maybe' nested type.-class ProjectableFlattenMaybe a b where- flatten :: ProjectableMaybe p => p a -> p b---- | Compose 'Maybe' type in record phantom type.-instance ProjectableFlattenMaybe (Maybe a) b- => ProjectableFlattenMaybe (Maybe (Maybe a)) b where- flatten = flatten . flattenMaybe---- | Not 'Maybe' type is not processed.-instance ProjectableFlattenMaybe (Maybe a) (Maybe a) where- flatten = id---- | Get narrower record with flatten leaf phantom Maybe types along with projection path.-flattenPiMaybe :: (PersistableWidth a, ProjectableMaybe (Record cont), ProjectableFlattenMaybe (Maybe b) c)- => Record cont (Maybe a) -- ^ Source 'Record'. 'Maybe' phantom type- -> Pi a b -- ^ Projection path- -> Record cont c -- ^ Narrower 'Record'. Flatten 'Maybe' phantom type-flattenPiMaybe p = flatten . Record.piMaybe p---- | Get narrower record with flatten leaf phantom Maybe types along with projection path.-(!??) :: (PersistableWidth a, ProjectableMaybe (Record cont), ProjectableFlattenMaybe (Maybe b) c)- => Record cont (Maybe a) -- ^ Source 'Record'. 'Maybe' phantom type- -> Pi a b -- ^ Projection path- -> Record cont c -- ^ Narrower flatten and projected object.-(!??) = flattenPiMaybe---infixl 8 !, ?!, ?!?, !??
+ src/Database/Relational/Sequence.hs view
@@ -0,0 +1,118 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleContexts #-}++-- |+-- Module : Database.Relational.Sequence+-- Copyright : 2017 Kei Hibino+-- License : BSD3+--+-- Maintainer : ex8k.hibino@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- This module provides structures about sequence tables.+module Database.Relational.Sequence (+ Sequence (..), seqRelation,+ unsafeSpecifySequence,++ SequenceDerivable (..),++ Binding (..), fromRelation,++ Number, unsafeSpecifyNumber, extractNumber,+ ($$!), ($$),++ updateNumber,+ ) where++import Prelude hiding (seq)++import Database.Record (PersistableWidth)+import Database.Relational.Monad.Class (wheres)+import Database.Relational.Monad.BaseType (Relation)+import Database.Relational.Monad.Trans.Assigning ((<-#))+import Database.Relational.Table (TableDerivable, derivedTable, Table)+import Database.Relational.Pi (Pi)+import Database.Relational.Projectable ((.<=.), value, unitPlaceHolder, (!))+import Database.Relational.ProjectableClass (ShowConstantTermsSQL)+import Database.Relational.Relation (tableOf)+import qualified Database.Relational.Relation as Relation+import Database.Relational.Effect (updateTarget')+import Database.Relational.Type (Update, typedUpdate)+++-- | Basic record to express sequence table+data Sequence s i =+ Sequence+ { seqTable :: Table s+ , seqExtract :: s -> i+ , seqKey :: Pi s i+ }++-- | Unsafely specify sequence table.+unsafeSpecifySequence :: TableDerivable s => (s -> i) -> Pi s i -> Sequence s i+unsafeSpecifySequence = Sequence derivedTable++-- | Infer 'Relation' of sequence table+seqRelation :: TableDerivable s => Sequence s i -> Relation () s+seqRelation = Relation.table . seqTable++-- | 'Sequence' derivation rule+class TableDerivable s => SequenceDerivable s i | s -> i where+ derivedSequence :: Sequence s i++-- | Derivation rule for binding between 'Table' and 'Sequence'+class (TableDerivable r, SequenceDerivable s i)+ => Binding r s i | r -> s where+ fromTable :: Table r -> Sequence s i+ fromTable = const derivedSequence++-- | Derive 'Sequence' from corresponding 'Relation'+fromRelation :: Binding r s i+ => Relation () r+ -> Sequence s i+fromRelation = fromTable . tableOf++-- | Sequence number type for record type 'r'+newtype Number r i = Number i deriving (Eq, Ord, Show)++-- | Unsafely specify sequence number.+unsafeSpecifyNumber :: Binding r s i => i -> Number r i+unsafeSpecifyNumber = Number++-- | Get untyped sequence number.+extractNumber :: Number r i -> i+extractNumber (Number i) = i++-- | Unsafely apply sequence number.+($$!) :: (i -> r) -- ^ sequence number should be passed to proper field of record+ -> Number r i+ -> r+($$!) = (. extractNumber)++-- | Unsafely apply sequence number. Only safe to build corresponding record type.+($$) :: Binding r s i+ => (i -> r) -- ^ sequence number should be passed to proper field of record+ -> Number r i+ -> r+($$) = ($$!)++{-+updateNumber :: PersistableWidth p => Sequence r p -> Update (p, p)+updateNumber seqt = typedUpdate (table seqt) . updateTarget' $ \ proj -> do+ (phv', ()) <- placeholder (\ph -> key seqt <-# ph)+ (phx', ()) <- placeholder (\ph -> wheres $ proj ! key seqt .<=. ph)+ return $ (,) |$| phv' |*| phx'+ -}++-- | Update statement for sequence table+updateNumber :: (PersistableWidth s, Integral i, ShowConstantTermsSQL i)+ => i -- ^ sequence number to set. expect not SQL injectable.+ -> Sequence s i -- ^ sequence table+ -> Update ()+updateNumber i seqt = typedUpdate (seqTable seqt) . updateTarget' $ \ proj -> do+ let iv = value i+ seqKey seqt <-# iv+ wheres $ proj ! seqKey seqt .<=. iv -- fool proof+ return unitPlaceHolder
src/Database/Relational/TH.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ExplicitForAll #-} {-# LANGUAGE ParallelListComp #-}+{-# LANGUAGE CPP #-} -- | -- Module : Database.Relational.TH@@ -36,7 +37,8 @@ defineScalarDegree, -- * Column projections- defineColumns, defineColumnsDefault,+ defineColumnsDefault, defineOverloadedColumnsDefault,+ defineColumns, defineOverloadedColumns, defineTuplePi, @@ -58,6 +60,7 @@ -- * Reify makeRelationalRecordDefault,+ makeRelationalRecordDefault', reifyRelation, ) where @@ -73,7 +76,8 @@ TypeQ, Type (AppT, ConT), varT, tupleT, appT, arrowT, classP) import Language.Haskell.TH.Compat.Reify (unVarI) import Language.Haskell.TH.Name.CamelCase- (VarName, varName, ConName (ConName), conName, varNameWithPrefix, varCamelcaseName, toVarExp, toTypeCon)+ (VarName, varName, ConName (ConName), conName,+ varNameWithPrefix, varCamelcaseName, toVarExp, toTypeCon) import Language.Haskell.TH.Lib.Extra (simpleValD, maybeD, integralE) import Database.Record.TH@@ -83,15 +87,16 @@ import Database.Relational (Table, Pi, id', Relation, ShowConstantTermsSQL,- NameConfig (..), SchemaNameMode (..), IdentifierQuotation (..),- Config (normalizedTableName, schemaNameMode, nameConfig, identifierQuotation),+ NameConfig (..), SchemaNameMode (..), IdentifierQuotation (..), defaultConfig,+ Config (normalizedTableName, disableOverloadedProjection, disableSpecializedProjection,+ schemaNameMode, nameConfig, identifierQuotation), relationalQuerySQL, Query, relationalQuery, KeyUpdate, Insert, derivedInsert, InsertQuery, derivedInsertQuery, HasConstraintKey(constraintKey), Primary, NotNull, primary, primaryUpdate) -import Database.Relational.BaseTH (defineTuplePi, defineRecordProjections)+import Database.Relational.InternalTH.Base (defineTuplePi, defineRecordProjections) import Database.Relational.Scalar (defineScalarDegree)-import Database.Relational.Constraint (Key, unsafeDefineConstraintKey)+import Database.Relational.Constraint (unsafeDefineConstraintKey) import Database.Relational.Table (TableDerivable (..)) import qualified Database.Relational.Table as Table import Database.Relational.Relation (derivedRelation)@@ -99,6 +104,7 @@ import Database.Relational.Type (unsafeTypedQuery) import qualified Database.Relational.Pi.Unsafe as UnsafePi +import qualified Database.Relational.InternalTH.Overloaded as Overloaded -- | Rule template to infer constraint key. defineHasConstraintKeyInstance :: TypeQ -- ^ Constraint type@@ -150,52 +156,48 @@ defineHasNotNullKeyInstance . fst . recordTemplate (recordConfig $ nameConfig config) scm --- | Column projection path 'Pi' template.-columnTemplate' :: TypeQ -- ^ Record type- -> VarName -- ^ Column declaration variable name- -> ExpQ -- ^ Column index expression in record (begin with 0)- -> TypeQ -- ^ Column type- -> Q [Dec] -- ^ Column projection path declaration-columnTemplate' recType var' iExp colType = do- let var = varName var'- simpleValD var [t| Pi $recType $colType |]- [| UnsafePi.definePi $(iExp) |]---- | Column projection path 'Pi' and constraint key template.-columnTemplate :: Maybe (TypeQ, VarName) -- ^ May Constraint type and constraint object name- -> TypeQ -- ^ Record type- -> VarName -- ^ Column declaration variable name- -> ExpQ -- ^ Column index expression in record (begin with 0)- -> TypeQ -- ^ Column type- -> Q [Dec] -- ^ Column projection path declaration-columnTemplate mayConstraint recType var' iExp colType = do- col <- columnTemplate' recType var' iExp colType- cr <- maybe- (return [])- ( \(constraint, cname') -> do- simpleValD (varName cname') [t| Key $constraint $recType $colType |]- [| unsafeDefineConstraintKey $(iExp) |] )- mayConstraint- return $ col ++ cr+projectionTemplate :: ConName -- ^ Record type name+ -> VarName -- ^ Column declaration variable name+ -> Int -- ^ Column leftest index+ -> TypeQ -- ^ Column type+ -> Q [Dec] -- ^ Column projection path declaration+projectionTemplate recName var ix colType = do+ let offsetsExp = toVarExp . columnOffsetsVarNameDefault $ conName recName+ simpleValD (varName var)+ [t| Pi $(toTypeCon recName) $colType |]+ [| UnsafePi.definePi $ $offsetsExp ! $(integralE ix) |] --- | Column projection path 'Pi' templates.-defineColumns :: ConName -- ^ Record type name- -> [((VarName, TypeQ), Maybe (TypeQ, VarName))] -- ^ Column info list- -> Q [Dec] -- ^ Column projection path declarations+-- | Projection path 'Pi' templates.+defineColumns :: ConName -- ^ Record type name+ -> [(VarName, TypeQ)] -- ^ Column info list+ -> Q [Dec] -- ^ Column projection path declarations defineColumns recTypeName cols = do- let defC ((cn, ct), mayCon) ix = columnTemplate mayCon (toTypeCon recTypeName) cn- [| $(toVarExp . columnOffsetsVarNameDefault $ conName recTypeName) ! $(integralE ix) |] ct+ let defC (name, typ) ix = projectionTemplate recTypeName name ix typ fmap concat . sequence $ zipWith defC cols [0 :: Int ..] --- | Make column projection path and constraint key templates using default naming rule.-defineColumnsDefault :: ConName -- ^ Record type name- -> [((String, TypeQ), Maybe TypeQ)] -- ^ Column info list- -> Q [Dec] -- ^ Column projection path declarations+-- | Overloaded projection path 'Pi' templates.+defineOverloadedColumns :: ConName -- ^ Record type name+ -> [(String, TypeQ)] -- ^ Column info list+ -> Q [Dec] -- ^ Column projection path declarations+defineOverloadedColumns recTypeName cols = do+ let defC (name, typ) ix =+ Overloaded.monomorphicProjection recTypeName name ix typ+ fmap concat . sequence $ zipWith defC cols [0 :: Int ..]++-- | Make projection path templates using default naming rule.+defineColumnsDefault :: ConName -- ^ Record type name+ -> [(String, TypeQ)] -- ^ Column info list+ -> Q [Dec] -- ^ Column projection path declarations defineColumnsDefault recTypeName cols =- defineColumns recTypeName [((varN n, ct), fmap (withCName n) mayC) | ((n, ct), mayC) <- cols]- where varN name = varCamelcaseName (name ++ "'")- withCName name t = (t, varCamelcaseName ("constraint_key_" ++ name))+ defineColumns recTypeName [ (varCamelcaseName $ name ++ "'", typ) | (name, typ) <- cols ] +-- | Make overloaded projection path templates using default naming rule.+defineOverloadedColumnsDefault :: ConName -- ^ Record type name+ -> [(String, TypeQ)] -- ^ Column info list+ -> Q [Dec] -- ^ Column projection path declarations+defineOverloadedColumnsDefault recTypeName cols =+ defineOverloadedColumns recTypeName [ (nameBase . varName $ varCamelcaseName name, typ) | (name, typ) <- cols ]+ -- | Rule template to infer table derivations. defineTableDerivableInstance :: TypeQ -> String -> [String] -> Q [Dec] defineTableDerivableInstance recordType' table columns =@@ -289,11 +291,11 @@ |] -- | Make templates about table and column metadatas using specified naming rule.-defineTableTypesWithConfig :: Config -- ^ Configuration to generate query with- -> String -- ^ Schema name- -> String -- ^ Table name- -> [((String, TypeQ), Maybe TypeQ)] -- ^ Column names and types and constraint type- -> Q [Dec] -- ^ Result declarations+defineTableTypesWithConfig :: Config -- ^ Configuration to generate query with+ -> String -- ^ Schema name+ -> String -- ^ Table name+ -> [(String, TypeQ)] -- ^ Column names and types and constraint type+ -> Q [Dec] -- ^ Result declarations defineTableTypesWithConfig config schema table columns = do let nmconfig = nameConfig config recConfig = recordConfig nmconfig@@ -304,9 +306,15 @@ (table `varNameWithPrefix` "insertQuery") (fst $ recordTemplate recConfig schema table) (tableSQL (normalizedTableName config) (schemaNameMode config) (identifierQuotation config) schema table)- (map ((quote (identifierQuotation config)) . fst . fst) columns)- colsDs <- defineColumnsDefault (recordTypeName recConfig schema table) columns- return $ tableDs ++ colsDs+ (map ((quote (identifierQuotation config)) . fst) columns)+ let typeName = recordTypeName recConfig schema table+ colsDs <- if disableSpecializedProjection config+ then [d| |]+ else defineColumnsDefault typeName columns+ pcolsDs <- if disableOverloadedProjection config+ then [d| |]+ else defineOverloadedColumnsDefault typeName columns+ return $ tableDs ++ colsDs ++ pcolsDs -- | Make templates about table, column and haskell record using specified naming rule. defineTableTypesAndRecord :: Config -- ^ Configuration to generate query with@@ -320,7 +328,7 @@ recD <- defineRecordTypeWithConfig recConfig schema table columns derives rconD <- defineProductConstructorInstanceWithConfig config schema table [t | (_, t) <- columns] ctD <- [d| instance ShowConstantTermsSQL $(fst $ recordTemplate recConfig schema table) |]- tableDs <- defineTableTypesWithConfig config schema table [(c, Nothing) | c <- columns ]+ tableDs <- defineTableTypesWithConfig config schema table columns return $ recD ++ rconD ++ ctD ++ tableDs -- | Template of derived primary 'Query'.@@ -450,9 +458,10 @@ -- | Generate all templates against defined record like type constructor -- other than depending on sql-value type.-makeRelationalRecordDefault :: Name -- ^ Type constructor name- -> Q [Dec] -- ^ Result declaration-makeRelationalRecordDefault recTypeName = do+makeRelationalRecordDefault' :: Config+ -> Name -- ^ Type constructor name+ -> Q [Dec] -- ^ Result declaration+makeRelationalRecordDefault' config recTypeName = do let recTypeConName = ConName recTypeName (((tyCon, vars), _dataCon), (mayNs, cts)) <- reifyRecordType recTypeName pw <- Record.definePersistableWidthInstance tyCon vars@@ -461,15 +470,34 @@ Just ns -> case vars of [] -> do {- monomorphic case -} off <- Record.defineColumnOffsets recTypeConName- cs <- defineColumnsDefault recTypeConName- [ ((nameBase n, ct), Nothing) | n <- ns | ct <- cts ]- return $ off ++ cs- _:_ -> {- polymorphic case -}- defineRecordProjections tyCon vars- [varName $ varCamelcaseName (nameBase n ++ "'") | n <- ns]- cts+ let cnames = [ (nameBase n, ct) | n <- ns | ct <- cts ]+ cs <- if disableSpecializedProjection config+ then [d| |]+ else defineColumnsDefault recTypeConName cnames+ pcs <- if disableOverloadedProjection config+ then [d| |]+ else defineOverloadedColumnsDefault recTypeConName cnames+ return $ off ++ cs ++ pcs+ _:_ -> do {- polymorphic case -}+ cols <- if disableSpecializedProjection config+ then [d| |]+ else defineRecordProjections tyCon vars+ [varName $ varCamelcaseName (nameBase n ++ "'") | n <- ns]+ cts+ ovls <- if disableOverloadedProjection config+ then [d| |]+ else Overloaded.polymorphicProjections tyCon vars+ [nameBase n | n <- ns]+ cts+ return $ cols ++ ovls pc <- defineProductConstructor recTypeName let scPred v = classP ''ShowConstantTermsSQL [varT v] ct <- instanceD (mapM scPred vars) (appT [t| ShowConstantTermsSQL |] tyCon) [] return $ concat [pw, cols, pc, [ct]]++-- | Generate all templates against defined record like type constructor+-- other than depending on sql-value type.+makeRelationalRecordDefault :: Name -- ^ Type constructor name+ -> Q [Dec] -- ^ Result declaration+makeRelationalRecordDefault = makeRelationalRecordDefault' defaultConfig
src/Database/Relational/Table.hs view
@@ -10,7 +10,9 @@ -- This module defines table type which has table metadatas. module Database.Relational.Table ( -- * Phantom typed table type- Table, unType, name, shortName, width, columns, index, table, toMaybe, recordWidth,+ Table, untype, name, shortName, width, columns, index, table, toMaybe, recordWidth,+ unType,+ toSubQuery, -- * Table existence inference@@ -32,12 +34,17 @@ newtype Table r = Table Untyped -- | Untype table.+untype :: Table t -> Untyped+untype (Table u) = u++{-# DEPRECATED unType "Use untype instead of this." #-}+-- | Deprecated. use 'untype'. unType :: Table t -> Untyped-unType (Table u) = u+unType = untype -- | Name string of table in SQL name :: Table r -> String-name = name' . unType+name = name' . untype -- | Not qualified name string of table in SQL shortName :: Table r -> String@@ -45,17 +52,17 @@ -- | Width of table width :: Table r -> Int-width = width' . unType+width = width' . untype -- | Column name strings in SQL columns :: Table r -> [StringSQL]-columns = columns' . unType+columns = columns' . untype -- | Column name string in SQL specified by index index :: Table r -> Int -- ^ Column index -> StringSQL -- ^ Column name String in SQL-index = (!) . unType+index = (!) . untype -- | Cast phantom type into 'Maybe' type. toMaybe :: Table r -> Table (Maybe r)@@ -70,7 +77,7 @@ -- | 'SubQuery' from 'Table'. toSubQuery :: Table r -- ^ Typed 'Table' metadata -> SubQuery -- ^ Result 'SubQuery'-toSubQuery = Syntax.Table . unType+toSubQuery = Syntax.Table . untype -- | Inference rule of 'Table' existence. class PersistableWidth r => TableDerivable r where
src/Database/Relational/TupleInstances.hs view
@@ -18,10 +18,21 @@ import Control.Applicative ((<$>)) -import Database.Relational.BaseTH+import Database.Record (PersistableWidth)++import Database.Relational.Pi (Pi)+import Database.Relational.InternalTH.Base (defineTuplePi, defineTupleShowConstantInstance,) $(concat <$> mapM defineTuplePi [2..7]) $(concat <$> mapM defineTupleShowConstantInstance [2..7]) -- Generic instances of tuple types are generated from 2 to 7 in GHC.Generics.++-- | Projection path for fst of tuple.+fst' :: (PersistableWidth a, PersistableWidth b) => Pi (a, b) a+fst' = tuplePi2_0'++-- | Projection path for snd of tuple.+snd' :: (PersistableWidth a, PersistableWidth b) => Pi (a, b) b+snd' = tuplePi2_1'
test/Model.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DataKinds #-} module Model where
test/sqlsEq.hs view
@@ -415,15 +415,6 @@ return $ fromMaybe (value 1) (a ?! intA0') >< b -maybeY :: Relation () (SetA, SetB)-maybeY = relation $ do- a <- queryMaybe setA- b <- query setB-- wheres $ a ?! strA2' .=. b ! mayStrB1'-- return $ fromMaybe (SetA |$| value 1 |*| value "foo" |*| value "var") a >< b- notX :: Relation () (Maybe Bool) notX = relation $ return $ not' valueFalse@@ -447,12 +438,6 @@ , eqProp "fromMaybe" maybeX "SELECT ALL CASE WHEN (T0.int_a0 IS NULL) THEN 1 ELSE T0.int_a0 END AS f0, \ \ T1.int_b0 AS f1, T1.may_str_b1 AS f2, T1.str_b2 AS f3 \- \ FROM TEST.set_a T0 RIGHT JOIN TEST.set_b T1 ON (0=0) WHERE (T0.str_a2 = T1.may_str_b1)"- , eqProp "fromMaybe record" maybeY- "SELECT ALL CASE WHEN (T0.int_a0 IS NULL) THEN 1 ELSE T0.int_a0 END AS f0, \- \ CASE WHEN (T0.int_a0 IS NULL) THEN 'foo' ELSE T0.str_a1 END AS f1, \- \ CASE WHEN (T0.int_a0 IS NULL) THEN 'var' ELSE T0.str_a2 END AS f2, \- \ T1.int_b0 AS f3, T1.may_str_b1 AS f4, T1.str_b2 AS f5 \ \ FROM TEST.set_a T0 RIGHT JOIN TEST.set_b T1 ON (0=0) WHERE (T0.str_a2 = T1.may_str_b1)" , eqProp "not" notX "SELECT ALL (NOT (0=1)) AS f0"