diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Aleksey Uimanov
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Aleksey Uimanov nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,134 @@
+# What ?
+
+`postgresql-query` is a library for more simple query generation for
+PostgreSQL database. It is not an ORM (but contains some part of). It
+contains interpolating quasiquote for simple query generation.
+
+# Motivation
+
+When you want to perform some complex SQL query using
+`postgresql-simple` you writing this query by hands like that:
+
+```haskell
+let q = mconcat
+        [ "SELECT u.id, u.name, count(p.id) "
+        , "FROM users as u INNER JOIN posts as p "
+        , "ON u.id = p.user_id "
+        , "WHERE u.name like ? AND u.created BETWEEN ? AND ? "
+        , "GROUP BY u.id ORDER BY ? " ]
+```
+
+Well, this is not realy complex. Now what you need to perform the
+query is to paste parameters instead of this `?` signs:
+
+```haskell
+query con q ("%Peyton%", now, yesterday)
+```
+
+Did you see the mistake? We forgot about ordering field. To perform this query we must
+
+```haskell
+query con q ("%Peyton%", now, yesterday, Identifier "...
+```
+
+Oups!. If we use `Identifier "u.name"` we will get `"u.name"` in our
+query which is just not right. Sql syntax assumes `"u"."name"` for
+this query. We can not use query parameter to paste optional field
+here.
+
+
+Next example is more complex:
+
+```haskell
+let name = Just "%Peyton%" -- assume we getting parameters from query
+    minage = Just 10
+    maxage = Just 50
+    condlist = catMaybes
+               [ const " u.name like ? " <$> name
+               , const " u.age > ? " <$> minage
+               , const " u.age < ? " <$> maxage ]
+    paramlist = catMaybes
+                [ toField <$> name
+                , toField <$> minage
+                , toField <$> maxage ]
+    cond = if L.null condlist
+           then mempty
+           else "WHERE " <> (mconcat $ L.intersperse " AND " condlist)
+    q = "SELECT u.id, u.name, u.age FROM users AS u " <> cond
+query con q paramlist
+```
+
+So much to write and so many chances to make a mistake. What if we
+could write this like:
+
+```haskell
+let name = Just "%Peyton%" -- assume we getting parameters from query
+    minage = Just 10
+    maxage = Just 50
+    ord = "u.name" :: FN -- <- special type for field names!
+    condlist = catMaybes
+               [ (\a -> [sqlExp|u.name like #{a}|]) <$> name
+               , (\a -> [sqlExp|u.age > #{a}|])     <$> minage
+               , (\a -> [sqlExp|u.age < #{a}|])     <$> maxage ]
+    cond = if L.null condlist
+           then mempty
+           else [sqlExp|WHERE ^{mconcat $ L.intersperse " AND " condlist}|]
+pqQuery [sqlExp|SELECT u.id, u.name, u.age
+                FROM users AS u ^{cond}
+                ORDER BY ^{ord}|]
+```
+
+Much better!
+
+# sqlExp
+
+Quasiquote `sqlExp` has two way of interpolation:
+
+* `#{exp}` - pastes inside query arbitrary value which type is
+  instance of `ToField` typeclass. It performs correct strings
+  escaping so it is not the same as stupid string interpolation. Dont
+  worry about sql-injections when using it.
+
+* `^{exp}` - pastes inside query arbitrary value which type has
+  instance of `ToSqlBuilder` typeclass.
+
+`sqlExp` returns `SqlBuilder` which has a `Monoid` instance
+and made for effective concatination (bytestring builder works
+inside).
+
+This quasiquote correctly handles string literals and quoted
+identifiers. It also removes line and block (even nested) sql comments
+from resulting query as well as sequences of space characters. You are
+free to write queries like
+
+```sql
+WHERE name SIMILAR TO '\^{2,3}' -- line comment #{ololo}
+```
+
+or even
+
+```sql
+WHERE "#{strange}identifier" SIMILAR TO '#{1,10}' /*nested/*^{block}*/comment*/
+```
+
+`sqlExp` will remove all comments and will not interpolate inside
+string literals or quoted identifiers at all.
+
+## sqlExpEmbed and sqlExpFile
+
+If you have realy huge hardcore sql template you can
+
+```haskell
+pgQuery $(sqlExpEmbed "sql/foo/bar.sql")
+```
+
+It works just like Yesod's templates. You can use interpolation inside
+templates like inside `sqlExp`.
+
+```haskell
+pgQuery $(sqlExpFile "foo/bar")
+```
+
+Is absolutely the same as above. It just prepends `sql/` and
+appends `.sql` to your string. If you agree to follow naming
+conventions you are welcome to use `sqlExpFile`.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/postgresql-query.cabal b/postgresql-query.cabal
new file mode 100644
--- /dev/null
+++ b/postgresql-query.cabal
@@ -0,0 +1,104 @@
+name:                postgresql-query
+version:             1.0.0
+
+synopsis: Sql interpolating quasiquote plus some kind of primitive ORM
+          using it
+
+license:             BSD3
+license-file:        LICENSE
+author:              Aleksey Uimanov
+maintainer:          s9gf4ult@gmail.com
+-- copyright:
+category:            Database
+build-type:          Simple
+
+extra-source-files: README.md
+
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs: src
+
+  exposed-modules: Database.PostgreSQL.Query
+                 , Database.PostgreSQL.Query.Entity
+                 , Database.PostgreSQL.Query.Functions
+                 , Database.PostgreSQL.Query.Internal
+                 , Database.PostgreSQL.Query.SqlBuilder
+                 , Database.PostgreSQL.Query.TH
+                 , Database.PostgreSQL.Query.TH.SqlExp
+                 , Database.PostgreSQL.Query.Types
+
+  default-extensions: TemplateHaskell
+                    , CPP
+                    , DeriveDataTypeable
+                    , DeriveGeneric
+                    , EmptyDataDecls
+                    , FlexibleContexts
+                    , FlexibleInstances
+                    , GADTs
+                    , GeneralizedNewtypeDeriving
+                    , LambdaCase
+                    , MultiParamTypeClasses
+                    , NoImplicitPrelude
+                    , NoMonomorphismRestriction
+                    , OverloadedStrings
+                    , QuasiQuotes
+                    , RecordWildCards
+                    , ScopedTypeVariables
+                    , StandaloneDeriving
+                    , TupleSections
+                    , TypeFamilies
+                    , TypeOperators
+                    , UndecidableInstances
+                    , ViewPatterns
+
+  build-depends: base >=4.6 && < 5
+               , aeson
+               , attoparsec
+               , blaze-builder
+               , bytestring
+               , containers
+               , either
+               , exceptions
+               , file-embed
+               , haskell-src-meta
+               , monad-control                 == 0.3.3.1 || > 1.0.0.3
+               , monad-logger
+               , mtl
+               , postgresql-simple             >= 0.4.10.0
+               , resource-pool
+               , semigroups
+               , template-haskell
+               , text
+               , time
+               , transformers                            < 0.4
+               , transformers-base
+               , transformers-compat           >= 0.3
+
+  ghc-options: -Wall
+
+  default-language:    Haskell2010
+
+
+test-suite test
+  type:    exitcode-stdio-1.0
+  default-language:    Haskell2010
+  ghc-options:     -Wall
+  hs-source-dirs:  test
+  main-is: Main.hs
+
+  default-extensions: OverloadedStrings
+                    , TemplateHaskell
+                    , FlexibleInstances
+
+  build-depends: base >=4.6 && < 5
+               , QuickCheck
+               , attoparsec
+               , postgresql-query
+               , quickcheck-assertions
+               , quickcheck-instances
+               , tasty
+               , tasty-hunit
+               , tasty-quickcheck
+               , tasty-th
+               , text
diff --git a/src/Database/PostgreSQL/Query.hs b/src/Database/PostgreSQL/Query.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query.hs
@@ -0,0 +1,41 @@
+module Database.PostgreSQL.Query
+       ( -- * Common usage modules
+         module Database.PostgreSQL.Query.Entity
+       , module Database.PostgreSQL.Query.Functions
+       , module Database.PostgreSQL.Query.SqlBuilder
+       , module Database.PostgreSQL.Query.TH
+       , module Database.PostgreSQL.Query.Types
+
+           -- * Some re-exports from postgresql-simple
+       , Connection, connect, defaultConnectInfo, connectPostgreSQL
+       , ConnectInfo(..) , ToField(..), ToRow(..), FromField(..)
+       , FromRow(..), Query(..), Only(..), In(..), Oid(..), Values(..)
+       , (:.)(..), PGArray(..), HStoreList(..), HStoreMap(..)
+       , ToHStore(..), HStoreBuilder , hstore, parseHStoreList
+       , ToHStoreText(..), HStoreText , sqlQQ
+       ) where
+
+
+import Database.PostgreSQL.Simple
+    ( ToRow, Connection, FromRow, defaultConnectInfo,
+      connectPostgreSQL, connect, ConnectInfo(..) )
+import Database.PostgreSQL.Simple.FromField ( FromField(..) )
+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
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/Entity.hs
@@ -0,0 +1,26 @@
+module Database.PostgreSQL.Query.Entity
+       ( Entity(..)
+       , Ent
+       ) where
+
+import Data.Proxy
+import Data.Text ( Text )
+import Data.Typeable
+    ( Typeable )
+
+-- | 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 -> Text
+    -- | 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 -> [Text]
+
+deriving instance Typeable EntityId
+
+-- | Entity with it's id
+type Ent a = (EntityId a, a)
diff --git a/src/Database/PostgreSQL/Query/Functions.hs b/src/Database/PostgreSQL/Query/Functions.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/Functions.hs
@@ -0,0 +1,370 @@
+module Database.PostgreSQL.Query.Functions
+       ( -- * Raw query execution
+         pgQuery
+       , pgExecute
+       , pgQueryEntities
+         -- * Transactions
+       , pgWithTransaction
+       , pgWithSavepoint
+         -- * Work with entities
+       , pgInsertEntity
+       , pgInsertManyEntities
+       , pgInsertManyEntitiesId
+       , pgSelectEntities
+       , pgSelectJustEntities
+       , pgSelectEntitiesBy
+       , pgGetEntity
+       , pgGetEntityBy
+       , pgDeleteEntity
+       , pgUpdateEntity
+       , pgSelectCount
+         -- * Auxiliary functions
+       , 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.Text ( Text )
+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, mkIdent  )
+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_,
+      withTransaction, withSavepoint )
+import Database.PostgreSQL.Simple.FromField
+    ( FromField )
+import Database.PostgreSQL.Simple.ToField
+    ( ToField )
+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 all queries inside one transaction. Rollback transaction on exceptions
+pgWithTransaction :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m)
+                  => m a
+                  -> m a
+pgWithTransaction action = withPGConnection $ \con -> do
+    control $ \runInIO -> do
+        withTransaction con $ runInIO action
+
+-- | Same as `pgWithTransaction` but executes queries inside savepoint
+pgWithSavepoint :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m) => m a -> m a
+pgWithSavepoint action = withPGConnection $ \con -> do
+    control $ \runInIO -> do
+        withSavepoint con $ runInIO action
+
+{- | 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 ()
+pgInsertManyEntities [] = return ()
+pgInsertManyEntities ents' =
+    let ents = NL.fromList ents'
+    in void $ pgExecute $ insertManyEntities ents
+
+
+{- | Delete entity.
+
+@
+rmUser :: EntityId User -> Handler ()
+rmUser uid = do
+    pgDeleteEntity uid
+@
+
+-}
+
+pgDeleteEntity :: forall a m. (Entity a, HasPostgres m, MonadLogger m, ToField (EntityId a), Functor m)
+               => EntityId a
+               -> m ()
+pgDeleteEntity eid =
+    let p = Proxy :: Proxy a
+    in (const ()) <$> pgExecute [sqlExp|DELETE FROM ^{mkIdent $ 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)]
+@
+
+-}
+
+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 ()
+pgUpdateEntity eid b =
+    let p = Proxy :: Proxy a
+        mr = toMarkedRow b
+    in if L.null $ unMR mr
+       then return ()
+       else fmap (const ())
+            $ pgExecute [sqlExp|UPDATE ^{mkIdent $ 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 ^{mkIdent $ 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
+
+@
+pgRepsertRow "emails" (MR [("user_id", mkValue uid)]) (MR [("email", mkValue email)])
+@
+
+Then firstly will be performed
+
+@
+UPDATE "emails" SET email = 'foo@bar.com' WHERE "user_id" = 1234
+@
+
+And if no one row is affected (which is returned by 'pgExecute'), then
+
+@
+INSERT INTO "emails" ("user_id", "email") VALUES (1234, 'foo@bar.com')
+@
+
+will be performed
+
+-}
+
+pgRepsertRow :: (HasPostgres m, MonadLogger m, ToMarkedRow wrow, ToMarkedRow urow)
+             => Text              -- ^ Table name
+             -> wrow              -- ^ where condition
+             -> urow              -- ^ update row
+             -> m ()
+pgRepsertRow tname wrow urow = do
+    let wmr = toMarkedRow wrow
+    aff <- pgExecute $ updateTable tname urow
+           [sqlExp|WHERE ^{mrToBuilder "AND" wmr}|]
+    when (aff == 0) $ do
+        let umr = toMarkedRow urow
+            imr = wmr <> umr
+        _ <- pgExecute $ insertInto tname imr
+        return ()
diff --git a/src/Database/PostgreSQL/Query/Internal.hs b/src/Database/PostgreSQL/Query/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/Internal.hs
@@ -0,0 +1,275 @@
+module Database.PostgreSQL.Query.Internal
+       ( -- * Entity functions
+         entityFields
+       , entityFieldsId
+       , selectEntity
+       , selectEntitiesBy
+       , insertEntity
+       , insertManyEntities
+       , entityToMR
+         -- * Low level generators
+       , buildFields
+       , updateTable
+       , insertInto
+       ) where
+
+
+import Prelude
+
+import Data.List.NonEmpty ( NonEmpty )
+import Data.Monoid
+import Data.Proxy ( Proxy(..) )
+import Data.Text ( Text )
+import Database.PostgreSQL.Query.Entity
+    ( Entity(..) )
+import Database.PostgreSQL.Query.SqlBuilder
+    ( SqlBuilder, ToSqlBuilder(..),
+      mkIdent, mkValue )
+import Database.PostgreSQL.Query.TH
+    ( sqlExp )
+import Database.PostgreSQL.Query.Types
+    ( FN(..), textFN, MarkedRow(..),
+      ToMarkedRow(..), mrToBuilder )
+import Database.PostgreSQL.Simple.ToRow
+    ( ToRow(..) )
+
+import qualified Data.List.NonEmpty as NL
+import qualified Data.List as L
+
+{- $setup
+>>> import Database.PostgreSQL.Simple
+>>> import Database.PostgreSQL.Simple.ToField
+>>> import PGSimple.SqlBuilder
+>>> con <- connect defaultConnectInfo
+-}
+
+
+{-| Generates comma separated list of field names
+
+>>> runSqlBuilder con $ buildFields ["u" <> "name", "u" <> "phone", "e" <> "email"]
+"\"u\".\"name\", \"u\".\"phone\", \"e\".\"email\""
+-}
+buildFields :: [FN] -> SqlBuilder
+buildFields flds = mconcat
+                    $ L.intersperse ", "
+                    $ map toSqlBuilder flds
+
+{- | generates __UPDATE__ query
+
+>>> let name = "%vip%"
+>>> runSqlBuilder con $ updateTable "ships" (MR [("size", mkValue 15)]) [sqlExp|WHERE size > 15 AND name NOT LIKE #{name}|]
+"UPDATE \"ships\" SET  \"size\" = 15  WHERE size > 15 AND name NOT LIKE '%vip%'"
+
+-}
+
+updateTable :: (ToSqlBuilder q, ToMarkedRow flds)
+            => Text              -- ^ table name
+            -> flds              -- ^ fields to update
+            -> q                 -- ^ condition
+            -> SqlBuilder
+updateTable tname flds q =
+    let mr = toMarkedRow flds
+        setFields = mrToBuilder ", " mr
+    in [sqlExp|UPDATE ^{mkIdent tname}
+               SET ^{setFields} ^{q}|]
+
+
+{- | Generate INSERT INTO query for entity
+
+>>> runSqlBuilder con $ insertInto "foo" $ MR [("name", mkValue "vovka"), ("hobby", mkValue "president")]
+"INSERT INTO \"foo\" (\"name\", \"hobby\") VALUES ('vovka', 'president')"
+
+-}
+
+insertInto :: (ToMarkedRow b)
+           => Text               -- ^ table name
+           -> b                  -- ^ list of pairs (name, value) to insert into
+           -> SqlBuilder
+insertInto tname b =
+    let mr = toMarkedRow b
+        names = mconcat
+                $ L.intersperse ", "
+                $ map (toSqlBuilder . fst)
+                $ unMR mr
+        values = mconcat
+                 $ L.intersperse ", "
+                 $ map snd
+                 $ unMR mr
+    in [sqlExp|INSERT INTO ^{mkIdent 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 . FN . (:[]))
+    $ 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 ^{mkIdent $ 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 = map textFN $ 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 mkIdent
+                $ fieldNames p
+        values = mconcat
+                 $ L.intersperse ","
+                 $ map rValue
+                 $ NL.toList rows
+
+    in [sqlExp|INSERT INTO ^{mkIdent $ tableName p}
+               (^{names}) VALUES ^{values}|]
+  where
+    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
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/SqlBuilder.hs
@@ -0,0 +1,132 @@
+module Database.PostgreSQL.Query.SqlBuilder
+       ( -- * Types
+         SqlBuilder(..)
+       , ToSqlBuilder(..)
+       , Qp(..)
+         -- * SqlBuilder helpers
+       , emptyB
+       , runSqlBuilder
+       , mkIdent
+       , mkValue
+       , sqlBuilderPure
+       , sqlBuilderFromField
+       ) 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)
diff --git a/src/Database/PostgreSQL/Query/TH.hs b/src/Database/PostgreSQL/Query/TH.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/TH.hs
@@ -0,0 +1,130 @@
+module Database.PostgreSQL.Query.TH
+       ( -- * Deriving instances
+         deriveFromRow
+       , deriveToRow
+         -- * Embedding sql files
+       , embedSql
+       , sqlFile
+         -- * Sql string interpolation
+       , sqlExp
+       , sqlExpEmbed
+       , sqlExpFile
+       ) where
+
+import Prelude
+
+import Control.Applicative
+import Data.FileEmbed ( embedFile )
+import Database.PostgreSQL.Simple.FromRow ( FromRow(..), field )
+import Database.PostgreSQL.Simple.ToRow ( ToRow(..) )
+import Database.PostgreSQL.Simple.Types ( Query(..) )
+import Language.Haskell.TH
+import Database.PostgreSQL.Query.TH.SqlExp
+
+
+cName :: (Monad m) => Con -> m Name
+cName (NormalC n _) = return n
+cName (RecC n _) = return n
+cName _ = error "Constructor must be simple"
+
+cArgs :: (Monad m) => Con -> m Int
+cArgs (NormalC _ n) = return $ length n
+cArgs (RecC _ n) = return $ length n
+cArgs _ = error "Constructor must be simple"
+
+-- | Derive 'FromRow' instance. i.e. you have type like that
+--
+-- @
+-- data Entity = Entity
+--               { eField :: Text
+--               , eField2 :: Int
+--               , efield3 :: Bool }
+-- @
+--
+-- then 'deriveFromRow' will generate this instance:
+-- instance FromRow Entity where
+--
+-- @
+-- instance FromRow Entity where
+--     fromRow = Entity
+--               \<$> field
+--               \<*> field
+--               \<*> field
+-- @
+--
+-- Datatype must have just one constructor with arbitrary count of fields
+deriveFromRow :: Name -> Q [Dec]
+deriveFromRow t = do
+    TyConI (DataD _ _ _ [con] _) <- reify t
+    cname <- cName con
+    cargs <- cArgs con
+    [d|instance FromRow $(return $ ConT t) where
+           fromRow = $(fieldsQ cname cargs)|]
+  where
+    fieldsQ cname cargs = do
+        fld <- [| field |]
+        fmp <- [| (<$>) |]
+        fap <- [| (<*>) |]
+        return $ UInfixE (ConE cname) fmp (fapChain cargs fld fap)
+
+    fapChain 0 _ _ = error "there must be at least 1 field in constructor"
+    fapChain 1 fld _ = fld
+    fapChain n fld fap = UInfixE fld fap (fapChain (n-1) fld fap)
+
+lookupVNameErr :: String -> Q Name
+lookupVNameErr name =
+    lookupValueName name >>=
+    maybe (error $ "could not find identifier: " ++ name)
+          return
+
+
+-- | derives 'ToRow' instance for datatype like
+--
+-- @
+-- data Entity = Entity
+--               { eField :: Text
+--               , eField2 :: Int
+--               , efield3 :: Bool }
+-- @
+--
+-- it will derive instance like that:
+--
+-- @
+-- instance ToRow Entity where
+--      toRow (Entity e1 e2 e3) =
+--          [ toField e1
+--          , toField e2
+--          , toField e3 ]
+-- @
+deriveToRow :: Name -> Q [Dec]
+deriveToRow t = do
+    TyConI (DataD _ _ _ [con] _) <- reify t
+    cname <- cName con
+    cargs <- cArgs con
+    cvars <- sequence
+             $ replicate cargs
+             $ newName "a"
+    [d|instance ToRow $(return $ ConT t) where
+           toRow $(return $ ConP cname $ map VarP cvars) = $(toFields cvars)|]
+  where
+    toFields v = do
+        tof <- lookupVNameErr "toField"
+        return $ ListE
+            $ map
+            (\e -> AppE (VarE tof) (VarE e))
+            v
+
+-- embed sql file as value
+embedSql :: String               -- ^ File path
+         -> Q Exp
+embedSql path = do
+    [e| (Query ( $(embedFile path) )) |]
+{-# DEPRECATED embedSql "use 'sqlExpEmbed' instead" #-}
+
+-- embed sql file by pattern. __sqlFile "dir/file"__ is just the same as
+-- __embedSql "sql/dir/file.sql"__
+sqlFile :: String                -- ^ sql file pattern
+        -> Q Exp
+sqlFile s = do
+    embedSql $ "sql/" ++ s ++ ".sql"
+{-# DEPRECATED sqlFile "use 'sqlExpFile' instead" #-}
diff --git a/src/Database/PostgreSQL/Query/TH/SqlExp.hs b/src/Database/PostgreSQL/Query/TH/SqlExp.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/TH/SqlExp.hs
@@ -0,0 +1,267 @@
+module Database.PostgreSQL.Query.TH.SqlExp
+       ( -- * QQ
+         sqlExp
+         -- * Types
+       , Rope(..)
+         -- * Parser
+       , ropeParser
+       , parseRope
+       , squashRope
+       , buildQ
+         -- * Template haskell
+       , sqlQExp
+       , sqlExpEmbed
+       , sqlExpFile
+       ) where
+import Prelude hiding (takeWhile)
+
+import Control.Applicative
+import Control.Monad ( when )
+import Data.Attoparsec.Combinator
+import Data.Attoparsec.Text
+import Data.Char ( isSpace )
+import Data.FileEmbed ( bsToExp )
+import Data.Maybe
+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
+import Language.Haskell.TH.Syntax
+
+import qualified Data.ByteString as B
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+
+{- $setup
+>>> import Database.PostgreSQL.Simple
+>>> import PGSimple.SqlBuilder
+>>> import qualified Data.List as L
+>>> c <- connect defaultConnectInfo
+-}
+
+{- | Maybe the main feature of all library. Quasiquoter which builds
+'SqlBuilder' from string query. Removes line comments and block
+comments (even nested) and sequences of spaces. Correctly works
+handles string literals and quoted identifiers. Here is examples of usage
+
+>>> let name = "name"
+>>> let val = "some 'value'"
+>>> runSqlBuilder c [sqlExp|SELECT * FROM tbl WHERE ^{mkIdent name} = #{val}|]
+"SELECT * FROM tbl WHERE \"name\" = 'some ''value'''"
+
+And more comples example:
+
+>>> let name = Just "name"
+>>> let size = Just 10
+>>> let active = Nothing :: Maybe Bool
+>>> let condlist = catMaybes [ fmap (\a -> [sqlExp|name = #{a}|]) name, fmap (\a -> [sqlExp|size = #{a}|]) size, fmap (\a -> [sqlExp|active = #{a}|]) active]
+>>> let cond = if L.null condlist then mempty else [sqlExp| WHERE ^{mconcat $ L.intersperse " AND " $ condlist} |]
+>>> runSqlBuilder c [sqlExp|SELECT *   FROM tbl ^{cond} -- line comment|]
+"SELECT * FROM tbl  WHERE name = 'name' AND size = 10  "
+
+-}
+
+sqlExp :: QuasiQuoter
+sqlExp = QuasiQuoter
+         { quoteExp  = sqlQExp
+         , quotePat  = error "sqlInt used in pattern"
+         , quoteType = error "sqlInt used in type"
+         , quoteDec  = error "sqlInt used in declaration"
+         }
+
+-- | 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 __^{..}__
+    deriving (Ord, Eq, Show)
+
+parseRope :: String -> [Rope]
+parseRope s = either error id
+              $ parseOnly ropeParser
+              $ T.pack s
+
+ropeParser :: Parser [Rope]
+ropeParser = many1 $ choice
+             [ quoted
+             , iquoted
+             , ropeint
+             , ropepaste
+             , comment
+             , bcomment
+             , spaces
+             , (RLit . T.singleton) <$> anyChar
+             ]
+  where
+    eofErf e p =
+        choice
+        [ endOfInput
+          *> (error $ "Unexpected end of input: " <> e)
+        , p
+        ]
+
+    unquoteBraces = T.replace "\\}" "}"
+
+    ropeint = do
+        _ <- string "#{"
+        e <- many1 $ choice
+             [ string "\\}"
+             , T.singleton <$> notChar '}'
+             ]
+        _ <- char '}'
+        return $ RInt $ unquoteBraces $ mconcat e
+
+    ropepaste = do
+        _ <- string "^{"
+        e <- many1 $ choice
+             [ string "\\}"
+             , T.singleton <$> notChar '}'
+             ]
+        _ <- char '}'
+        return $ RPaste $ unquoteBraces $ mconcat e
+
+    comment = do
+        b <- string "--"
+        c <- takeWhile (`notElem` ['\r', '\n'])
+        endOfLine <|> endOfInput
+        return $ RComment $ b <> c
+    spaces = (RSpaces . T.length) <$> takeWhile1 isSpace
+
+    bcomment :: Parser Rope
+    bcomment = RComment <$> go
+      where
+        go = do
+            b <- string "/*"
+            c <- many' $ choice
+                 [ go
+                 , justStar
+                 , T.singleton <$> notChar '*'
+                 ]
+            eofErf "block comment not finished, maybe typo" $ do
+                e <- string "*/"
+                return $ b <> mconcat c <> e
+        justStar = do
+            _ <- char '*'
+            peekChar >>= \case
+                (Just '/') -> fail "no way"
+                _ -> return "*"
+
+    quoted = do
+        _ <- char '\''
+        ret <- many' $ choice
+               [ string "''"
+               , string "\\'"
+               , T.singleton <$> notChar '\''
+               ]
+        eofErf "string literal not finished" $ do
+            _ <- char '\''
+            return $ RLit $ "'" <> mconcat ret <> "'"
+
+    iquoted = do
+        _ <- char '"'
+        ret <- many' $ choice
+               [ string "\"\""
+               , T.singleton <$> notChar '"'
+               ]
+        eofErf "quoted identifier not finished" $ do
+            _ <- char '"'
+            return $ RLit $ "\"" <> mconcat ret <> "\""
+
+
+-- | Build builder from rope
+buildBuilder :: Exp              -- ^ Expression of type 'Query'
+             -> Rope
+             -> Maybe (Q Exp)
+buildBuilder _ (RLit t) = Just $ do
+    bs <- bsToExp $ T.encodeUtf8 t
+    [e| toSqlBuilder $(pure bs) |]
+buildBuilder q (RInt 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
+    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 _) = " "
+
+-- | Removes sequential occurencies of 'RLit' constructors. Also
+-- removes commentaries and squash sequences of spaces to single space
+-- symbol
+squashRope :: [Rope] -> [Rope]
+squashRope = go . catMaybes . map cleanRope
+  where
+    cleanRope (RComment _) = Nothing
+    cleanRope (RSpaces _) = Just $ RLit " "
+    cleanRope x = Just x
+
+    go ((RLit a):(RLit b):xs) = go ((RLit $ a <> b):xs)
+    go (x:xs) = x:(go xs)
+    go [] = []
+
+-- | Build expression of type 'SqlBuilder' from SQL query with interpolation
+sqlQExp :: String
+        -> Q Exp                 -- ^ Expression of type 'SqlBuilder'
+sqlQExp s = do
+    let rope = squashRope
+               $ parseRope s
+    q <- buildQ rope
+    exps <- sequence
+            $ catMaybes
+            $ map (buildBuilder q) rope
+    [e| ( mconcat $(pure $ ListE exps) ) |]
+
+{- | Embed sql template and perform interpolation
+
+@
+let name = "name"
+    foo = "bar"
+    query = $(sqlExpEmbed "sql/foo/bar.sql") -- using 'foo' and 'bar' inside
+@
+-}
+
+sqlExpEmbed :: String            -- ^ file path
+            -> Q Exp             -- ^ Expression of type 'SqlBuilder'
+sqlExpEmbed fpath = do
+    qAddDependentFile fpath
+    s <- runIO $ T.unpack . T.decodeUtf8 <$> B.readFile fpath
+    sqlQExp s
+
+{- | Just like 'sqlExpEmbed' but uses pattern instead of file
+name. So, code
+
+@
+let query = $(sqlExpFile "foo/bar")
+@
+
+is just the same as
+
+@
+let query = $(sqlExpEmbed "sql/foo/bar.sql")
+@
+
+This function inspired by Yesod's 'widgetFile'
+-}
+
+sqlExpFile :: String
+           -> Q Exp
+sqlExpFile ptr = sqlExpEmbed $ "sql/" <> ptr <> ".sql"
diff --git a/src/Database/PostgreSQL/Query/Types.hs b/src/Database/PostgreSQL/Query/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Query/Types.hs
@@ -0,0 +1,369 @@
+module Database.PostgreSQL.Query.Types
+       ( -- * Query execution
+         HasPostgres(..)
+       , TransactionSafe
+       , PgMonadT(..)
+       , runPgMonadT
+       , launchPG
+        -- * Auxiliary types
+       , InetText(..)
+       , FN(..)
+       , textFN
+       , MarkedRow(..)
+       , mrToBuilder
+       , ToMarkedRow(..)
+       ) where
+
+import Prelude
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Base ( MonadBase(..) )
+import Control.Monad.Catch
+    ( MonadThrow, MonadMask, MonadCatch )
+import Control.Monad.Cont.Class ( MonadCont )
+import Control.Monad.Error.Class ( MonadError )
+import Control.Monad.Fix ( MonadFix(..) )
+import Control.Monad.Logger
+import Control.Monad.Reader
+    ( MonadReader(..), ReaderT(..) )
+import Control.Monad.State.Class ( MonadState )
+import Control.Monad.Trans
+import Control.Monad.Trans.Cont
+import Control.Monad.Trans.Control
+import Control.Monad.Trans.Either
+import Control.Monad.Trans.Except
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Maybe
+import Control.Monad.Writer.Class ( MonadWriter )
+import Data.Monoid
+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 GHC.Generics
+
+import qualified Data.List as L
+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.Text as T
+import qualified Data.Text.Encoding as T
+
+{- $setup
+>>> import PGSimple.SqlBuilder
+>>> c <- connect defaultConnectInfo
+-}
+
+
+-- | type to put and get from db 'inet' and 'cidr' typed postgresql
+-- fields. This should be in postgresql-simple in fact.
+newtype InetText =
+    InetText
+    { unInetText :: T.Text
+    } deriving ( IsString, Eq, Ord, Read, Show
+               , Typeable, Monoid, ToField )
+
+instance FromField InetText where
+    fromField fld Nothing = returnError ConversionFailed
+                            fld "can not convert Null to InetText"
+    fromField fld (Just bs) = do
+        n <- typename fld
+        case n of
+            "inet" -> result
+            "cidr" -> result
+            _ -> returnError
+                 ConversionFailed fld
+                 "could not convert to InetText"
+      where
+        result = return $ InetText
+                 $ T.decodeUtf8 bs
+
+
+
+{- | Dote separated field name. Each element in nested list will be
+properly quoted and separated by dot. It also have instance of
+'ToSqlBuilder' and 'IsString` so you can:
+
+>>> let a = "hello" :: FN
+>>> a
+FN ["hello"]
+
+>>> let b = "user.name" :: FN
+>>> b
+FN ["user","name"]
+
+>>> let n = "u.name" :: FN
+>>> runSqlBuilder c $ toSqlBuilder n
+"\"u\".\"name\""
+
+>>> ("user" <> "name") :: FN
+FN ["user","name"]
+
+>>> let a = "name" :: FN
+>>> let b = "email" :: FN
+>>> runSqlBuilder c [sqlExp|^{"u" <> a} = 'name', ^{"e" <> b} = 'email'|]
+"\"u\".\"name\" = 'name', \"e\".\"email\" = 'email'"
+
+-}
+
+newtype FN =
+    FN [Text]
+    deriving (Ord, Eq, Show, Monoid, Typeable, Generic)
+
+instance ToSqlBuilder FN where
+    toSqlBuilder (FN tt) =
+        mconcat
+        $ L.intersperse "."
+        $ map mkIdent tt
+
+instance IsString FN where
+    fromString s =
+        FN
+        $ map T.pack
+        $ filter (/= ".")
+        $ L.groupBy f s
+      where
+        f a b = not $ a == '.' || b == '.'
+
+{- | Single field to 'FN'
+
+>>> textFN "hello"
+FN ["hello"]
+
+>>> textFN "user.name"
+FN ["user.name"]
+
+Note that it does not split string to parts by point like instance of
+`IsString` does
+
+-}
+
+textFN :: Text -> FN
+textFN = FN . (:[])
+
+{- | Marked row is list of pairs of field name and some sql
+expression. Used to generate queries like:
+
+@
+name = 'name' AND size = 10 AND length = 20
+@
+
+or
+
+@
+UPDATE tbl SET name = 'name', size = 10, lenght = 20
+@
+
+-}
+
+newtype MarkedRow =
+    MR
+    { unMR :: [(FN, SqlBuilder)]
+    } deriving (Monoid, Typeable, Generic)
+
+class ToMarkedRow a where
+    -- | generate list of pairs (field name, field value)
+    toMarkedRow :: a -> MarkedRow
+
+instance ToMarkedRow MarkedRow where
+    toMarkedRow = id
+
+{- | Turns marked row to query intercalating it with other builder
+
+>>> runSqlBuilder c $ mrToBuilder "AND" $ MR [("name", mkValue "petr"), ("email", mkValue "foo@bar.com")]
+" \"name\" = 'petr' AND \"email\" = 'foo@bar.com' "
+
+-}
+
+mrToBuilder :: SqlBuilder        -- ^ Builder to intercalate with
+            -> MarkedRow
+            -> SqlBuilder
+mrToBuilder b (MR l) = mconcat
+                       $ L.intersperse b
+                       $ map tobld l
+  where
+    tobld (f, val) = [sqlExp| ^{f} = ^{val} |]
+
+
+-- | Instances of this typeclass can acquire connection and pass it to
+-- computation. It can be reader of pool of connections or just reader of
+-- connection
+
+class (MonadBase IO m) => HasPostgres m where
+    withPGConnection :: (Connection -> m a) -> m a
+
+instance (HasPostgres m) => HasPostgres (EitherT e m) where
+    withPGConnection action = do
+        EitherT $ withPGConnection $ \con -> do
+            runEitherT $ action con
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m) => HasPostgres (ExceptT e m) where
+    withPGConnection action = do
+        ExceptT $ withPGConnection $ \con -> do
+            runExceptT $ action con
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m) => HasPostgres (IdentityT m) where
+    withPGConnection action = do
+        IdentityT $ withPGConnection $ \con -> do
+            runIdentityT $ action con
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m) => HasPostgres (MaybeT m) where
+    withPGConnection action = do
+        MaybeT $ withPGConnection $ \con -> do
+            runMaybeT $ action con
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m) => HasPostgres (ReaderT r m) where
+    withPGConnection action = do
+        ReaderT $ \r -> withPGConnection $ \con ->
+            runReaderT (action con) r
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m) => HasPostgres (STL.StateT s m) where
+    withPGConnection action = do
+        STL.StateT $ \s -> withPGConnection $ \con ->
+            STL.runStateT (action con) s
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m) => HasPostgres (STS.StateT s m) where
+    withPGConnection action = do
+        STS.StateT $ \s -> withPGConnection $ \con ->
+            STS.runStateT (action con) s
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m) => HasPostgres (ContT r m) where
+    withPGConnection action = do
+        ContT $ \r -> withPGConnection $ \con ->
+            runContT (action con) r
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m, Monoid w) => HasPostgres (WL.WriterT w m) where
+    withPGConnection action = do
+        WL.WriterT $ withPGConnection $ \con ->
+            WL.runWriterT (action con)
+    {-# INLINABLE withPGConnection #-}
+
+instance (HasPostgres m, Monoid w) => HasPostgres (WS.WriterT w m) where
+    withPGConnection action = do
+        WS.WriterT $ withPGConnection $ \con ->
+            WS.runWriterT (action con)
+    {-# INLINABLE withPGConnection #-}
+
+-- | Empty typeclass signing monad in which transaction is
+-- safe. i.e. `PgMonadT` have this instance, but some other monad giving
+-- connection from e.g. connection pool is not.
+class TransactionSafe (m :: * -> *)
+
+instance (TransactionSafe m) => TransactionSafe (EitherT e m)
+instance (TransactionSafe m) => TransactionSafe (ExceptT e m)
+instance (TransactionSafe m) => TransactionSafe (IdentityT m)
+instance (TransactionSafe m) => TransactionSafe (MaybeT m)
+instance (TransactionSafe m) => TransactionSafe (ReaderT r m)
+instance (TransactionSafe m) => TransactionSafe (STL.StateT s m)
+instance (TransactionSafe m) => TransactionSafe (STS.StateT s m)
+instance (TransactionSafe m) => TransactionSafe (ContT r m)
+instance (TransactionSafe m, Monoid w) => TransactionSafe (WL.WriterT w m)
+instance (TransactionSafe m, Monoid w) => TransactionSafe (WS.WriterT w m)
+
+
+-- | Reader of connection. Has instance of 'HasPostgres'. So if you have a
+-- connection you can run queries in this monad using 'runPgMonadT'. Or you
+-- can use this transformer to run sequence of queries using same
+-- connection with 'launchPG'.
+newtype PgMonadT m a =
+    PgMonadT
+    { unPgMonadT :: ReaderT Connection m a
+    } deriving ( Functor, Applicative, Monad , MonadWriter w
+               , MonadState s, MonadError e, MonadTrans
+               , Alternative, MonadFix, MonadPlus, MonadIO
+               , MonadCont, MonadThrow, MonadCatch, MonadMask
+               , MonadBase b, MonadLogger )
+
+#if MIN_VERSION_monad_control(1,0,0)
+instance (MonadBaseControl b m) => MonadBaseControl b (PgMonadT m) where
+    type StM (PgMonadT m) a = StM (ReaderT Connection m) a
+    liftBaseWith action = PgMonadT $ do
+        liftBaseWith $ \runInBase -> action (runInBase . unPgMonadT)
+    restoreM st = PgMonadT $ restoreM st
+    {-# INLINABLE liftBaseWith #-}
+    {-# INLINABLE restoreM #-}
+
+instance MonadTransControl PgMonadT where
+    type StT PgMonadT a = StT (ReaderT Connection) a
+    liftWith action = PgMonadT $ do
+        liftWith $ \runTrans -> action (runTrans . unPgMonadT)
+    restoreT st = PgMonadT $ restoreT st
+    {-# INLINABLE liftWith #-}
+    {-# INLINABLE restoreT #-}
+#else
+instance (MonadBaseControl b m) => MonadBaseControl b (PgMonadT m) where
+    newtype StM (PgMonadT m) a
+        = PgMTM (StM (ReaderT Connection m) a)
+    liftBaseWith action = PgMonadT $ do
+        liftBaseWith $ \runInBase -> do
+            action ((PgMTM `liftM`) . runInBase . unPgMonadT)
+    restoreM (PgMTM st) = PgMonadT $ restoreM st
+    {-# INLINABLE liftBaseWith #-}
+    {-# INLINABLE restoreM #-}
+
+instance MonadTransControl PgMonadT where
+    newtype StT PgMonadT a
+        = PgMTT
+          { unPgMTT :: StT (ReaderT Connection) a
+          }
+    liftWith action = PgMonadT $ do
+        liftWith $ \runTrans -> do -- ReaderT Connection n a -> n (StT (ReaderT Connection n) a)
+            action ((PgMTT `liftM`) . runTrans . unPgMonadT)
+    restoreT st = PgMonadT $ restoreT $ unPgMTT `liftM` st
+    {-# INLINABLE liftWith #-}
+    {-# INLINABLE restoreT #-}
+#endif
+
+instance (MonadReader r m) => MonadReader r (PgMonadT m) where
+    ask = lift ask
+    local md ac = do
+        con <- PgMonadT ask
+        lift $ do
+            local md $ runPgMonadT con ac
+    reader = lift . reader
+    {-# INLINABLE ask #-}
+    {-# INLINABLE local #-}
+    {-# INLINABLE reader #-}
+
+instance (MonadBase IO m) => HasPostgres (PgMonadT m) where
+    withPGConnection action = do
+        con <- PgMonadT ask
+        action con
+    {-# INLINABLE withPGConnection #-}
+
+instance TransactionSafe (PgMonadT m)
+
+
+runPgMonadT :: Connection -> PgMonadT m a -> m a
+runPgMonadT con (PgMonadT action) = runReaderT action con
+
+{- | If your monad have instance of 'HasPostgres' you maybe dont need this
+function, unless your instance use 'withPGPool' which acquires connection
+from pool for each query. If you want to run sequence of queries using same
+connection you need this function
+
+-}
+
+launchPG :: (HasPostgres m)
+         => PgMonadT m a
+         -> m a
+launchPG act = withPGConnection $ \con -> do
+    runPgMonadT con act
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,125 @@
+{-# 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 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
