Shiroさんの翻訳プログラミングClojureが発売されたこともあって、この前のShibuya.lispではClojure祭りでしたね。
先日、Tokyo.cljの記念すべき第1回「Clojure Hackason」も開催されました。主催者は @masa_edw さんです。しかも定期的に月1ペースでハッカソンを開催するそうです。すごいですね。
さらに日本でClojureを流行らせようと、@making さんが clojure-users.org というサイトも運営されています。なかなかすごいバイタリティです。
これは、ひょっとして、今まさに空前のClojureブームなのではないか!

そこで僕は何をやるのか。僕はご存知のようにWeb屋なので、Webアプリケーションを作ることに興味があります。ClojureでWebアプリケーション、とくれば、もちろんGoogle AppEngineですね。
今日は、 @making さん作の、DatastoreのClojureラッパー、「clj-gae-ds」をいじってみたので紹介したいと思います。
「何言ってんだドク、日本製は最高なんだぜ」
ClojureのAppEngine用のラッパーと言えばappengine-cljがあります。ただこのライブラリは一部欠けた部分があって、結局AppEngineのJava APIを叩かないといけないとかで面倒な部分もあります。
その点clj-gae-dsはきれいにラップされてますし、まあ、なにより日本製ですしね。Made in makingですしね。日本のClojurianはみんな使うといいです。
Entityを挿入・更新
RDBMSではデータ一つ一つをRowとかRecordとか言いますが、DatastoreではEntityと言います。まずはmap-entityを使って挿入するEntityを作ります。
(map-entity "kind" :prop1 "value" :prop2 "value")
DatastoreではテーブルのことをKindと言います。これを使って以下のようにEntityを作ります。
(def luffy (map-entity "person" :name "Monkey D. Luffy"))
Datastoreはスキーマレスなので、Entityに好きなPropertyをつけることができます。
(def luffy (map-entity "person" :name "Monkey D. Luffy" :ability "GomGom" :bounty 100000000))
もしPropertyの値を取得/変更したい場合はget-prop / set-propを使います。
(get-prop luffy :name) ;;=> "Monkey D. Luffy"
(set-prop luffy :bounty 300000000) ;; 懸賞金が1億→3億に
このEntityはまだDatastoreに保存されていません。これを実際にDatastoreに入れるにはds-putを使います。
(ds-put luffy)
あんまり使わないかもしれないですが、返り値はKeyオブジェクトです。
DatastoreからEntityを検索・取得
挿入する際はEntityというオブジェクトを介しましたが、逆にデータを取り出したいときはQueryというオブジェクトを作らないといけません。
以下は”person”からすべてのデータを取り出すQueryです。
(query "person")
もし、取り出すデータに条件をつけたい場合はadd-filterを使います。
(add-filter (query "person") "ability" :eq "Santoryu")
(追記) Property名はstringです。keywordじゃありません。気をつけてください。僕も気をつけます。
(追記) Property名がkeywordにも対応したそうです。仕事早いです。以下で出てくるadd-sortもstring / keywordの両方使えます。
比較演算子にはキーワード形式で :eq, :neq, :lt, :gt, :lte, :gte, :in 、もしくは 関数形式で =, not=, >, >=, <, <= を使えるようです。これはappengine-cljに対してかなり便利な機能だと思います。
さらにこのQueryからEntityを取り出すには query-seq を使います。これは、クエリを受け取ってLazySeqを返してくれる便利な関数です。
;; 三刀流のメンバーは誰?
(let [q (add-filter (query "person") "ability" :eq "Santoryu")]
(first (query-seq q)))
結果をソートしたい場合はadd-sortを使います。
;; 懸賞金が高い順に3人取得
(let [q (add-sort (query "person") "bounty" :desc)]
(take 3 (query-seq q)))
ただ結果に含まれるEntity数だけを知りたい場合はcount-entitiesが使えます。
;; 女性メンバーは何人?
(let [q (add-filter (query "person") "sex" :eq "female")]
(count-entities q))
Entityの削除
Datastoreの削除はパフォーマンス上好ましくないですが、必要な場合もあるでしょう。Entityの削除はds-deleteで行います。
注意すべきなのが、このds-deleteの引数はKeyオブジェクトということです。Entityではありません。EntityからKeyを取り出すには (.getKey entity) する必要があります。
(ds-delete (.getKey usopp))
EntityをMapに変換
他に、EntityをMapに変換してくれるentity-map もあります。map-entityではありません。ややこしいですね。これは関数名を entity->map に改めるべきだと思いますが…
(entity-map nami)
まとめ
他にもいくつか関数が提供されていますが、日常的に使うものは以上のもので十分っぽいです。
clj-gae-dsはラッパーではありますが、EntityとかQueryとかKeyとか存在理由のわからないオブジェクトが出てくるのでDatastoreの知識がない人にはわかりづらいかもしれないですね。
Tokyo.clj#2 Clojure Hackasonの参加者募集中
来月開催予定のTokyo.clj#2 Clojure Hackasonの参加者を募集中です。今見ると7人ほど空きがあります。ゴールデンウィークなので僕は参加できないかもですが、興味がある人はぜひ参加を。
→Clojure Hackasonに参加する
最近のコメント