packages feed

ejdb2-binding 0.1.0.0 → 0.2.0.0

raw patch · 6 files changed

+106/−43 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Database.EJDB2: fold :: FromJSON b => Database -> (a -> (Int64, Maybe b) -> a) -> a -> Query -> IO a

Files

CHANGELOG.md view
@@ -0,0 +1,8 @@+# Changelog+All notable changes to this project will be documented in this file.++The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),++## [0.2.0.0] - 2020-04-19+### Added+- fold function to reduce a query result
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.1.0.0+version:             0.2.0.0 license:             MIT license-file:        LICENSE homepage:            https://github.com/cescobaz/ejdb2haskell#readme@@ -69,6 +69,7 @@                        CollectionTests                        IndexTests                        OnlineBackupTests+                       FoldTests   build-depends:       base ^>=4.12.0.0                      , tasty ^>=1.2.3                      , tasty-hunit ^>=0.10.0.2
src/Database/EJDB2.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ module Database.EJDB2     ( init     , Database@@ -28,6 +30,7 @@     , ensureIndex     , removeIndex     , onlineBackup+    , fold     ) where  import           Control.Exception@@ -35,6 +38,7 @@  import qualified Data.Aeson                             as Aeson import qualified Data.ByteString                        as BS+import qualified Data.HashMap.Strict                    as Map import           Data.IORef import           Data.Int import           Data.Word@@ -129,42 +133,68 @@     \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)++-- | Iterate over query result building the result+fold :: Aeson.FromJSON b+     => Database+     -> (a+         -> (Int64, Maybe b)+         -> a) -- ^ The second argument is a tuple with the object id and the object+     -> a -- ^ Initial result+     -> Query+     -> IO a+fold database f i query = newIORef (f, i) >>= \ref ->+    exec (foldVisitor ref) database query >> snd <$> readIORef ref++foldVisitor :: Aeson.FromJSON b+            => IORef ((a -> (Int64, Maybe b) -> a), a)+            -> EJDBExecVisitor+foldVisitor ref _ docPtr _ = do+    doc <- peek docPtr+    value <- decode (raw doc)+    let id = fromIntegral $ EJDBDoc.id doc+    modifyIORef' ref $ \(f, partial) -> (f, f partial (id, value))+    return 0+ {-|   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 = exec Database.EJDB2.visitor+getList database query = reverse <$> fold database foldList [] query -visitor :: Aeson.FromJSON a => IORef [(Int64, Maybe a)] -> EJDBExecVisitor-visitor ref _ docPtr _ = do-    doc <- peek docPtr-    value <- decode (raw doc)-    modifyIORef' ref $ \list -> (fromIntegral $ EJDBDoc.id doc, value) : list-    return 0+foldList :: Aeson.FromJSON a+         => [(Int64, Maybe a)]+         -> (Int64, Maybe a)+         -> [(Int64, Maybe a)]+foldList = flip (:)  {-|   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' = exec Database.EJDB2.visitor'+getList' database query = reverse <$> fold database foldList' [] query -visitor' :: Aeson.FromJSON a => IORef [Maybe a] -> EJDBExecVisitor-visitor' ref _ docPtr _ = do-    doc <- peek docPtr-    value <- decode' (raw doc) (fromIntegral $ EJDBDoc.id doc)-    modifyIORef' ref $ \list -> value : list-    return 0+foldList'+    :: Aeson.FromJSON a => [Maybe a] -> (Int64, Maybe Aeson.Value) -> [Maybe a]+foldList' list (id, value) = parse (setId id value) : list -exec :: (IORef [a] -> EJDBExecVisitor) -> Database -> Query -> IO [a]-exec visitor (Database _ ejdb) (Query jql _ _) = do-    ref <- newIORef []-    visitor <- mkEJDBExecVisitor (visitor ref)-    let exec = EJDBExec.zero { db = ejdb, q = jql, EJDBExec.visitor = visitor }-    finally (with exec $ \execPtr -> do-                 c_ejdb_exec execPtr >>= checkRC-                 reverse <$> readIORef ref)-            (freeHaskellFunPtr visitor)+parse :: Aeson.FromJSON a => Maybe Aeson.Value -> Maybe a+parse Nothing = Nothing+parse (Just value) = case Aeson.fromJSON value of+    Aeson.Success v -> Just v+    Aeson.Error _ -> Nothing +setId :: Int64 -> Maybe Aeson.Value -> Maybe Aeson.Value+setId id (Just (Aeson.Object map)) =+    Just (Aeson.Object (Map.insert "id" (Aeson.Number $ fromIntegral id) map))+setId _ Nothing = Nothing+setId _ value = value+ {-|   Save new document into collection under new generated identifier. -}@@ -321,3 +351,4 @@ onlineBackup (Database _ ejdb) filePath = withCString filePath $ \cFilePath ->     alloca $ \timestampPtr -> c_ejdb_online_backup ejdb timestampPtr cFilePath     >>= checkRC >> peek timestampPtr >>= \(CUIntMax t) -> return t+
src/Database/EJDB2/JBL.hs view
@@ -1,13 +1,10 @@-{-# LANGUAGE OverloadedStrings #-}--module Database.EJDB2.JBL ( decode, decode', encode, encodeToByteString ) where+module Database.EJDB2.JBL ( decode, encode, encodeToByteString ) where  import           Control.Exception  import qualified Data.Aeson                  as Aeson import qualified Data.ByteString             as BS import qualified Data.ByteString.Lazy        as BSL-import qualified Data.HashMap.Strict         as Map import           Data.IORef import           Data.Int @@ -21,9 +18,6 @@ decode :: Aeson.FromJSON a => JBL -> IO (Maybe a) decode jbl = Aeson.decode <$> decodeToByteString jbl -decode' :: Aeson.FromJSON a => JBL -> Int64 -> IO (Maybe a)-decode' jbl id = parse . setId id <$> decode jbl- decodeToByteString :: JBL -> IO BSL.ByteString decodeToByteString jbl = do     ref <- newIORef BSL.empty@@ -31,18 +25,6 @@     c_jbl_as_json jbl thePrinter nullPtr 0         >>= Result.checkRCFinally (freeHaskellFunPtr thePrinter)     BSL.reverse <$> readIORef ref--parse :: Aeson.FromJSON a => Maybe Aeson.Value -> Maybe a-parse Nothing = Nothing-parse (Just value) = case Aeson.fromJSON value of-    Aeson.Success v -> Just v-    Aeson.Error _ -> Nothing--setId :: Int64 -> Maybe Aeson.Value -> Maybe Aeson.Value-setId id (Just (Aeson.Object map)) =-    Just (Aeson.Object (Map.insert "id" (Aeson.Number $ fromIntegral id) map))-setId _ Nothing = Nothing-setId _ value = value  printer :: IORef BSL.ByteString -> JBLJSONPrinter printer ref _ 0 (CChar ch) _ _ = do
+ test/FoldTests.hs view
@@ -0,0 +1,38 @@+module FoldTests where++import           Data.Int++import qualified Database.EJDB2         as DB+import           Database.EJDB2.Options+import qualified Database.EJDB2.Query   as Query++import           Plant++import           Prelude                hiding ( id )++import           Test.Tasty+import           Test.Tasty.HUnit++tests :: TestTree+tests = withResource (DB.open testReadOnlyDatabaseOpts) DB.close $+    \databaseIO -> testGroup "get" [ foldOnIsTreeTest databaseIO ]++testReadOnlyDatabaseOpts :: Options+testReadOnlyDatabaseOpts =+    DB.minimalOptions "./test/read-only-db" [ DB.readonlyOpenFlags ]++foldOnIsTreeTest :: IO DB.Database -> TestTree+foldOnIsTreeTest databaseIO = testCase "foldOnIsTree" $ do+    database <- databaseIO+    query <- Query.fromString "@plants/*"+    result <- DB.fold database foldOnIsTree (0, 0) query+    result @?= (1, 3)++foldOnIsTree :: (Int, Int) -> (Int64, Maybe Plant) -> (Int, Int)+foldOnIsTree acc (_, Nothing) = acc+foldOnIsTree acc@(trueCount, falseCount) (_, Just plant) =+    maybe acc+          (\flag -> if flag+                    then (trueCount + 1, falseCount)+                    else (trueCount, falseCount + 1))+          (isTree plant)
test/Main.hs view
@@ -6,6 +6,8 @@  import           DeleteTests +import           FoldTests+ import           GetTests  import           IndexTests@@ -32,4 +34,5 @@                   , CollectionTests.tests                   , IndexTests.tests                   , OnlineBackupTests.tests+                  , FoldTests.tests                   ]