2020年1月3日金曜日

esqueletoでSQL関数

Esqueletoで関数


Yesodやってて、関数を使う必要性があったのですがいまいちやり方が曖昧だったので調べてみた、案外簡単だった。

面倒くさいのでだいぶはしょる、Handlerから使う想定、kusoをした時刻がNULLなら「1800-01-01 00:00:00 UTC」にする。


import qualified Database.Esqueleto as E
import qualified Database.Esqueleto.Internal.Sql as E

...
...
kusoTime :: HandlerFor App ([E.Value UTCTime])
kusoTime = runDB $ do
    result <- E.select $ E.from $ \table -> do
        return $ coalesceDate (table E.^. KusoLastKusoTime)
    return result
        where
            coalesceDate :: E.SqlExpr (E.Value (Maybe UTCTime)) ->
 E.SqlExpr (E.Value UTCTime)
            coalesceDate t = E.unsafeSqlFunction "COALESCE" (t, defDate')
            defDate :: E.SqlExpr (E.Value UTCTime)
            defDate = E.unsafeSqlValue "TIMESTAMP \'1800-01-01 00:00:00 UTC\'"
こう書くと
SELECT COALESCE("kuso"."last_kuso_time", TIMESTAMP '1800-01-01 00:00:00 UTC') FROM "kuso"
こんなSQLが出力される、2020年。

2019年9月21日土曜日

YesodでXMLをレスポンスする

XML APIサーバーで使いたい


バックエンドの開発用サーバーを皆に黙って、こっそりYesodで作ろうかと思ってたら、メンテナーがいなくなることが判明し、全員に却下されることとなったが、いつかやってやろうと思っている。


でXML


YesodでXMLを出力する、TemplateHaskellを使うと結構簡単

{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module Handler.Home where

import Import
import Text.XML
import Text.Hamlet.XML
import qualified Data.Map as M
import qualified Text.XML.Stream.Render as R

getHomeR :: Handler TypedContent
getHomeR = selectRep $ do
    provideRep $ return $ repXml $ renderText rs (getXml 10)

getXml :: Int -> Document
getXml n = Document p elm []
    where
        p = Prologue [] Nothing []
        elm = Element "root" M.empty [xml|
<params>
    <param>#{pack $ show n}
    <param>yyy
|]

rs :: R.RenderSettings
rs = def


Handler部分だけですが、TypedContentとrepXmlでcontent-type/xmlに変えて、Document型を返す関数をrenderText関数へ食わせるだけ。

THとか使わない版


ベタに書くとこんな感じか、オレオレデータをXMLに無理やり変換してるだけ、あまり綺麗じゃないので許してね

{-# LANGUAGE OverloadedStrings #-}

import Text.XML
import qualified Data.Text as T
import qualified Data.Text.Internal as T
import qualified Data.Text.Lazy as L
import qualified Data.Text.Internal.Lazy as L
import qualified Data.Map as M

data Foo = Foo {
    identFoo :: Int
  , namefoo :: T.Text
  , argList :: [Argument]
} deriving(Show)

data Argument = Argument {
    nameArg :: T.Text
  , dataArg :: Maybe T.Text
} deriving(Show)

data Other = Other {
    identOther :: Int
  , nameOther :: T.Text
} deriving(Show)

main :: IO ()
main = putStrLn $ T.unpack $ L.toStrict $
  renderText (def :: RenderSettings) $ createDoc $ (foos createFoo) ++ (others createOther)

createDoc :: [Node] -> Document
createDoc nodes = Document prlg elem [] 
    where
      prlg = Prologue [] Nothing []
      elem = Element (Name "root" Nothing Nothing) M.empty nodes
      
foos :: [Foo] -> [Node]
foos = map (fooNodes)

others :: [Other] -> [Node]
others = map (otherNodes)

node :: Int -> T.Text -> M.Map Name T.Text
node i name = M.fromList [
                   (Name "id" Nothing Nothing, (T.pack $ show i))
                 , (Name "name" Nothing Nothing, name)
               ]

fooNodes :: Foo -> Node
fooNodes f@(Foo i name arg) = NodeElement elem
    where
      elem = Element n
                     (node i name)
                     nodes
      n = Name "foo" Nothing Nothing
      nodes = map (\(Argument an dt) ->
                     NodeElement
                         (Element (Name "argument" Nothing Nothing)
                         (M.fromList [(Name "name" Nothing Nothing, an)])
                         (nodeCont dt))
                  ) arg

otherNodes :: Other -> Node
otherNodes o@(Other i name) = NodeElement elem
    where
      elem = Element n
                     (node i name)
                     []
      n = Name "other" Nothing Nothing

nodeCont :: Maybe T.Text -> [Node]
nodeCont (Just val) = [NodeContent val]
nodeCont _ = []

createFoo :: [Foo]
createFoo = [Foo 1 "test" createArgument, Foo 2 "test2" createArguments]
            
createArgument :: [Argument]
createArgument = [Argument "a" (Just "empty 吉田")]

createArguments :: [Argument]
createArguments = [Argument "b" (Just "エンペラー 吉田"), Argument "c" Nothing]

createOther :: [Other]
createOther = [Other 2 "someother"]

{-
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <foo id="1" name="test">
        <argument name="a">empty 吉田</argument>
    </foo>
    <foo id="2" name="test2">
        <argument name="b">エンペラー 吉田</argument>
        <argument name="c"/>
    </foo>
    <other id="2" name="someother"/>
</root>
-}




とりあえず、吉田さんのとこに上げときます

https://github.com/calimakvo/resp-xml

2019年9月20日金曜日

Shizuoka.php 行ってきた

久しぶりに静岡に行ってきた


ここ最近プログラムを書かなくなって、久しくPHPのバージョンも5.7あたりの記憶しか無くなっていたので、最近のPHP界隈の話を聞けて良かった。

皆さんの資料はこちらです

https://shizuokaphp.connpass.com/event/26794/presentation/

PHPの言語仕様もだいぶ改良されてました、時間取ってまたコード書いてみようと思います。

後の飲み会も、たのしく飲ませていただきました。(2次会以降はクズばかりになったって聞きましたが...)

また、開催されるときは、飲みに行こうかとおもいます、ポリちゃんお疲れでした。

Shizuoka.hs について


何か最近、以前の言語戦争を思わせるようなツイートを目にしたのと、またそれに間違いがあるので、ここで正確な情報をお知らせしたいとおもいます。

 じつは、


こうなんですよ!

そして伊豆半島はかわいいピンク色、そう全部Haskellなんです、皆さん覚えておいてください。
そして、この地図を作ってくださった方が再度正確に修正して下さるということで、安堵してますが、有難うございます。

ついでで申し訳ないのですが、色もそうなんですが、私もgoみたいにかわいいアイコンを作ってはみたものの上手に出来ないので私が大ファンの吉田さんを参考に置いてみました。

こんな感じでお願いします。

この年になって双子抱えて、gentooとか飲酒ととかほんと忙しいのですが、

今年中には 

Shizuoka.hs

ベースは三島haskell無名関数の会)

 やるので、みなさん仲良く静岡で飲もうね。

ちょっと何言ってるか分からないけど、yoropiku...