Você não precisa reinventar a roda no PostgreSQL, existem dois métodos simples implementados para realizar verificações de sobreposição:
- SQL's
OVERLAPS
operador :
Simples o suficiente,
where("(start_at, end_at) OVERLAPS (?, ?)", range.first, range.last)
No entanto, isso permite que um intervalo seja exatamente após o outro
(em outras palavras, ele verifica início <=tempo
Isso também é simples, geralmente. Mas o PostgreSQL não tem um tipo de intervalo embutido para
time
(no entanto, existem tsrange
, tstzrange
e daterange
para os outros tipos temporais). Você precisa criar este tipo de intervalo para si mesmo:
CREATE TYPE timerange AS RANGE (subtype = time);
Mas depois disso, você pode verificar a sobreposição com
where("timerange(start_at, end_at) && timerange(?, ?)", range.first, range.last)
Prós dos tipos de intervalo:
-
você pode se controlar, como você deseja lidar com os limites do intervalo
f.ex. você pode usartimerange(start_at, end_at, '[]')
para incluir o ponto inicial e o ponto final dos intervalos. Por padrão, inclui o início, mas exclui o ponto final dos intervalos.
-
pode ser indexado, f.ex. com
CREATE INDEX events_times_idx ON events USING GIST (timerange(start_at, end_at));
-
Restrições de exclusão :isso é essencialmente o mesmo, o que você deseja alcançar, mas será aplicado no nível do banco de dados (como,UNIQUE
ou quaisquer outras restrições):
ALTER TABLE events ADD CONSTRAINT events_exclude_overlapping EXCLUDE USING GIST (timerange(start_at, end_at) WITH &&);