diff --git a/Database/Groundhog.hs b/Database/Groundhog.hs
--- a/Database/Groundhog.hs
+++ b/Database/Groundhog.hs
@@ -20,6 +20,7 @@
   , limitTo
   , offsetBy
   , orderBy
+  , deleteByKey
   -- * Expressions
   , (=.)
   , (&&.), (||.)
diff --git a/Database/Groundhog/Core.hs b/Database/Groundhog/Core.hs
--- a/Database/Groundhog/Core.hs
+++ b/Database/Groundhog/Core.hs
@@ -273,10 +273,12 @@
   insertByAll   :: PersistEntity v => v -> m (Either (AutoKey v) (AutoKey v))
   -- | Replace a record with the given autogenerated key. Result is undefined if the record does not exist.
   replace       :: (PersistEntity v, PrimitivePersistField (Key v BackendSpecific)) => Key v BackendSpecific -> v -> m ()
+  -- | Replace a record. The unique key marker defines what unique key of the entity is used.
+  replaceBy     :: (PersistEntity v, IsUniqueKey (Key v (Unique u))) => u (UniqueMarker v) -> v -> m ()
   -- | Return a list of the records satisfying the condition. Example: @select $ (FirstField ==. \"abc\" &&. SecondField >. \"def\") \`orderBy\` [Asc ThirdField] \`limitTo\` 100@
   select        :: (PersistEntity v, EntityConstr v c, HasSelectOptions opts (PhantomDb m) (RestrictionHolder v c))
                 => opts -> m [v]
-  -- | Return a list of all records. Order is undefined. It is useful for datatypes with multiple constructors.
+  -- | Return a list of all records. Order is undefined. It can be useful for datatypes with multiple constructors.
   selectAll     :: PersistEntity v => m [(AutoKey v, v)]
   -- | Fetch an entity from a database
   get           :: (PersistEntity v, PrimitivePersistField (Key v BackendSpecific)) => Key v BackendSpecific -> m (Maybe v)
@@ -287,10 +289,12 @@
   -- | Remove the records satisfying the condition
   delete        :: (PersistEntity v, EntityConstr v c) => Cond (PhantomDb m) (RestrictionHolder v c) -> m ()
   -- | Remove the record with given key. No-op if the record does not exist
-  deleteByKey   :: (PersistEntity v, PrimitivePersistField (Key v BackendSpecific)) => Key v BackendSpecific -> m ()
+  deleteBy      :: (PersistEntity v, PrimitivePersistField (Key v BackendSpecific)) => Key v BackendSpecific -> m ()
+  -- | Remove all records. The entity parameter is used only for type inference.
+  deleteAll     :: PersistEntity v => v -> m ()
   -- | Count total number of records satisfying the condition
   count         :: (PersistEntity v, EntityConstr v c) => Cond (PhantomDb m) (RestrictionHolder v c) -> m Int
-  -- | Count total number of records with all constructors
+  -- | Count total number of records with all constructors. The entity parameter is used only for type inference
   countAll      :: PersistEntity v => v -> m Int
   -- | Fetch projection of some fields. Example: @project (SecondField, ThirdField) $ (FirstField ==. \"abc\" &&. SecondField >. \"def\") \`orderBy\` [Asc ThirdField] \`offsetBy\` 100@
   project       :: (PersistEntity v, EntityConstr v c, Projection p (PhantomDb m) (RestrictionHolder v c) a, HasSelectOptions opts (PhantomDb m) (RestrictionHolder v c))
diff --git a/Database/Groundhog/Expression.hs b/Database/Groundhog/Expression.hs
--- a/Database/Groundhog/Expression.hs
+++ b/Database/Groundhog/Expression.hs
@@ -8,7 +8,8 @@
 -- StringField ==. \"abc\" &&. NumberField >. (0 :: Int) ||. MaybeField ==. (Nothing :: Maybe String) ||. MaybeField ==. Just \"def\"
 -- @
 --
--- Note that polymorphic values like numbers or Nothing must have a type annotation
+-- Note that polymorphic values like numbers or Nothing must have a type annotation.
+-- Comparison operators specific for SQL such as IN and LIKE are defined in "Database.Groundhog.Generic.Sql.Functions".
 
 module Database.Groundhog.Expression
   ( Expression(..)
@@ -142,4 +143,4 @@
 isFieldNothing :: (Expression db r f, FieldLike f db r (Maybe a), PrimitivePersistField (Maybe a), Unifiable f (Maybe a)) => f -> Cond db r
 isFieldNothing a = a `eq` Nothing where
   eq :: (Expression db r f, Expression db r a, FieldLike f db r a, Unifiable f a) => f -> a -> Cond db r
-  eq = (==.)
+  eq = (==.)
diff --git a/Database/Groundhog/Generic.hs b/Database/Groundhog/Generic.hs
--- a/Database/Groundhog/Generic.hs
+++ b/Database/Groundhog/Generic.hs
@@ -51,6 +51,7 @@
   , mapAllRows
   , phantomDb
   , isSimple
+  , deleteByKey
   ) where
 
 import Database.Groundhog.Core
@@ -319,3 +320,7 @@
 -- | It helps to run 'withConnSavepoint' within a monad.
 withSavepoint :: (HasConn m cm conn, SingleConnectionManager cm conn, Savepoint conn) => String -> m a -> m a
 withSavepoint name m = ask >>= withConnNoTransaction (withConnSavepoint name m)
+
+{-# DEPRECATED deleteByKey "Use deleteBy instead" #-}
+deleteByKey :: (PersistBackend m, PersistEntity v, PrimitivePersistField (Key v BackendSpecific)) => Key v BackendSpecific -> m ()
+deleteByKey = deleteBy
diff --git a/Database/Groundhog/Generic/PersistBackendHelpers.hs b/Database/Groundhog/Generic/PersistBackendHelpers.hs
--- a/Database/Groundhog/Generic/PersistBackendHelpers.hs
+++ b/Database/Groundhog/Generic/PersistBackendHelpers.hs
@@ -10,10 +10,12 @@
   , project
   , count
   , replace
+  , replaceBy
   , update
   , delete
+  , deleteBy
+  , deleteAll
   , insertByAll
-  , deleteByKey
   , countAll
   , insertBy
   ) where
@@ -196,6 +198,23 @@
               execFunc updateDiscrQuery [head vals, toPrimitivePersistValue proxy k]
         Nothing -> return ()
 
+replaceBy :: forall m v u . (PersistBackend m, PersistEntity v, IsUniqueKey (Key v (Unique u)))
+          => (Utf8 -> Utf8) -- ^ escape
+          -> (Utf8 -> [PersistValue] -> m ()) -- ^ function to execute query
+          -> u (UniqueMarker v)
+          -> v
+          -> m ()
+replaceBy escape execFunc u v = do
+  uniques <- toPersistValues $ (extractUnique v `asTypeOf` ((undefined :: u (UniqueMarker v) -> Key v (Unique u)) u))
+  vals <- toEntityPersistValues v
+  let e = entityDef (undefined :: v)
+      uFields = renderChain escape (fieldChain u) []
+      RenderS cond condVals = intercalateS " AND " $ mkUniqueCond uFields uniques
+      constr = head $ constructors e
+      upds = renderFields (\f -> escape f <> "=?") $ constrParams constr
+      updateQuery = "UPDATE " <> tableName escape e constr <> " SET " <> upds <> " WHERE " <> cond
+  execFunc updateQuery (tail . vals . condVals $ [])
+
 update :: forall m db r v c . (SqlDb db, QueryRaw db ~ Snippet db, db ~ PhantomDb m, r ~ RestrictionHolder v c, PersistBackend m, PersistEntity v, EntityConstr v c)
        => (Utf8 -> Utf8) -> (Utf8 -> [PersistValue] -> m ()) -> (Cond db r -> Maybe (RenderS db r)) -> [Update db r] -> Cond db r -> m ()
 update escape execFunc renderCond' upds cond = do
@@ -247,9 +266,9 @@
         Nothing -> liftM Right $ Core.insert v
         Just xs -> return $ Left $ fst $ fromPurePersistValues proxy xs
 
-deleteByKey :: forall m v . (PersistBackend m, PersistEntity v, PrimitivePersistField (Key v BackendSpecific))
+deleteBy :: forall m v . (PersistBackend m, PersistEntity v, PrimitivePersistField (Key v BackendSpecific))
             => (Utf8 -> Utf8) -> (Utf8 -> [PersistValue] -> m ()) -> Key v BackendSpecific -> m ()
-deleteByKey escape execFunc k = execFunc query [toPrimitivePersistValue proxy k] where
+deleteBy escape execFunc k = execFunc query [toPrimitivePersistValue proxy k] where
   e = entityDef ((undefined :: Key v u -> v) k)
   proxy = undefined :: Proxy (PhantomDb m)
   constr = head $ constructors e
@@ -258,6 +277,13 @@
     else "id"
   -- the entries in the constructor table are deleted because of the reference on delete cascade
   query = "DELETE FROM " <> mainTableName escape e <> " WHERE " <> idName <> "=?"
+
+deleteAll :: forall m v . (PersistBackend m, PersistEntity v)
+          => (Utf8 -> Utf8) -> (Utf8 -> [PersistValue] -> m ()) -> v -> m ()
+deleteAll escape execFunc (_ :: v) = do
+  let e = entityDef (undefined :: v)
+      query = "DELETE FROM " <> mainTableName escape e
+  execFunc query []
 
 countAll :: forall m v . (PersistBackend m, PersistEntity v)
          => (Utf8 -> Utf8) -> (forall a . Utf8 -> [DbType] -> [PersistValue] -> (RowPopper m -> m a) -> m a) -> v -> m Int
diff --git a/Database/Groundhog/Generic/Sql/Functions.hs b/Database/Groundhog/Generic/Sql/Functions.hs
--- a/Database/Groundhog/Generic/Sql/Functions.hs
+++ b/Database/Groundhog/Generic/Sql/Functions.hs
@@ -18,10 +18,12 @@
 
 in_ :: (SqlDb db, QueryRaw db ~ Snippet db, Expression db r a, Expression db r b, PrimitivePersistField b, Unifiable a b) =>
     a -> [b] -> Cond db r
+in_ _ [] = CondEmpty
 in_ a bs = CondRaw $ Snippet $ \esc p -> [parens 45 p $ renderExpr esc (toExpr a) <> " IN (" <> commasJoin (map (renderExpr esc . toExpr) bs) <> ")"]
 
 notIn_ :: (SqlDb db, QueryRaw db ~ Snippet db, Expression db r a, Expression db r b, PrimitivePersistField b, Unifiable a b) =>
        a -> [b] -> Cond db r
+notIn_ _ [] = CondEmpty
 notIn_ a bs = CondRaw $ Snippet $ \esc p -> [parens 45 p $ renderExpr esc (toExpr a) <> " NOT IN (" <> commasJoin (map (renderExpr esc . toExpr) bs) <> ")"]
 
 like :: (SqlDb db, QueryRaw db ~ Snippet db, ExpressionOf db r a String) => a -> String -> Cond db r
diff --git a/Database/Groundhog/Instances.hs b/Database/Groundhog/Instances.hs
--- a/Database/Groundhog/Instances.hs
+++ b/Database/Groundhog/Instances.hs
@@ -12,7 +12,7 @@
 import Data.ByteString.Char8 (ByteString, unpack)
 import Data.Int (Int8, Int16, Int32, Int64)
 import Data.Time (Day, TimeOfDay, UTCTime)
-import Data.Time.LocalTime (ZonedTime)
+import Data.Time.LocalTime (ZonedTime, zonedTimeToUTC, utc, utcToZonedTime)
 import Data.Word (Word8, Word16, Word32, Word64)
 
 instance (PersistField a', PersistField b') => Embedded (a', b') where
@@ -187,11 +187,13 @@
 instance PrimitivePersistField UTCTime where
   toPrimitivePersistValue _ a = PersistUTCTime a
   fromPrimitivePersistValue _ (PersistUTCTime a) = a
+  fromPrimitivePersistValue _ (PersistZonedTime (ZT a)) = zonedTimeToUTC a
   fromPrimitivePersistValue _ x = readHelper x ("Expected UTCTime, received: " ++ show x)
 
 instance PrimitivePersistField ZonedTime where
   toPrimitivePersistValue _ a = PersistZonedTime (ZT a)
   fromPrimitivePersistValue _ (PersistZonedTime (ZT a)) = a
+  fromPrimitivePersistValue _ (PersistUTCTime a) = utcToZonedTime utc a
   fromPrimitivePersistValue _ x = readHelper x ("Expected ZonedTime, received: " ++ show x)
 
 instance (PrimitivePersistField a, NeverNull a) => PrimitivePersistField (Maybe a) where
diff --git a/groundhog.cabal b/groundhog.cabal
--- a/groundhog.cabal
+++ b/groundhog.cabal
@@ -1,11 +1,11 @@
 name:            groundhog
-version:         0.4.0.3
+version:         0.4.1
 license:         BSD3
 license-file:    LICENSE
 author:          Boris Lykah <lykahb@gmail.com>
 maintainer:      Boris Lykah <lykahb@gmail.com>
 synopsis:        Type-safe datatype-database mapping library.
-description:     This library maps your datatypes to a relational model, in a way similar to what ORM libraries do in OOP. The schema can be configured flexibly which makes integration with existing databases easy. Groundhog supports schema migrations, composite keys, advanced expressions in queries, and much more. See examples folder on GitHub.
+description:     This library maps your datatypes to a relational model, in a way similar to what ORM libraries do in OOP. The schema can be configured flexibly which makes integration with existing databases easy. Groundhog supports schema migrations, composite keys, advanced expressions in queries, and much more. See tutorial <https://www.fpcomplete.com/user/lykahb/groundhog> and examples <https://github.com/lykahb/groundhog/tree/master/examples> on GitHub.
 category:        Database
 stability:       Stable
 cabal-version:   >= 1.6
