tripLL-0.1.0.0: src/TripLL/Bindings/LevelDBHexa.hs
{-# LANGUAGE TypeSynonymInstances
, OverloadedStrings
, MultiParamTypeClasses
, FlexibleInstances #-}
{-|
Module : TripLL.Bindings.LevelDBHexa
Description : An implementation for the tripLL interface.
Copyright : (c) Philipp Pfeiffer, 2015
License : MIT
Maintainer : pfiff@hax-f.net
Stability : experimental
Portability : POSIX
Gives an implementation for the tripLL interface based upon the `LevelDB` database.
-}
module TripLL.Bindings.LevelDBHexa (
-- * Base Types
LevelDBHexa (..),
-- Re-Exports:
module TripLL
) where
---- LevelDB: ----
import qualified Database.LevelDB.Base as LDB
import qualified Database.LevelDB.Streaming as S
import qualified Database.LevelDB.Internal as LDBI
---- Intern: ----
import TripLL
---- Data: ----
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LS
import qualified Data.Serialize as BIN
import Data.Either (rights)
---- Control: ----
import Control.Applicative
import Control.Monad
-------------
-- Base Types
-------------
-- | The main handle of this implementation, 'LevelDBHexa'.
type LevelDBHexa = LDB.DB
type ByTriple = Triple BS.ByteString
type QueryByTriple = QueryTriple BS.ByteString
-------------------
-- Encoding:
-------------------
instance BIN.Serialize ByTriple where
put (Triple s p o) = BIN.put (s,p,o)
get = fmap (\(s,p,o) -> Triple s p o) BIN.get
----------------
-- Intern Misc
----------------
tupleKey :: BS.ByteString -> BS.ByteString -> BS.ByteString -> BS.ByteString -> BS.ByteString
tupleKey i v1 v2 v3 = i
`BS.append` "::"
`BS.append` v1
`BS.append` "::"
`BS.append` v2
`BS.append` "::"
`BS.append` v3
queryOpener :: Maybe BS.ByteString -> Maybe BS.ByteString -> Maybe BS.ByteString -> BS.ByteString
queryOpener Nothing Nothing Nothing = "spo::"
queryOpener (Just s) Nothing Nothing = "spo::" `BS.append` s
queryOpener Nothing (Just p) Nothing = "pso::" `BS.append` p
queryOpener Nothing Nothing (Just o) = "ops::" `BS.append` o
queryOpener (Just s) (Just p) Nothing = "spo::" `BS.append` s `BS.append` "::" `BS.append` p
queryOpener (Just s) Nothing (Just o) = "osp::" `BS.append` o `BS.append` "::" `BS.append` s
queryOpener Nothing (Just p) (Just o) = "ops::" `BS.append` o `BS.append` "::" `BS.append` p
queryOpener (Just s) (Just p) (Just o) = "spo::" `BS.append` s `BS.append` "::" `BS.append` p `BS.append` "::" `BS.append` o
---------------------
-- Hexastore Instance
---------------------
instance Triplestore LevelDBHexa BS.ByteString where
-------------------
-- PUT into
-------------------
put (Triple s p o) db = let
encodedTrip = BIN.encode (Triple s p o)
in
LDB.write db LDB.defaultWriteOptions
[ LDB.Put (tupleKey "spo" s p o) encodedTrip
--, LDB.Put (tupleKey "sop" s o p) encodedTrip
, LDB.Put (tupleKey "pso" p s o) encodedTrip
--, LDB.Put (tupleKey "pos" p o s) encodedTrip
, LDB.Put (tupleKey "osp" o s p) encodedTrip
, LDB.Put (tupleKey "ops" o p s) encodedTrip ]
-------------------
-- DELETE
-------------------
del (Triple s p o) db = LDB.write db LDB.defaultWriteOptions
[ LDB.Del (tupleKey "spo" s p o)
--, LDB.Del (tupleKey "sop" s o p)
, LDB.Del (tupleKey "pso" p s o)
--, LDB.Del (tupleKey "pos" p o s)
, LDB.Del (tupleKey "osp" o s p)
, LDB.Del (tupleKey "ops" o p s) ]
-----------------------
-- BATCH operations
-----------------------
batch [] _ = return ()
batch (Put t:xs) db = do { TripLL.put t db; batch xs db }
batch (Delete t:xs) db = do { TripLL.del t db; batch xs db }
----------------------
-- QUERY
----------------------
query (Triple s p o) db =
let
op = queryOpener s p o
in
LDB.withIter db LDB.defaultReadOptions $ \iter ->
do
entries <- S.toList $ S.entrySlice iter
(S.KeyRange
op
(\bs -> compare bs (op `BS.append` "\xff")))
S.Asc
return $ rights (fmap (BIN.decode . snd) entries)
--------------------------
-- WITHHEXA bracket
--------------------------
withTrip path = LDB.withDB path (LDB.defaultOptions { LDB.createIfMissing = False, LDB.errorIfExists = False })
-------------------------
-- CREATE
-------------------------
createAndOpen path = LDB.open path (LDB.defaultOptions { LDB.createIfMissing = True, LDB.errorIfExists = True })
open path = LDB.open path (LDB.defaultOptions { LDB.createIfMissing = False, LDB.errorIfExists = False})
close = LDBI.unsafeClose