From 0d940e86083ce2d115ad589ce32c2a4c4f5f849e Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Mon, 22 Jun 2026 00:57:55 +0100 Subject: [PATCH] refactor(bookings): use computed booking fields and LATERAL joins Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- backend/handlers/bookings/bookings.go | 37 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/backend/handlers/bookings/bookings.go b/backend/handlers/bookings/bookings.go index c1a8ebe..26780be 100644 --- a/backend/handlers/bookings/bookings.go +++ b/backend/handlers/bookings/bookings.go @@ -428,16 +428,19 @@ func GetAllUserBookingsHandler(w http.ResponseWriter, r *http.Request) { dataQuery := ` SELECT b.id, b.start_time, b.status, b.notes, b.created_at, b.updated_at, b.created_by, - (SELECT total_amount FROM bookings WHERE id = b.id) AS total_amount, - (SELECT COALESCE(SUM(amount), 0) - FROM payments - WHERE booking_id = b.id AND status = 'completed') AS amount_paid, - (SELECT total_duration_minutes FROM bookings WHERE id = b.id) AS duration_minutes, + b.total_amount, + COALESCE(pt.amount_paid, 0) AS amount_paid, + b.total_duration_minutes AS duration_minutes, b.deposit_required, - (SELECT COALESCE(SUM(amount), 0) + COALESCE(pt.pre_start_amount_paid, 0) AS pre_start_amount_paid + FROM bookings b + LEFT JOIN LATERAL ( + SELECT + COALESCE(SUM(amount) FILTER (WHERE status = 'completed'), 0) AS amount_paid, + COALESCE(SUM(amount) FILTER (WHERE status = 'completed' AND created_at < b.start_time), 0) AS pre_start_amount_paid FROM payments - WHERE booking_id = b.id AND status = 'completed' AND created_at < b.start_time) AS pre_start_amount_paid - FROM bookings b` + whereClause + WHERE booking_id = b.id + ) pt ON true` + whereClause dataArgs := make([]interface{}, len(whereArgs)) copy(dataArgs, whereArgs) @@ -662,13 +665,16 @@ func GetAllAdminBookingsHandler(w http.ResponseWriter, r *http.Request) { COALESCE(bt.total_amount, 0) - COALESCE(pt.total_paid, 0) AS amount_due, b.deposit_required, COALESCE(bt.service_count, 0) AS service_count, - (SELECT COALESCE(SUM(p2.amount), 0) - FROM payments p2 - WHERE p2.booking_id = b.id AND p2.status = 'completed' AND p2.created_at < b.start_time) AS pre_start_amount_paid + COALESCE(pre_pay.pre_start_amount_paid, 0) AS pre_start_amount_paid FROM bookings b LEFT JOIN users u ON b.user_id = u.id LEFT JOIN booking_totals bt ON b.id = bt.booking_id LEFT JOIN payment_totals pt ON b.id = pt.booking_id + LEFT JOIN LATERAL ( + SELECT COALESCE(SUM(amount), 0) AS pre_start_amount_paid + FROM payments + WHERE booking_id = b.id AND status = 'completed' AND created_at < b.start_time + ) pre_pay ON true ` var args []interface{} @@ -1734,13 +1740,16 @@ func SearchAdminBookingsHandler(w http.ResponseWriter, r *http.Request) { COALESCE(pt.total_paid, 0) AS amount_paid, COALESCE(bt.total_amount, 0) - COALESCE(pt.total_paid, 0) AS amount_due, b.deposit_required, - (SELECT COALESCE(SUM(p2.amount), 0) - FROM payments p2 - WHERE p2.booking_id = b.id AND p2.status = 'completed' AND p2.created_at < b.start_time) AS pre_start_amount_paid + COALESCE(pre_pay.pre_start_amount_paid, 0) AS pre_start_amount_paid FROM bookings b LEFT JOIN users u ON b.user_id = u.id LEFT JOIN booking_totals bt ON b.id = bt.booking_id LEFT JOIN payment_totals pt ON b.id = pt.booking_id + LEFT JOIN LATERAL ( + SELECT COALESCE(SUM(amount), 0) AS pre_start_amount_paid + FROM payments + WHERE booking_id = b.id AND status = 'completed' AND created_at < b.start_time + ) pre_pay ON true -- NOTE: ILIKE with leading wildcard prevents B-tree index usage. -- At scale, replace with pg_trgm GIN index: CREATE INDEX idx_bookings_search_trgm ON bookings USING GIN (id gin_trgm_ops, notes gin_trgm_ops); -- Also consider indexes on users (n_first_name, n_last_name, fn, email, phone) for the joined table.