packages feed

opaleye 0.6.7000.0 → 0.6.7001.0

raw patch · 16 files changed

+298/−149 lines, 16 filesdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base

API changes (from Hackage documentation)

- Opaleye.Internal.Order: instance Data.Semigroup.Semigroup (Opaleye.Internal.Order.Order a)
- Opaleye.Internal.PrimQuery: Order :: [OrderExpr] -> (PrimQuery' a) -> PrimQuery' a
- Opaleye.Internal.PrimQuery: [order] :: PrimQueryFold' a p -> [OrderExpr] -> p -> p
- Opaleye.Internal.Sql: order :: [OrderExpr] -> Select -> Select
+ Opaleye.Internal.Order: distinctOn :: Unpackspec b b -> (a -> b) -> (a, PrimQuery, Tag) -> (a, PrimQuery, Tag)
+ Opaleye.Internal.Order: distinctOnBy :: Unpackspec b b -> (a -> b) -> Order a -> (a, PrimQuery, Tag) -> (a, PrimQuery, Tag)
+ Opaleye.Internal.Order: instance GHC.Base.Semigroup (Opaleye.Internal.Order.Order a)
+ Opaleye.Internal.PrimQuery: DistinctOnOrderBy :: (Maybe (NonEmpty PrimExpr)) -> [OrderExpr] -> (PrimQuery' a) -> PrimQuery' a
+ Opaleye.Internal.PrimQuery: [distinctOnOrderBy] :: PrimQueryFold' a p -> Maybe (NonEmpty PrimExpr) -> [OrderExpr] -> p -> p
+ Opaleye.Internal.Print: ppDistinctOn :: Maybe (NonEmpty SqlExpr) -> Doc
+ Opaleye.Internal.Sql: [distinctOn] :: From -> Maybe (NonEmpty SqlExpr)
+ Opaleye.Internal.Sql: distinctOnOrderBy :: Maybe (NonEmpty PrimExpr) -> [OrderExpr] -> Select -> Select
+ Opaleye.Internal.Table: instance GHC.Base.Semigroup (Opaleye.Internal.Table.Zip a)
+ Opaleye.Operators: lowerBound :: IsRangeType a => Column (SqlRange a) -> Column (Nullable a)
+ Opaleye.Operators: upperBound :: IsRangeType a => Column (SqlRange a) -> Column (Nullable a)
+ Opaleye.Order: distinctOn :: Default Unpackspec b b => (a -> b) -> Select a -> Select a
+ Opaleye.Order: distinctOnBy :: Default Unpackspec b b => (a -> b) -> Order a -> Select a -> Select a
- Opaleye.Constant: Constant :: (haskells -> fields) -> Constant haskells fields
+ Opaleye.Constant: Constant :: haskells -> fields -> Constant haskells fields
- Opaleye.Internal.HaskellDB.Sql.Generate: SqlGenerator :: (SqlTable -> [PrimExpr] -> Assoc -> SqlUpdate) -> (SqlTable -> [PrimExpr] -> SqlDelete) -> (SqlTable -> [Attribute] -> NonEmpty [PrimExpr] -> Maybe OnConflict -> SqlInsert) -> (PrimExpr -> SqlExpr) -> (Literal -> String) -> (String -> String) -> SqlGenerator
+ Opaleye.Internal.HaskellDB.Sql.Generate: SqlGenerator :: SqlTable -> [PrimExpr] -> Assoc -> SqlUpdate -> SqlTable -> [PrimExpr] -> SqlDelete -> SqlTable -> [Attribute] -> NonEmpty [PrimExpr] -> Maybe OnConflict -> SqlInsert -> PrimExpr -> SqlExpr -> Literal -> String -> String -> String -> SqlGenerator
- Opaleye.Internal.PrimQuery: PrimQueryFold :: p -> (a -> p) -> (TableIdentifier -> Bindings PrimExpr -> p) -> (NonEmpty p -> [PrimExpr] -> p) -> (Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), PrimExpr) -> p -> p) -> ([OrderExpr] -> p -> p) -> (LimitOp -> p -> p) -> (JoinType -> PrimExpr -> Bindings PrimExpr -> Bindings PrimExpr -> p -> p -> p) -> (Bool -> p -> p -> p) -> ([Symbol] -> NonEmpty [PrimExpr] -> p) -> (BinOp -> Bindings (PrimExpr, PrimExpr) -> (p, p) -> p) -> (String -> p -> p) -> (PrimExpr -> Bindings PrimExpr -> p) -> PrimQueryFold' a p
+ Opaleye.Internal.PrimQuery: PrimQueryFold :: p -> a -> p -> TableIdentifier -> Bindings PrimExpr -> p -> NonEmpty p -> [PrimExpr] -> p -> Bindings (Maybe (AggrOp, [OrderExpr], AggrDistinct), PrimExpr) -> p -> p -> Maybe (NonEmpty PrimExpr) -> [OrderExpr] -> p -> p -> LimitOp -> p -> p -> JoinType -> PrimExpr -> Bindings PrimExpr -> Bindings PrimExpr -> p -> p -> p -> Bool -> p -> p -> p -> [Symbol] -> NonEmpty [PrimExpr] -> p -> BinOp -> Bindings (PrimExpr, PrimExpr) -> (p, p) -> p -> String -> p -> p -> PrimExpr -> Bindings PrimExpr -> p -> PrimQueryFold' a p
- Opaleye.Internal.Sql: From :: SelectAttrs -> [Select] -> [SqlExpr] -> Maybe (NonEmpty SqlExpr) -> [(SqlExpr, SqlOrder)] -> Maybe Int -> Maybe Int -> From
+ Opaleye.Internal.Sql: From :: SelectAttrs -> [Select] -> [SqlExpr] -> Maybe (NonEmpty SqlExpr) -> [(SqlExpr, SqlOrder)] -> Maybe (NonEmpty SqlExpr) -> Maybe Int -> Maybe Int -> From
- Opaleye.Manipulation: Delete :: Table fieldsW fieldsR -> (fieldsR -> Field SqlBool) -> Returning fieldsR Int64 -> Delete haskells
+ Opaleye.Manipulation: Delete :: Table fieldsW fieldsR -> fieldsR -> Field SqlBool -> Returning fieldsR Int64 -> Delete haskells
- Opaleye.Manipulation: Update :: Table fieldsW fieldsR -> (fieldsR -> fieldsW) -> (fieldsR -> Field SqlBool) -> Returning fieldsR haskells -> Update haskells
+ Opaleye.Manipulation: Update :: Table fieldsW fieldsR -> fieldsR -> fieldsW -> fieldsR -> Field SqlBool -> Returning fieldsR haskells -> Update haskells

Files

CHANGELOG.md view
@@ -1,3 +1,13 @@+## 0.6.7001.0++* Fix bug with infinity in range bounds++* Fix incompatibility with GHC 8.4++* Add range accessors, `upperBound` and `lowerBound`++* Add `distinctOn` and `distinctOnBy`+ ## 0.6.7000.0  This is a pre-release of version 0.7.0.0.  GHC >= 8.0 is required.  It
Test/Test.hs view
@@ -1,42 +1,37 @@-{-# LANGUAGE Arrows #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Arrows              #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE ScopedTypeVariables #-}  module Main where -import qualified QuickCheck-import qualified TypeFamilies ()--import           Opaleye (Column, Nullable, Query, QueryArr, (.==), (.>))-import qualified Opaleye as O-import qualified Opaleye.Internal.Aggregate as IA--import qualified Database.PostgreSQL.Simple as PGS+import qualified Configuration.Dotenv             as Dotenv+import           Control.Applicative              ((<$>), (<*>), (<|>))+import qualified Control.Applicative              as A+import           Control.Arrow                    ((&&&), (***), (<<<), (>>>))+import qualified Control.Arrow                    as Arr+import qualified Data.Aeson                       as Json+import qualified Data.Function                    as F+import qualified Data.List                        as L+import           Data.Monoid                      ((<>))+import qualified Data.Ord                         as Ord+import qualified Data.Profunctor                  as P+import qualified Data.Profunctor.Product          as PP+import qualified Data.Profunctor.Product.Default  as D+import qualified Data.String                      as String+import qualified Data.Text                        as T+import qualified Data.Time                        as Time+import qualified Database.PostgreSQL.Simple       as PGS import qualified Database.PostgreSQL.Simple.Range as R-import qualified Data.Profunctor.Product.Default as D-import qualified Data.Profunctor.Product as PP-import qualified Data.Profunctor as P-import qualified Data.Ord as Ord-import qualified Data.List as L-import           Data.Monoid ((<>))-import qualified Data.String as String-import qualified Data.Time   as Time-import qualified Data.Aeson as Json-import qualified Data.Text as T--import           System.Environment (lookupEnv)--import           Control.Applicative ((<$>), (<*>), (<|>))-import qualified Control.Applicative as A-import qualified Control.Arrow as Arr-import           Control.Arrow ((&&&), (***), (<<<), (>>>))--import           GHC.Int (Int64)--import Test.Hspec--import qualified Configuration.Dotenv as Dotenv+import           GHC.Int                          (Int64)+import           Opaleye                          (Column, Nullable, Query,+                                                   QueryArr, (.==), (.>))+import qualified Opaleye                          as O+import qualified Opaleye.Internal.Aggregate       as IA+import qualified QuickCheck+import           System.Environment               (lookupEnv)+import           Test.Hspec+import qualified TypeFamilies                     ()  {- @@ -424,6 +419,60 @@ testDistinct :: Test testDistinct = it "" $ O.distinct table1Q `queryShouldReturnSorted` (L.nub table1data) ++testDistinctOn :: Test+testDistinctOn = do+    it "distinct on (col1)" $ \conn -> do+        let p = fst+            q = O.distinctOn p table1Q+            expected = L.nubBy (F.on (==) p) $ L.sortOn p table1data+        testH q (\r -> L.sort r `shouldBe` L.sort expected) conn+    it "distinct on (col1, col2)" $ \conn -> do+        let p = fst &&& snd+            q = O.distinctOn p table1Q+            expected = L.nubBy (F.on (==) p) $ L.sortOn p table1data+        testH q (\r -> L.sort r `shouldBe` L.sort expected) conn++    let f1 (x,_,_) = x+        f2 (_,y,_) = y+        f3 (_,_,z) = z++    it "distinct on (col1) order by col2" $ \conn -> do+        let proj = f1+            ord  = f2+            q = O.distinctOnBy proj (O.asc ord) $ O.values pgTriples+            expected = L.nubBy ((==) `F.on` proj) $ L.sortOn (proj &&& ord) triples+        testH q (\r -> L.sort r `shouldBe` L.sort expected) conn+    it "distinct on (col1, col2) order by col3" $ \conn -> do+        let proj = f1 &&& f2+            ord  = f3+            q = O.distinctOnBy proj (O.asc ord) $ O.values pgTriples+            expected = L.nubBy ((==) `F.on` proj) $ L.sortOn (proj &&& ord) triples+        testH q (\r -> L.sort r `shouldBe` L.sort expected) conn+    it "distinct on (col3) order by col2 desc" $ \conn -> do+        let proj = f3+            ord  = f2+            q = O.distinctOnBy proj (O.desc ord) $ O.values pgTriples+            expected = L.nubBy ((==) `F.on` proj) . L.reverse $+                L.sortOn (proj &&& ord) triples+        testH q (\r -> L.sort r `shouldBe` L.sort expected) conn+    where++        pgTriples :: [(O.Column O.PGInt8, O.Column O.PGInt8, O.Column O.PGText)]+        pgTriples = (\(x,y,z) -> (O.pgInt8 x, O.pgInt8 y, O.pgStrictText z)) <$> triples++        triples :: [(Int64, Int64, T.Text)]+        triples =+            [ (1, 900, "a")+            , (1, 800, "a")+            , (2, 400, "a")+            , (2, 500, "b")+            , (2, 500, "b")+            , (4, 400, "b")+            , (4, 600, "b")+            , (4, 100, "b")+            ]+ -- FIXME: the unsafeCoerceColumn is currently needed because the type -- changes required for aggregation are not currently dealt with by -- Opaleye.@@ -976,6 +1025,22 @@         range a b = O.pgRange O.pgInt4 (R.Inclusive a) (R.Exclusive b)         q = A.pure $ (range 1 2) O..-|- (range 2 3) +testRangeBoundsEnum :: forall a b.+    ( Show a, Eq a, Enum a, O.IsRangeType b+    , O.QueryRunnerColumnDefault (Nullable b) (Maybe a))+        => String -> (a -> Column b) -> a -> a -> Test+testRangeBoundsEnum msg mkCol x y = it msg $ \conn -> do+    -- bound functions for discrete range types return fields as from the form [x,y)+    let ranges = [ O.pgRange mkCol (R.Inclusive x) R.PosInfinity+                 , O.pgRange mkCol R.NegInfinity   (R.Inclusive y)+                 , O.pgRange mkCol (R.Exclusive x) (R.Exclusive y)+                 ]+    [r1,r2,r3] <- mapM (O.runQuery conn . pure . (O.lowerBound &&& O.upperBound)) ranges+    r1 `shouldBe` [(Just x, Nothing)]+    r2 `shouldBe` [(Nothing, Just $ succ y)]+    r3 `shouldBe` [(Just $ succ x, Just y)]++ -- Note: these tests are left out of allTests until Travis supports -- Postgresql >= 9.4 jsonbTests :: [Test]@@ -1054,6 +1119,8 @@         testDoubleAggregate       describe "distinct" $ do         testDistinct+      describe "distinct on"+        testDistinctOn       describe "order" $ do         testOrderBy         testOrderBy2@@ -1111,3 +1178,7 @@         testRangeRightExtension         testRangeLeftExtension         testRangeAdjacency+        testRangeBoundsEnum "can access bounds from an Int8 range"+            O.pgInt8 10 26+        testRangeBoundsEnum "can access bounds from a date range"+            O.pgDay (read "2018-01-01") (read "2018-01-12")
opaleye.cabal view
@@ -1,6 +1,6 @@ name:            opaleye copyright:       Copyright (c) 2014-2018 Purely Agile Limited-version:         0.6.7000.0+version:         0.6.7001.0 synopsis:        An SQL-generating DSL targeting PostgreSQL description:     An SQL-generating DSL targeting PostgreSQL.  Allows                  Postgres queries to be written within Haskell in a@@ -18,7 +18,7 @@                  CHANGELOG.md                  *.md                  Doc/*.md-tested-with:     GHC==8.2.2, GHC==8.0.2+tested-with:     GHC==8.4.3, GHC==8.2.2, GHC==8.0.2  source-repository head   type:     git@@ -29,7 +29,7 @@   hs-source-dirs: src   build-depends:       aeson               >= 0.6     && < 1.4-    , base                >= 4.6     && < 5+    , base                >= 4.9     && < 5     , base16-bytestring   >= 0.1.1.6 && < 0.2     , case-insensitive    >= 1.2     && < 1.3     , bytestring          >= 0.10    && < 0.11
src/Opaleye/Internal/HaskellDB/Sql/Print.hs view
@@ -19,6 +19,7 @@                                      commaH                                     ) where +import Prelude hiding ((<>)) import Opaleye.Internal.HaskellDB.Sql (SqlColumn(..), SqlDelete(..),                                SqlExpr(..), SqlOrder(..), SqlInsert(..),                                SqlUpdate(..), SqlTable(..), SqlRangeBound(..),@@ -137,8 +138,8 @@   where value_boundTypeT = \case           Inclusive a -> (Inclusive', a)           Exclusive a -> (Exclusive', a)-          PosInfinity -> (Exclusive', ConstSqlExpr "'infinity'")-          NegInfinity -> (Exclusive', ConstSqlExpr "'-infinity'")+          PosInfinity -> (Exclusive', ConstSqlExpr "NULL")+          NegInfinity -> (Exclusive', ConstSqlExpr "NULL")          (startType, startValue) = value_boundTypeT start         (endType,   endValue)   = value_boundTypeT end
src/Opaleye/Internal/Optimize.hs view
@@ -41,7 +41,7 @@                                                =<< T.sequence x)                                       <*> pure y   , PQ.aggregate = fmap . PQ.Aggregate-  , PQ.order     = fmap . PQ.Order+  , PQ.distinctOnOrderBy = \mDistinctOns -> fmap . PQ.DistinctOnOrderBy mDistinctOns   , PQ.limit     = fmap . PQ.Limit   , PQ.join      = \jt pe pes1 pes2 pq1 pq2 -> PQ.Join jt pe pes1 pes2 <$> pq1 <*> pq2   , PQ.existsf   = \b pq1 pq2 -> PQ.Exists b <$> pq1 <*> pq2
src/Opaleye/Internal/Order.hs view
@@ -1,21 +1,19 @@ module Opaleye.Internal.Order where -import           Data.Function (on)--import qualified Data.List.NonEmpty as NL--import qualified Opaleye.Column as C-import qualified Opaleye.Internal.Column as IC-import qualified Opaleye.Internal.Tag as T-import qualified Opaleye.Internal.PrimQuery as PQ--import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ-import qualified Data.Functor.Contravariant as C+import           Data.Function                        (on)+import qualified Data.Functor.Contravariant           as C import qualified Data.Functor.Contravariant.Divisible as Divisible-import qualified Data.Profunctor as P-import qualified Data.Monoid as M-import qualified Data.Semigroup as S-import qualified Data.Void as Void+import qualified Data.List.NonEmpty                   as NL+import qualified Data.Monoid                          as M+import qualified Data.Profunctor                      as P+import qualified Data.Semigroup                       as S+import qualified Data.Void                            as Void+import qualified Opaleye.Column                       as C+import qualified Opaleye.Internal.Column              as IC+import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ+import qualified Opaleye.Internal.PrimQuery           as PQ+import qualified Opaleye.Internal.Tag                 as T+import qualified Opaleye.Internal.Unpackspec          as U  {-| An `Order` @a@ represents a sort order and direction for the elements@@ -55,7 +53,7 @@  orderByU :: Order a -> (a, PQ.PrimQuery, T.Tag) -> (a, PQ.PrimQuery, T.Tag) orderByU os (columns, primQ, t) = (columns, primQ', t)-  where primQ' = PQ.Order oExprs primQ+  where primQ' = PQ.DistinctOnOrderBy Nothing oExprs primQ         oExprs = orderExprs columns os  orderExprs :: a -> Order a -> [HPQ.OrderExpr]@@ -66,6 +64,17 @@  offset' :: Int -> (a, PQ.PrimQuery, T.Tag) -> (a, PQ.PrimQuery, T.Tag) offset' n (x, q, t) = (x, PQ.Limit (PQ.OffsetOp n) q, t)++distinctOn :: U.Unpackspec b b -> (a -> b)+           -> (a, PQ.PrimQuery, T.Tag) -> (a, PQ.PrimQuery, T.Tag)+distinctOn ups proj = distinctOnBy ups proj (Order $ const [])++distinctOnBy :: U.Unpackspec b b -> (a -> b) -> Order a+             -> (a, PQ.PrimQuery, T.Tag) -> (a, PQ.PrimQuery, T.Tag)+distinctOnBy ups proj ord (cols, pq, t) = (cols, pqOut, t)+    where pqOut = case U.collectPEs ups (proj cols) of+            x:xs -> PQ.DistinctOnOrderBy (Just $ x NL.:| xs) (orderExprs cols ord) pq+            []   -> pq  -- | Order the results of a given query exactly, as determined by the given list -- of input columns. Note that this list does not have to contain an entry for
src/Opaleye/Internal/PrimQuery.hs view
@@ -45,7 +45,11 @@                   | Product   (NEL.NonEmpty (PrimQuery' a)) [HPQ.PrimExpr]                   | Aggregate (Bindings (Maybe (HPQ.AggrOp, [HPQ.OrderExpr], HPQ.AggrDistinct), HPQ.PrimExpr))                               (PrimQuery' a)-                  | Order     [HPQ.OrderExpr] (PrimQuery' a)+                  -- | Represents both @DISTINCT ON@ and @ORDER BY@ clauses. In order to represent valid+                  --   SQL only, @DISTINCT ON@ expressions are always interpreted as the first @ORDER BY@s+                  --   when present, preceding any in the provided list.+                  --   See 'Opaleye.Internal.Sql.distinctOnOrderBy'.+                  | DistinctOnOrderBy (Maybe (NEL.NonEmpty HPQ.PrimExpr)) [HPQ.OrderExpr] (PrimQuery' a)                   | Limit     LimitOp (PrimQuery' a)                   | Join      JoinType                               HPQ.PrimExpr@@ -66,62 +70,62 @@ type PrimQueryFold = PrimQueryFold' ()  data PrimQueryFold' a p = PrimQueryFold-  { unit      :: p-  , empty     :: a -> p-  , baseTable :: TableIdentifier -> Bindings HPQ.PrimExpr -> p-  , product   :: NEL.NonEmpty p -> [HPQ.PrimExpr] -> p-  , aggregate :: Bindings (Maybe (HPQ.AggrOp, [HPQ.OrderExpr], HPQ.AggrDistinct), HPQ.PrimExpr) -> p -> p-  , order     :: [HPQ.OrderExpr] -> p -> p-  , limit     :: LimitOp -> p -> p-  , join      :: JoinType-              -> HPQ.PrimExpr-              -> Bindings HPQ.PrimExpr-              -> Bindings HPQ.PrimExpr-              -> p-              -> p-              -> p-  , existsf   :: Bool -> p -> p -> p-  , values    :: [Symbol] -> NEL.NonEmpty [HPQ.PrimExpr] -> p-  , binary    :: BinOp -> Bindings (HPQ.PrimExpr, HPQ.PrimExpr) -> (p, p) -> p-  , label     :: String -> p -> p-  , relExpr   :: HPQ.PrimExpr -> Bindings HPQ.PrimExpr -> p+  { unit              :: p+  , empty             :: a -> p+  , baseTable         :: TableIdentifier -> Bindings HPQ.PrimExpr -> p+  , product           :: NEL.NonEmpty p -> [HPQ.PrimExpr] -> p+  , aggregate         :: Bindings (Maybe (HPQ.AggrOp, [HPQ.OrderExpr], HPQ.AggrDistinct), HPQ.PrimExpr) -> p -> p+  , distinctOnOrderBy :: Maybe (NEL.NonEmpty HPQ.PrimExpr) -> [HPQ.OrderExpr] -> p -> p+  , limit             :: LimitOp -> p -> p+  , join              :: JoinType+                      -> HPQ.PrimExpr+                      -> Bindings HPQ.PrimExpr+                      -> Bindings HPQ.PrimExpr+                      -> p+                      -> p+                      -> p+  , existsf           :: Bool -> p -> p -> p+  , values            :: [Symbol] -> NEL.NonEmpty [HPQ.PrimExpr] -> p+  , binary            :: BinOp -> Bindings (HPQ.PrimExpr, HPQ.PrimExpr) -> (p, p) -> p+  , label             :: String -> p -> p+  , relExpr           :: HPQ.PrimExpr -> Bindings HPQ.PrimExpr -> p     -- ^ A relation-valued expression   }   primQueryFoldDefault :: PrimQueryFold' a (PrimQuery' a) primQueryFoldDefault = PrimQueryFold-  { unit      = Unit-  , empty     = Empty-  , baseTable = BaseTable-  , product   = Product-  , aggregate = Aggregate-  , order     = Order-  , limit     = Limit-  , join      = Join-  , values    = Values-  , binary    = Binary-  , label     = Label-  , relExpr   = RelExpr-  , existsf   = Exists+  { unit              = Unit+  , empty             = Empty+  , baseTable         = BaseTable+  , product           = Product+  , aggregate         = Aggregate+  , distinctOnOrderBy = DistinctOnOrderBy+  , limit             = Limit+  , join              = Join+  , values            = Values+  , binary            = Binary+  , label             = Label+  , relExpr           = RelExpr+  , existsf           = Exists   }  foldPrimQuery :: PrimQueryFold' a p -> PrimQuery' a -> p foldPrimQuery f = fix fold   where fold self primQ = case primQ of-          Unit                      -> unit      f-          Empty a                   -> empty     f a-          BaseTable ti syms         -> baseTable f ti syms-          Product qs pes            -> product   f (fmap self qs) pes-          Aggregate aggrs q         -> aggregate f aggrs (self q)-          Order pes q               -> order     f pes (self q)-          Limit op q                -> limit     f op (self q)-          Join j cond pe1 pe2 q1 q2 -> join      f j cond pe1 pe2 (self q1) (self q2)-          Values ss pes             -> values    f ss pes-          Binary binop pes (q1, q2) -> binary    f binop pes (self q1, self q2)-          Label l pq                -> label     f l (self pq)-          RelExpr pe syms           -> relExpr   f pe syms-          Exists b q1 q2            -> existsf   f b (self q1) (self q2)+          Unit                        -> unit              f+          Empty a                     -> empty             f a+          BaseTable ti syms           -> baseTable         f ti syms+          Product qs pes              -> product           f (fmap self qs) pes+          Aggregate aggrs q           -> aggregate         f aggrs (self q)+          DistinctOnOrderBy dxs oxs q -> distinctOnOrderBy f dxs oxs (self q)+          Limit op q                  -> limit             f op (self q)+          Join j cond pe1 pe2 q1 q2   -> join              f j cond pe1 pe2 (self q1) (self q2)+          Values ss pes               -> values            f ss pes+          Binary binop pes (q1, q2)   -> binary            f binop pes (self q1, self q2)+          Label l pq                  -> label             f l (self pq)+          RelExpr pe syms             -> relExpr           f pe syms+          Exists b q1 q2              -> existsf           f b (self q1) (self q2)         fix g = let x = g x in x  times :: PrimQuery -> PrimQuery -> PrimQuery
src/Opaleye/Internal/Print.hs view
@@ -33,9 +33,15 @@ ppSql (SelectLabel v)  = ppSelectLabel v ppSql (SelectExists v) = ppSelectExists v +ppDistinctOn :: Maybe (NEL.NonEmpty HSql.SqlExpr) -> Doc+ppDistinctOn = maybe mempty $ \nel ->+    text "DISTINCT ON" <+>+        text "(" $$ HPrint.commaV HPrint.ppSqlExpr (NEL.toList nel) $$ text ")"+ ppSelectFrom :: From -> Doc ppSelectFrom s = text "SELECT"-                 <+> ppAttrs (Sql.attrs s)+                 <+> ppDistinctOn (Sql.distinctOn s)+                 $$  ppAttrs (Sql.attrs s)                  $$  ppTables (Sql.tables s)                  $$  HPrint.ppWhere (Sql.criteria s)                  $$  ppGroupBy (Sql.groupBy s)
src/Opaleye/Internal/QueryArr.hs view
@@ -17,16 +17,10 @@ import qualified Data.Profunctor as P import qualified Data.Profunctor.Product as PP --- | @QueryArr a b@ is analogous to a Haskell function @a -> [b]@.- -- Ideally this should be wrapped in a monad which automatically -- increments the Tag, but I couldn't be bothered to do that. newtype QueryArr a b = QueryArr ((a, PQ.PrimQuery, Tag) -> (b, PQ.PrimQuery, Tag)) --- | A Postgres query, i.e. some functionality that can run via SQL--- and produce a collection of rows.------ @Query a@ is analogous to a Haskell value @[a]@. type Query = QueryArr ()  simpleQueryArr :: ((a, Tag) -> (b, PQ.PrimQuery, Tag)) -> QueryArr a b
src/Opaleye/Internal/RunQuery.hs view
@@ -89,7 +89,7 @@               -- We never actually look at the columns except to see               -- its "type" in the case of a sum profunctor               (columns -> Bool)-              -- ^ Have we actually requested any columns?  If we+              -- Have we actually requested any columns?  If we               -- asked for zero columns then the SQL generator will               -- have to put a dummy 0 into the SELECT statement,               -- since we can't select zero columns.  In that case we
src/Opaleye/Internal/Sql.hs view
@@ -36,13 +36,14 @@   deriving Show  data From = From {-  attrs     :: SelectAttrs,-  tables    :: [Select],-  criteria  :: [HSql.SqlExpr],-  groupBy   :: Maybe (NEL.NonEmpty HSql.SqlExpr),-  orderBy   :: [(HSql.SqlExpr, HSql.SqlOrder)],-  limit     :: Maybe Int,-  offset    :: Maybe Int+  attrs      :: SelectAttrs,+  tables     :: [Select],+  criteria   :: [HSql.SqlExpr],+  groupBy    :: Maybe (NEL.NonEmpty HSql.SqlExpr),+  orderBy    :: [(HSql.SqlExpr, HSql.SqlOrder)],+  distinctOn :: Maybe (NEL.NonEmpty HSql.SqlExpr),+  limit      :: Maybe Int,+  offset     :: Maybe Int   }           deriving Show @@ -82,19 +83,19 @@  sqlQueryGenerator :: PQ.PrimQueryFold' V.Void Select sqlQueryGenerator = PQ.PrimQueryFold-  { PQ.unit      = unit-  , PQ.empty     = empty-  , PQ.baseTable = baseTable-  , PQ.product   = product-  , PQ.aggregate = aggregate-  , PQ.order     = order-  , PQ.limit     = limit_-  , PQ.join      = join-  , PQ.values    = values-  , PQ.binary    = binary-  , PQ.label     = label-  , PQ.relExpr   = relExpr-  , PQ.existsf   = exists+  { PQ.unit              = unit+  , PQ.empty             = empty+  , PQ.baseTable         = baseTable+  , PQ.product           = product+  , PQ.aggregate         = aggregate+  , PQ.distinctOnOrderBy = distinctOnOrderBy+  , PQ.limit             = limit_+  , PQ.join              = join+  , PQ.values            = values+  , PQ.binary            = binary+  , PQ.label             = label+  , PQ.relExpr           = relExpr+  , PQ.existsf           = exists   }  exists :: Bool -> Select -> Select -> Select@@ -153,10 +154,19 @@ aggrExpr :: Maybe (HPQ.AggrOp, [HPQ.OrderExpr], HPQ.AggrDistinct) -> HPQ.PrimExpr -> HPQ.PrimExpr aggrExpr = maybe id (\(op, ord, distinct) e -> HPQ.AggrExpr distinct op e ord) -order :: [HPQ.OrderExpr] -> Select -> Select-order oes s = SelectFrom $-    newSelect { tables = [s]-              , orderBy = map (SD.toSqlOrder SD.defaultSqlGenerator) oes }+distinctOnOrderBy :: Maybe (NEL.NonEmpty HPQ.PrimExpr) -> [HPQ.OrderExpr] -> Select -> Select+distinctOnOrderBy distinctExprs orderExprs s = SelectFrom $ newSelect+    { tables     = [s]+    , distinctOn = fmap (SG.sqlExpr SD.defaultSqlGenerator) <$> distinctExprs+    , orderBy    = map (SD.toSqlOrder SD.defaultSqlGenerator) $+        -- Postgres requires all 'DISTINCT ON' expressions to appear before any other+        -- 'ORDER BY' expressions if there are any.+        maybe [] (map (HPQ.OrderExpr ascOp) . NEL.toList) distinctExprs ++ orderExprs+    }+    where+        ascOp = HPQ.OrderOp+            { HPQ.orderDirection = HPQ.OpAsc+            , HPQ.orderNulls     = HPQ.NullsLast }  limit_ :: PQ.LimitOp -> Select -> Select limit_ lo s = SelectFrom $ newSelect { tables = [s]@@ -221,13 +231,14 @@  newSelect :: From newSelect = From {-  attrs     = Star,-  tables    = [],-  criteria  = [],-  groupBy   = Nothing,-  orderBy   = [],-  limit     = Nothing,-  offset    = Nothing+  attrs      = Star,+  tables     = [],+  criteria   = [],+  groupBy    = Nothing,+  orderBy    = [],+  distinctOn = Nothing,+  limit      = Nothing,+  offset     = Nothing   }  sqlExpr :: HPQ.PrimExpr -> HSql.SqlExpr
src/Opaleye/Internal/Table.hs view
@@ -19,6 +19,7 @@ import qualified Data.Profunctor.Product as PP import qualified Data.List.NonEmpty as NEL import           Data.Monoid (Monoid, mempty, mappend)+import           Data.Semigroup (Semigroup, (<>)) import           Control.Applicative (Applicative, pure, (<*>), liftA2) import qualified Control.Arrow as Arr @@ -177,6 +178,9 @@         extract (pes, s) = ((Zip (fmap return pes), [s]), ())  data Zip a = Zip { unZip :: NEL.NonEmpty [a] }++instance Semigroup (Zip a) where+  (<>) = mappend  instance Monoid (Zip a) where   mempty = Zip mempty'
src/Opaleye/Operators.hs view
@@ -349,6 +349,14 @@ liesWithin :: T.IsRangeType a => Column a -> Column (T.SqlRange a) -> F.Field T.SqlBool liesWithin = C.binOp (HPQ.:<@) +-- | Access the upper bound of a range. For discrete range types it is the exclusive bound.+upperBound :: T.IsRangeType a => Column (T.SqlRange a) -> Column (C.Nullable a)+upperBound (Column range) = Column $ HPQ.FunExpr "upper" [range]++-- | Access the lower bound of a range. For discrete range types it is the inclusive bound.+lowerBound :: T.IsRangeType a => Column (T.SqlRange a) -> Column (C.Nullable a)+lowerBound (Column range) = Column $ HPQ.FunExpr "lower" [range]+ infix 4 .<< (.<<) :: Column (T.SqlRange a) -> Column (T.SqlRange a) -> F.Field T.SqlBool (.<<) = C.binOp (HPQ.:<<)
src/Opaleye/Order.hs view
@@ -1,7 +1,8 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleContexts #-} --- | Ordering, @LIMIT@ and @OFFSET@+-- | Ordering, @LIMIT@, @OFFSET@ and @DISTINCT ON@  module Opaleye.Order ( -- * Order by                        orderBy@@ -14,6 +15,9 @@                      -- * Limit and offset                      , limit                      , offset+                     -- * Distinct on+                     , distinctOn+                     , distinctOnBy                      -- * Exact ordering                      , O.exact                      -- * Other@@ -21,15 +25,15 @@                      , SqlOrd                      ) where +import qualified Data.Profunctor.Product.Default as D import qualified Opaleye.Column as C-import           Opaleye.QueryArr (Query)-import qualified Opaleye.Internal.QueryArr as Q+import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ import qualified Opaleye.Internal.Order as O+import qualified Opaleye.Internal.QueryArr as Q+import qualified Opaleye.Internal.Unpackspec as U import qualified Opaleye.Select         as S import qualified Opaleye.SqlTypes as T -import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ- -- We can probably disable ConstraintKinds and TypeSynonymInstances -- when we move to Sql... instead of PG.. @@ -116,6 +120,24 @@ -} offset :: Int -> S.Select a -> S.Select a offset n a = Q.simpleQueryArr (O.offset' n . Q.runSimpleQueryArr a)++-- * Distinct on++-- | Keep a row from each set where the given function returns the same result. No+--   ordering is guaranteed. Mutliple fields may be distinguished by projecting out+--   tuples of 'Column's. Use 'distinctOnBy' to control how the rows are chosen.+distinctOn :: D.Default U.Unpackspec b b => (a -> b) -> S.Select a -> S.Select a+distinctOn proj q = Q.simpleQueryArr (O.distinctOn D.def proj . Q.runSimpleQueryArr q)+++-- | Keep the row from each set where the given function returns the same result. The+--   row is chosen according to which comes first by the supplied ordering. However, no+--   output ordering is guaranteed. Mutliple fields may be distinguished by projecting+--   out tuples of 'Column's.+distinctOnBy :: D.Default U.Unpackspec b b => (a -> b) -> O.Order a+             -> S.Select a -> S.Select a+distinctOnBy proj ord q = Q.simpleQueryArr (O.distinctOnBy D.def proj ord . Q.runSimpleQueryArr q)+  -- * Other 
src/Opaleye/QueryArr.hs view
@@ -1,5 +1,5 @@--- | 'Query' and 'QueryArr' are the composable units of database--- querying that are used in Opaleye.+-- | Use "Opaleye.Select" instead.  This module will be deprecated in+-- 0.7.  module Opaleye.QueryArr (Query, QueryArr) where 
src/Opaleye/Select.hs view
@@ -1,6 +1,15 @@+-- | 'Select' and 'SelectArr' are the composable units of database+-- querying that are used in Opaleye.+ module Opaleye.Select where  import qualified Opaleye.QueryArr as Q -type SelectArr = Q.QueryArr+-- | A Postgres @SELECT@, i.e. some functionality that can run via SQL+-- and produce a collection of rows.+--+-- @Select a@ is analogous to a Haskell value @[a]@. type Select = SelectArr ()++-- | @SelectArr a b@ is analogous to a Haskell function @a -> [b]@.+type SelectArr = Q.QueryArr