module Database.Persist.Zookeeper.Query
where
import Database.Persist
import Data.Monoid
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans.Reader
import qualified Data.Text as T
import qualified Database.Zookeeper as Z
import Database.Persist.Zookeeper.Internal
import Database.Persist.Zookeeper.Store
import Database.Persist.Zookeeper.ZooUtil
import Data.Conduit
import qualified Data.Conduit.List as CL
import Data.Acquire
instance PersistQuery Z.Zookeeper where
updateWhere filterList valList = do
stat <- ask
srcRes <- selectKeysRes filterList []
liftIO $ with srcRes ( $$ loop stat)
where
loop stat = do
key <- await
case key of
Just key' -> do
liftIO $ flip runReaderT stat $ update key' valList
loop stat
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
selectSourceRes filterList [] = do
stat <- ask
(str::[String]) <- liftIO $ flip runReaderT stat $ execZookeeperT $ \zk -> do
Z.getChildren zk (filter2path filterList) Nothing
return $ return $ loop stat str
where
loop _ [] = return ()
loop stat (x:xs) = do
let key = txtToKey $ T.pack $ (filter2path filterList) <> "/" <> x
va <- liftIO $ flip runReaderT stat $ 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 stat xs
selectSourceRes _ _ = error "not supported selectOpt"
selectFirst filterList [] = do
srcRes <- selectSourceRes filterList []
liftIO $ with srcRes ( $$ CL.head)
selectFirst _ _ = error "not supported selectOpt"
selectKeysRes filterList [] = do
stat <- ask
(str::[String]) <- liftIO $ flip runReaderT stat $ execZookeeperT $ \zk ->
Z.getChildren zk (filter2path filterList) Nothing
return $ return (loop stat str)
where
loop _ [] = return ()
loop stat (x:xs) = do
let key = txtToKey $ T.pack $ (filter2path filterList) <> "/" <> x
va <- liftIO $ flip runReaderT stat $ get key
case va of
Nothing -> return ()
Just v -> do
let (chk,_,_) = filterClause v filterList
if chk
then yield key
else return ()
loop stat xs
selectKeysRes _ _ = 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
-> 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