diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
 # CHANGELOG
 
+## 3.0.0
+### Added
+* Ability to mask some sensitive query arguments in query logs. In case you dont
+  want someone can see your secret data in logs.
+  * Added interpolation syntax `#?{argumentExpression}` for masked parameters
+  * Added `pgQueryWithMasker` and `pgExecuteWithMasker` for custom log masker
+* `MonadPostgres` type synonim
+### Changed
+* Refactoring of `SqlBuilder` and `Entity` modules
+* Some low-level intefaces changed
 ## 2.3.0
 ### Added
 * `derivePgEnum` TH generator for enum fields
diff --git a/postgresql-query.cabal b/postgresql-query.cabal
--- a/postgresql-query.cabal
+++ b/postgresql-query.cabal
@@ -1,5 +1,5 @@
 name:                postgresql-query
-version:             2.3.0
+version:             3.0.0
 
 synopsis: Sql interpolating quasiquote plus some kind of primitive ORM
           using it
@@ -25,9 +25,15 @@
 
   exposed-modules: Database.PostgreSQL.Query
                  , Database.PostgreSQL.Query.Entity
+                 , Database.PostgreSQL.Query.Entity.Class
+                 , Database.PostgreSQL.Query.Entity.Functions
+                 , Database.PostgreSQL.Query.Entity.Internal
                  , Database.PostgreSQL.Query.Functions
                  , Database.PostgreSQL.Query.Internal
                  , Database.PostgreSQL.Query.SqlBuilder
+                 , Database.PostgreSQL.Query.SqlBuilder.Builder
+                 , Database.PostgreSQL.Query.SqlBuilder.Class
+                 , Database.PostgreSQL.Query.SqlBuilder.Types
                  , Database.PostgreSQL.Query.TH
                  , Database.PostgreSQL.Query.TH.Common
                  , Database.PostgreSQL.Query.TH.Entity
@@ -36,18 +42,20 @@
                  , Database.PostgreSQL.Query.TH.SqlExp
                  , Database.PostgreSQL.Query.Types
 
-  default-extensions: CPP
+  default-extensions: AutoDeriveTypeable
+                    , CPP
+                    , ConstraintKinds
+                    , DataKinds
                     , DeriveDataTypeable
                     , DeriveGeneric
                     , EmptyDataDecls
                     , FlexibleContexts
                     , FlexibleInstances
+                    , FunctionalDependencies
                     , GADTs
                     , GeneralizedNewtypeDeriving
                     , LambdaCase
                     , MultiParamTypeClasses
-                    , NoImplicitPrelude
-                    , NoMonomorphismRestriction
                     , OverloadedStrings
                     , QuasiQuotes
                     , RecordWildCards
@@ -88,6 +96,7 @@
                , transformers
                , transformers-base
                , transformers-compat           >= 0.3
+               , type-fun                      >= 0.1.0
 
   ghc-options: -Wall
 
@@ -100,15 +109,21 @@
   ghc-options:     -Wall
   hs-source-dirs:  test
   main-is: Main.hs
+  other-modules: BuilderTest
+               , ParserTest
 
-  default-extensions: FlexibleInstances
+  default-extensions: CPP
+                    , FlexibleInstances
                     , OverloadedStrings
+                    , QuasiQuotes
                     , TemplateHaskell
 
   build-depends: QuickCheck
                , attoparsec
                , base                          >=4.6 && < 5
+               , derive
                , postgresql-query
+               , postgresql-simple
                , quickcheck-assertions
                , quickcheck-instances
                , tasty
@@ -124,7 +139,8 @@
   hs-source-dirs:  example
   main-is: Main.hs
 
-  default-extensions: FlexibleInstances
+  default-extensions: AutoDeriveTypeable
+                    , FlexibleInstances
                     , OverloadedStrings
                     , TemplateHaskell
 
diff --git a/src/Database/PostgreSQL/Query.hs b/src/Database/PostgreSQL/Query.hs
--- a/src/Database/PostgreSQL/Query.hs
+++ b/src/Database/PostgreSQL/Query.hs
@@ -12,7 +12,7 @@
        , FromRow(..), Query(..), Only(..), In(..), Oid(..), Values(..)
        , (:.)(..), PGArray(..), HStoreList(..), HStoreMap(..)
        , ToHStore(..), HStoreBuilder , hstore, parseHStoreList
-       , ToHStoreText(..), HStoreText , sqlQQ
+       , ToHStoreText(..), HStoreText
        ) where
 
 
@@ -23,19 +23,12 @@
 import Database.PostgreSQL.Simple.FromRow ( FromRow(..) )
 import Database.PostgreSQL.Simple.HStore hiding
     ( toBuilder, toLazyByteString ) -- to prevent conflicts
-import Database.PostgreSQL.Simple.SqlQQ
 import Database.PostgreSQL.Simple.ToField ( ToField(..) )
 import Database.PostgreSQL.Simple.ToRow ( ToRow(..) )
 import Database.PostgreSQL.Simple.Types
-import Language.Haskell.TH.Quote ( QuasiQuoter )
 
 import Database.PostgreSQL.Query.Entity
 import Database.PostgreSQL.Query.Functions
 import Database.PostgreSQL.Query.SqlBuilder
 import Database.PostgreSQL.Query.TH
 import Database.PostgreSQL.Query.Types
-
-sqlQQ :: QuasiQuoter
-sqlQQ = sql
-
-{-# DEPRECATED sqlQQ "Use 'sqlExp' instead" #-}
diff --git a/src/Database/PostgreSQL/Query/Entity.hs b/src/Database/PostgreSQL/Query/Entity.hs
--- a/src/Database/PostgreSQL/Query/Entity.hs
+++ b/src/Database/PostgreSQL/Query/Entity.hs
@@ -1,26 +1,9 @@
 module Database.PostgreSQL.Query.Entity
-       ( Entity(..)
-       , Ent
-       ) where
-
-import Data.Proxy
-import Data.Text ( Text )
-import Data.Typeable ( Typeable )
-import Database.PostgreSQL.Query.Types
-
--- | Auxiliary typeclass for data types which can map to rows of some
--- table. This typeclass is used inside functions like 'pgSelectEntities' to
--- generate queries.
-class Entity a where
-    -- | Id type for this entity
-    data EntityId a :: *
-    -- | Table name of this entity
-    tableName :: Proxy a -> FN
-    -- | Field names without 'id' and 'created'. The order of field names must match
-    -- with order of fields in 'ToRow' and 'FromRow' instances of this type.
-    fieldNames :: Proxy a -> [FN]
-
-deriving instance Typeable EntityId
+  ( module Database.PostgreSQL.Query.Entity.Class
+  , module Database.PostgreSQL.Query.Entity.Functions
+  , module Database.PostgreSQL.Query.Entity.Internal
+  ) where
 
--- | Entity with it's id
-type Ent a = (EntityId a, a)
+import Database.PostgreSQL.Query.Entity.Class
+import Database.PostgreSQL.Query.Entity.Functions
+import Database.PostgreSQL.Query.Entity.Internal
diff --git a/src/Database/PostgreSQL/Query/Entity/Class.hs b/src/Database/PostgreSQL/Query/Entity/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/Entity/Class.hs
@@ -0,0 +1,25 @@
+module Database.PostgreSQL.Query.Entity.Class
+       ( Entity(..)
+       , Ent
+       ) where
+
+import Data.Proxy
+import Data.Typeable ( Typeable )
+import Database.PostgreSQL.Query.Types
+
+-- | Auxiliary typeclass for data types which can map to rows of some
+-- table. This typeclass is used inside functions like 'pgSelectEntities' to
+-- generate queries.
+class Entity a where
+    -- | Id type for this entity
+    data EntityId a :: *
+    -- | Table name of this entity
+    tableName :: Proxy a -> FN
+    -- | Field names without 'id' and 'created'. The order of field names must match
+    -- with order of fields in 'ToRow' and 'FromRow' instances of this type.
+    fieldNames :: Proxy a -> [FN]
+
+deriving instance Typeable EntityId
+
+-- | Entity with it's id
+type Ent a = (EntityId a, a)
diff --git a/src/Database/PostgreSQL/Query/Entity/Functions.hs b/src/Database/PostgreSQL/Query/Entity/Functions.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/Entity/Functions.hs
@@ -0,0 +1,287 @@
+module Database.PostgreSQL.Query.Entity.Functions
+  ( -- * Work with entities
+    pgInsertEntity
+  , pgInsertManyEntities
+  , pgInsertManyEntitiesId
+  , pgSelectEntities
+  , pgSelectJustEntities
+  , pgSelectEntitiesBy
+  , pgGetEntity
+  , pgGetEntityBy
+  , pgQueryEntities
+  , pgDeleteEntity
+  , pgUpdateEntity
+  , pgSelectCount
+  ) where
+
+import Control.Monad.Logger
+import Data.Int ( Int64 )
+import Data.Maybe ( listToMaybe )
+import Data.Proxy ( Proxy(..) )
+import Data.Typeable ( Typeable )
+import Database.PostgreSQL.Query.Entity.Class
+import Database.PostgreSQL.Query.Entity.Internal
+import Database.PostgreSQL.Query.Functions
+import Database.PostgreSQL.Query.SqlBuilder
+import Database.PostgreSQL.Query.TH
+    ( sqlExp )
+import Database.PostgreSQL.Query.Types
+import Database.PostgreSQL.Simple
+import Database.PostgreSQL.Simple.FromField
+import Database.PostgreSQL.Simple.ToField
+
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative
+#endif
+
+import qualified Data.List as L
+import qualified Data.List.NonEmpty as NL
+
+
+-- | Insert new entity and return it's id
+pgInsertEntity
+  :: forall a m
+   . ( MonadPostgres m, MonadLogger m, Entity a
+     , ToRow a, FromField (EntityId a) )
+  => a
+  -> m (EntityId a)
+pgInsertEntity a = do
+    pgQuery [sqlExp|^{insertEntity a} RETURNING id|] >>= \case
+        ((Only ret):_) -> return ret
+        _       -> fail "Query did not return any response"
+
+
+{- | Select entities as pairs of (id, entity).
+
+@
+handler :: Handler [Ent a]
+handler = do
+    now <- liftIO getCurrentTime
+    let back = addUTCTime (days  (-7)) now
+    pgSelectEntities id
+        [sqlExp|WHERE created BETWEEN \#{now} AND \#{back}
+               ORDER BY created|]
+
+handler2 :: Text -> Handler [Ent Foo]
+handler2 fvalue = do
+    pgSelectEntities ("t"<>)
+        [sqlExp|AS t INNER JOIN table2 AS t2
+                ON t.t2_id = t2.id
+                WHERE t.field = \#{fvalue}
+                ORDER BY t2.field2|]
+   -- Here the query will be: SELECT ... FROM tbl AS t INNER JOIN ...
+@
+
+-}
+
+pgSelectEntities
+  :: forall m a q
+   . ( Functor m, MonadPostgres m, MonadLogger m, Entity a
+     , FromRow a, ToSqlBuilder q, FromField (EntityId a) )
+  => (FN -> FN)
+   -- ^ Entity fields name modifier, e.g. ("tablename"<>). Each field of entity
+   -- will be processed by this modifier before pasting to the query
+  -> q
+   -- ^ part of query just after __SELECT .. FROM table__.
+  -> m [Ent a]
+pgSelectEntities fpref q = do
+    let p = Proxy :: Proxy a
+    pgQueryEntities [sqlExp|^{selectEntity (entityFieldsId fpref) p} ^{q}|]
+
+
+-- | Same as 'pgSelectEntities' but do not select id
+pgSelectJustEntities
+  :: forall m a q
+   . ( Functor m, MonadPostgres m, MonadLogger m, Entity a
+     , FromRow a, ToSqlBuilder q )
+  => (FN -> FN)
+  -> q
+  -> m [a]
+pgSelectJustEntities fpref q = do
+    let p = Proxy :: Proxy a
+    pgQuery [sqlExp|^{selectEntity (entityFields id fpref) p} ^{q}|]
+
+{- | Select entities by condition formed from 'MarkedRow'. Usefull function when
+you know
+
+-}
+
+pgSelectEntitiesBy
+  :: forall a m b
+   . ( Functor m, MonadPostgres m, MonadLogger m, Entity a, ToMarkedRow b
+     , FromRow a, FromField (EntityId a) )
+  => b
+  -> m [Ent a]
+pgSelectEntitiesBy b =
+    let p = Proxy :: Proxy a
+    in pgQueryEntities $ selectEntitiesBy ("id":) p b
+
+
+-- | Select entity by id
+--
+-- @
+-- getUser :: EntityId User ->  Handler User
+-- getUser uid = do
+--     pgGetEntity uid
+--         >>= maybe notFound return
+-- @
+pgGetEntity
+  :: forall m a
+   . ( ToField (EntityId a), Entity a, FromRow a
+     , MonadPostgres m, MonadLogger m, Functor m)
+  => EntityId a
+  -> m (Maybe a)
+pgGetEntity eid = do
+    listToMaybe <$> pgSelectJustEntities id [sqlExp|WHERE id = #{eid} LIMIT 1|]
+
+
+{- | Get entity by some fields constraint
+
+@
+getUser :: UserName -> Handler User
+getUser name = do
+    pgGetEntityBy
+        (MR [("name", mkValue name),
+             ("active", mkValue True)])
+        >>= maybe notFound return
+@
+
+The query here will be like
+
+@
+pgQuery [sqlExp|SELECT id, name, phone ... FROM users WHERE name = #{name} AND active = #{True}|]
+@
+
+-}
+
+pgGetEntityBy
+  :: forall m a b
+   . ( Entity a, MonadPostgres m, MonadLogger m, ToMarkedRow b
+     , FromField (EntityId a), FromRow a, Functor m )
+  => b               -- ^ uniq constrained list of fields and values
+  -> m (Maybe (Ent a))
+pgGetEntityBy b =
+    let p = Proxy :: Proxy a
+    in fmap listToMaybe
+       $ pgQueryEntities
+       [sqlExp|^{selectEntitiesBy ("id":) p b} LIMIT 1|]
+
+
+-- | Same as 'pgInsertEntity' but insert many entities at one
+-- action. Returns list of id's of inserted entities
+pgInsertManyEntitiesId
+  :: forall a m
+   . ( Entity a, MonadPostgres m, MonadLogger m
+     , ToRow a, FromField (EntityId a))
+  => [a]
+  -> m [EntityId a]
+pgInsertManyEntitiesId [] = return []
+pgInsertManyEntitiesId ents' =
+    let ents = NL.fromList ents'
+        q = [sqlExp|^{insertManyEntities ents} RETURNING id|]
+    in map fromOnly <$> pgQuery q
+
+-- | Insert many entities without returning list of id like
+-- 'pgInsertManyEntitiesId' does
+pgInsertManyEntities
+  :: forall a m
+   . (Entity a, MonadPostgres m, MonadLogger m, ToRow a)
+  => [a]
+  -> m Int64
+pgInsertManyEntities [] = return 0
+pgInsertManyEntities ents' =
+    let ents = NL.fromList ents'
+    in pgExecute $ insertManyEntities ents
+
+
+{- | Delete entity.
+
+@
+rmUser :: EntityId User -> Handler ()
+rmUser uid = do
+    pgDeleteEntity uid
+@
+
+Return 'True' if row was actually deleted.
+-}
+
+pgDeleteEntity
+  :: forall a m
+   . (Entity a, MonadPostgres m, MonadLogger m, ToField (EntityId a), Functor m)
+  => EntityId a
+  -> m Bool
+pgDeleteEntity eid =
+    let p = Proxy :: Proxy a
+    in fmap (1 ==)
+       $ pgExecute [sqlExp|DELETE FROM ^{tableName p}
+                           WHERE id = #{eid}|]
+
+
+{- | Update entity using 'ToMarkedRow' instanced value. Requires 'Proxy'
+while 'EntityId' is not a data type.
+
+@
+fixUser :: Text -> EntityId User -> Handler ()
+fixUser username uid = do
+    pgGetEntity uid
+        >>= maybe notFound run
+  where
+    run user =
+        pgUpdateEntity uid
+        $ MR [("active", mkValue True)
+              ("name", mkValue username)]
+@
+
+Returns 'True' if record was actually updated and 'False' if there was
+not row with such id (or was more than 1, in fact)
+-}
+
+pgUpdateEntity
+  :: forall a b m
+   . ( ToMarkedRow b, Entity a, MonadPostgres m, MonadLogger m
+     , ToField (EntityId a), Functor m, Typeable a, Typeable b)
+  => EntityId a
+  -> b
+  -> m Bool
+pgUpdateEntity eid b =
+    let p = Proxy :: Proxy a
+        mr = toMarkedRow b
+    in if L.null $ unMR mr
+       then return False
+       else fmap (1 ==)
+            $ pgExecute [sqlExp|UPDATE ^{tableName p}
+                                SET ^{mrToBuilder ", " mr}
+                                WHERE id = #{eid}|]
+
+{- | Select count of entities with given query
+
+@
+activeUsers :: Handler Integer
+activeUsers = do
+    pgSelectCount (Proxy :: Proxy User)
+        [sqlExp|WHERE active = #{True}|]
+@
+
+-}
+
+
+-- | Executes arbitrary query and parses it as entities and their ids
+pgQueryEntities
+  :: ( ToSqlBuilder q, MonadPostgres m, MonadLogger m, Entity a
+     , FromRow a, FromField (EntityId a))
+  => q
+  -> m [Ent a]
+pgQueryEntities q =
+    map toTuples <$> pgQuery q
+  where
+    toTuples ((Only eid) :. entity) = (eid, entity)
+
+pgSelectCount
+  :: forall m a q
+   . ( Entity a, MonadPostgres m, MonadLogger m, ToSqlBuilder q )
+  => Proxy a
+  -> q
+  -> m Integer
+pgSelectCount p q = do
+    [[c]] <- pgQuery [sqlExp|SELECT count(id) FROM ^{tableName p} ^{q}|]
+    return c
diff --git a/src/Database/PostgreSQL/Query/Entity/Internal.hs b/src/Database/PostgreSQL/Query/Entity/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/Entity/Internal.hs
@@ -0,0 +1,207 @@
+module Database.PostgreSQL.Query.Entity.Internal
+  ( -- * Entity functions
+    entityFields
+  , entityFieldsId
+  , selectEntity
+  , selectEntitiesBy
+  , insertEntity
+  , insertManyEntities
+  , entityToMR
+  ) where
+
+import Data.List.NonEmpty ( NonEmpty )
+import Data.Monoid
+import Data.Proxy ( Proxy(..) )
+import Database.PostgreSQL.Query.Entity.Class
+import Database.PostgreSQL.Query.Internal
+import Database.PostgreSQL.Query.SqlBuilder
+    ( SqlBuilder, ToSqlBuilder(..), mkValue )
+import Database.PostgreSQL.Query.TH
+    ( sqlExp )
+import Database.PostgreSQL.Query.Types
+    ( FN(..), MarkedRow(..),
+      ToMarkedRow(..), mrToBuilder )
+import Database.PostgreSQL.Simple.ToRow
+    ( ToRow(..) )
+
+import qualified Data.List.NonEmpty as NL
+import qualified Data.List as L
+
+
+{- | Build entity fields
+
+>>> data Foo = Foo { fName :: Text, fSize :: Int }
+>>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
+>>> runSqlBuilder con $ entityFields id id (Proxy :: Proxy Foo)
+"\"name\", \"size\""
+
+>>> runSqlBuilder con $ entityFields ("id":) id (Proxy :: Proxy Foo)
+"\"id\", \"name\", \"size\""
+
+>>> runSqlBuilder con $ entityFields (\l -> ("id":l) ++ ["created"]) id (Proxy :: Proxy Foo)
+"\"id\", \"name\", \"size\", \"created\""
+
+>>> runSqlBuilder con $ entityFields id ("f"<>) (Proxy :: Proxy Foo)
+"\"f\".\"name\", \"f\".\"size\""
+
+>>> runSqlBuilder con $ entityFields ("f.id":) ("f"<>) (Proxy :: Proxy Foo)
+"\"f\".\"id\", \"f\".\"name\", \"f\".\"size\""
+
+-}
+
+entityFields :: (Entity a)
+             => ([FN] -> [FN])    -- ^ modify list of fields. Applied second
+             -> (FN -> FN)        -- ^ modify each field name,
+                                -- e.g. prepend each field with
+                                -- prefix, like ("t"<>). Applied first
+             -> Proxy a
+             -> SqlBuilder
+entityFields xpref fpref p =
+    buildFields
+    $ xpref
+    $ map fpref
+    $ fieldNames p
+
+{- | Same as 'entityFields' but prefixes list of names with __id__
+field. This is shorthand function for often usage.
+
+>>> data Foo = Foo { fName :: Text, fSize :: Int }
+>>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
+>>> runSqlBuilder con $ entityFieldsId id (Proxy :: Proxy Foo)
+"\"id\", \"name\", \"size\""
+
+>>> runSqlBuilder con $ entityFieldsId ("f"<>) (Proxy :: Proxy Foo)
+"\"f\".\"id\", \"f\".\"name\", \"f\".\"size\""
+
+-}
+
+entityFieldsId :: (Entity a)
+               => (FN -> FN)
+               -> Proxy a
+               -> SqlBuilder
+entityFieldsId fpref p =
+    let xpref = ((fpref "id"):)
+    in entityFields xpref fpref p
+
+{- | Generate SELECT query string for entity
+
+>>> data Foo = Foo { fName :: Text, fSize :: Int }
+>>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
+>>> runSqlBuilder con $ selectEntity (entityFieldsId id) (Proxy :: Proxy Foo)
+"SELECT \"id\", \"name\", \"size\" FROM \"foo\""
+
+>>> runSqlBuilder con $ selectEntity (entityFieldsId ("f"<>)) (Proxy :: Proxy Foo)
+"SELECT \"f\".\"id\", \"f\".\"name\", \"f\".\"size\" FROM \"foo\""
+
+>>> runSqlBuilder con $ selectEntity (entityFields id id) (Proxy :: Proxy Foo)
+"SELECT \"name\", \"size\" FROM \"foo\""
+
+-}
+
+selectEntity :: (Entity a)
+             => (Proxy a -> SqlBuilder) -- ^ build fields part from proxy
+             -> Proxy a
+             -> SqlBuilder
+selectEntity bld p =
+    [sqlExp|SELECT ^{bld p} FROM ^{tableName p}|]
+
+
+{- | Generates SELECT FROM WHERE query with most used conditions
+
+>>> data Foo = Foo { fName :: Text, fSize :: Int }
+>>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
+>>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR []
+"SELECT \"name\", \"size\" FROM \"foo\""
+
+>>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR [("name", mkValue "fooname")]
+"SELECT \"name\", \"size\" FROM \"foo\" WHERE  \"name\" = 'fooname' "
+
+>>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR [("name", mkValue "fooname"), ("size", mkValue 10)]
+"SELECT \"name\", \"size\" FROM \"foo\" WHERE  \"name\" = 'fooname' AND \"size\" = 10 "
+
+-}
+
+selectEntitiesBy :: (Entity a, ToMarkedRow b)
+                 => ([FN] -> [FN])
+                 -> Proxy a
+                 -> b
+                 -> SqlBuilder
+selectEntitiesBy xpref p b =
+    let mr = toMarkedRow b
+        cond = if L.null $ unMR mr
+               then mempty
+               else [sqlExp| WHERE ^{mrToBuilder "AND" mr}|]
+        q = selectEntity (entityFields xpref id) p
+    in q <> cond
+
+
+
+{- | Convert entity instance to marked row to perform inserts updates
+and same stuff
+
+>>> data Foo = Foo { fName :: Text, fSize :: Int }
+>>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
+>>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
+>>> runSqlBuilder con $ mrToBuilder ", " $ entityToMR $ Foo "Enterprise" 610
+" \"name\" = 'Enterprise' ,  \"size\" = 610 "
+
+-}
+
+entityToMR :: forall a. (Entity a, ToRow a) => a -> MarkedRow
+entityToMR a =
+    let p = Proxy :: Proxy a
+        names = fieldNames p
+        values = map mkValue $ toRow a
+    in MR $ zip names values
+
+
+{- | Generates __INSERT INTO__ query for any instance of 'Entity' and 'ToRow'
+
+>>> data Foo = Foo { fName :: Text, fSize :: Int }
+>>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
+>>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
+>>> runSqlBuilder con $ insertEntity $ Foo "Enterprise" 910
+"INSERT INTO \"foo\" (\"name\", \"size\") VALUES ('Enterprise', 910)"
+
+-}
+
+insertEntity :: forall a. (Entity a, ToRow a) => a -> SqlBuilder
+insertEntity a =
+    let p = Proxy :: Proxy a
+        mr = entityToMR a
+    in insertInto (tableName p) mr
+
+{- | Same as 'insertEntity' but generates query to insert many queries at same time
+
+>>> data Foo = Foo { fName :: Text, fSize :: Int }
+>>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
+>>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
+>>> runSqlBuilder con $ insertManyEntities $ NL.fromList [Foo "meter" 1, Foo "table" 2, Foo "earth" 151930000000]
+"INSERT INTO \"foo\" (\"name\",\"size\") VALUES ('meter',1),('table',2),('earth',151930000000)"
+
+-}
+
+insertManyEntities :: forall a. (Entity a, ToRow a)
+                   => NonEmpty a
+                   -> SqlBuilder
+insertManyEntities rows =
+    let p = Proxy :: Proxy a
+        names = mconcat
+                $ L.intersperse ","
+                $ map toSqlBuilder
+                $ fieldNames p
+        values = mconcat
+                 $ L.intersperse ","
+                 $ map rValue
+                 $ NL.toList rows
+
+    in [sqlExp|INSERT INTO ^{tableName p}
+               (^{names}) VALUES ^{values}|]
+  where
+    rValue :: a -> SqlBuilder
+    rValue row =
+        let values = mconcat
+                     $ L.intersperse ","
+                     $ map mkValue
+                     $ toRow row
+        in [sqlExp|(^{values})|]
diff --git a/src/Database/PostgreSQL/Query/Functions.hs b/src/Database/PostgreSQL/Query/Functions.hs
--- a/src/Database/PostgreSQL/Query/Functions.hs
+++ b/src/Database/PostgreSQL/Query/Functions.hs
@@ -1,71 +1,86 @@
 module Database.PostgreSQL.Query.Functions
        ( -- * Raw query execution
          pgQuery
+       , pgQueryWithMasker
        , pgExecute
-       , pgQueryEntities
+       , pgExecuteWithMasker
          -- * Transactions
        , pgWithTransaction
        , pgWithSavepoint
        , pgWithTransactionMode
        , pgWithTransactionModeRetry
        , pgWithTransactionSerializable
-         -- * Work with entities
-       , pgInsertEntity
-       , pgInsertManyEntities
-       , pgInsertManyEntitiesId
-       , pgSelectEntities
-       , pgSelectJustEntities
-       , pgSelectEntitiesBy
-       , pgGetEntity
-       , pgGetEntityBy
-       , pgDeleteEntity
-       , pgUpdateEntity
-       , pgSelectCount
-         -- * Auxiliary functions
+         -- * Auxiliary
        , pgRepsertRow
        ) where
 
-import Prelude
-
-import Control.Applicative
 import Control.Monad
 import Control.Monad.Base
 import Control.Monad.Logger
 import Control.Monad.Trans.Control
 import Data.Int ( Int64 )
-import Data.Maybe ( listToMaybe )
 import Data.Monoid
-import Data.Proxy ( Proxy(..) )
-import Data.Typeable ( Typeable )
-import Database.PostgreSQL.Query.Entity
-    ( Entity(..), Ent )
 import Database.PostgreSQL.Query.Internal
-    ( insertEntity, selectEntity, entityFieldsId,
-      entityFields, selectEntitiesBy, insertManyEntities,
-      updateTable, insertInto )
 import Database.PostgreSQL.Query.SqlBuilder
-    ( ToSqlBuilder(..), runSqlBuilder )
 import Database.PostgreSQL.Query.TH
-    ( sqlExp )
 import Database.PostgreSQL.Query.Types
-    ( FN, HasPostgres(..), TransactionSafe,
-      ToMarkedRow(..), MarkedRow(..), mrToBuilder )
 import Database.PostgreSQL.Simple
-    ( ToRow, FromRow, execute_, query_, )
-import Database.PostgreSQL.Simple.FromField
-    ( FromField )
-import Database.PostgreSQL.Simple.Internal
-    ( SqlError )
-import Database.PostgreSQL.Simple.ToField
-    ( ToField )
 import Database.PostgreSQL.Simple.Transaction
-import Database.PostgreSQL.Simple.Types
-    ( Query(..), Only(..), (:.)(..) )
 
-import qualified Data.List as L
-import qualified Data.List.NonEmpty as NL
 import qualified Data.Text.Encoding as T
 
+{- | Execute query generated by 'SqlBuilder'. Typical use case:
+
+@
+let userName = "Vovka Erohin" :: Text
+pgQuery [sqlExp| SELECT id, name FROM users WHERE name = #{userName}|]
+@
+
+Or
+
+@
+let userName = "Vovka Erohin" :: Text
+pgQuery $ Qp "SELECT id, name FROM users WHERE name = ?" [userName]
+@
+
+Which is almost the same. In both cases proper value escaping is performed
+so you stay protected from sql injections.
+
+-}
+
+pgQuery
+  :: (HasPostgres m, MonadLogger m, ToSqlBuilder q, FromRow r)
+  => q
+  -> m [r]
+pgQuery = pgQueryWithMasker defaultLogMasker
+
+-- | Execute arbitrary query and return count of affected rows
+pgExecute
+  :: (HasPostgres m, MonadLogger m, ToSqlBuilder q)
+  => q
+  -> m Int64
+pgExecute = pgExecuteWithMasker defaultLogMasker
+
+pgQueryWithMasker
+  :: (HasPostgres m, MonadLogger m, ToSqlBuilder q, FromRow r)
+  => LogMasker
+  -> q
+  -> m [r]
+pgQueryWithMasker masker q = withPGConnection $ \c -> do
+    (queryBs, logBs) <- liftBase $ runSqlBuilder c masker $ toSqlBuilder q
+    logDebugN $ T.decodeUtf8 logBs
+    liftBase $ query_ c queryBs
+
+pgExecuteWithMasker
+  :: (HasPostgres m, MonadLogger m, ToSqlBuilder q)
+  => LogMasker
+  -> q
+  -> m Int64
+pgExecuteWithMasker masker q = withPGConnection $ \c -> do
+    (queryBs, logBs) <- liftBase $ runSqlBuilder c masker $ toSqlBuilder q
+    logDebugN $ T.decodeUtf8 logBs
+    liftBase $ execute_ c queryBs
+
 -- | Execute all queries inside one transaction. Rollback transaction on exceptions
 pgWithTransaction :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m)
                   => m a
@@ -122,265 +137,8 @@
     control $ \runInIO -> do
         withTransactionSerializable con $ runInIO ma
 
-{- | Execute query generated by 'SqlBuilder'. Typical use case:
 
-@
-let userName = "Vovka Erohin" :: Text
-pgQuery [sqlExp| SELECT id, name FROM users WHERE name = #{userName}|]
-@
 
-Or
-
-@
-let userName = "Vovka Erohin" :: Text
-pgQuery $ Qp "SELECT id, name FROM users WHERE name = ?" [userName]
-@
-
-Which is almost the same. In both cases proper value escaping is performed
-so you stay protected from sql injections.
-
--}
-
-pgQuery :: (HasPostgres m, MonadLogger m, ToSqlBuilder q, FromRow r)
-        => q -> m [r]
-pgQuery q = withPGConnection $ \c -> do
-    b <- liftBase $ runSqlBuilder c $ toSqlBuilder q
-    logDebugN $ T.decodeUtf8 $ fromQuery b
-    liftBase $ query_ c b
-
--- | Execute arbitrary query and return count of affected rows
-pgExecute :: (HasPostgres m, MonadLogger m, ToSqlBuilder q)
-          => q -> m Int64
-pgExecute q = withPGConnection $ \c -> do
-    b <- liftBase $ runSqlBuilder c $ toSqlBuilder q
-    logDebugN $ T.decodeUtf8 $ fromQuery b
-    liftBase $ execute_ c b
-
--- | Executes arbitrary query and parses it as entities and their ids
-pgQueryEntities :: ( ToSqlBuilder q, HasPostgres m, MonadLogger m, Entity a
-                  , FromRow a, FromField (EntityId a))
-                => q -> m [Ent a]
-pgQueryEntities q =
-    map toTuples <$> pgQuery q
-  where
-    toTuples ((Only eid) :. entity) = (eid, entity)
-
-
--- | Insert new entity and return it's id
-pgInsertEntity :: forall a m. (HasPostgres m, MonadLogger m, Entity a,
-                         ToRow a, FromField (EntityId a))
-               => a
-               -> m (EntityId a)
-pgInsertEntity a = do
-    pgQuery [sqlExp|^{insertEntity a} RETURNING id|] >>= \case
-        ((Only ret):_) -> return ret
-        _       -> fail "Query did not return any response"
-
-
-{- | Select entities as pairs of (id, entity).
-
-@
-handler :: Handler [Ent a]
-handler = do
-    now <- liftIO getCurrentTime
-    let back = addUTCTime (days  (-7)) now
-    pgSelectEntities id
-        [sqlExp|WHERE created BETWEEN \#{now} AND \#{back}
-               ORDER BY created|]
-
-handler2 :: Text -> Handler [Ent Foo]
-handler2 fvalue = do
-    pgSelectEntities ("t"<>)
-        [sqlExp|AS t INNER JOIN table2 AS t2
-                ON t.t2_id = t2.id
-                WHERE t.field = \#{fvalue}
-                ORDER BY t2.field2|]
-   -- Here the query will be: SELECT ... FROM tbl AS t INNER JOIN ...
-@
-
--}
-
-pgSelectEntities :: forall m a q. ( Functor m, HasPostgres m, MonadLogger m, Entity a
-                            , FromRow a, ToSqlBuilder q, FromField (EntityId a) )
-                 => (FN -> FN)   -- ^ Entity fields name modifier,
-                                -- e.g. ("tablename"<>). Each field of
-                                -- entity will be processed by this
-                                -- modifier before pasting to the query
-                 -> q           -- ^ part of query just after __SELECT .. FROM table__.
-                 -> m [Ent a]
-pgSelectEntities fpref q = do
-    let p = Proxy :: Proxy a
-    pgQueryEntities [sqlExp|^{selectEntity (entityFieldsId fpref) p} ^{q}|]
-
-
--- | Same as 'pgSelectEntities' but do not select id
-pgSelectJustEntities :: forall m a q. ( Functor m, HasPostgres m, MonadLogger m, Entity a
-                                 , FromRow a, ToSqlBuilder q )
-                     => (FN -> FN)
-                     -> q
-                     -> m [a]
-pgSelectJustEntities fpref q = do
-    let p = Proxy :: Proxy a
-    pgQuery [sqlExp|^{selectEntity (entityFields id fpref) p} ^{q}|]
-
-{- | Select entities by condition formed from 'MarkedRow'. Usefull function when you know
-
--}
-
-pgSelectEntitiesBy :: forall a m b.( Functor m, HasPostgres m, MonadLogger m, Entity a, ToMarkedRow b
-                     , FromRow a, FromField (EntityId a) )
-                   => b
-                   -> m [Ent a]
-pgSelectEntitiesBy b =
-    let p = Proxy :: Proxy a
-    in pgQueryEntities $ selectEntitiesBy ("id":) p b
-
-
--- | Select entity by id
---
--- @
--- getUser :: EntityId User ->  Handler User
--- getUser uid = do
---     pgGetEntity uid
---         >>= maybe notFound return
--- @
-pgGetEntity :: forall m a. (ToField (EntityId a), Entity a,
-                      HasPostgres m, MonadLogger m, FromRow a, Functor m)
-            => EntityId a
-            -> m (Maybe a)
-pgGetEntity eid = do
-    listToMaybe <$> pgSelectJustEntities id [sqlExp|WHERE id = #{eid} LIMIT 1|]
-
-
-{- | Get entity by some fields constraint
-
-@
-getUser :: UserName -> Handler User
-getUser name = do
-    pgGetEntityBy
-        (MR [("name", mkValue name),
-             ("active", mkValue True)])
-        >>= maybe notFound return
-@
-
-The query here will be like
-
-@
-pgQuery [sqlExp|SELECT id, name, phone ... FROM users WHERE name = #{name} AND active = #{True}|]
-@
-
--}
-
-pgGetEntityBy :: forall m a b. ( Entity a, HasPostgres m, MonadLogger m, ToMarkedRow b
-                         , FromField (EntityId a), FromRow a, Functor m )
-              => b               -- ^ uniq constrained list of fields and values
-              -> m (Maybe (Ent a))
-pgGetEntityBy b =
-    let p = Proxy :: Proxy a
-    in fmap listToMaybe
-       $ pgQueryEntities
-       [sqlExp|^{selectEntitiesBy ("id":) p b} LIMIT 1|]
-
-
--- | Same as 'pgInsertEntity' but insert many entities at one
--- action. Returns list of id's of inserted entities
-pgInsertManyEntitiesId :: forall a m. ( Entity a, HasPostgres m, MonadLogger m
-                                , ToRow a, FromField (EntityId a))
-                       => [a]
-                       -> m [EntityId a]
-pgInsertManyEntitiesId [] = return []
-pgInsertManyEntitiesId ents' =
-    let ents = NL.fromList ents'
-        q = [sqlExp|^{insertManyEntities ents} RETURNING id|]
-    in map fromOnly <$> pgQuery q
-
--- | Insert many entities without returning list of id like
--- 'pgInsertManyEntitiesId' does
-pgInsertManyEntities :: forall a m. (Entity a, HasPostgres m, MonadLogger m, ToRow a)
-                     => [a]
-                     -> m Int64
-pgInsertManyEntities [] = return 0
-pgInsertManyEntities ents' =
-    let ents = NL.fromList ents'
-    in pgExecute $ insertManyEntities ents
-
-
-{- | Delete entity.
-
-@
-rmUser :: EntityId User -> Handler ()
-rmUser uid = do
-    pgDeleteEntity uid
-@
-
-Return 'True' if row was actually deleted.
--}
-
-pgDeleteEntity :: forall a m. (Entity a, HasPostgres m, MonadLogger m, ToField (EntityId a), Functor m)
-               => EntityId a
-               -> m Bool
-pgDeleteEntity eid =
-    let p = Proxy :: Proxy a
-    in fmap (1 ==)
-       $ pgExecute [sqlExp|DELETE FROM ^{tableName p}
-                           WHERE id = #{eid}|]
-
-
-{- | Update entity using 'ToMarkedRow' instanced value. Requires 'Proxy'
-while 'EntityId' is not a data type.
-
-@
-fixUser :: Text -> EntityId User -> Handler ()
-fixUser username uid = do
-    pgGetEntity uid
-        >>= maybe notFound run
-  where
-    run user =
-        pgUpdateEntity uid
-        $ MR [("active", mkValue True)
-              ("name", mkValue username)]
-@
-
-Returns 'True' if record was actually updated and 'False' if there was
-not row with such id (or was more than 1, in fact)
--}
-
-pgUpdateEntity :: forall a b m. (ToMarkedRow b, Entity a, HasPostgres m, MonadLogger m,
-                           ToField (EntityId a), Functor m, Typeable a, Typeable b)
-               => EntityId a
-               -> b
-               -> m Bool
-pgUpdateEntity eid b =
-    let p = Proxy :: Proxy a
-        mr = toMarkedRow b
-    in if L.null $ unMR mr
-       then return False
-       else fmap (1 ==)
-            $ pgExecute [sqlExp|UPDATE ^{tableName p}
-                                SET ^{mrToBuilder ", " mr}
-                                WHERE id = #{eid}|]
-
-{- | Select count of entities with given query
-
-@
-activeUsers :: Handler Integer
-activeUsers = do
-    pgSelectCount (Proxy :: Proxy User)
-        [sqlExp|WHERE active = #{True}|]
-@
-
--}
-
-pgSelectCount :: forall m a q. ( Entity a, HasPostgres m, MonadLogger m, ToSqlBuilder q )
-              => Proxy a
-              -> q
-              -> m Integer
-pgSelectCount p q = do
-    [[c]] <- pgQuery [sqlExp|SELECT count(id) FROM ^{tableName p} ^{q}|]
-    return c
-
-
-
 {- | Perform repsert of the same row, first trying "update where" then
 "insert" with concatenated fields. Which means that if you run
 
@@ -404,11 +162,13 @@
 
 -}
 
-pgRepsertRow :: (HasPostgres m, MonadLogger m, ToMarkedRow wrow, ToMarkedRow urow)
-             => FN              -- ^ Table name
-             -> wrow            -- ^ where condition
-             -> urow            -- ^ update row
-             -> m ()
+pgRepsertRow
+  :: ( MonadPostgres m, MonadLogger m
+     , ToMarkedRow wrow, ToMarkedRow urow)
+  => FN                         -- ^ Table name
+  -> wrow                       -- ^ where condition
+  -> urow                       -- ^ update row
+  -> m ()
 pgRepsertRow tname wrow urow = do
     let wmr = toMarkedRow wrow
     aff <- pgExecute $ updateTable tname urow
diff --git a/src/Database/PostgreSQL/Query/Internal.hs b/src/Database/PostgreSQL/Query/Internal.hs
--- a/src/Database/PostgreSQL/Query/Internal.hs
+++ b/src/Database/PostgreSQL/Query/Internal.hs
@@ -1,37 +1,19 @@
 module Database.PostgreSQL.Query.Internal
-       ( -- * Entity functions
-         entityFields
-       , entityFieldsId
-       , selectEntity
-       , selectEntitiesBy
-       , insertEntity
-       , insertManyEntities
-       , entityToMR
-         -- * Low level generators
-       , buildFields
+       ( -- * Low level generators
+         buildFields
        , updateTable
        , insertInto
        ) where
 
-
-import Prelude
-
-import Data.List.NonEmpty ( NonEmpty )
-import Data.Monoid
-import Data.Proxy ( Proxy(..) )
-import Database.PostgreSQL.Query.Entity
-    ( Entity(..) )
 import Database.PostgreSQL.Query.SqlBuilder
-    ( SqlBuilder, ToSqlBuilder(..), mkValue )
 import Database.PostgreSQL.Query.TH
-    ( sqlExp )
 import Database.PostgreSQL.Query.Types
-    ( FN(..), MarkedRow(..),
-      ToMarkedRow(..), mrToBuilder )
-import Database.PostgreSQL.Simple.ToRow
-    ( ToRow(..) )
 
-import qualified Data.List.NonEmpty as NL
+#if !MIN_VERSION_base(4,8,0)
+import Data.Monoid
+#endif
+
+
 import qualified Data.List as L
 
 {- $setup
@@ -96,182 +78,3 @@
                  $ unMR mr
     in [sqlExp|INSERT INTO ^{tname}
                (^{names}) VALUES (^{values})|]
-
-
-{- | Build entity fields
-
->>> data Foo = Foo { fName :: Text, fSize :: Int }
->>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
->>> runSqlBuilder con $ entityFields id id (Proxy :: Proxy Foo)
-"\"name\", \"size\""
-
->>> runSqlBuilder con $ entityFields ("id":) id (Proxy :: Proxy Foo)
-"\"id\", \"name\", \"size\""
-
->>> runSqlBuilder con $ entityFields (\l -> ("id":l) ++ ["created"]) id (Proxy :: Proxy Foo)
-"\"id\", \"name\", \"size\", \"created\""
-
->>> runSqlBuilder con $ entityFields id ("f"<>) (Proxy :: Proxy Foo)
-"\"f\".\"name\", \"f\".\"size\""
-
->>> runSqlBuilder con $ entityFields ("f.id":) ("f"<>) (Proxy :: Proxy Foo)
-"\"f\".\"id\", \"f\".\"name\", \"f\".\"size\""
-
--}
-
-entityFields :: (Entity a)
-             => ([FN] -> [FN])    -- ^ modify list of fields. Applied second
-             -> (FN -> FN)        -- ^ modify each field name,
-                                -- e.g. prepend each field with
-                                -- prefix, like ("t"<>). Applied first
-             -> Proxy a
-             -> SqlBuilder
-entityFields xpref fpref p =
-    buildFields
-    $ xpref
-    $ map fpref
-    $ fieldNames p
-
-{- | Same as 'entityFields' but prefixes list of names with __id__
-field. This is shorthand function for often usage.
-
->>> data Foo = Foo { fName :: Text, fSize :: Int }
->>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
->>> runSqlBuilder con $ entityFieldsId id (Proxy :: Proxy Foo)
-"\"id\", \"name\", \"size\""
-
->>> runSqlBuilder con $ entityFieldsId ("f"<>) (Proxy :: Proxy Foo)
-"\"f\".\"id\", \"f\".\"name\", \"f\".\"size\""
-
--}
-
-entityFieldsId :: (Entity a)
-               => (FN -> FN)
-               -> Proxy a
-               -> SqlBuilder
-entityFieldsId fpref p =
-    let xpref = ((fpref "id"):)
-    in entityFields xpref fpref p
-
-{- | Generate SELECT query string for entity
-
->>> data Foo = Foo { fName :: Text, fSize :: Int }
->>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
->>> runSqlBuilder con $ selectEntity (entityFieldsId id) (Proxy :: Proxy Foo)
-"SELECT \"id\", \"name\", \"size\" FROM \"foo\""
-
->>> runSqlBuilder con $ selectEntity (entityFieldsId ("f"<>)) (Proxy :: Proxy Foo)
-"SELECT \"f\".\"id\", \"f\".\"name\", \"f\".\"size\" FROM \"foo\""
-
->>> runSqlBuilder con $ selectEntity (entityFields id id) (Proxy :: Proxy Foo)
-"SELECT \"name\", \"size\" FROM \"foo\""
-
--}
-
-selectEntity :: (Entity a)
-             => (Proxy a -> SqlBuilder) -- ^ build fields part from proxy
-             -> Proxy a
-             -> SqlBuilder
-selectEntity bld p =
-    [sqlExp|SELECT ^{bld p} FROM ^{tableName p}|]
-
-
-{- | Generates SELECT FROM WHERE query with most used conditions
-
->>> data Foo = Foo { fName :: Text, fSize :: Int }
->>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
->>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR []
-"SELECT \"name\", \"size\" FROM \"foo\""
-
->>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR [("name", mkValue "fooname")]
-"SELECT \"name\", \"size\" FROM \"foo\" WHERE  \"name\" = 'fooname' "
-
->>> runSqlBuilder con $ selectEntitiesBy id (Proxy :: Proxy Foo) $ MR [("name", mkValue "fooname"), ("size", mkValue 10)]
-"SELECT \"name\", \"size\" FROM \"foo\" WHERE  \"name\" = 'fooname' AND \"size\" = 10 "
-
--}
-
-selectEntitiesBy :: (Entity a, ToMarkedRow b)
-                 => ([FN] -> [FN])
-                 -> Proxy a
-                 -> b
-                 -> SqlBuilder
-selectEntitiesBy xpref p b =
-    let mr = toMarkedRow b
-        cond = if L.null $ unMR mr
-               then mempty
-               else [sqlExp| WHERE ^{mrToBuilder "AND" mr}|]
-        q = selectEntity (entityFields xpref id) p
-    in q <> cond
-
-
-
-{- | Convert entity instance to marked row to perform inserts updates
-and same stuff
-
->>> data Foo = Foo { fName :: Text, fSize :: Int }
->>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
->>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
->>> runSqlBuilder con $ mrToBuilder ", " $ entityToMR $ Foo "Enterprise" 610
-" \"name\" = 'Enterprise' ,  \"size\" = 610 "
-
--}
-
-entityToMR :: forall a. (Entity a, ToRow a) => a -> MarkedRow
-entityToMR a =
-    let p = Proxy :: Proxy a
-        names = fieldNames p
-        values = map mkValue $ toRow a
-    in MR $ zip names values
-
-
-{- | Generates __INSERT INTO__ query for any instance of 'Entity' and 'ToRow'
-
->>> data Foo = Foo { fName :: Text, fSize :: Int }
->>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
->>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
->>> runSqlBuilder con $ insertEntity $ Foo "Enterprise" 910
-"INSERT INTO \"foo\" (\"name\", \"size\") VALUES ('Enterprise', 910)"
-
--}
-
-insertEntity :: forall a. (Entity a, ToRow a) => a -> SqlBuilder
-insertEntity a =
-    let p = Proxy :: Proxy a
-        mr = entityToMR a
-    in insertInto (tableName p) mr
-
-{- | Same as 'insertEntity' but generates query to insert many queries at same time
-
->>> data Foo = Foo { fName :: Text, fSize :: Int }
->>> instance Entity Foo where {newtype EntityId Foo = FooId Int ; fieldNames _ = ["name", "size"] ; tableName _ = "foo"}
->>> instance ToRow Foo where { toRow Foo{..} = [toField fName, toField fSize] }
->>> runSqlBuilder con $ insertManyEntities $ NL.fromList [Foo "meter" 1, Foo "table" 2, Foo "earth" 151930000000]
-"INSERT INTO \"foo\" (\"name\",\"size\") VALUES ('meter',1),('table',2),('earth',151930000000)"
-
--}
-
-insertManyEntities :: forall a. (Entity a, ToRow a)
-                   => NonEmpty a
-                   -> SqlBuilder
-insertManyEntities rows =
-    let p = Proxy :: Proxy a
-        names = mconcat
-                $ L.intersperse ","
-                $ map toSqlBuilder
-                $ fieldNames p
-        values = mconcat
-                 $ L.intersperse ","
-                 $ map rValue
-                 $ NL.toList rows
-
-    in [sqlExp|INSERT INTO ^{tableName p}
-               (^{names}) VALUES ^{values}|]
-  where
-    rValue :: a -> SqlBuilder
-    rValue row =
-        let values = mconcat
-                     $ L.intersperse ","
-                     $ map mkValue
-                     $ toRow row
-        in [sqlExp|(^{values})|]
diff --git a/src/Database/PostgreSQL/Query/SqlBuilder.hs b/src/Database/PostgreSQL/Query/SqlBuilder.hs
--- a/src/Database/PostgreSQL/Query/SqlBuilder.hs
+++ b/src/Database/PostgreSQL/Query/SqlBuilder.hs
@@ -1,132 +1,9 @@
 module Database.PostgreSQL.Query.SqlBuilder
-       ( -- * Types
-         SqlBuilder(..)
-       , ToSqlBuilder(..)
-       , Qp(..)
-         -- * SqlBuilder helpers
-       , emptyB
-       , runSqlBuilder
-       , mkIdent
-       , mkValue
-       , sqlBuilderPure
-       , sqlBuilderFromField
+       ( module Database.PostgreSQL.Query.SqlBuilder.Builder
+       , module Database.PostgreSQL.Query.SqlBuilder.Class
+       , module Database.PostgreSQL.Query.SqlBuilder.Types
        ) where
 
-import Prelude
-
-import Blaze.ByteString.Builder
-    ( Builder, toByteString )
-import Control.Applicative
-import Data.ByteString ( ByteString )
-import Data.Monoid
-import Data.String
-import Data.Text ( Text )
-import Data.Typeable ( Typeable )
-import Database.PostgreSQL.Simple
-import Database.PostgreSQL.Simple.Internal
-    ( buildAction )
-import Database.PostgreSQL.Simple.ToField
-import Database.PostgreSQL.Simple.Types
-    ( Query(..), Identifier(..) )
-import GHC.Generics ( Generic )
-
-import qualified Blaze.ByteString.Builder.ByteString as BB
-import qualified Blaze.ByteString.Builder.Char.Utf8 as BB
-import qualified Data.ByteString.Lazy as BL
-import qualified Data.Text as T
-import qualified Data.Text.Lazy as TL
-
-{- $setup
->>> c <- connect defaultConnectInfo
--}
-
--- | Things which always can be transformed to 'SqlBuilder'
-class ToSqlBuilder a where
-    toSqlBuilder :: a -> SqlBuilder
-
--- | Special constructor to perform old-style query interpolation
-data Qp = forall row. (ToRow row) => Qp Query row
-
-instance ToSqlBuilder Qp where
-    toSqlBuilder (Qp q row) = SqlBuilder $ \c ->
-        BB.fromByteString <$> formatQuery c q row
-
-
--- | Builder wich can be effectively concatenated. Requires 'Connection'
--- inside for string quoting implemented in __libpq__
-newtype SqlBuilder =
-    SqlBuilder
-    { sqlBuild :: Connection -> IO Builder }
-    deriving (Typeable, Generic)
-
--- | Typed synonym of 'mempty'
-emptyB :: SqlBuilder
-emptyB = mempty
-
-{- | Performs parameters interpolation and return ready to execute query
-
->>> let val = 10
->>> let name = "field"
->>> runSqlBuilder c $ "SELECT * FROM tbl WHERE " <> mkIdent name <> " = " <> mkValue val
-"SELECT * FROM tbl WHERE \"field\" = 10"
-
--}
-
-runSqlBuilder :: Connection -> SqlBuilder -> IO Query
-runSqlBuilder con (SqlBuilder bld) =
-    (Query . toByteString) <$> bld con
-
-instance IsString SqlBuilder where
-    fromString s =
-        let b = fromString s :: ByteString
-        in toSqlBuilder b
-
-instance ToSqlBuilder SqlBuilder where
-    toSqlBuilder = id
-instance ToSqlBuilder Builder where
-    toSqlBuilder = sqlBuilderPure
-instance ToSqlBuilder ByteString where
-    toSqlBuilder = sqlBuilderPure . BB.fromByteString
-instance ToSqlBuilder BL.ByteString where
-    toSqlBuilder = sqlBuilderPure . BB.fromLazyByteString
-instance ToSqlBuilder String where
-    toSqlBuilder = sqlBuilderPure . BB.fromString
-instance ToSqlBuilder T.Text where
-    toSqlBuilder = sqlBuilderPure . BB.fromText
-instance ToSqlBuilder TL.Text where
-    toSqlBuilder = sqlBuilderPure . BB.fromLazyText
-
-{- | Shorthand function to convert identifier name to builder
-
->>> runSqlBuilder c $ mkIdent "simple\"ident"
-"\"simple\"\"ident\""
-
-Note correct string quoting made by __libpq__
--}
-
-mkIdent :: Text -> SqlBuilder
-mkIdent t = sqlBuilderFromField "mkident a" $ Identifier t
-
-{- | Shorthand function to convert single value to builder
-
->>> runSqlBuilder c $ mkValue "some ' value"
-"'some '' value'"
-
-Note correct string quoting
--}
-
-mkValue :: (ToField a) => a -> SqlBuilder
-mkValue a = sqlBuilderFromField "mkValue a" a
-
--- | Lift pure bytestring builder to 'SqlBuilder'
-sqlBuilderPure :: Builder -> SqlBuilder
-sqlBuilderPure b = SqlBuilder $ const $ pure b
-
-sqlBuilderFromField :: (ToField a) => Query -> a -> SqlBuilder
-sqlBuilderFromField q a =
-    SqlBuilder $ \c -> buildAction c q [] $ toField a --  FIXME: pass something as parameters string
-
-instance Monoid SqlBuilder where
-    mempty = sqlBuilderPure mempty
-    mappend (SqlBuilder a) (SqlBuilder b) =
-        SqlBuilder $ \c -> mappend <$> (a c) <*> (b c)
+import Database.PostgreSQL.Query.SqlBuilder.Builder
+import Database.PostgreSQL.Query.SqlBuilder.Class
+import Database.PostgreSQL.Query.SqlBuilder.Types
diff --git a/src/Database/PostgreSQL/Query/SqlBuilder/Builder.hs b/src/Database/PostgreSQL/Query/SqlBuilder/Builder.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/SqlBuilder/Builder.hs
@@ -0,0 +1,90 @@
+module Database.PostgreSQL.Query.SqlBuilder.Builder
+       ( SqlBuilder(..)
+         -- * Running
+       , runSqlBuilder
+         -- * Building
+       , emptyB
+       , mkValue
+       , mkMaskedValue
+       , sqlBuilderFromField
+       -- ** Unsafe
+       , sqlBuilderPure
+       , sqlBuilderFromByteString
+       ) where
+
+import Blaze.ByteString.Builder (Builder)
+import Data.ByteString (ByteString)
+import Data.Semigroup
+import Data.String
+import Data.Typeable
+import Database.PostgreSQL.Query.SqlBuilder.Types
+import Database.PostgreSQL.Simple
+import Database.PostgreSQL.Simple.Internal
+import Database.PostgreSQL.Simple.ToField
+import Database.PostgreSQL.Simple.Types
+import GHC.Generics (Generic)
+
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative
+#endif
+
+import qualified Blaze.ByteString.Builder as BB
+import qualified Blaze.ByteString.Builder.Char.Utf8 as BB
+
+
+-- | Builder wich can be effectively concatenated. Requires 'Connection'
+-- inside for string quoting implemented in __libpq__. Builds two strings: query
+-- string and log string which may differ.
+newtype SqlBuilder = SqlBuilder
+  { sqlBuild :: Connection -> LogMasker -> IO SqlBuilderResult
+  } deriving (Typeable, Generic)
+
+instance Semigroup SqlBuilder where
+  (SqlBuilder a) <> (SqlBuilder b) =
+    SqlBuilder $ \c masker -> (<>) <$> (a c masker) <*> (b c masker)
+
+instance Monoid SqlBuilder where
+  mempty = sqlBuilderPure mempty
+  mappend = (<>)
+
+instance IsString SqlBuilder where
+  fromString s = SqlBuilder $ \_ _ -> return $ builderResultPure $ BB.fromString s
+
+-- | Returns query string with log bytestring
+runSqlBuilder :: Connection -> LogMasker -> SqlBuilder -> IO (Query, ByteString)
+runSqlBuilder con masker (SqlBuilder bld) = toTuple <$> bld con masker
+  where
+    toTuple res =
+      ( Query $ BB.toByteString $ sbQueryString res
+      , BB.toByteString $ sbLogString res )
+
+-- | Typed synonym of 'mempty'
+emptyB :: SqlBuilder
+emptyB = mempty
+
+-- | Shorthand function to convert single field value to builder
+mkValue :: (ToField a) => a -> SqlBuilder
+mkValue = sqlBuilderFromField FieldDefault
+
+-- | Shorthand function to convert single masked field value (which should not
+-- be shown in log)
+mkMaskedValue :: (ToField a) => a -> SqlBuilder
+mkMaskedValue = sqlBuilderFromField FieldMasked
+
+sqlBuilderFromField :: (ToField a) => FieldOption -> a -> SqlBuilder
+sqlBuilderFromField fo field = SqlBuilder $ \con masker -> do
+  qbs <- buildAction con "" [] $ toField field
+  let sbQueryString = qbs
+      sbLogString   = masker fo qbs
+  return SqlBuilderResult{..}
+
+-- | Lift pure bytestring builder to 'SqlBuilder'. This is unsafe to use
+-- directly in your code.
+sqlBuilderPure :: Builder -> SqlBuilder
+sqlBuilderPure b = SqlBuilder $ \_ _ -> pure $ builderResultPure b
+
+-- | Unsafe function to make SqlBuilder from arbitrary ByteString. Does not
+-- perform any checks. Dont use it directly in your code unless you know what
+-- you are doing.
+sqlBuilderFromByteString :: ByteString -> SqlBuilder
+sqlBuilderFromByteString = sqlBuilderPure . BB.fromByteString
diff --git a/src/Database/PostgreSQL/Query/SqlBuilder/Class.hs b/src/Database/PostgreSQL/Query/SqlBuilder/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/SqlBuilder/Class.hs
@@ -0,0 +1,19 @@
+module Database.PostgreSQL.Query.SqlBuilder.Class
+       ( ToSqlBuilder(..)
+       ) where
+
+import Database.PostgreSQL.Query.SqlBuilder.Builder
+import Database.PostgreSQL.Simple.Types
+
+-- | Things which always can be transformed to 'SqlBuilder'
+class ToSqlBuilder a where
+  toSqlBuilder :: a -> SqlBuilder
+
+instance ToSqlBuilder SqlBuilder where
+  toSqlBuilder = id
+
+instance ToSqlBuilder Identifier where
+  toSqlBuilder ident = mkValue ident
+
+instance ToSqlBuilder QualifiedIdentifier where
+  toSqlBuilder qident = mkValue qident
diff --git a/src/Database/PostgreSQL/Query/SqlBuilder/Types.hs b/src/Database/PostgreSQL/Query/SqlBuilder/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/SqlBuilder/Types.hs
@@ -0,0 +1,64 @@
+module Database.PostgreSQL.Query.SqlBuilder.Types
+       ( -- * Sql builder result
+         SqlBuilderResult(..)
+       , builderResultPure
+         -- * Field masking in logs
+       , FieldOption(..)
+       , LogMasker
+       , defaultLogMasker
+       , hugeFieldsMasker
+       ) where
+
+
+import Blaze.ByteString.Builder (Builder)
+import Data.Semigroup
+import Data.String
+import Data.Typeable
+import GHC.Generics (Generic)
+import Language.Haskell.TH.Lift
+
+import qualified Blaze.ByteString.Builder as BB
+import qualified Data.ByteString as BS
+
+-- | Result if SqlBuilder. Contains separated builder for query and log.
+data SqlBuilderResult = SqlBuilderResult
+  { sbQueryString :: Builder
+  , sbLogString   :: Builder
+  } deriving (Typeable, Generic)
+
+instance Semigroup SqlBuilderResult where
+  (SqlBuilderResult a b) <> (SqlBuilderResult a' b') =
+    SqlBuilderResult (a <> a') (b <> b')
+
+instance Monoid SqlBuilderResult where
+  mempty  = SqlBuilderResult mempty mempty
+  mappend = (<>)
+
+builderResultPure :: Builder -> SqlBuilderResult
+builderResultPure b = SqlBuilderResult b b
+
+-- | Option for field instructing 'LogMasker' what to do with field when logging
+data FieldOption
+  = FieldDefault
+    -- ^ Do nothing. Field should be pasted as is
+  | FieldMasked
+    -- ^ Mask field in logs with placeholder.
+  deriving (Eq, Ord, Show, Typeable, Generic)
+
+deriveLift ''FieldOption
+
+-- | Function modifying query parameter value before pasting it to log.
+type LogMasker = FieldOption -> Builder -> Builder
+
+-- | Simply replaces masked fields with placeholder.
+defaultLogMasker :: LogMasker
+defaultLogMasker FieldDefault bb = bb
+defaultLogMasker FieldMasked _  = "'<MASKED BY POSTGRESQL-QUERY>'"
+
+-- | Masks fields which size is bigger than given argument in bytes.
+hugeFieldsMasker :: Int -> LogMasker
+hugeFieldsMasker maxsize _ bb =
+  let bl = BS.length $ BB.toByteString bb
+  in if bl > maxsize
+     then fromString $ "'<STRING SIZE: " ++ show bl ++ " MASKED BY POSTGRESQL-QUERY>'"
+     else bb
diff --git a/src/Database/PostgreSQL/Query/TH.hs b/src/Database/PostgreSQL/Query/TH.hs
--- a/src/Database/PostgreSQL/Query/TH.hs
+++ b/src/Database/PostgreSQL/Query/TH.hs
@@ -8,8 +8,6 @@
   , module Database.PostgreSQL.Query.TH.SqlExp
   ) where
 
-import Prelude
-
 import Database.PostgreSQL.Query.TH.Entity
 import Database.PostgreSQL.Query.TH.Enum
 import Database.PostgreSQL.Query.TH.Row
diff --git a/src/Database/PostgreSQL/Query/TH/Entity.hs b/src/Database/PostgreSQL/Query/TH/Entity.hs
--- a/src/Database/PostgreSQL/Query/TH/Entity.hs
+++ b/src/Database/PostgreSQL/Query/TH/Entity.hs
@@ -7,7 +7,7 @@
 
 import Data.Default
 import Data.String
-import Database.PostgreSQL.Query.Entity ( Entity(..) )
+import Database.PostgreSQL.Query.Entity.Class
 import Database.PostgreSQL.Query.TH.Common
 import Database.PostgreSQL.Query.Types ( FN(..) )
 import Database.PostgreSQL.Simple.FromField
diff --git a/src/Database/PostgreSQL/Query/TH/Enum.hs b/src/Database/PostgreSQL/Query/TH/Enum.hs
--- a/src/Database/PostgreSQL/Query/TH/Enum.hs
+++ b/src/Database/PostgreSQL/Query/TH/Enum.hs
@@ -5,12 +5,15 @@
   , InflectorFunc
   ) where
 
-import Prelude
-
 import Data.FileEmbed
 import Database.PostgreSQL.Simple.FromField
 import Database.PostgreSQL.Simple.ToField
 import Language.Haskell.TH
+
+#if !MIN_VERSION_base(4,8,0)
+import Data.Traversable
+import Control.Applicative
+#endif
 
 import qualified Data.Text.Encoding as T
 import qualified Data.Text as T
diff --git a/src/Database/PostgreSQL/Query/TH/Row.hs b/src/Database/PostgreSQL/Query/TH/Row.hs
--- a/src/Database/PostgreSQL/Query/TH/Row.hs
+++ b/src/Database/PostgreSQL/Query/TH/Row.hs
@@ -10,6 +10,9 @@
 import Database.PostgreSQL.Simple.ToRow ( ToRow(..) )
 import Language.Haskell.TH
 
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative
+#endif
 
 {-| Derive 'FromRow' instance. i.e. you have type like that
 
diff --git a/src/Database/PostgreSQL/Query/TH/SqlExp.hs b/src/Database/PostgreSQL/Query/TH/SqlExp.hs
--- a/src/Database/PostgreSQL/Query/TH/SqlExp.hs
+++ b/src/Database/PostgreSQL/Query/TH/SqlExp.hs
@@ -7,7 +7,6 @@
        , ropeParser
        , parseRope
        , squashRope
-       , buildQ
          -- * Template haskell
        , sqlQExp
        , sqlExpEmbed
@@ -25,9 +24,6 @@
 import Data.Monoid
 import Data.Text ( Text )
 import Database.PostgreSQL.Query.SqlBuilder
-    ( sqlBuilderFromField,
-      ToSqlBuilder(..) )
-import Database.PostgreSQL.Simple.Types ( Query(..) )
 import Language.Haskell.Meta.Parse.Careful
 import Language.Haskell.TH
 import Language.Haskell.TH.Quote
@@ -77,11 +73,12 @@
 
 -- | Internal type. Result of parsing sql string
 data Rope
-    = RLit Text            -- ^ Part of raw sql
-    | RComment Text        -- ^ Sql comment
-    | RSpaces Int          -- ^ Sequence of spaces
-    | RInt Text            -- ^ String with haskell expression inside __#{..}__
-    | RPaste Text          -- ^ String with haskell expression inside __^{..}__
+    = RLit Text             -- ^ Part of raw sql
+    | RComment Text         -- ^ Sql comment
+    | RSpaces Int           -- ^ Sequence of spaces
+    | RInt FieldOption Text -- ^ String with haskell expression inside __#{..}__
+                            -- or __#?{..}__
+    | RPaste Text           -- ^ String with haskell expression inside __^{..}__
     deriving (Ord, Eq, Show)
 
 parseRope :: String -> [Rope]
@@ -93,8 +90,9 @@
 ropeParser = many1 $ choice
              [ quoted
              , iquoted
-             , ropeint
-             , ropepaste
+             , RInt FieldMasked <$> someNested "#?{"
+             , RInt FieldDefault <$> someNested "#{"
+             , RPaste <$> someNested "^{"
              , comment
              , bcomment
              , spaces
@@ -110,23 +108,17 @@
 
     unquoteBraces = T.replace "\\}" "}"
 
-    ropeint = do
-        _ <- string "#{"
-        e <- many1 $ choice
-             [ string "\\}"
-             , T.singleton <$> notChar '}'
-             ]
-        _ <- char '}'
-        return $ RInt $ unquoteBraces $ mconcat e
-
-    ropepaste = do
-        _ <- string "^{"
+    -- Prefix must be string like '#{' or something
+    someNested :: Text -> Parser Text
+    someNested prefix = do
+        _ <- string prefix
         e <- many1 $ choice
              [ string "\\}"
              , T.singleton <$> notChar '}'
              ]
-        _ <- char '}'
-        return $ RPaste $ unquoteBraces $ mconcat e
+        eofErf ("block " <> T.unpack prefix <> " not finished") $ do
+          _ <- char '}'
+          return $ unquoteBraces $ mconcat e
 
     comment = do
         b <- string "--"
@@ -177,33 +169,20 @@
 
 
 -- | Build builder from rope
-buildBuilder :: Exp              -- ^ Expression of type 'Query'
-             -> Rope
+buildBuilder :: Rope
              -> Maybe (Q Exp)
-buildBuilder _ (RLit t) = Just $ do
+buildBuilder (RLit t) = Just $ do
     bs <- bsToExp $ T.encodeUtf8 t
-    [e| toSqlBuilder $(pure bs) |]
-buildBuilder q (RInt t) = Just $ do
+    [e| sqlBuilderFromByteString $(pure bs) |]
+buildBuilder (RInt fo t) = Just $ do
     when (T.null $ T.strip t) $ fail "empty interpolation string found"
     let ex = either error id $ parseExp $ T.unpack t
-    [e| sqlBuilderFromField $(pure q) $(pure ex) |]
-buildBuilder _ (RPaste t) = Just $ do
+    [e| sqlBuilderFromField $(lift fo) $(pure ex) |]
+buildBuilder (RPaste t) = Just $ do
     when (T.null $ T.strip t) $ fail "empty paste string found"
     let ex = either error id $ parseExp $ T.unpack t
     [e| toSqlBuilder $(pure ex) |]
-buildBuilder _ _ = Nothing
-
--- | Build 'Query' expression from row
-buildQ :: [Rope] -> Q Exp
-buildQ r = do
-    bs <- bsToExp $ mconcat $ map fromRope r
-    [e| Query $(pure bs) |]
-  where
-    fromRope (RLit t) = T.encodeUtf8 t
-    fromRope (RInt t) = "#{" <> (T.encodeUtf8 t) <> "}"
-    fromRope (RPaste p) = "^{" <> (T.encodeUtf8 p) <> "}"
-    fromRope (RComment c) = T.encodeUtf8 c
-    fromRope (RSpaces _) = " "
+buildBuilder _ = Nothing
 
 -- | Removes sequential occurencies of 'RLit' constructors. Also
 -- removes commentaries and squash sequences of spaces to single space
@@ -223,12 +202,10 @@
 sqlQExp :: String
         -> Q Exp                 -- ^ Expression of type 'SqlBuilder'
 sqlQExp s = do
-    let rope = squashRope
-               $ parseRope s
-    q <- buildQ rope
+    let rope = squashRope $ parseRope s
     exps <- sequence
             $ catMaybes
-            $ map (buildBuilder q) rope
+            $ map buildBuilder rope
     [e| ( mconcat $(pure $ ListE exps) ) |]
 
 {- | Embed sql template and perform interpolation
diff --git a/src/Database/PostgreSQL/Query/Types.hs b/src/Database/PostgreSQL/Query/Types.hs
--- a/src/Database/PostgreSQL/Query/Types.hs
+++ b/src/Database/PostgreSQL/Query/Types.hs
@@ -1,11 +1,13 @@
 module Database.PostgreSQL.Query.Types
        ( -- * Query execution
          HasPostgres(..)
+       , MonadPostgres
        , TransactionSafe
        , PgMonadT(..)
        , runPgMonadT
        , launchPG
         -- * Auxiliary types
+       , Qp(..)
        , InetText(..)
        , FN(..)
        , textFN
@@ -14,8 +16,6 @@
        , ToMarkedRow(..)
        ) where
 
-import Prelude
-
 import Control.Applicative
 import Control.Monad
 import Control.Monad.Base ( MonadBase(..) )
@@ -38,29 +38,30 @@
 import Control.Monad.Trans.Maybe
 import Control.Monad.Writer.Class ( MonadWriter )
 import Data.HSet
-import Data.Monoid
 import Data.Pool
 import Data.String
 import Data.Text ( Text )
 import Data.Typeable
 import Database.PostgreSQL.Query.SqlBuilder
-    ( mkIdent, ToSqlBuilder(..), SqlBuilder(..) )
 import Database.PostgreSQL.Query.TH.SqlExp
-    ( sqlExp )
 import Database.PostgreSQL.Simple
 import Database.PostgreSQL.Simple.FromField
-    ( FromField(..), typename, returnError )
 import Database.PostgreSQL.Simple.ToField
-    ( ToField )
+import Database.PostgreSQL.Simple.Types
 import GHC.Generics
 import Instances.TH.Lift ()
 import Language.Haskell.TH.Lift ( deriveLift )
 
-import qualified Data.List as L
+#if !MIN_VERSION_base(4,8,0)
+import Data.Monoid
+#endif
+
+import qualified Blaze.ByteString.Builder.ByteString as BB
 import qualified Control.Monad.Trans.State.Lazy as STL
 import qualified Control.Monad.Trans.State.Strict as STS
 import qualified Control.Monad.Trans.Writer.Lazy as WL
 import qualified Control.Monad.Trans.Writer.Strict as WS
+import qualified Data.List as L
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
 
@@ -71,6 +72,13 @@
 -}
 
 
+-- | Special constructor to perform old-style query interpolation
+data Qp = forall row. (ToRow row) => Qp Query row
+
+instance ToSqlBuilder Qp where
+  toSqlBuilder (Qp q row) = SqlBuilder $ \con _ ->
+    builderResultPure . BB.fromByteString <$> formatQuery con q row
+
 -- | type to put and get from db 'inet' and 'cidr' typed postgresql
 -- fields. This should be in postgresql-simple in fact.
 newtype InetText = InetText
@@ -131,7 +139,7 @@
     toSqlBuilder (FN tt) =
         mconcat
         $ L.intersperse "."
-        $ map mkIdent tt
+        $ map (toSqlBuilder . Identifier) tt
 
 instance IsString FN where
     fromString s =
@@ -200,6 +208,7 @@
   where
     tobld (f, val) = [sqlExp| ^{f} = ^{val} |]
 
+type MonadPostgres m = (HasPostgres m, MonadLogger m)
 
 -- | Instances of this typeclass can acquire connection and pass it to
 -- computation. It can be reader of pool of connections or just reader of
diff --git a/test/BuilderTest.hs b/test/BuilderTest.hs
new file mode 100644
--- /dev/null
+++ b/test/BuilderTest.hs
@@ -0,0 +1,33 @@
+module BuilderTest
+       ( builderTests
+       ) where
+
+import Data.Text (Text)
+import Database.PostgreSQL.Query
+import Database.PostgreSQL.Simple
+import Test.Tasty
+import Test.Tasty.HUnit
+
+caseLogDefault :: IO Connection -> TestTree
+caseLogDefault iocon = testCase "expect parameter pasted" $ do
+  con <- iocon
+  let t = "TEXT" :: Text
+  (q, l) <- runSqlBuilder con defaultLogMasker [sqlExp|INSERT #{t}|]
+  q @?= "INSERT 'TEXT'"
+  l @?= "INSERT 'TEXT'"
+
+caseLogMask :: IO Connection -> TestTree
+caseLogMask iocon = testCase "exptect parameter masked" $ do
+  con <- iocon
+  let t = "TEXT" :: Text
+  (q, l) <- runSqlBuilder con defaultLogMasker [sqlExp|INSERT #?{t}|]
+  q @?= "INSERT 'TEXT'"
+  l @?= "INSERT '<MASKED BY POSTGRESQL-QUERY>'"
+
+
+builderTests :: TestTree
+builderTests =
+  withResource (connectPostgreSQL "") close $ \con -> testGroup "BuilderTest"
+  [ caseLogMask con
+  , caseLogDefault con
+  ]
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,125 +1,10 @@
-{-# OPTIONS -fno-warn-orphans #-}
-
 module Main where
 
-import Control.Applicative
-import Data.Attoparsec.Text ( parseOnly )
-import Data.Monoid
-import Data.Text ( Text )
-import Database.PostgreSQL.Query.TH.SqlExp
-import Test.QuickCheck.Assertions
-import Test.QuickCheck.Instances ()
-import Test.QuickCheck.Modifiers
-import Test.QuickCheck.Property
-    ( Result )
+import BuilderTest
+import ParserTest
 import Test.Tasty
-import Test.Tasty.QuickCheck
-import Test.Tasty.TH
 
-import qualified Data.Text as T
-
-noSeqSpace :: [Rope] -> [Rope]
-noSeqSpace ((RSpaces a):(RSpaces b):xs) = noSeqSpace
-                                          $ (RSpaces $ a + b):xs
-noSeqSpace (x:xs) = x:(noSeqSpace xs)
-noSeqSpace [] = []
-
-newtype RopeList
-    = RopeList [Rope]
-    deriving (Ord, Eq, Show)
-
-instance Arbitrary RopeList where
-    arbitrary =
-        resize 10 $ (RopeList . noSeqSpace . getNonEmpty) <$> arbitrary
-
-wordAlpha :: [Text]
-wordAlpha = map T.singleton
-            $ ['A'..'Z'] ++ ['a'..'z']
-            ++ "!@$%&*()[];|{}<>="
-
-stringAlpha :: [Text]
-stringAlpha = wordAlpha ++ ["''", "\\'", " "]
-
-identAlpha :: [Text]
-identAlpha = wordAlpha ++ ["\"\"", " "]
-
-intAlpha :: [Text]
-intAlpha = wordAlpha ++ [" "]
-
-instance Arbitrary Rope where
-    arbitrary =
-        oneof [ RLit <$> stringLit
-              , RLit <$> idLit
-              , RInt <$> ropeInt
-              , RPaste <$> ropePaste
-              , RComment <$> comment
-              , RComment <$> bcomment
-              , RSpaces <$> spaces
-              , RLit <$> wordLit
-              ]
-      where
-        selems = resize 5 . listOf . elements
-        selems1 = resize 5 . listOf1 . elements
-        stringLit = do
-            x <- selems stringAlpha
-            return $ "'" <> mconcat x <> "'"
-
-        idLit = do
-            x <- selems identAlpha
-            return $ "\"" <> mconcat x <> "\""
-        ropeInt = do
-            x <- selems intAlpha
-            return $ "#{" <> mconcat x <> "}"
-        ropePaste = do
-            x <- selems1 intAlpha
-            return $ "^{" <> mconcat x <> "}"
-        comment = do
-            s <- selems wordAlpha
-            return $ "--" <> mconcat s
-        bcomment = do
-            n <- selems wordAlpha
-            return $ "/*" <> mconcat n <> "*/"
-        spaces = suchThat arbitrary (>= 1)
-        wordLit = fmap mconcat
-                  $ selems1 wordAlpha
-
-
-flattenRope :: [Rope] -> Text
-flattenRope = mconcat . map f
-  where
-    f (RLit t) = t
-    f (RComment c) = case T.uncons c of
-        (Just ('-', _)) -> c <> "\n"
-        _ -> c
-    f (RSpaces s) = mconcat $ replicate s " "
-    f (RInt t) = "#{" <> quoteBrace t <> "}"
-    f (RPaste t) = "^{" <> quoteBrace t <> "}"
-    quoteBrace = T.replace "}" "\\}"
-
-prop_RopeParser ::  RopeList -> Result
-prop_RopeParser (RopeList rope) =
-    (Right $ squashRope rope) ==?
-    (fmap squashRope $ parseOnly ropeParser $ flattenRope rope)
-
--- case_cleanLit :: Assertion
--- case_cleanLit =
---     mapM_ (\(a, b) -> a @=? (cleanLit b))
---     [ ("hello hello", "hello     hello")
---     , ("'hello     hello    '",  "'hello     hello    '")
---     , (" SELECT ", " SELECT   --     ")
---     , ("xxx '  ''  '", "xxx     '  ''  '")
---     , ("xxx xxx  xxx", "xxx   xxx --     \n     xxx")
---     , (" '    ''\\'' ", "    '    ''\\''     ")
---     , ("'''\\'''''\\'' ", "'''\\'''''\\'' ")
---     , (" \"    ident    \" ", " \"    ident    \" ")
---     , (" one - two -> plus ", " one -    \n  two    -> plus -- \n")
---     , ("xxx ", "xxx /* thus must eliminate */")
---     , ("xxx  xxx", "xxx /* bla /* nested */ \n comment */ xxx")
---     ]
-
-mainGroup :: TestTree
-mainGroup = $testGroupGenerator
-
 main :: IO ()
-main = do
-    defaultMain mainGroup
+main = defaultMain $ testGroup "main"
+  [ parserTests
+  , builderTests ]
diff --git a/test/ParserTest.hs b/test/ParserTest.hs
new file mode 100644
--- /dev/null
+++ b/test/ParserTest.hs
@@ -0,0 +1,178 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module ParserTest
+       ( parserTests
+       ) where
+
+import Data.Attoparsec.Text ( parseOnly )
+import Data.Derive.Arbitrary
+import Data.DeriveTH
+import Data.Monoid
+import Data.Text ( Text )
+import Database.PostgreSQL.Query.SqlBuilder
+import Database.PostgreSQL.Query.TH.SqlExp
+import Test.QuickCheck.Assertions
+import Test.QuickCheck.Instances ()
+import Test.QuickCheck.Modifiers
+import Test.Tasty
+import Test.Tasty.HUnit
+import Test.Tasty.QuickCheck
+import Test.Tasty.TH
+
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative
+#endif
+
+import qualified Data.Text as T
+
+noSeqSpace :: [Rope] -> [Rope]
+noSeqSpace ((RSpaces a):(RSpaces b):xs) = noSeqSpace
+                                          $ (RSpaces $ a + b):xs
+noSeqSpace (x:xs) = x:(noSeqSpace xs)
+noSeqSpace [] = []
+
+newtype RopeList = RopeList [Rope]
+  deriving (Ord, Eq, Show)
+
+instance Arbitrary RopeList where
+  arbitrary = resize 10 $ (RopeList . noSeqSpace . getNonEmpty) <$> arbitrary
+
+wordAlpha :: [Text]
+wordAlpha = map T.singleton
+            $ ['A'..'Z'] ++ ['a'..'z']
+            ++ "!@$%&*()[];|{}<>="
+
+stringAlpha :: [Text]
+stringAlpha = wordAlpha ++ ["''", "\\'", " "]
+
+identAlpha :: [Text]
+identAlpha = wordAlpha ++ ["\"\"", " "]
+
+intAlpha :: [Text]
+intAlpha = wordAlpha ++ [" "]
+
+derive makeArbitrary ''FieldOption
+
+instance Arbitrary Rope where
+    arbitrary =
+        oneof [ RLit <$> stringLit
+              , RLit <$> idLit
+              , RInt <$> arbitrary <*> ropeInt
+              , RPaste <$> ropePaste
+              , RComment <$> comment
+              , RComment <$> bcomment
+              , RSpaces <$> spaces
+              , RLit <$> wordLit
+              ]
+      where
+        selems = resize 5 . listOf . elements
+        selems1 = resize 5 . listOf1 . elements
+        stringLit = do
+            x <- selems stringAlpha
+            return $ "'" <> mconcat x <> "'"
+        idLit = do
+            x <- selems identAlpha
+            return $ "\"" <> mconcat x <> "\""
+        ropeInt = do
+            x <- selems intAlpha
+            return $ "#{" <> mconcat x <> "}"
+        ropePaste = do
+            x <- selems1 intAlpha
+            return $ "^{" <> mconcat x <> "}"
+        comment = do
+            s <- selems wordAlpha
+            return $ "--" <> mconcat s
+        bcomment = do
+            n <- selems wordAlpha
+            return $ "/*" <> mconcat n <> "*/"
+        spaces = suchThat arbitrary (>= 1)
+        wordLit = fmap mconcat
+                  $ selems1 wordAlpha
+
+flattenRope :: [Rope] -> Text
+flattenRope = mconcat . map f
+  where
+    f (RLit t) = t
+    f (RComment c) = case T.uncons c of
+        (Just ('-', _)) -> c <> "\n"
+        _ -> c
+    f (RSpaces s) = mconcat $ replicate s " "
+    f (RInt FieldDefault t) = "#{" <> quoteBrace t <> "}"
+    f (RInt FieldMasked t) = "#?{" <> quoteBrace t <> "}"
+    f (RPaste t) = "^{" <> quoteBrace t <> "}"
+    quoteBrace = T.replace "}" "\\}"
+
+prop_RopeParser ::  RopeList -> Result
+prop_RopeParser (RopeList rope) =
+    (Right $ squashRope rope) ==?
+    (fmap squashRope $ parseOnly ropeParser $ flattenRope rope)
+
+expectParser :: (Eq a, Show a) => ([Rope] -> a) -> (a, Text) -> Assertion
+expectParser predicate (a, raw) = do
+  rope <- either fail return $ parseOnly ropeParser raw
+  a @=? predicate rope
+
+case_expectLiterals :: Assertion
+case_expectLiterals = mapM_ (expectParser takeLits)
+    [ ("hello hello", "hello     hello")
+    , ("'hello     hello    '",  "'hello     hello    '")
+    , (" SELECT ", " SELECT   --     ")
+    , ("xxx '  ''  '", "xxx     '  ''  '")
+    , ("xxx xxx  xxx", "xxx   xxx --     \n     xxx")
+    , (" '    ''\\'' ", "    '    ''\\''     ")
+    , ("'''\\'''''\\'' ", "'''\\'''''\\'' ")
+    , (" \"    ident    \" ", " \"    ident    \" ")
+    , (" one - two -> plus ", " one -    \n  two    -> plus -- \n")
+    , ("xxx ", "xxx /* this must eliminate */")
+    , ("xxx  xxx", "xxx /* bla /* nested */ \n comment */ xxx")
+    ]
+  where
+    takeLits = mconcat . map takeLit
+    takeLit :: Rope -> Text
+    takeLit (RLit t) = t
+    takeLit (RSpaces _) = " "
+    takeLit _ = ""
+
+case_expectComments :: Assertion
+case_expectComments = mapM_ (expectParser takeComments)
+    [ ("", "hello     hello")
+    , ("",  "'hello     hello    '")
+    , ("-- line comment", " SELECT   -- line comment")
+    , ("/* comment */", "/* comment */ '  /* */ '' --  '")
+    ]
+  where
+    takeComments = mconcat . map takeComment
+    takeComment :: Rope -> Text
+    takeComment (RComment t) = t
+    takeComment _ = ""
+
+case_expectInterpolation :: Assertion
+case_expectInterpolation = mapM_ (expectParser takeInterpol)
+    [ ("", "  hello    hello ")
+    , ("something", " hello #{something} happend")
+    , ("something", " hello ^{something} happend")
+    , ("something", " hello #?{something} happend")
+    , ("", " 'hello #{something} happend' ")
+    , ("", " 'hello ^{something} happend' ")
+    , ("", " 'hello #?{something} happend' ")
+    , ("", " \"hello #{something} happend\" ")
+    , ("", " \"hello ^{something} happend\" ")
+    , ("", " \"hello #?{something} happend\" ")
+    , ("", " -- hello #{something} happend ")
+    , ("", " -- hello ^{something} happend' ")
+    , ("", " -- hello #?{something} happend' ")
+    , ("", " /* hello #{something} happend */ ")
+    , ("", " /* hello ^{something} happend */ ")
+    , ("", " /* hello #?{something} happend */ ")
+
+    ]
+  where
+    takeInterpol = mconcat . map go
+    go :: Rope -> Text
+    go (RInt _ t) = t
+    go (RPaste t) = t
+    go _ = ""
+
+
+parserTests :: TestTree
+parserTests = $testGroupGenerator
