Позвольте мне предварить это, признав, что существует несколько различных способов достижения перекрытия, но что касается этого вопроса, я специально пытаюсь выяснить, как использовать фактический метод PostgreSQL OVERLAPS с Arel. С этой целью этот вопрос больше связан с получением лучшего понимания Arel, чем с реализацией некоторой версии перекрывающейся функциональности.
Я использую Rails 5.1
Это оператор SQL, который я пытаюсь продублировать в Arel:
SELECT DISTINCT
venues.id
FROM
venues
LEFT OUTER JOIN
reservations
ON
venues.id = reservations.venue_id
WHERE (
(reservations.venue_id IS NULL)
OR NOT (
(reservations.start, reservations.end)
OVERLAPS
(DATE '2018-09-02', DATE '2018-09-03')
)
)
В настоящее время у меня есть следующее, что генерирует вышеуказанное:
Venue.arel_table.project(
Venue.arel_table[:id]
).from(
Venue.arel_table
).join(
Reservation.arel_table, Arel::Nodes::OuterJoin
).on(
Venue.arel_table[:id].eq(Reservation.arel_table[:venue_id])
).where(
Arel::Nodes::Grouping.new(
Reservation.arel_table[:venue_id].eq(nil)
).or(
Arel.sql("NOT ((reservations.start, reservations.end) OVERLAPS (DATE '2018-09-02', DATE '2018-09-03'))")
)
)
Однако мне кажется, что есть способ сделать это лучше; Я пытался реализовать Arel::Nodes::NamedFunction для OVERLAPS, однако, когда я заменяю приведенный выше оператор Arel.sql следующим, он не выполняет SQL должным образом:
Arel::Nodes::NamedFunction.new(
'OVERLAPS',
[
Arel::Nodes::SqlLiteral.new('(reservations.start, reservations.end)'),
Arel::Nodes::SqlLiteral.new("(DATE '2018-09-02', DATE '2018-09-03')")
]
)
приводит к
...OVERLAPS ((reservations.start, reservations.end), (DATE '2018-09-02', DATE '2018-09-03'))
Каков правильный метод реализации OVERLAPS с Arel?





Поскольку OVERLAPS является оператором SQL, я считаю, что следующее выражение должно работать:
Arel::Nodes::InfixOperation.new(
'OVERLAPS',
Arel::Nodes::SqlLiteral.new('(reservations.start, reservations.end)'),
Arel::Nodes::SqlLiteral.new("(DATE '2018-09-02', DATE '2018-09-03')"
)