packages feed

relational-query 0.9.0.1 → 0.9.0.2

raw patch · 7 files changed

+159/−41 lines, 7 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Database.Relational.Query.Projectable: case' :: (OperatorProjectable p, ProjectableShowSql p) => p a -> [(p a, p b)] -> p b -> p b
+ Database.Relational.Query.Projectable: case' :: OperatorProjectable (Projection c) => Projection c a -> [(Projection c a, Projection c b)] -> Projection c b -> Projection c b
- Database.Relational.Query.Projectable: caseMaybe :: (OperatorProjectable p, ProjectableShowSql p, ProjectableMaybe p) => p a -> [(p a, p (Maybe b))] -> p (Maybe b)
+ Database.Relational.Query.Projectable: caseMaybe :: OperatorProjectable (Projection c) => Projection c a -> [(Projection c a, Projection c (Maybe b))] -> Projection c (Maybe b)
- Database.Relational.Query.Projectable: caseSearch :: (OperatorProjectable p, ProjectableShowSql p) => [(p (Maybe Bool), p a)] -> p a -> p a
+ Database.Relational.Query.Projectable: caseSearch :: OperatorProjectable (Projection c) => [(Projection c (Maybe Bool), Projection c a)] -> Projection c a -> Projection c a
- Database.Relational.Query.Projectable: caseSearchMaybe :: (OperatorProjectable p, ProjectableShowSql p) => [(p (Maybe Bool), p (Maybe a))] -> p (Maybe a)
+ Database.Relational.Query.Projectable: caseSearchMaybe :: OperatorProjectable (Projection c) => [(Projection c (Maybe Bool), Projection c (Maybe a))] -> Projection c (Maybe a)
- Database.Relational.Query.Projectable: casesOrElse :: (OperatorProjectable p, ProjectableShowSql p) => [(p (Maybe Bool), p a)] -> p a -> p a
+ Database.Relational.Query.Projectable: casesOrElse :: OperatorProjectable (Projection c) => [(Projection c (Maybe Bool), Projection c a)] -> Projection c a -> Projection c a
- Database.Relational.Query.Projectable: casesOrElse' :: (OperatorProjectable p, ProjectableShowSql p) => (p a, [(p a, p b)]) -> p b -> p b
+ Database.Relational.Query.Projectable: casesOrElse' :: OperatorProjectable (Projection c) => (Projection c a, [(Projection c a, Projection c b)]) -> Projection c b -> Projection c b

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ <!-- -*- Markdown -*- --> +## 0.9.0.2++- Bugfix of case projected record. ( https://github.com/khibino/haskell-relational-record/issues/54 )+ ## 0.9.0.1  - Use Haskell implementation test instead of flag test in .cabal
relational-query.cabal view
@@ -1,5 +1,5 @@ name:                relational-query-version:             0.9.0.1+version:             0.9.0.2 synopsis:            Typeful, Modular, Relational, algebraic query engine description:         This package contiains typeful relation structure and                      relational-algebraic query building DSL which can
src/Database/Relational/Query/Internal/Sub.hs view
@@ -21,6 +21,9 @@        , JoinProduct, QueryProductTree        , ProductTreeBuilder, ProductBuilder +       , CaseClause (..), WhenClauses(..)+       , caseSearch, case'+        , UntypedProjection, untypedProjectionWidth, ProjectionUnit (..)        , Projection, untypeProjection, typedProjection, projectionWidth        , projectFromColumns, projectFromScalarSubQuery@@ -116,12 +119,23 @@ -- | Type for join product of query. type JoinProduct = Maybe QueryProductTree +-- | when clauses+data WhenClauses =+  WhenClauses [(UntypedProjection, UntypedProjection)] UntypedProjection+  deriving Show +-- | case clause+data CaseClause+  = CaseSearch WhenClauses+  | CaseSimple UntypedProjection WhenClauses+  deriving Show+ -- | Projection structure unit with single column width data ProjectionUnit   = RawColumn StringSQL            -- ^ used in immediate value or unsafe operations   | SubQueryRef (Qualified Int)    -- ^ normalized sub-query reference T<n> with Int index   | Scalar SubQuery                -- ^ scalar sub-query+  | Case CaseClause Int            -- ^ <n>th column of case clause   deriving Show  -- | Untyped projection. Forgot record type.@@ -152,6 +166,38 @@ -- | Unsafely generate 'Projection' from scalar sub-query. projectFromScalarSubQuery :: SubQuery -> Projection c t projectFromScalarSubQuery = typedProjection . (:[]) . Scalar++whenClauses :: String                             -- ^ Error tag+            -> [(Projection c a, Projection c b)] -- ^ Each when clauses+            -> Projection c b                     -- ^ Else result projection+            -> WhenClauses                        -- ^ Result clause+whenClauses eTag ws0 e = d ws0+  where+    d []       = error $ eTag ++ ": Empty when clauses!"+    d ws@(_:_) =+      WhenClauses [ (untypeProjection p, untypeProjection r) | (p, r) <- ws ]+      $ untypeProjection e++-- | Search case operator correnponding SQL search /CASE/.+--   Like, /CASE WHEN p0 THEN a WHEN p1 THEN b ... ELSE c END/+caseSearch :: [(Projection c (Maybe Bool), Projection c a)] -- ^ Each when clauses+           -> Projection c a                                -- ^ Else result projection+           -> Projection c a                                -- ^ Result projection+caseSearch ws e =+    typedProjection [ Case c i | i <- [0 .. projectionWidth e - 1] ]+  where+    c = CaseSearch $ whenClauses "caseSearch" ws e++-- | Simple case operator correnponding SQL simple /CASE/.+--   Like, /CASE x WHEN v THEN a WHEN w THEN b ... ELSE c END/+case' :: Projection c a                     -- ^ Projection value to match+      -> [(Projection c a, Projection c b)] -- ^ Each when clauses+      -> Projection c b                     -- ^ Else result projection+      -> Projection c b                     -- ^ Result projection+case' v ws e =+    typedProjection [ Case c i | i <- [0 .. projectionWidth e - 1] ]+  where+    c = CaseSimple (untypeProjection v) $ whenClauses "case'" ws e   -- | Type for restriction of query.
src/Database/Relational/Query/Projectable.hs view
@@ -64,7 +64,6 @@ import Prelude hiding (pi)  import Data.String (IsString)-import Data.Monoid ((<>), mconcat) import Control.Applicative ((<$>))  import Language.SQL.Keyword (Keyword)@@ -75,6 +74,7 @@    HasColumnConstraint, NotNull)  import Database.Relational.Query.Internal.SQL (StringSQL, stringSQL, showStringSQL)+import qualified Database.Relational.Query.Internal.Sub as Internal  import Database.Relational.Query.ProjectableClass   (ProjectableFunctor (..), ProjectableApplicative (..), )@@ -352,59 +352,48 @@                    => p (Maybe a) -> p (Maybe b) showNumMaybe = unsafeCastProjectable -whensClause :: (OperatorProjectable p, ProjectableShowSql p)-            => String       -- ^ Error tag-            -> [(p a, p b)] -- ^ Each when clauses-            -> p b          -- ^ Else result projection-            -> Keyword      -- ^ Result projection-whensClause eTag cs0 e = d cs0  where-  d []       = error $ eTag ++ ": Empty when clauses!"-  d cs@(_:_) = mconcat [when' p r | (p, r) <- cs] <> else' <> SQL.END-  when' p r = SQL.WHEN <> unsafeShowSql' p <> SQL.THEN <> unsafeShowSql' r-  else'     = SQL.ELSE <> unsafeShowSql' e- -- | Search case operator correnponding SQL search /CASE/. --   Like, /CASE WHEN p0 THEN a WHEN p1 THEN b ... ELSE c END/-caseSearch :: (OperatorProjectable p, ProjectableShowSql p)-           => [(p (Maybe Bool), p a)] -- ^ Each when clauses-           -> p a                     -- ^ Else result projection-           -> p a                     -- ^ Result projection-caseSearch cs e = unsafeProjectSql' $ SQL.CASE <> whensClause "caseSearch" cs e+caseSearch :: OperatorProjectable (Projection c)+           => [(Projection c (Maybe Bool), Projection c a)] -- ^ Each when clauses+           -> Projection c a                                -- ^ Else result projection+           -> Projection c a                                -- ^ Result projection+caseSearch = Internal.caseSearch  -- | Same as 'caseSearch', but you can write like <when list> `casesOrElse` <else clause>.-casesOrElse :: (OperatorProjectable p, ProjectableShowSql p)-            => [(p (Maybe Bool), p a)] -- ^ Each when clauses-            -> p a                     -- ^ Else result projection-            -> p a                     -- ^ Result projection+casesOrElse :: OperatorProjectable (Projection c)+            => [(Projection c (Maybe Bool), Projection c a)] -- ^ Each when clauses+            -> Projection c a                                -- ^ Else result projection+            -> Projection c a                                -- ^ Result projection casesOrElse = caseSearch  -- | Null default version of 'caseSearch'.-caseSearchMaybe :: (OperatorProjectable p, ProjectableShowSql p)-                => [(p (Maybe Bool), p (Maybe a))] -- ^ Each when clauses-                -> p (Maybe a)                     -- ^ Result projection+caseSearchMaybe :: OperatorProjectable (Projection c) -- (Projection c) is always ProjectableMaybe+                => [(Projection c (Maybe Bool), Projection c (Maybe a))] -- ^ Each when clauses+                -> Projection c (Maybe a)                                -- ^ Result projection caseSearchMaybe cs = caseSearch cs unsafeValueNull  -- | Simple case operator correnponding SQL simple /CASE/. --   Like, /CASE x WHEN v THEN a WHEN w THEN b ... ELSE c END/-case' :: (OperatorProjectable p, ProjectableShowSql p)-      => p a          -- ^ Projection value to match-      -> [(p a, p b)] -- ^ Each when clauses-      -> p b          -- ^ Else result projection-      -> p b          -- ^ Result projection-case' v cs e = unsafeProjectSql' $ SQL.CASE <> unsafeShowSql' v <> whensClause "case'" cs e+case' :: OperatorProjectable (Projection c)+      => Projection c a                     -- ^ Projection value to match+      -> [(Projection c a, Projection c b)] -- ^ Each when clauses+      -> Projection c b                     -- ^ Else result projection+      -> Projection c b                     -- ^ Result projection+case' = Internal.case'  -- | Uncurry version of 'case'', and you can write like ... `casesOrElse'` <else clause>.-casesOrElse' :: (OperatorProjectable p, ProjectableShowSql p)-             => (p a, [(p a, p b)]) -- ^ Projection value to match and each when clauses list-             -> p b                 -- ^ Else result projection-             -> p b                 -- ^ Result projection+casesOrElse' :: OperatorProjectable (Projection c)+             => (Projection c a, [(Projection c a, Projection c b)]) -- ^ Projection value to match and each when clauses list+             -> Projection c b                                       -- ^ Else result projection+             -> Projection c b                                       -- ^ Result projection casesOrElse' =  uncurry case'  -- | Null default version of 'case''.-caseMaybe :: (OperatorProjectable p, ProjectableShowSql p, ProjectableMaybe p)-          => p a                  -- ^ Projection value to match-          -> [(p a, p (Maybe b))] -- ^ Each when clauses-          -> p (Maybe b)          -- ^ Result projection+caseMaybe :: OperatorProjectable (Projection c) -- (Projection c) is always ProjectableMaybe+          => Projection c a                             -- ^ Projection value to match+          -> [(Projection c a, Projection c (Maybe b))] -- ^ Each when clauses+          -> Projection c (Maybe b)                     -- ^ Result projection caseMaybe v cs = case' v cs unsafeValueNull  -- | Binary operator corresponding SQL /IN/ .
src/Database/Relational/Query/ProjectableClass.hs view
@@ -61,7 +61,23 @@                      -> [StringSQL] showConstantTermsSQL = toList . showConstantTermsSQL' --- | Interface for constant SQL term list.+{- |+'ShowConstantTermsSQL' 'a' is implicit rule to derive function to convert+from haskell record type 'a' into constant SQL terms.++Generic programming (<https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#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 
src/Database/Relational/Query/Sub.hs view
@@ -58,6 +58,7 @@   (AggregateElem, composeGroupBy, ) import Database.Relational.Query.Internal.Sub   (SubQuery (..), Projection,+   CaseClause(..), WhenClauses (..),    UntypedProjection, ProjectionUnit (..),    JoinProduct, QueryProductTree, ProductBuilder,    NodeAttr (Just', Maybe), ProductTree (Leaf, Join),@@ -243,12 +244,28 @@   d (Flat {})               =  normalized   d (Aggregated {})         =  normalized +-- | index result of each when clause and else clause.+indexWhensClause :: WhenClauses -> Int -> StringSQL+indexWhensClause (WhenClauses ps e) i =+    mconcat [ when' p r | (p, r)  <-  ps] <> else' <> SQL.END+  where+    when' p r = SQL.WHEN <> rowStringSQL (map columnOfProjectionUnit p) <>+                SQL.THEN <> columnOfUntypedProjection r i+    else'     = SQL.ELSE <> columnOfUntypedProjection e i++-- | index result of each when clause and else clause.+caseClause :: CaseClause -> Int -> StringSQL+caseClause c i = d c  where+  d (CaseSearch wcl)    = SQL.CASE <> indexWhensClause wcl i+  d (CaseSimple m wcl)  = SQL.CASE <> rowStringSQL (map columnOfProjectionUnit m) <> indexWhensClause wcl i+ -- | Convert from ProjectionUnit into column. columnOfProjectionUnit :: ProjectionUnit -> StringSQL columnOfProjectionUnit = d  where   d (RawColumn e)     = e   d (SubQueryRef qi)  = Internal.qualifier qi `columnFromId` Internal.unQualify qi   d (Scalar sub)      = showUnitSQL sub+  d (Case c i)        = caseClause c i  -- | Get column SQL string of 'UntypedProjection'. columnOfUntypedProjection :: UntypedProjection -- ^ Source 'Projection'
test/sqlsEq.hs view
@@ -308,6 +308,52 @@   , eqProp "div"   (bin53 (./.)) "SELECT ALL (5 / 3) AS f0"   ] +caseSearchX :: Relation () String+caseSearchX = relation $ do+  return $+    caseSearch+    [ (value 2 .=. value (1  :: Int32)            , value "foo")+    , (value 5 .=. value 3 .+. value (2 :: Int32) , value "bar")+    , (value "a" .=. value "b"                    , value "baz") ]+    (value "other")++caseX :: Relation () String+caseX = relation $ do+  return $+    case'+    (value (5 :: Int32))+    [ (value 1             , value "foo")+    , (value 3 .+. value 2 , value "bar")+    , (value 10            , value "baz") ]+    (value "other")++caseRecordX :: Relation () Int32+caseRecordX = relation $ do+  return $+    case'+    (value (5 :: Int32))+    [ (value 1             , (,) |$| value 1 |*| value "foo")+    , (value 3 .+. value 2 , (,) |$| value 2 |*| value "bar")+    , (value 10            , (,) |$| value 3 |*| value "baz") ]+    ((,) |$| value (0 :: Int32) |*| value "other")+    ! fst'+    .*.+    value 10++cases :: [Test]+cases =+  [ eqProp "caseSearch" caseSearchX+    "SELECT ALL CASE WHEN (2 = 1) THEN 'foo' WHEN (5 = (3 + 2)) THEN 'bar' WHEN ('a' = 'b') THEN 'baz' ELSE 'other' END AS f0"+  , eqProp "case"       caseX+    "SELECT ALL CASE 5 WHEN 1 THEN 'foo' WHEN (3 + 2) THEN 'bar' WHEN 10 THEN 'baz' ELSE 'other' END AS f0"+  , eqProp "caseRecord" caseRecordX+    "SELECT ALL (CASE 5 WHEN 1 THEN 1 WHEN (3 + 2) THEN 2 WHEN 10 THEN 3 ELSE 0 END * 10) AS f0"+  ]++_p_cases :: IO ()+_p_cases =+  mapM_ print [show caseSearchX, show caseX]+ nothingX :: Relation () (SetA, Maybe SetB) nothingX =  relation $ do   a <- query setA@@ -630,7 +676,7 @@  tests :: [Test] tests =-  concat [ tables, monadic, directJoins, join3s, nested, bin, uni+  concat [ tables, monadic, directJoins, join3s, nested, bin, cases, uni          , groups, orders, partitions, exps, effs, correlated]  main :: IO ()