Skip to content

Commit

Permalink
Completed getQueryPredictions implementation (#45)
Browse files Browse the repository at this point in the history
* Completed getQueryPredictions implementation

* Fixed locationBias
  • Loading branch information
cgalvan authored May 16, 2024
1 parent 6239593 commit 89499d3
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 16 deletions.
22 changes: 12 additions & 10 deletions src/places.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,18 +229,24 @@ class MigrationAutocompleteService {
getQueryPredictions(request, callback) {
const query = request.input;
const locationBias = request.locationBias; // optional
const bounds = request.bounds; // optional

const input: SearchPlaceIndexForSuggestionsRequest = {
IndexName: this._placeIndexName,
Text: query, // required
};

// TODO: Create helper methods for converting to/from LatLng concrete and literal
if (locationBias) {
if (typeof locationBias.lat === "function") {
input.BiasPosition = [locationBias.lng(), locationBias.lat()];
} else {
input.BiasPosition = [locationBias.lng, locationBias.lat];
// If bounds is specified, then location bias is ignored
if (bounds) {
const latLngBounds = new MigrationLatLngBounds(bounds);
const southWest = latLngBounds.getSouthWest();
const northEast = latLngBounds.getNorthEast();

input.FilterBBox = [southWest.lng(), southWest.lat(), northEast.lng(), northEast.lat()];
} else if (locationBias) {
const lngLat = LatLngToLngLat(locationBias);
if (lngLat) {
input.BiasPosition = lngLat;
}
}

Expand All @@ -254,10 +260,6 @@ class MigrationAutocompleteService {
const results = response.Results;
if (results && results.length !== 0) {
results.forEach(function (result) {
if (!result.Text) {
return;
}

const prediction: QueryAutocompletePrediction = {
description: result.Text,
};
Expand Down
154 changes: 148 additions & 6 deletions test/places.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { MigrationPlacesService } from "../src/places";
import { MigrationAutocompleteService, MigrationPlacesService } from "../src/places";
import { MigrationLatLng, MigrationLatLngBounds, PlacesServiceStatus } from "../src/googleCommon";

// Spy on console.error so we can verify it gets called in error cases
Expand Down Expand Up @@ -57,6 +57,23 @@ const mockedClientSend = jest.fn((command) => {
},
});
}
} else if (command instanceof SearchPlaceIndexForSuggestionsCommand) {
if (command.input.Text == clientErrorQuery) {
// Return an empty object that will throw an error
resolve({});
} else {
resolve({
Results: [
{
Text: "cool places near austin",
},
{
PlaceId: "COOL_PLACE_1",
Text: "123 cool place way, austin, tx",
},
],
});
}
} else {
reject();
}
Expand All @@ -71,8 +88,15 @@ jest.mock("@aws-sdk/client-location", () => ({
};
}),
}));
import { GetPlaceCommand, LocationClient, SearchPlaceIndexForTextCommand } from "@aws-sdk/client-location";

import {
GetPlaceCommand,
LocationClient,
SearchPlaceIndexForSuggestionsCommand,
SearchPlaceIndexForTextCommand,
} from "@aws-sdk/client-location";

const autocompleteService = new MigrationAutocompleteService();
autocompleteService._client = new LocationClient();
const placesService = new MigrationPlacesService();
placesService._client = new LocationClient();

Expand Down Expand Up @@ -250,14 +274,14 @@ test("getDetails should handle client error", (done) => {
});
});

test("textSearch should only use bounds if location was also specified", (done) => {
test("textSearch should ignore location if bounds was also specified", (done) => {
const east = 0;
const north = 1;
const south = 2;
const west = 3;
const request = {
query: "cool places in austin",
bounds: new MigrationLatLngBounds(new MigrationLatLng(south, west), new MigrationLatLng(east, north)),
bounds: new MigrationLatLngBounds(new MigrationLatLng(south, west), new MigrationLatLng(north, east)),
location: new MigrationLatLng(4, 5),
};

Expand All @@ -269,7 +293,7 @@ test("textSearch should only use bounds if location was also specified", (done)
expect(mockedClientSend).toHaveBeenCalledWith(expect.any(SearchPlaceIndexForTextCommand));
const clientInput = mockedClientSend.mock.calls[0][0].input;

expect(clientInput.FilterBBox).toStrictEqual([west, south, north, east]);
expect(clientInput.FilterBBox).toStrictEqual([west, south, east, north]);
expect(clientInput.BiasPosition).toBeUndefined();

expect(firstResult.name).toStrictEqual("Austin");
Expand Down Expand Up @@ -401,3 +425,121 @@ test("textSearch should handle client error", (done) => {
done();
});
});

test("getQueryPredictions should ignore location if bounds was also specified", (done) => {
const east = 0;
const north = 1;
const south = 2;
const west = 3;
const request = {
input: "cool place",
bounds: new MigrationLatLngBounds(new MigrationLatLng(south, west), new MigrationLatLng(north, east)),
locationBias: new MigrationLatLng(4, 5),
};

autocompleteService.getQueryPredictions(request, (results, status) => {
expect(mockedClientSend).toHaveBeenCalledTimes(1);
expect(mockedClientSend).toHaveBeenCalledWith(expect.any(SearchPlaceIndexForSuggestionsCommand));
const clientInput = mockedClientSend.mock.calls[0][0].input;

expect(clientInput.FilterBBox).toStrictEqual([west, south, east, north]);
expect(clientInput.BiasPosition).toBeUndefined();

expect(results.length).toStrictEqual(2);

const firstResult = results[0];
expect(firstResult.description).toStrictEqual("cool places near austin");
expect(firstResult.place_id).toBeUndefined();

const secondResult = results[1];
expect(secondResult.description).toStrictEqual("123 cool place way, austin, tx");
expect(secondResult.place_id).toStrictEqual("COOL_PLACE_1");

expect(status).toStrictEqual(PlacesServiceStatus.OK);

// Signal the unit test is complete
done();
});
});

test("getQueryPredictions should accept bounds as a literal", (done) => {
const east = 0;
const north = 1;
const south = 2;
const west = 3;
const request = {
input: "cool place",
bounds: { east: east, north: north, south: south, west: west },
};

autocompleteService.getQueryPredictions(request, (results, status) => {
expect(mockedClientSend).toHaveBeenCalledTimes(1);
expect(mockedClientSend).toHaveBeenCalledWith(expect.any(SearchPlaceIndexForSuggestionsCommand));
const clientInput = mockedClientSend.mock.calls[0][0].input;

expect(clientInput.FilterBBox).toStrictEqual([west, south, east, north]);
expect(clientInput.BiasPosition).toBeUndefined();

expect(results.length).toStrictEqual(2);

const firstResult = results[0];
expect(firstResult.description).toStrictEqual("cool places near austin");
expect(firstResult.place_id).toBeUndefined();

const secondResult = results[1];
expect(secondResult.description).toStrictEqual("123 cool place way, austin, tx");
expect(secondResult.place_id).toStrictEqual("COOL_PLACE_1");

expect(status).toStrictEqual(PlacesServiceStatus.OK);

// Signal the unit test is complete
done();
});
});

test("getQueryPredictions should accept location bias if there is no bounds specified", (done) => {
const request = {
input: "cool place",
locationBias: new MigrationLatLng(testLat, testLng),
};

autocompleteService.getQueryPredictions(request, (results, status) => {
expect(mockedClientSend).toHaveBeenCalledTimes(1);
expect(mockedClientSend).toHaveBeenCalledWith(expect.any(SearchPlaceIndexForSuggestionsCommand));
const clientInput = mockedClientSend.mock.calls[0][0].input;

expect(clientInput.BiasPosition).toStrictEqual([testLng, testLat]);
expect(clientInput.FilterBBox).toBeUndefined();

expect(results.length).toStrictEqual(2);

const firstResult = results[0];
expect(firstResult.description).toStrictEqual("cool places near austin");
expect(firstResult.place_id).toBeUndefined();

const secondResult = results[1];
expect(secondResult.description).toStrictEqual("123 cool place way, austin, tx");
expect(secondResult.place_id).toStrictEqual("COOL_PLACE_1");

expect(status).toStrictEqual(PlacesServiceStatus.OK);

// Signal the unit test is complete
done();
});
});

test("getQueryPredictions should handle client error", (done) => {
const request = {
input: clientErrorQuery,
};

autocompleteService.getQueryPredictions(request, (results, status) => {
expect(results).toHaveLength(0);
expect(status).toStrictEqual(PlacesServiceStatus.UNKNOWN_ERROR);

expect(console.error).toHaveBeenCalledTimes(1);

// Signal the unit test is complete
done();
});
});

0 comments on commit 89499d3

Please sign in to comment.