amplify-swift/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Client...

215 lines
9.1 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import Amplify
import Foundation
import AWSLocation
extension AWSLocationGeoPlugin {
// MARK: - Search
/// Search for places or points of interest.
/// - Parameters:
/// - text: The place name or address to be used in the search. (case insensitive)
/// - area: The area (.near or .boundingBox) for the search. (optional)
/// - countries: Limits the search to the given a list of countries/regions. (optional)
/// - maxResults: The maximum number of results returned per request. (optional)
/// - placeIndexName: The name of the Place Index to query. (optional)
/// - Returns :
/// It returns a Geo.Place array.
/// - Throws:
/// `Geo.Error.accessDenied` if request authorization issue
/// `Geo.Error.serviceError` if service is down/resource not found/throttling/validation error
/// `Geo.Error.invalidConfiguration` if invalid configuration
/// `Geo.Error.networkError` if request failed or network unavailable
/// `Geo.Error.pluginError` if encapsulated error received by a dependent plugin
/// `Geo.Error.unknown` if error is unknown
public func search(for text: String,
options: Geo.SearchForTextOptions? = nil) async throws -> [Geo.Place] {
var request = SearchPlaceIndexForTextInput()
request.indexName = (options?.pluginOptions as? AWSLocationGeoPluginSearchOptions)?
.searchIndex ?? pluginConfig.defaultSearchIndex
guard request.indexName != nil else {
throw Geo.Error.invalidConfiguration(
GeoPluginErrorConstants.missingDefaultSearchIndex.errorDescription,
GeoPluginErrorConstants.missingDefaultSearchIndex.recoverySuggestion)
}
request.text = text
if let area = options?.area {
switch area {
case .near(let coordinates):
request.biasPosition = [coordinates.longitude,
coordinates.latitude]
case .within(let boundingBox):
request.filterBBox = [boundingBox.southwest.longitude,
boundingBox.southwest.latitude,
boundingBox.northeast.longitude,
boundingBox.northeast.latitude]
}
}
if let countries = options?.countries {
request.filterCountries = countries.map { country in
country.code
}
}
if let maxResults = options?.maxResults {
request.maxResults = maxResults as Int
}
do {
let response = try await locationService.searchPlaceIndex(forText: request)
var results = [LocationClientTypes.Place]()
if let responseResults = response.results {
results = responseResults.compactMap {
$0.place
}
}
let places: [Geo.Place] = results.compactMap {
guard let long = $0.geometry?.point?.first,
let lat = $0.geometry?.point?.last
else {
return nil
}
return Geo.Place(coordinates: Geo.Coordinates(latitude: lat, longitude: long),
label: $0.label,
addressNumber: $0.addressNumber,
street: $0.street,
municipality: $0.municipality,
neighborhood: $0.neighborhood,
region: $0.region,
subRegion: $0.subRegion,
postalCode: $0.postalCode,
country: $0.country)
}
return places
} catch {
let geoError = GeoErrorHelper.mapAWSLocationError(error)
throw geoError
}
}
/// Reverse geocodes a given pair of coordinates and returns a list of Places
/// closest to the specified position.
/// - Parameters:
/// - coordinates: Specifies a coordinate for the query.
/// - maxResults: The maximum number of results returned per request. (optional)
/// - placeIndexName: The name of the Place Index to query. (optional)
/// - Return value :
/// It returns a Geo.Place array.
/// - Throws:
/// `Geo.Error.accessDenied` if request authorization issue
/// `Geo.Error.serviceError` if service is down/resource not found/throttling/validation error
/// `Geo.Error.invalidConfiguration` if invalid configuration
/// `Geo.Error.networkError` if request failed or network unavailable
/// `Geo.Error.pluginError` if encapsulated error received by a dependent plugin
/// `Geo.Error.unknown` if error is unknown
public func search(for coordinates: Geo.Coordinates,
options: Geo.SearchForCoordinatesOptions? = nil) async throws -> [Geo.Place] {
var request = SearchPlaceIndexForPositionInput()
request.indexName = (options?.pluginOptions as? AWSLocationGeoPluginSearchOptions)?
.searchIndex ?? pluginConfig.defaultSearchIndex
guard request.indexName != nil else {
throw Geo.Error.invalidConfiguration(
GeoPluginErrorConstants.missingDefaultSearchIndex.errorDescription,
GeoPluginErrorConstants.missingDefaultSearchIndex.recoverySuggestion)
}
request.position = [coordinates.longitude,
coordinates.latitude]
if let maxResults = options?.maxResults {
request.maxResults = maxResults as Int
}
do {
let response = try await locationService.searchPlaceIndex(forPosition: request)
var results = [LocationClientTypes.Place]()
if let responseResults = response.results {
results = responseResults.compactMap {
$0.place
}
}
let places: [Geo.Place] = results.compactMap {
guard let long = $0.geometry?.point?.first,
let lat = $0.geometry?.point?.last
else {
return nil
}
return Geo.Place(coordinates: Geo.Coordinates(latitude: lat, longitude: long),
label: $0.label,
addressNumber: $0.addressNumber,
street: $0.street,
municipality: $0.municipality,
neighborhood: $0.neighborhood,
region: $0.region,
subRegion: $0.subRegion,
postalCode: $0.postalCode,
country: $0.country)
}
return places
} catch {
let geoError = GeoErrorHelper.mapAWSLocationError(error)
throw geoError
}
}
// MARK: - Maps
/// Retrieves metadata for available map resources.
/// - Returns: Metadata for all available map resources.
/// - Throws:
/// `Geo.Error.accessDenied` if request authorization issue
/// `Geo.Error.serviceError` if service is down/resource not found/throttling/validation error
/// `Geo.Error.invalidConfiguration` if invalid configuration
/// `Geo.Error.networkError` if request failed or network unavailable
/// `Geo.Error.pluginError` if encapsulated error received by a dependent plugin
/// `Geo.Error.unknown` if error is unknown
public func availableMaps() async throws -> [Geo.MapStyle] {
let mapStyles = Array(pluginConfig.maps.values)
guard !mapStyles.isEmpty else {
throw Geo.Error.invalidConfiguration(
GeoPluginErrorConstants.missingMaps.errorDescription,
GeoPluginErrorConstants.missingMaps.recoverySuggestion)
}
return mapStyles
}
/// Retrieves the default map resource.
/// - Returns: Metadata for the default map resource.
/// - Throws:
/// `Geo.Error.accessDenied` if request authorization issue
/// `Geo.Error.serviceError` if service is down/resource not found/throttling/validation error
/// `Geo.Error.invalidConfiguration` if invalid configuration
/// `Geo.Error.networkError` if request failed or network unavailable
/// `Geo.Error.pluginError` if encapsulated error received by a dependent plugin
/// `Geo.Error.unknown` if error is unknown
public func defaultMap() async throws -> Geo.MapStyle {
guard let mapName = pluginConfig.defaultMap, let mapStyle = pluginConfig.maps[mapName] else {
throw Geo.Error.invalidConfiguration(
GeoPluginErrorConstants.missingDefaultMap.errorDescription,
GeoPluginErrorConstants.missingDefaultMap.recoverySuggestion)
}
return mapStyle
}
}