diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,11 @@
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 
+## [0.3.0.0] - 2020-05-01
+### Changed
+- Query is now a data type with binding as Monad
+- Query is available via Database.EJDB2 module
+
 ## [0.2.0.0] - 2020-04-19
 ### Added
 - fold function to reduce a query result
diff --git a/cbits/finalizer.c b/cbits/finalizer.c
deleted file mode 100644
--- a/cbits/finalizer.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "finalizer.h"
-#include <stdlib.h>
-
-void finalizerJQL(JQL* jql) {
-  JQL* jqlCopy = jql;
-  jql_destroy(jql);
-  free(jqlCopy);
-}
diff --git a/cbits/finalizer.h b/cbits/finalizer.h
deleted file mode 100644
--- a/cbits/finalizer.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <ejdb2/ejdb2.h>
-
-void finalizerJQL(JQL* jql);
diff --git a/ejdb2-binding.cabal b/ejdb2-binding.cabal
--- a/ejdb2-binding.cabal
+++ b/ejdb2-binding.cabal
@@ -3,7 +3,7 @@
 category:            Database
 description:         Binding to EJDB2 C library, an embedded JSON noSQL database. Package requires libejdb2 to build. Please see the README on GitHub at <https://github.com/cescobaz/ejdb2haskell#readme>
 synopsis:            Binding to EJDB2 C library, an embedded JSON noSQL database
-version:             0.2.0.0
+version:             0.3.0.0
 license:             MIT
 license-file:        LICENSE
 homepage:            https://github.com/cescobaz/ejdb2haskell#readme
@@ -12,8 +12,6 @@
 author:              Francesco Burelli
 maintainer:          francesco.burelli@protonmail.com
 extra-source-files:  CHANGELOG.md
-                     cbits/finalizer.h
-                     cbits/finalizer.c
                      test/read-only-db
 
 source-repository head
@@ -22,7 +20,6 @@
 
 library
   exposed-modules:     Database.EJDB2
-                     , Database.EJDB2.Query
                      , Database.EJDB2.Meta
                      , Database.EJDB2.CollectionMeta
                      , Database.EJDB2.IndexMeta
@@ -31,10 +28,10 @@
                      , Database.EJDB2.WAL
                      , Database.EJDB2.KV
   other-modules:
-                       Database.EJDB2.JBL
+                       Database.EJDB2.Query
+                     , Database.EJDB2.JBL
                      , Database.EJDB2.Result
                      , Database.EJDB2.IndexMode
-                     , Database.EJDB2.QueryConstructor
                      , Database.EJDB2.Bindings.EJDB2
                      , Database.EJDB2.Bindings.JQL
                      , Database.EJDB2.Bindings.JBL
@@ -45,12 +42,10 @@
                      , bytestring ^>=0.10.10.0
                      , aeson ^>=1.4.6.0
                      , unordered-containers ^>=0.2.10.0
+                     , mtl ^>=2.2.2
   build-tool-depends:  hsc2hs:hsc2hs
   extra-libraries:     ejdb2
   pkgconfig-depends:   libejdb2
-  c-sources:           cbits/finalizer.c
-  install-includes:    finalizer.h
-  include-dirs:        cbits
   hs-source-dirs:      src
   default-language:    Haskell2010
 
diff --git a/src/Database/EJDB2.hs b/src/Database/EJDB2.hs
--- a/src/Database/EJDB2.hs
+++ b/src/Database/EJDB2.hs
@@ -31,6 +31,20 @@
     , removeIndex
     , onlineBackup
     , fold
+    , Query(..)
+    , noBind
+    , setBool
+    , setBoolAtIndex
+    , setI64
+    , setI64AtIndex
+    , setF64
+    , setF64AtIndex
+    , setString
+    , setStringAtIndex
+    , setRegex
+    , setRegexAtIndex
+    , setNull
+    , setNullAtIndex
     ) where
 
 import           Control.Exception
@@ -53,7 +67,6 @@
 import qualified Database.EJDB2.KV                      as KV
 import           Database.EJDB2.Options                 as Options
 import           Database.EJDB2.Query
-import           Database.EJDB2.QueryConstructor
 import           Database.EJDB2.Result
 
 import           Foreign
@@ -128,16 +141,17 @@
             (c_jbl_destroy jblPtr)
 
 -- | Executes a given query and returns the number of documents.
-getCount :: Database -> Query -> IO Int64
-getCount (Database _ ejdb) (Query jql _ _) = alloca $
+getCount :: Database -> Query q -> IO Int64
+getCount (Database _ ejdb) query = withQuery query $ \jql -> alloca $
     \countPtr -> c_ejdb_count ejdb jql countPtr 0 >>= checkRC >> peek countPtr
     >>= \(CIntMax int) -> return int
 
-exec :: EJDBExecVisitor -> Database -> Query -> IO ()
-exec visitor (Database _ ejdb) (Query jql _ _) = do
-    visitor <- mkEJDBExecVisitor visitor
-    let exec = EJDBExec.zero { db = ejdb, q = jql, EJDBExec.visitor = visitor }
-    finally (with exec c_ejdb_exec >>= checkRC) (freeHaskellFunPtr visitor)
+exec :: EJDBExecVisitor -> Database -> Query q -> IO ()
+exec visitor (Database _ ejdb) query = withQuery query $ \jql -> do
+    cVisitor <- mkEJDBExecVisitor visitor
+    let exec =
+            EJDBExec.zero { db = ejdb, q = jql, EJDBExec.visitor = cVisitor }
+    finally (with exec c_ejdb_exec >>= checkRC) (freeHaskellFunPtr cVisitor)
 
 -- | Iterate over query result building the result
 fold :: Aeson.FromJSON b
@@ -146,7 +160,7 @@
          -> (Int64, Maybe b)
          -> a) -- ^ The second argument is a tuple with the object id and the object
      -> a -- ^ Initial result
-     -> Query
+     -> Query q
      -> IO a
 fold database f i query = newIORef (f, i) >>= \ref ->
     exec (foldVisitor ref) database query >> snd <$> readIORef ref
@@ -164,7 +178,7 @@
 {-|
   Executes a given query and builds a query result as list of tuple with id and document.
 -}
-getList :: Aeson.FromJSON a => Database -> Query -> IO [(Int64, Maybe a)]
+getList :: Aeson.FromJSON a => Database -> Query q -> IO [(Int64, Maybe a)]
 getList database query = reverse <$> fold database foldList [] query
 
 foldList :: Aeson.FromJSON a
@@ -176,7 +190,7 @@
 {-|
   Executes a given query and builds a query result as list of documents with id injected as attribute.
 -}
-getList' :: Aeson.FromJSON a => Database -> Query -> IO [Maybe a]
+getList' :: Aeson.FromJSON a => Database -> Query q -> IO [Maybe a]
 getList' database query = reverse <$> fold database foldList' [] query
 
 foldList'
diff --git a/src/Database/EJDB2/Bindings/JQL.hs b/src/Database/EJDB2/Bindings/JQL.hs
--- a/src/Database/EJDB2/Bindings/JQL.hs
+++ b/src/Database/EJDB2/Bindings/JQL.hs
@@ -33,6 +33,3 @@
 
 foreign import ccall unsafe "ejdb2/jql.h jql_destroy" c_jql_destroy
     :: Ptr JQL -> IO ()
-
-foreign import ccall "finalizer.h &finalizerJQL" p_finalizerJQL
-    :: FunPtr (Ptr JQL -> IO ())
diff --git a/src/Database/EJDB2/HTTP.hsc b/src/Database/EJDB2/HTTP.hsc
--- a/src/Database/EJDB2/HTTP.hsc
+++ b/src/Database/EJDB2/HTTP.hsc
@@ -21,7 +21,7 @@
                        , port :: !Int32 -- ^ Listen port number, required
                        , bind :: Maybe String -- ^ Listen IP\/host. Default: /localhost/
                        , accessToken :: Maybe String -- ^ Server access token passed in /X-Access-Token/ header. Default: zero
-                       , blocking :: !Bool -- ^ Block 'open' thread until http service finished.
+                       , blocking :: !Bool -- ^ Block open thread until http service finished.
 -- Otherwise HTTP servee started in background.
 
                        , readAnon :: !Bool -- ^ Allow anonymous read-only database access
diff --git a/src/Database/EJDB2/Query.hs b/src/Database/EJDB2/Query.hs
--- a/src/Database/EJDB2/Query.hs
+++ b/src/Database/EJDB2/Query.hs
@@ -1,6 +1,8 @@
 module Database.EJDB2.Query
-    ( Query
-    , fromString
+    ( Query(..)
+    , BindM
+    , withQuery
+    , noBind
     , setBool
     , setBoolAtIndex
     , setI64
@@ -15,12 +17,14 @@
     , setNullAtIndex
     ) where
 
-import qualified Data.Bool                       as Bool
+import           Control.Monad.IO.Class
+import           Control.Monad.State.Lazy
+
+import qualified Data.Bool                   as Bool
 import           Data.IORef
 import           Data.Int
 
 import           Database.EJDB2.Bindings.JQL
-import           Database.EJDB2.QueryConstructor
 import           Database.EJDB2.Result
 
 import           Foreign
@@ -28,33 +32,62 @@
 import           Foreign.C.Types
 import           Foreign.Marshal.Alloc
 
--- | Create query object from specified text query. Collection must be specified in query.
-fromString :: String -- ^ Query text
-           -> IO Query
-fromString string = do
+-- | Query data with binding. Collection must be specified in query.
+data Query a = Query String -- ^ Query text with collection
+                     (BindM a)
+
+data BindState = BindState JQL [CString]
+
+-- | Monad to apply binding to 'Query'
+type BindM a = StateT BindState IO a
+
+bind :: BindM a -> BindState -> IO BindState
+bind bindM state = execStateT bindM state
+
+getJQL :: BindM JQL
+getJQL = get >>= \(BindState jql _) -> return jql
+
+noBind :: BindM ()
+noBind = return ()
+
+freeBindState :: BindState -> IO BindState
+freeBindState (BindState jql cStrings) = mapM_ free cStrings
+    >> return (BindState jql [])
+
+withQuery :: Query a -> (JQL -> IO b) -> IO b
+withQuery (Query query bindM) f = do
+    (jqlPtr, jql) <- createQuery query
+    bindState <- bind bindM (BindState jql [])
+    result <- f jql
+    destroyQuery jqlPtr
+    freeBindState bindState
+    return result
+
+createQuery :: String -- ^ Query text
+            -> IO (Ptr JQL, JQL)
+createQuery string = do
     jqlPtr <- malloc
     withCString string $ \cString -> do
         c_jql_create jqlPtr nullPtr cString >>= checkRC
         jql <- peek jqlPtr
-        jqlFPtr <- newForeignPtr p_finalizerJQL jqlPtr
-        ioRef <- newIORef []
-        return $ Query jql jqlFPtr ioRef
+        return (jqlPtr, jql)
 
+destroyQuery :: Ptr JQL -> IO ()
+destroyQuery jqlPtr = c_jql_destroy jqlPtr >> free jqlPtr
+
 -- | Bind bool to query placeholder
 setBool :: Bool
         -> String -- ^ Placeholder
-        -> Query
-        -> IO ()
-setBool bool placeholder (Query jql _ _) =
-    withCString placeholder $ \cPlaceholder ->
+        -> BindM ()
+setBool bool placeholder =
+    getJQL >>= \jql -> liftIO $ withCString placeholder $ \cPlaceholder ->
     c_jql_set_bool jql cPlaceholder 0 (CBool (Bool.bool 0 1 bool)) >>= checkRC
 
 -- | Bind bool to query at specified index
 setBoolAtIndex :: Bool
                -> Int -- ^ Index
-               -> Query
-               -> IO ()
-setBoolAtIndex bool index (Query jql _ _) =
+               -> BindM ()
+setBoolAtIndex bool index = getJQL >>= \jql -> liftIO $
     c_jql_set_bool jql
                    nullPtr
                    (CInt $ fromIntegral index)
@@ -63,94 +96,80 @@
 -- | Bind number to query placeholder
 setI64 :: Int64
        -> String -- ^ Placeholder
-       -> Query
-       -> IO ()
-setI64 number placeholder (Query jql _ _) = withCString placeholder $
-    \cPlaceholder -> c_jql_set_i64 jql cPlaceholder 0 (CIntMax number)
-    >>= checkRC
+       -> BindM ()
+setI64 number placeholder =
+    getJQL >>= \jql -> liftIO $ withCString placeholder $ \cPlaceholder ->
+    c_jql_set_i64 jql cPlaceholder 0 (CIntMax number) >>= checkRC
 
 -- | Bind number to query at specified index
 setI64AtIndex :: Int64
               -> Int -- ^ Index
-              -> Query
-              -> IO ()
-setI64AtIndex number index (Query jql _ _) =
+              -> BindM ()
+setI64AtIndex number index = getJQL >>= \jql -> liftIO $
     c_jql_set_i64 jql nullPtr (CInt $ fromIntegral index) (CIntMax number)
     >>= checkRC
 
 -- | Bind 'Double' to query placeholder
 setF64 :: Double
        -> String -- ^ Placeholder
-       -> Query
-       -> IO ()
-setF64 number placeholder (Query jql _ _) = withCString placeholder $
-    \cPlaceholder -> c_jql_set_f64 jql cPlaceholder 0 (CDouble number)
-    >>= checkRC
+       -> BindM ()
+setF64 number placeholder =
+    getJQL >>= \jql -> liftIO $ withCString placeholder $ \cPlaceholder ->
+    c_jql_set_f64 jql cPlaceholder 0 (CDouble number) >>= checkRC
 
 -- | Bind 'Double' to query at specified index
 setF64AtIndex :: Double
               -> Int -- ^ Index
-              -> Query
-              -> IO ()
-setF64AtIndex number index (Query jql _ _) =
+              -> BindM ()
+setF64AtIndex number index = getJQL >>= \jql -> liftIO $
     c_jql_set_f64 jql nullPtr (CInt $ fromIntegral index) (CDouble number)
     >>= checkRC
 
-newCStringInIORef :: String -> IORef [ForeignPtr CChar] -> IO CString
-newCStringInIORef string ioRef = do
-    cString <- newCString string
-    cStringPtr <- newForeignPtr finalizerFree cString
-    modifyIORef' ioRef ((:) cStringPtr)
-    return cString
+newCStringInBindState :: String -> BindM CString
+newCStringInBindState string = get >>= \(BindState jql strings) ->
+    liftIO (newCString string) >>= \cString ->
+    put (BindState jql (cString : strings)) >> return cString
 
 -- | Bind string to query placeholder
 setString :: String
           -> String -- ^ Placeholder
-          -> Query
-          -> IO ()
-setString string placeholder (Query jql _ ioRef) = do
-    cString <- newCStringInIORef string ioRef
-    withCString placeholder $
-        \cPlaceholder -> c_jql_set_str jql cPlaceholder 0 cString >>= checkRC
+          -> BindM ()
+setString string placeholder = newCStringInBindState string
+    >>= \cString -> getJQL >>= \jql -> liftIO $ withCString placeholder $
+    \cPlaceholder -> c_jql_set_str jql cPlaceholder 0 cString >>= checkRC
 
 -- | Bind string to query at specified index
 setStringAtIndex :: String
                  -> Int -- ^ Index
-                 -> Query
-                 -> IO ()
-setStringAtIndex string index (Query jql _ ioRef) = do
-    cString <- newCStringInIORef string ioRef
+                 -> BindM ()
+setStringAtIndex string index =
+    newCStringInBindState string >>= \cString -> getJQL >>= \jql -> liftIO $
     c_jql_set_str jql nullPtr (CInt $ fromIntegral index) cString >>= checkRC
 
 -- | Bind regex to query placeholder
 setRegex :: String -- ^ Regex
          -> String -- ^ Placeholder
-         -> Query
-         -> IO ()
-setRegex string placeholder (Query jql _ ioRef) = do
-    cString <- newCStringInIORef string ioRef
-    withCString placeholder $
-        \cPlaceholder -> c_jql_set_regexp jql cPlaceholder 0 cString >>= checkRC
+         -> BindM ()
+setRegex string placeholder = newCStringInBindState string
+    >>= \cString -> getJQL >>= \jql -> liftIO $ withCString placeholder $
+    \cPlaceholder -> c_jql_set_regexp jql cPlaceholder 0 cString >>= checkRC
 
 -- | Bind regex to query at specified index
 setRegexAtIndex :: String -- ^ Regex
                 -> Int -- ^ Index
-                -> Query
-                -> IO ()
-setRegexAtIndex string index (Query jql _ ioRef) = do
-    cString <- newCStringInIORef string ioRef
+                -> BindM ()
+setRegexAtIndex string index =
+    newCStringInBindState string >>= \cString -> getJQL >>= \jql -> liftIO $
     c_jql_set_regexp jql nullPtr (CInt $ fromIntegral index) cString >>= checkRC
 
 -- | Bind /null/ value to query placeholder
 setNull :: String -- ^ Placeholder
-        -> Query
-        -> IO ()
-setNull placeholder (Query jql _ _) = withCString placeholder $
+        -> BindM ()
+setNull placeholder = getJQL >>= \jql -> liftIO $ withCString placeholder $
     \cPlaceholder -> c_jql_set_null jql cPlaceholder 0 >>= checkRC
 
 -- | Bind /null/ value to query at specified index
 setNullAtIndex :: Int -- ^ Index
-               -> Query
-               -> IO ()
-setNullAtIndex index (Query jql _ _) =
+               -> BindM ()
+setNullAtIndex index = getJQL >>= \jql -> liftIO $
     c_jql_set_null jql nullPtr (CInt $ fromIntegral index) >>= checkRC
diff --git a/src/Database/EJDB2/QueryConstructor.hs b/src/Database/EJDB2/QueryConstructor.hs
deleted file mode 100644
--- a/src/Database/EJDB2/QueryConstructor.hs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Database.EJDB2.QueryConstructor ( Query(..) ) where
-
-import           Data.IORef
-
-import           Database.EJDB2.Bindings.JQL
-
-import           Foreign
-import           Foreign.C.Types
-
--- | Query handle
-data Query = Query { jql     :: JQL
-                   , jqlPtr  :: ForeignPtr JQL
-                   , strings :: IORef [ForeignPtr CChar]
-                   }
diff --git a/test/CollectionTests.hs b/test/CollectionTests.hs
--- a/test/CollectionTests.hs
+++ b/test/CollectionTests.hs
@@ -4,7 +4,6 @@
 
 import           Database.EJDB2
 import           Database.EJDB2.Options
-import qualified Database.EJDB2.Query   as Query
 
 import           Plant
 
@@ -29,7 +28,7 @@
     database <- databaseIO
     id <- putNew database "plants" plant
     removeCollection database "plants"
-    count <- Query.fromString "@plants/*" >>= getCount database
+    count <- getCount database $ Query "@plants/*" noBind
     count @?= 0
   where
     plant = nothingPlant { id          = Nothing
@@ -44,7 +43,7 @@
     database <- databaseIO
     id <- putNew database "plants" plant
     renameCollection database "plants" "vegetables"
-    count <- Query.fromString "@plants/*" >>= getCount database
+    count <- getCount database $ Query "@plants/*" noBind
     count @?= 0
     storedPlant <- getById database "vegetables" id
     storedPlant @?= Just plant
diff --git a/test/FoldTests.hs b/test/FoldTests.hs
--- a/test/FoldTests.hs
+++ b/test/FoldTests.hs
@@ -4,7 +4,6 @@
 
 import qualified Database.EJDB2         as DB
 import           Database.EJDB2.Options
-import qualified Database.EJDB2.Query   as Query
 
 import           Plant
 
@@ -24,7 +23,7 @@
 foldOnIsTreeTest :: IO DB.Database -> TestTree
 foldOnIsTreeTest databaseIO = testCase "foldOnIsTree" $ do
     database <- databaseIO
-    query <- Query.fromString "@plants/*"
+    let query = DB.Query "@plants/*" DB.noBind
     result <- DB.fold database foldOnIsTree (0, 0) query
     result @?= (1, 3)
 
diff --git a/test/GetTests.hs b/test/GetTests.hs
--- a/test/GetTests.hs
+++ b/test/GetTests.hs
@@ -10,7 +10,6 @@
 
 import           Database.EJDB2
 import           Database.EJDB2.Options
-import qualified Database.EJDB2.Query   as Query
 
 import           Plant
 
@@ -55,19 +54,17 @@
 getCountTest :: IO Database -> TestTree
 getCountTest databaseIO = testCase "getCount" $ do
     database <- databaseIO
-    count <- Query.fromString "@plants/*" >>= getCount database
+    count <- getCount database $ Query "@plants/*" noBind
     count @?= 4
 
-getListTestQuery :: IO Query.Query
-getListTestQuery = do
-    query <- Query.fromString "@plants/[isTree=:tree] | asc /name"
-    Query.setBool False "tree" query
-    return query
+getListTestQuery :: Query ()
+getListTestQuery =
+    Query "@plants/[isTree=:tree] | asc /name" $ setBool False "tree"
 
 getListTest :: IO Database -> TestTree
 getListTest databaseIO = testCase "getList" $ do
     database <- databaseIO
-    plants <- getListTestQuery >>= getList database
+    plants <- getList database getListTestQuery
     plants
         @?= [ ( 2
                   , Just nothingPlant { id          = Nothing
@@ -101,7 +98,7 @@
 getListTest' :: IO Database -> TestTree
 getListTest' databaseIO = testCase "getList'" $ do
     database <- databaseIO
-    plants <- getListTestQuery >>= getList' database
+    plants <- getList' database getListTestQuery
     plants @?= [ Just nothingPlant { id          = Just 2
                                    , name        = Just "gentiana brentae"
                                    , isTree      = Just False
@@ -137,7 +134,7 @@
 getListFromNotExistingCollectionTest databaseIO =
     testCase "getListFromNotExistingCollectionTest" $ do
         database <- databaseIO
-        query <- Query.fromString "@noexisting/[isTree=:tree] | asc /name"
-        Query.setBool False "tree" query
+        let query = Query "@noexisting/[isTree=:tree] | asc /name" $
+                setBool False "tree"
         list <- getList database query :: IO [(Int64, Maybe Value)]
         list @?= []
diff --git a/test/QueryTests.hs b/test/QueryTests.hs
--- a/test/QueryTests.hs
+++ b/test/QueryTests.hs
@@ -7,7 +7,6 @@
 
 import           Database.EJDB2
 import           Database.EJDB2.Options
-import qualified Database.EJDB2.Query   as Query
 
 import           Plant
 
@@ -41,8 +40,8 @@
 getListWithBoolQueryTest :: IO Database -> TestTree
 getListWithBoolQueryTest databaseIO = testCase "getListWithBoolQuery" $ do
     database <- databaseIO
-    query <- Query.fromString "@plants/[isTree=:?] | asc /name"
-    Query.setBoolAtIndex False 0 query
+    let query = Query "@plants/[isTree=:?] | asc /name"
+                      (setBoolAtIndex False 0)
     plants <- getList database query
     plants
         @?= [ ( 2
@@ -77,8 +76,7 @@
 getListWithI64QueryTest :: IO Database -> TestTree
 getListWithI64QueryTest databaseIO = testCase "getListWithI64Query" $ do
     database <- databaseIO
-    query <- Query.fromString "@plants/[year>:year] | asc /name"
-    Query.setI64 1800 "year" query
+    let query = Query "@plants/[year>:year] | asc /name" (setI64 1800 "year")
     plants <- getList database query
     plants
         @?= [ ( 2
@@ -103,8 +101,7 @@
 getListWithI64AtIndexQueryTest :: IO Database -> TestTree
 getListWithI64AtIndexQueryTest databaseIO = testCase "getListWithI64AtIndexQuery" $ do
     database <- databaseIO
-    query <- Query.fromString "@plants/[year>:?] | asc /name"
-    Query.setI64AtIndex 1800 0 query
+    let query = Query "@plants/[year>:?] | asc /name" (setI64AtIndex 1800 0)
     plants <- getList database query
     plants
         @?= [ ( 2
@@ -129,8 +126,8 @@
 getListWithF64QueryTest :: IO Database -> TestTree
 getListWithF64QueryTest databaseIO = testCase "getListWithF64Query" $ do
     database <- databaseIO
-    query <- Query.fromString "@plants/[ratio > :ratio] | asc /name"
-    Query.setF64 1.6 "ratio" query
+    let query = Query "@plants/[ratio > :ratio] | asc /name"
+                      (setF64 1.6 "ratio")
     plants <- getList database query
     plants @?= [ ( 4
                      , Just nothingPlant { id          = Nothing
@@ -145,29 +142,27 @@
                ]
 
 getListWithF64AtIndexQueryTest :: IO Database -> TestTree
-getListWithF64AtIndexQueryTest databaseIO =
-    testCase "getListWithF64AtIndexQuery" $ do
-        database <- databaseIO
-        query <- Query.fromString "@plants/[ratio > :?] | asc /name"
-        Query.setF64AtIndex 1.6 0 query
-        plants <- getList database query
-        plants @?= [ ( 4
-                         , Just nothingPlant { id          = Nothing
-                                             , name        =
-                                                   Just "leucanthemum vulgare"
-                                             , isTree      = Just False
-                                             , year        = Just 1778
-                                             , description = Just "very common flower in Italy 🍕"
-                                             , ratio       = Just 1.618
-                                             }
-                         )
-                   ]
+getListWithF64AtIndexQueryTest databaseIO = testCase "getListWithF64AtIndexQuery" $ do
+    database <- databaseIO
+    let query = Query "@plants/[ratio > :?] | asc /name" (setF64AtIndex 1.6 0)
+    plants <- getList database query
+    plants @?= [ ( 4
+                     , Just nothingPlant { id          = Nothing
+                                         , name        =
+                                               Just "leucanthemum vulgare"
+                                         , isTree      = Just False
+                                         , year        = Just 1778
+                                         , description = Just "very common flower in Italy 🍕"
+                                         , ratio       = Just 1.618
+                                         }
+                     )
+               ]
 
 getListWithStringQueryTest :: IO Database -> TestTree
 getListWithStringQueryTest databaseIO = testCase "getListWithStringQuery" $ do
     database <- databaseIO
-    query <- Query.fromString "@plants/[name=:name] | asc /name"
-    Query.setString "pinus" "name" query
+    let query = Query "@plants/[name=:name] | asc /name"
+                      (setString "pinus" "name")
     plants <- getList database query
     plants @?= [ ( 1
                      , Just nothingPlant { id          = Nothing
@@ -183,8 +178,8 @@
 getListWithStringAtIndexQueryTest databaseIO =
     testCase "getListWithStringAtIndexQuery" $ do
         database <- databaseIO
-        query <- Query.fromString "@plants/[name=:?] | asc /name"
-        Query.setStringAtIndex "pinus" 0 query
+        let query = Query "@plants/[name=:?] | asc /name"
+                          (setStringAtIndex "pinus" 0)
         plants <- getList database query
         plants @?= [ ( 1
                          , Just nothingPlant { id          = Nothing
@@ -199,9 +194,8 @@
 getListWithRegexQueryTest :: IO Database -> TestTree
 getListWithRegexQueryTest databaseIO = testCase "getListWithRegexQuery" $ do
     database <- databaseIO
-    query
-        <- Query.fromString "@plants/[description re :description ] | asc /name"
-    Query.setRegex ".*Italy.*" "description" query
+    let query = Query "@plants/[description re :description ] | asc /name"
+                      (setRegex ".*Italy.*" "description")
     plants <- getList database query
     plants @?= [ ( 4
                      , Just nothingPlant { id          = Nothing
@@ -219,8 +213,8 @@
 getListWithRegexAtIndexQueryTest databaseIO =
     testCase "getListWithRegexAtIndexQuery" $ do
         database <- databaseIO
-        query <- Query.fromString "@plants/[description re :?] | asc /name"
-        Query.setRegexAtIndex "very.*Italy" 0 query
+        let query = Query "@plants/[description re :?] | asc /name"
+                          (setRegexAtIndex "very.*Italy" 0)
         plants <- getList database query
         plants @?= [ ( 4
                          , Just nothingPlant { id          = Nothing
@@ -237,8 +231,7 @@
 getListWithNullQueryTest :: IO Database -> TestTree
 getListWithNullQueryTest databaseIO = testCase "getListWithNullQuery" $ do
     database <- databaseIO
-    query <- Query.fromString "@plants/[ratio=:ratio] | asc /name"
-    Query.setNull "ratio" query
+    let query = Query "@plants/[ratio=:ratio] | asc /name" (setNull "ratio")
     plants <- getList database query
     plants @?= [ ( 1
                      , Just nothingPlant { id          = Nothing
@@ -255,8 +248,7 @@
 getListWithNullAtIndexQueryTest databaseIO =
     testCase "getListWithNullAtIndexQuery" $ do
         database <- databaseIO
-        query <- Query.fromString "@plants/[ratio=:?] | asc /name"
-        Query.setNullAtIndex 0 query
+        let query = Query "@plants/[ratio=:?] | asc /name" (setNullAtIndex 0)
         plants <- getList database query
         plants @?= [ ( 1
                          , Just nothingPlant { id          = Nothing
@@ -272,10 +264,10 @@
 getListWithMixedQueryTest :: IO Database -> TestTree
 getListWithMixedQueryTest databaseIO = testCase "getListWithMixedQuery" $ do
     database <- databaseIO
-    query <- Query.fromString "@plants/[year>:year] and /[isTree=:?] and /[name=:?] | asc /name"
-    Query.setI64 1700 "year" query
-    Query.setBoolAtIndex True 0 query
-    Query.setStringAtIndex "pinus" 1 query
+    let query = Query "@plants/[year>:year] and /[isTree=:?] and /[name=:?] | asc /name" $ do
+            setI64 1700 "year"
+            setBoolAtIndex True 0
+            setStringAtIndex "pinus" 1
     plants <- getList database query
     plants @?= [ ( 1
                      , Just nothingPlant { id          = Nothing
@@ -291,9 +283,9 @@
 getListWithTwoStringsQueryTest databaseIO =
     testCase "getListWithTwoStringsQuery" $ do
         database <- databaseIO
-        query <- Query.fromString "@plants/[description re :descr] and /[name=:name] | asc /name"
-        Query.setRegex ".*wow.*" "descr" query
-        Query.setString "pinus" "name" query
+        let query = Query "@plants/[description re :descr] and /[name=:name] | asc /name" $ do
+                setRegex ".*wow.*" "descr"
+                setString "pinus" "name"
         plants <- getList database query
         plants @?= [ ( 1
                          , Just nothingPlant { id          = Nothing
