Search code examples
ruby-on-railsrubysqueel

Finding multiple time slots with Squeel gem


I have a model Planning with a start_time attributes. Say I would like to get all the plannings that are between 9AM and 12PM OR between 6PM and 11PM.

Basically I would do:

Planning.where do 
     (start_time >= @start_time[0]) & (start_time <= @end_time[0]) 
     | 
     (start_time >= @start_time[1]) & (start_time <= @end_time[1])
end

The thing is that the number of time slots varies... Any thougths?

If it can help, I use Squeel gem.

Thanks in advance!


Solution

  • You can do whatever you want within the where block; yet you must return the actual query at the end, because this is what will be used as the where clause.

    So, given an array of times like this:

    times = [ [ '09:00:00', '12:00:00' ], [ '18:00:00', '23:00:00' ] ]
    

    Here is a verbose solution:

    Planning.where do
      query = nil
    
      times.each do |a,b|
        q = (start_time >= a) & (end_time <= b)
    
        if query
          query |= q
        else
          query = q
        end
      end
    
      query
    end
    

    Here is a more clever solution:

    Planning.where do
      times.map { |a,b| (start_time >= a) & (end_time <= b) }.reduce(&:|)
    end
    

    Both do generate the following SQL:

    SELECT "plannings".* FROM "plannings"
    WHERE ((
      ("plannings"."start_time" >= '09:00:00' AND "plannings"."end_time" <= '12:00:00')
      OR
      ("plannings"."start_time" >= '18:00:00' AND "plannings"."end_time" <= '23:00:00')
    ))