updates on the api endpoints on the customer page and more
This commit is contained in:
104
scratch/check_booking_paging.go
Normal file
104
scratch/check_booking_paging.go
Normal file
@@ -0,0 +1,104 @@
|
||||
//go:build ignore
|
||||
|
||||
// Read-only: does the console's page-by-page drain actually see every booking?
|
||||
//
|
||||
// GetAdminBookings runs Offset/Limit with NO ORDER BY. In Postgres that makes
|
||||
// the row order across pages unspecified, so a paged drain can legally return
|
||||
// the same row twice and never return another. This replays the exact 6 pages
|
||||
// the console fetches and compares the union against the table.
|
||||
//
|
||||
// go run scratch/check_booking_paging.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
|
||||
"doormile/config"
|
||||
"doormile/db"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
const pageSize = 100 // what the server actually returns: min(100, requested)
|
||||
|
||||
type row struct{ Bookingid int }
|
||||
|
||||
func main() {
|
||||
_ = godotenv.Load()
|
||||
cfg := config.Load()
|
||||
db.Connect(cfg)
|
||||
if db.DB == nil {
|
||||
log.Fatal("no DB connection")
|
||||
}
|
||||
|
||||
var total int64
|
||||
db.DB.Raw(`SELECT count(*) FROM pickupbookings`).Scan(&total)
|
||||
pages := int((total + pageSize - 1) / pageSize)
|
||||
fmt.Printf("bookings: %d, pages of %d: %d\n\n", total, pageSize, pages)
|
||||
|
||||
// The truth: every id that exists.
|
||||
var all []row
|
||||
db.DB.Raw(`SELECT bookingid FROM pickupbookings`).Scan(&all)
|
||||
truth := map[int]bool{}
|
||||
for _, r := range all {
|
||||
truth[r.Bookingid] = true
|
||||
}
|
||||
|
||||
// The drain, exactly as the console runs it — unordered Offset/Limit.
|
||||
seen := map[int]int{}
|
||||
for p := 0; p < pages; p++ {
|
||||
var page []row
|
||||
db.DB.Raw(`SELECT bookingid FROM pickupbookings LIMIT ? OFFSET ?`, pageSize, p*pageSize).Scan(&page)
|
||||
for _, r := range page {
|
||||
seen[r.Bookingid]++
|
||||
}
|
||||
fmt.Printf(" page %d: %d rows\n", p+1, len(page))
|
||||
}
|
||||
|
||||
missed := []int{}
|
||||
for id := range truth {
|
||||
if seen[id] == 0 {
|
||||
missed = append(missed, id)
|
||||
}
|
||||
}
|
||||
dupes := []int{}
|
||||
for id, n := range seen {
|
||||
if n > 1 {
|
||||
dupes = append(dupes, id)
|
||||
}
|
||||
}
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(missed)))
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(dupes)))
|
||||
|
||||
fmt.Printf("\nunordered drain saw %d distinct of %d\n", len(seen), len(truth))
|
||||
fmt.Printf(" MISSED %d: %v\n", len(missed), head(missed, 20))
|
||||
fmt.Printf(" DUPLICATED %d: %v\n", len(dupes), head(dupes, 20))
|
||||
|
||||
// The same drain with a deterministic order — the proposed fix.
|
||||
seenOrdered := map[int]int{}
|
||||
for p := 0; p < pages; p++ {
|
||||
var page []row
|
||||
db.DB.Raw(`SELECT bookingid FROM pickupbookings ORDER BY bookingid DESC LIMIT ? OFFSET ?`,
|
||||
pageSize, p*pageSize).Scan(&page)
|
||||
for _, r := range page {
|
||||
seenOrdered[r.Bookingid]++
|
||||
}
|
||||
}
|
||||
missedOrdered := 0
|
||||
for id := range truth {
|
||||
if seenOrdered[id] == 0 {
|
||||
missedOrdered++
|
||||
}
|
||||
}
|
||||
fmt.Printf("\nwith ORDER BY bookingid DESC: saw %d distinct, missed %d\n",
|
||||
len(seenOrdered), missedOrdered)
|
||||
}
|
||||
|
||||
func head(xs []int, n int) []int {
|
||||
if len(xs) > n {
|
||||
return xs[:n]
|
||||
}
|
||||
return xs
|
||||
}
|
||||
Reference in New Issue
Block a user