refactor(scheduling): replace inline duration queries with booking fields
Simplify scheduling handlers by using bookings.total_duration_minutes and bookings.end_time computed columns instead of inline UNION sub-queries for duration calculations. Remove unnecessary ::text casts from end_time columns (using native timestamptz). Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -34,7 +34,7 @@ type DayWorkingHours struct {
|
|||||||
// --- Default Hours Handlers ---
|
// --- Default Hours Handlers ---
|
||||||
func GetDefaultHours(w http.ResponseWriter, r *http.Request) {
|
func GetDefaultHours(w http.ResponseWriter, r *http.Request) {
|
||||||
rows, err := db.Conn.Query(r.Context(), `
|
rows, err := db.Conn.Query(r.Context(), `
|
||||||
SELECT weekday, start_time::text, end_time::text, is_open
|
SELECT weekday, start_time::text, end_time, is_open
|
||||||
FROM working_hours ORDER BY weekday
|
FROM working_hours ORDER BY weekday
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -140,7 +140,7 @@ func GetWorkingHours(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Load default hours
|
// Load default hours
|
||||||
defaultMap := map[int]DefaultHours{}
|
defaultMap := map[int]DefaultHours{}
|
||||||
defRows, _ := db.Conn.Query(r.Context(), `
|
defRows, _ := db.Conn.Query(r.Context(), `
|
||||||
SELECT weekday, start_time::text, end_time::text, is_open
|
SELECT weekday, start_time::text, end_time, is_open
|
||||||
FROM working_hours
|
FROM working_hours
|
||||||
`)
|
`)
|
||||||
for defRows.Next() {
|
for defRows.Next() {
|
||||||
@@ -183,7 +183,7 @@ func GetWorkingHours(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
exHoursMap := map[int]map[int]ExceptionalHours{}
|
exHoursMap := map[int]map[int]ExceptionalHours{}
|
||||||
if len(groupIDs) > 0 {
|
if len(groupIDs) > 0 {
|
||||||
query, args, _ := sqlIn("SELECT group_id, weekday, start_time::text, end_time::text, is_open FROM exceptional_working_hours WHERE group_id IN (%s)", groupIDs)
|
query, args, _ := sqlIn("SELECT group_id, weekday, start_time::text, end_time, is_open FROM exceptional_working_hours WHERE group_id IN (%s)", groupIDs)
|
||||||
rows, _ := db.Conn.Query(r.Context(), query, args...)
|
rows, _ := db.Conn.Query(r.Context(), query, args...)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var h ExceptionalHours
|
var h ExceptionalHours
|
||||||
@@ -365,7 +365,7 @@ func GetAvailableHours(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Load default hours
|
// Load default hours
|
||||||
defaultMap := map[int]DefaultHours{}
|
defaultMap := map[int]DefaultHours{}
|
||||||
defRows, _ := db.Conn.Query(r.Context(), `SELECT weekday, start_time::text, end_time::text, is_open FROM working_hours`)
|
defRows, _ := db.Conn.Query(r.Context(), `SELECT weekday, start_time::text, end_time, is_open FROM working_hours`)
|
||||||
for defRows.Next() {
|
for defRows.Next() {
|
||||||
var d DefaultHours
|
var d DefaultHours
|
||||||
if err := defRows.Scan(&d.Weekday, &d.StartTime, &d.EndTime, &d.IsOpen); err == nil {
|
if err := defRows.Scan(&d.Weekday, &d.StartTime, &d.EndTime, &d.IsOpen); err == nil {
|
||||||
@@ -406,7 +406,7 @@ func GetAvailableHours(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
exHoursMap := map[int]map[int]ExceptionalHours{}
|
exHoursMap := map[int]map[int]ExceptionalHours{}
|
||||||
if len(groupIDs) > 0 {
|
if len(groupIDs) > 0 {
|
||||||
query, args, _ := sqlIn("SELECT group_id, weekday, start_time::text, end_time::text, is_open FROM exceptional_working_hours WHERE group_id IN (%s)", groupIDs)
|
query, args, _ := sqlIn("SELECT group_id, weekday, start_time::text, end_time, is_open FROM exceptional_working_hours WHERE group_id IN (%s)", groupIDs)
|
||||||
rows, _ := db.Conn.Query(r.Context(), query, args...)
|
rows, _ := db.Conn.Query(r.Context(), query, args...)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var h ExceptionalHours
|
var h ExceptionalHours
|
||||||
@@ -427,38 +427,10 @@ func GetAvailableHours(w http.ResponseWriter, r *http.Request) {
|
|||||||
bookingRows, _ := db.Conn.Query(r.Context(), `
|
bookingRows, _ := db.Conn.Query(r.Context(), `
|
||||||
SELECT
|
SELECT
|
||||||
b.start_time,
|
b.start_time,
|
||||||
COALESCE((SELECT SUM(dur) FROM (
|
b.total_duration_minutes AS total_duration
|
||||||
SELECT CASE
|
|
||||||
WHEN bs.override_duration_minutes IS NOT NULL AND bs.override_duration_minutes > 0
|
|
||||||
THEN bs.override_duration_minutes
|
|
||||||
ELSE s.duration_minutes
|
|
||||||
END AS dur
|
|
||||||
FROM booking_services bs LEFT JOIN services s ON bs.service_id = s.id WHERE bs.booking_id = b.id
|
|
||||||
UNION ALL
|
|
||||||
SELECT CASE
|
|
||||||
WHEN bcs.override_duration_minutes IS NOT NULL AND bcs.override_duration_minutes > 0
|
|
||||||
THEN bcs.override_duration_minutes
|
|
||||||
ELSE cs.duration_minutes
|
|
||||||
END
|
|
||||||
FROM booking_custom_services bcs LEFT JOIN custom_services cs ON bcs.custom_service_id = cs.id WHERE bcs.booking_id = b.id
|
|
||||||
) sub), 0) AS total_duration
|
|
||||||
FROM bookings b
|
FROM bookings b
|
||||||
WHERE b.start_time < $2
|
WHERE b.start_time < $2
|
||||||
AND b.start_time + (COALESCE((SELECT SUM(dur) FROM (
|
AND b.end_time > $1
|
||||||
SELECT CASE
|
|
||||||
WHEN bs.override_duration_minutes IS NOT NULL AND bs.override_duration_minutes > 0
|
|
||||||
THEN bs.override_duration_minutes
|
|
||||||
ELSE s.duration_minutes
|
|
||||||
END AS dur
|
|
||||||
FROM booking_services bs LEFT JOIN services s ON bs.service_id = s.id WHERE bs.booking_id = b.id
|
|
||||||
UNION ALL
|
|
||||||
SELECT CASE
|
|
||||||
WHEN bcs.override_duration_minutes IS NOT NULL AND bcs.override_duration_minutes > 0
|
|
||||||
THEN bcs.override_duration_minutes
|
|
||||||
ELSE cs.duration_minutes
|
|
||||||
END
|
|
||||||
FROM booking_custom_services bcs LEFT JOIN custom_services cs ON bcs.custom_service_id = cs.id WHERE bcs.booking_id = b.id
|
|
||||||
) sub), 0) * INTERVAL '1 minute') > $1
|
|
||||||
AND b.status NOT IN ('client_cancelled', 'we_cancelled', 'no_show', 'pending_release', 'deposit_lapsed')
|
AND b.status NOT IN ('client_cancelled', 'we_cancelled', 'no_show', 'pending_release', 'deposit_lapsed')
|
||||||
ORDER BY b.start_time
|
ORDER BY b.start_time
|
||||||
`, start, end)
|
`, start, end)
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func ListExceptionalGroups(w http.ResponseWriter, r *http.Request) {
|
|||||||
for i := range groups {
|
for i := range groups {
|
||||||
// Load 7-day hours
|
// Load 7-day hours
|
||||||
hoursRows, err := db.Conn.Query(r.Context(), `
|
hoursRows, err := db.Conn.Query(r.Context(), `
|
||||||
SELECT id, weekday, start_time::text, end_time::text, is_open
|
SELECT id, weekday, start_time::text, end_time, is_open
|
||||||
FROM exceptional_working_hours
|
FROM exceptional_working_hours
|
||||||
WHERE group_id=$1 ORDER BY weekday
|
WHERE group_id=$1 ORDER BY weekday
|
||||||
`, groups[i].ID)
|
`, groups[i].ID)
|
||||||
|
|||||||
@@ -380,16 +380,8 @@ func AnonymizeStaleGuestAccounts(ctx context.Context) error {
|
|||||||
data_retention_consent = FALSE,
|
data_retention_consent = FALSE,
|
||||||
updated_at = NOW()
|
updated_at = NOW()
|
||||||
WHERE account_role = 'guest'
|
WHERE account_role = 'guest'
|
||||||
AND id NOT IN (
|
AND NOT EXISTS (SELECT 1 FROM bookings WHERE user_id = users.id AND status IN ('pending', 'confirmed'))
|
||||||
SELECT user_id FROM bookings WHERE status IN ('pending', 'confirmed')
|
AND EXISTS (SELECT 1 FROM bookings WHERE user_id = users.id GROUP BY user_id HAVING MAX(start_time) < NOW() - INTERVAL '6 months')
|
||||||
)
|
|
||||||
AND id IN (
|
|
||||||
SELECT user_id
|
|
||||||
FROM bookings
|
|
||||||
WHERE user_id IS NOT NULL
|
|
||||||
GROUP BY user_id
|
|
||||||
HAVING MAX(start_time) < NOW() - INTERVAL '6 months'
|
|
||||||
)
|
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user