selda 0.1.8.0 → 0.1.9.0
raw patch · 5 files changed
+57/−11 lines, 5 files
Files
- ChangeLog.md +7/−0
- selda.cabal +2/−2
- src/Database/Selda.hs +1/−1
- src/Database/Selda/Frontend.hs +21/−2
- src/Database/Selda/Query.hs +26/−6
ChangeLog.md view
@@ -1,6 +1,13 @@ # Revision history for Selda +## 0.1.9.0 -- 2017-06-16++* Properly document semantics of order.+* Export conditional inserts.+* Fix Haste build for backends.++ ## 0.1.8.0 -- 2017-06-10 * Move SQL pretty-printing config into a single type.
selda.cabal view
@@ -1,5 +1,5 @@ name: selda-version: 0.1.8.0+version: 0.1.9.0 synopsis: Type-safe, high-level EDSL for interacting with relational databases. description: This package provides an EDSL for writing portable, type-safe, high-level database code. Its feature set includes querying and modifying databases,@@ -11,7 +11,7 @@ To use this package you need at least one backend package, in addition to this package. There are currently two different backend packages: selda-sqlite and selda-postgresql.-homepage: https://github.com/valderman/selda+homepage: https://selda.link license: MIT license-file: LICENSE author: Anton Ekblad
src/Database/Selda.hs view
@@ -93,7 +93,7 @@ , count, avg, sum_, max_, min_ -- * Modifying tables , Insert- , insert, insert_, insertWithPK, tryInsert, def+ , insert, insert_, insertWithPK, tryInsert, insertUnless, insertWhen, def , update, update_, upsert , deleteFrom, deleteFrom_ -- * Prepared statements
src/Database/Selda/Frontend.hs view
@@ -3,7 +3,7 @@ module Database.Selda.Frontend ( Result, Res, MonadIO (..), MonadSelda (..), SeldaT , query- , insert, insert_, insertWithPK, tryInsert, insertUnless+ , insert, insert_, insertWithPK, tryInsert, insertWhen, insertUnless , update, update_, upsert , deleteFrom, deleteFrom_ , createTable, tryCreateTable@@ -109,7 +109,8 @@ -- | Perform the given insert, if no rows already present in the table match -- the given predicate.--- Returns the primary key of the inserted row, if the insert was performed.+-- Returns the primary key of the last inserted row,+-- if the insert was performed. -- If called on a table which doesn't have an auto-incrementing primary key, -- @Just id@ is always returned on successful insert, where @id@ is a row -- identifier guaranteed to not match any row in any table.@@ -124,6 +125,24 @@ -> [a] -> m (Maybe RowID) insertUnless tbl check rows = upsert tbl check id rows++-- | Like 'insertUnless', but performs the insert when at least one row matches+-- the predicate.+insertWhen :: ( MonadCatch m+ , MonadSelda m+ , Insert a+ , Columns (Cols s a)+ , Result (Cols s a)+ )+ => Table a+ -> (Cols s a -> Col s Bool)+ -> [a]+ -> m (Maybe RowID)+insertWhen tbl check rows = transaction $ do+ matches <- update tbl check id+ if matches > 0+ then Just <$> insertWithPK tbl rows+ else pure Nothing -- | Like 'insert', but does not return anything. -- Use this when you really don't care about how many rows were inserted.
src/Database/Selda/Query.hs view
@@ -86,8 +86,8 @@ -- > -- SELECT COUNT(name) AS c, address FROM housing GROUP BY name HAVING c > 1 -- > -- > numPpl = do--- > num_tenants :*: address <- aggregate $ do--- > _ :*: address <- select housing+-- > (num_tenants :*: address) <- aggregate $ do+-- > (_ :*: address) <- select housing -- > groupBy address -- > return (count address :*: some address) -- > restrict (num_tenants .> 1)@@ -121,9 +121,9 @@ -- -- > getAddresses :: Query s (Col s Text :*: Col s (Maybe Text)) -- > getAddresses = do--- > name :*: _ <- select people--- > _ :*: address <- leftJoin (\(n :*: _) -> n .== name)--- > (select addresses)+-- > (name :*: _) <- select people+-- > (_ :*: address) <- leftJoin (\(n :*: _) -> n .== name)+-- > (select addresses) -- > return (name :*: address) leftJoin :: (Columns a, Columns (OuterCols a), Columns (LeftCols a)) => (OuterCols a -> Col s Bool)@@ -168,7 +168,7 @@ -- how many people have a pet at home: -- -- > aggregate $ do--- > name :*: pet_name <- select people+-- > (name :*: pet_name) <- select people -- > name' <- groupBy name -- > return (name' :*: count(pet_name) > 0) groupBy :: Col (Inner s) a -> Query (Inner s) (Aggr (Inner s) a)@@ -193,6 +193,26 @@ return $ unsafeCoerce res -- | Sort the result rows in ascending or descending order on the given row.+--+-- If multiple @order@ directives are given, later directives are given+-- precedence but do not cancel out earlier ordering directives.+-- To get a list of persons sorted primarily on age and secondarily on name:+--+-- > peopleInAgeAndNameOrder = do+-- > (name :*: age) <- select people+-- > order name ascending+-- > order age ascending+-- > return name+--+-- For a table @["Alice" :*: 20, "Bob" :*: 20, "Eve" :*: 18]@, this query+-- will always return @["Eve", "Alice", "Bob"]@.+--+-- The reason for later orderings taking precedence and not the other way+-- around is composability: @order@ should always sort the current+-- result set to avoid weird surprises when a previous @order@ directive+-- is buried somewhere deep in an earlier query.+-- However, the ordering must always be stable, to ensure that previous+-- calls to order are not simply erased. order :: Col s a -> Order -> Query s () order (C c) o = Query $ do st <- get