Haskellのデータ型をJSON化しRedisへ入れ込む
JSONまわりのライブラリにどんなものがあるのか調べつつ、Data.Aesonの出来の素晴らしさに感心しながらサンプルコードを書いてみました。
JSON化したデータをhedis(Redisクライアント)でRedisへ入れ込み、さらにみんなのPHPでHaskellのデータ型をPHPのインスタンスとして復元するという、何とも利用価値がない、コードです。
でこれをですね、実行しますとRedisへJSON化されたデータが格納され、その後格納したデータを再度、haskellのデータ型へ戻しています。
{-# LANGUAGE OverloadedStrings, FlexibleContexts #-} import Data.Aeson import Control.Applicative ((<$>),(<*>)) import Control.Monad (mzero) import Control.Monad.IO.Class (liftIO) import qualified Data.ByteString.Internal as I import Data.ByteString.Lazy.Char8 import Data.Text.Encoding import Data.Text import qualified Data.HashMap.Strict as H import Database.Redis -- JSON化する痛風型 data TwoFoose = Nyouichi { code :: Text, name :: Text, popularity :: Integer } | Nyouji { code :: Text, name :: Text, popularity :: Integer } | Unknown deriving(Show, Eq) instance FromJSON TwoFoose where parseJSON (Object val) = case H.lookup "type" val of Just obj -> case obj of "Nyouichi" -> Nyouichi <$> val .: "code" <*> val .: "name" <*> val .: "popularity" "Nyouji" -> Nyouji <$> val .: "code" <*> val .: "name" <*> val .: "popularity" _ -> return Unknown parseJSON _ = mzero instance ToJSON TwoFoose where toJSON (Nyouichi c n p) = object [ "type" .= decodeUtf8 "Nyouichi", "code" .= c, "name" .= n, "popularity" .= p ] toJSON (Nyouji c n p) = object [ "type" .= decodeUtf8 "Nyouji", "code" .= c, "name" .= n, "popularity" .= p ] store :: (ToJSON a, RedisCtx m f) => I.ByteString -> a -> m (f Status) store key v = set key (toStrict $ encode v) storeObj :: RedisCtx m f => TwoFoose -> m (f Status) storeObj v = store (encodeUtf8 (code v)) v loadObj :: RedisCtx m f => I.ByteString -> m (f (Maybe I.ByteString)) loadObj = get convert :: Either t (Maybe I.ByteString) -> Maybe TwoFoose convert (Right (Just bs)) = Data.Aeson.decode (fromStrict bs) convert _ = Nothing selfConnectInfo :: ConnectInfo selfConnectInfo = defaultConnectInfo { connectHost = "localhost", connectPort = PortNumber 6379, connectAuth = Nothing, connectMaxConnections = 100, connectMaxIdleTime = 30 } main :: IO() main = do conn <- connect selfConnectInfo runRedis conn $ do storeObj ichi storeObj ji i <- loadObj "nyou_kouichi" liftIO $ print $ (convert i) j <- loadObj "nyou_sanji" liftIO $ print $ (convert j) u <- loadObj "majika" liftIO $ print $ (convert u) where ichi = Nyouichi "nyou_kouichi" "尿高一" 888888 ji = Nyouji "nyou_sanji" "尿惨二" 99999999
もちろんRedisデーモンは起動しておいてください
cuomo@karky7 ~ $ runhaskell RedisJson.hs Just (Nyouichi {code = "nyou_kouichi", name = "\23615\39640\19968", popularity = 888888}) Just (Nyouji {code = "nyou_sanji", name = "\23615\24808\20108", popularity = 99999999}) Just Unknown cuomo@karky7 ~ $
Redisへ格納されているJSONの確認
cuomo@karky7 ~ $ redis-cli -h localhost redis localhost:6379> KEYS * 1) "nyou_kouichi" 2) "majika" 3) "nyou_sanji" redis localhost:6379> redis 127.0.0.1:6379> get nyou_kouichi "{\"popularity\":888888,\"name\":\"\xe5\xb0\xbf\xe9\xab\x98\xe4\xb8\x80\",\"code\":\"nyou_kouichi\",\"type\":\"Nyouichi\"}" cuomo@karky7 ~ $尿高一さんが入ってますね
JSONをPHPのインスタンスを作成してみる
Redisへ保存されているJSONから、PHPのオブジェクトインスタンスを作成してみる。おれおれオブジェクト指向なのでPHPでは、ご法度的な技法でも突っ込まないでください 笑...
Redisからすべてのキーを取得して、TwoFooseFactoryでオブジェクトへ変換可能ならインスタンスを作成します。PHPからRedisへアクセスするためPHPのRedisクライアントを入れてください、何でもいいですが、私はこれを入れました。
karky7 ~ # emerge dev-php/pecl-redis
<?php /** * 尿酸ズを生成する工場 */ class TwoFooseFactory { protected $classTable; function __construct() { $this->classTable = array( 'Nyouichi' => 1, 'Nyouji' => 1 ); } public function createInstance($json) { $i = json_decode($json); if($i) { $instance = NULL; $class_name = $this->getClassName($i->type); if($class_name != '') { $instance = new $class_name($i->code, $i->name, $i->popularity); } else { $instance = new Unknown(); } return $instance; } throw new Exception("Json decode error."); } protected function getClassName($cname) { if(array_key_exists($cname, $this->classTable)) { return $cname; } return ''; } } /** * PHP5.4.0以降で利用可能 */ trait SharedFunc { protected $code; protected $name; protected $popularity; function __construct($code='', $name='', $popularity='') { $this->code = $code; $this->name = $name; $this->popularity = $popularity; } public function __get($name) { return $this->{$name}; } } /** * クラス定義 */ class Unknown { use SharedFunc; } class TwoFooseBase { use SharedFunc; } class Nyouichi extends TwoFooseBase { } class Nyouji extends TwoFooseBase { } /** * main */ function main() { $redis = new Redis(); $redis->pconnect('127.0.0.1', 6379); $keys = $redis->keys('*'); $factory = new TwoFooseFactory(); foreach($keys as $i => $k) { $i++; $json = $redis->get($k); $Instance = $factory->createInstance($json); print("= {$i} =\n"); print("Instance: " . get_class($Instance) . "\n"); print(" Code: " . $Instance->code . "\n"); print(" Name: " . $Instance->name . "\n"); print(" Pop: " . $Instance->popularity . "\n"); print("\n"); } } main(); ?>
PHPを実行して、JSONへアクセスしてみる
cuomo@karky7 ~ $ php RedisJson.php = 1 = Instance: Nyouichi Code: nyou_kouichi Name: 尿高一 Pop: 888888 = 2 = Instance: Unknown Code: Name: Pop: = 3 = Instance: Nyouji Code: nyou_sanji Name: 尿惨二 Pop: 99999999 cuomo@karky7 ~ $ほーぅら、JSONを利用した、Haskellデータ型とPHPのオブジェクトインスタンスの相互利用が可能になりました。
何とか、もう少しでいいのでHaskell力が欲しい今日この頃です
それからお酒の飲みすぎの痛風にはご注意ください。
0 件のコメント:
コメントを投稿