packages feed

tripLL (empty) → 0.1.0.0

raw patch · 6 files changed

+307/−0 lines, 6 filesdep +basedep +bytestringdep +cerealsetup-changed

Dependencies added: base, bytestring, cereal, filepath, leveldb-haskell

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 Philipp Pfeiffer++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,35 @@+# tripLL++## Introduction++`tripLL` is a very simple triple store, written in Haskell. It provides a basic interface to write, delete and query triples -- in fact, that's it. On top, there are some bindings to realizations of triple stores, such that this tiny library can be used out of box.++Right now it is thought that exactly one binding is imported within a project and only this binding (since it re-exports the interface).++## A simple example++```{.Haskell}+{-# LANGUAGE OverloadedStrings #-}++{- This examples uses the leveldb realization. This means that triples become triples of strict bytestrings and the leveldb lib has to be installed. -}++import TripLL.Bindings.LevelDBHexa++main = do -- open the database:+          handle <- createAndOpen "data/store.tripdb" :: IO LevelDBHexa+          -- batch something into it:+          batch [ Put (Triple "Frenzy" "likes" "Jealousy")+                , Put (Triple "Hate" "loves" "Hatred")+                , Put (Triple "Frenzy" "likes" "Hate")]+                handle+          -- querying the database:+          res <- query (Triple (Just "Frenzy") Nothing Nothing) handle+          -- now, `res :: [Triple Strict.ByteString]`, do something with it...+          -- ...+          -- and clean up:+          close handle+```++## Contributions++The LevelDB Binding is based upon (http://nodejsconfit.levelgraph.io/), which is based upon the idea to build up a hexastore. Freely interpreted.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/TripLL.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE OverloadedStrings, MultiParamTypeClasses, FunctionalDependencies #-}+{-|+Module      : TripLL+Description : The tripLL interface.+Copyright   : (c) Philipp Pfeiffer, 2015+License     : MIT+Maintainer  : pfiff@hax-f.net+Stability   : experimental+Portability : POSIX++Gives a basic interface to a triple store. See homepage for an example.+-}+module TripLL (+  -- * Base Types for Accesing and Querying+  Triplestore (..),+  Triple (..),+  TriplePosition (..),+  flatten,+  QueryTriple (..),+  BatchAction (..)+) where++----- System: -----+import System.FilePath++-- | The 'Triplestore' typeclass is an interface for triple stores. Every backend of this library uses this interface.+class Triplestore h b | h -> b where+  -- | most simple actions, a triple store has to support, 'put' and 'del' of triples:+  put      :: Triple b -> h -> IO ()+  del      :: Triple b -> h -> IO ()+  -- | doing several simple actions in one go, one can use 'batch'.+  batch    :: [BatchAction b] -> h -> IO ()+  -- | querying triples is done by filling in the known fields with 'Just x'.+  query    :: QueryTriple b -> h -> IO [Triple b]+  -- bracket:+  withTrip :: FilePath -> (h -> IO a) -> IO a+  -- system:+  createAndOpen :: FilePath -> IO h+  open          :: FilePath -> IO h+  close         :: h ->  IO ()+++-- | 'TriplePosition' gives a type for the fields within a 'Triple'.+data TriplePosition = Subject | Predicate | Object deriving (Eq, Show)++-- | A 'Triple' is just anything consisting of three ordered pieces.+data Triple a = Triple { subject :: a+                       , predicate :: a+                       , object :: a }++-- | 'QueryTriple' is a shorthand for 'Triple' where the argument is encapsulated within a 'Maybe'.+type QueryTriple a = Triple (Maybe a)+++-- | With 'within' one can query accessor invariant the different elements of a triple. Meant to be used in infix: @Subject `within` (Triple "s" "p" "o") == "s"@.+within :: TriplePosition -> Triple a -> a+within Subject = subject+within Predicate = predicate+within Object = object++-- | 'into' can be used as a annotated setter.+into :: Triple a -> TriplePosition -> a -> Triple a+into t Subject x = t { subject = x }+into t Predicate x = t { predicate = x }+into t Object x = t { object = x }++-- | 'flatten' forgets about the description of the fields.+flatten :: Triple a -> (a, a, a)+flatten (Triple s p o) = (s,p,o)++-- | A 'BatchAction' is either a 'Put' or a 'Delete', i.e. either a `write given triple into database` or a `delete given triple from database`.+data BatchAction a = Put (Triple a) | Delete (Triple a)
+ src/TripLL/Bindings/LevelDBHexa.hs view
@@ -0,0 +1,144 @@+{-# 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
+ tripLL.cabal view
@@ -0,0 +1,34 @@+-- Initial tripLL.cabal generated by cabal init.  For further+-- documentation, see http://haskell.org/cabal/users-guide/++name:                tripLL+version:             0.1.0.0+synopsis:            A very simple triple store+-- description:+homepage:            https://github.com/aphorisme/tripLL+license:             MIT+license-file:        LICENSE+author:              Philipp Pfeiffer+maintainer:          pfiff@hax-f.net+-- copyright:+category:            Database+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++library+  exposed-modules:      TripLL+                      , TripLL.Bindings.LevelDBHexa+  -- other-modules:+  other-extensions:      OverloadedStrings+                       , MultiParamTypeClasses+                       , FunctionalDependencies+                       , TypeSynonymInstances+                       , FlexibleInstances+  build-depends:         base >=4.8 && <4.9+                       , filepath >=1.4 && <1.5+                       , bytestring >=0.10 && <0.11+                       , cereal >= 0.4+                       , leveldb-haskell >= 0.6+  hs-source-dirs:      src+  default-language:    Haskell2010