From 03fab7360e3673e025f6ca8afc169b2a8ecbb1f2 Mon Sep 17 00:00:00 2001 From: Cameron Reeves Date: Fri, 16 Oct 2026 05:12:52 +1100 Subject: [PATCH] fix(booking): PROJ-1652 hydrate_parents with no parent ids Booking.hydrate_parents queried `id IN ()` when none of the bookings had a parent_id, which Postgres rejects as a syntax error. staff-api calls it for every non-empty result when include_parent_bookings=true, so Concierge's asset request list (type=asset-request, parentless bookings) answered 500. Return the bookings unchanged when there are no parent ids to load. Co-Authored-By: Claude Opus 5.5 --- spec/booking_spec.cr | 22 ++++++++++++++++++++++ src/placeos-models/booking.cr | 2 ++ 2 files changed, 24 insertions(+) diff --git a/spec/booking_spec.cr b/spec/booking_spec.cr index 4a9195cb..13bdec68 100644 --- a/spec/booking_spec.cr +++ b/spec/booking_spec.cr @@ -679,6 +679,28 @@ module PlaceOS::Model child_booking_json["linked_parent_booking"].as_h.should_not be_nil child_booking_json["linked_parent_booking"].as_h["id"].should eq(parent_booking.id) end + it "hydrate_parents returns bookings that have no parent unchanged" do + tenant_id = Generator.tenant.id.not_nil! + user_email = "one@place.tech" + booking = Booking.new( + booking_type: "asset-request", + asset_ids: ["laptop-1"], + booking_start: 1.hour.from_now.to_unix, + booking_end: 2.hours.from_now.to_unix, + user_email: PlaceOS::Model::Email.new(user_email), + user_name: "One", + booked_by_email: PlaceOS::Model::Email.new(user_email), + booked_by_name: "One", + tenant_id: tenant_id, + booked_by_id: "user-1", + history: [] of Booking::History, + ).save! + + hydrated = Booking.hydrate_parents([Booking.find(booking.id)]) + hydrated.map(&.id).should eq([booking.id]) + JSON.parse(hydrated[0].to_json).as_h["linked_parent_booking"]?.try(&.raw).should be_nil + end + it "excludes deleted recurring instances from expand_bookings" do tenant_id = Generator.tenant.id.not_nil! user_email = "steve@place.tech" diff --git a/src/placeos-models/booking.cr b/src/placeos-models/booking.cr index e26fdff0..d8aae01e 100644 --- a/src/placeos-models/booking.cr +++ b/src/placeos-models/booking.cr @@ -809,6 +809,8 @@ module PlaceOS::Model def self.hydrate_parents(bookings : Array(Booking)) parent_ids = bookings.compact_map(&.parent_id).uniq! + # an empty list renders as `IN ()`, which Postgres rejects + return bookings if parent_ids.empty? parents = Booking.where(id: parent_ids).to_a parents_by_id = parents.index_by(&.id) bookings.each do |booking|