packages feed

ejdb2-binding 0.2.0.0 → 0.3.0.0

raw patch · 13 files changed

+169/−177 lines, 13 filesdep +mtlPVP ok

version bump matches the API change (PVP)

Dependencies added: mtl

API changes (from Hackage documentation)

- Database.EJDB2.Query: data Query
- Database.EJDB2.Query: fromString :: String -> IO Query
- Database.EJDB2.Query: setBool :: Bool -> String -> Query -> IO ()
- Database.EJDB2.Query: setBoolAtIndex :: Bool -> Int -> Query -> IO ()
- Database.EJDB2.Query: setF64 :: Double -> String -> Query -> IO ()
- Database.EJDB2.Query: setF64AtIndex :: Double -> Int -> Query -> IO ()
- Database.EJDB2.Query: setI64 :: Int64 -> String -> Query -> IO ()
- Database.EJDB2.Query: setI64AtIndex :: Int64 -> Int -> Query -> IO ()
- Database.EJDB2.Query: setNull :: String -> Query -> IO ()
- Database.EJDB2.Query: setNullAtIndex :: Int -> Query -> IO ()
- Database.EJDB2.Query: setRegex :: String -> String -> Query -> IO ()
- Database.EJDB2.Query: setRegexAtIndex :: String -> Int -> Query -> IO ()
- Database.EJDB2.Query: setString :: String -> String -> Query -> IO ()
- Database.EJDB2.Query: setStringAtIndex :: String -> Int -> Query -> IO ()
+ Database.EJDB2: Query :: String -> BindM a -> Query a
+ Database.EJDB2: data Query a
+ Database.EJDB2: noBind :: BindM ()
+ Database.EJDB2: setBool :: Bool -> String -> BindM ()
+ Database.EJDB2: setBoolAtIndex :: Bool -> Int -> BindM ()
+ Database.EJDB2: setF64 :: Double -> String -> BindM ()
+ Database.EJDB2: setF64AtIndex :: Double -> Int -> BindM ()
+ Database.EJDB2: setI64 :: Int64 -> String -> BindM ()
+ Database.EJDB2: setI64AtIndex :: Int64 -> Int -> BindM ()
+ Database.EJDB2: setNull :: String -> BindM ()
+ Database.EJDB2: setNullAtIndex :: Int -> BindM ()
+ Database.EJDB2: setRegex :: String -> String -> BindM ()
+ Database.EJDB2: setRegexAtIndex :: String -> Int -> BindM ()
+ Database.EJDB2: setString :: String -> String -> BindM ()
+ Database.EJDB2: setStringAtIndex :: String -> Int -> BindM ()
- Database.EJDB2: fold :: FromJSON b => Database -> (a -> (Int64, Maybe b) -> a) -> a -> Query -> IO a
+ Database.EJDB2: fold :: FromJSON b => Database -> (a -> (Int64, Maybe b) -> a) -> a -> Query q -> IO a
- Database.EJDB2: getCount :: Database -> Query -> IO Int64
+ Database.EJDB2: getCount :: Database -> Query q -> IO Int64
- Database.EJDB2: getList :: FromJSON a => Database -> Query -> IO [(Int64, Maybe a)]
+ Database.EJDB2: getList :: FromJSON a => Database -> Query q -> IO [(Int64, Maybe a)]
- Database.EJDB2: getList' :: FromJSON a => Database -> Query -> IO [Maybe a]
+ Database.EJDB2: getList' :: FromJSON a => Database -> Query q -> IO [Maybe a]

Files

CHANGELOG.md view
@@ -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
− cbits/finalizer.c
@@ -1,8 +0,0 @@-#include "finalizer.h"-#include <stdlib.h>--void finalizerJQL(JQL* jql) {-  JQL* jqlCopy = jql;-  jql_destroy(jql);-  free(jqlCopy);-}
− cbits/finalizer.h
@@ -1,3 +0,0 @@-#include <ejdb2/ejdb2.h>--void finalizerJQL(JQL* jql);
ejdb2-binding.cabal view
@@ -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 
src/Database/EJDB2.hs view
@@ -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'
src/Database/EJDB2/Bindings/JQL.hs view
@@ -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 ())
src/Database/EJDB2/HTTP.hsc view
@@ -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
src/Database/EJDB2/Query.hs view
@@ -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
− src/Database/EJDB2/QueryConstructor.hs
@@ -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]-                   }
test/CollectionTests.hs view
@@ -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
test/FoldTests.hs view
@@ -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) 
test/GetTests.hs view
@@ -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 @?= []
test/QueryTests.hs view
@@ -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