Skip to content

Add dynamic radius filtering with ST_DWithin and distance in response #607

@BigBen-7

Description

@BigBen-7

Description

The GET /gists endpoint currently uses a hardcoded or default radius. This issue makes the radius fully dynamic, ensures the PostGIS ST_DWithin query is correctly parameterized, and adds distanceMeters to every gist in the response so the frontend can sort and display results correctly.

Context

  • GistRepository already uses ST_DWithin but the implementation needs tightening
  • ST_DWithin with geography type measures distance in metres
  • QueryGistsDto has a radius field that needs proper validation
  • Max radius should be capped at 5000m to prevent abuse
  • Spatial index on location column must exist for performance

Requirements

  • Validate radius in QueryGistsDto: min 50m, max 5000m, default 500m
  • Ensure GistRepository.findNearby() passes radius as a parameterized value — never string-interpolated
  • Add ST_Distance to the SELECT clause so the response includes distanceMeters for each gist
  • Sort results by ST_Distance ascending then created_at descending as tiebreaker
  • Ensure the PostGIS query uses ::geography cast on the input point

Files to Touch

  • Backend/src/gists/dto/query-gists.dto.ts — validate radius with @min(50) @max(5000) @IsOptional
  • Backend/src/gists/gist.repository.ts — add ST_Distance to SELECT, sort by distance
  • Backend/src/gists/gists.service.ts — pass distanceMeters through to response
  • Backend/src/gists/entities/gist.entity.ts — confirm spatial index exists

Query Reference

SELECT *,
  ST_Distance(
    location::geography,
    ST_SetSRID(ST_MakePoint(:lon, :lat), 4326)::geography
  ) AS distance_meters
FROM gists
WHERE ST_DWithin(
  location::geography,
  ST_SetSRID(ST_MakePoint(:lon, :lat), 4326)::geography,
  :radius
)
AND expires_at > NOW()
ORDER BY distance_meters ASC, created_at DESC
LIMIT :limit;

Acceptance Criteria

  • GET /gists?lat=6.5244&lon=3.3792&radius=1000 returns gists within 1km
  • Each gist in the response includes distanceMeters
  • Results are sorted nearest-first
  • radius above 5000 returns 400 validation error
  • radius below 50 returns 400 validation error
  • EXPLAIN ANALYZE confirms spatial index is used — document in PR description

Complexity: 250 points

Metadata

Metadata

Assignees

No one assigned

    Labels

    BackendBackend issues

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions