Корректное использование Range.overlaps в SQLModel/SQLAlchemy

Вопрос или проблема

У меня есть следующий код:

overlapping: Sequence[Booking] = (
    await session.exec(
        select(Booking)
        .join(Apartment)
        .join(User)
        .where(
            Range(
                lower=booking.end_date,
                upper=booking.cleaning_deadline,
                bounds="[]",
            ).overlaps(Range(Booking.end_date, Booking.cleaning_deadline))
        )
    )
).all()

Он выдает следующий вывод:

Traceback (most recent call last):
  ...
  File "/home/jakov/Projects/intis/src/web/server.py", line 120, in import_calendar
    ).overlaps(Range(Booking.end_date, Booking.cleaning_deadline))
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jakov/.cache/pypoetry/virtualenvs/intis-I4I4liA8-py3.12/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/ranges.py", line 381, in overlaps
    self._compare_edges(slower, slower_b, olower, olower_b) >= 0
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jakov/.cache/pypoetry/virtualenvs/intis-I4I4liA8-py3.12/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/ranges.py", line 274, in _compare_edges
    if value1 < value2:  # type: ignore
       ^^^^^^^^^^^^^^^
  File "/home/jakov/.cache/pypoetry/virtualenvs/intis-I4I4liA8-py3.12/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 3938, in __bool__
    raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined

В общем, я хочу выполнить этот запрос через ORM:

select * from booking b where (b.end_date , b.cleaning_deadline) overlaps (?, ?);

Я протестировал это в базе данных, и это работает, но я не могу заставить SQLAlchemy сделать то, что я хочу.

Ответ или решение

Ваша проблема связана с тем, что вы пытаетесь использовать метод overlaps из библиотеки SQLAlchemy для создания запроса, который проверяет, пересекаются ли два диапазона дат. Судя по вашему коду и стеку вызовов, возникает ошибка, связанная с тем, как вы определяете диапазоны в запросе.

Чтобы корректно использовать Range.overlaps, вам нужно убедиться, что вы правильно задаете стек диапазонов для сравнения. Ваша цель состоит в том, чтобы проверить, пересекаются ли диапазоны дат, которые вы хотите получить.

Вот исправленный вариант вашего кода с пояснениями:

from sqlalchemy import select
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.dialects.postgresql import RANGE
from typing import Sequence

# Предполагая, что Booking, Apartment и User уже определены как модели SQLAlchemy

async def get_overlapping_bookings(session: AsyncSession, booking: Booking) -> Sequence[Booking]:
    overlapping: Sequence[Booking] = (
        await session.execute(
            select(Booking)
            .join(Apartment)
            .join(User)
            .where(
                RANGE(
                    lower=booking.end_date,
                    upper=booking.cleaning_deadline,
                    bounds="[]"
                ).overlaps(RANGE(Booking.end_date, Booking.cleaning_deadline, bounds="[]"))
            )
        )
    ).scalars().all()

    return overlapping

Объяснения:

  1. Правильная структура запроса: Используйте метод execute для выполнения SQL-запроса вместо exec. Также убедитесь, что используете scalars() для извлечения результатов из запроса.

  2. Параметры диапазона: Убедитесь, что вы задаете границы одинаково для обоих диапазонов. Вы используете bounds="[]", что значит, что границы являются закрытыми (включают конечные значения). Если ваши данные могут включать границы (например, если end_date одной брони совпадает с cleaning_deadline другой), вам нужно учесть это.

  3. Асинхронная работа с сессией: Если вы используете AsyncSession, не забудьте правильно его настроить и закрыть. В данном примере предполагается, что session передается в функцию как асинхронная сессия.

  4. Ошибка, связанная с булевым значением: причиной ошибки может быть некорректное использование или сравнение объектов диапазонов. Убедитесь, что вы используете их правильно и всегда возвращаете корректные объекты.

Таким образом, исправив вышеописанные моменты, вы сможете успешно выполнять запрос для поиска пересекающихся резервирований.

Оцените материал
Добавить комментарий

Капча загружается...