SequelはJDBC以外ならいい

今度はSequelを試してみます。まずは、PostgreSQLにpostgres-prでつないでみます。

require 'rubygems'
require 'sequel'

DB = Sequel.postgres(:database => 'postgres',
                     :user => 'postgres', :password => 'postgres')

DB[:user_data].all.each do |user_data|
  puts "#{user_data[:user_id]} #{user_data[:user_account].kconv(Kconv::SJIS, Kconv::UTF8)}"
end

モデルを作らなくても使えるのが、いいですね。
ActiveRecordの時と同様、kconvによるSJIS変換は無視してください。

JDBCだとこんな感じ。

require 'rubygems'
require 'sequel'

DB = Sequel.jdbc(:uri => 'jdbc:postgresql:postgres',
                 :user => 'postgres', :password => 'postgres')

Sequel::JDBC.load_driver('org.postgresql.Driver')

DB["SELECT * FROM user_data"].all.each do |user_data|
  puts "#{user_data[:user_id]} #{user_data[:user_account].kconv(Kconv::SJIS, Kconv::UTF8)}"
end; nil

JDBCドライバの登録が美しくありません。どなたか他に方法がありましたら教えてください。
また、JDBCの場合、シンボルによる表指定ができません。DB["SELECT * FROM user_data"].allは実行できても、DB[:user_data].allはエラーになります。

DB["SELECT * FROM user_data"].all    # success
DB[:user_data].all                   # fail

なぜかというと、JDBC接続時にDB[:user_data].allによって作られるSQL文が SELECT * FROM \"USER_DATA\" になってしまうからなんですよね。PostgreSQLでは表名の大文字と小文字を区別し、デフォルトでは小文字なので、USER_DATAなんて表はないということになってしまうのです。

sequel_core/sql.rbに以下のような記述がありました。

    # This method quotes the given name with the SQL standard double quote. 
    # It uppercases the name given to conform with the SQL standard. This
    # should be overridden by subclasses to provide quoting not matching the
    # SQL standard, such as backtick (used by MySQL and SQLite), or where
    # lowercase is the default for unquoted identifiers (PostgreSQL).
    #
    # If you are using a database such as Oracle that defaults to uppercase
    # but you are using lower case identifiers, you should override this
    # method to not upcase the name for those identifiers.
    def quoted_identifier(name)
      "\"#{name.to_s.upcase}\""
    end

これが原因らしいぞ。デフォルトで大文字にしちゃうわけね。adapters/postgres.rbではquoted_identifierをオーバーライドしてupcaseを消し去るのでDB[:user_data].allはエラーにならないが、JDBCだと大文字の表を探しちゃうわけか。

というわけで、回避策としては、シンボルを使わないか、Sequel::JDBC::Datasetを書き換えるかです。後者だと、以下のようになります。

require 'rubygems'
require 'sequel'

module Sequel
  module JDBC
    class Dataset < Sequel::Dataset
      def quoted_identifier(name)
        "\"#{name.to_s}\""
      end
    end
  end
end

DB = Sequel.jdbc(:uri => 'jdbc:postgresql:postgres',
                 :user => 'postgres', :password => 'postgres')

Sequel::JDBC.load_driver('org.postgresql.Driver')

DB[:user_data].all.each do |user_data|
  puts "#{user_data[:user_id]} #{user_data[:user_account].kconv(Kconv::SJIS, Kconv::UTF8)}"
end

他にも罠がありそうで、JDBC接続でSequelを使うのは危険な感じがします。