11class SubscriptionVacanciesMatchingQuery
22 attr_reader :scope
33
4+ # British National Grid SRID (EPSG:27700) is a projected coordinate system used for mapping in Great Britain.
5+ # It provides coordinates in meters, which is useful for distance calculations, which we need
6+ # for radius-based searches.
7+ # It is significantly more accurate for distance calculations in Great Britain that EPSG:3857 (Web Mercator).
8+ # EPSG:3857 distort distances and areas, especially as you move away from the equator. What would cause a multiplier
9+ # between 1.5x and 1.7x for radius/buffer distances in our case to get the matches we would expect.
10+ BRITISH_NATIONAL_GRID_SRID = 27700 # rubocop:disable Style/NumericLiterals
11+
412 # Builds the query to find the IDs for the vacancies matching the subscription criteria.
513 # The subquery is needed to be able to combine our requirements into a valid single SQL statement:
614 # - retrieve unique DISTINCT ON vacancy ids: As the location filter may return the same vacancy multiple times (vacancy for multiple orgs).
@@ -169,9 +177,9 @@ def location_filter(scope, subscription_location, subscription)
169177 # 'area_before_type_cast' and 'geopoint_before_type_cast' are used to avoid casting the fields into RGeo objects.
170178 # This reduces memory usage and speeds up the query. As we don't need to use the actual objects in Ruby code,
171179 # just need to know if they are present in DB.
172- if subscription . uk_area_before_type_cast . present?
180+ if subscription . area_before_type_cast . present?
173181 location_by_area_filter ( scope , subscription )
174- elsif subscription . uk_geopoint_before_type_cast . present? && subscription . radius_in_metres . present?
182+ elsif subscription . geopoint_before_type_cast . present? && subscription . radius_in_metres . present?
175183 location_by_geopoint_filter ( scope , subscription )
176184 else
177185 scope . none # Invalid location filter (having no area or geopoint) returns no matches
@@ -189,11 +197,9 @@ def location_filter(scope, subscription_location, subscription)
189197 # Including 'publish_on' in the distinct: The provided scope may be ordered by publish on date. When using distinct
190198 # with ordering, Postgres requires all selected columns to be included in the distinct clause or will fail during execution.
191199 def location_by_area_filter ( scope , subscription )
192- subscriptions = Subscription . arel_table
193- organisations = Organisation . arel_table
194200 scope . joins ( "INNER JOIN subscriptions ON subscriptions.id = '#{ subscription . id } '" )
195201 . joins ( :organisations )
196- . where ( subscriptions [ :uk_area ] . st_contains ( organisations [ :uk_geopoint ] ) )
202+ . where ( "ST_Contains( subscriptions.area, organisations.geopoint::geometry)" )
197203 end
198204
199205 # Filter vacancies where their organisations' geopoints fall within the subscription's radius from the subscription's
@@ -208,8 +214,8 @@ def location_by_area_filter(scope, subscription)
208214 def location_by_geopoint_filter ( scope , subscription )
209215 scope . joins ( "INNER JOIN subscriptions ON subscriptions.id = '#{ subscription . id } '" )
210216 . joins ( :organisations )
211- . where ( "ST_DWithin(organisations.uk_geopoint ::geometry,
212- subscriptions.uk_geopoint ,
217+ . where ( "ST_DWithin(ST_Transform( organisations.geopoint ::geometry, #{ BRITISH_NATIONAL_GRID_SRID } ) ,
218+ ST_Transform( subscriptions.geopoint, #{ BRITISH_NATIONAL_GRID_SRID } ) ,
213219 subscriptions.radius_in_metres)" )
214220 end
215221end
0 commit comments