offices that has_manymeeting_rooms meeting_rooms that has_manybookings
meeting_rooms office_id FK to offices
bookings meeting_room_id FK to meeting_rooms
I managed to get only the booked meeting_rooms by office_id within start_time and end_time
def list_booked_meeting_rooms(office_id, start_time, end_time) do
query = from office in Office,
where: office.id == ^office_id,
join: meeting_rooms in assoc(office, :meeting_rooms),
join: bookings in assoc(meeting_rooms, :bookings),
where: bookings.start_time < ^end_time and ^start_time < bookings.end_time,
select: meeting_rooms
Repo.all(query)
end
Now I need to figure out how to get a list of available meeting rooms within the start_time and end_time which the reverse of list_booked_meeting_rooms where it will return a list of unbooked meeting_rooms
I tried doing it this way, but it does not work obviously. I’m not sure how to get the correct result
def list_available_meeting_rooms(office_id, start_time, end_time) do
query = from office in Office,
where: office.id == ^office_id,
join: meeting_rooms in assoc(office, :meeting_rooms),
join: bookings in assoc(meeting_rooms, :bookings),
where: not (bookings.start_time < ^end_time and ^start_time < bookings.end_time) and is_nil(bookings),
select: meeting_rooms
Repo.all(query)
end
I tried it out, but it did not work because of the or in the where statement
is_nil(bookings.id)
this statement will only be true if there no booking has been made
not fragment("(?, ?) OVERLAPS (?, ?)", bookings.start_time, booking.end_time, ^start_time, ^end_time)
this statement will return true if there is a past booking or future booking
btw, bookings.start_time < ^end_time and ^start_time < bookings.end_time return the same result as OVERLAPS. you can check here
the condition should be wheremeeting_room do not have booking at start_time and end_time period but I’m not sure how to build the query
Keep in mind that this kind of query is subject to race conditions. Two clients could make this query, and the time span would show as open, and then both can attempt to reserve the spot. You’ll want to make sure that the part of the code that actually make the reservation serializes access to that timeslot.
That’s true. But it only cater for case if there’s no booking.
So if there’s an existing booking in the future or in the past this won’t work.
Solve one case through. Progress!
I managed to get the list of available meeting_room by changing the query a bit
from office in Office,
where: office.id == ^office_id,
join: meeting_rooms in assoc(office, :meeting_rooms),
where: fragment("NOT EXISTS (SELECT * FROM bookings WHERE start_time < ? AND ? < end_time)", ^selected_end_time, ^selected_start_time),
select: meeting_rooms
It worked when there is no booking at selected_end_time and selected_start_time which returns 2 available meeting_rooms
When creating a booking at selected_end_time and selected_start_time, it will return empty which is wrong and should return 1 available meeting_rooms
Not sure what went wrong