New O/R Mapper	

for Common Lisp
株式会社はてな	


id:nitro_idiot

2014/01/23 Lisp Meet Up presented by Shibuya.lisp #13
自己紹介
• 深町英太郎	

• id:nitro_idiot	

• 株式会社はてな勤務	

• Webアプリケーションエンジニア	

• ブログ「八発白中」

blog.8arrow.org
作ったもの
• Clack	


• CL-Project	


• Caveman	


• Shelly	


• ningle	


• Lesque	


• CL-TEST-MORE	


• Quickdocs	


• CL-DB...
O/R Mapper
• O/Rマッパー知ってますか	

• DBのデータをオブジェクトとして扱う	

• ObjectStore知ってますか	

• ↑と同じだけど永続化の概念がある
O/R Mapper
• O/Rマッパー知ってますか	

• Postmodern, CLSQL	

• ObjectStore知ってますか	

• Elephant, AllegroCache
O/R Mapper
• O/Rマッパー知ってますか	

• Postmodern, CLSQL	

• ObjectStore知ってますか	

• Elephant, AllegroCache
例: Postmodern
(defclass country ()!
((name :col-type string :initarg :name!
:reader country-name)!
(inhabitants :col-type ...
例: Postmodern
(defclass country ()!
((name :col-type string :initarg :name!
:reader country-name)!
(inhabitants :col-type ...
例: Integral
(defclass country ()!
((name :col-type string :initarg :name!
:primary-key t!
:not-null t!
:reader country-nam...
メタクラス?
• クラスのクラス	

• クラス定義時に<dao-table-class>のインス

タンスが作成されてcountryクラスになる	

• 指定しないとstandard-classのクラスになる
メタクラス?
• (Integralでは)
• 自動的に

何に使っているか	


<dao-class> を継承させる	


• スロットのクラスを指定できる	

• 通常はstandard-direct-slot-definition	

•...
メタクラス?
• まあ、変なクラスを作れるってことです。
例: Postmodern
• 話はPostmodernにもどる
例: Postmodern
• defclass

に (:metaclass dao-class) をつける	


• カラムの型を指定できる	

• PRIMARY

KEYを指定できる	


一見、良さそうに見える
既存のORMの問題
• こんなスキーマを開発初期から定義できる

わけねーだろーが!!

(defclass country ()!
((name :col-type string :initarg :name!
:reader country...
既存のORMの問題
• 最初にCREATE TABLE文を流してしまう

と、クラス定義を変更したいときに困る	

• カラム追加したくなったら?	

• カラムのデータ型変えたくなったら?	

• Postmodernではテーブルの再作成しか...
Integral
• New

O/Rマッパー	


• Postmodernの持つ問題の解決
Integral
• クラス定義を変更したらDBスキーマにも

変更を反映する
= マイグレーション
マイグレーション
(defclass user ()!
((name :col-type text!
:initarg :name))!
(:metaclass <dao-table-class>))
マイグレーション
(defclass user ()!
((name :col-type text!
:initarg :name)!
(profile :col-type text!
:initarg :profile))!
(:metacl...
マイグレーション
(defclass user ()!
((name :col-type text!
:initarg :name)!
(profile :col-type text!
:initarg :profile))!
(:metacl...
マイグレーション
(defclass user ()!
((id :col-type serial!
:primary-key t)!
(name :col-type (varchar 64)!
:initarg :name)!
(profil...
オートマイグレーションモード
• *auto-migration-mode*をTにすると発動	

• クラスを再定義するたびにmigrate-table	

• 開発時に超便利
マイグレーションの実装
• 泥臭い	

• 普通にDBスキーマ引いてきてスロットと

比較しているだけ	

• DBの種類を見て、ValidなSQLを吐く	

• ALTER TABLEの実行順序も考慮
オートマイグレーションモードの実装
• initialize-instance

と reinitialize-instance の :after

で *auto-migration-mode* の値を見て T なら
migrate-tabl...
Integral	

• クラス定義

→ DBスキーマ の追随の話を

しましたね。	

• 既にあるテーブルと一緒に使うにはどうし

たらいいの???
Integral	

• DBスキーマ

よ

→ クラス定義 の追随もできる
:generate-slots	

!
!

(defclass user () ()!
(:metaclass <dao-table-class>)!
(:generate-slots t))

DBからスキーマ定義を取ってきてスロット
をつ...
:generate-slots	

!
!

(defclass user () ()!
(:metaclass <dao-table-class>)!
(:generate-slots t))

DBからスキーマ定義を取ってきてスロット
をつ...
:generate-slots	

!
!

(defclass user () ()!
(:metaclass <dao-table-class>)!
(:generate-slots t))

DBからスキーマ定義を取ってきてスロット
をつ...
:generate-slots	

!
!

(defclass user () ()!
(:metaclass <dao-table-class>)!
(:generate-slots t))

DBからスキーマ定義を取ってきてスロット
をつ...
:generate-slots	

の実装
• 定義したときはスロットは空	

• 最初にmake-instanceする直前にDBスキーマ

を取ってきてスロットをつっこむ	

• 定義時にやらない理由は、定義時にDB

接続がある保証が無いか...
:generate-slots	

の実装
• 既存のクラスにスロットを追加するのは

意外と面倒	

• c2mop:ensure-class-using-class

を使って上書

きする	

• このときスロット名が同じものが既に定

...
CRUD
•

Create: (save-dao (make-instance ‘user :name “Eitarow”))	


•

Read: (select-dao ‘user (where (:= :name “Eitarow”)...
CRUD
• update-daoやdelete-daoのとき実行される

SQLはUPDATE文とDELETE文	

• WHERE句が一意である必要がある	

• (でないと関係ない列まで変更する)	

• 通常はPRIMARY

KEYを...
CRUD
• Integralでは、PRIMARY

KEYの定義が無いと

きは自動で%oidというPRIMARY KEYを付与	

• 後でPRIMARY

KEYが定義されるとマイグ

レーションでDROP COLUMNされるから
別に問...
暗黙の継承<dao-table>
• select-dao, save-dao, delete-dao

は <dao-table>

のメソッドとして定義されている	

• Postmodernでは定義クラスが単一のクラス

を継承しない (...
共通のクラスを継承する利点
• たとえばRailsのScaffoldみたいな機能	

• テーブルクラスからHTMLのformを吐くみ

たいな機能が作れる	

• 他バリデーション機能とか
Postmodern vs Integral
Postmodern

Integral

対応DB

PostgreSQL

MySQL, PostgreSQL,
SQLite3

マイグレー
ション

なし

あり

自動PK

なし

あり...
Integral

https://github.com/fukamachi/integral
Upcoming SlideShare
Loading in...5
×

Integral - New O/R Mapper for Common Lisp

11,209
-1

Published on

A short introduction about a new O/R Mapper for Common Lisp named "Integral" and it's inside.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
11,209
On Slideshare
0
From Embeds
0
Number of Embeds
20
Actions
Shares
0
Downloads
7
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Integral - New O/R Mapper for Common Lisp

  1. 1. New O/R Mapper for Common Lisp 株式会社はてな id:nitro_idiot 2014/01/23 Lisp Meet Up presented by Shibuya.lisp #13
  2. 2. 自己紹介 • 深町英太郎 • id:nitro_idiot • 株式会社はてな勤務 • Webアプリケーションエンジニア • ブログ「八発白中」 blog.8arrow.org
  3. 3. 作ったもの • Clack • CL-Project • Caveman • Shelly • ningle • Lesque • CL-TEST-MORE • Quickdocs • CL-DBI • Integral See 8arrow.org
  4. 4. O/R Mapper • O/Rマッパー知ってますか • DBのデータをオブジェクトとして扱う • ObjectStore知ってますか • ↑と同じだけど永続化の概念がある
  5. 5. O/R Mapper • O/Rマッパー知ってますか • Postmodern, CLSQL • ObjectStore知ってますか • Elephant, AllegroCache
  6. 6. O/R Mapper • O/Rマッパー知ってますか • Postmodern, CLSQL • ObjectStore知ってますか • Elephant, AllegroCache
  7. 7. 例: Postmodern (defclass country ()! ((name :col-type string :initarg :name! :reader country-name)! (inhabitants :col-type integer :initarg :inhabitants! :accessor country-inhabitants)! (sovereign :col-type (or db-null string) :initarg :sovereign! :accessor country-sovereign))! (:metaclass dao-class)! (:keys name))
  8. 8. 例: Postmodern (defclass country ()! ((name :col-type string :initarg :name! :reader country-name)! (inhabitants :col-type integer :initarg :inhabitants! :accessor country-inhabitants)! (sovereign :col-type (or db-null string) :initarg :sovereign! :accessor country-sovereign))! (:metaclass dao-class)! (:keys name)) CREATE TABLE country (! name TEXT NOT NULL,! inhabitants INTEGER NOT NULL,! sovereign TEXT,! PRIMARY KEY (name))
  9. 9. 例: Integral (defclass country ()! ((name :col-type string :initarg :name! :primary-key t! :not-null t! :reader country-name)! (inhabitants :col-type integer :initarg :inhabitants! :not-null t! :accessor country-inhabitants)! (sovereign :col-type string :initarg :sovereign! :accessor country-sovereign))! (:metaclass <dao-table-class>)) Integralでもほとんど同じ。 :metaclassを指定する
  10. 10. メタクラス? • クラスのクラス • クラス定義時に<dao-table-class>のインス タンスが作成されてcountryクラスになる • 指定しないとstandard-classのクラスになる
  11. 11. メタクラス? • (Integralでは) • 自動的に 何に使っているか <dao-class> を継承させる • スロットのクラスを指定できる • 通常はstandard-direct-slot-definition • その他、定義・再定義時の処理など
  12. 12. メタクラス? • まあ、変なクラスを作れるってことです。
  13. 13. 例: Postmodern • 話はPostmodernにもどる
  14. 14. 例: Postmodern • defclass に (:metaclass dao-class) をつける • カラムの型を指定できる • PRIMARY KEYを指定できる 一見、良さそうに見える
  15. 15. 既存のORMの問題 • こんなスキーマを開発初期から定義できる わけねーだろーが!! (defclass country ()! ((name :col-type string :initarg :name! :reader country-name)! (inhabitants :col-type integer :initarg :inhabitants! :accessor country-inhabitants)! (sovereign :col-type (or db-null string) :initarg :sovereign! :accessor country-sovereign))! (:metaclass dao-class)! (:keys name))
  16. 16. 既存のORMの問題 • 最初にCREATE TABLE文を流してしまう と、クラス定義を変更したいときに困る • カラム追加したくなったら? • カラムのデータ型変えたくなったら? • Postmodernではテーブルの再作成しかない
  17. 17. Integral • New O/Rマッパー • Postmodernの持つ問題の解決
  18. 18. Integral • クラス定義を変更したらDBスキーマにも 変更を反映する = マイグレーション
  19. 19. マイグレーション (defclass user ()! ((name :col-type text! :initarg :name))! (:metaclass <dao-table-class>))
  20. 20. マイグレーション (defclass user ()! ((name :col-type text! :initarg :name)! (profile :col-type text! :initarg :profile))! (:metaclass <dao-table-class>))
  21. 21. マイグレーション (defclass user ()! ((name :col-type text! :initarg :name)! (profile :col-type text! :initarg :profile))! (:metaclass <dao-table-class>)) (migrate-table 'user)! ;-> ALTER TABLE `user` ADD COLUMN `profile` TEXT AFTER `name`;! ;=> NIL
  22. 22. マイグレーション (defclass user ()! ((id :col-type serial! :primary-key t)! (name :col-type (varchar 64)! :initarg :name)! (profile :col-type text! :initarg :profile))! (:metaclass <dao-table-class>)) (migrate-table 'user)! ;-> ALTER TABLE `user` DROP COLUMN `%oid`;! ; ALTER TABLE `user` MODIFY COLUMN `name` VARCHAR(64);! ; ALTER TABLE `user` ADD COLUMN `id` SERIAL NOT NULL PRIMARY KEY FIRST;! ;=> NIL
  23. 23. オートマイグレーションモード • *auto-migration-mode*をTにすると発動 • クラスを再定義するたびにmigrate-table • 開発時に超便利
  24. 24. マイグレーションの実装 • 泥臭い • 普通にDBスキーマ引いてきてスロットと 比較しているだけ • DBの種類を見て、ValidなSQLを吐く • ALTER TABLEの実行順序も考慮
  25. 25. オートマイグレーションモードの実装 • initialize-instance と reinitialize-instance の :after で *auto-migration-mode* の値を見て T なら migrate-table 走らせるだけ
  26. 26. Integral • クラス定義 → DBスキーマ の追随の話を しましたね。 • 既にあるテーブルと一緒に使うにはどうし たらいいの???
  27. 27. Integral • DBスキーマ よ → クラス定義 の追随もできる
  28. 28. :generate-slots ! ! (defclass user () ()! (:metaclass <dao-table-class>)! (:generate-slots t)) DBからスキーマ定義を取ってきてスロット をつっこむ
  29. 29. :generate-slots ! ! (defclass user () ()! (:metaclass <dao-table-class>)! (:generate-slots t)) DBからスキーマ定義を取ってきてスロット をつっこむ (make-instance 'user :name "Eitarow Fukamachi")! ;=> #<USER %oid: <unbound>>
  30. 30. :generate-slots ! ! (defclass user () ()! (:metaclass <dao-table-class>)! (:generate-slots t)) DBからスキーマ定義を取ってきてスロット をつっこむ class User < ActiveRecord::Base! end
  31. 31. :generate-slots ! ! (defclass user () ()! (:metaclass <dao-table-class>)! (:generate-slots t)) DBからスキーマ定義を取ってきてスロット をつっこむ class User < ActiveRecord::Base! end なんか似てますね
  32. 32. :generate-slots の実装 • 定義したときはスロットは空 • 最初にmake-instanceする直前にDBスキーマ を取ってきてスロットをつっこむ • 定義時にやらない理由は、定義時にDB 接続がある保証が無いから
  33. 33. :generate-slots の実装 • 既存のクラスにスロットを追加するのは 意外と面倒 • c2mop:ensure-class-using-class を使って上書 きする • このときスロット名が同じものが既に定 義されてると死ぬのでちゃんとマージする
  34. 34. CRUD • Create: (save-dao (make-instance ‘user :name “Eitarow”)) • Read: (select-dao ‘user (where (:= :name “Eitarow”))) • Update: (save-dao user-obj) • Delete: (delete-dao user-obj)
  35. 35. CRUD • update-daoやdelete-daoのとき実行される SQLはUPDATE文とDELETE文 • WHERE句が一意である必要がある • (でないと関係ない列まで変更する) • 通常はPRIMARY KEYを使う
  36. 36. CRUD • Integralでは、PRIMARY KEYの定義が無いと きは自動で%oidというPRIMARY KEYを付与 • 後でPRIMARY KEYが定義されるとマイグ レーションでDROP COLUMNされるから 別に問題ないよね
  37. 37. 暗黙の継承<dao-table> • select-dao, save-dao, delete-dao は <dao-table> のメソッドとして定義されている • Postmodernでは定義クラスが単一のクラス を継承しない (metaclassのみ) • テーブルクラスに共通のメソッドを定義で きない
  38. 38. 共通のクラスを継承する利点 • たとえばRailsのScaffoldみたいな機能 • テーブルクラスからHTMLのformを吐くみ たいな機能が作れる • 他バリデーション機能とか
  39. 39. Postmodern vs Integral Postmodern Integral 対応DB PostgreSQL MySQL, PostgreSQL, SQLite3 マイグレー ション なし あり 自動PK なし あり なし あり スロット
 自動生成
  40. 40. Integral https://github.com/fukamachi/integral
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×