Skip to content

feat: Implement arrivals-and-departures-for-location endpoint#787

Open
ARCoder181105 wants to merge 17 commits into
OneBusAway:mainfrom
ARCoder181105:feature/arrivals-departures-for-location
Open

feat: Implement arrivals-and-departures-for-location endpoint#787
ARCoder181105 wants to merge 17 commits into
OneBusAway:mainfrom
ARCoder181105:feature/arrivals-departures-for-location

Conversation

@ARCoder181105
Copy link
Copy Markdown
Contributor

@ARCoder181105 ARCoder181105 commented Mar 25, 2026

Overview
This PR ports the arrivals-and-departures-for-location endpoint from the legacy Java codebase into the Go maglev architecture. This endpoint allows clients to retrieve active arrivals and departures for multiple stops within a specified geographic bounding box or radius.

Key Features

  • Geospatial Querying: Utilizes the in-memory R-tree index to efficiently locate stops within the requested coordinate boundaries.
  • Overnight Trip Support: Queries active stop times across a 3-day window (yesterday, today, tomorrow) to ensure accurate scheduling for late-night routes.
  • Separated References: Aggregates Agencies, Routes, Stops, Trips, and Situations into a deduplicated references block to strictly adhere to the legacy JSON schema and optimize payload size.
  • Nearby Stops: Calculates haversine distance for nearbyStopIds to identify and include stops within the radius that may not currently have active arrivals.

Bug Fixes

  • Trip Status Fix: Resolved an existing issue in arrivals_and_departure_for_stop.go where the vehicle parameter was incorrectly passed as nil to BuildTripStatus.

Testing

  • Added table-driven tests for comprehensive parameter validation (radius, spans, minute offsets, timestamps).
  • Implemented end-to-end integration tests verifying payload structure and maximum record counts.
  • Validated context cancellation and timeout handling under load.

fix #799

Summary by CodeRabbit

  • New Features

    • Added a location-based arrivals-and-departures endpoint with distance-sorted nearby stops and a new nearby-stop data type.
    • Responses use a constructor that ensures consistent reference blocks and non-nil list fields (nearbyStopIds, situationIds, stopIds).
    • New API route registered with standard cache, auth, and rate-limit behavior.
  • Bug Fixes

    • Arrival status now reflects schedule deviation; trip status is vehicle-aware.
    • Situation identifiers now use alert IDs only; related query results are deterministically ordered.
    • lastUpdateTime is always emitted in arrival objects.
  • Tests

    • Comprehensive unit/integration tests for parameter validation, sorting, limits, errors, context cancellation (429 allowed), and end-to-end behavior.

@ARCoder181105 ARCoder181105 changed the title Feature/arrivals departures for location feat: implement arrivals-and-departures-for-location endpoint Mar 25, 2026
@ARCoder181105 ARCoder181105 changed the title feat: implement arrivals-and-departures-for-location endpoint feat: Implement arrivals-and-departures-for-location endpoint Mar 27, 2026
@ARCoder181105 ARCoder181105 marked this pull request as ready for review March 27, 2026 15:54
@ARCoder181105
Copy link
Copy Markdown
Contributor Author

Hi @aaronbrethorst,

I've ported the arrivals-and-departures-for-location endpoint and achieved strict schema parity with the Java implementation. I was able to map almost all of the fields successfully.

A few technical notes and questions for your review:

  • JSON Output Improvement (Bug Fix): I noticed the legacy Java output dumps massive amounts of duplicate IDs into the entry.stopIds array. I fixed this in the Go implementation by using a map to ensure the returned stopIds array is properly deduplicated.
  • N+1 Query Avoidance: I structured the GTFS DB calls to batch-fetch agencies, routes, and trips outside the main loops to keep the endpoint latency low.
  • Sorting Logic: I intentionally did not port the primarySortAgency sorting logic from Java's BeanFactoryV2. It looked like a Spring-injected customization specific to Sound Transit, so I left the Go references unsorted to match our other Maglev endpoints.
  • Realtime Testing Blocker: I had some trouble fully comparing the realtime GTFS-RT output because my local Java Docker container is failing to configure/run with the realtime data streams. The static schedule parity is completely verified, however.

Finally, I know some of my inline code comments might be a bit vague. I wrote them based on my current understanding of the pipeline, but I would really appreciate your suggestions on how I can improve the documentation for future maintainers.

Let me know what you think!

@ARCoder181105
Copy link
Copy Markdown
Contributor Author

Also I know the commits are also a bit vague once these changes approves I will squash and rebase the branch into single atomic commit...

@ARCoder181105
Copy link
Copy Markdown
Contributor Author

Note: arrivalEnabled and departureEnabled are currently hardcoded to true. To make these strictly match the
GTFS schedule, we will need to update the GetStopTimesForStopInWindow SQL query to explicitly select the pickup_type and drop_off_type columns. I plan to do this in a quick follow-up PR so this one stays focused on the core handler logic.

@ARCoder181105 ARCoder181105 marked this pull request as draft March 28, 2026 03:30
@ARCoder181105 ARCoder181105 marked this pull request as ready for review March 28, 2026 04:40
ARCoder181105 added a commit to ARCoder181105/maglev that referenced this pull request Mar 28, 2026
Port Java arrivals-and-departures-for-location to Go maglev architecture.

- Geospatial stop lookup via in-memory R-tree index
- 3-day window queries (yesterday/today/tomorrow) for overnight trip support
- Batch-fetch routes/trips/stop-times to avoid N+1 queries
- Deduplicated references block (Agencies, Routes, Stops, Trips, Situations)
- nearbyStopIds via haversine distance, excluding stops already in stopIds
- arrivalStatus derived from schedule deviation (LATE/EARLY/ON_TIME/default)
- limitExceeded flag honoring maxCount (mirrors Java MaxCountSupport)
- Add StopWithDistance model and NewArrivalsAndDeparturesForLocationResponse
- Add ORDER BY to GetAgenciesForStops for deterministic results
- Fix nil vehicle passed to BuildTripStatus in arrivals_and_departure_for_stop.go
- Register GET /api/where/arrivals-and-departures-for-location.json
- Add unit, E2E, and context cancellation tests

Closes OneBusAway#787
Fixes OneBusAway#799
@ARCoder181105 ARCoder181105 force-pushed the feature/arrivals-departures-for-location branch from e3c9b4d to b056442 Compare March 28, 2026 11:01
@3rabiii
Copy link
Copy Markdown
Contributor

3rabiii commented Mar 28, 2026

Hey @ARCoder181105 Great work on this endpoint!
While reviewing the legacy Java documentation and code (ArrivalsAndDeparturesForLocationAction) for API parity, I noticed that this endpoint should also accept a few more optional parameters:
1.routeType: an optional comma-delimited list of GTFS routeTypes to filter by.
2.emptyReturnsNotFound: a boolean flag to indicate if an empty result should return a 404 instead of a 200.
I see we are parsing latSpan, lonSpan, time, etc., but it seems these might have been missed in the ArrivalsAndDeparturesForLocationParams struct.

@ARCoder181105
Copy link
Copy Markdown
Contributor Author

Hi @3rabiii, thanks for the review!

I have implemented the missing parameters you mentioned (routeType and emptyReturnsNotFound which now properly returns a 404).

I also addressed a few other minor parity gaps (added frequencyMinutesBefore and fixed the nearbyStopIds logic to match the Java setIncludeInputIdsInNearby(true) override).

Everything has been tested and verified against the live PugetSound schema. Ready for another look whenever you have time!

@ARCoder181105
Copy link
Copy Markdown
Contributor Author

Hi @aaronbrethorst , @Ahmedhossamdev

The PR is ready for review ...

@Ahmedhossamdev
Copy link
Copy Markdown
Member

Hi @ARCoder181105
Can you update the openapi now? I have added the new endpoint to our openapi.yml file

@3rabiii
Copy link
Copy Markdown
Contributor

3rabiii commented Mar 29, 2026

@Ahmedhossamdev I already updated it here #807

@ARCoder181105
Copy link
Copy Markdown
Contributor Author

ARCoder181105 commented Mar 29, 2026

Already done by @3rabiii , PR #807

Port Java arrivals-and-departures-for-location to Go maglev architecture.

- Geospatial stop lookup via in-memory R-tree index
- 3-day window queries (yesterday/today/tomorrow) for overnight trip support
- Batch-fetch routes/trips/stop-times to avoid N+1 queries
- Deduplicated references block (Agencies, Routes, Stops, Trips, Situations)
- nearbyStopIds via haversine distance, excluding stops already in stopIds
- arrivalStatus derived from schedule deviation (LATE/EARLY/ON_TIME/default)
- limitExceeded flag honoring maxCount (mirrors Java MaxCountSupport)
- Add StopWithDistance model and NewArrivalsAndDeparturesForLocationResponse
- Add ORDER BY to GetAgenciesForStops for deterministic results
- Fix nil vehicle passed to BuildTripStatus in arrivals_and_departure_for_stop.go
- Register GET /api/where/arrivals-and-departures-for-location.json
- Add unit, E2E, and context cancellation tests

Closes OneBusAway#787
Fixes OneBusAway#799
…dpoint

- Add parsing and handling for emptyReturnsNotFound parameter
- Add parsing and GTFS filtering for routeType parameter
- Add frequencyMinutesBefore and frequencyMinutesAfter parsing
- Fix nearbyStopIds logic to match Java's includeInputIdsInNearby=true override
…stopSequence offset in arrivals-and-departures-for-location
@ARCoder181105 ARCoder181105 force-pushed the feature/arrivals-departures-for-location branch from e4feabe to 4c74707 Compare April 26, 2026 10:17
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new GET /api/where/arrivals-and-departures-for-location.json endpoint (params, stop resolution, 3-day stop_times aggregation, GTFS-RT merging, response builder), adds StopWithDistance and response constructor, changes ArrivalAndDeparture JSON tag, normalizes situation IDs, wires vehicle into trip status, adds tests, and makes small GTFS SQL and helper fixes.

Changes

Arrivals-and-departures-for-location feature

Layer / File(s) Summary
API route registration & handler entry
internal/restapi/routes.go, internal/restapi/arrivals_and_departures_for_location.go
Registers GET /api/where/arrivals-and-departures-for-location.json and implements the top-level handler and exported ArrivalsAndDeparturesForLocationParams.
Parameter parsing & validation
internal/restapi/arrivals_and_departures_for_location.go
Parses/validates lat/lon + radius/span, time (unix ms), minutesBefore/minutesAfter, frequency windows, routeType CSV, maxCount, emptyReturnsNotFound, collecting field-level errors.
Stop resolution & agency selection
internal/restapi/arrivals_and_departures_for_location.go
Queries stops within bbox/radius, resolves per-stop agency with deterministic primary-agency fallback, collects stop-level alerts.
Active stop_time aggregation (3-day window)
internal/restapi/arrivals_and_departures_for_location.go, gtfsdb/*
Fetches stop_times across day offsets (-1..1), filters by active service IDs, and batches route/trip lookups to avoid N+1 queries.
Arrival construction & enrichment
internal/restapi/arrivals_and_departures_for_location.go, internal/restapi/trips_helper.go, internal/restapi/arrivals_and_departures_for_stop_handler.go
Builds per-arrival entries (scheduled + predicted times), computes deviation→status, applies trip status (now vehicle-aware), applies alerts (situation IDs now use alert.ID raw), computes distance/stop-sequence/block info, deduplicates alerts globally.
References & response model
internal/models/response.go, internal/models/stops.go, internal/models/arrival_and_departure.go
Adds NewArrivalsAndDeparturesForLocationResponse, new StopWithDistance type, ensures nil→empty slices in response, and updates ArrivalAndDeparture.LastUpdateTime JSON tag to always emit lastUpdateTime.
Nearby stops & queriedStopIDs
internal/restapi/arrivals_and_departures_for_location.go
Computes distance-sorted nearby stops (returns StopWithDistance) and builds queriedStopIDs only for stops that produced arrivals.
Sorting, limits, and output
internal/restapi/arrivals_and_departures_for_location.go
Sorts arrivals by predicted (else scheduled) arrival time and enforces maxCount limiting when building the response; includes aggregated references block and situationIds.
Tests: unit & integration
internal/restapi/arrivals_and_departures_for_location_test.go, internal/restapi/input_validation_integration_test.go, internal/restapi/context_cancellation_test.go
Adds comprehensive param-parsing unit tests and HTTP integration tests (auth, 400s, empty-area vs 404 behavior, sorting/limits) and extends context-cancellation expectations (accepts 429 under short timeouts).

GTFS / DB and helper fixes (separate concerns)

Layer / File(s) Summary
SQL deterministic ordering
gtfsdb/query.sql, gtfsdb/query.sql.go
GetAgenciesForStops :many now includes ORDER BY a.id ASC, stop_times.stop_id ASC to make returned rows deterministic.
Block layover index bounds fix
gtfsdb/helpers.go
buildBlockLayoverIndex now computes layover bounds from last-stop ArrivalTime and next-stop DepartureTime, skips inserts when start > end to avoid negative-duration layovers.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant API as RestAPI Handler
    participant Resolver as Stop Resolver
    participant DB as GTFS DB
    participant RT as GTFS-RT Service
    participant Builder as Response Builder

    Client->>API: GET /arrivals-and-departures-for-location.json (lat,lon,radius,...)
    API->>Resolver: validate params, compute bbox/radius
    Resolver->>DB: query stops within bbox/radius
    DB-->>Resolver: stop list
    API->>DB: fetch active stop_times/trips/routes (3-day window)
    DB-->>API: scheduled stop_times + references
    API->>RT: fetch vehicle positions & alerts for relevant trips
    RT-->>API: vehicles, alerts
    API->>Builder: compute predicted/scheduled times, statuses, distances, nearby stops
    Builder-->>API: arrivalsAndDepartures + references
    API-->>Client: 200 OK with JSON envelope
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • OneBusAway/maglev#893 — Related changes to ArrivalAndDeparture.LastUpdateTime representation and JSON tagging.
  • OneBusAway/maglev#910 — Test/response-type refactor affecting arrival/departure response handling and assertions.

Suggested reviewers

  • aaronbrethorst
  • Ahmedhossamdev
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main objective: implementing a new API endpoint for arrivals and departures filtered by location.
Linked Issues check ✅ Passed All core requirements from issue #799 are met: parameter parsing/validation, GTFS data retrieval avoiding N+1 queries, strict JSON schema parity, spatial filtering, nearby stops, and unit/integration tests including context cancellation.
Out of Scope Changes check ✅ Passed Minor changes to existing files (latency fixes, JSON tag updates, trip status improvements) are justified as supporting changes for the new endpoint and do not constitute out-of-scope work.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
internal/restapi/context_cancellation_test.go (1)

84-95: 429 as an allowed outcome may dilute cancellation-signal quality.

Because all sub-tests reuse the same API/rate limiter, a rate-limit hit can pass this assertion without validating context-cancel handling. Consider isolating limiter state per sub-test (fresh API/mux) for this suite.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/restapi/context_cancellation_test.go` around lines 84 - 95, The test
currently allows HTTP 429 as an acceptable response which can mask failures in
context-cancellation handling because all sub-tests share the same rate limiter;
update the test to initialize a fresh API/mux (and its rate limiter) for each
sub-test so limiter state is isolated, and remove http.StatusTooManyRequests
from the accepted status list in the assertion; specifically, change the
sub-test setup to create a new server/handler (new API/mux/rate limiter
instance) per t.Run and assert only 200, 401, 400, 404, 408, 500, or 504 (no
429).
internal/models/response.go (1)

80-90: Minor: Consider using map[string]any for consistency.

The rest of this file uses map[string]any (lines 22, 31, 41, 55), but this function uses map[string]interface{}. While functionally equivalent since Go 1.18, using any would maintain consistency.

♻️ Optional consistency fix
-	entryData := map[string]interface{}{
+	entryData := map[string]any{
 		"arrivalsAndDepartures": arrivalsAndDepartures,
 		"limitExceeded":         limitExceeded,
 		"nearbyStopIds":         nearbyStopIds,
 		"situationIds":          situationIds,
 		"stopIds":               stopIds,
 	}
-	data := map[string]interface{}{
+	data := map[string]any{
 		"entry":      entryData,
 		"references": references,
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/models/response.go` around lines 80 - 90, The maps entryData and
data are declared with map[string]interface{} but the rest of the file uses
map[string]any; update the declarations for both entryData and data to use
map[string]any (keeping the same keys/values) to maintain type-consistency with
other maps in this file (look for symbols entryData and data in response.go and
replace interface{} with any).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/restapi/arrivals_and_departures_for_location.go`:
- Around line 686-694: Replace direct accesses to nullable fields
trip.TripHeadsign.String and trip.DirectionID.Int64 with explicit .Valid checks:
compute a headsign variable (e.g., headsign := "" ; if trip.TripHeadsign.Valid {
headsign = trip.TripHeadsign.String }) and a direction string (e.g., dir := "" ;
if trip.DirectionID.Valid { dir = strconv.FormatInt(trip.DirectionID.Int64, 10)
}) and pass those into utils.FormCombinedID/strconv.FormatInt call sites instead
of accessing .String/.Int64 directly; apply the same pattern for any other
sql.NullString/sql.NullInt64 usages across handlers in internal/restapi (look
for trip.TripHeadsign and trip.DirectionID to locate occurrences).

---

Nitpick comments:
In `@internal/models/response.go`:
- Around line 80-90: The maps entryData and data are declared with
map[string]interface{} but the rest of the file uses map[string]any; update the
declarations for both entryData and data to use map[string]any (keeping the same
keys/values) to maintain type-consistency with other maps in this file (look for
symbols entryData and data in response.go and replace interface{} with any).

In `@internal/restapi/context_cancellation_test.go`:
- Around line 84-95: The test currently allows HTTP 429 as an acceptable
response which can mask failures in context-cancellation handling because all
sub-tests share the same rate limiter; update the test to initialize a fresh
API/mux (and its rate limiter) for each sub-test so limiter state is isolated,
and remove http.StatusTooManyRequests from the accepted status list in the
assertion; specifically, change the sub-test setup to create a new
server/handler (new API/mux/rate limiter instance) per t.Run and assert only
200, 401, 400, 404, 408, 500, or 504 (no 429).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bc9fb6dd-17be-430c-ba39-c3c40fb2fe67

📥 Commits

Reviewing files that changed from the base of the PR and between 9f32dc9 and 4c74707.

📒 Files selected for processing (12)
  • gtfsdb/query.sql
  • gtfsdb/query.sql.go
  • internal/models/arrival_and_departure.go
  • internal/models/response.go
  • internal/models/stops.go
  • internal/restapi/arrivals_and_departures_for_location.go
  • internal/restapi/arrivals_and_departures_for_location_test.go
  • internal/restapi/arrivals_and_departures_for_stop_handler.go
  • internal/restapi/context_cancellation_test.go
  • internal/restapi/input_validation_integration_test.go
  • internal/restapi/routes.go
  • internal/restapi/trips_helper.go

Comment thread internal/restapi/arrivals_and_departures_for_location.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/models/response.go`:
- Around line 62-92: In NewArrivalsAndDeparturesForLocationResponse ensure the
arrivalsAndDepartures parameter is normalized to an empty slice when nil so it
serializes as [] instead of null; update the function near the existing nil
checks for nearbyStopIds/situationIds/stopIds to add a check for
arrivalsAndDepartures and set it to an empty []ArrivalAndDeparture when nil
before building entryData so the response schema stays stable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 36c1862c-4a85-4e03-9758-55bb99397822

📥 Commits

Reviewing files that changed from the base of the PR and between 4c74707 and 3c21702.

📒 Files selected for processing (1)
  • internal/models/response.go

Comment thread internal/models/response.go
@ARCoder181105
Copy link
Copy Markdown
Contributor Author

Hi @aaronbrethorst , @Ahmedhossamdev

I resolved merge conflicts and failing test

The PR is ready for review....

@ARCoder181105
Copy link
Copy Markdown
Contributor Author

Remaining API Parity Gaps

Tested against: https://api.pugetsound.onebusaway.org/api/where/arrivals-and-departures-for-location.json?key=TEST&lat=47.653&lon=-122.307&latSpan=0.008&lonSpan=0.008

arrivalsAndDepartures[] fields

Field Local Production Notes
status "ON_TIME" for block-propagated "default" Should only be ON_TIME/LATE/EARLY for direct GTFS-RT trip updates; block-propagated predictions should stay "default"
arrivalEnabled always true false at first stop Origin stop (stopSequence 0) should have arrivalEnabled: false
distanceFromStop 0 real distance (e.g. 710m) Depends on vehicle position propagation logic
numberOfStopsAway -1 real count (e.g. 2, 19) Same dependency as above

tripStatus object

Field Local Production Notes
scheduled present (false) absent Extra field not in the OBA OpenAPI spec
frequency absent null Should serialize as null when trip is not frequency-based

Top-level entry fields

Field Local Production Notes
situationIds [] populated (e.g. ["40_17550", ...]) Requires agency-wide and route-wide alert matching, not just trip-level

These are good candidates for follow-up issues. The core work (block-based prediction propagation, blockTripSequence correction, nearbyStopIds, vehicleId, tripStatus presence, stopSequence, lastUpdateTime) is already merged and working. 🚌

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
gtfsdb/query.sql (1)

677-677: 💤 Low value

Consider making sort direction explicit.

SQL defaults to ascending order, but explicitly specifying ASC improves readability and makes intent clearer.

✨ Proposed change for clarity
-ORDER BY a.id, stop_times.stop_id;
+ORDER BY a.id ASC, stop_times.stop_id ASC;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gtfsdb/query.sql` at line 677, The ORDER BY clause at the end of the query
("ORDER BY a.id, stop_times.stop_id") relies on implicit ascending order; update
it to be explicit by appending ASC to each sort key (e.g., ORDER BY a.id ASC,
stop_times.stop_id ASC) to improve readability and make intent clear when
editing or reviewing the query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@gtfsdb/query.sql`:
- Line 677: The ORDER BY clause at the end of the query ("ORDER BY a.id,
stop_times.stop_id") relies on implicit ascending order; update it to be
explicit by appending ASC to each sort key (e.g., ORDER BY a.id ASC,
stop_times.stop_id ASC) to improve readability and make intent clear when
editing or reviewing the query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b49acfa-42da-4c3b-bcaf-5b07cf917b5a

📥 Commits

Reviewing files that changed from the base of the PR and between 3b9bffc and 5b09806.

📒 Files selected for processing (6)
  • gtfsdb/query.sql
  • gtfsdb/query.sql.go
  • internal/models/arrival_and_departure.go
  • internal/restapi/arrivals_and_departures_for_stop_handler.go
  • internal/restapi/routes.go
  • internal/restapi/trips_helper.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • internal/models/arrival_and_departure.go
  • internal/restapi/routes.go
  • internal/restapi/arrivals_and_departures_for_stop_handler.go
  • internal/restapi/trips_helper.go
  • gtfsdb/query.sql.go

@ARCoder181105 ARCoder181105 marked this pull request as draft May 14, 2026 13:19
@sonarqubecloud
Copy link
Copy Markdown

@ARCoder181105 ARCoder181105 marked this pull request as ready for review May 14, 2026 14:27
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
internal/restapi/arrivals_and_departures_for_location.go (2)

586-589: ⚡ Quick win

Don't swallow batch-fetch errors; propagate at least context cancellation.

When batchFetchLocationRoutesAndTrips fails (e.g., ctx cancellation, DB outage), this returns (false, nil), so the outer per-stop loop in arrivalsAndDeparturesForLocationHandler continues iterating over the remaining stops despite the client having gone away or the DB being unhealthy. The internal warning log in the batch helper doesn't help the request loop short-circuit. The inner loop already calls clientCanceledResponse for ctx.Err() at line 599–602; do the same here so cancellation/timeout failures actually abort the handler.

♻️ Proposed change
 	routesLookup, tripsLookup, tripStopCountMap, bErr := api.batchFetchLocationRoutesAndTrips(ctx, stopCode, allActiveStopTimes)
 	if bErr != nil {
-		return false, nil
+		if ctx.Err() != nil {
+			api.clientCanceledResponse(w, r, ctx.Err())
+			return false, ctx.Err()
+		}
+		return false, nil
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/restapi/arrivals_and_departures_for_location.go` around lines 586 -
589, The batchFetchLocationRoutesAndTrips error is being swallowed (returning
false, nil) which prevents request-level cancellation/DB errors from aborting
arrivalsAndDeparturesForLocationHandler; change the handling after calling
batchFetchLocationRoutesAndTrips so that if bErr != nil you check ctx.Err(): if
ctx.Err() != nil call clientCanceledResponse(ctx) (as done in the inner loop)
and return its result, otherwise propagate/return the bErr (or a wrapped error)
so the handler short-circuits on DB failures instead of continuing to the next
stop. Ensure you update the branch that currently returns (false, nil) to return
the appropriate cancellation response or the error from
batchFetchLocationRoutesAndTrips.

297-309: ⚡ Quick win

Several DB/spatial errors are silently dropped.

A few call sites in this handler discard returned errors with _:

  • Line 297: stops, _ := api.GtfsManager.GetStopsForLocation(...) — a failure in the bbox query yields the same "no stops" path as a legitimately empty result, including triggering emptyReturnsNotFound 404s. The caller can't distinguish "out of area" from "lookup failed".
  • Lines 898–899: GetStopsByIDs and GetRoutesForStops errors are dropped during references assembly, which can yield a silently truncated references block (missing stops/routes) without any log line.

At minimum, log these errors (e.g., via api.Logger.Warn) so failures are observable; the line-297 error in particular is worth surfacing as a 5xx since it gates the entire response shape. This matches the warn-and-degrade pattern you already use elsewhere in this file (e.g., fetchStopTimesForDayOffset).

Also applies to: 898-899

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/restapi/arrivals_and_departures_for_location.go` around lines 297 -
309, The handler currently ignores errors from
api.GtfsManager.GetStopsForLocation and later calls
GetStopsByIDs/GetRoutesForStops, causing silent failures; update the call sites
(GetStopsForLocation in the arrivals_and_departures_for_location handler and the
GetStopsByIDs/GetRoutesForStops usages during references assembly) to capture
the returned error, log it with api.Logger.Warn (including context like the
location params or stop IDs), and for the initial GetStopsForLocation error
return an appropriate 5xx response instead of treating it as an empty result
(preserve the existing emptyReturnsNotFound flow only for legitimately empty
slices); follow the existing warn-and-degrade pattern used by
fetchStopTimesForDayOffset for non-fatal downstream errors so references are
logged when truncated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/restapi/arrivals_and_departures_for_location.go`:
- Around line 586-589: The batchFetchLocationRoutesAndTrips error is being
swallowed (returning false, nil) which prevents request-level cancellation/DB
errors from aborting arrivalsAndDeparturesForLocationHandler; change the
handling after calling batchFetchLocationRoutesAndTrips so that if bErr != nil
you check ctx.Err(): if ctx.Err() != nil call clientCanceledResponse(ctx) (as
done in the inner loop) and return its result, otherwise propagate/return the
bErr (or a wrapped error) so the handler short-circuits on DB failures instead
of continuing to the next stop. Ensure you update the branch that currently
returns (false, nil) to return the appropriate cancellation response or the
error from batchFetchLocationRoutesAndTrips.
- Around line 297-309: The handler currently ignores errors from
api.GtfsManager.GetStopsForLocation and later calls
GetStopsByIDs/GetRoutesForStops, causing silent failures; update the call sites
(GetStopsForLocation in the arrivals_and_departures_for_location handler and the
GetStopsByIDs/GetRoutesForStops usages during references assembly) to capture
the returned error, log it with api.Logger.Warn (including context like the
location params or stop IDs), and for the initial GetStopsForLocation error
return an appropriate 5xx response instead of treating it as an empty result
(preserve the existing emptyReturnsNotFound flow only for legitimately empty
slices); follow the existing warn-and-degrade pattern used by
fetchStopTimesForDayOffset for non-fatal downstream errors so references are
logged when truncated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0456dcd8-41d9-4b3b-8e18-40b34e00e525

📥 Commits

Reviewing files that changed from the base of the PR and between 5b09806 and 9d3989b.

📒 Files selected for processing (3)
  • gtfsdb/helpers.go
  • gtfsdb/query.sql
  • internal/restapi/arrivals_and_departures_for_location.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • gtfsdb/query.sql

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement arrivals-and-departures-for-location endpoint

3 participants