Created
December 15, 2017 04:01
-
-
Save IzumiSy/7c345b5f545bc0b9bbf3861399246535 to your computer and use it in GitHub Desktop.
ROM.rb repository example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "rom" | |
require "rom/sql" | |
# | |
# ## Relationを定義 | |
# | |
# ROMのRelationは`ROM::Relation[:アダプタ名]`を継承したクラスとして定義する | |
# associationsブロックの中で`belongs_to`や`has_many`などの関連も定義をする | |
# ここで定義したRelationは下で出てくるROMの初期化の際にROMへの登録を行う必要がある。 | |
# | |
module Relations | |
class Users < ROM::Relation[:sql] | |
schema(:users) do | |
# Relationの関連定義はActiveRecordと似ている。 | |
# has_many, belongs_toやhas_many-throughなどがあるのでドキュメントを参照のこと | |
# http://rom-rb.org/learn/sql/associations/ | |
associations do | |
has_many :books | |
end | |
# schemaブロックの中では関連の定義に加えて以下のように明示的に | |
# Relationのカラムを定義できる。この場合、プライマリ・キーは | |
# `Types::Serial`である必要がある | |
attribute :id, Types::Serial | |
attribute :name, Types::String | |
attribute :age, Types::Int | |
end | |
# Repositoryの中で呼び出せるクラスメソッドを以下のように定義できる | |
# ROM.rbのSQLアダプタ(rom-sql)は内部でSequalizeを使っているので | |
# where句などもその記法に従う | |
def by_pk(id) | |
where(id: id) | |
end | |
def adult | |
where{age > 20} | |
end | |
end | |
class Books < ROM::Relation[:sql] | |
schema(:books) do | |
associations do | |
belongs_to :user | |
end | |
# booksの場合にはuserに対してbelongs_toで関連を持っているので | |
# その関連に対して`Types::ForeignKey(:users)`のように明示的に | |
# 利用する外部キーを指定できる。ない場合には自動で推論される。 | |
attribute :id, Types::Serial | |
attribute :title, Types::Int | |
attribute :user_id, Types::ForeignKey(:users) | |
end | |
end | |
end | |
# | |
# ## Repositoryを定義 | |
# | |
# Repositoryからは定義されているRelationを触ることができる | |
# | |
module Repositories | |
class User < ROM::Repository[:users] | |
# ROM.rbではRepositoryがRelationに対してどのようなアクセスをできるのか | |
# という点を明確に制限できる。ここでは:createをコマンドとして有効化しているが | |
# :create以外にも:updateや:deleteがある。 | |
commands :create | |
# 以下のようにクラスメソッドを定義できる。 | |
# これらのデータはROM::Structによってラップされて返される | |
# ここではusersのみを読んでいるが、booksも同様にメソッドのなかでアクセスできる | |
def adults | |
users.adult | |
end | |
# `aggregate`メソッドを使うことによって、Relationで定義されている | |
# 関連Relationのデータを子要素としてフェッチできる | |
# `aggregates`を呼ぶ場合には明示的にRelationを指定しなくてもよさそう。 | |
def all | |
aggregate(:books) | |
end | |
def by_id(id) | |
aggregate(:books).by_pk(id).one | |
end | |
end | |
end | |
# | |
# ## ROMにRelationを登録 | |
# | |
# 上で定義した2つのRelationをROMに登録 | |
# | |
config = ROM::Configuration.new(:sql, "sqlite::memory") | |
config.register_relation(Relations::Users) | |
config.register_relation(Relations::Books) | |
rom = ROM.container(config) | |
# SQLiteでテーブルを作るマイグレーションを適用 | |
migration = ROM::SQL.migration(rom) do | |
change do | |
create_table(:users) do | |
primary_key :id | |
string :name | |
integer :age | |
end | |
create_table(:books) do | |
primary_key :id | |
foreign_key :user_id, :users | |
string :title | |
end | |
end | |
end | |
gateway = rom.gateways[:default] | |
migration.apply(gateway.connection, :up) | |
# | |
# ## Repositoryを使ってみる | |
# | |
# RepositoryはRelationとは異なり、ROMへ登録するのではなく、ROMのインスタンスを | |
# コンストラクタDIすることでRepositoryのインスタンスを作るという形になる。 | |
# | |
userRepository = Repositories::User.new(rom) | |
userRepository.create(name: "Justine", age: 10) | |
userRepository.create(name: "Jessy", age: 18) | |
userRepository.create(name: "Michael", age: 23) | |
# テストのためにBooksテーブルにRelation経由でデータを入れてみる | |
# (外部キー成約があるので、userレコードを作ったあとじゃないとダメ) | |
books = rom.relations[:books] | |
books.insert(title: "Good Book", user_id: 1) | |
books.insert(title: "Nice Book", user_id: 1) | |
# | |
# ### Repositoryからレコードを取得 | |
# | |
# ここでは`by_id`や`adults`などの、Repositories::Userの中で定義した | |
# クラスメソッドを呼び出すことができる。Relationの結果が常にハッシュなのに対して | |
# Repositoryによる取得の返り値はROM::Structという構造体の形になる。 | |
# これはデフォルトでtrueになっている`auto_struct`をfalseに指定することで | |
# 止めることができる | |
# | |
users = userRepository.all | |
users.each { |user| p user } | |
# => #<ROM::Struct::User id=1 name="Justine" age=10 books=[ | |
# #<ROM::Struct::Book id=1 title="Good Book" user_id=1>, | |
# #<ROM::Struct::Book id=2 title="Nice Book" user_id=1> | |
# ]> | |
# #<ROM::Struct::User id=2 name="Jessy" age=18 books=[]> | |
# #<ROM::Struct::User id=3 name="Michael" age=23 books=[]> | |
single_user = userRepository.by_id(1) | |
p single_user | |
# => #<ROM::Struct::User id=1 name="Justine" age=10 books=[ | |
# #<ROM::Struct::Book id=1 title="Good Book" user_id=1>, | |
# #<ROM::Struct::Book id=2 title="Nice Book" user_id=1> | |
# ]> | |
users = userRepository.adults | |
users.each { |user| p user } | |
# => #<ROM::Struct::User id=3 name="Michael" age=23> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment