Skip to content

Commit 75c3451

Browse files
authored
feat(GeoSearch): add geospatial query support (algolia#105)
1 parent 912bfb8 commit 75c3451

File tree

5 files changed

+236
-27
lines changed

5 files changed

+236
-27
lines changed

helper/lib/src/model/search_state.dart

Lines changed: 202 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ class SearchState implements MultiSearchState {
4040
this.tagFilters,
4141
this.userToken,
4242
this.clickAnalytics,
43+
this.aroundLatLngViaIP,
44+
this.aroundLatLng,
45+
this.aroundRadius,
46+
this.minimumAroundRadius,
47+
this.aroundPrecision,
48+
this.insideBoundingBox,
4349
});
4450

4551
/// Index name
@@ -122,6 +128,169 @@ class SearchState implements MultiSearchState {
122128
/// events.
123129
final bool? clickAnalytics;
124130

131+
///
132+
/// **AroundLatLngViaIP**
133+
///
134+
/// Search for entries around a given location automatically computed from the requester’s IP address.
135+
/// By computing a central geolocation (from an IP), this has three consequences:
136+
/// - a radius / circle is computed automatically, based on the density of the records near the point defined by this setting
137+
/// - only records that fall within the bounds of the circle are returned
138+
/// - records are ranked according to the distance from the center of the circle
139+
///
140+
/// **Usage notes:**
141+
/// - With this setting, you are using the end user’s IP to define a central axis point of a circle in geo-coordinates.
142+
/// - Algolia automatically calculates the size of the circular radius around this central axis.
143+
/// - To control the precise size of the radius, you would use [aroundRadius].
144+
/// - To control a minimum size, you would use [minimumAroundRadius].
145+
/// - If you are sending the request from your servers, you must set the X-Forwarded-For HTTP header with the front-end user’s IP address for it to be used as the basis for the computation of the search location.
146+
/// - Note: This setting differs from [aroundLatLng], which allows you to specify the exact latitude and longitude of the center of the circle.
147+
/// - This parameter will be ignored if used along with [insideBoundingBox] or [insidePolygon]
148+
/// - We currently only support IPv4 addresses. If the end user has an IPv6 address, this parameter won’t work as intended.
149+
///
150+
/// Source: [Learn more](https://www.algolia.com/doc/api-reference/api-parameters/aroundLatLngViaIP/)
151+
///
152+
final bool? aroundLatLngViaIP;
153+
154+
///
155+
/// **AroundLatLng**
156+
///
157+
/// Search for entries around a central geolocation, enabling a geo search within a circular area.
158+
///
159+
/// By defining this central point, there are three consequences:
160+
/// - a radius / circle is computed automatically, based on the density of the records near the point defined by this setting
161+
/// - only records that fall within the bounds of the circle are returned
162+
/// - records are ranked according to the distance from the center of the circle
163+
///
164+
/// **Usage notes:**
165+
/// - With this setting, you are defining a central point of a circle, whose geo-coordinates are expressed as two floats separated by a comma.
166+
/// - Note: This setting differs from [aroundLatLngViaIP], which uses the end user’s IP to determine the geo-coordinates.
167+
/// - This parameter will be ignored if used along with [insideBoundingBox] or [insidePolygon]
168+
/// - To control the maximum size of the radius, you would use [aroundRadius].
169+
/// - To control the minimum size, you would use [minimumAroundRadius].
170+
/// - The size of this radius depends on the density of the area around the central point. If there are a large number of hits close to the central point, the radius can be small. The less hits near the center, the larger the radius will be.
171+
/// - Note: If the results returned are less than the number of hits per page (hitsPerPage), then the number returned will be less than the hitsPerPage. For example, if you recieve 15 results, you could still see a larger number of hits per page, such as hitsPerPage=20.
172+
///
173+
/// Source: [Learn more](https://www.algolia.com/doc/api-reference/api-parameters/aroundLatLng/)
174+
///
175+
final String? aroundLatLng;
176+
177+
///
178+
/// **AroundRadius**
179+
///
180+
/// Define the maximum radius for a geo search (in meters).
181+
///
182+
/// **Usage notes:**
183+
/// - This setting only works within the context of a radial (circuler) geo search,
184+
/// enabled by `aroundLatLngViaIP` or `aroundLatLng`.
185+
/// - ***How the radius is calculated:***
186+
/// - If you specify the meters of the radius (instead of `all`), then only records
187+
/// that fall within the bounds of the circle (as defined by the radius) will be
188+
/// returned. Additionally, the ranking of the returned hits will be based on the
189+
/// distance from the central axist point.
190+
/// - If you use `all`, there is no longer any filtering based on the radius. All
191+
/// relevant results are returned, but the ranking is still based on the distance
192+
/// from the central axis point.
193+
/// - If you do not use this setting, and yet perform a radial geo search (using
194+
/// `aroundLatLngViaIP` or `aroundLatLng`), the radius is automatically computed
195+
/// from the density of the searched area. See also `minimumAroundRadius`, which
196+
/// determines the minimum size of the radius.
197+
/// - For this setting to have any effect on your ranking, the geo criterion must be
198+
/// included in your ranking formula (which is the case by default).
199+
///
200+
/// **Options:**
201+
/// - `radius_in_meters`: Integer value (in meters) representing the radius around the
202+
/// coordinates specified during the query.
203+
/// - `all`: Disables the radius logic, allowing all results to be returned, regardless
204+
/// of distance. Ranking is still based on proxiùmity to the central axis point. This
205+
/// option is faster than specifying a high integer value.
206+
///
207+
/// value must be a `int` or `'all'`
208+
///
209+
/// `1 = 1 Meter`
210+
///
211+
/// `Therefore for 1000 = 1 Kilometer`
212+
///
213+
/// `'aroundRadius' => 1000` // 1km
214+
///
215+
/// Source: [Learn more](https://www.algolia.com/doc/api-reference/api-parameters/aroundRadius/)
216+
///
217+
final dynamic aroundRadius;
218+
219+
///
220+
/// **AroundPrecision**
221+
///
222+
/// Precision of geo search (in meters), to add grouping by geo location to the ranking
223+
/// formula.
224+
///
225+
/// When ranking hits, geo distances are grouped into ranges of `aroundPrecision` size.
226+
/// All hits within the same range are considered equal with respect to the `geo` ranking
227+
/// parameter.
228+
///
229+
/// For example, if you set `aroundPrecision` to `100`, any two objects lying in the range
230+
/// `[0, 99m]` from the searched location will be considered equal; same for `[100, 199]`,
231+
/// `[200, 299]`, etc.
232+
///
233+
/// Usage notes:
234+
/// - For this setting to have any effect, the [geo criterion](https://www.algolia.com/doc/guides/managing-results/must-do/custom-ranking/in-depth/ranking-criteria#geo-if-applicable)
235+
/// must be included in your ranking formula (which is the case by default).
236+
///
237+
/// `1 = 1 Meter`
238+
///
239+
/// `Therefore for 1000 = 1 Kilometer`
240+
///
241+
/// `'aroundPrecision' => 1000` // 1km
242+
///
243+
/// Source: [Learn more](https://www.algolia.com/doc/api-reference/api-parameters/aroundPrecision/)
244+
///
245+
final int? aroundPrecision;
246+
247+
///
248+
/// **MinimumAroundRadius**
249+
///
250+
/// Minimum radius (in meters) used for a geo search when `aroundRadius` is not set.
251+
///
252+
/// When a radius is automatically generated, the area of the circle might be too
253+
/// small to include enough records. This setting allows you to increase the size
254+
/// of the circle, thus ensuring sufficient coverage.
255+
///
256+
/// **Usage notes:**
257+
/// - This setting only works within the context of a circular geo search,
258+
/// enabled by `aroundLatLng` or `aroundLatLngViaIP`.
259+
/// - This parameter is ignored when `aroundRadius` is set.
260+
///
261+
/// `1 = 1 Meter`
262+
///
263+
/// `Therefore for 1000 = 1 Kilometer`
264+
///
265+
/// `'minimumAroundRadius' => 1000` // 1km
266+
///
267+
/// Source: [Learn more](https://www.algolia.com/doc/api-reference/api-parameters/minimumAroundRadius/)
268+
///
269+
final int? minimumAroundRadius;
270+
271+
///
272+
/// **InsideBoundingBox**
273+
///
274+
/// Search inside a rectangular area (in geo coordinates).
275+
///
276+
/// The rectangle is defined by two diagonally opposite points (hereafter `p1` and `p2`),
277+
/// hence by 4 floats: `p1Lat`, `p1Lng`, `p2Lat`, `p2Lng`.
278+
///
279+
/// For example: `insideBoundingBox = [ 47.3165, 4.9665, 47.3424, 5.0201 ]`
280+
///
281+
/// **Usage notes**
282+
/// - You may specify multiple bounding boxes, in which case the search will use the
283+
/// union (OR) of the rectangles. To do this, pass either:
284+
/// - more than 4 values (must be a multiple of 4: 8, 12…); example:
285+
/// `47.3165,4.9665,47.3424,5.0201,40.9234,2.1185,38.6430,1.9916`;
286+
/// - [aroundLatLng] and [aroundLatLngViaIP] will be ignored if used along with this
287+
/// parameter.
288+
/// - Be careful when your coordinates cross over the `180th meridian`.
289+
///
290+
/// Source: [Learn more](https://www.algolia.com/doc/api-reference/api-parameters/insideBoundingBox/)
291+
///
292+
final List<double>? insideBoundingBox;
293+
125294
/// Make a copy of the search state.
126295
SearchState copyWith({
127296
List<String>? attributesToHighlight,
@@ -148,6 +317,12 @@ class SearchState implements MultiSearchState {
148317
int? maxValuesPerFacet,
149318
int? page,
150319
bool? clickAnalytics,
320+
bool? aroundLatLngViaIP,
321+
String? aroundLatLng,
322+
dynamic aroundRadius,
323+
int? aroundPrecision,
324+
int? minimumAroundRadius,
325+
List<double>? insideBoundingBox,
151326
}) =>
152327
SearchState(
153328
attributesToHighlight:
@@ -176,6 +351,12 @@ class SearchState implements MultiSearchState {
176351
maxValuesPerFacet: maxValuesPerFacet ?? this.maxValuesPerFacet,
177352
page: page ?? this.page,
178353
clickAnalytics: clickAnalytics ?? this.clickAnalytics,
354+
aroundLatLngViaIP: aroundLatLngViaIP ?? this.aroundLatLngViaIP,
355+
aroundLatLng: aroundLatLng ?? this.aroundLatLng,
356+
aroundRadius: aroundRadius ?? this.aroundRadius,
357+
aroundPrecision: aroundPrecision ?? this.aroundPrecision,
358+
minimumAroundRadius: minimumAroundRadius ?? this.minimumAroundRadius,
359+
insideBoundingBox: insideBoundingBox ?? this.insideBoundingBox,
179360
);
180361

181362
@override
@@ -207,7 +388,13 @@ class SearchState implements MultiSearchState {
207388
tagFilters.equals(other.tagFilters) &&
208389
analytics == other.analytics &&
209390
userToken == other.userToken &&
210-
clickAnalytics == other.clickAnalytics;
391+
clickAnalytics == other.clickAnalytics &&
392+
aroundLatLngViaIP == other.aroundLatLngViaIP &&
393+
aroundLatLng == other.aroundLatLng &&
394+
aroundRadius == other.aroundRadius &&
395+
aroundPrecision == other.aroundPrecision &&
396+
minimumAroundRadius == other.minimumAroundRadius &&
397+
insideBoundingBox.equals(other.insideBoundingBox);
211398

212399
@override
213400
int get hashCode =>
@@ -234,7 +421,13 @@ class SearchState implements MultiSearchState {
234421
tagFilters.hashing() ^
235422
analytics.hashCode ^
236423
userToken.hashCode ^
237-
clickAnalytics.hashCode;
424+
clickAnalytics.hashCode ^
425+
aroundLatLngViaIP.hashCode ^
426+
aroundLatLng.hashCode ^
427+
aroundRadius.hashCode ^
428+
aroundPrecision.hashCode ^
429+
minimumAroundRadius.hashCode ^
430+
insideBoundingBox.hashing();
238431

239432
@override
240433
String toString() => 'SearchState{'
@@ -261,5 +454,11 @@ class SearchState implements MultiSearchState {
261454
'sumOrFiltersScore: $sumOrFiltersScore, '
262455
'tagFilters: $tagFilters, '
263456
'userToken: $userToken, '
264-
'clickAnalytics: $clickAnalytics}';
457+
'clickAnalytics: $clickAnalytics, '
458+
'aroundLatLngViaIP: $aroundLatLngViaIP, '
459+
'aroundLatLng: $aroundLatLng, '
460+
'aroundRadius: $aroundRadius, '
461+
'aroundPrecision: $aroundPrecision, '
462+
'minimumAroundRadius: $minimumAroundRadius, '
463+
'insideBoundingBox: $insideBoundingBox}';
265464
}

helper/lib/src/service/algolia_client_extensions.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ extension AlgolisSearchStateExt on SearchState {
4949
userToken: userToken,
5050
filters: filters,
5151
clickAnalytics: clickAnalytics,
52+
aroundLatLng: aroundLatLng,
53+
aroundLatLngViaIP: aroundLatLngViaIP,
54+
aroundPrecision: aroundPrecision,
55+
aroundRadius: aroundRadius,
56+
minimumAroundRadius: minimumAroundRadius,
57+
insideBoundingBox: insideBoundingBox,
5258
);
5359
return search;
5460
}

helper/pubspec.yaml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ environment:
77
sdk: '>=3.0.0 <4.0.0'
88
flutter: '>=1.17.0'
99
dependencies:
10-
algolia_insights: ^0.2.1
11-
algoliasearch: ^0.2.0
12-
collection: ^1.16.0
10+
algolia_insights: ">=0.2.0 <1.0.0"
11+
algoliasearch: ">=0.2.0 <1.0.0"
12+
collection: ">=1.17.0 <2.0.0"
1313
flutter:
1414
sdk: flutter
15-
logging: ^1.0.2
16-
meta: ^1.7.0
17-
rxdart: ^0.27.4
15+
logging: ">=1.0.0 <2.0.0"
16+
meta: ">=1.7.0 <2.0.0"
17+
rxdart: ">=0.26.0 <1.0.0"
1818
dev_dependencies:
19-
build_runner: 2.4.4
20-
flutter_lints: ^2.0.0
19+
build_runner: ">=2.0.0 <3.0.0"
20+
flutter_lints: ">=2.0.0 <3.0.0"
2121
flutter_test:
2222
sdk: flutter
23-
lints: ^2.1.0
24-
mockito: ^5.4.2
25-
provider: ^6.0.3
26-
test: ^1.24.0
23+
lints: ">=2.1.0 <3.0.0"
24+
mockito: ">=5.0.0 <6.0.0"
25+
provider: ">=6.0.0 <7.0.0"
26+
test: ">=1.20.0 <2.0.0"

insights/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.2
2+
3+
- **CHORE**: Update dependencies to be more relaxed.
4+
15
## 0.2.1
26

37
- **CHORE**: Fix pana issues (#95).

insights/pubspec.yaml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ environment:
88
sdk: ">=2.17.5 <4.0.0"
99
flutter: '>=1.17.0'
1010
dependencies:
11-
algolia_client_insights: ^0.2.0
12-
collection: ^1.16.0
11+
algolia_client_insights: ">=0.2.0 <0.3.0"
12+
collection: ">=1.17.0 <2.0.0"
1313
flutter:
1414
sdk: flutter
15-
hive: ^2.2.3
16-
logging: ^1.0.2
17-
meta: ^1.7.0
18-
path_provider: ^2.0.15
19-
rxdart: ^0.27.4
20-
uuid: ^3.0.6
15+
hive: ">=2.0.0 <3.0.0"
16+
logging: ">=1.0.0 <2.0.0"
17+
meta: ">=1.7.0 <2.0.0"
18+
path_provider: ">=2.0.0 <3.0.0"
19+
rxdart: ">=0.27.0 <1.0.0"
20+
uuid: ">=3.0.0 <5.0.0"
2121

2222
dev_dependencies:
23-
build_runner: ^2.4.4
24-
lints: ^2.1.0
25-
mockito: ^5.4.0
26-
test: ^1.24.0
23+
build_runner: ">=2.4.0 <3.0.0"
24+
lints: ">=2.0.0 <3.0.0"
25+
mockito: ">=5.0.0 <6.0.0"
26+
test: ">=1.0.0 <2.0.0"
2727
test_api: ">=0.2.1 <0.6.0"

0 commit comments

Comments
 (0)