Compare commits

...

101 Commits

Author SHA1 Message Date
Antonio Carlón
f68f997eb7 Merge pull request #595 from CartoDB/development
Fix origin/destination in isolines
2020-03-27 09:13:29 +01:00
Antonio Carlón
4d231c1db0 Merge pull request #594 from CartoDB/Fix_here_is_destination_param
Fixing is_destination for HERE isolines
2020-03-27 08:11:37 +01:00
antoniocarlon
a1fdaacb4c Fixed spacing 2020-03-18 12:14:16 +01:00
antoniocarlon
09e24e13d3 Fixing is_destination for HERE isolines 2020-03-18 12:09:12 +01:00
Manuel J. Morillo
1a2d8e865c Merge pull request #592 from CartoDB/development
Deploy client `0.29.0` and server `0.38.0` to prod
2020-03-18 10:13:19 +01:00
Manuel J. Morillo
a2790c90d9 Merge pull request #593 from CartoDB/code_review_592
CODE REVIEW for client 0.29.0 and server 0.38.0
2020-03-18 09:40:13 +01:00
manmorjim
083b634ea7 Update NEWS 2020-03-17 11:53:21 +01:00
manmorjim
36f271751b Update dependencies to fix vulnerabilities 2020-03-17 11:51:31 +01:00
manmorjim
2d78caeef2 Migration scripts for server 2020-03-17 11:27:10 +01:00
manmorjim
24df64681d Migration scripts for client 2020-03-17 11:20:47 +01:00
manmorjim
b7c9ff8dac Remove @@plpythonu@@ vars from old_versions 2020-03-17 09:49:54 +01:00
Manuel J. Morillo
f4df0a5f7c Merge pull request #591 from CartoDB/deploy_0.29.0client_0.38.0server
Update NEWS with the release (deploy) date
2020-03-13 10:46:36 +01:00
manmorjim
1daa5b1451 Update NEWS with the release (deploy) date 2020-03-13 10:41:26 +01:00
Manuel J. Morillo
f075a9416b Merge pull request #590 from CartoDB/fix_client_vars_replacement
Fixes client release 0.29.0
2020-03-11 11:01:06 +01:00
Manuel J. Morillo
201ab42665 Keep 0.38.0 version 2020-03-10 17:24:17 +01:00
manmorjim
c793293fae Changes from 'development' 2020-03-10 17:21:54 +01:00
manmorjim
40d1b4eafd Update dependencies 2020-03-10 17:19:46 +01:00
manmorjim
0a902d7f00 Replace @@plpythonu@@ vars 2020-03-10 17:19:19 +01:00
manmorjim
9b95682243 Add @@plpythonu@@ vars into old_versions 2020-03-10 17:18:55 +01:00
Manuel J. Morillo
e77038ce2f Merge pull request #589 from CartoDB/fix_release_0.38
Fix server release 0.38.0
2020-03-10 16:51:11 +01:00
manmorjim
8f720e8165 Update dependencies 2020-03-10 15:45:31 +01:00
manmorjim
da9948cba3 Fix release 0.38.0
Replace `@@plpythonu@@` vars in old_versions
2020-03-10 15:45:04 +01:00
manmorjim
35ff75ea64 Replace @@plpythonu@@ vars in old_versions 2020-03-09 13:02:26 +01:00
Manuel J. Morillo
18459fb906 Merge pull request #588 from CartoDB/fix_release_0.29
Fix release 0.29.0
2020-03-09 11:50:44 +01:00
manmorjim
796ba4a15e Files for the release 0.29.0 2020-03-09 11:15:23 +01:00
manmorjim
63e5379016 restore 0.28.0 files 2020-03-09 11:09:58 +01:00
manmorjim
ee837e0e5f release 0.29.0 2020-03-06 17:57:32 +01:00
manmorjim
c6e5711905 Replace @@plpythonu@@ var in old_versions 2020-03-06 17:57:02 +01:00
Daniel G. Aubert
10a62cc3c5 Merge pull request #587 from CartoDB/development
python-0.23.1 deploy to production
2020-03-06 16:31:56 +01:00
Daniel G. Aubert
021469c825 Merge pull request #586 from CartoDB/release-python-0.23.1
Release python 0.23.1
2020-03-06 11:42:02 +01:00
Daniel García Aubert
84bdd8a828 Update NEWS 2020-03-06 10:49:37 +01:00
Daniel García Aubert
67fa730436 Bump python library to version 0.23.1 2020-03-06 10:43:39 +01:00
Daniel G. Aubert
151c768894 Merge pull request #583 from CartoDB/tomtom_bulk_qps_retry
add qps_retry to tomtom bulk API calls
2020-03-06 10:29:34 +01:00
Daniel García Aubert
3560c07d7f Merge branch 'development' into tomtom_bulk_qps_retry 2020-03-05 10:47:01 +01:00
Manuel J. Morillo
18816f2bfb Merge pull request #584 from CartoDB/pg12_migration
[PG12] Adapt project to PostgreSQL 12 and PostGIS 3
2020-03-05 10:34:35 +01:00
manmorjim
e99d88500a Use authenticated query for geocoding 2020-03-02 15:27:32 +01:00
manmorjim
2664095e21 Update tolerance and fixture values 2020-03-02 15:26:59 +01:00
manmorjim
5bb0e67499 Add method parameter to requests
It allows using POST for large URI to prevent errors `414 Request-URI Too Large`
2020-03-02 15:24:56 +01:00
manmorjim
e3e037563b Deconding the tests output 2020-03-02 15:21:32 +01:00
manmorjim
944bc8c3ff Create the type geomval in the extension schema
Having it as public.geomval means that we would block ourselves from installing `postgis_raster` if this extension is installed.
2020-03-02 09:09:10 +01:00
manmorjim
e97d350e5a Decode redis responses by default
In python3 redis responses are encoded by default.
2020-02-27 17:20:10 +01:00
manmorjim
880f756eae Add the extension schema to the SEARCH_PATH 2020-02-27 16:06:30 +01:00
manmorjim
0164b07b92 Install always python lib in python2 for unit tests 2020-02-27 10:46:06 +01:00
manmorjim
4a880805cc Fix conditional CI 2020-02-27 10:19:13 +01:00
manmorjim
5370ea23c7 Conditional jobs dependint on PG version 2020-02-27 10:14:42 +01:00
Alberto Romeu
f1cd40f7e7 add qps_retry to tomtom bulk API calls 2020-02-26 19:52:56 +01:00
manmorjim
7aefba181c Install packages in python3 using pip3 2020-02-26 18:52:26 +01:00
manmorjim
35f098686c Force non-zero exit if tests failed 2020-02-26 17:39:35 +01:00
manmorjim
8a3f28c45b Rename output test directory 2020-02-26 17:32:59 +01:00
manmorjim
53a0e7abf3 Show errors if tests failed 2020-02-26 17:32:08 +01:00
manmorjim
3c916bdfc9 Adapt dataservices-api server to python3
Related to https://github.com/CartoDB/cartodb-platform/issues/6237
2020-02-26 15:49:15 +01:00
manmorjim
b2a06c6ed6 Create the type geomval if not exist
Related to https://github.com/CartoDB/cartodb-platform/issues/6237
2020-02-26 15:42:10 +01:00
manmorjim
d5b0d86997 Add variable @@plpythonu@@
Related with https://github.com/CartoDB/cartodb-platform/issues/6237
2020-02-26 15:41:04 +01:00
manmorjim
fa2bed0df5 Add details about what the rule does 2020-02-26 15:38:43 +01:00
ibrahim menem
d920d72b0b remove integration tests from github actions (#581) 2020-02-26 13:17:56 +01:00
ibrahim
495f2425bc add integration tests to ci 2020-02-25 15:55:39 +01:00
manmorjim
6a34f5d6cb Release 0.29.0 2020-02-24 16:14:29 +01:00
manmorjim
e08ca8f6bc Creates the type geomval if does not exist
PG12 migration #6237
2020-02-24 16:13:48 +01:00
manmorjim
dd907ac2bc Using @@plpythonu@@ variable
PG12 migration #6237
2020-02-24 16:12:27 +01:00
Antonio Carlón
0268b67d0c Merge pull request #578 from CartoDB/development
Added Mapbox true isolines
2020-02-12 12:56:37 +01:00
antoniocarlon
a90391aeef Updated NEWS.md 2020-02-12 11:32:15 +01:00
Antonio Carlón
426800df63 Merge pull request #572 from CartoDB/Add_Mapbox_true_isochrones
[leapfrog] First implementation of the true Mapbox isochrones
2020-02-12 11:26:15 +01:00
Antonio Carlón
3ca6133a9e Merge pull request #577 from CartoDB/Mapbox_iso_autogenerated_files
Added autogenerated files
2020-02-12 11:21:54 +01:00
antoniocarlon
f39e3551a0 Merge branch 'Add_Mapbox_true_isochrones' into Mapbox_iso_autogenerated_files 2020-02-11 15:51:17 +01:00
antoniocarlon
6b50d004bd Fix error 2020-02-11 15:45:04 +01:00
antoniocarlon
6081613220 Added autogenerated files 2020-02-11 15:29:35 +01:00
antoniocarlon
ef5b82450a Avoid renaming the matrix parameter to isolines 2020-02-11 15:25:12 +01:00
antoniocarlon
ab71acd461 Removed generated files to ease review 2020-02-11 14:08:19 +01:00
antoniocarlon
34e715f460 Deleted old mapbox isolines implementation (server extension) 2020-02-11 10:01:37 +01:00
antoniocarlon
822c574b5c Deleted old mapbox isolines implementation 2020-02-11 10:00:27 +01:00
antoniocarlon
484a05dbd9 Deleted new client version 2020-02-11 09:58:04 +01:00
antoniocarlon
62cbed7f17 Fixed speed 2020-02-10 16:56:17 +01:00
antoniocarlon
02d705465c Removed unneeded message 2020-02-10 15:45:51 +01:00
antoniocarlon
e696fa2d39 Add test to validate time ranges 2020-02-10 13:18:45 +01:00
antoniocarlon
d5efc681e4 Validate time ranges 2020-02-10 13:18:24 +01:00
antoniocarlon
cd366d7589 Extracting correct coordinates 2020-02-10 13:07:21 +01:00
antoniocarlon
80c1433bbd Fix error 2020-02-10 11:51:13 +01:00
antoniocarlon
8f823a5fae Fixed error 2020-02-10 10:27:11 +01:00
antoniocarlon
3eb36f99bb Added mapbox_iso isolines provider to config 2020-02-10 10:13:42 +01:00
antoniocarlon
8c3b10a061 Client extension changes 2020-02-07 16:24:04 +01:00
antoniocarlon
3b5f33503b Server extension changes 2020-02-07 15:52:31 +01:00
antoniocarlon
a171d91204 Merge development 2020-02-07 14:05:41 +01:00
ibrahim menem
efca8e7c9d update github actions workflow to include pg12 (#576)
* update github actions workflow to include pg12

* Pass PG_VERSION env correctly
2020-02-04 18:11:34 +01:00
Rafa de la Torre
b35e67f65a Merge pull request #575 from CartoDB/add-github-actions
add CI tests to github actions
2020-01-30 16:32:45 +01:00
ibrahim
04e81584d1 add CI tests to github actions 2020-01-30 15:50:49 +01:00
jvillarf
9e57df371a Update README.md 2020-01-21 09:00:20 +01:00
Antonio Carlón
b845717077 Merge pull request #574 from CartoDB/development
Add geocodio geocoder
2020-01-20 13:01:28 +01:00
antoniocarlon
9955b3b8ff Updated NEWS.md 2020-01-20 12:56:40 +01:00
Antonio Carlón
89dff1244f Merge pull request #571 from CartoDB/antoniocarlon/568/Add_geocodio_geocoder
Add Geocodio geocoder
2020-01-20 12:53:15 +01:00
antoniocarlon
b495fcfef3 Add geocodio geocoder to tests 2020-01-20 11:20:36 +01:00
antoniocarlon
a2f0ee01a2 Add geocodio geocoder to tests 2020-01-20 11:16:57 +01:00
antoniocarlon
0c23cc4f4f Modification to trigger the CI 2020-01-20 11:07:00 +01:00
antoniocarlon
2a68291da7 First implementation of the true Mapbox isochrones 2020-01-17 17:04:43 +01:00
antoniocarlon
861bef0382 Fixed badly generated client scripts 2020-01-15 17:40:36 +01:00
antoniocarlon
9b9f032d30 Fixed geocoding with components 2020-01-15 14:48:31 +01:00
antoniocarlon
620b02c259 Added geocodio config to the README file 2020-01-14 15:04:47 +01:00
antoniocarlon
9558df2095 Client extension sql files 2020-01-14 13:34:02 +01:00
antoniocarlon
b5d3c5fd8e Server extension sql files 2020-01-14 13:33:33 +01:00
antoniocarlon
42c9d21475 Extensions 2020-01-14 13:27:16 +01:00
antoniocarlon
1e0a8fae06 Added geocodio geocoder to the Python library 2020-01-14 13:25:44 +01:00
antoniocarlon
7a08cdf096 Old versions 2020-01-14 13:23:22 +01:00
109 changed files with 25526 additions and 510 deletions

56
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: dataservices-api PR testing
on: push
jobs:
dataservices-api:
runs-on: ubuntu-latest
strategy:
matrix:
pg_version: [10, 12]
env:
PG_VERSION: ${{ matrix.pg_version }}
steps:
- uses: actions/checkout@v1
- name: Setup gcloud authentication
uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
with:
service_account_key: ${{ secrets.GCS }}
- name: Pull base image
run: gcloud auth configure-docker && docker pull gcr.io/cartodb-on-gcp-ci-testing/cartodb-postgresql-base:${{ matrix.pg_version }}
- name: Checkout ci tools repository
uses: actions/checkout@v2
with:
repository: CartoDB/ci-tools
path: ci-tools
token: ${{ secrets.CARTOFANTE_PAT }}
- name: Copy ci files to root
run: cp ci-tools/repos/${{ github.event.repository.name }}/* .
- name: Start docker-compose services
run: docker-compose -f docker-compose.yaml up -d
- name: Install required python3 libs
run: docker-compose -f docker-compose.yaml exec -T postgres-server bash -c "cd /dataservices-api/server/ && sudo pip3 install -U -r ./lib/python/cartodb_services/requirements.txt && sudo pip3 install -U ./lib/python/cartodb_services"
if: env.PG_VERSION == 12
- name: Install required python libs
run: docker-compose -f docker-compose.yaml exec -T postgres-server bash -c "cd /dataservices-api/server/ && pip install -U -r ./lib/python/cartodb_services/requirements.txt && pip install -U ./lib/python/cartodb_services"
- name: Run python library tests
run: docker-compose -f docker-compose.yaml exec -T postgres-server bash -c "cd /dataservices-api/server/ && MAPBOX_API_KEY=$MAPBOX_API_KEY TOMTOM_API_KEY=$TOMTOM_API_KEY GEOCODIO_API_KEY=$GEOCODIO_API_KEY nosetests lib/python/cartodb_services/test"
env:
MAPBOX_API_KEY: ${{ secrets.MAPBOX_API_KEY }}
TOMTOM_API_KEY: ${{ secrets.TOMTOM_API_KEY }}
GEOCODIO_API_KEY: ${{ secrets.GEOCODIO_API_KEY }}
timeout-minutes: 5
- name: Run server tests
run: docker-compose -f docker-compose.yaml exec -T postgres-server bash -c "cd /dataservices-api/server/extension/ && sudo make clean all install installcheck || (cat /dataservices-api/server/extension/test_out/regression.diffs && false)"
timeout-minutes: 5
- name: Run client tests
run: docker-compose -f docker-compose.yaml exec -T postgres-server bash -c "sudo createuser publicuser --no-createrole --no-createdb --no-superuser -U postgres && cd /dataservices-api/client/ && sudo make clean all install installcheck || (cat /home/ubuntu/dataservices-api/client/test_out/regression.diffs && false)"
timeout-minutes: 5

29
NEWS.md
View File

@@ -1,3 +1,32 @@
Mar 17th, 2020
==============
* Version `0.29.0` of the client extension
* Adapted client to PG12 (https://github.com/CartoDB/cartodb-platform/issues/6237)
* Version `0.38.0` of the server extension
* Adapted server to PG12 (https://github.com/CartoDB/cartodb-platform/issues/6237)
* Update dependencies to fix vulnerabilities
Mar 6th, 2020
==============
* Version `0.23.1` of the Python library
* Added query per second throttle to TomTom bulk API calls
Feb 12th, 2020
==============
* Version `0.23.0` of the Python library
* Added Mapbox true isolines
* Version `0.37.0` of the server extension
* Added Mapbox true isolines
Jan 20th, 2020
==============
* Version `0.22.0` of the Python library
* Added geocodio geocoder
* Version `0.36.0` of the server extension
* Added geocodio geocoder
* Version `0.28.0` of the client extension
* Added geocodio geocoder
Oct 9th, 2019 Oct 9th, 2019
============== ==============
* Version `0.27.0` of the client extension * Version `0.27.0` of the client extension

View File

@@ -40,6 +40,7 @@ Steps to deploy a new Data Services API version :
# in dataservices-api repo root path: # in dataservices-api repo root path:
cd server/lib/python/cartodb_services && sudo pip install -r requirements.txt && sudo pip install . --upgrade cd server/lib/python/cartodb_services && sudo pip install -r requirements.txt && sudo pip install . --upgrade
``` ```
**CLOUD DEPLOY NOTE**: we were not installing automatically `requirements.txt`, so we fixed it in https://github.com/CartoDB/cartodb-platform/pull/6187 . Please, be aware that in some corner cases scenarios, rolling back to a previous version might require to manually force-install some dependency versions that were upgraded previously in this step.
- Create a database to hold all the server part and a user for it - Create a database to hold all the server part and a user for it
@@ -180,6 +181,15 @@ SELECT CDB_Conf_SetConf(
); );
``` ```
#### Geocod.io configuration
```sql
SELECT CDB_Conf_SetConf(
'geocodio_conf',
'{"geocoder": {"api_keys": ["your_api_key"], "monthly_quota": 999999}}'
);
```
#### Data Observatory #### Data Observatory
```sql ```sql

View File

@@ -14,6 +14,14 @@ AWK = awk
PG_CONFIG = pg_config PG_CONFIG = pg_config
PG_PARALLEL := $(shell $(PG_CONFIG) --version | ($(AWK) '{$$2*=1000; if ($$2 >= 9600) print 1; else print 0;}' 2> /dev/null || echo 0)) PG_PARALLEL := $(shell $(PG_CONFIG) --version | ($(AWK) '{$$2*=1000; if ($$2 >= 9600) print 1; else print 0;}' 2> /dev/null || echo 0))
# PG12 compatibility
PG_VERSION := $(shell $(PG_CONFIG) --version | $(AWK) '{split($$2,a,"."); print a[1]}')
PG_12_GE := $(shell [ $(PG_VERSION) -ge 12 ] && echo true)
PLPYTHONU := plpythonu
ifeq ($(PG_12_GE), true)
PLPYTHONU := plpython3u
endif
# OLD_VERSIONS = $(wildcard old_versions/*.sql) # OLD_VERSIONS = $(wildcard old_versions/*.sql)
# DATA = $(NEW_EXTENSION_ARTIFACT) \ # DATA = $(NEW_EXTENSION_ARTIFACT) \
# $(OLD_VERSIONS) \ # $(OLD_VERSIONS) \
@@ -25,9 +33,9 @@ DATA = $(NEW_EXTENSION_ARTIFACT) \
$(OLD_VERSIONS) $(OLD_VERSIONS)
SOURCES_DATA_DIR = sql/ SOURCES_DATA_DIR = sql/
REGRESS = $(notdir $(basename $(sort $(wildcard test/sql/*test.sql)))) REGRESS = $(notdir $(basename $(sort $(wildcard test/sql/*test.sql))))
TEST_DIR = test/ REGRESS_EXPEC = $(notdir $(basename $(sort $(wildcard test/expected/*test.out))))
TEST_DIR = test
REGRESS_OPTS = --inputdir='$(TEST_DIR)' --outputdir='$(TEST_DIR)' --user='postgres' REGRESS_OPTS = --inputdir='$(TEST_DIR)' --outputdir='$(TEST_DIR)' --user='postgres'
# DATA is a special variable used by postgres build infrastructure # DATA is a special variable used by postgres build infrastructure
@@ -54,7 +62,8 @@ SOURCES_DATA = $(wildcard $(SOURCES_DATA_DIR)/*.sql) $(GENERATED_SQL_FILES)
$(NEW_EXTENSION_ARTIFACT): $(SOURCES_DATA) $(NEW_EXTENSION_ARTIFACT): $(SOURCES_DATA)
rm -f $@ rm -f $@
cat $(SOURCES_DATA_DIR)/*.sql >> $@ cat $(SOURCES_DATA_DIR)/*.sql | \
$(SED) -e 's/@@plpythonu@@/$(PLPYTHONU)/g' >> $@
ifeq ($(PG_PARALLEL), 0) ifeq ($(PG_PARALLEL), 0)
# Remove PARALLEL in aggregates and functions # Remove PARALLEL in aggregates and functions
$(eval TMPFILE := $(shell mktemp /tmp/$(basename $0).XXXXXXXX)) $(eval TMPFILE := $(shell mktemp /tmp/$(basename $0).XXXXXXXX))
@@ -87,6 +96,8 @@ devclean:
rm -f $(NEW_EXTENSION_ARTIFACT) rm -f $(NEW_EXTENSION_ARTIFACT)
rm -f $(GENERATED_SQL_FILES) rm -f $(GENERATED_SQL_FILES)
clean: restore_copies
# If needed remove PARALLEL tags from the release files # If needed remove PARALLEL tags from the release files
release_remove_parallel_deploy: release_remove_parallel_deploy:
ifeq ($(PG_PARALLEL), 0) ifeq ($(PG_PARALLEL), 0)
@@ -97,9 +108,58 @@ ifeq ($(PG_PARALLEL), 0)
done done
endif endif
restore_copies:
# tests
for f in $(basename $(wildcard test/sql/*.copy)); do \
cat $${f}.copy > $${f}; \
done
for f in $(basename $(wildcard test/expected/*.copy)); do \
cat $${f}.copy > $${f}; \
done
rm -f test/sql/*.copy;
rm -f test/expected/*.copy;
# data
for f in $(basename $(wildcard sql/*.copy)); do \
cat $${f}.copy > $${f}; \
done
rm -f sql/*.copy;
# old_versions
for f in $(basename $(wildcard old_versions/*.copy)); do \
cat $${f}.copy > $${f}; \
done
rm -f old_versions/*.copy;
# current scripts
for f in $(basename $(wildcard *.copy)); do \
cat $${f}.copy > $${f}; \
done
rm -f *.copy;
# Replacing variables defined within test files
replace_variables: restore_copies
# tests
for f in $(sort $(wildcard test/sql/*test.sql)); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
for f in $(sort $(wildcard test/expected/*test.out)); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
# data
for f in $(wildcard sql/*.sql); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
# old_versions
for f in $(wildcard old_versions/*.sql); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
# current scripts
for f in $(wildcard *.sql); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $(EXTENSION).control;
# Install the current release into the PostgreSQL extensions directory # Install the current release into the PostgreSQL extensions directory
deploy: release_remove_parallel_deploy deploy: release_remove_parallel_deploy
$(INSTALL_DATA) $(EXTENSION).control '$(DESTDIR)$(datadir)/extension/' $(INSTALL_DATA) $(EXTENSION).control '$(DESTDIR)$(datadir)/extension/'
$(INSTALL_DATA) old_versions/*.sql *.sql '$(DESTDIR)$(datadir)/extension/' $(INSTALL_DATA) old_versions/*.sql *.sql '$(DESTDIR)$(datadir)/extension/'
install: deploy install: replace_variables deploy

View File

@@ -4,7 +4,7 @@
"requires": { "requires": {
"postgresql": "^11.0.0", "postgresql": "^11.0.0",
"postgis": "^2.5.0.0", "postgis": "^2.5.0.0",
"carto_postgresql_ext": "^0.32.0" "carto_postgresql_ext": "^0.36.0"
}, },
"works_with": { "works_with": {
} }

View File

@@ -0,0 +1,19 @@
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_client UPDATE TO '0.29.0'" to load this file. \quit
-- Make sure we have a sane search path to create/update the extension
SET search_path = "$user",cartodb,public,cdb_dataservices_client;
-- HERE goes your code to upgrade/downgrade
-- PG12_DEPRECATED
-- Create geomval if it doesn't exist (in postgis 3+ it only exists in postgis_raster)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'geomval') THEN
CREATE TYPE cdb_dataservices_client.geomval AS (
geom geometry,
val double precision
);
END IF;
END$$;

View File

@@ -0,0 +1,14 @@
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_client UPDATE TO '0.28.0'" to load this file. \quit
-- Make sure we have a sane search path to create/update the extension
SET search_path = "$user",cartodb,public,cdb_dataservices_client;
-- HERE goes your code to upgrade/downgrade
-- PG12_DEPRECATED
-- Create geomval if it doesn't exist (in postgis 3+ it only exists in postgis_raster)
DO $$
BEGIN
DROP TYPE IF EXISTS cdb_dataservices_client.geomval RESTRICT;
END$$;

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
comment = 'CartoDB dataservices client API extension' comment = 'CartoDB dataservices client API extension'
default_version = '0.27.0' default_version = '0.29.0'
requires = 'plproxy, cartodb' requires = 'plproxy, cartodb'
superuser = true superuser = true
schema = cdb_dataservices_client schema = cdb_dataservices_client

View File

@@ -0,0 +1,83 @@
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_client UPDATE TO '0.28.0'" to load this file. \quit
-- Make sure we have a sane search path to create/update the extension
SET search_path = "$user",cartodb,public,cdb_dataservices_client;
-- HERE goes your code to upgrade/downgrade
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocodio_geocode_street_point_exception_safe (searchtext text ,city text DEFAULT NULL ,state_province text DEFAULT NULL ,country text DEFAULT NULL)
RETURNS public.Geometry AS $$
DECLARE
ret public.Geometry;
username text;
orgname text;
_returned_sqlstate TEXT;
_message_text TEXT;
_pg_exception_context TEXT;
apikey_permissions json;
BEGIN
SELECT u, o, p INTO username, orgname, apikey_permissions FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text, p json);
IF apikey_permissions IS NULL OR NOT apikey_permissions::jsonb ? 'geocoding' THEN
RAISE EXCEPTION 'Geocoding permission denied';
END IF;
-- JSON value stored "" is taken as literal
IF username IS NULL OR username = '' OR username = '""' THEN
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
END IF;
BEGIN
SELECT cdb_dataservices_client._cdb_geocodio_geocode_street_point(username, orgname, searchtext, city, state_province, country) INTO ret; RETURN ret;
EXCEPTION
WHEN OTHERS THEN
GET STACKED DIAGNOSTICS _returned_sqlstate = RETURNED_SQLSTATE,
_message_text = MESSAGE_TEXT,
_pg_exception_context = PG_EXCEPTION_CONTEXT;
RAISE WARNING USING ERRCODE = _returned_sqlstate, MESSAGE = _message_text, DETAIL = _pg_exception_context;
RETURN ret;
END;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER STABLE PARALLEL UNSAFE
SET search_path = pg_temp;
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocodio_geocode_street_point (username text, orgname text, searchtext text, city text, state_province text, country text);
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocodio_geocode_street_point (username text, orgname text, searchtext text, city text DEFAULT NULL, state_province text DEFAULT NULL, country text DEFAULT NULL)
RETURNS Geometry AS $$
CONNECT cdb_dataservices_client._server_conn_str();
SELECT cdb_dataservices_server.cdb_geocodio_geocode_street_point (username, orgname, searchtext, city, state_province, country);
$$ LANGUAGE plproxy VOLATILE PARALLEL UNSAFE;
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_geocodio_geocode_street_point (searchtext text ,city text ,state_province text ,country text);
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocodio_geocode_street_point (searchtext text ,city text DEFAULT NULL ,state_province text DEFAULT NULL ,country text DEFAULT NULL)
RETURNS public.Geometry AS $$
DECLARE
ret public.Geometry;
username text;
orgname text;
apikey_permissions json;
BEGIN
SELECT u, o, p INTO username, orgname, apikey_permissions FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text, p json);
IF apikey_permissions IS NULL OR NOT apikey_permissions::jsonb ? 'geocoding' THEN
RAISE EXCEPTION 'Geocoding permission denied' USING ERRCODE = '01007';
END IF;
-- JSON value stored "" is taken as literal
IF username IS NULL OR username = '' OR username = '""' THEN
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
END IF;
SELECT cdb_dataservices_client._cdb_geocodio_geocode_street_point(username, orgname, searchtext, city, state_province, country) INTO ret; RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER STABLE PARALLEL UNSAFE
SET search_path = pg_temp;
GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocodio_geocode_street_point(searchtext text, city text, state_province text, country text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_dataservices_client._cdb_geocodio_geocode_street_point_exception_safe(searchtext text, city text, state_province text, country text ) TO publicuser;

View File

@@ -0,0 +1,14 @@
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_client UPDATE TO '0.27.0'" to load this file. \quit
-- Make sure we have a sane search path to create/update the extension
SET search_path = "$user",cartodb,public,cdb_dataservices_client;
-- HERE goes your code to upgrade/downgrade
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocodio_geocode_street_point_exception_safe;
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocodio_geocode_street_point;
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_geocodio_geocode_street_point;

File diff suppressed because it is too large Load Diff

View File

@@ -160,6 +160,17 @@
- { name: state_province, type: text, default: 'NULL'} - { name: state_province, type: text, default: 'NULL'}
- { name: country, type: text, default: 'NULL'} - { name: country, type: text, default: 'NULL'}
- name: cdb_geocodio_geocode_street_point
return_type: public.Geometry
requires_permission: true
permission_name: geocoding
permission_error: Geocoding permission denied
params:
- { name: searchtext, type: text}
- { name: city, type: text, default: 'NULL'}
- { name: state_province, type: text, default: 'NULL'}
- { name: country, type: text, default: 'NULL'}
- name: cdb_mapzen_geocode_street_point - name: cdb_mapzen_geocode_street_point
return_type: public.Geometry return_type: public.Geometry
requires_permission: true requires_permission: true

View File

@@ -18,3 +18,16 @@ $func$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_jsonb_array_casttext(jsonb) RETURNS text[] AS $f$ CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_jsonb_array_casttext(jsonb) RETURNS text[] AS $f$
SELECT array_agg(x) || ARRAY[]::text[] FROM jsonb_array_elements_text($1) t(x); SELECT array_agg(x) || ARRAY[]::text[] FROM jsonb_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE; $f$ LANGUAGE sql IMMUTABLE;
-- PG12_DEPRECATED
-- Create geomval if it doesn't exist (in postgis 3+ it only exists in postgis_raster)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'geomval') THEN
CREATE TYPE cdb_dataservices_client.geomval AS (
geom geometry,
val double precision
);
END IF;
END$$;

View File

@@ -138,7 +138,7 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_client.__DST_PrepareTableOBS_GetMeas
) )
return True return True
$$ LANGUAGE plpythonu VOLATILE PARALLEL UNSAFE; $$ LANGUAGE @@plpythonu@@ VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION cdb_dataservices_client.__DST_PopulateTableOBS_GetMeasure( CREATE OR REPLACE FUNCTION cdb_dataservices_client.__DST_PopulateTableOBS_GetMeasure(
username text, username text,
@@ -231,7 +231,7 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_client.__DST_PopulateTableOBS_GetMea
fdw_server=plpy.quote_literal(server_name))) fdw_server=plpy.quote_literal(server_name)))
return True return True
$$ LANGUAGE plpythonu VOLATILE PARALLEL UNSAFE; $$ LANGUAGE @@plpythonu@@ VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._DST_ConnectUserTable( CREATE OR REPLACE FUNCTION cdb_dataservices_client._DST_ConnectUserTable(
username text, username text,

View File

@@ -2,7 +2,7 @@
SET client_min_messages TO WARNING; SET client_min_messages TO WARNING;
-- Install dependencies -- Install dependencies
CREATE EXTENSION postgis; CREATE EXTENSION postgis;
CREATE EXTENSION plpythonu; CREATE EXTENSION @@plpythonu@@;
CREATE EXTENSION cartodb; CREATE EXTENSION cartodb;
CREATE EXTENSION plproxy; CREATE EXTENSION plproxy;
-- Install the extension -- Install the extension

View File

@@ -2,7 +2,7 @@
SET client_min_messages TO WARNING; SET client_min_messages TO WARNING;
-- Install dependencies -- Install dependencies
CREATE EXTENSION postgis; CREATE EXTENSION postgis;
CREATE EXTENSION plpythonu; CREATE EXTENSION @@plpythonu@@;
CREATE EXTENSION cartodb; CREATE EXTENSION cartodb;
CREATE EXTENSION plproxy; CREATE EXTENSION plproxy;

View File

@@ -5,7 +5,6 @@ EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/defau
# The new version to be generated from templates # The new version to be generated from templates
SED = sed SED = sed
ERB = erb ERB = erb
REPLACEMENTS = -i 's/$(EXTVERSION)/$(NEW_VERSION)/g'
NEW_EXTENSION_ARTIFACT = $(EXTENSION)--$(EXTVERSION).sql NEW_EXTENSION_ARTIFACT = $(EXTENSION)--$(EXTVERSION).sql
AWK = awk AWK = awk
@@ -14,7 +13,8 @@ PG_CONFIG = pg_config
PG_PARALLEL := $(shell $(PG_CONFIG) --version | ($(AWK) '{$$2*=1000; if ($$2 >= 9600) print 1; else print 0;}' 2> /dev/null || echo 0)) PG_PARALLEL := $(shell $(PG_CONFIG) --version | ($(AWK) '{$$2*=1000; if ($$2 >= 9600) print 1; else print 0;}' 2> /dev/null || echo 0))
REGRESS = $(notdir $(basename $(sort $(wildcard test/sql/*test.sql)))) REGRESS = $(notdir $(basename $(sort $(wildcard test/sql/*test.sql))))
TEST_DIR = test/ REGRESS_EXPEC = $(notdir $(basename $(sort $(wildcard test/expected/*test.out))))
TEST_DIR = test
REGRESS_OPTS = --inputdir='$(TEST_DIR)' --outputdir='$(TEST_DIR)' --user='postgres' REGRESS_OPTS = --inputdir='$(TEST_DIR)' --outputdir='$(TEST_DIR)' --user='postgres'
# DATA is a special variable used by postgres build infrastructure # DATA is a special variable used by postgres build infrastructure
@@ -33,6 +33,19 @@ PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs) PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS) include $(PGXS)
# PG12 compatibility
PG_VERSION := $(shell $(PG_CONFIG) --version | $(AWK) '{split($$2,a,"."); print a[1]}')
PG_12_GE := $(shell [ $(PG_VERSION) -ge 12 ] && echo true)
PLPYTHONU := plpythonu
ifeq ($(PG_12_GE), true)
PLPYTHONU := plpython3u
endif
REPLACEMENTS = -e 's/@@plpythonu@@/$(PLPYTHONU)/g'
ifneq ($(NEW_VERSION),)
REPLACEMENTS += -e 's/$(EXTVERSION)/$(NEW_VERSION)/g'
endif
$(NEW_EXTENSION_ARTIFACT): $(SOURCES_DATA) $(NEW_EXTENSION_ARTIFACT): $(SOURCES_DATA)
rm -f $@ rm -f $@
cat $(SOURCES_DATA_DIR)/*.sql >> $@ cat $(SOURCES_DATA_DIR)/*.sql >> $@
@@ -44,22 +57,27 @@ ifeq ($(PG_PARALLEL), 0)
mv $(TMPFILE) $@ mv $(TMPFILE) $@
endif endif
# $(EXTENSION).control: $(EXTENSION).control.in Makefile
# $(SED) $(REPLACEMENTS) $< > $@
.PHONY: all .PHONY: all
all: $(DATA) all: $(DATA)
.PHONY: release .PHONY: release
release: $(EXTENSION).control $(SOURCES_DATA) release: $(EXTENSION).control $(SOURCES_DATA)
test -n "$(NEW_VERSION)" # $$NEW_VERSION VARIABLE MISSING. Eg. make release NEW_VERSION=0.x.0 test -n "$(NEW_VERSION)" # $$NEW_VERSION VARIABLE MISSING. Eg. make release NEW_VERSION=0.x.0
git mv *.sql old_versions for f in $(wildcard *.sql); do \
$(SED) $(REPLACEMENTS) $(EXTENSION).control git mv $${f} old_versions/$${f}; \
done
$(SED) -i 's/$(EXTVERSION)/$(NEW_VERSION)/g' $(EXTENSION).control
git add $(EXTENSION).control git add $(EXTENSION).control
cat $(SOURCES_DATA_DIR)/*.sql > $(EXTENSION)--$(NEW_VERSION).sql cat $(SOURCES_DATA_DIR)/*.sql > $(EXTENSION)--$(NEW_VERSION).sql
$(ERB) version=$(NEW_VERSION) upgrade_downgrade_template.erb > $(EXTENSION)--$(EXTVERSION)--$(NEW_VERSION).sql $(ERB) version=$(NEW_VERSION) upgrade_downgrade_template.erb > $(EXTENSION)--$(EXTVERSION)--$(NEW_VERSION).sql
$(ERB) version=$(EXTVERSION) upgrade_downgrade_template.erb > $(EXTENSION)--$(NEW_VERSION)--$(EXTVERSION).sql $(ERB) version=$(EXTVERSION) upgrade_downgrade_template.erb > $(EXTENSION)--$(NEW_VERSION)--$(EXTVERSION).sql
git add $(EXTENSION)--$(NEW_VERSION).sql git add $(EXTENSION)--$(NEW_VERSION).sql
@echo @echo
@echo "Please review the file $(EXTENSION)--$(EXTVERSION)--$(NEW_VERSION).sql and add any code needed to upgrade $(EXTVERSION) to $(NEW_VERSION)" @echo "Please review the file $(EXTENSION)--$(EXTVERSION)--$(NEW_VERSION).sql.in and add any code needed to upgrade $(EXTVERSION) to $(NEW_VERSION)"
@echo "Please review the file $(EXTENSION)--$(NEW_VERSION)--$(EXTVERSION).sql and add any code needed to downgrade $(NEW_VERSION) to $(EXTVERSION)" @echo "Please review the file $(EXTENSION)--$(NEW_VERSION)--$(EXTVERSION).sql.in and add any code needed to downgrade $(NEW_VERSION) to $(EXTVERSION)"
@echo @echo
# Only meant for development time, do not use once a version is released # Only meant for development time, do not use once a version is released
@@ -67,6 +85,8 @@ release: $(EXTENSION).control $(SOURCES_DATA)
devclean: devclean:
rm -f $(NEW_EXTENSION_ARTIFACT) rm -f $(NEW_EXTENSION_ARTIFACT)
clean: restore_copies
# If needed remove PARALLEL tags from the release files # If needed remove PARALLEL tags from the release files
release_remove_parallel_deploy: release_remove_parallel_deploy:
ifeq ($(PG_PARALLEL), 0) ifeq ($(PG_PARALLEL), 0)
@@ -82,7 +102,60 @@ deploy: release_remove_parallel_deploy
$(INSTALL_DATA) $(EXTENSION).control '$(DESTDIR)$(datadir)/extension/' $(INSTALL_DATA) $(EXTENSION).control '$(DESTDIR)$(datadir)/extension/'
$(INSTALL_DATA) old_versions/*.sql *.sql '$(DESTDIR)$(datadir)/extension/' $(INSTALL_DATA) old_versions/*.sql *.sql '$(DESTDIR)$(datadir)/extension/'
install: deploy restore_copies:
# tests
for f in $(basename $(wildcard test/sql/*.copy)); do \
cat $${f}.copy > $${f}; \
done
for f in $(basename $(wildcard test/expected/*.copy)); do \
cat $${f}.copy > $${f}; \
done
rm -f test/sql/*.copy;
rm -f test/expected/*.copy;
# data
for f in $(basename $(wildcard sql/*.copy)); do \
cat $${f}.copy > $${f}; \
done
rm -f sql/*.copy;
# old_versions
for f in $(basename $(wildcard old_versions/*.copy)); do \
cat $${f}.copy > $${f}; \
done
rm -f old_versions/*.copy;
# current scripts
for f in $(basename $(wildcard *.copy)); do \
cat $${f}.copy > $${f}; \
done
rm -f *.copy;
# %.sql:
# $(SED) $(REPLACEMENTS) $< > $@
# Replacing variables defined within test files
replace_variables: restore_copies
# tests
for f in $(sort $(wildcard test/sql/*test.sql)); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
for f in $(sort $(wildcard test/expected/*test.out)); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
# data
for f in $(SOURCES_DATA); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
# old_versions
for f in $(wildcard old_versions/*.sql); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
# current scripts
for f in $(wildcard *.sql); do \
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $${f}; \
done
sed --in-place=.copy -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $(EXTENSION).control;
install: replace_variables deploy
reinstall: install reinstall: install
psql -U postgres -d dataservices_db -c "drop extension if exists cdb_dataservices_server; create extension cdb_dataservices_server;" psql -U postgres -d dataservices_db -c "drop extension if exists cdb_dataservices_server; create extension cdb_dataservices_server;"

View File

@@ -4,10 +4,10 @@
"requires": { "requires": {
"postgresql": "^10.0.0", "postgresql": "^10.0.0",
"postgis": "^2.4.0.0", "postgis": "^2.4.0.0",
"carto_postgresql_ext": "^0.23.0" "carto_postgresql_ext": "^0.36.0"
}, },
"works_with": { "works_with": {
"dataservices-api-server-python-lib": "^0.19.1", "dataservices-api-server-python-lib": "^0.23.1",
"observatory-server-extension": "^1.9.0" "observatory-server-extension": "^1.9.0"
} }
} }

View File

@@ -0,0 +1,76 @@
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.38.0'" to load this file. \quit
-- HERE goes your code to upgrade/downgrade
-- PG12_DEPRECATED
-- Create geomval if it doesn't exist (in postgis 3+ it only exists in postgis_raster)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'geomval') THEN
CREATE TYPE cdb_dataservices_server.geomval AS (
geom geometry,
val double precision
);
END IF;
END$$;
---- cdb_geocode_namedplace_point(city_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
RETURNS Geometry AS $$
from plpy import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
try:
street_point = plpy.prepare("SELECT cdb_dataservices_server.cdb_geocode_street_point($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(street_point, [username, orgname, city_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
import sys
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name])[0]['point']
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
---- cdb_geocode_namedplace_point(city_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
RETURNS Geometry AS $$
from plpy import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
try:
street_point = plpy.prepare("SELECT cdb_dataservices_server.cdb_geocode_street_point($1, $2, $3, NULL, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(street_point, [username, orgname, city_name, country_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
import sys
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, country_name])[0]['point']
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
RETURNS Geometry AS $$
from plpy import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
try:
street_point = plpy.prepare("SELECT cdb_dataservices_server.cdb_geocode_street_point($1, $2, $3, NULL, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(street_point, [username, orgname, city_name, admin1_name, country_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
import sys
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -0,0 +1,71 @@
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.37.0'" to load this file. \quit
-- HERE goes your code to upgrade/downgrade
-- PG12_DEPRECATED
-- Create geomval if it doesn't exist (in postgis 3+ it only exists in postgis_raster)
DO $$
BEGIN
DROP TYPE IF EXISTS cdb_dataservices_server.geomval RESTRICT;
END$$;
---- cdb_geocode_namedplace_point(city_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
RETURNS Geometry AS $$
import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
try:
street_point = plpy.prepare("SELECT cdb_dataservices_server.cdb_geocode_street_point($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(street_point, [username, orgname, city_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
import sys
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name])[0]['point']
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
---- cdb_geocode_namedplace_point(city_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
RETURNS Geometry AS $$
import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
try:
street_point = plpy.prepare("SELECT cdb_dataservices_server.cdb_geocode_street_point($1, $2, $3, NULL, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(street_point, [username, orgname, city_name, country_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
import sys
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, country_name])[0]['point']
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
RETURNS Geometry AS $$
import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
try:
street_point = plpy.prepare("SELECT cdb_dataservices_server.cdb_geocode_street_point($1, $2, $3, NULL, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(street_point, [username, orgname, city_name, admin1_name, country_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
import sys
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
comment = 'CartoDB dataservices server extension' comment = 'CartoDB dataservices server extension'
default_version = '0.35.1' default_version = '0.38.0'
requires = 'plpythonu, plproxy, postgis, cdb_geocoder' requires = '@@plpythonu@@, plproxy, postgis, cdb_geocoder'
superuser = true superuser = true
schema = cdb_dataservices_server schema = cdb_dataservices_server

View File

@@ -0,0 +1,197 @@
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.36.0'" to load this file. \quit
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$
from cartodb_services.metrics import metrics
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
params = {'username': username, 'orgname': orgname, 'searchtext': searchtext, 'city': city, 'state_province': state_province, 'country': country}
with metrics('cdb_geocode_street_point', user_geocoder_config, logger, params):
if user_geocoder_config.heremaps_geocoder:
here_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.google_geocoder:
google_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.mapzen_geocoder:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.mapbox_geocoder:
mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.tomtom_geocoder:
tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.geocodio_geocoder:
geocodio_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocodio_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(geocodio_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
else:
raise Exception('Requested geocoder is not available')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocodio_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$
# The configuration is retrieved but no checks are performed on it
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
geocodio_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocodio_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(geocodio_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocodio_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$
from iso3166 import countries
from cartodb_services.tools import ServiceManager, QuotaExceededException
from cartodb_services.geocodio import GeocodioGeocoder
from cartodb_services.tools.country import country_to_iso3
from cartodb_services.refactor.service.geocodio_geocoder_config import GeocodioGeocoderConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_manager = ServiceManager('geocoder', GeocodioGeocoderConfigBuilder, username, orgname, GD)
try:
service_manager.assert_within_limits()
geocoder = GeocodioGeocoder(service_manager.config.geocodio_api_key, service_manager.logger, service_manager.config.service_params)
country_iso3166 = None
if country:
country_iso3 = country_to_iso3(country)
if country_iso3:
country_iso3166 = countries.get(country_iso3).alpha2.lower()
coordinates = geocoder.geocode(searchtext=searchtext, city=city,
state_province=state_province,
country=country_iso3166)
if coordinates:
service_manager.quota_service.increment_success_service_use()
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
return point['st_setsrid']
else:
service_manager.quota_service.increment_empty_service_use()
return None
except QuotaExceededException as qe:
service_manager.quota_service.increment_failed_service_use()
return None
except BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to geocode street point using Geocodio', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using Geocodio')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_geocode_street_point(username TEXT, orgname TEXT, searches jsonb)
RETURNS SETOF cdb_dataservices_server.geocoding AS $$
from cartodb_services.metrics import metrics
from cartodb_services.tools import Logger
import json
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
params = {'username': username, 'orgname': orgname, 'searches': json.loads(searches)}
with metrics('cdb_bulk_geocode_street_point', user_geocoder_config, logger, params):
if user_geocoder_config.google_geocoder:
provider_function = "_cdb_bulk_google_geocode_street_point";
elif user_geocoder_config.heremaps_geocoder:
provider_function = "_cdb_bulk_heremaps_geocode_street_point";
elif user_geocoder_config.tomtom_geocoder:
provider_function = "_cdb_bulk_tomtom_geocode_street_point";
elif user_geocoder_config.mapbox_geocoder:
provider_function = "_cdb_bulk_mapbox_geocode_street_point";
elif user_geocoder_config.geocodio_geocoder:
provider_function = "_cdb_bulk_geocodio_geocode_street_point";
else:
raise Exception('Requested geocoder is not available')
plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.{}($1, $2, $3); ".format(provider_function), ["text", "text", "jsonb"])
return plpy.execute(plan, [username, orgname, searches])
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_geocodio_geocode_street_point(username TEXT, orgname TEXT, searches jsonb)
RETURNS SETOF cdb_dataservices_server.geocoding AS $$
from cartodb_services import run_street_point_geocoder
from cartodb_services.tools import ServiceManager
from cartodb_services.refactor.service.geocodio_geocoder_config import GeocodioGeocoderConfigBuilder
from cartodb_services.geocodio import GeocodioBulkGeocoder
from cartodb_services.tools import Logger
import cartodb_services
cartodb_services.init(plpy, GD)
logger_config = GD["logger_config"]
logger = Logger(logger_config)
service_manager = ServiceManager('geocoder', GeocodioGeocoderConfigBuilder, username, orgname, GD)
geocoder = GeocodioBulkGeocoder(service_manager.config.geocodio_api_key, service_manager.logger, service_manager.config.service_params)
return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches)
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_admin0_polygon(username text, orgname text, country_name text)
RETURNS Geometry AS $$
from cartodb_services.metrics import QuotaService
from cartodb_services.metrics import InternalGeocoderConfig
from cartodb_services.metrics import metrics
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
plpy.execute("SELECT cdb_dataservices_server._get_internal_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_geocoder_config = GD["user_internal_geocoder_config_{0}".format(username)]
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
quota_service = QuotaService(user_geocoder_config, redis_conn)
params = {'username': username, 'orgname': orgname, 'country_name': country_name}
with metrics('cdb_geocode_admin0_polygon', user_geocoder_config, logger, params):
try:
plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_admin0_polygon(trim($1)) AS mypolygon", ["text"])
rv = plpy.execute(plan, [country_name], 1)
result = rv[0]["mypolygon"]
if result:
quota_service.increment_success_service_use()
return result
else:
quota_service.increment_empty_service_use()
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to geocode admin0 polygon', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode admin0 polygon')
finally:
quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;

View File

@@ -0,0 +1,79 @@
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.35.1'" to load this file. \quit
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$
from cartodb_services.metrics import metrics
from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
params = {'username': username, 'orgname': orgname, 'searchtext': searchtext, 'city': city, 'state_province': state_province, 'country': country}
with metrics('cdb_geocode_street_point', user_geocoder_config, logger, params):
if user_geocoder_config.heremaps_geocoder:
here_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.google_geocoder:
google_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.mapzen_geocoder:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.mapbox_geocoder:
mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.tomtom_geocoder:
tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
else:
raise Exception('Requested geocoder is not available')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_geocodio_geocode_street_point;
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_geocodio_geocode_street_point;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_geocode_street_point(username TEXT, orgname TEXT, searches jsonb)
RETURNS SETOF cdb_dataservices_server.geocoding AS $$
from cartodb_services.metrics import metrics
from cartodb_services.tools import Logger
import json
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
params = {'username': username, 'orgname': orgname, 'searches': json.loads(searches)}
with metrics('cdb_bulk_geocode_street_point', user_geocoder_config, logger, params):
if user_geocoder_config.google_geocoder:
provider_function = "_cdb_bulk_google_geocode_street_point";
elif user_geocoder_config.heremaps_geocoder:
provider_function = "_cdb_bulk_heremaps_geocode_street_point";
elif user_geocoder_config.tomtom_geocoder:
provider_function = "_cdb_bulk_tomtom_geocode_street_point";
elif user_geocoder_config.mapbox_geocoder:
provider_function = "_cdb_bulk_mapbox_geocode_street_point";
else:
raise Exception('Requested geocoder is not available')
plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.{}($1, $2, $3); ".format(provider_function), ["text", "text", "jsonb"])
return plpy.execute(plan, [username, orgname, searches])
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_bulk_geocodio_geocode_street_point;

View File

@@ -0,0 +1,126 @@
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.37.0'" to load this file. \quit
-- HERE goes your code to upgrade/downgrade
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isodistance(
username TEXT,
orgname TEXT,
source geometry(Geometry, 4326),
mode TEXT,
data_range integer[],
options text[])
RETURNS SETOF cdb_dataservices_server.isoline AS $$
from cartodb_services.tools import ServiceManager
from cartodb_services.mapbox import MapboxIsolines
from cartodb_services.mapbox.types import TRANSPORT_MODE_TO_MAPBOX
from cartodb_services.tools import Coordinate
from cartodb_services.refactor.service.mapbox_isolines_config import MapboxIsolinesConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_manager = ServiceManager('isolines', MapboxIsolinesConfigBuilder, username, orgname, GD)
service_manager.assert_within_limits()
try:
mapbox_isolines = MapboxIsolines(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params)
if source:
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
lon = plpy.execute("SELECT ST_X('%s') AS lon" % source)[0]['lon']
origin = Coordinate(lon,lat)
else:
raise Exception('source is NULL')
profile = TRANSPORT_MODE_TO_MAPBOX.get(mode)
# -- TODO Support options properly
isolines = {}
for r in data_range:
isoline = mapbox_isolines.calculate_isodistance(origin, r, profile)
isolines[r] = isoline
result = []
for r in data_range:
if len(isolines[r]) >= 3:
# -- TODO encapsulate this block into a func/method
locations = isolines[r] + [ isolines[r][0] ] # close the polygon repeating the first point
wkt_coordinates = ','.join(["%f %f" % (l.longitude, l.latitude) for l in locations])
sql = "SELECT ST_CollectionExtract(ST_MakeValid(ST_MPolyFromText('MULTIPOLYGON((({0})))', 4326)),3) as geom".format(wkt_coordinates)
multipolygon = plpy.execute(sql, 1)[0]['geom']
else:
multipolygon = None
result.append([source, r, multipolygon])
service_manager.quota_service.increment_success_service_use()
service_manager.quota_service.increment_isolines_service_use(len(isolines))
return result
except BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to get Mapbox isolines', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to get Mapbox isolines')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isochrones(
username TEXT,
orgname TEXT,
source geometry(Geometry, 4326),
mode TEXT,
data_range integer[],
options text[])
RETURNS SETOF cdb_dataservices_server.isoline AS $$
from cartodb_services.tools import ServiceManager
from cartodb_services.mapbox import MapboxIsolines
from cartodb_services.mapbox.types import TRANSPORT_MODE_TO_MAPBOX
from cartodb_services.tools import Coordinate
from cartodb_services.tools.coordinates import coordinates_to_polygon
from cartodb_services.refactor.service.mapbox_isolines_config import MapboxIsolinesConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_manager = ServiceManager('isolines', MapboxIsolinesConfigBuilder, username, orgname, GD)
service_manager.assert_within_limits()
try:
mapbox_isolines = MapboxIsolines(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params)
if source:
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
lon = plpy.execute("SELECT ST_X('%s') AS lon" % source)[0]['lon']
origin = Coordinate(lon,lat)
else:
raise Exception('source is NULL')
profile = TRANSPORT_MODE_TO_MAPBOX.get(mode)
resp = mapbox_isolines.calculate_isochrone(origin, data_range, profile)
if resp:
result = []
for isochrone in resp:
result_polygon = coordinates_to_polygon(isochrone.coordinates)
if result_polygon:
result.append([source, isochrone.duration, result_polygon])
else:
result.append([source, isochrone.duration, None])
service_manager.quota_service.increment_success_service_use()
service_manager.quota_service.increment_isolines_service_use(len(result))
return result
else:
service_manager.quota_service.increment_empty_service_use()
return []
except BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to get Mapbox isochrones', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to get Mapbox isochrones')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.36.0'" to load this file. \quit
-- HERE goes your code to upgrade/downgrade
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isodistance(
username TEXT,
orgname TEXT,
source geometry(Geometry, 4326),
mode TEXT,
data_range integer[],
options text[])
RETURNS SETOF cdb_dataservices_server.isoline AS $$
from cartodb_services.tools import ServiceManager
from cartodb_services.mapbox import MapboxMatrixClient, MapboxIsolines
from cartodb_services.mapbox.types import TRANSPORT_MODE_TO_MAPBOX
from cartodb_services.tools import Coordinate
from cartodb_services.refactor.service.mapbox_isolines_config import MapboxIsolinesConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_manager = ServiceManager('isolines', MapboxIsolinesConfigBuilder, username, orgname, GD)
service_manager.assert_within_limits()
try:
client = MapboxMatrixClient(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params)
mapbox_isolines = MapboxIsolines(client, service_manager.logger)
if source:
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
lon = plpy.execute("SELECT ST_X('%s') AS lon" % source)[0]['lon']
origin = Coordinate(lon,lat)
else:
raise Exception('source is NULL')
profile = TRANSPORT_MODE_TO_MAPBOX.get(mode)
# -- TODO Support options properly
isolines = {}
for r in data_range:
isoline = mapbox_isolines.calculate_isodistance(origin, r, profile)
isolines[r] = isoline
result = []
for r in data_range:
if len(isolines[r]) >= 3:
# -- TODO encapsulate this block into a func/method
locations = isolines[r] + [ isolines[r][0] ] # close the polygon repeating the first point
wkt_coordinates = ','.join(["%f %f" % (l.longitude, l.latitude) for l in locations])
sql = "SELECT st_multi(ST_CollectionExtract(ST_MakeValid(ST_MPolyFromText('MULTIPOLYGON((({0})))', 4326)),3)) as geom".format(wkt_coordinates)
multipolygon = plpy.execute(sql, 1)[0]['geom']
else:
multipolygon = None
result.append([source, r, multipolygon])
service_manager.quota_service.increment_success_service_use()
service_manager.quota_service.increment_isolines_service_use(len(isolines))
return result
except BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to get Mapbox isolines', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to get Mapbox isolines')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isochrones(
username TEXT,
orgname TEXT,
source geometry(Geometry, 4326),
mode TEXT,
data_range integer[],
options text[])
RETURNS SETOF cdb_dataservices_server.isoline AS $$
from cartodb_services.tools import ServiceManager
from cartodb_services.mapbox import MapboxMatrixClient, MapboxIsolines
from cartodb_services.mapbox.types import TRANSPORT_MODE_TO_MAPBOX
from cartodb_services.tools import Coordinate
from cartodb_services.tools.coordinates import coordinates_to_polygon
from cartodb_services.refactor.service.mapbox_isolines_config import MapboxIsolinesConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_manager = ServiceManager('isolines', MapboxIsolinesConfigBuilder, username, orgname, GD)
service_manager.assert_within_limits()
try:
client = MapboxMatrixClient(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params)
mapbox_isolines = MapboxIsolines(client, service_manager.logger)
if source:
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
lon = plpy.execute("SELECT ST_X('%s') AS lon" % source)[0]['lon']
origin = Coordinate(lon,lat)
else:
raise Exception('source is NULL')
profile = TRANSPORT_MODE_TO_MAPBOX.get(mode)
resp = mapbox_isolines.calculate_isochrone(origin, data_range, profile)
if resp:
result = []
for isochrone in resp:
result_polygon = coordinates_to_polygon(isochrone.coordinates)
if result_polygon:
result.append([source, isochrone.duration, result_polygon])
else:
result.append([source, isochrone.duration, None])
service_manager.quota_service.increment_success_service_use()
service_manager.quota_service.increment_isolines_service_use(len(result))
return result
else:
service_manager.quota_service.increment_empty_service_use()
return []
except BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to get Mapbox isochrones', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to get Mapbox isochrones')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
-- PG12_DEPRECATED
-- Create geomval if it doesn't exist (in postgis 3+ it only exists in postgis_raster)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'geomval') THEN
CREATE TYPE cdb_dataservices_server.geomval AS (
geom geometry,
val double precision
);
END IF;
END$$;

View File

@@ -69,7 +69,7 @@ RETURNS cdb_dataservices_server.simple_route AS $$
raise Exception('Error trying to calculate Mapbox routing') raise Exception('Error trying to calculate Mapbox routing')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_route_with_waypoints( CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_route_with_waypoints(
username TEXT, username TEXT,
@@ -137,7 +137,7 @@ RETURNS cdb_dataservices_server.simple_route AS $$
raise Exception('Error trying to calculate TomTom routing') raise Exception('Error trying to calculate TomTom routing')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_route_with_waypoints( CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_route_with_waypoints(
username TEXT, username TEXT,
@@ -198,4 +198,4 @@ RETURNS cdb_dataservices_server.simple_route AS $$
raise Exception('Error trying to calculate mapzen routing') raise Exception('Error trying to calculate mapzen routing')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;

View File

@@ -37,7 +37,7 @@ RETURNS cdb_dataservices_server.simple_route AS $$
return [result[0]['shape'],result[0]['length'], result[0]['duration']] return [result[0]['shape'],result[0]['length'], result[0]['duration']]
else: else:
raise Exception('Requested routing method is not available') raise Exception('Requested routing method is not available')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_route_with_waypoints( CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_route_with_waypoints(
@@ -76,4 +76,4 @@ RETURNS cdb_dataservices_server.simple_route AS $$
return [result[0]['shape'],result[0]['length'], result[0]['duration']] return [result[0]['shape'],result[0]['length'], result[0]['duration']]
else: else:
raise Exception('Requested routing method is not available') raise Exception('Requested routing method is not available')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -15,4 +15,4 @@ RETURNS boolean AS $$
'redis_metrics_connection': redis_metrics_connection, 'redis_metrics_connection': redis_metrics_connection,
} }
return True return True
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;

View File

@@ -14,7 +14,7 @@ RETURNS text AS $$
user_obs_config = GD["user_obs_config_{0}".format(username)] user_obs_config = GD["user_obs_config_{0}".format(username)]
return user_obs_config.connection_str return user_obs_config.connection_str
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshotJSON( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshotJSON(
username TEXT, username TEXT,
@@ -68,7 +68,7 @@ RETURNS json AS $$
raise Exception('Error trying to obs_get_demographic_snapshot') raise Exception('Error trying to obs_get_demographic_snapshot')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot(
username TEXT, username TEXT,
@@ -125,7 +125,7 @@ RETURNS SETOF JSON AS $$
raise Exception('Error trying to obs_get_demographic_snapshot') raise Exception('Error trying to obs_get_demographic_snapshot')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshotJSON( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshotJSON(
username TEXT, username TEXT,
@@ -177,7 +177,7 @@ RETURNS json AS $$
raise Exception('Error trying to obs_get_segment_snapshot') raise Exception('Error trying to obs_get_segment_snapshot')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot(
username TEXT, username TEXT,
@@ -232,7 +232,7 @@ RETURNS SETOF JSON AS $$
raise Exception('Error trying to OBS_GetSegmentSnapshot') raise Exception('Error trying to OBS_GetSegmentSnapshot')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeasure( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeasure(
username TEXT, username TEXT,
@@ -289,7 +289,7 @@ RETURNS NUMERIC AS $$
raise Exception('Error trying to OBS_GetMeasure') raise Exception('Error trying to OBS_GetMeasure')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetCategory( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetCategory(
username TEXT, username TEXT,
@@ -344,7 +344,7 @@ RETURNS TEXT AS $$
raise Exception('Error trying to OBS_GetCategory') raise Exception('Error trying to OBS_GetCategory')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusMeasure( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusMeasure(
username TEXT, username TEXT,
@@ -401,7 +401,7 @@ RETURNS NUMERIC AS $$
raise Exception('Error trying to OBS_GetUSCensusMeasure') raise Exception('Error trying to OBS_GetUSCensusMeasure')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusCategory( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusCategory(
username TEXT, username TEXT,
@@ -456,7 +456,7 @@ RETURNS TEXT AS $$
raise Exception('Error trying to OBS_GetUSCensusCategory') raise Exception('Error trying to OBS_GetUSCensusCategory')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPopulation( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPopulation(
username TEXT, username TEXT,
@@ -511,7 +511,7 @@ RETURNS NUMERIC AS $$
raise Exception('Error trying to OBS_GetPopulation') raise Exception('Error trying to OBS_GetPopulation')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeasureById( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeasureById(
username TEXT, username TEXT,
@@ -566,7 +566,7 @@ RETURNS NUMERIC AS $$
raise Exception('Error trying to OBS_GetMeasureById') raise Exception('Error trying to OBS_GetMeasureById')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetData( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetData(
username TEXT, username TEXT,
@@ -627,7 +627,7 @@ RETURNS TABLE (
raise Exception('Error trying to OBS_GetData') raise Exception('Error trying to OBS_GetData')
finally: finally:
quota_service.increment_total_service_use(len(geomvals)) quota_service.increment_total_service_use(len(geomvals))
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetData( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetData(
username TEXT, username TEXT,
@@ -688,7 +688,7 @@ RETURNS TABLE (
raise Exception('Error trying to OBS_GetData') raise Exception('Error trying to OBS_GetData')
finally: finally:
quota_service.increment_total_service_use(len(geomrefs)) quota_service.increment_total_service_use(len(geomrefs))
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeta( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeta(
username TEXT, username TEXT,
@@ -736,7 +736,7 @@ RETURNS JSON AS $$
import sys import sys
logger.error('Error trying to OBS_GetMeta', sys.exc_info(), data={"username": username, "orgname": orgname}) logger.error('Error trying to OBS_GetMeta', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetMeta') raise Exception('Error trying to OBS_GetMeta')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_MetadataValidation( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_MetadataValidation(
username TEXT, username TEXT,
@@ -782,4 +782,4 @@ RETURNS TABLE(valid boolean, errors text[]) AS $$
import sys import sys
logger.error('Error trying to OBS_MetadataValidation', sys.exc_info(), data={"username": username, "orgname": orgname}) logger.error('Error trying to OBS_MetadataValidation', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_MetadataValidation') raise Exception('Error trying to OBS_MetadataValidation')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -55,7 +55,7 @@ RETURNS TABLE(id text, description text, name text, aggregate text, source text)
raise Exception('Error trying to OBS_Search') raise Exception('Error trying to OBS_Search')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetAvailableBoundaries( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetAvailableBoundaries(
username TEXT, username TEXT,
@@ -113,4 +113,4 @@ RETURNS TABLE(boundary_id text, description text, time_span text, tablename text
raise Exception('Error trying to OBS_GetMeasureById') raise Exception('Error trying to OBS_GetMeasureById')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -49,7 +49,7 @@ RETURNS geometry(Geometry, 4326) AS $$
raise Exception('Error trying to OBS_GetBoundary') raise Exception('Error trying to OBS_GetBoundary')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryId( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryId(
username TEXT, username TEXT,
@@ -102,7 +102,7 @@ RETURNS TEXT AS $$
raise Exception('Error trying to OBS_GetBoundaryId') raise Exception('Error trying to OBS_GetBoundaryId')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryById( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryById(
username TEXT, username TEXT,
@@ -155,7 +155,7 @@ RETURNS geometry(Geometry, 4326) AS $$
raise Exception('Error trying to OBS_GetBoundaryById') raise Exception('Error trying to OBS_GetBoundaryById')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByGeometry( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByGeometry(
username TEXT, username TEXT,
@@ -215,7 +215,7 @@ RETURNS TABLE(the_geom geometry, geom_refs text) AS $$
raise Exception('Error trying to OBS_GetBoundariesByGeometry') raise Exception('Error trying to OBS_GetBoundariesByGeometry')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius(
username TEXT, username TEXT,
@@ -277,7 +277,7 @@ RETURNS TABLE(the_geom geometry, geom_refs text) AS $$
raise Exception('Error trying to OBS_GetBoundariesByPointAndRadius') raise Exception('Error trying to OBS_GetBoundariesByPointAndRadius')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByGeometry( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByGeometry(
username TEXT, username TEXT,
@@ -337,7 +337,7 @@ RETURNS TABLE(the_geom geometry, geom_refs text) AS $$
raise Exception('Error trying to OBS_GetPointsByGeometry') raise Exception('Error trying to OBS_GetPointsByGeometry')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByPointAndRadius( CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByPointAndRadius(
username TEXT, username TEXT,
@@ -399,4 +399,4 @@ RETURNS TABLE(the_geom geometry, geom_refs text) AS $$
raise Exception('Error trying to OBS_GetPointsByPointAndRadius') raise Exception('Error trying to OBS_GetPointsByPointAndRadius')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -8,7 +8,7 @@ RETURNS cdb_dataservices_server.ds_fdw_metadata AS $$
return plpy.execute("SELECT * FROM cdb_dataservices_server.__DST_ConnectUserTable({username}::text, {orgname}::text, {user_db_role}::text, {schema}::text, {dbname}::text, {host_addr}::text, {table_name}::text)" return plpy.execute("SELECT * FROM cdb_dataservices_server.__DST_ConnectUserTable({username}::text, {orgname}::text, {user_db_role}::text, {schema}::text, {dbname}::text, {host_addr}::text, {table_name}::text)"
.format(username=plpy.quote_nullable(username), orgname=plpy.quote_nullable(orgname), user_db_role=plpy.quote_literal(user_db_role), schema=plpy.quote_literal(input_schema), dbname=plpy.quote_literal(dbname), table_name=plpy.quote_literal(table_name), host_addr=plpy.quote_literal(host_addr)) .format(username=plpy.quote_nullable(username), orgname=plpy.quote_nullable(orgname), user_db_role=plpy.quote_literal(user_db_role), schema=plpy.quote_literal(input_schema), dbname=plpy.quote_literal(dbname), table_name=plpy.quote_literal(table_name), host_addr=plpy.quote_literal(host_addr))
)[0] )[0]
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.__DST_ConnectUserTable(username text, orgname text, user_db_role text, input_schema text, dbname text, host_addr text, table_name text) CREATE OR REPLACE FUNCTION cdb_dataservices_server.__DST_ConnectUserTable(username text, orgname text, user_db_role text, input_schema text, dbname text, host_addr text, table_name text)
RETURNS cdb_dataservices_server.ds_fdw_metadata AS $$ RETURNS cdb_dataservices_server.ds_fdw_metadata AS $$

View File

@@ -8,7 +8,7 @@ RETURNS boolean AS $$
logger_config = LoggerConfig(plpy) logger_config = LoggerConfig(plpy)
GD[cache_key] = logger_config GD[cache_key] = logger_config
return True return True
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
-- This is done in order to avoid an undesired depedency on cartodb extension -- This is done in order to avoid an undesired depedency on cartodb extension
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_conf_getconf(input_key text) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_conf_getconf(input_key text)
@@ -46,7 +46,7 @@ RETURNS boolean AS $$
geocoder_config = GeocoderConfig(redis_conn, plpy, username, orgname, provider) geocoder_config = GeocoderConfig(redis_conn, plpy, username, orgname, provider)
GD[cache_key] = geocoder_config GD[cache_key] = geocoder_config
return True return True
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_internal_geocoder_config(username text, orgname text) CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_internal_geocoder_config(username text, orgname text)
RETURNS boolean AS $$ RETURNS boolean AS $$
@@ -60,7 +60,7 @@ RETURNS boolean AS $$
geocoder_config = InternalGeocoderConfig(redis_conn, plpy, username, orgname) geocoder_config = InternalGeocoderConfig(redis_conn, plpy, username, orgname)
GD[cache_key] = geocoder_config GD[cache_key] = geocoder_config
return True return True
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_isolines_routing_config(username text, orgname text) CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_isolines_routing_config(username text, orgname text)
RETURNS boolean AS $$ RETURNS boolean AS $$
@@ -74,7 +74,7 @@ RETURNS boolean AS $$
isolines_routing_config = IsolinesRoutingConfig(redis_conn, plpy, username, orgname) isolines_routing_config = IsolinesRoutingConfig(redis_conn, plpy, username, orgname)
GD[cache_key] = isolines_routing_config GD[cache_key] = isolines_routing_config
return True return True
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_routing_config(username text, orgname text) CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_routing_config(username text, orgname text)
RETURNS boolean AS $$ RETURNS boolean AS $$
@@ -88,7 +88,7 @@ RETURNS boolean AS $$
routing_config = RoutingConfig(redis_conn, plpy, username, orgname) routing_config = RoutingConfig(redis_conn, plpy, username, orgname)
GD[cache_key] = routing_config GD[cache_key] = routing_config
return True return True
$$ LANGUAGE plpythonu SECURITY DEFINER; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_obs_config(username text, orgname text) CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_obs_config(username text, orgname text)
RETURNS boolean AS $$ RETURNS boolean AS $$
@@ -102,4 +102,4 @@ RETURNS boolean AS $$
obs_config = ObservatoryConfig(redis_conn, plpy, username, orgname) obs_config = ObservatoryConfig(redis_conn, plpy, username, orgname)
GD[cache_key] = obs_config GD[cache_key] = obs_config
return True return True
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;

View File

@@ -106,7 +106,7 @@ RETURNS SETOF cdb_dataservices_server.service_quota_info AS $$
ret += [[service, monthly_quota, used_quota, soft_limit, provider]] ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
return ret return ret
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_quota_info_batch( CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_quota_info_batch(
@@ -136,7 +136,7 @@ RETURNS SETOF cdb_dataservices_server.service_quota_info_batch AS $$
ret += [[info['service'], info['monthly_quota'], info['used_quota'], info['soft_limit'], info['provider'], info['max_batch_size']]] ret += [[info['service'], info['monthly_quota'], info['used_quota'], info['soft_limit'], info['provider'], info['max_batch_size']]]
return ret return ret
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_enough_quota( CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_enough_quota(
username TEXT, username TEXT,

View File

@@ -30,10 +30,13 @@ RETURNS Geometry AS $$
elif user_geocoder_config.tomtom_geocoder: elif user_geocoder_config.tomtom_geocoder:
tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"]) tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point'] return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
elif user_geocoder_config.geocodio_geocoder:
geocodio_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocodio_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(geocodio_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
else: else:
raise Exception('Requested geocoder is not available') raise Exception('Requested geocoder is not available')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
@@ -49,7 +52,7 @@ RETURNS Geometry AS $$
else: else:
raise Exception('Here geocoder is not available for your account.') raise Exception('Here geocoder is not available for your account.')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -64,7 +67,7 @@ RETURNS Geometry AS $$
else: else:
raise Exception('Google geocoder is not available for your account.') raise Exception('Google geocoder is not available for your account.')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -77,7 +80,7 @@ RETURNS Geometry AS $$
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"]) mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point'] return plpy.execute(mapzen_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapbox_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapbox_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -90,7 +93,7 @@ RETURNS Geometry AS $$
mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"]) mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point'] return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -103,7 +106,20 @@ RETURNS Geometry AS $$
tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"]) tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point'] return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocodio_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$
# The configuration is retrieved but no checks are performed on it
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
geocodio_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocodio_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
return plpy.execute(geocodio_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_here_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -136,7 +152,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode street point using here maps') raise Exception('Error trying to geocode street point using here maps')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_google_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -168,7 +184,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode street point using google maps') raise Exception('Error trying to geocode street point using google maps')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -209,7 +225,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode street point using mapzen') raise Exception('Error trying to geocode street point using mapzen')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -255,7 +271,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode street point using Mapbox') raise Exception('Error trying to geocode street point using Mapbox')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -301,4 +317,50 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode street point using TomTom') raise Exception('Error trying to geocode street point using TomTom')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocodio_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
RETURNS Geometry AS $$
from iso3166 import countries
from cartodb_services.tools import ServiceManager, QuotaExceededException
from cartodb_services.geocodio import GeocodioGeocoder
from cartodb_services.tools.country import country_to_iso3
from cartodb_services.refactor.service.geocodio_geocoder_config import GeocodioGeocoderConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_manager = ServiceManager('geocoder', GeocodioGeocoderConfigBuilder, username, orgname, GD)
try:
service_manager.assert_within_limits()
geocoder = GeocodioGeocoder(service_manager.config.geocodio_api_key, service_manager.logger, service_manager.config.service_params)
country_iso3166 = None
if country:
country_iso3 = country_to_iso3(country)
if country_iso3:
country_iso3166 = countries.get(country_iso3).alpha2.lower()
coordinates = geocoder.geocode(searchtext=searchtext, city=city,
state_province=state_province,
country=country_iso3166)
if coordinates:
service_manager.quota_service.increment_success_service_use()
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
return point['st_setsrid']
else:
service_manager.quota_service.increment_empty_service_use()
return None
except QuotaExceededException as qe:
service_manager.quota_service.increment_failed_service_use()
return None
except BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to geocode street point using Geocodio', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using Geocodio')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -16,7 +16,7 @@ RETURNS JSON AS $$
return json.dumps({'limit': rate_limit_config.limit, 'period': rate_limit_config.period}) return json.dumps({'limit': rate_limit_config.limit, 'period': rate_limit_config.period})
else: else:
return None return None
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_user_rate_limit( CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_user_rate_limit(
username TEXT, username TEXT,
@@ -40,7 +40,7 @@ RETURNS VOID AS $$
period = None period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period) config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_user_rate_limits(config) config_setter.set_user_rate_limits(config)
$$ LANGUAGE plpythonu VOLATILE PARALLEL UNSAFE; $$ LANGUAGE @@plpythonu@@ VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_org_rate_limit( CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_org_rate_limit(
username TEXT, username TEXT,
@@ -64,7 +64,7 @@ RETURNS VOID AS $$
period = None period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period) config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_org_rate_limits(config) config_setter.set_org_rate_limits(config)
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_server_rate_limit( CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_server_rate_limit(
username TEXT, username TEXT,
@@ -88,4 +88,4 @@ RETURNS VOID AS $$
period = None period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period) config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_server_rate_limits(config) config_setter.set_server_rate_limits(config)
$$ LANGUAGE plpythonu VOLATILE PARALLEL UNSAFE; $$ LANGUAGE @@plpythonu@@ VOLATILE PARALLEL UNSAFE;

View File

@@ -32,13 +32,15 @@ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
provider_function = "_cdb_bulk_tomtom_geocode_street_point"; provider_function = "_cdb_bulk_tomtom_geocode_street_point";
elif user_geocoder_config.mapbox_geocoder: elif user_geocoder_config.mapbox_geocoder:
provider_function = "_cdb_bulk_mapbox_geocode_street_point"; provider_function = "_cdb_bulk_mapbox_geocode_street_point";
elif user_geocoder_config.geocodio_geocoder:
provider_function = "_cdb_bulk_geocodio_geocode_street_point";
else: else:
raise Exception('Requested geocoder is not available') raise Exception('Requested geocoder is not available')
plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.{}($1, $2, $3); ".format(provider_function), ["text", "text", "jsonb"]) plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.{}($1, $2, $3); ".format(provider_function), ["text", "text", "jsonb"])
return plpy.execute(plan, [username, orgname, searches]) return plpy.execute(plan, [username, orgname, searches])
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_google_geocode_street_point(username TEXT, orgname TEXT, searches jsonb) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_google_geocode_street_point(username TEXT, orgname TEXT, searches jsonb)
RETURNS SETOF cdb_dataservices_server.geocoding AS $$ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
@@ -49,7 +51,7 @@ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
service_manager = LegacyServiceManager('geocoder', username, orgname, GD) service_manager = LegacyServiceManager('geocoder', username, orgname, GD)
geocoder = GoogleMapsBulkGeocoder(service_manager.config.google_client_id, service_manager.config.google_api_key, service_manager.logger) geocoder = GoogleMapsBulkGeocoder(service_manager.config.google_client_id, service_manager.config.google_api_key, service_manager.logger)
return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches) return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches)
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_heremaps_geocode_street_point(username TEXT, orgname TEXT, searches jsonb) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_heremaps_geocode_street_point(username TEXT, orgname TEXT, searches jsonb)
RETURNS SETOF cdb_dataservices_server.geocoding AS $$ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
@@ -60,7 +62,7 @@ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
service_manager = LegacyServiceManager('geocoder', username, orgname, GD) service_manager = LegacyServiceManager('geocoder', username, orgname, GD)
geocoder = HereMapsBulkGeocoder(service_manager.config.heremaps_app_id, service_manager.config.heremaps_app_code, service_manager.logger, service_manager.config.heremaps_service_params) geocoder = HereMapsBulkGeocoder(service_manager.config.heremaps_app_id, service_manager.config.heremaps_app_code, service_manager.logger, service_manager.config.heremaps_service_params)
return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches) return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches)
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_tomtom_geocode_street_point(username TEXT, orgname TEXT, searches jsonb) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_tomtom_geocode_street_point(username TEXT, orgname TEXT, searches jsonb)
RETURNS SETOF cdb_dataservices_server.geocoding AS $$ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
@@ -77,7 +79,7 @@ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
service_manager = ServiceManager('geocoder', TomTomGeocoderConfigBuilder, username, orgname, GD) service_manager = ServiceManager('geocoder', TomTomGeocoderConfigBuilder, username, orgname, GD)
geocoder = TomTomBulkGeocoder(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params) geocoder = TomTomBulkGeocoder(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches) return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches)
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_mapbox_geocode_street_point(username TEXT, orgname TEXT, searches jsonb) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_mapbox_geocode_street_point(username TEXT, orgname TEXT, searches jsonb)
RETURNS SETOF cdb_dataservices_server.geocoding AS $$ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
@@ -94,5 +96,21 @@ RETURNS SETOF cdb_dataservices_server.geocoding AS $$
service_manager = ServiceManager('geocoder', MapboxGeocoderConfigBuilder, username, orgname, GD) service_manager = ServiceManager('geocoder', MapboxGeocoderConfigBuilder, username, orgname, GD)
geocoder = MapboxBulkGeocoder(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params) geocoder = MapboxBulkGeocoder(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params)
return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches) return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches)
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_bulk_geocodio_geocode_street_point(username TEXT, orgname TEXT, searches jsonb)
RETURNS SETOF cdb_dataservices_server.geocoding AS $$
from cartodb_services import run_street_point_geocoder
from cartodb_services.tools import ServiceManager
from cartodb_services.refactor.service.geocodio_geocoder_config import GeocodioGeocoderConfigBuilder
from cartodb_services.geocodio import GeocodioBulkGeocoder
from cartodb_services.tools import Logger
import cartodb_services
cartodb_services.init(plpy, GD)
logger_config = GD["logger_config"]
logger = Logger(logger_config)
service_manager = ServiceManager('geocoder', GeocodioGeocoderConfigBuilder, username, orgname, GD)
geocoder = GeocodioBulkGeocoder(service_manager.config.geocodio_api_key, service_manager.logger, service_manager.config.service_params)
return run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, orgname, searches)
$$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -35,7 +35,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode admin0 polygon') raise Exception('Error trying to geocode admin0 polygon')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -36,7 +36,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode admin1 polygon') raise Exception('Error trying to geocode admin1 polygon')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
---- cdb_geocode_admin1_polygon(admin1_name text, country_name text) ---- cdb_geocode_admin1_polygon(admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text, country_name text)
@@ -74,7 +74,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode admin1 polygon') raise Exception('Error trying to geocode admin1 polygon')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -1,7 +1,7 @@
---- cdb_geocode_namedplace_point(city_name text) ---- cdb_geocode_namedplace_point(city_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
import spiexceptions from plpy import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()") plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
@@ -16,12 +16,12 @@ RETURNS Geometry AS $$
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname}) logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"]) internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name])[0]['point'] return plpy.execute(internal_plan, [username, orgname, city_name])[0]['point']
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
---- cdb_geocode_namedplace_point(city_name text, country_name text) ---- cdb_geocode_namedplace_point(city_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
import spiexceptions from plpy import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()") plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
@@ -36,12 +36,12 @@ RETURNS Geometry AS $$
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname}) logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"]) internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, country_name])[0]['point'] return plpy.execute(internal_plan, [username, orgname, city_name, country_name])[0]['point']
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text) ---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
import spiexceptions from plpy import spiexceptions
from cartodb_services.tools import Logger,LoggerConfig from cartodb_services.tools import Logger,LoggerConfig
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()") plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
@@ -56,7 +56,7 @@ RETURNS Geometry AS $$
logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname}) logger.error('Error geocoding namedplace using geocode street point, falling back to internal geocoder', sys.exc_info(), data={"username": username, "orgname": orgname})
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"]) internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point'] return plpy.execute(internal_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_internal_geocode_namedplace(username text, orgname text, city_name text, admin1_name text DEFAULT NULL, country_name text DEFAULT NULL) CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_internal_geocode_namedplace(username text, orgname text, city_name text, admin1_name text DEFAULT NULL, country_name text DEFAULT NULL)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -101,7 +101,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode namedplace point') raise Exception('Error trying to geocode namedplace point')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -35,7 +35,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode postal code point') raise Exception('Error trying to geocode postal code point')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_point(username text, orgname text, code double precision) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_point(username text, orgname text, code double precision)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -77,7 +77,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode postal code point') raise Exception('Error trying to geocode postal code point')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_point(username text, orgname text, code double precision, country text) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_point(username text, orgname text, code double precision, country text)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -119,7 +119,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode postal code polygon') raise Exception('Error trying to geocode postal code polygon')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_polygon(username text, orgname text, code double precision) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_polygon(username text, orgname text, code double precision)
RETURNS Geometry AS $$ RETURNS Geometry AS $$
@@ -162,7 +162,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode postal code polygon') raise Exception('Error trying to geocode postal code polygon')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_polygon(username text, orgname text, code double precision, country text) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_polygon(username text, orgname text, code double precision, country text)
RETURNS Geometry AS $$ RETURNS Geometry AS $$

View File

@@ -35,7 +35,7 @@ RETURNS Geometry AS $$
raise Exception('Error trying to geocode postal code polygon') raise Exception('Error trying to geocode postal code polygon')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -55,7 +55,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('Error trying to get mapzen isolines') raise Exception('Error trying to get mapzen isolines')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isodistance( CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isodistance(
username TEXT, username TEXT,
@@ -121,7 +121,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('Error trying to get mapzen isolines') raise Exception('Error trying to get mapzen isolines')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isodistance( CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isodistance(
username TEXT, username TEXT,
@@ -132,7 +132,7 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isodistance(
options text[]) options text[])
RETURNS SETOF cdb_dataservices_server.isoline AS $$ RETURNS SETOF cdb_dataservices_server.isoline AS $$
from cartodb_services.tools import ServiceManager from cartodb_services.tools import ServiceManager
from cartodb_services.mapbox import MapboxMatrixClient, MapboxIsolines from cartodb_services.mapbox import MapboxIsolines
from cartodb_services.mapbox.types import TRANSPORT_MODE_TO_MAPBOX from cartodb_services.mapbox.types import TRANSPORT_MODE_TO_MAPBOX
from cartodb_services.tools import Coordinate from cartodb_services.tools import Coordinate
from cartodb_services.refactor.service.mapbox_isolines_config import MapboxIsolinesConfigBuilder from cartodb_services.refactor.service.mapbox_isolines_config import MapboxIsolinesConfigBuilder
@@ -144,8 +144,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
service_manager.assert_within_limits() service_manager.assert_within_limits()
try: try:
client = MapboxMatrixClient(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params) mapbox_isolines = MapboxIsolines(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params)
mapbox_isolines = MapboxIsolines(client, service_manager.logger)
if source: if source:
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat'] lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
@@ -169,7 +168,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
# -- TODO encapsulate this block into a func/method # -- TODO encapsulate this block into a func/method
locations = isolines[r] + [ isolines[r][0] ] # close the polygon repeating the first point locations = isolines[r] + [ isolines[r][0] ] # close the polygon repeating the first point
wkt_coordinates = ','.join(["%f %f" % (l.longitude, l.latitude) for l in locations]) wkt_coordinates = ','.join(["%f %f" % (l.longitude, l.latitude) for l in locations])
sql = "SELECT st_multi(ST_CollectionExtract(ST_MakeValid(ST_MPolyFromText('MULTIPOLYGON((({0})))', 4326)),3)) as geom".format(wkt_coordinates) sql = "SELECT ST_CollectionExtract(ST_MakeValid(ST_MPolyFromText('MULTIPOLYGON((({0})))', 4326)),3) as geom".format(wkt_coordinates)
multipolygon = plpy.execute(sql, 1)[0]['geom'] multipolygon = plpy.execute(sql, 1)[0]['geom']
else: else:
multipolygon = None multipolygon = None
@@ -186,7 +185,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('Error trying to get Mapbox isolines') raise Exception('Error trying to get Mapbox isolines')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_isodistance( CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_isodistance(
username TEXT, username TEXT,
@@ -250,7 +249,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('Error trying to get TomTom isolines') raise Exception('Error trying to get TomTom isolines')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isochrones( CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isochrones(
username TEXT, username TEXT,
@@ -311,7 +310,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('Error trying to get mapzen isochrones') raise Exception('Error trying to get mapzen isochrones')
finally: finally:
quota_service.increment_total_service_use() quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isochrones( CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isochrones(
username TEXT, username TEXT,
@@ -322,7 +321,7 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapbox_isochrones(
options text[]) options text[])
RETURNS SETOF cdb_dataservices_server.isoline AS $$ RETURNS SETOF cdb_dataservices_server.isoline AS $$
from cartodb_services.tools import ServiceManager from cartodb_services.tools import ServiceManager
from cartodb_services.mapbox import MapboxMatrixClient, MapboxIsolines from cartodb_services.mapbox import MapboxIsolines
from cartodb_services.mapbox.types import TRANSPORT_MODE_TO_MAPBOX from cartodb_services.mapbox.types import TRANSPORT_MODE_TO_MAPBOX
from cartodb_services.tools import Coordinate from cartodb_services.tools import Coordinate
from cartodb_services.tools.coordinates import coordinates_to_polygon from cartodb_services.tools.coordinates import coordinates_to_polygon
@@ -335,8 +334,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
service_manager.assert_within_limits() service_manager.assert_within_limits()
try: try:
client = MapboxMatrixClient(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params) mapbox_isolines = MapboxIsolines(service_manager.config.mapbox_api_key, service_manager.logger, service_manager.config.service_params)
mapbox_isolines = MapboxIsolines(client, service_manager.logger)
if source: if source:
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat'] lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
@@ -370,7 +368,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('Error trying to get Mapbox isochrones') raise Exception('Error trying to get Mapbox isochrones')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_isochrones( CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_isochrones(
username TEXT, username TEXT,
@@ -428,4 +426,4 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('Error trying to get TomTom isochrones') raise Exception('Error trying to get TomTom isochrones')
finally: finally:
service_manager.quota_service.increment_total_service_use() service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ SECURITY DEFINER STABLE PARALLEL RESTRICTED;

View File

@@ -31,7 +31,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
return plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options]) return plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
else: else:
raise Exception('Requested isolines provider is not available') raise Exception('Requested isolines provider is not available')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-- heremaps isodistance -- heremaps isodistance
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_here_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_here_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
@@ -46,7 +46,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
result = plpy.execute(here_plan, [username, orgname, type, source, mode, range, options]) result = plpy.execute(here_plan, [username, orgname, type, source, mode, range, options])
return result return result
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-- mapzen isodistance -- mapzen isodistance
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
@@ -60,7 +60,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
result = plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options]) result = plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
return result return result
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-- mapbox isodistance -- mapbox isodistance
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapbox_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapbox_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
@@ -74,7 +74,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
result = plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options]) result = plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
return result return result
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-- tomtom isodistance -- tomtom isodistance
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
@@ -88,4 +88,4 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
result = plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options]) result = plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
return result return result
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -31,7 +31,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
return plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options]) return plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
else: else:
raise Exception('Requested isolines provider is not available') raise Exception('Requested isolines provider is not available')
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-- heremaps isochrone -- heremaps isochrone
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_here_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_here_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
@@ -46,7 +46,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
result = plpy.execute(here_plan, [username, orgname, type, source, mode, range, options]) result = plpy.execute(here_plan, [username, orgname, type, source, mode, range, options])
return result return result
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-- mapzen isochrone -- mapzen isochrone
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
@@ -59,7 +59,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"]) mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
result = plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options]) result = plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
return result return result
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-- mapbox isochrone -- mapbox isochrone
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapbox_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapbox_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
@@ -72,7 +72,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"]) mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
result = plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options]) result = plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
return result return result
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;
-- tomtom isochrone -- tomtom isochrone
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
@@ -85,4 +85,4 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"]) tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
result = plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options]) result = plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
return result return result
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED; $$ LANGUAGE @@plpythonu@@ STABLE PARALLEL RESTRICTED;

View File

@@ -2,7 +2,7 @@
SET client_min_messages TO WARNING; SET client_min_messages TO WARNING;
-- Install dependencies -- Install dependencies
CREATE EXTENSION postgis; CREATE EXTENSION postgis;
CREATE EXTENSION plpythonu; CREATE EXTENSION @@plpythonu@@;
CREATE EXTENSION plproxy; CREATE EXTENSION plproxy;
CREATE EXTENSION cartodb; CREATE EXTENSION cartodb;
CREATE EXTENSION cdb_geocoder; CREATE EXTENSION cdb_geocoder;
@@ -39,7 +39,13 @@ SELECT cartodb.cdb_conf_setconf('mapbox_conf', '{"routing": {"api_keys": ["routi
(1 row) (1 row)
SELECT cartodb.cdb_conf_setconf('tomtom_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "isolines": {"api_keys": ["matrix_dummy_api_key"], "monthly_quota": 1500000}}'); SELECT cartodb.cdb_conf_setconf('tomtom_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "isolines": {"api_keys": ["isolines_dummy_api_key"], "monthly_quota": 1500000}}');
cdb_conf_setconf
------------------
(1 row)
SELECT cartodb.cdb_conf_setconf('geocodio_conf', '{"geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}}');
cdb_conf_setconf cdb_conf_setconf
------------------ ------------------

View File

@@ -1,3 +1,4 @@
\set ECHO none
SELECT exists(SELECT * SELECT exists(SELECT *
FROM pg_proc p FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)

View File

@@ -2,7 +2,7 @@
SET client_min_messages TO WARNING; SET client_min_messages TO WARNING;
-- Install dependencies -- Install dependencies
CREATE EXTENSION postgis; CREATE EXTENSION postgis;
CREATE EXTENSION plpythonu; CREATE EXTENSION @@plpythonu@@;
CREATE EXTENSION plproxy; CREATE EXTENSION plproxy;
CREATE EXTENSION cartodb; CREATE EXTENSION cartodb;
CREATE EXTENSION cdb_geocoder; CREATE EXTENSION cdb_geocoder;
@@ -16,7 +16,8 @@ SELECT cartodb.cdb_conf_setconf('redis_metadata_config', '{"redis_host": "localh
SELECT cartodb.cdb_conf_setconf('heremaps_conf', '{"geocoder": {"app_id": "dummy_id", "app_code": "dummy_code", "geocoder_cost_per_hit": 1}, "isolines": {"app_id": "dummy_id", "app_code": "dummy_code"}}'); SELECT cartodb.cdb_conf_setconf('heremaps_conf', '{"geocoder": {"app_id": "dummy_id", "app_code": "dummy_code", "geocoder_cost_per_hit": 1}, "isolines": {"app_id": "dummy_id", "app_code": "dummy_code"}}');
SELECT cartodb.cdb_conf_setconf('mapzen_conf', '{"routing": {"api_key": "routing_dummy_api_key", "monthly_quota": 1500000}, "geocoder": {"api_key": "geocoder_dummy_api_key", "monthly_quota": 1500000}, "matrix": {"api_key": "matrix_dummy_api_key", "monthly_quota": 1500000}}'); SELECT cartodb.cdb_conf_setconf('mapzen_conf', '{"routing": {"api_key": "routing_dummy_api_key", "monthly_quota": 1500000}, "geocoder": {"api_key": "geocoder_dummy_api_key", "monthly_quota": 1500000}, "matrix": {"api_key": "matrix_dummy_api_key", "monthly_quota": 1500000}}');
SELECT cartodb.cdb_conf_setconf('mapbox_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "matrix": {"api_keys": ["matrix_dummy_api_key"], "monthly_quota": 1500000}}'); SELECT cartodb.cdb_conf_setconf('mapbox_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "matrix": {"api_keys": ["matrix_dummy_api_key"], "monthly_quota": 1500000}}');
SELECT cartodb.cdb_conf_setconf('tomtom_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "isolines": {"api_keys": ["matrix_dummy_api_key"], "monthly_quota": 1500000}}'); SELECT cartodb.cdb_conf_setconf('tomtom_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "isolines": {"api_keys": ["isolines_dummy_api_key"], "monthly_quota": 1500000}}');
SELECT cartodb.cdb_conf_setconf('geocodio_conf', '{"geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}}');
SELECT cartodb.cdb_conf_setconf('logger_conf', '{"geocoder_log_path": "/dev/null"}'); SELECT cartodb.cdb_conf_setconf('logger_conf', '{"geocoder_log_path": "/dev/null"}');
SELECT cartodb.cdb_conf_setconf('data_observatory_conf', '{"connection": {"whitelist": ["ethervoid"], "production": "host=localhost port=5432 dbname=contrib_regression user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}, "monthly_quota": 100000}'); SELECT cartodb.cdb_conf_setconf('data_observatory_conf', '{"connection": {"whitelist": ["ethervoid"], "production": "host=localhost port=5432 dbname=contrib_regression user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}, "monthly_quota": 100000}');

View File

@@ -1,3 +1,10 @@
\set ECHO none
-- add the schema cdb_dataservices_server to the SEARCH_PATH
DO $$ BEGIN
PERFORM set_config('search_path', current_setting('search_path')||', cdb_dataservices_server', false);
END $$;
\set ECHO all
SELECT exists(SELECT * SELECT exists(SELECT *
FROM pg_proc p FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)

View File

@@ -2,6 +2,11 @@
\set VERBOSITY verbose \set VERBOSITY verbose
SET client_min_messages TO error; SET client_min_messages TO error;
-- add the schema cdb_dataservices_server to the SEARCH_PATH
DO $$ BEGIN
PERFORM set_config('search_path', current_setting('search_path')||', cdb_dataservices_server', false);
END $$;
-- Set configuration for a user 'foo' -- Set configuration for a user 'foo'
DO $$ DO $$
import json import json
@@ -14,7 +19,7 @@ DO $$
service_config.user.set('soft_obs_general_limit', True) service_config.user.set('soft_obs_general_limit', True)
service_config.user.set('period_end_date', '20170516') service_config.user.set('period_end_date', '20170516')
$$ LANGUAGE plpythonu; $$ LANGUAGE @@plpythonu@@;
-- Mock Observatory backend function -- Mock Observatory backend function
@@ -37,7 +42,7 @@ GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_observatory TO geocoder_api;
SELECT * FROM cdb_dataservices_server.OBS_GetData( SELECT * FROM cdb_dataservices_server.OBS_GetData(
'foo', 'foo',
NULL, NULL,
'{"(0103000020E61000000100000005000000010000E0F67F52C096D88AE6B25F4440010000E0238052C0BF6D8A1A8D5D4440010000D0DA7E52C05F03F3CC265D444001000020F47E52C0F2DD78AB5D5F4440010000E0F67F52C096D88AE6B25F4440,1)"}'::public._geomval, '{"(0103000020E61000000100000005000000010000E0F67F52C096D88AE6B25F4440010000E0238052C0BF6D8A1A8D5D4440010000D0DA7E52C05F03F3CC265D444001000020F47E52C0F2DD78AB5D5F4440010000E0F67F52C096D88AE6B25F4440,1)"}'::_geomval,
'[{"id": 1, "score": 52.7515548093083898758340051256007949661290516400338, "geom_id": "us.census.tiger.census_tract", "denom_id": "us.census.acs.B01003001", "numer_id": "us.census.acs.B03002003", "geom_name": "US Census Tracts", "geom_type": "Geometry", "num_geoms": 2.86483076549783307739486952736, "denom_name": "Total Population", "denom_type": "Numeric", "numer_name": "White Population", "numer_type": "Numeric", "score_rank": 1, "target_area": 0.000307374806576033, "geom_colname": "the_geom", "score_rownum": 1, "target_geoms": null, "denom_colname": "total_pop", "denom_reltype": ' '[{"id": 1, "score": 52.7515548093083898758340051256007949661290516400338, "geom_id": "us.census.tiger.census_tract", "denom_id": "us.census.acs.B01003001", "numer_id": "us.census.acs.B03002003", "geom_name": "US Census Tracts", "geom_type": "Geometry", "num_geoms": 2.86483076549783307739486952736, "denom_name": "Total Population", "denom_type": "Numeric", "numer_name": "White Population", "numer_type": "Numeric", "score_rank": 1, "target_area": 0.000307374806576033, "geom_colname": "the_geom", "score_rownum": 1, "target_geoms": null, "denom_colname": "total_pop", "denom_reltype": '
'"denominator", "geom_timespan": "2015", "normalization": "prenormalized", "numer_colname": "white_pop", "timespan_rank": 1, "geom_tablename": "obs_87a814e485deabe3b12545a537f693d16ca702c2", "max_score_rank": null, "numer_timespan": "2010 - 2014", "suggested_name": "white_pop_2010_2014", "denom_aggregate": "sum", "denom_tablename": "obs_b393b5b88c6adda634b2071a8005b03c551b609a", "numer_aggregate": "sum", "numer_tablename": "obs_b393b5b88c6adda634b2071a8005b03c551b609a", "timespan_rownum": 1, "geom_description": "Census tracts are small, relatively permanent statistical subdivisions of a county or equivalent entity that are updated by local participants prior to each decennial census as part of the Census Bureaus Participant Statistical Areas Program. The Census Bureau delineates census tracts in situations where no local participant existed or where state, local, or tribal governments' '"denominator", "geom_timespan": "2015", "normalization": "prenormalized", "numer_colname": "white_pop", "timespan_rank": 1, "geom_tablename": "obs_87a814e485deabe3b12545a537f693d16ca702c2", "max_score_rank": null, "numer_timespan": "2010 - 2014", "suggested_name": "white_pop_2010_2014", "denom_aggregate": "sum", "denom_tablename": "obs_b393b5b88c6adda634b2071a8005b03c551b609a", "numer_aggregate": "sum", "numer_tablename": "obs_b393b5b88c6adda634b2071a8005b03c551b609a", "timespan_rownum": 1, "geom_description": "Census tracts are small, relatively permanent statistical subdivisions of a county or equivalent entity that are updated by local participants prior to each decennial census as part of the Census Bureaus Participant Statistical Areas Program. The Census Bureau delineates census tracts in situations where no local participant existed or where state, local, or tribal governments'
'declined to participate. The primary purpose of census tracts is to provide a stable set of geographic units for the presentation of statistical data.\r\n\r\nCensus tracts generally have a population size between 1,200 and 8,000 people, with an optimum size of 4,000 people. A census tract usually covers a contiguous area; however, the spatial size of census tracts varies widely depending on the density of settlement. Census tract boundaries are delineated with the intention of being maintained over a long time so that statistical comparisons can be made from census to census. Census tracts occasionally are split due to population growth or merged as a result of substantial population decline.\r\n\r\nCensus tract boundaries generally follow visible and identifiable features. They may follow nonvisible legal boundaries, such as minor civil division (MCD) or incorporated place boundaries' 'declined to participate. The primary purpose of census tracts is to provide a stable set of geographic units for the presentation of statistical data.\r\n\r\nCensus tracts generally have a population size between 1,200 and 8,000 people, with an optimum size of 4,000 people. A census tract usually covers a contiguous area; however, the spatial size of census tracts varies widely depending on the density of settlement. Census tract boundaries are delineated with the intention of being maintained over a long time so that statistical comparisons can be made from census to census. Census tracts occasionally are split due to population growth or merged as a result of substantial population decline.\r\n\r\nCensus tract boundaries generally follow visible and identifiable features. They may follow nonvisible legal boundaries, such as minor civil division (MCD) or incorporated place boundaries'

View File

@@ -34,4 +34,4 @@ def _reset():
plpy = None plpy = None
GD = None GD = None
from geocoder import run_street_point_geocoder, StreetPointBulkGeocoder from cartodb_services.geocoder import run_street_point_geocoder, StreetPointBulkGeocoder

View File

@@ -1,11 +1,13 @@
from google import GoogleMapsBulkGeocoder from cartodb_services.google import GoogleMapsBulkGeocoder
from here import HereMapsBulkGeocoder from cartodb_services.here import HereMapsBulkGeocoder
from tomtom import TomTomBulkGeocoder from cartodb_services.tomtom import TomTomBulkGeocoder
from mapbox import MapboxBulkGeocoder from cartodb_services.mapbox import MapboxBulkGeocoder
from cartodb_services.geocodio import GeocodioBulkGeocoder
BATCH_GEOCODER_CLASS_BY_PROVIDER = { BATCH_GEOCODER_CLASS_BY_PROVIDER = {
'google': GoogleMapsBulkGeocoder, 'google': GoogleMapsBulkGeocoder,
'heremaps': HereMapsBulkGeocoder, 'heremaps': HereMapsBulkGeocoder,
'tomtom': TomTomBulkGeocoder, 'tomtom': TomTomBulkGeocoder,
'mapbox': MapboxBulkGeocoder 'mapbox': MapboxBulkGeocoder,
'geocodio': GeocodioBulkGeocoder,
} }

View File

@@ -1,3 +1,3 @@
from service_configuration import ServiceConfiguration from .service_configuration import ServiceConfiguration
from rate_limits import RateLimitsConfig, RateLimitsConfigBuilder, RateLimitsConfigSetter from .rate_limits import RateLimitsConfig, RateLimitsConfigBuilder, RateLimitsConfigSetter
from legacy_rate_limits import RateLimitsConfigLegacyBuilder from .legacy_rate_limits import RateLimitsConfigLegacyBuilder

View File

@@ -1,5 +1,5 @@
import json import json
from rate_limits import RateLimitsConfig from cartodb_services.config.rate_limits import RateLimitsConfig
class RateLimitsConfigLegacyBuilder(object): class RateLimitsConfigLegacyBuilder(object):
""" """

View File

@@ -1,6 +1,6 @@
import json import json
from service_configuration import ServiceConfiguration from cartodb_services.config.service_configuration import ServiceConfiguration
class RateLimitsConfig(object): class RateLimitsConfig(object):
""" """

View File

@@ -1,7 +1,7 @@
#!/usr/local/bin/python #!/usr/local/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from tools import QuotaExceededException, Logger from cartodb_services.tools import QuotaExceededException, Logger
from collections import namedtuple from collections import namedtuple
import json import json
@@ -71,7 +71,7 @@ def run_street_point_geocoder(plpy, GD, geocoder, service_manager, username, org
except Exception as e: except Exception as e:
import sys import sys
logger.error("Error processing geocode", sys.exc_info(), data={"username": username, "orgname": orgname}) logger.error("Error processing geocode", sys.exc_info(), data={"username": username, "orgname": orgname})
metadata['processing_error'] = 'Error: {}'.format(e.message) metadata['processing_error'] = 'Error: {}'.format(e)
results.append([result[0], None, json.dumps(metadata)]) results.append([result[0], None, json.dumps(metadata)])
failed_count += 1 failed_count += 1

View File

@@ -0,0 +1,2 @@
from cartodb_services.geocodio.geocoder import GeocodioGeocoder
from cartodb_services.geocodio.bulk_geocoder import GeocodioBulkGeocoder

View File

@@ -0,0 +1,76 @@
import requests
from cartodb_services import StreetPointBulkGeocoder
from cartodb_services.geocodio import GeocodioGeocoder
from iso3166 import countries
from cartodb_services.tools.country import country_to_iso3
class GeocodioBulkGeocoder(GeocodioGeocoder, StreetPointBulkGeocoder):
MAX_BATCH_SIZE = 100 # Setting an upper limit (not stated in the documentation)
MIN_BATCHED_SEARCH = 0
READ_TIMEOUT = 60
CONNECT_TIMEOUT = 10
MAX_RETRIES = 1
def __init__(self, token, logger, service_params=None):
GeocodioGeocoder.__init__(self, token, logger, service_params)
self.connect_timeout = self.CONNECT_TIMEOUT
self.read_timeout = self.READ_TIMEOUT
self.max_retries = self.MAX_RETRIES
if service_params is not None:
self.connect_timeout = service_params.get('connect_timeout', self.CONNECT_TIMEOUT)
self.read_timeout = service_params.get('read_timeout', self.READ_TIMEOUT)
self.max_retries = service_params.get('max_retries', self.MAX_RETRIES)
self.session = requests.Session()
def _should_use_batch(self, searches):
return len(searches) >= self.MIN_BATCHED_SEARCH
def _serial_geocode(self, searches):
results = []
for search in searches:
elements = self._encoded_elements(search)
result = self.geocode_meta(*elements)
if result:
results.append((search[0], result[0], result[1]))
else:
results.append((search[0], None, None))
return results
def _encoded_elements(self, search):
(search_id, address, city, state, country) = search
address = address.encode('utf-8') if address else None
city = city.encode('utf-8') if city else None
state = state.encode('utf-8') if state else None
country = self._country_code(country) if country else None
return address, city, state, country
def _batch_geocode(self, searches):
if len(searches) == 1:
return self._serial_geocode(searches)
else:
frees = []
for search in searches:
elements = self._encoded_elements(search)
free = ', '.join([elem for elem in elements if elem])
frees.append(free)
full_results = self.geocode_free_text_meta(frees)
results = []
for s, r in zip(searches, full_results):
results.append((s[0], r[0], r[1]))
return results
def _country_code(self, country):
country_iso3166 = country
country_iso3 = country_to_iso3(country)
if country_iso3:
country_iso3166 = countries.get(country_iso3).alpha2.lower()
return country_iso3166

View File

@@ -0,0 +1,126 @@
from geocodio import GeocodioClient
from geocodio.exceptions import GeocodioAuthError, GeocodioServerError, GeocodioDataError, GeocodioError
from cartodb_services.tools.qps import qps_retry
from cartodb_services.metrics import Traceable
from cartodb_services.geocoder import EMPTY_RESPONSE, geocoder_metadata
from cartodb_services.tools.exceptions import ServiceException
RELEVANCE_BY_LOCATION_TYPE = {
'rooftop': 1,
'point': 0.9,
'range_interpolation': 0.8,
'nearest_rooftop_match': 0.7,
'intersection': 0.6,
'street_center': 0.5,
'place': 0.4,
'state': 0.1,
}
class GeocodioGeocoder(Traceable):
'''
Python wrapper for the Geocodio Geocoder service.
'''
def __init__(self, token, logger, service_params=None):
service_params = service_params or {}
self._token = token
self._logger = logger
self._geocoder = GeocodioClient(self._token)
def _validate_input(self, searchtext, city=None, state_province=None,
country=None):
if searchtext and searchtext.strip():
return True
elif city:
return True
elif state_province:
return True
return False
@qps_retry(qps=15, provider='geocodio')
def geocode(self, searchtext, city=None, state_province=None,
country=None):
return self._geocode_meta(searchtext, city, state_province, country)[0]
def geocode_meta(self, searchtext, city=None, state_province=None,
country=None):
return self._geocode_meta(searchtext, city, state_province, country)[0]
@qps_retry(qps=15, provider='geocodio')
def _geocode_meta(self, searchtext, city=None, state_province=None,
country=None):
if not self._validate_input(searchtext, city, state_province, country):
return EMPTY_RESPONSE
try:
free_text_components = [searchtext, city, state_province, country]
req = '; '.join([c for c in free_text_components if c is not None and c.strip()])
response = self._geocoder.geocode(req)
return self._parse_geocoder_response(response)
except GeocodioDataError as gde:
return EMPTY_RESPONSE
except GeocodioAuthError as gae:
raise ServiceException('Geocodio authorization error: ' + str(gae), None)
except GeocodioServerError as gse:
raise ServiceException('geocodio server error: ' + str(gse), None)
except GeocodioError as ge:
raise ServiceException('Unknown Geocodio error: ' + str(ge), None)
@qps_retry(qps=15)
def geocode_free_text_meta(self, free_searches, country=None):
"""
:param free_searches: Free text searches
:return: list of [x, y] on success, [] on error
"""
output = []
try:
if country:
free_searches = ['{s}, {country}'.format(s, country) for s in free_searches]
responses = self._geocoder.geocode(free_searches)
for response in responses:
output.append(self._parse_geocoder_response(response))
except GeocodioDataError as gde:
return EMPTY_RESPONSE
except GeocodioAuthError as gae:
raise ServiceException('Geocodio authorization error: ' + str(gae), None)
except GeocodioServerError as gse:
raise ServiceException('geocodio server error: ' + str(gse), None)
except GeocodioError as ge:
raise ServiceException('Unknown Geocodio error: ' + str(ge), None)
return output
def _parse_geocoder_response(self, response):
if response is None or not response:
return EMPTY_RESPONSE
if response.get('results') is None or not response.get('results'):
return EMPTY_RESPONSE
if response.coords is None or not response.coords:
return EMPTY_RESPONSE
coords = [None, None]
accuracy = None
accuracy_type = None
accuracy = response.accuracy
if response.coords is not None and response.coords:
coords = [response.coords[1], response.coords[0]]
if response.get('results'):
accuracy_type = response.get('results')[0].get('accuracy_type')
metadata = geocoder_metadata(RELEVANCE_BY_LOCATION_TYPE.get(accuracy_type), response.accuracy, accuracy_type)
return [coords, metadata]

View File

@@ -0,0 +1 @@
GEOCODIO_GEOCODER_APIKEY_ROUNDROBIN = 'geocodio_geocoder_apikey_roundrobin'

View File

@@ -1,2 +1,2 @@
from geocoder import GoogleMapsGeocoder from cartodb_services.google.geocoder import GoogleMapsGeocoder
from bulk_geocoder import GoogleMapsBulkGeocoder from cartodb_services.google.bulk_geocoder import GoogleMapsBulkGeocoder

View File

@@ -1,5 +1,5 @@
from multiprocessing import Pool from multiprocessing import Pool
from exceptions import MalformedResult from cartodb_services.google.exceptions import MalformedResult
from cartodb_services import StreetPointBulkGeocoder from cartodb_services import StreetPointBulkGeocoder
from cartodb_services.geocoder import compose_address, geocoder_error_response from cartodb_services.geocoder import compose_address, geocoder_error_response
from cartodb_services.google import GoogleMapsGeocoder from cartodb_services.google import GoogleMapsGeocoder

View File

@@ -3,7 +3,7 @@
import googlemaps import googlemaps
import base64 import base64
from exceptions import InvalidGoogleCredentials from cartodb_services.google.exceptions import InvalidGoogleCredentials
class GoogleMapsClientFactory(): class GoogleMapsClientFactory():

View File

@@ -1,9 +1,11 @@
#!/usr/local/bin/python #!/usr/local/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
try:
from urlparse import parse_qs from urlparse import parse_qs
except:
from urllib.parse import parse_qs
from exceptions import MalformedResult from cartodb_services.google.exceptions import MalformedResult
from cartodb_services.geocoder import compose_address, geocoder_metadata, PRECISION_PRECISE, PRECISION_INTERPOLATED, EMPTY_RESPONSE from cartodb_services.geocoder import compose_address, geocoder_metadata, PRECISION_PRECISE, PRECISION_INTERPOLATED, EMPTY_RESPONSE
from cartodb_services.google.exceptions import InvalidGoogleCredentials from cartodb_services.google.exceptions import InvalidGoogleCredentials
from client_factory import GoogleMapsClientFactory from client_factory import GoogleMapsClientFactory

View File

@@ -1,3 +1,3 @@
from geocoder import HereMapsGeocoder from cartodb_services.here.geocoder import HereMapsGeocoder
from bulk_geocoder import HereMapsBulkGeocoder from cartodb_services.here.bulk_geocoder import HereMapsBulkGeocoder
from routing import HereMapsRoutingIsoline from cartodb_services.here.routing import HereMapsRoutingIsoline

View File

@@ -1,7 +1,7 @@
import requests import requests
import json import json
from exceptions import WrongParams from cartodb_services.here.exceptions import WrongParams
from requests.adapters import HTTPAdapter from requests.adapters import HTTPAdapter
from cartodb_services.metrics import Traceable from cartodb_services.metrics import Traceable
@@ -115,7 +115,7 @@ class HereMapsRoutingIsoline(Traceable):
def __parse_source_param(self, source, options): def __parse_source_param(self, source, options):
key = 'start' key = 'start'
if 'is_destination' in options and options['is_destination']: if 'is_destination' in options and options['is_destination'].lower() == 'true':
key = 'destination' key = 'destination'
return {key: source} return {key: source}

View File

@@ -1,5 +1,4 @@
from routing import MapboxRouting, MapboxRoutingResponse from cartodb_services.mapbox.routing import MapboxRouting, MapboxRoutingResponse
from geocoder import MapboxGeocoder from cartodb_services.mapbox.geocoder import MapboxGeocoder
from bulk_geocoder import MapboxBulkGeocoder from cartodb_services.mapbox.bulk_geocoder import MapboxBulkGeocoder
from isolines import MapboxIsolines, MapboxIsochronesResponse from cartodb_services.mapbox.isolines import MapboxIsolines, MapboxIsochronesResponse
from matrix_client import MapboxMatrixClient

View File

@@ -1,172 +1,143 @@
'''
Python implementation for Mapbox services based isolines.
Uses the Mapbox Time Matrix service.
'''
import json import json
import requests
from uritemplate import URITemplate
from cartodb_services.tools.exceptions import ServiceException
from cartodb_services.tools.qps import qps_retry
from cartodb_services.tools import Coordinate from cartodb_services.tools import Coordinate
from cartodb_services.tools.spherical import (get_angles,
calculate_dest_location) BASEURI = ('https://api.mapbox.com/isochrone/v1/mapbox/{profile}/{coordinates}?contours_minutes={contours_minutes}&access_token={apikey}')
from cartodb_services.mapbox.matrix_client import (validate_profile,
DEFAULT_PROFILE, PROFILE_DRIVING = 'driving'
PROFILE_WALKING, PROFILE_CYCLING = 'cycling'
PROFILE_DRIVING, PROFILE_WALKING = 'walking'
PROFILE_CYCLING, DEFAULT_PROFILE = PROFILE_DRIVING
ENTRY_DURATIONS,
ENTRY_DESTINATIONS, MAX_TIME_RANGE = 60 * 60 # The maximum time that can be specified is 60 minutes.
ENTRY_LOCATION) # https://docs.mapbox.com/api/navigation/#retrieve-isochrones-around-a-location
MAX_SPEEDS = { MAX_SPEEDS = {
PROFILE_WALKING: 3.3333333, # In m/s, assuming 12km/h walking speed PROFILE_WALKING: 3.3333333, # In m/s, assuming 12km/h walking speed
PROFILE_CYCLING: 16.67, # In m/s, assuming 60km/h max speed PROFILE_CYCLING: 16.67, # In m/s, assuming 60km/h max speed
PROFILE_DRIVING: 41.67 # In m/s, assuming 140km/h max speed PROFILE_DRIVING: 38.89 # In m/s, assuming 140km/h max speed
} }
DEFAULT_NUM_ANGLES = 24 VALID_PROFILES = (PROFILE_DRIVING,
DEFAULT_MAX_ITERS = 5 PROFILE_CYCLING,
DEFAULT_TOLERANCE = 0.1 PROFILE_WALKING)
MATRIX_NUM_ANGLES = DEFAULT_NUM_ANGLES ENTRY_FEATURES = 'features'
MATRIX_MAX_ITERS = DEFAULT_MAX_ITERS ENTRY_GEOMETRY = 'geometry'
MATRIX_TOLERANCE = DEFAULT_TOLERANCE ENTRY_COORDINATES = 'coordinates'
UNIT_FACTOR_ISOCHRONE = 1.0
UNIT_FACTOR_ISODISTANCE = 1000.0
DEFAULT_UNIT_FACTOR = UNIT_FACTOR_ISOCHRONE
class MapboxIsolines(): class MapboxIsolines():
''' '''
Python wrapper for Mapbox services based isolines. Python wrapper for Mapbox based isolines.
''' '''
def __init__(self, matrix_client, logger, service_params=None): def __init__(self, apikey, logger, service_params=None):
service_params = service_params or {} service_params = service_params or {}
self._matrix_client = matrix_client self._apikey = apikey
self._logger = logger self._logger = logger
def _calculate_matrix_cost(self, origin, targets, isorange, def _uri(self, origin, time_range, profile=DEFAULT_PROFILE):
profile=DEFAULT_PROFILE, uri = URITemplate(BASEURI).expand(apikey=self._apikey,
unit_factor=UNIT_FACTOR_ISOCHRONE, coordinates=origin,
number_of_angles=MATRIX_NUM_ANGLES): contours_minutes=time_range,
response = self._matrix_client.matrix([origin] + targets, profile=profile)
profile) return uri
def _validate_profile(self, profile):
if profile not in VALID_PROFILES:
raise ValueError('{profile} is not a valid profile. '
'Valid profiles are: {valid_profiles}'.format(
profile=profile,
valid_profiles=', '.join(
[x for x in VALID_PROFILES])))
def _validate_time_ranges(self, time_ranges):
for time_range in time_ranges:
if time_range > MAX_TIME_RANGE:
raise ValueError('Cannot query time ranges greater than {max_time_range} seconds'.format(
max_time_range=MAX_TIME_RANGE))
def _parse_coordinates(self, boundary):
coordinates = boundary.get(ENTRY_COORDINATES, [])
return [Coordinate(c[0], c[1]) for c in coordinates]
def _parse_isochrone_service(self, response):
json_response = json.loads(response) json_response = json.loads(response)
if not json_response:
coordinates = []
if json_response:
for feature in json_response[ENTRY_FEATURES]:
geometry = feature[ENTRY_GEOMETRY]
coordinates.append(self._parse_coordinates(geometry))
return coordinates
@qps_retry(qps=5, provider='mapbox')
def _calculate_isoline(self, origin, time_ranges,
profile=DEFAULT_PROFILE):
self._validate_time_ranges(time_ranges)
origin = '{lon},{lat}'.format(lat=origin.latitude,
lon=origin.longitude)
time_ranges.sort()
time_ranges_seconds = ','.join([str(round(t/60)) for t in time_ranges])
uri = self._uri(origin, time_ranges_seconds, profile)
try:
response = requests.get(uri)
if response.status_code == requests.codes.ok:
isolines = []
coordinates = self._parse_isochrone_service(response.text)
for t, c in zip(time_ranges, coordinates):
isolines.append(MapboxIsochronesResponse(c, t))
return isolines
elif response.status_code == requests.codes.bad_request:
return []
elif response.status_code == requests.codes.unprocessable_entity:
return [] return []
costs = [None] * number_of_angles
destinations = [None] * number_of_angles
for idx, cost in enumerate(json_response[ENTRY_DURATIONS][0][1:]):
if cost:
costs[idx] = cost * unit_factor
else: else:
costs[idx] = isorange raise ServiceException(response.status_code, response)
except requests.Timeout as te:
for idx, destination in enumerate(json_response[ENTRY_DESTINATIONS][1:]): # In case of timeout we want to stop the job because the server
destinations[idx] = Coordinate(destination[ENTRY_LOCATION][0], # could be down
destination[ENTRY_LOCATION][1]) self._logger.error('Timeout connecting to Mapbox isochrone service',
te)
return costs, destinations raise ServiceException('Error getting isochrone data from Mapbox',
None)
except requests.ConnectionError as ce:
# Don't raise the exception to continue with the geocoding job
self._logger.error('Error connecting to Mapbox isochrone service',
exception=ce)
return []
def calculate_isochrone(self, origin, time_ranges, def calculate_isochrone(self, origin, time_ranges,
profile=DEFAULT_PROFILE): profile=DEFAULT_PROFILE):
validate_profile(profile) self._validate_profile(profile)
max_speed = MAX_SPEEDS[profile] return self._calculate_isoline(origin=origin,
time_ranges=time_ranges,
isochrones = [] profile=profile)
for time_range in time_ranges:
upper_rmax = max_speed * time_range # an upper bound for the radius
coordinates = self.calculate_isoline(origin=origin,
isorange=time_range,
upper_rmax=upper_rmax,
cost_method=self._calculate_matrix_cost,
profile=profile,
unit_factor=UNIT_FACTOR_ISOCHRONE,
number_of_angles=MATRIX_NUM_ANGLES,
max_iterations=MATRIX_MAX_ITERS,
tolerance=MATRIX_TOLERANCE)
isochrones.append(MapboxIsochronesResponse(coordinates,
time_range))
return isochrones
def calculate_isodistance(self, origin, distance_range, def calculate_isodistance(self, origin, distance_range,
profile=DEFAULT_PROFILE): profile=DEFAULT_PROFILE):
validate_profile(profile) self._validate_profile(profile)
max_speed = MAX_SPEEDS[profile] max_speed = MAX_SPEEDS[profile]
time_range = distance_range / max_speed time_range = distance_range / max_speed
return self.calculate_isochrone(origin=origin, return self._calculate_isoline(origin=origin,
time_ranges=[time_range], time_ranges=[time_range],
profile=profile)[0].coordinates profile=profile)[0].coordinates
def calculate_isoline(self, origin, isorange, upper_rmax,
cost_method=_calculate_matrix_cost,
profile=DEFAULT_PROFILE,
unit_factor=DEFAULT_UNIT_FACTOR,
number_of_angles=DEFAULT_NUM_ANGLES,
max_iterations=DEFAULT_MAX_ITERS,
tolerance=DEFAULT_TOLERANCE):
# Formally, a solution is an array of {angle, radius, lat, lon, cost}
# with cardinality number_of_angles
# we're looking for a solution in which
# abs(cost - isorange) / isorange <= TOLERANCE
# Initial setup
angles = get_angles(number_of_angles)
rmax = [upper_rmax] * number_of_angles
rmin = [0.0] * number_of_angles
location_estimates = [calculate_dest_location(origin, a,
upper_rmax / 2.0)
for a in angles]
# Iterate to refine the first solution
for i in xrange(0, max_iterations):
# Calculate the "actual" cost for each location estimate.
# NOTE: sometimes it cannot calculate the cost and returns None.
# Just assume isorange and stop the calculations there
costs, destinations = cost_method(origin=origin,
targets=location_estimates,
isorange=isorange,
profile=profile,
unit_factor=unit_factor,
number_of_angles=number_of_angles)
if not costs:
continue
errors = [(cost - isorange) / float(isorange) for cost in costs]
max_abs_error = max([abs(e) for e in errors])
if max_abs_error <= tolerance:
# good enough, stop there
break
# let's refine the solution, binary search
for j in xrange(0, number_of_angles):
if abs(errors[j]) > tolerance:
if errors[j] > 0:
rmax[j] = (rmax[j] + rmin[j]) / 2.0
else:
rmin[j] = (rmax[j] + rmin[j]) / 2.0
location_estimates[j] = calculate_dest_location(origin,
angles[j],
(rmax[j] + rmin[j]) / 2.0)
# delete points that got None
location_estimates_filtered = []
for i, c in enumerate(costs):
if c != isorange and c < isorange * (1 + tolerance):
location_estimates_filtered.append(destinations[i])
return location_estimates_filtered
class MapboxIsochronesResponse: class MapboxIsochronesResponse:

View File

@@ -1,92 +0,0 @@
'''
Python client for the Mapbox Time Matrix service.
'''
import requests
from cartodb_services.metrics import Traceable
from cartodb_services.tools.coordinates import (validate_coordinates,
marshall_coordinates)
from cartodb_services.tools.exceptions import ServiceException
from cartodb_services.tools.qps import qps_retry
BASEURI = ('https://api.mapbox.com/directions-matrix/v1/mapbox/{profile}/'
'{coordinates}'
'?access_token={token}'
'&sources=0' # Set the first coordinate as source...
'&destinations=all') # ...and the rest as destinations
NUM_COORDINATES_MIN = 2 # https://www.mapbox.com/api-documentation/#matrix
NUM_COORDINATES_MAX = 25 # https://www.mapbox.com/api-documentation/#matrix
PROFILE_DRIVING_TRAFFIC = 'driving-traffic'
PROFILE_DRIVING = 'driving'
PROFILE_CYCLING = 'cycling'
PROFILE_WALKING = 'walking'
DEFAULT_PROFILE = PROFILE_DRIVING
VALID_PROFILES = [PROFILE_DRIVING_TRAFFIC,
PROFILE_DRIVING,
PROFILE_CYCLING,
PROFILE_WALKING]
ENTRY_DURATIONS = 'durations'
ENTRY_DESTINATIONS = 'destinations'
ENTRY_LOCATION = 'location'
def validate_profile(profile):
if profile not in VALID_PROFILES:
raise ValueError('{profile} is not a valid profile. '
'Valid profiles are: {valid_profiles}'.format(
profile=profile,
valid_profiles=', '.join(
[x for x in VALID_PROFILES])))
class MapboxMatrixClient(Traceable):
'''
Python wrapper for the Mapbox Time Matrix service.
'''
def __init__(self, token, logger, service_params=None):
service_params = service_params or {}
self._token = token
self._logger = logger
def _uri(self, coordinates, profile=DEFAULT_PROFILE):
return BASEURI.format(profile=profile, coordinates=coordinates,
token=self._token)
@qps_retry(qps=1)
def matrix(self, coordinates, profile=DEFAULT_PROFILE):
validate_profile(profile)
validate_coordinates(coordinates,
NUM_COORDINATES_MIN, NUM_COORDINATES_MAX)
coords = marshall_coordinates(coordinates)
uri = self._uri(coords, profile)
try:
response = requests.get(uri)
if response.status_code == requests.codes.ok:
return response.text
elif response.status_code == requests.codes.bad_request:
return '{}'
elif response.status_code == requests.codes.unprocessable_entity:
return '{}'
else:
raise ServiceException(response.status_code, response)
except requests.Timeout as te:
# In case of timeout we want to stop the job because the server
# could be down
self._logger.error('Timeout connecting to Mapbox matrix service',
te)
raise ServiceException('Error getting matrix data from Mapbox',
None)
except requests.ConnectionError as ce:
# Don't raise the exception to continue with the geocoding job
self._logger.error('Error connecting to Mapbox matrix service',
exception=ce)
return '{}'

View File

@@ -1,5 +1,5 @@
from routing import MapzenRouting, MapzenRoutingResponse from cartodb_services.mapzen.routing import MapzenRouting, MapzenRoutingResponse
from isolines import MapzenIsolines from cartodb_services.mapzen.isolines import MapzenIsolines
from geocoder import MapzenGeocoder from cartodb_services.mapzen.geocoder import MapzenGeocoder
from matrix_client import MatrixClient from cartodb_services.mapzen.matrix_client import MatrixClient
from isochrones import MapzenIsochrones from cartodb_services.mapzen.isochrones import MapzenIsochrones

View File

@@ -135,7 +135,7 @@ class MapzenIsolines:
# delete points that got None # delete points that got None
location_estimates_filtered = [] location_estimates_filtered = []
for i, c in enumerate(costs): for i, c in enumerate(costs):
if c <> isorange: if c != isorange:
location_estimates_filtered.append(location_estimates[i]) location_estimates_filtered.append(location_estimates[i])
return location_estimates_filtered return location_estimates_filtered

View File

@@ -1,4 +1,4 @@
from config import GeocoderConfig, IsolinesRoutingConfig, InternalGeocoderConfig, RoutingConfig, ConfigException, ObservatoryConfig from cartodb_services.metrics.config import GeocoderConfig, IsolinesRoutingConfig, InternalGeocoderConfig, RoutingConfig, ConfigException, ObservatoryConfig
from quota import QuotaService from cartodb_services.metrics.quota import QuotaService
from user import UserMetricsService from cartodb_services.metrics.user import UserMetricsService
from log import metrics, MetricsDataGatherer, Traceable from cartodb_services.metrics.log import metrics, MetricsDataGatherer, Traceable

View File

@@ -45,7 +45,7 @@ class ServiceConfig(object):
def _get_effective_monthly_quota(self, quota_key, default=0): def _get_effective_monthly_quota(self, quota_key, default=0):
quota_from_redis = self._redis_config.get(quota_key, None) quota_from_redis = self._redis_config.get(quota_key, None)
if quota_from_redis and quota_from_redis <> '': if quota_from_redis and quota_from_redis != '':
return int(quota_from_redis) return int(quota_from_redis)
else: else:
return default return default
@@ -405,6 +405,8 @@ class GeocoderConfig(ServiceConfig):
MAPBOX_GEOCODER_API_KEYS = 'mapbox_geocoder_api_keys' MAPBOX_GEOCODER_API_KEYS = 'mapbox_geocoder_api_keys'
TOMTOM_GEOCODER = 'tomtom' TOMTOM_GEOCODER = 'tomtom'
TOMTOM_GEOCODER_API_KEYS = 'tomtom_geocoder_api_keys' TOMTOM_GEOCODER_API_KEYS = 'tomtom_geocoder_api_keys'
GEOCODIO_GEOCODER = 'geocodio'
GEOCODIO_GEOCODER_API_KEYS = 'geocodio_geocoder_api_keys'
QUOTA_KEY = 'geocoding_quota' QUOTA_KEY = 'geocoding_quota'
SOFT_LIMIT_KEY = 'soft_geocoding_limit' SOFT_LIMIT_KEY = 'soft_geocoding_limit'
USERNAME_KEY = 'username' USERNAME_KEY = 'username'
@@ -437,6 +439,9 @@ class GeocoderConfig(ServiceConfig):
elif self._geocoder_provider == self.TOMTOM_GEOCODER: elif self._geocoder_provider == self.TOMTOM_GEOCODER:
if not self.tomtom_api_keys: if not self.tomtom_api_keys:
raise ConfigException("""TomTom config is not set up""") raise ConfigException("""TomTom config is not set up""")
elif self._geocoder_provider == self.GEOCODIO_GEOCODER:
if not self.geocodio_api_keys:
raise ConfigException("""Geocodio config is not set up""")
return True return True
@@ -476,6 +481,10 @@ class GeocoderConfig(ServiceConfig):
self._tomtom_api_keys = db_config.tomtom_geocoder_api_keys self._tomtom_api_keys = db_config.tomtom_geocoder_api_keys
self._cost_per_hit = 0 self._cost_per_hit = 0
self._tomtom_service_params = db_config.tomtom_geocoder_service_params self._tomtom_service_params = db_config.tomtom_geocoder_service_params
elif self._geocoder_provider == self.GEOCODIO_GEOCODER:
self._geocodio_api_keys = db_config.geocodio_geocoder_api_keys
self._cost_per_hit = 0
self._geocodio_service_params = db_config.geocodio_geocoder_service_params
@property @property
def service_type(self): def service_type(self):
@@ -489,6 +498,8 @@ class GeocoderConfig(ServiceConfig):
return 'geocoder_tomtom' return 'geocoder_tomtom'
elif self._geocoder_provider == self.NOKIA_GEOCODER: elif self._geocoder_provider == self.NOKIA_GEOCODER:
return 'geocoder_here' return 'geocoder_here'
elif self._geocoder_provider == self.GEOCODIO_GEOCODER:
return 'geocoder_geocodio'
@property @property
def heremaps_geocoder(self): def heremaps_geocoder(self):
@@ -510,6 +521,10 @@ class GeocoderConfig(ServiceConfig):
def tomtom_geocoder(self): def tomtom_geocoder(self):
return self._geocoder_provider == self.TOMTOM_GEOCODER return self._geocoder_provider == self.TOMTOM_GEOCODER
@property
def geocodio_geocoder(self):
return self._geocoder_provider == self.GEOCODIO_GEOCODER
@property @property
def google_client_id(self): def google_client_id(self):
return self._google_maps_client_id return self._google_maps_client_id
@@ -569,6 +584,14 @@ class GeocoderConfig(ServiceConfig):
def tomtom_service_params(self): def tomtom_service_params(self):
return self._tomtom_service_params return self._tomtom_service_params
@property
def geocodio_api_keys(self):
return self._geocodio_api_keys
@property
def geocodio_service_params(self):
return self._geocodio_service_params
@property @property
def is_high_resolution(self): def is_high_resolution(self):
return True return True
@@ -600,6 +623,7 @@ class ServicesDBConfig:
self._get_mapzen_config() self._get_mapzen_config()
self._get_mapbox_config() self._get_mapbox_config()
self._get_tomtom_config() self._get_tomtom_config()
self._get_geocodio_config()
self._get_data_observatory_config() self._get_data_observatory_config()
def _get_server_config(self): def _get_server_config(self):
@@ -652,6 +676,9 @@ class ServicesDBConfig:
raise ConfigException('Mapbox configuration missing') raise ConfigException('Mapbox configuration missing')
mapbox_conf = json.loads(mapbox_conf_json) mapbox_conf = json.loads(mapbox_conf_json)
# Note: We are no longer using the Matrix API but we have avoided renaming the `matrix` parameter
# to `isolines` to ensure retrocompatibility
self._mapbox_matrix_api_keys = mapbox_conf['matrix']['api_keys'] self._mapbox_matrix_api_keys = mapbox_conf['matrix']['api_keys']
self._mapbox_matrix_quota = mapbox_conf['matrix']['monthly_quota'] self._mapbox_matrix_quota = mapbox_conf['matrix']['monthly_quota']
self._mapbox_matrix_service_params = mapbox_conf['matrix'].get('service', {}) self._mapbox_matrix_service_params = mapbox_conf['matrix'].get('service', {})
@@ -679,6 +706,16 @@ class ServicesDBConfig:
self._tomtom_geocoder_quota = tomtom_conf['geocoder']['monthly_quota'] self._tomtom_geocoder_quota = tomtom_conf['geocoder']['monthly_quota']
self._tomtom_geocoder_service_params = tomtom_conf['geocoder'].get('service', {}) self._tomtom_geocoder_service_params = tomtom_conf['geocoder'].get('service', {})
def _get_geocodio_config(self):
geocodio_conf_json = self._get_conf('geocodio_conf')
if not geocodio_conf_json:
raise ConfigException('Geocodio configuration missing')
else:
geocodio_conf = json.loads(geocodio_conf_json)
self._geocodio_geocoder_api_keys = geocodio_conf['geocoder']['api_keys']
self._geocodio_geocoder_quota = geocodio_conf['geocoder']['monthly_quota']
self._geocodio_geocoder_service_params = geocodio_conf['geocoder'].get('service', {})
def _get_data_observatory_config(self): def _get_data_observatory_config(self):
do_conf_json = self._get_conf('data_observatory_conf') do_conf_json = self._get_conf('data_observatory_conf')
if not do_conf_json: if not do_conf_json:
@@ -848,6 +885,18 @@ class ServicesDBConfig:
def tomtom_geocoder_service_params(self): def tomtom_geocoder_service_params(self):
return self._tomtom_geocoder_service_params return self._tomtom_geocoder_service_params
@property
def geocodio_geocoder_api_keys(self):
return self._geocodio_geocoder_api_keys
@property
def geocodio_geocoder_monthly_quota(self):
return self.geocodio_geocoder_quota
@property
def geocodio_geocoder_service_params(self):
return self._geocodio_geocoder_service_params
@property @property
def data_observatory_connection_str(self): def data_observatory_connection_str(self):
return self._data_observatory_connection_str return self._data_observatory_connection_str

View File

@@ -6,7 +6,10 @@ import uuid
import plpy import plpy
from datetime import datetime from datetime import datetime
from contextlib import contextmanager from contextlib import contextmanager
try:
from urlparse import urlparse from urlparse import urlparse
except:
from urllib.parse import urlparse
@contextmanager @contextmanager

View File

@@ -1,5 +1,5 @@
from user import UserMetricsService from cartodb_services.metrics.user import UserMetricsService
from log import MetricsDataGatherer from cartodb_services.metrics.log import MetricsDataGatherer
from datetime import date from datetime import date
import re import re

View File

@@ -0,0 +1,128 @@
from dateutil.parser import parse as date_parse
from cartodb_services.refactor.service.utils import round_robin
from cartodb_services.geocodio.types import GEOCODIO_GEOCODER_APIKEY_ROUNDROBIN
class GeocodioGeocoderConfig(object):
"""
Configuration needed to operate the Geocodio geocoder service.
"""
def __init__(self,
geocoding_quota,
soft_geocoding_limit,
period_end_date,
cost_per_hit,
log_path,
geocodio_api_keys,
username,
organization,
service_params,
GD):
self._geocoding_quota = geocoding_quota
self._soft_geocoding_limit = soft_geocoding_limit
self._period_end_date = period_end_date
self._cost_per_hit = cost_per_hit
self._log_path = log_path
self._geocodio_api_keys = geocodio_api_keys
self._username = username
self._organization = organization
self._service_params = service_params
self._GD = GD
@property
def service_type(self):
return 'geocoder_geocodio'
@property
def provider(self):
return 'geocodio'
@property
def is_high_resolution(self):
return True
@property
def geocoding_quota(self):
return self._geocoding_quota
@property
def soft_geocoding_limit(self):
return self._soft_geocoding_limit
@property
def period_end_date(self):
return self._period_end_date
@property
def cost_per_hit(self):
return self._cost_per_hit
@property
def log_path(self):
return self._log_path
@property
def geocodio_api_key(self):
return round_robin(self._geocodio_api_keys, self._GD,
GEOCODIO_GEOCODER_APIKEY_ROUNDROBIN)
@property
def username(self):
return self._username
@property
def organization(self):
return self._organization
@property
def service_params(self):
return self._service_params
# TODO: for BW compat, remove
@property
def google_geocoder(self):
return False
class GeocodioGeocoderConfigBuilder(object):
def __init__(self, server_conf, user_conf, org_conf, username, orgname, GD):
self._server_conf = server_conf
self._user_conf = user_conf
self._org_conf = org_conf
self._username = username
self._orgname = orgname
self._GD = GD
def get(self):
geocodio_server_conf = self._server_conf.get('geocodio_conf')
geocodio_api_keys = geocodio_server_conf['geocoder']['api_keys']
geocodio_service_params = geocodio_server_conf['geocoder'].get('service', {})
geocoding_quota = self._get_quota()
soft_geocoding_limit = self._user_conf.get('soft_geocoding_limit').lower() == 'true'
cost_per_hit = 0
period_end_date_str = self._org_conf.get('period_end_date') or self._user_conf.get('period_end_date')
period_end_date = date_parse(period_end_date_str)
logger_conf = self._server_conf.get('logger_conf')
log_path = logger_conf.get('geocoder_log_path', None)
return GeocodioGeocoderConfig(geocoding_quota,
soft_geocoding_limit,
period_end_date,
cost_per_hit,
log_path,
geocodio_api_keys,
self._username,
self._orgname,
geocodio_service_params,
self._GD)
def _get_quota(self):
geocoding_quota = self._org_conf.get('geocoding_quota') or self._user_conf.get('geocoding_quota')
if geocoding_quota is '':
return 0
return int(geocoding_quota)

View File

@@ -92,6 +92,9 @@ class MapboxIsolinesConfigBuilder(object):
def get(self): def get(self):
mapbox_server_conf = self._server_conf.get('mapbox_conf') mapbox_server_conf = self._server_conf.get('mapbox_conf')
# Note: We are no longer using the Matrix API but we have avoided renaming the `matrix` parameter
# to `isolines` to ensure retrocompatibility
mapbox_api_keys = mapbox_server_conf['matrix']['api_keys'] mapbox_api_keys = mapbox_server_conf['matrix']['api_keys']
mapbox_service_params = mapbox_server_conf['matrix'].get('service', {}) mapbox_service_params = mapbox_server_conf['matrix'].get('service', {})

View File

@@ -1,5 +1,5 @@
from ..core.interfaces import ConfigBackendInterface from ..core.interfaces import ConfigBackendInterface
from null_config import NullConfigStorage from cartodb_services.refactor.storage.null_config import NullConfigStorage
class RedisConfigStorage(ConfigBackendInterface): class RedisConfigStorage(ConfigBackendInterface):

View File

@@ -18,5 +18,5 @@ class RedisConnectionBuilder():
else: else:
conn = StrictRedis(host=self._config.host, port=self._config.port, conn = StrictRedis(host=self._config.host, port=self._config.port,
db=self._config.db, retry_on_timeout=True, db=self._config.db, retry_on_timeout=True,
socket_timeout=self._config.timeout) socket_timeout=self._config.timeout, decode_responses=True)
return conn return conn

View File

@@ -1,4 +1,4 @@
from geocoder import TomTomGeocoder from cartodb_services.tomtom.geocoder import TomTomGeocoder
from bulk_geocoder import TomTomBulkGeocoder from cartodb_services.tomtom.bulk_geocoder import TomTomBulkGeocoder
from routing import TomTomRouting, TomTomRoutingResponse from cartodb_services.tomtom.routing import TomTomRouting, TomTomRoutingResponse
from isolines import TomTomIsolines, TomTomIsochronesResponse from cartodb_services.tomtom.isolines import TomTomIsolines, TomTomIsochronesResponse

View File

@@ -3,6 +3,7 @@ from requests.adapters import HTTPAdapter
from cartodb_services import StreetPointBulkGeocoder from cartodb_services import StreetPointBulkGeocoder
from cartodb_services.geocoder import geocoder_error_response from cartodb_services.geocoder import geocoder_error_response
from cartodb_services.tomtom import TomTomGeocoder from cartodb_services.tomtom import TomTomGeocoder
from cartodb_services.tools.qps import qps_retry
from cartodb_services.tools.exceptions import ServiceException from cartodb_services.tools.exceptions import ServiceException
@@ -59,6 +60,7 @@ class TomTomBulkGeocoder(TomTomGeocoder, StreetPointBulkGeocoder):
self._logger.error(msg, e) self._logger.error(msg, e)
return [geocoder_error_response(msg)] * len(searches) return [geocoder_error_response(msg)] * len(searches)
@qps_retry(qps=5, provider='tomtom')
def _send_batch(self, searches): def _send_batch(self, searches):
body = {'batchItems': [{'query': self._query(s)} for s in searches]} body = {'batchItems': [{'query': self._query(s)} for s in searches]}
request_params = { request_params = {
@@ -76,6 +78,7 @@ class TomTomBulkGeocoder(TomTomGeocoder, StreetPointBulkGeocoder):
self._logger.error(msg) self._logger.error(msg)
raise ServiceException(msg, response) raise ServiceException(msg, response)
@qps_retry(qps=5, provider='tomtom')
def _download_results(self, location): def _download_results(self, location):
stalled_retries = 0 stalled_retries = 0
while True: while True:

View File

@@ -1,9 +1,9 @@
from redis_tools import RedisConnection, RedisDBConfig from .redis_tools import RedisConnection, RedisDBConfig
from coordinates import Coordinate from .coordinates import Coordinate
from polyline import PolyLine from .polyline import PolyLine
from log import Logger, LoggerConfig from .log import Logger, LoggerConfig
from rate_limiter import RateLimiter from .rate_limiter import RateLimiter
from service_manager import ServiceManager from .service_manager import ServiceManager
from legacy_service_manager import LegacyServiceManager from .legacy_service_manager import LegacyServiceManager
from exceptions import QuotaExceededException, RateLimitExceeded from .exceptions import QuotaExceededException, RateLimitExceeded
from country import country_to_iso3 from .country import country_to_iso3

View File

@@ -1,7 +1,7 @@
import time import time
import random import random
from datetime import datetime from datetime import datetime
from exceptions import TimeoutException from cartodb_services.tools.exceptions import TimeoutException
import re import re
DEFAULT_RETRY_TIMEOUT = 60 DEFAULT_RETRY_TIMEOUT = 60

View File

@@ -23,7 +23,7 @@ class RedisConnection:
else: else:
conn = StrictRedis(host=self._config.host, port=self._config.port, conn = StrictRedis(host=self._config.host, port=self._config.port,
db=self._config.db, retry_on_timeout=True, db=self._config.db, retry_on_timeout=True,
socket_timeout=self._config.timeout) socket_timeout=self._config.timeout, decode_responses=True)
return conn return conn

View File

@@ -4,9 +4,10 @@ python-dateutil==2.2
googlemaps==2.5.1 googlemaps==2.5.1
rollbar==0.13.2 rollbar==0.13.2
# Dependency for googlemaps package # Dependency for googlemaps package
requests==2.9.1 requests==2.20.0
rratelimit==0.0.4 rratelimit==0.0.4
mapbox==0.14.0 mapbox==0.14.0
pygeocodio==0.11.1
# Test # Test
mock==1.3.0 mock==1.3.0

View File

@@ -10,7 +10,7 @@ from setuptools import setup, find_packages
setup( setup(
name='cartodb_services', name='cartodb_services',
version='0.21.4', version='0.23.2',
description='CartoDB Services API Python Library', description='CartoDB Services API Python Library',

View File

@@ -9,3 +9,8 @@ def mapbox_api_key():
def tomtom_api_key(): def tomtom_api_key():
"""Returns TomTom API key. Requires setting TOMTOM_API_KEY environment variable.""" """Returns TomTom API key. Requires setting TOMTOM_API_KEY environment variable."""
return os.environ['TOMTOM_API_KEY'] return os.environ['TOMTOM_API_KEY']
def geocodio_api_key():
"""Returns Geocodio API key. Requires setting GEOCODIO_API_KEY environment variable."""
return os.environ['GEOCODIO_API_KEY']

View File

@@ -7,7 +7,7 @@ from cartodb_services.metrics.config import *
class TestGeocoderUserConfig(TestCase): class TestGeocoderUserConfig(TestCase):
GEOCODER_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'tomtom', 'google'] GEOCODER_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'tomtom', 'geocodio', 'google']
def setUp(self): def setUp(self):
self.redis_conn = MockRedis() self.redis_conn = MockRedis()
@@ -31,6 +31,9 @@ class TestGeocoderUserConfig(TestCase):
elif geocoder_provider == 'tomtom': elif geocoder_provider == 'tomtom':
assert geocoder_config.tomtom_geocoder is True assert geocoder_config.tomtom_geocoder is True
assert geocoder_config.geocoding_quota == 100 assert geocoder_config.geocoding_quota == 100
elif geocoder_provider == 'geocodio':
assert geocoder_config.geocodio_geocoder is True
assert geocoder_config.geocoding_quota == 100
elif geocoder_provider == 'google': elif geocoder_provider == 'google':
assert geocoder_config.google_geocoder is True assert geocoder_config.google_geocoder is True
assert geocoder_config.geocoding_quota is None assert geocoder_config.geocoding_quota is None
@@ -84,7 +87,7 @@ class TestGeocoderUserConfig(TestCase):
class TestGeocoderOrgConfig(TestCase): class TestGeocoderOrgConfig(TestCase):
GEOCODER_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'tomtom', 'google'] GEOCODER_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'tomtom', 'geocodio', 'google']
def setUp(self): def setUp(self):
self.redis_conn = MockRedis() self.redis_conn = MockRedis()
@@ -113,6 +116,9 @@ class TestGeocoderOrgConfig(TestCase):
elif geocoder_provider == 'tomtom': elif geocoder_provider == 'tomtom':
assert geocoder_config.tomtom_geocoder is True assert geocoder_config.tomtom_geocoder is True
assert geocoder_config.geocoding_quota == 200 assert geocoder_config.geocoding_quota == 200
elif geocoder_provider == 'geocodio':
assert geocoder_config.geocodio_geocoder is True
assert geocoder_config.geocoding_quota == 200
elif geocoder_provider == 'google': elif geocoder_provider == 'google':
assert geocoder_config.google_geocoder is True assert geocoder_config.google_geocoder is True
assert geocoder_config.geocoding_quota is None assert geocoder_config.geocoding_quota is None

View File

@@ -0,0 +1,268 @@
import unittest
from mock import Mock
from cartodb_services.geocodio import GeocodioGeocoder
from cartodb_services.geocodio import GeocodioBulkGeocoder
from cartodb_services.tools.exceptions import ServiceException
from credentials import geocodio_api_key
INVALID_TOKEN = 'invalid_token'
VALID_ADDRESS_1 = 'Lexington Ave; New York; US'
VALID_ADDRESS_2 = 'E 14th St; New York; US'
VALID_ADDRESS_3 = '652 Lombard Street; San Francisco; California; United States'
VALID_SEARCH_TEXT_1='Lexington Ave'
VALID_CITY_1='New York'
VALID_STATE_PROVINCE_1='New York'
VALID_COUNTRY_1='US'
VALID_SEARCH_TEXT_2='E 14th St'
VALID_CITY_2='New York'
VALID_STATE_PROVINCE_2='New York'
VALID_COUNTRY_2='US'
VALID_SEARCH_TEXT_3='652 Lombard Street'
VALID_CITY_3='San Francisco'
VALID_STATE_PROVINCE_3='California'
VALID_COUNTRY_3='United States'
WELL_KNOWN_LONGITUDE_1 = -73.960
WELL_KNOWN_LATITUDE_1 = 40.774
WELL_KNOWN_LONGITUDE_2 = -73.983
WELL_KNOWN_LATITUDE_2 = 40.731
WELL_KNOWN_LONGITUDE_3 = -122.412
WELL_KNOWN_LATITUDE_3 = 37.803207
SEARCH_ID_1 = 1
SEARCH_ID_2 = 2
class GeocodioGeocoderTestCase(unittest.TestCase):
def setUp(self):
self.geocoder = GeocodioGeocoder(token=geocodio_api_key(), logger=Mock())
self.bulk_geocoder = GeocodioBulkGeocoder(token=geocodio_api_key(), logger=Mock())
### NON BULK
def test_invalid_token(self):
invalid_geocoder = GeocodioGeocoder(token=INVALID_TOKEN, logger=Mock())
with self.assertRaises(ServiceException):
invalid_geocoder.geocode(VALID_ADDRESS_1)
def test_valid_requests(self):
place = self.geocoder.geocode(VALID_ADDRESS_1)
self.assertEqual('%.3f' % place[0], '%.3f' % WELL_KNOWN_LONGITUDE_1)
self.assertEqual('%.3f' % place[1], '%.3f' % WELL_KNOWN_LATITUDE_1)
place = self.geocoder.geocode(VALID_ADDRESS_2)
self.assertEqual('%.3f' % place[0], '%.3f' % WELL_KNOWN_LONGITUDE_2)
self.assertEqual('%.3f' % place[1], '%.3f' % WELL_KNOWN_LATITUDE_2)
place = self.geocoder.geocode(VALID_ADDRESS_3)
self.assertEqual('%.3f' % place[0], '%.3f' % WELL_KNOWN_LONGITUDE_3)
self.assertEqual('%.3f' % place[1], '%.3f' % WELL_KNOWN_LATITUDE_3)
def test_valid_request_components(self):
place = self.geocoder.geocode(searchtext=VALID_SEARCH_TEXT_1,
city=VALID_CITY_1,
state_province=VALID_STATE_PROVINCE_1,
country=VALID_COUNTRY_1)
self.assertEqual('%.3f' % place[0], '%.3f' % WELL_KNOWN_LONGITUDE_1)
self.assertEqual('%.3f' % place[1], '%.3f' % WELL_KNOWN_LATITUDE_1)
place = self.geocoder.geocode(searchtext=VALID_SEARCH_TEXT_2,
city=VALID_CITY_2,
state_province=VALID_STATE_PROVINCE_2,
country=VALID_COUNTRY_2)
self.assertEqual('%.3f' % place[0], '%.3f' % WELL_KNOWN_LONGITUDE_2)
self.assertEqual('%.3f' % place[1], '%.3f' % WELL_KNOWN_LATITUDE_2)
place = self.geocoder.geocode(searchtext=VALID_SEARCH_TEXT_3,
city=VALID_CITY_3,
state_province=VALID_STATE_PROVINCE_3,
country=VALID_COUNTRY_3)
self.assertEqual('%.3f' % place[0], '%.3f' % WELL_KNOWN_LONGITUDE_3)
self.assertEqual('%.3f' % place[1], '%.3f' % WELL_KNOWN_LATITUDE_3)
def test_valid_request_namedplace(self):
place = self.geocoder.geocode(searchtext='New York')
assert place
def test_valid_request_namedplace2(self):
place = self.geocoder.geocode(searchtext='New York', country='us')
assert place
def test_odd_characters(self):
place = self.geocoder.geocode(searchtext='New York; &quot;USA&quot;')
assert place
def test_empty_request(self):
place = self.geocoder.geocode(searchtext='', country=None, city=None, state_province=None)
assert place == []
def test_empty_search_text_request(self):
place = self.geocoder.geocode(searchtext=' ', country='us', city=None, state_province="")
assert place == []
def test_unknown_place_request(self):
place = self.geocoder.geocode(searchtext='[unknown]', country='ch', state_province=None, city=None)
assert place == []
### BULK ONE
def test_invalid_token_bulk_one(self):
invalid_geocoder = GeocodioBulkGeocoder(token=INVALID_TOKEN, logger=Mock())
with self.assertRaises(ServiceException):
invalid_geocoder._batch_geocode([(SEARCH_ID_1, VALID_ADDRESS_1, None, None, None)])
def test_valid_request_bulk_one(self):
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, VALID_ADDRESS_1, None, None, None)])
self.assertEqual(place[0][0], SEARCH_ID_1)
self.assertEqual('%.3f' % place[0][1], '%.3f' % WELL_KNOWN_LONGITUDE_1)
self.assertEqual('%.3f' % place[0][2], '%.3f' % WELL_KNOWN_LATITUDE_1)
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, VALID_ADDRESS_2, None, None, None)])
self.assertEqual(place[0][0], SEARCH_ID_1)
self.assertEqual('%.3f' % place[0][1], '%.3f' % WELL_KNOWN_LONGITUDE_2)
self.assertEqual('%.3f' % place[0][2], '%.3f' % WELL_KNOWN_LATITUDE_2)
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, VALID_ADDRESS_3, None, None, None)])
self.assertEqual(place[0][0], SEARCH_ID_1)
self.assertEqual('%.3f' % place[0][1], '%.3f' % WELL_KNOWN_LONGITUDE_3)
self.assertEqual('%.3f' % place[0][2], '%.3f' % WELL_KNOWN_LATITUDE_3)
def test_valid_request_components_bulk_one(self):
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, VALID_SEARCH_TEXT_1, VALID_CITY_1, VALID_STATE_PROVINCE_1, VALID_COUNTRY_1)])
self.assertEqual(place[0][0], SEARCH_ID_1)
self.assertEqual('%.3f' % place[0][1], '%.3f' % WELL_KNOWN_LONGITUDE_1)
self.assertEqual('%.3f' % place[0][2], '%.3f' % WELL_KNOWN_LATITUDE_1)
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, VALID_SEARCH_TEXT_2, VALID_CITY_2, VALID_STATE_PROVINCE_2, VALID_COUNTRY_2)])
self.assertEqual(place[0][0], SEARCH_ID_1)
self.assertEqual('%.3f' % place[0][1], '%.3f' % WELL_KNOWN_LONGITUDE_2)
self.assertEqual('%.3f' % place[0][2], '%.3f' % WELL_KNOWN_LATITUDE_2)
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, VALID_SEARCH_TEXT_3, VALID_CITY_3, VALID_STATE_PROVINCE_3, VALID_COUNTRY_3)])
self.assertEqual(place[0][0], SEARCH_ID_1)
self.assertEqual('%.3f' % place[0][1], '%.3f' % WELL_KNOWN_LONGITUDE_3)
self.assertEqual('%.3f' % place[0][2], '%.3f' % WELL_KNOWN_LATITUDE_3)
def test_valid_request_namedplace_bulk_one(self):
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, 'New York', None, None, None)])
assert place
def test_valid_request_namedplace2_bulk_one(self):
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, 'New York', 'us', None, None)])
assert place
def test_odd_characters_bulk_one(self):
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, 'New York; &quot;USA&quot;', None, None, None)])
assert place
def test_empty_request_bulk_one(self):
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, '', None, None, None)])
assert place == [(SEARCH_ID_1, None, None)]
def test_empty_search_text_request_bulk_one(self):
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, ' ', 'us', None, "")])
assert place == [(SEARCH_ID_1, None, None)]
def test_unknown_place_request_bulk_one(self):
place = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, '[unknown]', 'ch', None, None)])
assert place == [(SEARCH_ID_1, None, None)]
### BULK MANY
def test_invalid_token_bulk_many(self):
invalid_geocoder = GeocodioBulkGeocoder(token=INVALID_TOKEN, logger=Mock())
with self.assertRaises(ServiceException):
invalid_geocoder._batch_geocode([(SEARCH_ID_1, VALID_ADDRESS_1, None, None, None),
(SEARCH_ID_2, VALID_ADDRESS_2, None, None, None)])
def test_valid_request_bulk_many(self):
places = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, VALID_ADDRESS_1, None, None, None),
(SEARCH_ID_2, VALID_ADDRESS_2, None, None, None)])
self.assertEqual(places[0][0], SEARCH_ID_1)
self.assertEqual('%.3f' % places[0][1][0], '%.3f' % WELL_KNOWN_LONGITUDE_1)
self.assertEqual('%.3f' % places[0][1][1], '%.3f' % WELL_KNOWN_LATITUDE_1)
self.assertEqual(places[1][0], SEARCH_ID_2)
self.assertEqual('%.3f' % places[1][1][0], '%.3f' % WELL_KNOWN_LONGITUDE_2)
self.assertEqual('%.3f' % places[1][1][1], '%.3f' % WELL_KNOWN_LATITUDE_2)
def test_valid_request_components_bulk_many(self):
places = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, VALID_SEARCH_TEXT_1, VALID_CITY_1, VALID_STATE_PROVINCE_1, VALID_COUNTRY_1),
(SEARCH_ID_2, VALID_SEARCH_TEXT_2, VALID_CITY_2, VALID_STATE_PROVINCE_2, VALID_COUNTRY_2)])
self.assertEqual(places[0][0], SEARCH_ID_1)
self.assertEqual(places[1][0], SEARCH_ID_2)
def test_valid_request_namedplace_bulk_many(self):
places = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, 'New York', None, None, None),
(SEARCH_ID_2, 'Los Angeles', None, None, None)])
assert places
self.assertEqual(places[0][0], SEARCH_ID_1)
self.assertEqual(places[1][0], SEARCH_ID_2)
def test_valid_request_namedplace2_bulk_many(self):
places = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, 'New York', 'us', None, None),
(SEARCH_ID_2, 'Los Angeles', None, None, None)])
assert places
self.assertEqual(places[0][0], SEARCH_ID_1)
self.assertEqual(places[1][0], SEARCH_ID_2)
def test_odd_characters_bulk_many(self):
places = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, 'New York; &quot;USA&quot;', None, None, None),
(SEARCH_ID_2, 'Los Angeles', None, None, None)])
assert places
self.assertEqual(places[0][0], SEARCH_ID_1)
self.assertEqual(places[1][0], SEARCH_ID_2)
def test_empty_request_bulk_many(self):
places = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, '', None, None, None),
(SEARCH_ID_2, '', None, None, None)])
assert places == [(SEARCH_ID_1, [], {}), (SEARCH_ID_2, [], {})]
def test_empty_search_text_request_bulk_many(self):
places = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, ' ', 'us', None, ""),
(SEARCH_ID_2, ' ', 'us', None, "")])
assert places == [(SEARCH_ID_1, [], {}), (SEARCH_ID_2, [], {})]
def test_unknown_place_request_bulk_many(self):
places = self.bulk_geocoder._batch_geocode([(SEARCH_ID_1, '[unknown]', 'ch', None, None),
(SEARCH_ID_2, '[unknown]', 'ch', None, None)])
assert places == [(SEARCH_ID_1, [], {}), (SEARCH_ID_2, [], {})]

Some files were not shown because too many files have changed in this diff Show More