packages feed

esqueleto 0.2.1 → 0.2.2

raw patch · 3 files changed

+178/−35 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Database.Esqueleto.Internal.Language: class Esqueleto query expr backend => From query expr backend a
+ Database.Esqueleto.Internal.Language: class Esqueleto query expr backend => FromPreprocess query expr backend a
+ Database.Esqueleto.Internal.Sql: class SqlSelect a r | a -> r, r -> a
+ Database.Esqueleto.Internal.Sql: type Escape = DBName -> Builder

Files

esqueleto.cabal view
@@ -1,5 +1,5 @@ name:                esqueleto-version:             0.2.1+version:             0.2.2 synopsis:            Bare bones, type-safe EDSL for SQL queries on persistent backends. homepage:            https://github.com/meteficha/esqueleto license:             BSD3@@ -42,7 +42,8 @@   <https://github.com/meteficha/esqueleto/>.   .   The name of this library means \"skeleton\" in Portuguese and-  contains all three SQL letters in the correct order =).+  contains all three SQL letters in the correct order =).  It was+  inspired by Scala's Squeryl but created from scratch.  source-repository head   type:     git
src/Database/Esqueleto/Internal/Language.hs view
@@ -7,8 +7,12 @@            , TypeFamilies            , UndecidableInstances  #-}+-- | This is an internal module, anything exported by this module+-- may change without a major version bump.  Please use only+-- "Database.Esqueleto" if possible. module Database.Esqueleto.Internal.Language-  ( Esqueleto(..)+  ( -- * The pretty face+    Esqueleto(..)   , from   , Value(..)   , InnerJoin(..)@@ -16,12 +20,15 @@   , LeftOuterJoin(..)   , RightOuterJoin(..)   , FullOuterJoin(..)-  , JoinKind(..)-  , IsJoinKind(..)   , OnClauseWithoutMatchingJoinException(..)-  , PreprocessedFrom   , OrderBy   , Update+    -- * The guts+  , JoinKind(..)+  , IsJoinKind(..)+  , PreprocessedFrom+  , From+  , FromPreprocess   ) where  import Control.Applicative (Applicative(..), (<$>))@@ -82,7 +89,7 @@   --   -- @   -- select $-  -- from $ \(foo `InnerJoin` bar) -> do+  -- from $ \\(foo ``InnerJoin`` bar) -> do   --   on (foo ^. FooId ==. bar ^. BarFooId)   --   ...   -- @@@ -94,7 +101,7 @@   --   -- @   -- select $-  -- from $ \(foo `InnerJoin` bar `InnerJoin` baz) -> do+  -- from $ \\(foo ``InnerJoin`` bar ``InnerJoin`` baz) -> do   --   on (baz ^. BazId ==. bar ^. BarBazId)   --   on (foo ^. FooId ==. bar ^. BarFooId)   --   ...@@ -105,18 +112,16 @@   --   -- @   -- let query1 =-  --       from $ \(foo `InnerJoin` bar) -> do+  --       from $ \\(foo ``InnerJoin`` bar) -> do   --         on (foo ^. FooId ==. bar ^. BarFooId)-  --   --     query2 =-  --       from $ \(mbaz `LeftOuterJoin` quux) -> do+  --       from $ \\(mbaz ``LeftOuterJoin`` quux) -> do   --         return (mbaz ?. BazName, quux)-  ---  --     test1 =      (,) <$> query1 <*> query2-  --     test2 = flip (,) <$> query2 <*> query1+  --     test1 =      (,) \<$\> query1 \<*\> query2+  --     test2 = flip (,) \<$\> query2 \<*\> query1   -- @   ---  -- If the order was *not* reversed, then @test2@ would be+  -- If the order was /not/ reversed, then @test2@ would be   -- broken: @query1@'s 'on' would refer to @query2@'s   -- 'LeftOuterJoin'.   on :: expr (Value Bool) -> query ()@@ -150,9 +155,9 @@   -- | @IS NULL@ comparison.   isNothing :: PersistField typ => expr (Value (Maybe typ)) -> expr (Value Bool) -  -- | Analog to 'Just', promotes a value of type @typ@ into one-  -- of type @Maybe typ@.  It should hold that @val . Just ===-  -- just . val@.+  -- | Analogous to 'Just', promotes a value of type @typ@ into+  -- one of type @Maybe typ@.  It should hold that @val . Just+  -- === just . val@.   just :: expr (Value typ) -> expr (Value (Maybe typ))    -- | @NULL@ value.@@ -215,7 +220,7 @@ -- -- @ -- select $--- from $ \(person `LeftOuterJoin` pet) ->+-- from $ \\(person ``LeftOuterJoin`` pet) -> --   ... -- @ --@@ -226,6 +231,8 @@ -- FROM Person LEFT OUTER JOIN Pet -- ... -- @+--+-- See also: 'from'. data LeftOuterJoin a b = a `LeftOuterJoin` b  -- | Data type that represents a @RIGHT OUTER JOIN@ (see 'LeftOuterJoin' for an example).@@ -290,19 +297,75 @@ data Update typ  --- | @FROM@ clause: bring an entity into scope.+-- | @FROM@ clause: bring entities into scope. ----- The following types implement 'from':+-- This function internally uses two type classes in order to+-- provide some flexibility of how you may call it.  Internally+-- we refer to these type classes as the two different magics. -----  * @Expr (Entity val)@, which brings a single entity into scope.+-- The innermost magic allows you to use @from@ with the+-- following types: -----  * Tuples of any other types supported by 'from'.  Calling---  'from' multiple times is the same as calling 'from' a---  single time and using a tuple.+--  * @expr (Entity val)@, which brings a single entity into+--  scope. ----- Note that using 'from' for the same entity twice does work--- and corresponds to a self-join.  You don't even need to use--- two different calls to 'from', you may use a tuple.+--  * @expr (Maybe (Entity val))@, which brings a single entity+--  that may be @NULL@ into scope.  Used for @OUTER JOIN@s.+--+--  * A @JOIN@ of any other two types allowed by the innermost+--  magic, where a @JOIN@ may be an 'InnerJoin', a 'CrossJoin', a+--  'LeftOuterJoin', a 'RightOuterJoin', or a 'FullOuterJoin'.+--  The @JOINs@ have right fixity, the same as in SQL.+--+-- The outermost magic allows you to use @from@ on any tuples of+-- types supported by innermost magic (and also tuples of tuples,+-- and so on), up to 8-tuples.+--+-- Note that using @from@ for the same entity twice does work and+-- corresponds to a self-join.  You don't even need to use two+-- different calls to @from@, you may use a @JOIN@ or a tuple.+--+-- The following are valid examples of uses of @from@ (the types+-- of the arguments of the lambda are inside square brackets):+--+-- @+-- from $ \\person -> ...+-- from $ \\(person, blogPost) -> ...+-- from $ \\(p ``LeftOuterJoin`` mb) -> ...+-- from $ \\(p1 ``InnerJoin`` f ``InnerJoin`` p2) -> ...+-- from $ \\((p1 ``InnerJoin`` f) ``InnerJoin`` p2) -> ...+-- @+--+-- The types of the arguments to the lambdas above are,+-- respectively:+--+-- @+-- person+--   :: ( Esqueleto query expr backend+--      , PersistEntity Person+--      , PersistEntityBackend Person ~ backend+--      ) => expr (Entity Person)+-- (person, blogPost)+--   :: (...) => (expr (Entity Person), expr (Entity BlogPost))+-- (p ``LeftOuterJoin`` mb)+--   :: (...) => InnerJoin (expr (Entity Person)) (expr (Maybe (Entity BlogPost)))+-- (p1 ``InnerJoin`` f ``InnerJoin`` p2)+--   :: (...) => InnerJoin+--                 (expr (Entity Person))+--                 (InnerJoin (expr (Entity Follow))+--                            (expr (Entity Person)))+-- ((p1 ``InnerJoin`` f) ``InnerJoin`` p2) ::+--   :: (...) => InnerJoin+--                 (InnerJoin (expr (Entity Person))+--                            (expr (Entity Follow)))+--                 (expr (Entity Person))+-- @+--+-- Note that some backends may not support all kinds of @JOIN@s.+-- For example, when using the SQL backend with SQLite, it will+-- not accept the last example above (which is associated to the+-- left, instead of being to the right) and will not accept+-- 'RightOuterJoin's or 'FullOuterJoin's. from :: From query expr backend a => (a -> query b) -> query b from = (from_ >>=) 
src/Database/Esqueleto/Internal/Sql.hs view
@@ -7,20 +7,27 @@            , OverloadedStrings            , UndecidableInstances  #-}+-- | This is an internal module, anything exported by this module+-- may change without a major version bump.  Please use only+-- "Database.Esqueleto" if possible. module Database.Esqueleto.Internal.Sql-  ( SqlQuery+  ( -- * The pretty face+    SqlQuery   , SqlExpr   , select   , selectSource   , selectDistinct   , selectDistinctSource+  , delete+  , update+    -- * The guts   , rawSelectSource   , runSource   , rawExecute-  , delete-  , update   , toRawSql   , Mode(..)+  , Escape+  , SqlSelect   ) where  import Control.Applicative (Applicative(..), (<$>))@@ -199,6 +206,7 @@  data OrderByType = ASC | DESC +-- | (Internal) Backend-specific function that escapes a 'DBName'. type Escape = DBName -> TLB.Builder  @@ -356,6 +364,45 @@  -- | Execute an @esqueleto@ @SELECT@ query inside @persistent@'s -- 'SqlPersist' monad and return a list of rows.+--+-- We've seen that 'from' has some magic about which kinds of+-- things you may bring into scope.  This 'select' function also+-- has some magic for which kinds of things you may bring back to+-- Haskell-land by using @SqlQuery@'s @return@:+--+--  * You may return a @SqlExpr ('Entity' v)@ for an entity @v@+--  (i.e., like the @*@ in SQL), which is then returned to+--  Haskell-land as just @Entity v@.+--+--  * You may return a @SqlExpr (Maybe (Entity v))@ for an entity+--  @v@ that may be @NULL@, which is then returned to+--  Haskell-land as @Maybe (Entity v)@.  Used for @OUTER JOIN@s.+--+--  * You may return a @SqlExpr ('Value' t)@ for a value @t@+--  (i.e., a single column), where @t@ is any instance of+--  'PersistField', which is then returned to Haskell-land as+--  @Value t@.  You may use @Value@ to return projections of an+--  @Entity@ (see @('^.')@ and @('?.')@) or to return any other+--  value calculated on the query (e.g., 'countRows' or+--  'sub_select').+--+-- The @SqlSelect a r@ class has functional dependencies that+-- allow type information to flow both from @a@ to @r@ and+-- vice-versa.  This means that you'll almost never have to give+-- any type signatures for @esqueleto@ queries.  For example, the+-- query @select $ from $ \\p -> return p@ alone is ambiguous, but+-- in the context of+--+-- @+-- do ps <- select $+--          from $ \\p ->+--          return p+--    liftIO $ mapM_ (putStrLn . personName . entityVal) ps+-- @+--+-- we are able to infer from that single @personName . entityVal@+-- function composition that the @p@ inside the query is of type+-- @SqlExpr (Entity Person)@. select :: ( SqlSelect a r           , MonadLogger m           , MonadResourceBase m )@@ -384,7 +431,7 @@ selectDistinct = selectDistinctSource >=> runSource  --- | Runs a 'C.Source' of rows.+-- | (Internal) Run a 'C.Source' of rows. runSource :: MonadResourceBase m =>              C.Source (C.ResourceT (SqlPersist m)) r           -> SqlPersist m [r]@@ -420,6 +467,16 @@ -- from $ \\appointment -> -- where_ (appointment ^. AppointmentDate <. val now) -- @+--+-- Unlike 'select', there is a useful way of using 'delete' that+-- will lead to type ambiguities.  If you want to delete all rows+-- (i.e., no 'where_' clause), you'll have to use a type signature:+--+-- @+-- delete $+-- from $ \\(appointment :: SqlExpr (Entity Appointment)) ->+-- return ()+-- @ delete :: ( MonadLogger m           , MonadResourceBase m )        => SqlQuery ()@@ -451,7 +508,12 @@ ----------------------------------------------------------------------  --- | Pretty prints a 'SqlQuery' into a SQL query.+-- | (Internal) Pretty prints a 'SqlQuery' into a SQL query.+--+-- Note: if you're curious about the SQL query being generated by+-- @esqueleto@, instead of manually using this function (which is+-- possible but tedious), you may just turn on query logging of+-- @persistent@. toRawSql :: SqlSelect a r => Mode -> Escape -> SqlQuery a -> (TLB.Builder, [PersistValue]) toRawSql mode esc query =   let (ret, SideData fromClauses setClauses whereClauses orderByClauses) =@@ -466,6 +528,7 @@       , makeOrderBy esc orderByClauses       ] +-- | (Internal) Mode of query being converted by 'toRawSql'. data Mode = SELECT | SELECT_DISTINCT | DELETE | UPDATE  @@ -552,8 +615,11 @@ parens b = "(" <> (b <> ")")  --- | Class for mapping results coming from 'SqlQuery' into actual--- results.+----------------------------------------------------------------------+++-- | (Internal) Class for mapping results coming from 'SqlQuery'+-- into actual results. -- -- This looks very similar to @RawSql@, and it is!  However, -- there are some crucial differences and ultimately they're@@ -571,11 +637,15 @@   -- | Transform a row of the result into the data type.   sqlSelectProcessRow :: [PersistValue] -> Either T.Text r ++-- | Not useful for 'select', but used for 'update' and 'delete'. instance SqlSelect () () where   sqlSelectCols _ _ = mempty   sqlSelectColCount _ = 0   sqlSelectProcessRow _ = Right () ++-- | You may return an 'Entity' from a 'select' query. instance PersistEntity a => SqlSelect (SqlExpr (Entity a)) (Entity a) where   sqlSelectCols escape expr@(EEntity ident) = ret       where@@ -602,6 +672,8 @@ getEntityVal :: SqlExpr (Entity a) -> a getEntityVal = error "Esqueleto/Sql/getEntityVal" ++-- | You may return a possibly-@NULL@ 'Entity' from a 'select' query. instance PersistEntity a => SqlSelect (SqlExpr (Maybe (Entity a))) (Maybe (Entity a)) where   sqlSelectCols escape (EMaybe ent) = sqlSelectCols escape ent   sqlSelectColCount = sqlSelectColCount . fromEMaybe@@ -612,6 +684,9 @@     | all (== PersistNull) cols = return Nothing     | otherwise                 = Just <$> sqlSelectProcessRow cols ++-- | You may return any single value (i.e. a single column) from+-- a 'select' query. instance PersistField a => SqlSelect (SqlExpr (Value a)) (Value a) where   sqlSelectCols esc (ERaw p f) = let (b, vals) = f esc                                  in (parensM p b, vals)@@ -619,6 +694,9 @@   sqlSelectProcessRow [pv] = Value <$> fromPersistValue pv   sqlSelectProcessRow _    = Left "SqlSelect (Value a): wrong number of columns." ++-- | You may return tuples (up to 8-tuples) and tuples of tuples+-- from a 'select' query. instance ( SqlSelect a ra          , SqlSelect b rb          ) => SqlSelect (a, b) (ra, rb) where@@ -642,6 +720,7 @@      in colCountFst `seq` processRow        -- Avoids recalculating 'colCountFst'.+  instance ( SqlSelect a ra          , SqlSelect b rb