Implement hybrid filtering strategy for parks and rides

- Added comprehensive documentation for hybrid filtering implementation, including architecture, API endpoints, performance characteristics, and usage examples.
- Developed a hybrid pagination and client-side filtering recommendation, detailing server-side responsibilities and client-side logic.
- Created a test script for hybrid filtering endpoints, covering various test cases including basic filtering, search functionality, pagination, and edge cases.
This commit is contained in:
pacnpal
2025-09-14 21:07:17 -04:00
parent 0fd6dc2560
commit 35f8d0ef8f
42 changed files with 8490 additions and 224 deletions

408
test_hybrid_endpoints.sh Executable file
View File

@@ -0,0 +1,408 @@
#!/bin/bash
# ThrillWiki Hybrid Filtering Endpoints Test Script
# Tests the newly synchronized Parks and Rides hybrid filtering endpoints
#
# Usage: ./test_hybrid_endpoints.sh [BASE_URL]
# Default BASE_URL: http://localhost:8000
set -e
# Configuration
BASE_URL="${1:-http://localhost:8000}"
VERBOSE=true
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Helper functions
print_header() {
local title="$1"
local level="${2:-1}"
case $level in
1) echo -e "\n${BLUE}================================================================================${NC}"
echo -e "${BLUE}$title${NC}"
echo -e "${BLUE}================================================================================${NC}" ;;
2) echo -e "\n${CYAN}--------------------------------------------------------------------------------${NC}"
echo -e "${CYAN}$title${NC}"
echo -e "${CYAN}--------------------------------------------------------------------------------${NC}" ;;
3) echo -e "\n${YELLOW}$title${NC}"
echo -e "${YELLOW}$(echo "$title" | sed 's/./~/g')${NC}" ;;
esac
}
print_endpoint() {
local method="$1"
local url="$2"
echo -e "\n${PURPLE}🔗 ENDPOINT:${NC} ${GREEN}$method${NC} $url"
}
print_description() {
local desc="$1"
echo -e "${CYAN}📋 DESCRIPTION:${NC} $desc"
}
make_request() {
local method="$1"
local url="$2"
local description="$3"
print_endpoint "$method" "$url"
print_description "$description"
echo -e "\n${YELLOW}📤 REQUEST:${NC}"
echo "curl -X $method \\"
echo " -H 'Accept: application/json' \\"
echo " -H 'Content-Type: application/json' \\"
echo " '$url'"
echo -e "\n${YELLOW}📥 RESPONSE:${NC}"
# Make the actual request
response=$(curl -s -w "\n%{http_code}" -X "$method" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
"$url")
# Extract status code and body
status_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')
# Print status
if [[ "$status_code" -ge 200 && "$status_code" -lt 300 ]]; then
echo -e "${GREEN}✅ SUCCESS: HTTP $status_code${NC}"
else
echo -e "${RED}❌ ERROR: HTTP $status_code${NC}"
fi
# Pretty print JSON response
if command -v jq >/dev/null 2>&1; then
echo "$body" | jq '.'
else
echo "$body"
fi
# Extract and display key metrics
if command -v jq >/dev/null 2>&1 && [[ "$status_code" -ge 200 && "$status_code" -lt 300 ]]; then
echo -e "\n${CYAN}📊 RESPONSE SUMMARY:${NC}"
# Total count
total_count=$(echo "$body" | jq -r '.total_count // empty')
if [[ -n "$total_count" ]]; then
echo -e " • Total Count: ${GREEN}$total_count${NC}"
fi
# Strategy
strategy=$(echo "$body" | jq -r '.strategy // empty')
if [[ -n "$strategy" ]]; then
if [[ "$strategy" == "client_side" ]]; then
echo -e " • Strategy: ${GREEN}🖥️ $strategy${NC}"
else
echo -e " • Strategy: ${BLUE}🌐 $strategy${NC}"
fi
fi
# Has more
has_more=$(echo "$body" | jq -r '.has_more // empty')
if [[ -n "$has_more" ]]; then
if [[ "$has_more" == "true" ]]; then
echo -e " • Has More: ${YELLOW}➡️ $has_more${NC}"
else
echo -e " • Has More: ${GREEN}🏁 $has_more${NC}"
fi
fi
# Next offset
next_offset=$(echo "$body" | jq -r '.next_offset // empty')
if [[ -n "$next_offset" && "$next_offset" != "null" ]]; then
echo -e " • Next Offset: ${CYAN}$next_offset${NC}"
fi
# Data counts
parks_count=$(echo "$body" | jq -r '.parks | length // empty' 2>/dev/null)
if [[ -n "$parks_count" ]]; then
echo -e " • Parks Returned: ${GREEN}$parks_count${NC}"
fi
rides_count=$(echo "$body" | jq -r '.rides | length // empty' 2>/dev/null)
if [[ -n "$rides_count" ]]; then
echo -e " • Rides Returned: ${GREEN}$rides_count${NC}"
fi
# Filter metadata summary
if echo "$body" | jq -e '.filter_metadata' >/dev/null 2>&1; then
echo -e " • Filter Metadata: ${GREEN}✅ Available${NC}"
# Count categorical options
countries=$(echo "$body" | jq -r '.filter_metadata.categorical.countries | length // 0' 2>/dev/null)
states=$(echo "$body" | jq -r '.filter_metadata.categorical.states | length // 0' 2>/dev/null)
categories=$(echo "$body" | jq -r '.filter_metadata.categorical.categories | length // 0' 2>/dev/null)
if [[ "$countries" -gt 0 ]]; then
echo -e " - Countries: ${CYAN}$countries${NC}"
fi
if [[ "$states" -gt 0 ]]; then
echo -e " - States: ${CYAN}$states${NC}"
fi
if [[ "$categories" -gt 0 ]]; then
echo -e " - Categories: ${CYAN}$categories${NC}"
fi
fi
fi
echo -e "\n${PURPLE}$(printf '%.0s-' {1..80})${NC}"
}
# Main test execution
main() {
print_header "THRILLWIKI HYBRID FILTERING ENDPOINTS TEST SUITE" 1
echo -e "Testing endpoints at: ${GREEN}$BASE_URL${NC}"
echo -e "Timestamp: ${CYAN}$(date)${NC}"
# Check if server is running
echo -e "\n${YELLOW}🔍 Checking server availability...${NC}"
if ! curl -s --connect-timeout 5 "$BASE_URL" >/dev/null; then
echo -e "${RED}❌ Server not available at $BASE_URL${NC}"
echo -e "${YELLOW}💡 Make sure to start the Django server first:${NC}"
echo -e " cd backend && uv run manage.py runserver_plus"
exit 1
fi
echo -e "${GREEN}✅ Server is running${NC}"
# ========================================================================
# PARKS HYBRID FILTERING TESTS
# ========================================================================
print_header "PARKS HYBRID FILTERING TESTS" 1
# Test 1: Basic Parks Hybrid Filtering
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/" \
"Basic hybrid filtering with no parameters - demonstrates automatic strategy selection"
# Test 2: Parks with Search Filter
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?search=disney" \
"Search for parks containing 'disney' - tests full-text search functionality"
# Test 3: Parks with Status Filter
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?status=OPERATING,CLOSED_TEMP" \
"Filter parks by multiple statuses - tests comma-separated list parameters"
# Test 4: Parks with Geographic Filters
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?country=United%20States&state=Florida,California" \
"Filter parks by country and multiple states - tests geographic filtering"
# Test 5: Parks with Numeric Range Filters
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?opening_year_min=1990&opening_year_max=2020&rating_min=4.0" \
"Filter parks by opening year range and minimum rating - tests numeric range filtering"
# Test 6: Parks with Size and Ride Count Filters
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?size_min=100&ride_count_min=10&coaster_count_min=5" \
"Filter parks by minimum size, ride count, and coaster count - tests park statistics filtering"
# Test 7: Parks with Operator Filter
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?operator=disney,universal" \
"Filter parks by operator slugs - tests company relationship filtering"
# Test 8: Parks Progressive Loading (with offset)
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?offset=50" \
"Progressive loading starting at offset 50 - tests server-side pagination"
# Test 9: Parks Filter Metadata
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/filter-metadata/" \
"Get comprehensive filter metadata for parks - provides all available filter options and ranges"
# Test 10: Parks Scoped Filter Metadata
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/filter-metadata/?scoped=true&country=United%20States" \
"Get filter metadata scoped to US parks - demonstrates dynamic metadata based on current filters"
# ========================================================================
# RIDES HYBRID FILTERING TESTS
# ========================================================================
print_header "RIDES HYBRID FILTERING TESTS" 1
# Test 1: Basic Rides Hybrid Filtering
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/" \
"Basic hybrid filtering with no parameters - demonstrates automatic strategy selection for rides"
# Test 2: Rides with Search Filter
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?search=coaster" \
"Search for rides containing 'coaster' - tests full-text search across ride names and descriptions"
# Test 3: Rides with Category Filter
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?category=RC,DR" \
"Filter rides by categories (Roller Coaster, Dark Ride) - tests ride category filtering"
# Test 4: Rides with Status and Park Filters
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?status=OPERATING&park_slug=cedar-point" \
"Filter operating rides at Cedar Point - tests status and park-specific filtering"
# Test 5: Rides with Manufacturer and Designer Filters
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?manufacturer=bolliger-mabillard&designer=bolliger-mabillard" \
"Filter rides by B&M as manufacturer and designer - tests company relationship filtering"
# Test 6: Rides with Roller Coaster Specific Filters
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?roller_coaster_type=INVERTED,FLYING&track_material=STEEL&has_inversions=true" \
"Filter inverted/flying steel coasters with inversions - tests roller coaster specific attributes"
# Test 7: Rides with Height and Speed Filters
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?height_ft_min=200&speed_mph_min=70&inversions_min=4" \
"Filter tall, fast coasters with multiple inversions - tests numeric performance filtering"
# Test 8: Rides with Rating and Capacity Filters
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?rating_min=4.5&capacity_min=1000&opening_year_min=2000" \
"Filter highly-rated, high-capacity modern rides - tests quality and operational metrics"
# Test 9: Rides with Height Requirement Filters
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?height_requirement_min=48&height_requirement_max=54" \
"Filter rides by height requirements (48-54 inches) - tests accessibility filtering"
# Test 10: Rides Progressive Loading
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?offset=25&category=RC" \
"Progressive loading of roller coasters starting at offset 25 - tests server-side pagination with filters"
# Test 11: Rides Filter Metadata
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/filter-metadata/" \
"Get comprehensive filter metadata for rides - provides all available filter options and ranges"
# Test 12: Rides Scoped Filter Metadata
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/filter-metadata/?scoped=true&category=RC" \
"Get filter metadata scoped to roller coasters - demonstrates dynamic metadata for specific categories"
# ========================================================================
# COMPLEX COMBINATION TESTS
# ========================================================================
print_header "COMPLEX COMBINATION TESTS" 1
# Test 1: Parks with All Filter Types
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?search=theme&status=OPERATING&country=United%20States&opening_year_min=1980&rating_min=4.0&size_min=50&ride_count_min=20" \
"Complex parks query combining search, status, geographic, temporal, rating, and size filters"
# Test 2: Rides with All Filter Types
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?search=steel&category=RC&status=OPERATING&roller_coaster_type=SITDOWN&track_material=STEEL&height_ft_min=100&speed_mph_min=50&rating_min=4.0&has_inversions=false" \
"Complex rides query combining search, category, status, coaster type, materials, performance, and rating filters"
# ========================================================================
# EDGE CASE TESTS
# ========================================================================
print_header "EDGE CASE TESTS" 1
# Test 1: Empty Results
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?search=nonexistentpark12345" \
"Search for non-existent park - tests empty result handling"
# Test 2: Invalid Parameters
make_request "GET" \
"$BASE_URL/api/v1/rides/hybrid/?height_ft_min=invalid&rating_min=15" \
"Invalid numeric parameters - tests parameter validation and error handling"
# Test 3: Large Offset
make_request "GET" \
"$BASE_URL/api/v1/parks/hybrid/?offset=99999" \
"Very large offset value - tests pagination boundary handling"
# ========================================================================
# PERFORMANCE COMPARISON TESTS
# ========================================================================
print_header "PERFORMANCE COMPARISON TESTS" 1
echo -e "\n${CYAN}📊 Testing response times for different strategies...${NC}"
# Time the requests
echo -e "\n${YELLOW}⏱️ Timing Parks Hybrid Endpoint:${NC}"
time curl -s -o /dev/null "$BASE_URL/api/v1/parks/hybrid/"
echo -e "\n${YELLOW}⏱️ Timing Rides Hybrid Endpoint:${NC}"
time curl -s -o /dev/null "$BASE_URL/api/v1/rides/hybrid/"
echo -e "\n${YELLOW}⏱️ Timing Parks Filter Metadata:${NC}"
time curl -s -o /dev/null "$BASE_URL/api/v1/parks/hybrid/filter-metadata/"
echo -e "\n${YELLOW}⏱️ Timing Rides Filter Metadata:${NC}"
time curl -s -o /dev/null "$BASE_URL/api/v1/rides/hybrid/filter-metadata/"
# ========================================================================
# SUMMARY
# ========================================================================
print_header "TEST SUITE SUMMARY" 1
echo -e "${GREEN}✅ Test suite completed successfully!${NC}"
echo -e "\n${CYAN}📋 ENDPOINTS TESTED:${NC}"
echo -e " • Parks Hybrid Filtering: ${GREEN}/api/v1/parks/hybrid/${NC}"
echo -e " • Parks Filter Metadata: ${GREEN}/api/v1/parks/hybrid/filter-metadata/${NC}"
echo -e " • Rides Hybrid Filtering: ${GREEN}/api/v1/rides/hybrid/${NC}"
echo -e " • Rides Filter Metadata: ${GREEN}/api/v1/rides/hybrid/filter-metadata/${NC}"
echo -e "\n${CYAN}🔍 KEY FEATURES DEMONSTRATED:${NC}"
echo -e " • Automatic strategy selection (client-side vs server-side)"
echo -e " • Progressive loading for large datasets"
echo -e " • Comprehensive filter options (17+ parameters per domain)"
echo -e " • Dynamic filter metadata generation"
echo -e " • Consistent response formats across domains"
echo -e " • Full-text search capabilities"
echo -e " • Numeric range filtering"
echo -e " • Multi-value parameter support"
echo -e " • Geographic and temporal filtering"
echo -e " • Roller coaster specific filtering"
echo -e " • Error handling and validation"
echo -e "\n${YELLOW}💡 NEXT STEPS:${NC}"
echo -e " • Integrate these endpoints into your frontend application"
echo -e " • Use filter metadata to build dynamic filter interfaces"
echo -e " • Implement progressive loading for better user experience"
echo -e " • Monitor performance and adjust thresholds as needed"
echo -e "\n${PURPLE}🎉 Happy filtering! 🎢${NC}"
}
# Check dependencies
check_dependencies() {
if ! command -v curl >/dev/null 2>&1; then
echo -e "${RED}❌ curl is required but not installed${NC}"
exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
echo -e "${YELLOW}⚠️ jq not found - JSON responses will not be pretty-printed${NC}"
fi
}
# Script execution
check_dependencies
main "$@"