Advertisement
Advertisement

More Related Content

Advertisement

Similar to Integral - New O/R Mapper for Common Lisp(20)

Recently uploaded(20)

Advertisement

Integral - New O/R Mapper for Common Lisp

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