Поиск нескольких временных интервалов с помощью драгоценного камня Squeel

У меня есть модель Planning с атрибутами start_time. Скажем, я хотел бы получить все планы с 9:00 до 12:00 ИЛИ с 18:00 до 23:00.

В основном я бы сделал:

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

Дело в том, что количество временных интервалов разное... Есть мысли?

Если это может помочь, я использую Squeel gem.

Заранее спасибо!


person Nima Izadi    schedule 22.11.2012    source источник


Ответы (3)


Вы можете делать все, что хотите, в блоке where; тем не менее, вы должны вернуть фактический запрос в конце, потому что это то, что будет использоваться в качестве предложения where.

Итак, учитывая такой массив времени:

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

Вот подробное решение:

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

Вот более умное решение:

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

Оба генерируют следующий 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')
))
person Julien Portalier    schedule 24.11.2012
comment
Классная штука - жаль мало примеров по сложным запросам со SQUEEL! - person prikha; 10.04.2013

Можете ли вы скопировать и вставить SQL, сгенерированный вашим рубиновым кодом, пожалуйста?

РЕДАКТИРОВАТЬ

Хорошо, теперь я понимаю вашу проблему, и вопрос был не ясен. Если вы хотите, чтобы код оставался читаемым, вам следует использовать ARel вместо squeel в этом случае (по крайней мере, не DSL, не предназначенный для этого). Вы должны иметь возможность применить функцию карты, а затем соединить все с помощью ИЛИ.

person Pierre Schambacher    schedule 23.11.2012
comment
Вот запрос, если я делаю так, как говорит systho. Он поставит оператор «И» вместо «ИЛИ» SELECT "courses".* FROM "courses" INNER JOIN "plannings" ON "plannings"."course_id" = "courses"."id" WHERE (("plannings"."start_time" >= '2000-01-01 09:00:00.000000' AND "plannings"."start_time" <= '2000-01-01 12:00:00.000000')) AND (("plannings"."start_time" >= '2000-01-01 12:00:00.000000' AND "plannings"."start_time" <= '2000-01-01 14:00:00.000000')) - person Nima Izadi; 23.11.2012

Метод Squeel where() возвращает AR:Relation, не так ли?

Затем вы сможете связать вызовы where() :

finder = Planing.scoped 
time_slots.each do |start_time, end_time|
    finder = finder.where{(start_time >= my{start_time}) & (start_time <= my{end_time}) }
end

Я не пробовал этот код, но не вижу причин, по которым он не сработает.

РЕДАКТИРОВАТЬ: Как вы сказали, это свяжет условия с AND , а не OR

можно попробовать следующее?

Planning.where do 
    time_slots.inject(false) do |memo, time_slot| 
        memo | (start_time >= time_slot.first) & (start_time <= time_slot.last)
    end
end 

Это может быть слишком много магии для работы с instance_eval squeel, но попробуйте :)

person systho    schedule 23.11.2012
comment
Это не работает, потому что в запросе будет использоваться оператор AND, а не оператор OR: (("plannings"."start_time" >= '2000-01-01 09:00:00.000000' AND "plannings"."start_time" <= '2000-01-01 12:00:00.000000')) AND (("plannings"."start_time" >= '2000-01-01 12:00:00.000000' AND "plannings"."start_time" <= '2000-01-01 14:00:00.000000')) - person Nima Izadi; 23.11.2012
comment
Я получаю NoMethodError (undefined method inject' для nil:NilClass)`:/ - person Nima Izadi; 23.11.2012
comment
Я предполагал, что вы можете поместить все ваши start_time и end_time в массив =› time_slot = [[start_time1, end_time1], [start_time2, end_time2], [start_time3, end_time3]] - person systho; 24.11.2012
comment
Я так и сделал, но может что-то упустил. - person Nima Izadi; 24.11.2012
comment
Хорошо, в любом случае ответ от Жюльена был чище :) - person systho; 24.11.2012