Techioz Blog

Sequelクエリですべてのデータセットを返す方法

概要

Rails スコープは nil ではなく all(ActiveRecord::Relation) を返します。 条件がnilの場合にメソッドチェーンを使用できるようにします。

class MyClass < ApplicationRecord
  scope :my_filter, ->(condition) { where(condition: condition) if condition.present? }
end

MyClass.where(foo: 'foo').my_filter(condition).order(:date)

Sequel にも同様の機能を実装したいのですが、Sequel ではすべてが Array を返すため、このコードはうまく機能しません。 Rails スコープと同様の機能を Sequel で作成するにはどうすればよいですか?

class MyClass < Sequel::Model
  dataset_module do
    def my_filter(condition)
      return all if condition.nil?
      where(condition: condition) 
    end
  end
end

解決策

where はデータセットを返すので、「すべて」も同じオブジェクトを返すことを希望していると思います。

識別したように、すべてが配列を返します。ただし、clone または self を使用してデータセットを取得できます。

したがって、実装を次のように変更するだけです。

class MyClass < Sequel::Model
  datase_module do
    def my_filter(condition)
      return clone if condition.nil?
      where(condition: condition) 
    end
  end
end

動作例: https://replit.com/@engineersmnky/SequelGemRailsScope#main.rb

追加情報:

クローンを選択したのは、ほとんどのクエリ メソッドがこのメソッドを利用しているためです (ActiveRecord での生成と同様)。

データセット#cloneは次のようになります

def clone(opts = nil || (return self))
  c = super(:freeze=>false)
  c.opts.merge!(opts)
  unless opts.each_key{|o| break if COLUMN_CHANGE_OPTS.include?(o)}
    c.clear_columns_cache
  end
  c.freeze
end

clone のメソッド シグネチャは、条件が渡されない場合に実行をショートカットし、単に self を返します。

コメントに記載されているように、

ただし、コメントには次のようにも書かれています

したがって、代わりに return self を使用することも選択できます。*

*上記の例では両方のオプションを実装して、それらの同一の機能に加えて、メソッド シグネチャが非常に興味深いことを示しました。