Edited at

ClojureでDBを扱う

More than 1 year has passed since last update.


書くこと

ClojureとKormaを使ってDBアクセスする。


Korma

https://github.com/korma/Korma

http://sqlkorma.com/

必要なことはここに全て書いてあるので、英語だけど読めば下の記事は読む必要がない。


前準備

Leiningenは入ってるものとする。

適当にプロジェクトを作ってdependenciesにkormaを追加しておく。

今回はRDBMSにMySQLを使用するので、MySQLのドライバもいれておく。


init.sh

lein new default app

cd app
vim project.clj


project.clj

(defproject app "0.1.0-SNAPSHOT"

:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [
[org.clojure/clojure "1.6.0"]
[korma "0.4.3"]
[mysql/mysql-connector-java "5.1.38"]
])



init.sh

lein test


テストはコケるものが用意されているので正常にコケる


DBに接続する

vim src/app/core.clj


src/app/core.clj

(ns app.core)

(use 'korma.db)
(use 'korma.core)

; DB接続を作成する
(defdb mydb
(mysql
{
:db "app_database"
;手元の環境ではSSL証明書はないので使わなようにしておく。
:subname "//127.0.0.1:3306/app_database?useSSL=false"
:user "app_database"
:excess-timeout 1000
:idle-timeout 1000
:initial-pool-size 1
:minimum-pool-size 1
:maximum-pool-size 1
:password "app_database"}))

; 使用するテーブルを呼び出しておく
(defentity app)

; 既存のテスト関数
(defn foo
"I don't do a whole lot."
[x]
(println x "Hello, World!"))


テスト用のDBを作っておく。


init.sql

CREATE DATABASE app_database;

GRANT ALL ON *.* TO 'app_database'@'%' IDENTIFIED BY 'app_detabase';
USE app_database;
CREATE TABLE app ( id INT(10) AUTO_INCREMENT PRIMARY KEY , name VARCHAR(20) , integer_value INT (10) DEFAULT 0);
INSERT INTO app ( name , integer_value) VALUES ("name1" , 1) ;
INSERT INTO app ( name , integer_value) VALUES ("name2" , 2) ;
INSERT INTO app ( name , integer_value) VALUES ("name3" , 3) ;


CRUD

特に衒いがなく直感的な使いやすい形でインターフェースが揃っている。


SELECT

CRUDさえできればとりあえずのことはできる。

Seectは帰り値がArrayで帰ってくるのでわかりやすく便利。


select.clj

(def select-result (select app (fields :id :name)))

; SELECT id , name FROM app;
(println
(:id (first select-result)))
(println
(:name (first select-result)))

; WHERE句をつけて実行する。
(def where-result (select app
(fields :id :name)
(where (= :id 1))
))
(println
(:id (first where-result)))

; 集計関数を使う
(def sum-result (select app
(aggregate (sum :integer_value) :integer_value_sum)
))
(println
(:integer_value_sum (first sum-result)))



INSERT


insert.clj

(insert app 

(values {
:name "name4"
:integer_value 33
}))


UPDATE


update.clj

(def update-result (update app

(where (or (= :id 1) (= :id 2) (= :id 3000))
(set-fields {
:name "updated_name"
:integer_value "20"
})))
(println update-result)
; 変更行数として2が表示される。
; id=3000の物は計上されない


DELETE


delete.clj

(delete app

(where (>= :id 3)))