How to return all Dataset by Sequel query

64 Views Asked by At

Rails scope returns all(ActiveRecord::Relation) instead of nil. So that I can use method chain when condition is nil.

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

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

I want to implement similar functionality in Sequel, but this code doesn't work well because all in Sequel returns an Array. How can I write a functionality in Sequel similar to Rails scope?

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

There are 1 best solutions below

2
engineersmnky On BEST ANSWER

Since where returns a Dataset I am assuming you would also like "all" to return the same object.

As you have identified all will return an Array; however you can retrieve the Dataset by using either clone or self

So we can just change your implementation to:

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

Working Example: https://replit.com/@engineersmnky/SequelGemRailsScope#main.rb

Additional Info:

I chose clone because most query methods utilize this method (similar to spawn in ActiveRecord).

Dataset#clone looks like this

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's method signature shortcuts execution if no condition is passed and simply returns self.

As stated in the comments

return self used above because clone is called by almost all other query methods, and it is the fastest approach

However the comments do also state

This method should generally not be called directly by user code.

So you could choose to just use return self instead.*

*I implemented both options in my Example above to show their identical functionality plus that method signature is pretty interesting