packages feed

persistent-zookeeper-0.1.0: Database/Persist/Zookeeper/Internal.hs

{-# LANGUAGE OverloadedStrings #-}
module Database.Persist.Zookeeper.Internal
       where
  
import Control.Monad.IO.Class (MonadIO (..))
import Data.Monoid
import Data.Maybe
import qualified Data.Aeson as A
import qualified Data.Text as T
import Database.Persist.Types
import Database.Persist.Class
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.ByteString.Base64.URL as B64
import qualified Data.Map as M


txtToKey :: (PersistEntity val) => T.Text -> Key val
txtToKey txt = 
  case (keyFromValues [PersistText txt]) of
    Right v -> v
    Left v -> error $ T.unpack v

keyToTxt :: (PersistEntity val) => Key val -> T.Text
--keyToTxt (Key (PersistText key)) = key
keyToTxt key = 
  case keyToValues key of
    [PersistText txt] -> txt
    _ -> error "keyToTxt"
--keyToTxt v = error $ "do not support "++show v

dummyFromKey :: Key v -> Maybe v
dummyFromKey _ = Nothing

dummyFromFList :: [Filter v] -> v
dummyFromFList _ = error "huga"

dummyFromUnique :: Unique v -> Maybe v
dummyFromUnique _ = Nothing

val2table :: (PersistEntity val) => val -> T.Text
val2table = unDBName . entityDB . entityDef . Just

val2uniqkey :: (MonadIO m, PersistEntity val) => val -> m (Maybe (Unique val))
val2uniqkey val = do
  case persistUniqueKeys val of
    (uniqkey:_) -> return $ Just uniqkey
    [] -> return Nothing

uniqkey2key :: (PersistEntity val) => Unique val -> Key val
uniqkey2key uniqkey =
  let dir = entity2path $ fromJust $ dummyFromUnique uniqkey
    in txtToKey $ T.pack $ dir <> "/" <>  (B.unpack $ B64.encode $ BL.toStrict $ A.encode $ persistUniqueToValues uniqkey)

entity2bin :: (PersistEntity val) => val -> B.ByteString
entity2bin val = BL.toStrict (A.encode (map toPersistValue (toPersistFields val)))

kv2v :: [PersistValue] -> [PersistValue]
kv2v [] = []
kv2v ((PersistList [_k,v] ):xs) = v:kv2v xs
kv2v (x:xs) = x:kv2v xs

bin2entity :: (PersistEntity val) => B.ByteString -> Maybe val
bin2entity bin =
  case A.decode (BL.fromStrict bin) :: Maybe [PersistValue]of
    Nothing -> Nothing
    Just v ->
      case fromPersistValues (kv2v v) of
        Right body  -> Just $ body
        Left s -> error $ T.unpack s
  

entity2path :: (PersistEntity val) => val -> String
entity2path val = "/" <> (T.unpack $ val2table val)

-- entityAndKey2path :: (PersistEntity val) => val -> Key val -> String
-- entityAndKey2path val (Key (PersistText txt)) = entity2path val <> "/" <>  ( B.unpack $ B64.encode $ B.pack $ T.unpack txt)
-- entityAndKey2path _ _ = error "key is not persist text"

-- key2path :: (PersistEntity val) => Key val -> String
-- key2path key = entityAndKey2path (fromJust (dummyFromKey key)) key



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"