Sequelã®Tipsã®ãããªãã®
Rubyã«ããã軽éãªãã¼ã¿ãã¼ã¹ãã¼ã«ãããã¨ãã¦ããªããªããæ軽ãªSequelã§ãããå®éã«ä½¿ãã«ããã£ã¦ããã¤ãæ©ãã ãã¤ã³ãããã£ãã®ã§ãåå¿é²ã¨ãã¦ãã®è§£æ±ºæ³ãã¡ã¢ãã¦ããã¾ãã
ãªãããã®è¨äºã¯Ruby 1.9.1p378ã¨Sequel 3.8.0ã®çµã¿åããã対象ã¨ãã¦æ¸ãã¦ãã¾ãã
ã¢ãã«ã®å®ç¾©åã«DBæ¥ç¶ãããããªã
Sequelã«ãActiveRecordãã¿ã¼ã³ã«åºã¥ããã¢ãã«ã®ä»çµã¿ãç¨æããã¦ãã¾ããããã¢ãã«ãå®ç¾©ããæç¹ã§ãã¼ã¿ãã¼ã¹ã¸ã®æ¥ç¶ãåå¨ãã¦ããªããã°ãªããªããã¨ããå¶ç´ãããã¾ãã
ã¤ã¾ãã
require 'sequel' Sequel.connect('sqlite://test.db') class User < Sequel::Model; end p User.all
ã¯åãã¾ããã
require 'sequel' class User < Sequel::Model; end # Sequel::Error Sequel.connect('sqlite://test.db') p User.all
ã¯åãã¾ããã"No database associated with Sequel::Model"ã¨ãã£ã¦æããã¾ãã
ãã®å¶ç´ãã©ãããã¨ãã«ä¸ä¾¿ãã¨ããã¨ãä¾ãã°
require 'sequel' class App def self.connect_database(option) Sequel.connect(option) end class User < Sequel::Model; end # Sequel::Error end App.connect_database('sqlite://test.db') p App::User.all
ã®ããã«ããã¼ã¿ãã¼ã¹é¢é£ã®å®ç¾©ãã¯ã©ã¹ãã¢ã¸ã¥ã¼ã«ã®ä¸ã«æ¼ãè¾¼ãããã¨ããã¨ããã¡ãã£ã¨ç¶ºéºã«æ¸ããªããªã£ã¦ãã¾ãã¾ãã
ããã¯module_evalã使ããã¨ã§è§£æ±ºã§ãã¾ãã
require 'sequel' class App class << self def connect_database(option) Sequel.connect(option) define_models end def define_models module_eval %{ class User < Sequel::Model; end } end end end App.connect_database('sqlite://test.db') p App::User.all
å®éã«ã¯ã¢ãã«å®ç¾©ã®ã¿ã¤ãã³ã°ãé ããã¦ããã ããªã®ã§ãããã¨ãããããããã£ã½ãæ¸ããããã¨ããç®çã¯éæã§ããããªãã¨ã
ãªããSequel::Modelãç¶æ¿ããã¯ã©ã¹ã¯ãæ¾ã£ã¦ããã¨åæã«ãããã¾ã§ã«æ¥ç¶ããä¸çªæåã®ãã¼ã¿ãã¼ã¹ãã¨é¢é£ä»ãããã¦ãã¾ãã¾ããä¾ãã°è¤æ°ã®ã¯ã©ã¹ã§ããããå¥ã®ãã¼ã¿ãã¼ã¹ãåç §ããããå ´åã¯ã以ä¸ã®ããã«ã¢ãã«ã¯ã©ã¹ã®ç¶æ¿æã«ãã¼ã¿ãã¼ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ã渡ãã¦ããã°OKã§ãã
require 'sequel' module App def connect_database(option) db = Sequel.connect(option) define_models(db) end def define_models(db) module_eval %{ class User < Sequel::Model(db); end } end end class AppA extend App end class AppB extend App end AppA.connect_database('sqlite://testa.db') AppB.connect_database('sqlite://testb.db') p AppA::User.all p AppB::User.all
ãã¾ãããããã±ã¼ã¹ããããã©ããã¯ãããã¾ãããâ¦ã
æåååã®ãã¼ã¿ãforce_encodingããã
ããã©ã«ãã§ã¯ãåå¾ããæåååãã¼ã¿ã®ã¨ã³ã³ã¼ãã£ã³ã°ã¯ASCII-8BITã«ãªã£ã¦ãã¾ãã
require 'sequel' Sequel.connect('sqlite://test.db') class User < Sequel::Model; end p User.first.name.encoding # => #<Encoding:ASCII-8BIT>
éä¸String#force_encodingãããã¦ãããã®ã§ãããé¢åãªå ´åã¯ForceEncodingãã©ã°ã¤ã³ã使ããã¨ã§ãå ¨ã¦ã®æåååã«ã©ã ã®ã¨ã³ã³ã¼ãã£ã³ã°ãå¼·å¶çã«æå®ã§ãã¾ãã
require 'sequel' Sequel.connect('sqlite://test.db') class User < Sequel::Model plugin :force_encoding, 'UTF-8' end p User.first.name.encoding # => #<Encoding:UTF-8>
ã¡ãªã¿ã«ãã¢ãã«ã§ã¯ãªããã¼ã¿ã»ããçµç±ã§æä½ããå ´åã¯ããã®ãããªå ¨ä½çã«ã¨ã³ã³ã¼ãã£ã³ã°ã®æå®ãããæ¹æ³ã¯ãªããããããã«force_encodingãããããããªãããã§ãã
require 'sequel' db = Sequel.connect('sqlite://test.db') p db[:users].first[:name] # => "\xE5\xA4\xAA\xE9\x83\x8E" p db[:users].first[:name].force_encoding('UTF-8') # => "太é"
ãã©ã¤ããªãã¼ãæå®ããã
Sequelã®ã¢ãã«ã¯ãããã©ã«ãã§ã¯ãã©ã¤ããªãã¼ã¯Restrictedãªå¤ã¨ãã¦ãæ示çãªæå®ã許å¯ããã¦ããªãç¶æ ã«ãªã£ã¦ãã¾ãã
require 'sequel' db = Sequel.connect('sqlite://test.db') # ãã¼ã¿ã»ããçµç±ã®å ´åã¯é¢ä¿ãªã db[:users].insert(:id => 123, :name => 'John', :age => 18) # ok class User < Sequel::Model; end User.create(:id => 456, :name => 'Bob', :age => 17) # Sequel::Error # => ...method id= doesn't exist or access is restricted to it...
ã¢ãã«å®ç¾©æã«unrestrict_primary_keyã宣è¨ãããã¨ã§ããã©ã¤ããªãã¼ã®æ示çãªæå®ãå¯è½ã¨ãªãã¾ãã
require 'sequel' Sequel.connect('sqlite://test.db') class User < Sequel::Model unrestrict_primary_key end User.create(:id => 456, :name => 'Bob', :age => 17) # ok
ååã®ã«ã©ã ãåå¨ãããã¼ãã«å士ãJOINããã
ä¾ãã°usersã¨postsã¨ãããã¼ãã«ããããåæ¹ãcreated_atã¨ããååã§ã¬ã³ã¼ãã®çææ¥æãè¨é²ãã¦ããã¨ãã¾ãããã®ã¨ãã
require 'sequel' Sequel.connect('sqlite://test.db') class User < Sequel::Model one_to_many :posts end class Post < Sequel::Model many_to_one :users end p Post.join(User, :id => :user_id).first.created_at # => User's created_at
ã®ããã«åç´ã«JOINããã¨ãå¾ãããã¬ã³ã¼ãã®created_atã¯Userã®ããã¨ãªãã¾ãã
ããããã±ã¼ã¹ã§ã¯graphã¡ã½ããã使ããã¨ã§ã«ã©ã åã®è¡çªãé²ããã¨ãã§ãã¾ããgraphã¡ã½ããã¯ããã¼ãã«æ¯ã«åå¥ã®ã¬ã³ã¼ããæ ¼ç´ããããã·ã¥ã¨ãã¦çµæãè¿ãã¾ãã
require 'sequel' Sequel.connect('sqlite://test.db') class User < Sequel::Model one_to_many :posts end class Post < Sequel::Model many_to_one :users end record = Post.graph(User, :id => :user_id).first p record[:posts].created_at # => Post's created_at p record[:users].created_at # => User's created_at
3ã¤ä»¥ä¸ã®ãã¼ãã«ãJOINããã
Sequelã¯ã¡ã½ãããã§ã¤ã³ã§ããããSQLãçæã§ããã®ã便å©ãªã®ã§ããããã¾ã«ãããããããã¤ã³ãã«ãªããã¨ãããã¾ãã
ä¾ãã°ä»èª¬æããgraphã¡ã½ãããããã¯JOINã®å·¦å´ã®ãã¼ãã«ã¨ãã¦ããç´åã¾ã§ã«çæããããã¼ã¿ã»ããã®ãã¡ãæå¾ã«JOINããããã¼ãã«ãã使ç¨ãã¾ãã
ã¤ã¾ãã以ä¸ã®ãããªã³ã¼ããå®è¡ããã¨ã
require 'sequel' Sequel.connect('sqlite://test.db') class User < Sequel::Model one_to_many :posts end class Category < Sequel::Model one_to_many :posts end class Post < Sequel::Model many_to_one :users many_to_one :categories end p Post.graph(User, :id => :user_id) .graph(Category, :id => :category_id) .first # Sequel::DatabaseError
categoriesãã¼ãã«ãJOINãã段éã§*1"no such column: users.category_id"ã¨æããã¾ããpostsã¨categoriesãJOINãã¦æ¬²ããã®ã«ãusersã¨categoriesãJOINãããã¨ãã¦ãã¾ã£ã¦ããããã§ãã
ãã®ãããªã±ã¼ã¹ã§ã¯ã:implicit_qualifierãªãã·ã§ã³ã«ãã£ã¦JOINã®å·¦è¾ºãæå®ãã¦ããã¾ãã
require 'sequel' Sequel.connect('sqlite://test.db') class User < Sequel::Model one_to_many :posts end class Category < Sequel::Model one_to_many :posts end class Post < Sequel::Model many_to_one :users many_to_one :categories end p Post.graph(User, :id => :user_id) .graph(Category, { :id => :category_id }, :implicit_qualifier => :posts) .first # ok
{}ã«ãã£ã¦ç¬¬2å¼æ°ã®JOINæ¡ä»¶ã¨ç¬¬3å¼æ°ã®ãªãã·ã§ã³ãæ示çã«åºå¥ãããã¨ãå¿ããã«ã
æ°ãä»ãããSequelã®ã¯ã»
ãã®ä»ãå ´åã«ãã£ã¦ã¯æ©ã¿ãã¤ã³ãã¨ãªããããããªããã¡ãã£ã¨å¤ãã£ãSequelã®ã¯ã»ã«ã¤ãã¦ãã¡ã¢ãæ®ãã¦ããã¾ãã
Sequel::DATABASESã®åå¨
Sequelã§ã¯ãçæãããã¼ã¿ãã¼ã¹ãå ¨ã¦Sequel::DATABASESã¨ããé åã«æ ¼ç´ãã¦ä¿æãã¦ãã¾ãã
注æãããã®ã¯ããããã¯å ã§ãã¼ã¿ãã¼ã¹ãæ±ãå ´åã¯ããããã¯ãæããã¿ã¤ãã³ã°ã§Sequel::DATABASESããã¤ã³ã¹ã¿ã³ã¹ãåé¤ãã¦ãããã®ã«ããããã¯ã使ããã«disconnectã¡ã½ããã§æ¥ç¶ãåã£ãå ´åã¯ãSequel::DATABASESããã¤ã³ã¹ã¿ã³ã¹ãåé¤ãã¦ããããæ®ã£ãã¾ã¾ã«ãªãâ¦ã¨ããç¹ã§ãã
require 'sequel' puts Sequel::DATABASES.length # => 0 Sequel.connect('sqlite://test.db') do |db| puts Sequel::DATABASES.length # => 1 end puts Sequel::DATABASES.length # => 0 db = Sequel.connect('sqlite://test.db') puts Sequel::DATABASES.length # => 1 db.disconnect puts Sequel::DATABASES.length # => 1 Sequel::DATABASES.delete(db) puts Sequel::DATABASES.length # => 0
ãã®å ´åãå½ç¶åç §ãæ®ã£ãã¾ã¾ã«ãªãã®ã§GCã®å¯¾è±¡ã«ãªãã¾ããããã¾ãåè¿°ã®ããã«ãããã©ã«ãã§ã¯ã¢ãã«ã¯æåã«æ¥ç¶ãããã¼ã¿ãã¼ã¹*2ã¨é¢é£ä»ããããããããæãã¬ã¨ããã§å¤ãªæåãããå±éºæ§ãããã¾ãã*3
å¿ è¦ã§ããã°ãä¸ã®ã³ã¼ãã®æå¾ã®ããã«èªåã§Sequel::DATABASESããã¤ã³ã¹ã¿ã³ã¹ãåãé¤ãã¦ããã¨è¯ããã¨æãã¾ãã
ã¢ãã«ã«å®ç¾©ãããã¢ã¯ã»ãµã¡ã½ãã
åè¿°ã®ããã«ãSequelã®ã¢ãã«ã¯å®ç¾©æã«ãã¼ã¿ãã¼ã¹ã«æ¥ç¶æ¸ã¿ã§ããå¿ è¦ãããã¾ãã
ä½æ ãã¨ããã¨ãã¢ãã«ã®å®ç¾©æã«ãã¼ãã«ã«åå¨ããã«ã©ã ãåå¾ããåã«ã©ã ã«å¯¾å¿ããã¢ã¯ã»ãµã¡ã½ãããå®ç¾©ãã¦ããããã§ãã
次ã®ãããªã³ã¼ããå®è¡ãã¦ã¿ãã¨ããããããã§ãã
require 'sequel' require 'logger' db = Sequel.connect('sqlite://test.db') db.loggers << Logger.new($stderr) class User < Sequel::Model; end # ãã®æç¹ã§SQLãçºè¡ãã¦ãã # SQLiteã®å ´å㯠PRAGMA table_info('users')
ãã®å ´åã«ä½ã«æ³¨æãããè¯ããã¨ããã¨ããã¢ãã«ã®å®ç¾©ä»¥éã«è¿½å ã»å¤æ´ãããã«ã©ã ã¯ã¢ã¯ã»ãµã¡ã½ããã«ããã¢ã¯ã»ã¹ãã§ããªããã¨ããç¹ã§ãã
require 'sequel' db = Sequel.connect('sqlite://test.db') class User < Sequel::Model; end puts User.instance_methods.include?(:name) # => true puts User.first.name # ok db.alter_table(:users) do add_column :country, :string, :default => 'jp' end # ããã·ã¥ã«ããã¢ã¯ã»ã¹ã¯ãã¤ã§ãå¯è½ puts User.first[:country] # => jp puts User.instance_methods.include?(:country) # => false puts User.first.country # NoMethodError
ããããã¾ãåé¡ã«ãªãã±ã¼ã¹ã¯ç¡ããããªæ°ããã¾ãããä¸ä¸ãããåé¡ã«ãªãå ´åã¯ãalter_tableå¾ã«å度ã¢ãã«å®ç¾©ããã¦ããã°OKã§ãããã®éã¯remove_constã§ä¸åº¦ã¢ãã«ã¯ã©ã¹ãåé¤ãããã¨ãå¿ããã«ã
*1:å®éã«ä¾å¤ãçºçãã¦ããã®ã¯çæããSQLãå®è¡ããæã§ãã
*2:ã¤ã¾ãSequel::DATABASES.first
*3:ç¹ã«åä½ãã¹ããªã©ã§è¦æ³¨æã