diff --git a/server/lib/python/cartodb_services/cartodb_services/mapbox/geocoder.py b/server/lib/python/cartodb_services/cartodb_services/mapbox/geocoder.py index ba6b853..a3d6f93 100644 --- a/server/lib/python/cartodb_services/cartodb_services/mapbox/geocoder.py +++ b/server/lib/python/cartodb_services/cartodb_services/mapbox/geocoder.py @@ -113,7 +113,7 @@ class MapboxGeocoder(Traceable): :return: list of [x, y] on success, [] on error """ try: - free_search = ';'.join(free_searches) + free_search = ';'.join([self._escape(fs) for fs in free_searches]) self._logger.debug('--> free search: {}'.format(free_search)) response = self._geocoder.forward(address=free_search.decode('utf-8'), country=country, @@ -139,3 +139,10 @@ class MapboxGeocoder(Traceable): self._logger.error('Error connecting to Mapbox geocoding server', exception=ce) return [] + + def _escape(self, free_search): + # Semicolon is used to separate batch geocoding; there's no documented + # way to pass actual semicolons, and %3B or ; won't work (check + # TestBulkStreetFunctions.test_semicolon and the docs, + # https://www.mapbox.com/api-documentation/#batch-requests) + return free_search.replace(';', ',') diff --git a/test/integration/test_street_functions.py b/test/integration/test_street_functions.py index 2c5a6e9..d1fdbd2 100644 --- a/test/integration/test_street_functions.py +++ b/test/integration/test_street_functions.py @@ -262,6 +262,19 @@ class TestBulkStreetFunctions(TestStreetFunctionsSetUp): response = self._run_authenticated(query) assert_equal(1, len(response['rows'])) + def test_semicolon(self): + query = "select *, st_x(the_geom), st_y(the_geom) " \ + "FROM cdb_dataservices_client.cdb_bulk_geocode_street_point( " \ + "'select * from jsonb_to_recordset(''[" \ + "{\"cartodb_id\": 1, \"address\": \"1900 amphitheatre parkway; mountain view; ca; us\"}," \ + "{\"cartodb_id\": 2, \"address\": \"1900 amphitheatre parkway, mountain view, ca, us\"}" \ + "]''::jsonb) as (cartodb_id integer, address text)', " \ + "'address', null, null, null)" + response = self._run_authenticated(query) + + x_y_by_cartodb_id = self._x_y_by_cartodb_id(response) + assert_equal(x_y_by_cartodb_id[1], x_y_by_cartodb_id[2]) + def _run_authenticated(self, query): authenticated_query = "{}&api_key={}".format(query, self.env_variables[