diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -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.
diff --git a/selda.cabal b/selda.cabal
--- a/selda.cabal
+++ b/selda.cabal
@@ -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
diff --git a/src/Database/Selda.hs b/src/Database/Selda.hs
--- a/src/Database/Selda.hs
+++ b/src/Database/Selda.hs
@@ -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
diff --git a/src/Database/Selda/Frontend.hs b/src/Database/Selda/Frontend.hs
--- a/src/Database/Selda/Frontend.hs
+++ b/src/Database/Selda/Frontend.hs
@@ -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.
diff --git a/src/Database/Selda/Query.hs b/src/Database/Selda/Query.hs
--- a/src/Database/Selda/Query.hs
+++ b/src/Database/Selda/Query.hs
@@ -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
