packages feed

persistent-zookeeper 0.0.2 → 0.0.3

raw patch · 5 files changed

+285/−5 lines, 5 filesdep +conduitdep +containersdep +transformers-basePVP ok

version bump matches the API change (PVP)

Dependencies added: conduit, containers, transformers-base

API changes (from Hackage documentation)

+ Database.Persist.Zookeeper: OrNullNo :: OrNull
+ Database.Persist.Zookeeper: OrNullYes :: OrNull
+ Database.Persist.Zookeeper: data OrNull
+ Database.Persist.Zookeeper: dummyFromFilts :: [Filter v] -> Maybe v
+ Database.Persist.Zookeeper: fieldval :: (PersistEntity val, PersistField typ) => EntityField val typ -> val -> PersistValue
+ Database.Persist.Zookeeper: filter2path :: PersistEntity val => [Filter val] -> String
+ Database.Persist.Zookeeper: filterClause :: PersistEntity val => val -> [Filter val] -> (Bool, Text, [PersistValue])
+ Database.Persist.Zookeeper: filterClauseHelper :: PersistEntity val => Bool -> OrNull -> val -> [Filter val] -> (Bool, Text, [PersistValue])
+ Database.Persist.Zookeeper: getFieldName :: (PersistEntity val, PersistField typ) => EntityField val typ -> Text
+ Database.Persist.Zookeeper: getFieldsName :: PersistEntity val => val -> [Text]
+ Database.Persist.Zookeeper: getList :: PersistEntity val => val -> [(Text, PersistValue)]
+ Database.Persist.Zookeeper: getMap :: PersistEntity val => val -> Map Text PersistValue
+ Database.Persist.Zookeeper: updateEntity :: PersistEntity val => val -> [Update val] -> Either Text val
+ Database.Persist.Zookeeper: updateVal :: PersistEntity val => PersistValue -> Update val -> PersistValue
+ Database.Persist.Zookeeper: updateVals :: PersistEntity val => [(Text, PersistValue)] -> Update val -> [(Text, PersistValue)]

Files

Database/Persist/Zookeeper.hs view
@@ -2,10 +2,12 @@     ( module Database.Persist.Zookeeper.Config     , module Database.Persist.Zookeeper.Store     , module Database.Persist.Zookeeper.Unique+    , module Database.Persist.Zookeeper.Query     , module Database.Persist.Zookeeper.PathPiece     ) where  import Database.Persist.Zookeeper.Config import Database.Persist.Zookeeper.Store import Database.Persist.Zookeeper.Unique()+import Database.Persist.Zookeeper.Query import Database.Persist.Zookeeper.PathPiece()
Database/Persist/Zookeeper/Internal.hs view
@@ -24,6 +24,9 @@ dummyFromKey :: Key v -> Maybe v dummyFromKey _ = Nothing +dummyFromFList :: [Filter v] -> v+dummyFromFList _ = error "huga"+ dummyFromUnique :: Unique v -> Maybe v dummyFromUnique _ = Nothing @@ -43,7 +46,6 @@  entity2bin :: (PersistEntity val) => val -> B.ByteString entity2bin val = BL.toStrict (A.encode (map toPersistValue (toPersistFields val)))-  kv2v :: [PersistValue] -> [PersistValue] kv2v [] = []
+ Database/Persist/Zookeeper/Query.hs view
@@ -0,0 +1,228 @@+{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Database.Persist.Zookeeper.Query+       where++import Database.Persist+import Data.Monoid+import Control.Applicative+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Trans.Control (MonadBaseControl)+import Control.Monad.Trans.Class+import qualified Data.Text as T+import qualified Database.Zookeeper as Z+import Database.Persist.Zookeeper.Config+import Database.Persist.Zookeeper.Internal+import Database.Persist.Zookeeper.Store+import qualified Data.Map as M+import Data.Conduit++filter2path :: (PersistEntity val) => [Filter val] -> String +filter2path filterList = entity2path $ dummyFromFList filterList++getMap :: PersistEntity val => val -> M.Map T.Text PersistValue+getMap val =  M.fromList $ getList val+getList :: PersistEntity val => val -> [(T.Text,PersistValue)]+getList val =  +  let fields = fmap toPersistValue (toPersistFields val)+      in zip (getFieldsName val) fields+getFieldsName :: (PersistEntity val) => val -> [T.Text]+getFieldsName val =  fmap (unDBName.fieldDB) $ entityFields $ entityDef $ Just val+getFieldName :: (PersistEntity val,PersistField typ) => EntityField val typ -> T.Text+getFieldName field =  unDBName $ fieldDB $ persistFieldDef $ field+fieldval :: (PersistEntity val,PersistField typ) => EntityField val typ -> val -> PersistValue+fieldval field val =  (getMap val) M.! (getFieldName field)+++updateEntity :: PersistEntity val =>  val -> [Update val] -> Either T.Text val+updateEntity val upds = +  fromPersistValues $ map snd $ foldl updateVals (getList val) upds+++updateVals :: PersistEntity val =>  [(T.Text,PersistValue)] -> Update val -> [(T.Text,PersistValue)]+updateVals [] _ = []+updateVals ((k,v):xs) u@(Update field _ _) = +  if getFieldName field == k+    then (k,updateVal v u):xs+    else (k,v):updateVals xs u+updateVals _ _ = error "not supported"++updateVal :: PersistEntity val =>  PersistValue -> Update val -> PersistValue+updateVal _v (Update _ val upd) = +  case upd of+    Assign -> toPersistValue val+    _ -> error "not support"+    -- Add -> (+) <$> v <$> toPersistValue val +    -- Subtract -> v - toPersistValue val +    -- Multiply -> v * toPersistValue val +    -- Divide -> v `div` toPersistValue val +updateVal _v _ = error "not supported"+++instance (Applicative m, Functor m, MonadIO m, MonadBaseControl IO m) => PersistQuery (ZookeeperT m) where+  update key valList = do+    va <- get key+    case va of+      Nothing -> return ()+      Just v ->+        case updateEntity v valList of+          Right v' -> +            replace key v'+          Left v' -> error $ show v'+  updateWhere filterList valList = do+    (selectKeys filterList []) $$ loop+    where+      loop = do+        key <- await+        case key of+          Just key' -> do+            lift $ update key' valList+            loop+          Nothing ->+            return ()+  deleteWhere filterList = do+    (str::[String]) <- execZookeeperT $ \zk -> do+      Z.getChildren zk (filter2path filterList) Nothing+    loop str+    where+      loop [] = return ()+      loop (x:xs) = do+        let key = txtToKey $ T.pack $ (filter2path filterList) <> "/" <> x+        va <- get key+        case va of+          Nothing -> return ()+          Just v -> do+            let (chk,_,_) = filterClause v filterList +            if chk+              then delete key+              else return ()+        loop xs+  selectSource filterList [] = do+    (str::[String]) <- lift $ execZookeeperT $ \zk -> do+      Z.getChildren zk (filter2path filterList) Nothing+    loop str+    where+      loop [] = return ()+      loop (x:xs) = do+        let key = txtToKey $ T.pack $ (filter2path filterList) <> "/" <> x+        va <- get key+        case va of+          Nothing -> return ()+          Just v -> do+            let (chk,_,_) = filterClause v filterList +            if chk+              then yield $ Entity key v+              else return ()+        loop xs+  selectSource _ _ = error "not supported selectOpt"+  selectFirst filterList selectOpts =  do+    (selectSource filterList selectOpts) $$ do+      val <- await+      case val of+        Just val' -> return $ Just val'+        Nothing -> return Nothing+  selectKeys filterList [] = do +    (str::[String]) <- lift $ execZookeeperT $ \zk -> +      Z.getChildren zk (filter2path filterList) Nothing+    loop str+    where+      loop [] = return ()+      loop (x:xs) = do+        let key = txtToKey $ T.pack $ (filter2path filterList) <> "/" <> x+        va <- get key+        case va of+          Nothing -> return ()+          Just v -> do+            let (chk,_,_) = filterClause v filterList +            if chk+              then yield key+              else return ()+        loop xs+  selectKeys  _ _ = error "not supported selectOpt"+  count filterList = do+    v <- selectList filterList []+    return $ length v++  +dummyFromFilts :: [Filter v] -> Maybe v+dummyFromFilts _ = Nothing++data OrNull = OrNullYes | OrNullNo+++filterClauseHelper :: PersistEntity val+             => Bool -- ^ include WHERE?+             -> OrNull+             -> val+             -> [Filter val]+             -> (Bool, T.Text, [PersistValue])+filterClauseHelper includeWhere orNull val filters =+    (bool, if not (T.null sql) && includeWhere+            then " WHERE " <> sql+            else sql, vals)+  where+    (bool, sql, vals) = combineAND filters+    combineAND = combine " AND " (&&)+    combineOR = combine " OR " (||)++    combine s op fs =+        (foldr1 op c ,T.intercalate s $ map wrapP a, mconcat b)+      where+        (c, a, b) = unzip3 $ map go fs+        wrapP x = T.concat ["(", x, ")"]+    go (BackendFilter _) = error "BackendFilter not expected"+    go (FilterAnd []) = (True,"1=1", [])+    go (FilterAnd fs) = combineAND fs+    go (FilterOr []) = (True,"1=0", [])+    go (FilterOr fs)  = combineOR fs+    go (Filter field value pfilter) = +      (showSqlFilter' pfilter (fieldval field val) allVals, +      name <> ":"+      <> T.pack (show (fieldval field val)) <> ":" +      <> showSqlFilter pfilter+      <> T.pack (show (showSqlFilter' pfilter (fieldval field val) allVals))+      <> "?5:" <> T.pack (show allVals) <> orNullSuffix, allVals) +      where+        +        filterValueToPersistValues :: forall a.  PersistField a => Either a [a] -> [PersistValue]+        filterValueToPersistValues v = map toPersistValue $ either return id v++        orNullSuffix =+            case orNull of+                OrNullYes -> mconcat [" OR ", name, " IS NULL"]+                OrNullNo -> ""++        allVals = filterValueToPersistValues value+        name = unDBName $ fieldDB $ persistFieldDef field+        showSqlFilter Eq = "="+        showSqlFilter Ne = "<>"+        showSqlFilter Gt = ">"+        showSqlFilter Lt = "<"+        showSqlFilter Ge = ">="+        showSqlFilter Le = "<="+        showSqlFilter In = " IN "+        showSqlFilter NotIn = " NOT IN "+        showSqlFilter (BackendSpecificFilter s) = s+        showSqlFilter' :: PersistFilter -> PersistValue -> [PersistValue] -> Bool+        showSqlFilter' Eq a b = (==) a (head b)+        showSqlFilter' Ne a b = (/=) a (head b)+        showSqlFilter' Gt a b = (>)  a (head b)+        showSqlFilter' Lt a b = (<)  a (head b)+        showSqlFilter' Ge a b = (>=) a (head b)+        showSqlFilter' Le a b = (<=) a (head b)+        showSqlFilter' In _ [] = False+        showSqlFilter' In a (x:xs) = if a==x then True else showSqlFilter' In a xs+        showSqlFilter' NotIn _ [] = True+        showSqlFilter' NotIn a (x:xs) = if a==x then False else showSqlFilter' NotIn a xs+        showSqlFilter' (BackendSpecificFilter _s) _ _ =  error "not supported"+++filterClause :: PersistEntity val+             => val+             -> [Filter val]+             -> (Bool, T.Text, [PersistValue])+filterClause val = filterClauseHelper True OrNullNo val
persistent-zookeeper.cabal view
@@ -1,5 +1,5 @@ name:            persistent-zookeeper-version:         0.0.2+version:         0.0.3 license:         BSD3 license-file:    LICENSE author:          Junji Hashimoto <junji.hashimoto@gree.net>@@ -25,6 +25,7 @@                    , attoparsec                    , mtl                    , transformers+                   , transformers-base                    , monad-control                    , utf8-string           >= 0.3.7    && < 0.4.0                    , binary                >= 0.7      && < 0.8@@ -35,6 +36,8 @@                    , template-haskell                    , base64-bytestring                    , stm+                   , conduit+                   , containers      exposed-modules: Database.Persist.Zookeeper @@ -42,6 +45,7 @@                      Database.Persist.Zookeeper.Internal                      Database.Persist.Zookeeper.Store                      Database.Persist.Zookeeper.Unique+                     Database.Persist.Zookeeper.Query                      Database.Persist.Zookeeper.PathPiece                      Database.Persist.Zookeeper.ZooUtil @@ -55,6 +59,7 @@                    , persistent-template   >= 1.3      && < 1.4                    , mtl                    , transformers+                   , transformers-base                    , utf8-string           >= 0.3.7    && < 0.4.0                    , bytestring            >= 0.10.0.0 && < 0.11.0.0                    , text                  >= 0.8@@ -73,5 +78,8 @@                    , base64-bytestring                    , hspec                    , stm+                   , conduit+                   , containers +--    ghc-options:     -Wall -ddump-splices     ghc-options:     -Wall
tests/basic-test.hs view
@@ -14,6 +14,7 @@ Person     name String     age Int+    hoge Int Maybe     PersonU name     deriving Show     deriving Eq@@ -27,7 +28,7 @@   withZookeeperConn zookeeperConf $ \conn -> do     hspec $ do       let key = (Key (PersistText "/person/WyJzVGVzdC9ob2dlIl0="))-      let val = Person "Test/hoge" 12+      let val = Person "Test/hoge" 12 Nothing       describe "PersistUnique test" $ do         it "insertUnique" $ do           v <- flip runZookeeperPool conn $ do@@ -57,5 +58,44 @@             delete key'             get key'           v' `shouldBe` Nothing-      -      +      describe "PersistQeuery test" $ do+        let check val' filter' expbool = case filterClause val' filter' of+                                           a@(bool,_,_) -> do+                                           print $ show a+                                           bool `shouldBe` expbool+        it "FilterTestEq" $ do+          check (Person "Test/hoge" 12 Nothing) [PersonName ==. ""] False+          check (Person "Test/hoge" 12 (Just 3)) [PersonHoge ==. Just 3] True+          check (Person "Test/hoge" 12 Nothing) [PersonAge ==. 12]  True+        it "FilterTestNe" $ do+          check (Person "Test/hoge" 12 Nothing) [PersonAge !=. 12] False+          check (Person "Test/hoge" 12 Nothing) [PersonAge !=. 11] True+          check (Person "Test/hoge" 12 (Just 4)) [PersonHoge !=. Just 4] False+          check (Person "Test/hoge" 12 Nothing) [PersonHoge !=. Just 3] True+          check (Person "Test/hoge" 12 (Just 4)) [PersonHoge !=. Just 3] True+        it "FilterTestLt" $ do+          check (Person "Test/hoge" 12 (Just 4)) [PersonHoge <=. Just 3] False+          check (Person "Test/hoge" 12 (Just 2)) [PersonHoge <=. Just 3] True+        it "StoreTest" $ do+          va <- flip runZookeeperPool conn $ do+            deleteWhere [PersonName !=. ""]+            _ <- insert (Person "hoge0" 1 Nothing)+            _ <- insert (Person "hoge1" 2 Nothing)+            _ <- insert (Person "hoge2" 3 Nothing)+            _ <- insert (Person "hoge3" 4 Nothing)+            selectList [PersonAge ==. 2] []+          (entityVal (head va)) `shouldBe` (Person "hoge1" 2 Nothing)+          [Entity _k v] <- flip runZookeeperPool conn $ do+            selectList [PersonName ==. "hoge2"] []+          v `shouldBe` (Person "hoge2" 3 Nothing)+          [Entity _k v1] <- flip runZookeeperPool conn $ do+            updateWhere [PersonName ==. "hoge2"] [PersonAge =. 10]+            selectList [PersonName ==. "hoge2"] []+          v1 `shouldBe` (Person "hoge2" 10 Nothing)+          v2 <- flip runZookeeperPool conn $ do+            selectList [PersonName !=. ""] []+          length v2 `shouldBe` 4+          v3 <- flip runZookeeperPool conn $ do+            deleteWhere [PersonName !=. ""]+            selectList [PersonName !=. ""] []+          length v3 `shouldBe` 0