From 64d2afb53647838ea96415c1a3756aa853fe4241 Mon Sep 17 00:00:00 2001 From: Carla Iriberri Date: Tue, 10 May 2016 18:05:53 +0200 Subject: [PATCH 1/7] Client side for the new data observatory functions (v0.5.0) --- client/Makefile | 4 +- .../cdb_dataservices_client--0.4.0--0.5.0.sql | 597 ++++++++++++++++++ .../cdb_dataservices_client--0.5.0--0.4.0.sql | 21 + client/cdb_dataservices_client.control | 2 +- .../cdb_dataservices_client--0.3.0--0.4.0.sql | 0 .../cdb_dataservices_client--0.4.0--0.3.0.sql | 0 .../cdb_dataservices_client--0.4.0.sql | 0 client/renderer/interface.yaml | 163 ++++- .../expected/90_data_observatory_test.out | 288 ++++++++- client/test/sql/90_data_observatory_test.sql | 177 +++++- 10 files changed, 1240 insertions(+), 12 deletions(-) create mode 100644 client/cdb_dataservices_client--0.4.0--0.5.0.sql create mode 100644 client/cdb_dataservices_client--0.5.0--0.4.0.sql rename client/{ => old_versions}/cdb_dataservices_client--0.3.0--0.4.0.sql (100%) rename client/{ => old_versions}/cdb_dataservices_client--0.4.0--0.3.0.sql (100%) rename client/{ => old_versions}/cdb_dataservices_client--0.4.0.sql (100%) diff --git a/client/Makefile b/client/Makefile index 6049479..167cac5 100644 --- a/client/Makefile +++ b/client/Makefile @@ -13,8 +13,8 @@ OLD_VERSIONS = $(wildcard old_versions/*.sql) # @see http://www.postgresql.org/docs/current/static/extend-pgxs.html DATA = $(NEW_EXTENSION_ARTIFACT) \ $(OLD_VERSIONS) \ - cdb_dataservices_client--0.3.0--0.4.0.sql \ - cdb_dataservices_client--0.4.0--0.3.0.sql + cdb_dataservices_client--0.4.0--0.5.0.sql \ + cdb_dataservices_client--0.5.0--0.4.0.sql REGRESS = $(notdir $(basename $(wildcard test/sql/*test.sql))) diff --git a/client/cdb_dataservices_client--0.4.0--0.5.0.sql b/client/cdb_dataservices_client--0.4.0--0.5.0.sql new file mode 100644 index 0000000..ac927b7 --- /dev/null +++ b/client/cdb_dataservices_client--0.4.0--0.5.0.sql @@ -0,0 +1,597 @@ +--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.5.0'" to load this file. \quit + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getdemographicsnapshot (geom geometry(Geometry, 4326), time_span text DEFAULT NULL, geometry_level text DEFAULT NULL) +RETURNS json AS $$ +DECLARE + ret json; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getdemographicsnapshot(username, orgname, geom, time_span, geometry_level) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getsegmentsnapshot (geom geometry(Geometry, 4326), geometry_level text DEFAULT NULL) +RETURNS json AS $$ +DECLARE + ret json; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getsegmentsnapshot(username, orgname, geom, geometry_level) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundary (geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getboundary(username, orgname, geom, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundaryid (geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getboundaryid(username, orgname, geom, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundarybyid (geometry_id text, boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getboundarybyid(username, orgname, geometry_id, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundariesbygeometry (geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getboundariesbygeometry(username, orgname, geom, boundary_id, time_span, overlap_type) AS query; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundariesbypointandradius (geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getboundariesbypointandradius(username, orgname, geom, radius, boundary_id, time_span, overlap_type) AS query; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getpointsbygeometry (geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getpointsbygeometry(username, orgname, geom, boundary_id, time_span, overlap_type) AS query; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getpointsbypointandradius (geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getpointsbypointandradius(username, orgname, geom, radius, boundary_id, time_span, overlap_type) AS query; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getmeasure (geom Geometry, measure_id text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getmeasure(username, orgname, geom, measure_id, normalize, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getcategory (geom Geometry, category_id text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getcategory(username, orgname, geom, category_id, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getuscensusmeasure (geom Geometry, name text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getuscensusmeasure(username, orgname, geom, name, normalize, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getuscensuscategory (geom Geometry, name text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getuscensuscategory(username, orgname, geom, name, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getpopulation (geom Geometry, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getpopulation(username, orgname, geom, normalize, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_search (search_term text, relevant_boundary text DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_search(username, orgname, search_term, relevant_boundary) AS query; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getavailableboundaries (geom Geometry, timespan text DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getavailableboundaries(username, orgname, geom, timespan) AS query; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getdemographicsnapshot (username text, organization_name text, geom geometry(Geometry, 4326), time_span text DEFAULT NULL, geometry_level text DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getdemographicsnapshot (username, organization_name, geom, time_span, geometry_level); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getsegmentsnapshot (username text, organization_name text, geom geometry(Geometry, 4326), geometry_level text DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getsegmentsnapshot (username, organization_name, geom, geometry_level); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundary (username text, organization_name text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getboundary (username, organization_name, geom, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundaryid (username text, organization_name text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS text AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getboundaryid (username, organization_name, geom, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundarybyid (username text, organization_name text, geometry_id text, boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getboundarybyid (username, organization_name, geometry_id, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundariesbygeometry (username text, organization_name text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getboundariesbygeometry (username, organization_name, geom, boundary_id, time_span, overlap_type); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundariesbypointandradius (username text, organization_name text, geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getboundariesbypointandradius (username, organization_name, geom, radius, boundary_id, time_span, overlap_type); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getpointsbygeometry (username text, organization_name text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getpointsbygeometry (username, organization_name, geom, boundary_id, time_span, overlap_type); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getpointsbypointandradius (username text, organization_name text, geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getpointsbypointandradius (username, organization_name, geom, radius, boundary_id, time_span, overlap_type); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getmeasure (username text, organization_name text, geom Geometry, measure_id text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getmeasure (username, organization_name, geom, measure_id, normalize, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getcategory (username text, organization_name text, geom Geometry, category_id text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getcategory (username, organization_name, geom, category_id, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getuscensusmeasure (username text, organization_name text, geom Geometry, name text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getuscensusmeasure (username, organization_name, geom, name, normalize, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getuscensuscategory (username text, organization_name text, geom Geometry, name text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getuscensuscategory (username, organization_name, geom, name, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getpopulation (username text, organization_name text, geom Geometry, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getpopulation (username, organization_name, geom, normalize, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_search (username text, organization_name text, search_term text, relevant_boundary text DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_search (username, organization_name, search_term, relevant_boundary); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getavailableboundaries (username text, organization_name text, geom Geometry, time_span text DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getavailableboundaries (username, organization_name, geom, time_span); + +$$ LANGUAGE plproxy; + +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getdemographicsnapshot(geom geometry(Geometry, 4326), time_span text, geometry_level text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getsegmentsnapshot(geom geometry(Geometry, 4326), geometry_level text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundary(geom geometry(Geometry, 4326), boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundaryid(geom geometry(Geometry, 4326), boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundarybyid(geometry_id text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundariesbygeometry(geom geometry(Geometry, 4326), boundary_id text, time_span text, overlap_type text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundariesbypointandradius(geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text, overlap_type text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getpointsbygeometry(geom geometry(Geometry, 4326), boundary_id text, time_span text, overlap_type text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getpointsbypointandradius(geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text, overlap_type text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getmeasure(geom Geometry, measure_id text, normalize text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getcategory(geom Geometry, category_id text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getuscensusmeasure(geom Geometry, name text, normalize text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getuscensuscategory(geom Geometry, name text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getpopulation(geom Geometry, normalize text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_search(search_term text, relevant_boundary text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getavailableboundaries(geom Geometry, time_span text) TO publicuser; diff --git a/client/cdb_dataservices_client--0.5.0--0.4.0.sql b/client/cdb_dataservices_client--0.5.0--0.4.0.sql new file mode 100644 index 0000000..b8a01be --- /dev/null +++ b/client/cdb_dataservices_client--0.5.0--0.4.0.sql @@ -0,0 +1,21 @@ +--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.4.0'" to load this file. \quit +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_get_demographic_snapshot(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_get_segment_snapshot(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getdemographicsnapshot(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getsegmentsnapshot(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getboundary(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getboundaryid(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getboundarybyid(text, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getboundariesbygeometry(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getboundariesbypointandradius(geometry, numeric, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getpointsbygeometry(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getpointsbypointandradius(geometry, numeric, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getmeasure(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getcategory(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getuscensusmeasure(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getuscensuscategory(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getpopulation(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_search(text); +DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getavailableboundaries(geometry); \ No newline at end of file diff --git a/client/cdb_dataservices_client.control b/client/cdb_dataservices_client.control index e8811fd..022051c 100644 --- a/client/cdb_dataservices_client.control +++ b/client/cdb_dataservices_client.control @@ -1,5 +1,5 @@ comment = 'CartoDB dataservices client API extension' -default_version = '0.4.0' +default_version = '0.5.0' requires = 'plproxy, cartodb' superuser = true schema = cdb_dataservices_client diff --git a/client/cdb_dataservices_client--0.3.0--0.4.0.sql b/client/old_versions/cdb_dataservices_client--0.3.0--0.4.0.sql similarity index 100% rename from client/cdb_dataservices_client--0.3.0--0.4.0.sql rename to client/old_versions/cdb_dataservices_client--0.3.0--0.4.0.sql diff --git a/client/cdb_dataservices_client--0.4.0--0.3.0.sql b/client/old_versions/cdb_dataservices_client--0.4.0--0.3.0.sql similarity index 100% rename from client/cdb_dataservices_client--0.4.0--0.3.0.sql rename to client/old_versions/cdb_dataservices_client--0.4.0--0.3.0.sql diff --git a/client/cdb_dataservices_client--0.4.0.sql b/client/old_versions/cdb_dataservices_client--0.4.0.sql similarity index 100% rename from client/cdb_dataservices_client--0.4.0.sql rename to client/old_versions/cdb_dataservices_client--0.4.0.sql diff --git a/client/renderer/interface.yaml b/client/renderer/interface.yaml index 6496b5b..7a3ace5 100644 --- a/client/renderer/interface.yaml +++ b/client/renderer/interface.yaml @@ -93,11 +93,168 @@ return_type: json params: - { name: geom, type: "geometry(Geometry, 4326)" } - - { name: time_span, type: "text", default: "'2009 - 2013'::text" } - - { name: geometry_level, type: text, default: "'\"us.census.tiger\".block_group'::text" } + - { name: time_span, type: "text", default: 'NULL' } + - { name: geometry_level, type: text, default: 'NULL' } - name: obs_get_segment_snapshot return_type: json params: - { name: geom, type: "geometry(Geometry, 4326)" } - - { name: geometry_level, type: text, default: "'\"us.census.tiger\".census_tract'::text" } \ No newline at end of file + - { name: geometry_level, type: text, default: 'NULL' } + +- name: obs_getdemographicsnapshot + return_type: json + params: + - { name: geom, type: "geometry(Geometry, 4326)" } + - { name: time_span, type: "text", default: 'NULL' } + - { name: geometry_level, type: text, default: 'NULL' } + +- name: obs_getsegmentsnapshot + return_type: json + params: + - { name: geom, type: "geometry(Geometry, 4326)" } + - { name: geometry_level, type: text, default: 'NULL' } + +- name: obs_getboundary + return_type: Geometry + params: + - { name: geom, type: "geometry(Geometry, 4326)" } + - { name: boundary_id, type: text } + - { name: time_span, type: text, default: 'NULL'} + +- name: obs_getboundaryid + return_type: text + params: + - { name: geom, type: "geometry(Geometry, 4326)" } + - { name: boundary_id, type: text } + - { name: time_span, type: text, default: 'NULL'} + +- name: obs_getboundarybyid + return_type: Geometry + params: + - { name: geometry_id, type: text } + - { name: boundary_id, type: text } + - { name: time_span, type: text, default: 'NULL'} + +- name: obs_getboundariesbygeometry + return_type: TABLE(the_geom geometry, geom_refs text) + multi_row: true + multi_field: true + table_fields: + - { name: the_geom, type: geometry } + - { name: geom_refs, type: text } + params: + - { name: geom, type: "geometry(Geometry, 4326)" } + - { name: boundary_id, type: text } + - { name: time_span, type: text, default: 'NULL'} + - { name: overlap_type, type: text, default: "'intersects'"} + +- name: obs_getboundariesbypointandradius + return_type: TABLE(the_geom geometry, geom_refs text) + multi_row: true + multi_field: true + table_fields: + - { name: the_geom, type: geometry } + - { name: geom_refs, type: text } + params: + - { name: geom, type: "geometry(Geometry, 4326)" } + - { name: radius, type: numeric } + - { name: boundary_id, type: text } + - { name: time_span, type: text, default: 'NULL'} + - { name: overlap_type, type: text, default: "'intersects'"} + +- name: obs_getpointsbygeometry + return_type: TABLE(the_geom geometry, geom_refs text) + multi_row: true + multi_field: true + table_fields: + - { name: the_geom, type: geometry } + - { name: geom_refs, type: text } + params: + - { name: geom, type: "geometry(Geometry, 4326)" } + - { name: boundary_id, type: text } + - { name: time_span, type: text, default: 'NULL'} + - { name: overlap_type, type: text, default: "'intersects'"} + +- name: obs_getpointsbypointandradius + return_type: TABLE(the_geom geometry, geom_refs text) + multi_row: true + multi_field: true + table_fields: + - { name: the_geom, type: geometry } + - { name: geom_refs, type: text } + params: + - { name: geom, type: "geometry(Geometry, 4326)" } + - { name: radius, type: numeric } + - { name: boundary_id, type: text } + - { name: time_span, type: text, default: 'NULL'} + - { name: overlap_type, type: text, default: "'intersects'"} + +- name: obs_getmeasure + return_type: numeric + params: + - { name: geom, type: Geometry } + - { name: measure_id, type: text } + - { name: normalize, type: text, default: "'area'"} + - { name: boundary_id, type: text, default: 'NULL' } + - { name: time_span, type: text, default: 'NULL'} + +- name: obs_getcategory + return_type: text + params: + - { name: geom, type: Geometry } + - { name: category_id, type: text } + - { name: boundary_id, type: text, default: 'NULL' } + - { name: time_span, type: text, default: 'NULL'} + +- name: obs_getuscensusmeasure + return_type: numeric + params: + - { name: geom, type: Geometry } + - { name: name, type: text } + - { name: normalize, type: text, default: "'area'"} + - { name: boundary_id, type: text, default: 'NULL' } + - { name: time_span, type: text, default: 'NULL'} + +- name: obs_getuscensuscategory + return_type: text + params: + - { name: geom, type: Geometry } + - { name: name, type: text } + - { name: boundary_id, type: text, default: 'NULL' } + - { name: time_span, type: text, default: 'NULL'} + +- name: obs_getpopulation + return_type: numeric + params: + - { name: geom, type: Geometry } + - { name: normalize, type: text, default: "'area'"} + - { name: boundary_id, type: text, default: 'NULL' } + - { name: time_span, type: text, default: 'NULL'} + +- name: obs_search + return_type: TABLE(id text, description text, name text, aggregate text, source text) + multi_row: true + multi_field: true + table_fields: + - { name: id, type: text } + - { name: description, type: text } + - { name: name, type: text } + - { name: aggregate, type: text } + - { name: source, type: text } + params: + - { name: search_term, type: text } + - { name: relevant_boundary, type: text, default: 'NULL' } + +- name: obs_getavailableboundaries + return_type: TABLE(boundary_id text, description text, time_span text, tablename text) + multi_row: true + multi_field: true + table_fields: + - { name: boundary_id, type: text } + - { name: description, type: text } + - { name: time_span, type: text } + - { name: tablename, type: text } + params: + - { name: geom, type: Geometry } + - { name: timespan, type: text, default: 'NULL'} diff --git a/client/test/expected/90_data_observatory_test.out b/client/test/expected/90_data_observatory_test.out index 44aac0e..5e8f8b2 100644 --- a/client/test/expected/90_data_observatory_test.out +++ b/client/test/expected/90_data_observatory_test.out @@ -21,9 +21,151 @@ BEGIN RETURN ret; END; $$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getdemographicsnapshot (username text, orgname text, geom geometry(Geometry, 4326), time_span text DEFAULT '2009 - 2013', geometry_level text DEFAULT '"us.census.tiger".block_group') +RETURNS json AS $$ +DECLARE + ret json; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getdemographicsnapshot invoked with params (%, %, %, %, %)', username, orgname, geom, time_span, geometry_level; + SELECT '{"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null}'::json INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getsegmentsnapshot (username text, orgname text, geom geometry(Geometry, 4326), geometry_level text DEFAULT '"us.census.tiger".census_tract') +RETURNS json AS $$ +DECLARE + ret json; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getsegmentsnapshot invoked with params (%, %, %, %)', username, orgname, geom, geometry_level; + SELECT '{"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null}'::json INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundary (username text, orgname text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry(Geometry, 4326) AS $$ +DECLARE + ret Geometry; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundary invoked with params (%, %, %, %, %)', username, orgname, geom, boundary_id, time_span; + SELECT '0106000020E6100000010000000103000000010000003500000056EF703B347C52C054FF2092215B44401B9AB2D30F7C52C03FE1ECD6325B4440B14B546F0D7C52C0BBCE86FC335B4440730F09DFFB7B52C0B796C9703C5B4440108FC4CBD37B52C0B96C74CE4F5B444001C0B167CF7B52C0ED0BE8853B5B4440C843DFDDCA7B52C05DDDB1D8265B4440A73D25E7C47B52C0D53BDC0E0D5B4440BB5E9A22C07B52C0F8A3A833F75A4440355F251FBB7B52C0B64604E3E05A444008910C39B67B52C098BF42E6CA5A44405227A089B07B52C0F204C24EB15A444024F1F274AE7B52C069E4F38AA75A44402B4A09C1AA7B52C06B63EC84975A4440E199D024B17B52C0546F0D6C955A44403C873254C57B52C02EAC1BEF8E5A44402593533BC37B52C0588AE42B815A4440973AC8EBC17B52C087890629785A44407A6F0C01C07B52C0E1EB6B5D6A5A44401B9B1DA9BE7B52C03F6F2A52615A444088855AD3BC7B52C088669E5C535A4440E1EA0088BB7B52C0E6E95C514A5A44400CE6AF90B97B52C070D05E7D3C5A44401E85EB51B87B52C0B03A72A4335A4440BAF3C473B67B52C09929ADBF255A4440CD920035B57B52C0454AB3791C5A4440F78DAF3DB37B52C0E09BA6CF0E5A4440DBC2F352B17B52C0703FE081015A444015C440D7BE7B52C05E83BEF4F659444041446ADAC57B52C0EFDFBC38F15944405FB1868BDC7B52C0C03E3A75E559444034BC5983F77B52C0205ED72FD8594440EFFCA204FD7B52C07E384888F25944403ACAC16C027C52C00876FC17085A444056478E74067C52C00FECF82F105A44400FECF82F107C52C0876D8B321B5A4440BB438A01127C52C0DE1CAED51E5A4440B9C15087157C52C034643C4A255A444099F221A81A7C52C0D0EFFB372F5A44404AED45B41D7C52C0785DBF60375A4440373465A71F7C52C065A71FD4455A4440C558A65F227C52C0D80DDB16655A4440F92EA52E197C52C09BA73AE4665A4440DEE522BE137C52C00664AF777F5A44405698BED7107C52C04759BF99985A444012D90759167C52C09430D3F6AF5A444044679945287C52C01F680586AC5A444049F086342A7C52C09CC3B5DAC35A44401FF5D72B2C7C52C0CB811E6ADB5A4440247EC51A2E7C52C0548B8862F25A4440FF59F3E32F7C52C0CB290131095B4440F96871C6307C52C09605137F145B444056EF703B347C52C054FF2092215B4440'::geometry INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundaryid (username text, orgname text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundaryid invoked with params (%, %, %, %, %)', username, orgname, geom, boundary_id, time_span; + SELECT '36047048500'::text INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundarybyid (username text, orgname text, geometry_id text, boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry(Geometry, 4326) AS $$ +DECLARE + ret Geometry; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundarybyid invoked with params (%, %, %, %, %)', username, orgname, geometry_id, boundary_id, time_span; + SELECT '0106000020E610000001000000010300000001000000930200005051F52B9D8352C042B28009DC50444093C2BCC7998352C0E89E758D965144402EFD4B52998352C09A07B0C8AF514440E75086AA988352C022FAB5F5D351444027874F3A918352C0A46B26DF6C53444018E945ED7E8352C04D81CCCEA25344401346B3B27D8352C05D50DF32A753444068226C787A8352C08D25AC8DB153444015C8EC2C7A8352C004560E2DB2534440DF8618AF798352C00FD07D39B3534440FEB627486C8352C0DC9E20B1DD534440B98C9B1A688352C05D328E91EC5344408B8A389D648352C0929048DBF853444075CAA31B618352C0986A662D05544440EA758BC0588352C0D6C397892254444048DFA469508352C0151DC9E53F544440B67F65A5498352C0F73DEAAF575444401403249A408352C05E2A36E6755444402367614F3B8352C06DE2E47E8754444011FC6F253B8352C0431B800D885444403E7958A8358352C0DD0A6135965444401D739EB12F8352C093DFA293A5544440FB04508C2C8352C035289A07B05444401EA4A7C8218352C0347F4C6BD3544440D7C05609168352C05053CBD6FA544440AC8E1CE90C8352C0C9AA083719554440FC8D76DCF08252C0BD18CA897655444048895DDBDB8252C0C3B7B06EBC554440698995D1C88252C032207BBDFB55444004A73E90BC8252C0DB4C857824564440BC1FB75F3E8252C08F368E588B574440E15D2EE23B8252C066F4A3E194574440C614AC71368252C0381268B0A9574440CEA44DD53D8152C04F1F813FFC564440A51133FB3C8152C0F607CA6DFB56444070D05E7D3C8152C0CB0C1B65FD564440C5C6BC8E388152C0F303577902574440EA043411368152C03F390A1005574440840B7904378152C0D34ECDE506574440390A1005338152C047E350BF0B5744405D143DF0318152C0D53BDC0E0D5744401D59F965308152C00A4966F50E574440236420CF2E8152C00FD253E41057444084EE92382B8152C0AD2D3C2F15574440E23D0796238152C0A304FD851E574440B3EDB435228152C001D9EBDD1F5744401EBE4C14218152C08BDCD3D51D574440A2D0B2EE1F8152C0FC1BB4571F57444007B0C8AF1F8152C0CC9717601F574440F678211D1E8152C0374E0AF31E5744401A69A9BC1D8152C0793D98141F574440102384471B8152C0CB2F833122574440B7EEE6A90E8152C09F1D705D315744405968E7340B8152C02C0E677E355744400E4A9869FB8052C0C91EA166485744401B2C9CA4F98052C05C001AA54B5744401AF8510DFB8052C0C51A2E724F574440925CFE43FA8052C0309DD66D50574440BB9866BAD78052C0035DFB027A574440A04FE449D28052C02920ED7F80574440DC9BDF30D18052C0E8305F5E80574440B43C0FEECE8052C0D8614CFA7B5744404AEEB089CC8052C0950A2AAA7E5744409A5B21ACC68052C032FE7DC6855744406682E15CC38052C01EF7ADD689574440F78DAF3DB38052C020CD58349D5744402FFA0AD28C8052C00919C8B3CB574440D0251C7A8B8052C00EA2B5A2CD57444001DE02098A8052C030444E5FCF5744404A404CC2858052C0992A1895D45744403480B740828052C0A33CF372D857444028ECA2E8818052C0CD0358E4D7574440F3AACE6A818052C074ECA012D75744402920ED7F808052C0DFA293A5D657444036E84B6F7F8052C092054CE0D6574440AD4CF8A57E8052C0E55FCB2BD757444042CA4FAA7D8052C01AA19FA9D7574440A2EC2DE57C8052C0205ED72FD8574440BB6246787B8052C08BE07F2BD95744405C74B2D47A8052C025E7C41EDA5744405CA8FC6B798052C0F52EDE8FDB574440FF0758AB768052C09AAF928FDD574440A60A4625758052C0C442AD69DE574440A73E90BC738052C05E49F25CDF574440BF9A0304738052C046ED7E15E0574440A19BFD81728052C070B4E386DF5744403D0AD7A3708052C0D0F0660DDE574440680586AC6E8052C04D469561DC57444063963D096C8052C0965AEF37DA574440944E24986A8052C0BA641C23D957444059501894698052C014B01D8CD8574440E21FB6F4688052C0614D6551D85744401895D409688052C0205ED72FD85744406379573D608052C0A4A487A1D55744401878EE3D5C8052C041B5C189E85744402F4FE78A528052C0A580B4FF01584440983270404B8052C0EECEDA6D1758444050357A35408052C0E3C281902C58444086C43D963E8052C0DC9DB5DB2E584440C5E061DA378052C0BFF2203D455844409946938B318052C0C4E9245B5D5844407C478D09318052C040A374E95F584440E3A8DC442D8052C0F92AF9D85D584440919C4CDC2A8052C06BD26D895C584440276893C3278052C0E9279CDD5A58444053B131AF238052C061C092AB5858444055336B29208052C068E55E605658444091990B5C1E8052C082C64CA25E584440AA2688BA0F8052C027F6D03E56584440F488D1730B8052C0D21C59F9655844400C1CD0D2158052C0BB96900F7A584440C6A69542208052C0B77BB94F8E584440D3A23EC91D8052C02EC901BB9A584440B6BDDD921C8052C0BF42E6CAA058444082E49D43198052C036902E36AD58444072FBE593158052C0ACA92C0ABB5844402B4F20EC148052C0EC3026FDBD584440E4BCFF8F138052C04E266E15C4584440C26856B60F8052C06E15C440D7584440C404357C0B8052C00F5EBBB4E1584440397CD289048052C0CA87A06AF4584440FB761211FE7F52C090F7AA9509594440D93C0E83F97F52C03561FBC9185944402828452BF77F52C0F06DFAB31F594440F9BD4D7FF67F52C0DC9A745B225944403AADDBA0F67F52C0BE4D7FF62359444093C49272F77F52C0526342CC25594440450DA661F87F52C0798EC87729594440F2CCCB61F77F52C0067FBF982D5944409B030473F47F52C017821C94305944401E300F99F27F52C05609168733594440E57FF277EF7F52C0EDBAB72231594440A3AA09A2EE7F52C0EA1ED95C355944405D18E945ED7F52C0D3F6AFAC345944401C5DA5BBEB7F52C076DB85E63A5944404BADF71BED7F52C0B1D991EA3B5944401F477364E57F52C0E48409A35959444022179CC1DF7F52C001D8800871594440A4703D0AD77F52C02EC6C03A8E594440457F68E6C97F52C061C26856B659444070404B57B07F52C0FCDEA63FFB594440DC10E335AF7F52C048E00F3FFF59444055F7C8E6AA7F52C02DB4739A055A4440A4E2FF8EA87F52C00CFFE9060A5A44407E8AE3C0AB7F52C0EC4960730E5A444006F2ECF2AD7F52C08CD99255115A444042588D25AC7F52C09BA8A5B9155A44405A9A5B21AC7F52C0F4BF5C8B165A44406762BA10AB7F52C0A5BA8097195A4440E5B7E864A97F52C0B6BDDD921C5A44402B4A09C1AA7F52C0499F56D11F5A4440D48041D2A77F52C0177FDB13245A4440C22FF5F3A67F52C0D55B035B255A4440FE7BF0DAA57F52C0F8FD9B17275A44409A046F48A37F52C04FADBEBA2A5A444045F12A6B9B7F52C0AC1919E42E5A44404BE2AC889A7F52C0A75CE15D2E5A4440462575029A7F52C0965984622B5A4440E75086AA987F52C0906802452C5A44400B2769FE987F52C05FB01BB62D5A444004029D499B7F52C0DD2230D6375A44404301DBC1887F52C0CBF10A444F5A4440D6A88768747F52C0B81E85EB515A44407C0C569C6A7F52C0F6CFD380415A4440CB113290677F52C0A9328CBB415A44407905A227657F52C03D7C9928425A44407EA5F3E1597F52C0787AA52C435A444009F7CABC557F52C0A2410A9E425A44408D23D6E2537F52C00EF8FC30425A444029780AB9527F52C08B19E1ED415A44402992AF04527F52C08B19E1ED415A4440C51A2E724F7F52C08B19E1ED415A4440AC36FFAF3A7F52C01AA6B6D4415A444009522976347F52C0A2410A9E425A4440F25D4A5D327F52C0252026E1425A44408252B4722F7F52C05A61FA5E435A444032E202D0287F52C013B534B7425A4440E0BBCD1B277F52C014E97E4E415A44409352D0ED257F52C0151DC9E53F5A444022F94A20257F52C0B08BA2073E5A4440CF9ECBD4247F52C0F3AE7AC03C5A444077A1B94E237F52C0F3AE7AC03C5A4440DDB419A7217F52C097FBE428405A4440666A12BC217F52C016A243E0485A44408EACFC32187F52C0CD8DE9094B5A44404F05DCF3FC7E52C0B952CF82505A4440D2E0B6B6F07E52C0FFCA4A93525A44404F029B73F07E52C0A7E7DD58505A4440EA3C2AFEEF7E52C020B41EBE4C5A44404A5F0839EF7E52C01AF7E6374C5A4440D462F030ED7E52C055F5F23B4D5A4440825660C8EA7E52C0B5FD2B2B4D5A4440825660C8EA7E52C072DA53724E5A44403C2CD49AE67E52C030B77BB94F5A44400DDC813AE57E52C0D76B7A50505A4440670DDE57E57E52C0072461DF4E5A4440C77DAB75E27E52C0A25EF0694E5A4440ABB2EF8AE07E52C04F04711E4E5A44403A3FC571E07E52C03C65355D4F5A4440643A747ADE7E52C04ED026874F5A444077F35487DC7E52C08A027D224F5A4440F0A5F0A0D97E52C031EBC5504E5A444068588CBAD67E52C0D8D30E7F4D5A444046B3B27DC87E52C06FB9FAB1495A4440B85A272EC77E52C03C821B295B5A444039CE6DC2BD7E52C097016729595A44409A07B0C8AF7E52C07FD93D79585A44407E8AE3C0AB7E52C0EBC37AA3565A4440C1E10511A97E52C0D097DEFE5C5A44401B82E3326E7E52C03F170D198F5A44408A3C49BA667E52C0D619DF17975A444026DF6C73637E52C07A32FFE89B5A4440E78BBD175F7E52C000FE2955A25A4440594DD7135D7E52C040852348A55A4440E36A64575A7E52C03EE94482A95A4440E603029D497E52C067B62BF4C15A4440ED42739D467E52C04701A260C65A4440253ACB2C427E52C03E40F7E5CC5A4440D026874F3A7E52C061C5A9D6C25A44405C5837DE1D7E52C0868F8829915A4440162EABB0197E52C007B5DFDA895A4440B859BC58187E52C083A279008B5A44408FE046CA167E52C011FB04508C5A4440B131AF230E7E52C0D2C43BC0935A44401A4CC3F0117E52C0F0FACC599F5A44401A321EA5127E52C06631B1F9B85A44402B836A83137E52C0E55C8AABCA5A4440C9737D1F0E7E52C0B376DB85E65A4440D3687231067E52C07405DB88275B444009DE9046057E52C09A94826E2F5B4440158C4AEA047E52C08D7E349C325B4440C808A870047E52C0B6114F76335B4440634337FB037E52C00F290648345B4440DAA7E331037E52C03E7958A8355B444082902C60027E52C0DE3CD521375B4440AB5791D1017E52C048BF7D1D385B4440942F6821017E52C095287B4B395B4440268C6665FB7D52C0548A1D8D435B44405C1B2AC6F97D52C065187783685B4440FA0B3D62F47D52C03FE08101845B4440E2E313B2F37D52C03196E997885B444038F4160FEF7D52C05D50DF32A75B4440109546CCEC7D52C07FDB1324B65B44401C261AA4E07D52C0BA641C23D95B444076BF0AF0DD7D52C06AF7AB00DF5B4440DCB8C5FCDC7D52C0B06F2711E15B44405A0EF450DB7D52C0081F4AB4E45B444084D558C2DA7D52C0F57F0EF3E55B4440BBB20B06D77D52C06E693524EE5B4440CE6BEC12D57D52C0FB592C45F25B444073672618CE7D52C09A0645F3005C4440BB7B80EECB7D52C0C7BAB88D065C4440F5F411F8C37D52C057E9EE3A1B5C44407B8670CCB27D52C09AB4A9BA475C4440240B98C0AD7D52C0282A1BD6545C4440E4839ECDAA7D52C0FA5E43705C5C4440E4805D4D9E7D52C08AAA5FE97C5C44401B2AC6F99B7D52C01C2444F9825C4440D3122BA3917D52C059F8FA5A975C4440A7ACA6EB897D52C0FD2D01F8A75C444007B5DFDA897D52C04818062CB95C44401EF7ADD6897D52C0399A232BBF5C444036397CD2897D52C0904946CEC25C444001DE02098A7D52C08A58C4B0C35C4440CB68E4F38A7D52C0527B116DC75C4440AD4F39268B7D52C0AB92C83EC85C4440531EDD088B7D52C0EB19C231CB5C4440C5C551B9897D52C070EB6E9EEA5C444090847D3B897D52C02E5393E00D5D44409C4CDC2A887D52C01D39D219185D4440FC6EBA65877D52C00D87A5811F5D4440D9CC21A9857D52C0641F6459305D44402D7590D7837D52C0DB4FC6F8305D44409354A698837D52C03FE1ECD6325D44402D5BEB8B847D52C05CC64D0D345D44403A3DEFC6827D52C02C0E677E355D44405299620E827D52C0938C9C853D5D444011AAD4EC817D52C0CE8AA8893E5D44407689EAAD817D52C045BB0A293F5D444094A2957B817D52C02C5F97E13F5D4440EDED96E4807D52C060048D99445D44407C7A6CCB807D52C00551F701485D4440BE69FAEC807D52C0999A046F485D44401781B1BE817D52C0ECF483BA485D444028ECA2E8817D52C0F6D214014E5D44403480B740827D52C07024D060535D4440BD35B055827D52C0CEF8BEB8545D44401C3EE944827D52C03F389F3A565D4440FF243E77827D52C0B534B742585D44407B2C7DE8827D52C02AFD84B35B5D44406F7EC344837D52C0535C55F65D5D4440DA006C40847D52C041F163CC5D5D4440459DB987847D52C0CE15A584605D4440FDBCA948857D52C0F4A44C6A685D44408658FD11867D52C097A608707A5D44404FAF9465887D52C03EC91D36915D4440BD38F1D58E7D52C0CFF753E3A55D44406876DD5B917D52C0F1B6D26BB35D44405B7A34D5937D52C0E4F1B4FCC05D4440B6476FB88F7D52C0C0E78711C25D4440743E3C4B907D52C0A5BBEB6CC85D4440D190F128957D52C03A394371C75D4440ADA06989957D52C0512D228AC95D4440D74D29AF957D52C01BB80375CA5D4440307F85CC957D52C0E542E55FCB5D444042EA76F6957D52C049D40B3ECD5D444054556820967D52C0B3226AA2CF5D44408F6D1970967D52C0C189E8D7D65D4440AD6C1FF2967D52C0F71BEDB8E15D4440BED7101C977D52C0C8B4368DED5D4440D47D00529B7D52C0EBE1CB44115E44403F00A94D9C7D52C068774831405E4440F7393E5A9C7D52C04339D1AE425E44409831056B9C7D52C090A2CEDC435E4440984BAAB69B7D52C02384471B475E4440A547533D997D52C04ED026874F5E44403F170D198F7D52C00E661360585E4440545227A0897D52C0E202D0285D5E4440D3139678407D52C026A435069D5E44406C753925207D52C0CA54C1A8A45E44403B1BF2CF0C7D52C0E17CEA58A55E4440FD12F1D6F97C52C078962023A05E444068C9E369F97C52C0A81ABD1AA05E44406FBA6587F87C52C037A79201A05E44407008556AF67C52C0CC24EA059F5E44404CE141B3EB7C52C0F3FE3F4E985E444003CE52B29C7C52C06C239EEC665E44409AB33EE5987C52C020EEEA55645E4440DFC0E446917C52C0CF6394675E5E444014200A664C7C52C07F315BB22A5E44401D8D43FD2E7C52C0D71533C2DB5D4440C4758C2B2E7C52C09C4B7155D95D4440EE08A7052F7C52C0444B1E4FCB5D444091B6F1272A7C52C0A7069ACFB95D444014C95702297C52C0CC785BE9B55D4440807F4A95287C52C0567C43E1B35D44407405DB88277C52C0A0C4E74EB05D44400057B263237C52C07E39B35DA15D4440AC8BDB68007C52C0AB90F2936A5D444025E4839ECD7B52C0395E81E8495D444018265305A37B52C0C2DCEEE53E5D44402781CD39787B52C0685721E5275D4440514832AB777B52C0639AE95E275D4440F2599E07777B52C0EC6987BF265D4440F94A2025767B52C0B16B7BBB255D44409485AFAF757B52C088D860E1245D4440893F8A3A737B52C09622F94A205D44408D0C7217617B52C0BF5E61C1FD5C444026C286A7577B52C0D3DA34B6D75C4440FCDD3B6A4C7B52C0D0967329AE5C444030630AD6387B52C082C64CA25E5C444081E7DEC3257B52C0A33B889D295C4440639AE95E277B52C0D47FD6FCF85B44407EC34483147B52C03A394371C75B4440342A70B20D7B52C0D826158DB55B444099EFE0270E7B52C06762BA10AB5B4440D3F36E2C287B52C0350873BB975B4440D427B9C3267B52C07842AF3F895B4440C4245CC8237B52C030D7A205685B4440880CAB78237B52C08B8A389D645B4440902E36AD147B52C0718C648F505B4440AF928FDD057B52C05169C4CC3E5B44407E8978EBFC7A52C0FC1BB4571F5B44409DF0129CFA7A52C05D86FF74035B4440DCD8EC48F57A52C044A51133FB5A444027BD6F7CED7A52C0D769A4A5F25A44406B9C4D47007B52C0E4F4F57CCD5A4440F29881CAF87A52C095D233BDC45A44403F19E3C3EC7A52C05BEB8B84B65A44403468E89FE07A52C0DF14562AA85A4440E0F08288D47A52C0224F92AE995A44403448C153C87A52C0B8E34D7E8B5A44401155F833BC7A52C06C91B41B7D5A44401DE6CB0BB07A52C050C3B7B06E5A444029779FE3A37A52C0A568E55E605A44400584D6C3977A52C0889AE8F3515A44401215AA9B8B7A52C0DD3F16A2435A4440EE21E17B7F7A52C0C1711937355A4440B3EC4960737A52C0E692AAED265A4440D7BFEB33677A52C0CAC4AD82185A4440E350BF0B5B7A52C04EEE77280A5A4440CE18E6046D7A52C001FA7DFFE6594440DAA9B9DC607A52C0B5A7E49CD8594440B7B6F0BC547A52C0DAC87553CA594440DB899290487A52C0ED7E15E0BB594440CB0EF10F5B7A52C0239D819197594440A25EF0694E7A52C0B340BB438A594440BBEB6CC83F7A52C092E9D0E9795944407F68E6C9357A52C033C4B12E6E594440205D6C5A297A52C05DA27A6B605944401B834E081D7A52C065AA605452594440765089EB187A52C0A27895B54D5944402A357BA0157A52C07B4D0F0A4A5944408A5759DB147A52C0F2B1BB404959444097530262127A52C0D0436D1B465944409E5E29CB107A52C0ADA1D45E445944400A630B410E7A52C07F85CC9541594440DB12B9E00C7A52C00F46EC134059444000378B170B7A52C039419B1C3E5944408A20CEC3097A52C06AF981AB3C59444080423D7D047A52C0670C738236594440CAA48636007A52C034677DCA31594440BF44BC75FE7952C0A051BAF42F594440605628D2FD7952C077BE9F1A2F59444093AAED26F87952C0DF87838428594440CFF6E80DF77952C033164D672759444011346612F57952C07C2AA73D2559444001310917F27952C0E8482EFF21594440730CC85EEF7952C05567B5C01E594440984A3FE1EC7952C0B6D782DE1B5944404CE141B3EB7952C0570394861A594440C91CCBBBEA7952C00B9A9658195944408E1EBFB7E97952C08EACFC3218594440A794D74AE87952C08FE046CA165944409677D503E67952C0B41EBE4C145944402EC55565DF7952C0E2E995B20C5944408F52094FE87952C09DF0129CFA58444052EC681CEA7952C06326512FF8584440E02D90A0F87952C0739EB12FD9584440519E7939EC7952C05C8DEC4ACB584440938AC6DADF7952C0A5846055BD5844401666A19DD37952C07C08AA46AF58444029CE5147C77952C0B3942C27A1584440B2666490BB7952C0AEEE586C935844404E232D95B77952C0EDF0D7648D584440A4198BA6B37952C0FC6EBA65875844401E34BBEEAD7952C0179B560A81584440A297512CB77952C0289831056B5844400DE02D90A07952C0B3D0CE6916584440789961A3AC7952C0A6D1E4620C58444076FEEDB25F7952C015713AC956574440D50627A25F7952C06072A3C85A574440E7A562635E7952C0E08096AE6057444012876C205D7952C05AD2510E6657444072C3EFA65B7952C0C4EC65DB69574440FCC6D79E597952C0374D9F1D7057444051D7DAFB547952C0554FE61F7D574440658D7A88467952C04F1DAB949E57444008556AF6407952C04A7D59DAA95744406F9C14E63D7952C0A5811FD5B0574440A679C7293A7952C09CC0745AB757444061FBC9181F7952C097A608707A574440B0C91AF5107952C03483F8C08E5744402E36AD14027952C0718BF9B9A1574440D4997B48F87852C089D00836AE574440BBD23252EF7852C090BB085394574440EF8E8CD5E67852C01840F850A2574440EACE13CFD97852C0B6847CD0B35744408C48145AD67852C09012BBB6B7574440E690D442C97852C084B53176C257444063F030ED9B7852C090BA9D7DE5574440DFC0E446917852C0DEE2E13D075844403FFD67CD8F7852C0719010E50B5844401C2785798F7852C0764D486B0C584440B1BE81C98D7852C093FE5E0A0F58444037363B527D7852C0093543AA28584440C3D50110777852C09355116E32584440EEE714E4677852C03387A4164A584440717500C45D7852C07EA5F3E1595844407442E8A04B7852C0E108522976584440211CB3EC497852C0CE35CCD0785844405791D101497852C09D7DE5417A584440CB660E492D7852C0056A3178985844401AC1C6F5EF7752C0B9162D40DB5844400F7C0C569C7752C03EE8D9ACFA584440AC1E300F997752C0828AAA5FE9584440A661F888987752C0C2A38D23D6584440DCBC7152987752C042959A3DD0584440A661F888987752C0302AA913D0584440E7FF55478E7752C05DC2A1B7785844402FFA0AD28C7752C0581CCEFC6A584440DCB930D28B7752C021567F8461584440FB20CB82897752C062D7F6764B58444079909E22877752C0D89942E7355844408C63247B847752C0B58993FB1D584440ACE46377817752C0677E350708584440C6C210397D7752C0B2F4A10BEA57444074B680D07A7752C0909DB7B1D9574440DB317557767752C0077767EDB65744409A7631CD747752C02D7B12D89C5744400D6C9560717752C054FEB5BC72574440FC34EECD6F7752C0A3E6ABE4635744409E7AA4C16D7752C0D1949D7E50574440FE9C82FC6C7752C0E046CA16495744401E4FCB0F5C7752C09B53C90050574440D503E621537752C0E063B0E25457444037DC476E4D7752C032569BFF5757444070ED4449487752C0836C59BE2E57444066F50EB7437752C054C554FA0957444032022A1C417752C0713C9F01F55644404487C091407752C01F7EFE7BF05644406E4E2503407752C05D4C33DDEB56444088F546AD307752C03ECBF3E0EE5644401F0F7D772B7752C04835ECF7C4564440A33B889D297752C026AAB706B656444087A4164A267752C0938E72309B5644403B6F63B3237752C050FD834886564440D7F7E120217752C00D6C956071564440132A38BC207752C07A8A1C226E564440315D88D51F7752C07E8E8F1667564440D4F02DAC1B7752C0ADA415DF505644409E95B4E21B7752C09AE8F35146564440B88D06F0167752C0BB46CB811E564440A435069D107752C0C8E88024EC554440C9703C9F017752C0F01307D0EF55444083DE1B43007752C0855D143DF05544404EB4AB90F27652C0A69718CBF45544401ABE8575E37652C0C214E5D2F855444041649126DE7652C0FACE2F4AD0554440293C6876DD7652C0807D74EACA554440FAD170CADC7652C0779FE3A3C55544403FABCC94D67652C0F58079C8945544405AD76839D07652C0B41D537765554440849ECDAACF7652C0272D5C56615544405DA79196CA7652C0D87F9D9B36554440331477BCC97652C06A10E6762F55444060AB048BC37652C062F20698F95444402D23F59ECA7652C05D6919A9F754444011C30E63D27652C0B8E864A9F554444021C9ACDEE17652C073D87DC7F0544440F0F96184F07652C06FB72407EC5444408577B988EF7652C0DFA5D425E3544440A089B0E1E97652C0C8091346B35444403621AD31E87652C0999CDA19A6544440C763062AE37652C0EF3B86C77E5444401F4AB4E4F17652C0E0D4079277544440E2E65432007752C054E4107173544440FF0241800C7752C061FA5E437054444057B26323107752C0F677B6476F5444402026E1421E7752C00FEB8D5A61544440834F73F2227752C0E3361AC05B544440C2F693313E7752C0C05AB56B4254444097900F7A367752C0780C8FFD2C544440F834272F327752C06684B70721544440C4758C2B2E7752C03D0801F9125444408D959867257752C00E4A9869FB534440E68F696D1A7752C02FF99FFCDD53444022C2BF081A7752C0247F30F0DC534440EF1CCA50157752C03599F1B6D2534440C0B2D2A4147752C06551D845D15344409048DBF8137752C09509BFD4CF53444014419C87137752C0FB027AE1CE534440E5F04927127752C01A84B9DDCB53444092B06F27117752C0DAC87553CA5344407EA65EB7087752C0228C9FC6BD534440A3E4D539067752C065170CAEB9534440C2FA3F87F97652C059F5B9DA8A5344408BFA2477D87652C082A62556465344406403E962D37652C03197546D3753444018B49080D17652C0D5928E72305344404A22FB20CB7652C0765089EB185344402A1900AAB87652C0BE0F070951524440E386DF4DB77652C01F63EE5A425244400F7D772B4B7652C005A568E55E524440FB3F87F9F27552C07D224F92AE5144405793A7ACA67552C0D7C0560916514440BEDA519CA37552C0A44FABE80F514440745B22179C7552C0E2CCAFE600514440DCD6169E977552C00B43E4F4F5504440A93121E6927552C05E807D74EA504440D13FC1C58A7552C056ED9A90D6504440096B63EC847552C0AB92C83EC8504440AE80423D7D7552C04127840EBA50444040F7E5CC767552C0D0967329AE50444089CE328B507552C0162D40DB6A504440C8ED974F567552C05646239F57504440211FF46C567552C03674B33F5050444015713AC9567552C059DC7F643A5044404AB20E47577552C028B682A62550444037AB3E575B7552C0F7AE415F7A4F44408D261763607552C0226C787AA54E444045460724617552C0A94885B1854E4440F62686E4647552C02D978DCEF94D444036AE7FD7677552C018AE0E80B84D4440B9E00CFE7E7552C0B01F6283854D4440446B459BE37552C0C5E23785954C444012A27C410B7652C03C1405FA444C4440588B4F01307652C0B058C345EE4B4440A6457D923B7652C07C28D192C74B44402C9CA4F9637652C0A2957B81594B4440A81ABD1AA07652C0300C5872154B4440FBC8AD49B77652C035272F32014B44404127840EBA7652C02AE109BDFE4A44401DCBBBEA017752C02172FA7ABE4A4440130CE71A667752C0C6A2E9EC644A44400A4B3CA06C7752C0BEF8A23D5E4A4440A5D93C0E837752C06473D53C474A4440FDBCA948857752C06B98A1F1444A4440F0C000C2877752C0F0DE5163424A4440D8817346947752C04450357A354A4440BF28417FA17752C08099EFE0274A44400A2DEBFEB17752C0BCAE5FB01B4A44407FF8F9EFC17752C08C0DDDEC0F4A444053C90050C57752C0B14B546F0D4A44402E71E481C87752C0BF61A2410A4A44401EFB592C457852C09F39EB538E494440056D72F8A47852C06D8E739B7049444036AD1402B97852C0D68BA19C68494440F59F353FFE7852C0BAA0BE654E494440289A07B0C87952C0C58F31772D4944406133C005D97952C0D862B7CF2A494440E1783E03EA7952C04DDA54DD2349444046B3B27DC87A52C06A11514CDE4844402F185C73477B52C0FCE25295B6484440A26131EA5A7B52C06A696E85B04844408499B67F657B52C036902E36AD4844404F8F6D19707B52C0C1C760C5A94844402E1D739EB17B52C02BDCF29194484440F9122A38BC7B52C0B5132521914844401021AE9CBD7B52C080D250A39048444081CEA44DD57B52C0431B800D88484440BBB88D06F07B52C076A38FF980484440B5A50EF27A7C52C07780272D5C484440F7C77BD5CA7C52C08AE5965643484440614D6551D87C52C05CFDD8243F484440E84CDA54DD7C52C03F1878EE3D4844409947FE60E07C52C05774EB353D484440AF0793E2E37C52C0FF5C34643C48444065A54929E87C52C0C45E28603B484440EFAB72A1F27C52C01F12BEF737484440D07D39B35D7D52C0075F984C1548444025AB22DC647D52C03D0801F912484440C39E76F86B7D52C0861C5BCF104844401211FE45D07F52C0F2CEA10C55474440B804E09F528252C0785C548B884644407615527E528252C0DB85E63A8D464440E2E5E95C518252C0BB270F0BB546444089B48D3F518252C0A7203F1BB94644400858AB764D8252C0F294D5743D474440CD565EF23F8252C07D7555A0164944401B28F04E3E8252C0E9F010C64F494440AAB4C5353E8252C0BDC117265349444032CB9E04368252C0F6285C8FC24944405111A7936C8252C09FE238F06A4B44402252D32EA68252C0BC02D193324D44404C50C3B7B08252C0F9F36DC1524D444068075C57CC8252C0ECDCB419A74D4440A31F0DA7CC8252C086E3F90CA84D44409D2E8B89CD8252C0438CD7BCAA4D44402BA1BB24CE8252C00726378AAC4D4440DDE9CE13CF8252C035423F53AF4D4440A774B0FECF8252C0C266800BB24D4440A626C11BD28252C007431D56B84D4440EDD286C3D28252C0DC476E4DBA4D44402638F581E48252C04A5F0839EF4D444074779D0DF98252C0E3C281902C4E4440890629780A8352C016DC0F78604E44408315A75A0B8352C0E5EFDE51634E4440EA793716148352C036E84B6F7F4E44404703780B248352C0C24CDBBFB24E44403046240A2D8352C09BE09BA6CF4E4440A4C00298328352C02D776682E14E444055F833BC598352C09F91088D604F4440B3B27DC85B8352C08922A46E674F444075E789E76C8352C066118AADA04F44400D52F014728352C051F355F2B14F4440C5ABAC6D8A8352C0D4D00660035044403D7E6FD39F8352C05C1ABFF04A5044405051F52B9D8352C042B28009DC504440'::geometry INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundariesbypointandradius (username text, orgname text, geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundariesbypointandradius invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, radius, boundary_id, time_span, overlap_type; + RETURN QUERY SELECT '0106000020E6100000010000000103000000010000001500000083A3E4D5397C52C09946938B315A44404AED45B41D7C52C0785DBF60375A444099F221A81A7C52C0D0EFFB372F5A4440B9C15087157C52C034643C4A255A4440BB438A01127C52C0DE1CAED51E5A44400FECF82F107C52C0876D8B321B5A4440510FD1E80E7C52C0C4D32B65195A44407FDAA84E077C52C0E0675C38105A444092AD2EA7047C52C08E75711B0D5A4440CF2D7425027C52C0A86DC328085A4440EFFCA204FD7B52C07E384888F259444034BC5983F77B52C0205ED72FD8594440E76F4221027C52C0F3A96395D259444081AD122C0E7C52C00ED6FF39CC594440CB63CDC8207C52C031276893C359444047205ED72F7C52C0287D21E4BC594440BD1C76DF317C52C0F8325184D4594440CD1FD3DA347C52C0B0A9F3A8F8594440C72E51BD357C52C0C3651536035A444043024697377C52C028999CDA195A444083A3E4D5397C52C09946938B315A4440'::geometry as the_geom, '36047048900'::text as geom_refs; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getpointsbygeometry (username text, orgname text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getpointsbygeometry invoked with params (%, %, %, %, %, %)', username, orgname, geom, boundary_id, time_span, overlap_type; + RETURN QUERY SELECT '0101000020E610000037CB75821A7C52C0BA8784EFFD594440'::geometry as the_geom, '36047048900'::text as geom_refs; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getpointsbypointandradius (username text, orgname text, geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getpointsbypointandradius invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, radius, boundary_id, time_span, overlap_type; + RETURN QUERY SELECT '0101000020E610000037CB75821A7C52C0BA8784EFFD594440'::geometry as the_geom, '36047048900'::text as geom_refs; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getmeasure (username text, orgname text, geom Geometry, measure_id text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getmeasure invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, measure_id, normalize, boundary_id, time_span; + SELECT 10923.093200390833950::numeric INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getcategory (username text, orgname text, geom Geometry, category_id text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getcategory invoked with params (%, %, %, %, %, %)', username, orgname, geom, category_id, boundary_id, time_span; + SELECT 'Wealthy, urban without Kids'::text INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getuscensusmeasure (username text, orgname text, geom Geometry, name text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getuscensusmeasure invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, name, normalize, boundary_id, time_span; + SELECT 6789.5647735060920500::numeric INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getuscensuscategory (username text, orgname text, geom Geometry, name text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getuscensuscategory invoked with params (%, %, %, %, %, %)', username, orgname, geom, name, boundary_id, time_span; + SELECT 'Wealthy, urban without Kids'::text INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getpopulation (username text, orgname text, geom Geometry, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getpopulation invoked with params (%, %, %, %, %, %)', username, orgname, geom, normalize, boundary_id, time_span; + SELECT 10923.093200390833950::numeric INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_search (username text, orgname text, search_term text, relevant_boundary text DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_search invoked with params (%, %, %, %)', username, orgname, search_term, relevant_boundary; + RETURN QUERY SELECT 'es.ine.total_pop'::text as id, 'The total number of all people living in a geographic area.'::text as description, 'Total Population'::text as name, 'sum'::text as aggregate, NULL::text as source; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getavailableboundaries (username text, orgname text, geom geometry(Geometry, 4326), timespan text DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getavailableboundaries invoked with params (%, %, %, %)', username, orgname, geom, timespan; + RETURN QUERY SELECT 'us.census.tiger.place'::text as boundary_id, 'Incorporated places are those reported to the Census Bureau as legally in existence as of January 1, 2010, as reported in the latest Boundary and Annexation Survey (BAS), under the laws of their respective states.'::text as description, '2014'::text as timespan, 'obs_7c9493c41fa8f4bd178ab993ea3d5891c1977667'::text as tablename; +END; +$$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundariesbygeometry (username text, orgname text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundariesbygeometry invoked with params (%, %, %, %, %, %)', username, orgname, geom, boundary_id, time_span, overlap_type; + RETURN QUERY SELECT '0106000020E61000000100000001030000000100000019000000DD96C805677C52C0CBD8D0CDFE5A44407A19C5724B7C52C033BF9A03045B4440FF59F3E32F7C52C0CB290131095B4440247EC51A2E7C52C0548B8862F25A44401FF5D72B2C7C52C0CB811E6ADB5A444049F086342A7C52C09CC3B5DAC35A444044679945287C52C01F680586AC5A444012D90759167C52C09430D3F6AF5A44405698BED7107C52C04759BF99985A4440DEE522BE137C52C00664AF777F5A4440F92EA52E197C52C09BA73AE4665A4440C558A65F227C52C0D80DDB16655A4440373465A71F7C52C065A71FD4455A44404AED45B41D7C52C0785DBF60375A444083A3E4D5397C52C09946938B315A4440F2B4FCC0557C52C01FF5D72B2C5A444026C286A7577C52C02BDD5D67435A44405BCF108E597C52C0C651B9895A5A444030D461855B7C52C0D1393FC5715A444065E1EB6B5D7C52C078280AF4895A44403AE63C635F7C52C07D1F0E12A25A44403F6F2A52617C52C05983F755B95A44405C3AE63C637C52C04852D2C3D05A444049810530657C52C0FAEE5696E85A4440DD96C805677C52C0CBD8D0CDFE5A4440'::geometry as the_geom, '36047049300'::text as geom_refs; +END; +$$ LANGUAGE 'plpgsql'; -- Exercise the public and the proxied function -SELECT obs_get_demographic_snapshot('POINT(-87.81406 41.89308)'::geometry); -NOTICE: cdb_dataservices_client._obs_get_demographic_snapshot(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_get_demographic_snapshot invoked with params (test_user, , 0101000000D53E1D8F19F455C0185B087250F24440, 2009 - 2013, "us.census.tiger".block_group) +SELECT obs_get_demographic_snapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '2009 - 2013'::text, '"us.census.tiger".block_group'::text); +NOTICE: cdb_dataservices_client._obs_get_demographic_snapshot(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_get_demographic_snapshot invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, 2009 - 2013, "us.census.tiger".block_group) CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_get_demographic_snapshot(username, orgname, geom, time_span, geometry_level)" PL/pgSQL function obs_get_demographic_snapshot(geometry,text,text) line 16 at SQL statement obs_get_demographic_snapshot @@ -31,8 +173,8 @@ PL/pgSQL function obs_get_demographic_snapshot(geometry,text,text) line 16 at SQ {"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null} (1 row) -SELECT obs_get_segment_snapshot('POINT(-87.81406 41.89308)'::geometry); -NOTICE: cdb_dataservices_client._obs_get_segment_snapshot(4): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_get_segment_snapshot invoked with params (test_user, , 0101000000D53E1D8F19F455C0185B087250F24440, "us.census.tiger".census_tract) +SELECT obs_get_segment_snapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '"us.census.tiger".block_group'::text); +NOTICE: cdb_dataservices_client._obs_get_segment_snapshot(4): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_get_segment_snapshot invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, "us.census.tiger".block_group) CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_get_segment_snapshot(username, orgname, geom, geometry_level)" PL/pgSQL function obs_get_segment_snapshot(geometry,text) line 16 at SQL statement obs_get_segment_snapshot @@ -40,3 +182,141 @@ PL/pgSQL function obs_get_segment_snapshot(geometry,text) line 16 at SQL stateme {"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null} (1 row) +SELECT obs_getdemographicsnapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '2009 - 2013', '"us.census.tiger".block_group'::text); +NOTICE: cdb_dataservices_client._obs_getdemographicsnapshot(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getdemographicsnapshot invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, 2009 - 2013, "us.census.tiger".block_group) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getdemographicsnapshot(username, orgname, geom, time_span, geometry_level)" +PL/pgSQL function obs_getdemographicsnapshot(geometry,text,text) line 16 at SQL statement + obs_getdemographicsnapshot +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null} +(1 row) + +SELECT obs_getsegmentsnapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '"us.census.tiger".block_group'::text); +NOTICE: cdb_dataservices_client._obs_getsegmentsnapshot(4): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getsegmentsnapshot invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, "us.census.tiger".block_group) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getsegmentsnapshot(username, orgname, geom, geometry_level)" +PL/pgSQL function obs_getsegmentsnapshot(geometry,text) line 16 at SQL statement + obs_getsegmentsnapshot +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null} +(1 row) + +SELECT obs_getboundary(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'us.census.tiger.census_tract'::text); +NOTICE: cdb_dataservices_client._obs_getboundary(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getboundary invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, us.census.tiger.census_tract, ) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getboundary(username, orgname, geom, boundary_id, time_span)" +PL/pgSQL function obs_getboundary(geometry,text,text) line 16 at SQL statement + obs_getboundary +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 0106000020E6100000010000000103000000010000003500000056EF703B347C52C054FF2092215B44401B9AB2D30F7C52C03FE1ECD6325B4440B14B546F0D7C52C0BBCE86FC335B4440730F09DFFB7B52C0B796C9703C5B4440108FC4CBD37B52C0B96C74CE4F5B444001C0B167CF7B52C0ED0BE8853B5B4440C843DFDDCA7B52C05DDDB1D8265B4440A73D25E7C47B52C0D53BDC0E0D5B4440BB5E9A22C07B52C0F8A3A833F75A4440355F251FBB7B52C0B64604E3E05A444008910C39B67B52C098BF42E6CA5A44405227A089B07B52C0F204C24EB15A444024F1F274AE7B52C069E4F38AA75A44402B4A09C1AA7B52C06B63EC84975A4440E199D024B17B52C0546F0D6C955A44403C873254C57B52C02EAC1BEF8E5A44402593533BC37B52C0588AE42B815A4440973AC8EBC17B52C087890629785A44407A6F0C01C07B52C0E1EB6B5D6A5A44401B9B1DA9BE7B52C03F6F2A52615A444088855AD3BC7B52C088669E5C535A4440E1EA0088BB7B52C0E6E95C514A5A44400CE6AF90B97B52C070D05E7D3C5A44401E85EB51B87B52C0B03A72A4335A4440BAF3C473B67B52C09929ADBF255A4440CD920035B57B52C0454AB3791C5A4440F78DAF3DB37B52C0E09BA6CF0E5A4440DBC2F352B17B52C0703FE081015A444015C440D7BE7B52C05E83BEF4F659444041446ADAC57B52C0EFDFBC38F15944405FB1868BDC7B52C0C03E3A75E559444034BC5983F77B52C0205ED72FD8594440EFFCA204FD7B52C07E384888F25944403ACAC16C027C52C00876FC17085A444056478E74067C52C00FECF82F105A44400FECF82F107C52C0876D8B321B5A4440BB438A01127C52C0DE1CAED51E5A4440B9C15087157C52C034643C4A255A444099F221A81A7C52C0D0EFFB372F5A44404AED45B41D7C52C0785DBF60375A4440373465A71F7C52C065A71FD4455A4440C558A65F227C52C0D80DDB16655A4440F92EA52E197C52C09BA73AE4665A4440DEE522BE137C52C00664AF777F5A44405698BED7107C52C04759BF99985A444012D90759167C52C09430D3F6AF5A444044679945287C52C01F680586AC5A444049F086342A7C52C09CC3B5DAC35A44401FF5D72B2C7C52C0CB811E6ADB5A4440247EC51A2E7C52C0548B8862F25A4440FF59F3E32F7C52C0CB290131095B4440F96871C6307C52C09605137F145B444056EF703B347C52C054FF2092215B4440 +(1 row) + +SELECT obs_getboundaryid(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'us.census.tiger.census_tract'::text); +NOTICE: cdb_dataservices_client._obs_getboundaryid(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getboundaryid invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, us.census.tiger.census_tract, ) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getboundaryid(username, orgname, geom, boundary_id, time_span)" +PL/pgSQL function obs_getboundaryid(geometry,text,text) line 16 at SQL statement + obs_getboundaryid +------------------- + 36047048500 +(1 row) + +SELECT obs_getboundarybyid('36047'::text, 'us.census.tiger.county'::text); +NOTICE: cdb_dataservices_client._obs_getboundarybyid(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getboundarybyid invoked with params (test_user, , 36047, us.census.tiger.county, ) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getboundarybyid(username, orgname, geometry_id, boundary_id, time_span)" +PL/pgSQL function obs_getboundarybyid(text,text,text) line 16 at SQL statement + obs_getboundarybyid +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 0106000020E610000001000000010300000001000000930200005051F52B9D8352C042B28009DC50444093C2BCC7998352C0E89E758D965144402EFD4B52998352C09A07B0C8AF514440E75086AA988352C022FAB5F5D351444027874F3A918352C0A46B26DF6C53444018E945ED7E8352C04D81CCCEA25344401346B3B27D8352C05D50DF32A753444068226C787A8352C08D25AC8DB153444015C8EC2C7A8352C004560E2DB2534440DF8618AF798352C00FD07D39B3534440FEB627486C8352C0DC9E20B1DD534440B98C9B1A688352C05D328E91EC5344408B8A389D648352C0929048DBF853444075CAA31B618352C0986A662D05544440EA758BC0588352C0D6C397892254444048DFA469508352C0151DC9E53F544440B67F65A5498352C0F73DEAAF575444401403249A408352C05E2A36E6755444402367614F3B8352C06DE2E47E8754444011FC6F253B8352C0431B800D885444403E7958A8358352C0DD0A6135965444401D739EB12F8352C093DFA293A5544440FB04508C2C8352C035289A07B05444401EA4A7C8218352C0347F4C6BD3544440D7C05609168352C05053CBD6FA544440AC8E1CE90C8352C0C9AA083719554440FC8D76DCF08252C0BD18CA897655444048895DDBDB8252C0C3B7B06EBC554440698995D1C88252C032207BBDFB55444004A73E90BC8252C0DB4C857824564440BC1FB75F3E8252C08F368E588B574440E15D2EE23B8252C066F4A3E194574440C614AC71368252C0381268B0A9574440CEA44DD53D8152C04F1F813FFC564440A51133FB3C8152C0F607CA6DFB56444070D05E7D3C8152C0CB0C1B65FD564440C5C6BC8E388152C0F303577902574440EA043411368152C03F390A1005574440840B7904378152C0D34ECDE506574440390A1005338152C047E350BF0B5744405D143DF0318152C0D53BDC0E0D5744401D59F965308152C00A4966F50E574440236420CF2E8152C00FD253E41057444084EE92382B8152C0AD2D3C2F15574440E23D0796238152C0A304FD851E574440B3EDB435228152C001D9EBDD1F5744401EBE4C14218152C08BDCD3D51D574440A2D0B2EE1F8152C0FC1BB4571F57444007B0C8AF1F8152C0CC9717601F574440F678211D1E8152C0374E0AF31E5744401A69A9BC1D8152C0793D98141F574440102384471B8152C0CB2F833122574440B7EEE6A90E8152C09F1D705D315744405968E7340B8152C02C0E677E355744400E4A9869FB8052C0C91EA166485744401B2C9CA4F98052C05C001AA54B5744401AF8510DFB8052C0C51A2E724F574440925CFE43FA8052C0309DD66D50574440BB9866BAD78052C0035DFB027A574440A04FE449D28052C02920ED7F80574440DC9BDF30D18052C0E8305F5E80574440B43C0FEECE8052C0D8614CFA7B5744404AEEB089CC8052C0950A2AAA7E5744409A5B21ACC68052C032FE7DC6855744406682E15CC38052C01EF7ADD689574440F78DAF3DB38052C020CD58349D5744402FFA0AD28C8052C00919C8B3CB574440D0251C7A8B8052C00EA2B5A2CD57444001DE02098A8052C030444E5FCF5744404A404CC2858052C0992A1895D45744403480B740828052C0A33CF372D857444028ECA2E8818052C0CD0358E4D7574440F3AACE6A818052C074ECA012D75744402920ED7F808052C0DFA293A5D657444036E84B6F7F8052C092054CE0D6574440AD4CF8A57E8052C0E55FCB2BD757444042CA4FAA7D8052C01AA19FA9D7574440A2EC2DE57C8052C0205ED72FD8574440BB6246787B8052C08BE07F2BD95744405C74B2D47A8052C025E7C41EDA5744405CA8FC6B798052C0F52EDE8FDB574440FF0758AB768052C09AAF928FDD574440A60A4625758052C0C442AD69DE574440A73E90BC738052C05E49F25CDF574440BF9A0304738052C046ED7E15E0574440A19BFD81728052C070B4E386DF5744403D0AD7A3708052C0D0F0660DDE574440680586AC6E8052C04D469561DC57444063963D096C8052C0965AEF37DA574440944E24986A8052C0BA641C23D957444059501894698052C014B01D8CD8574440E21FB6F4688052C0614D6551D85744401895D409688052C0205ED72FD85744406379573D608052C0A4A487A1D55744401878EE3D5C8052C041B5C189E85744402F4FE78A528052C0A580B4FF01584440983270404B8052C0EECEDA6D1758444050357A35408052C0E3C281902C58444086C43D963E8052C0DC9DB5DB2E584440C5E061DA378052C0BFF2203D455844409946938B318052C0C4E9245B5D5844407C478D09318052C040A374E95F584440E3A8DC442D8052C0F92AF9D85D584440919C4CDC2A8052C06BD26D895C584440276893C3278052C0E9279CDD5A58444053B131AF238052C061C092AB5858444055336B29208052C068E55E605658444091990B5C1E8052C082C64CA25E584440AA2688BA0F8052C027F6D03E56584440F488D1730B8052C0D21C59F9655844400C1CD0D2158052C0BB96900F7A584440C6A69542208052C0B77BB94F8E584440D3A23EC91D8052C02EC901BB9A584440B6BDDD921C8052C0BF42E6CAA058444082E49D43198052C036902E36AD58444072FBE593158052C0ACA92C0ABB5844402B4F20EC148052C0EC3026FDBD584440E4BCFF8F138052C04E266E15C4584440C26856B60F8052C06E15C440D7584440C404357C0B8052C00F5EBBB4E1584440397CD289048052C0CA87A06AF4584440FB761211FE7F52C090F7AA9509594440D93C0E83F97F52C03561FBC9185944402828452BF77F52C0F06DFAB31F594440F9BD4D7FF67F52C0DC9A745B225944403AADDBA0F67F52C0BE4D7FF62359444093C49272F77F52C0526342CC25594440450DA661F87F52C0798EC87729594440F2CCCB61F77F52C0067FBF982D5944409B030473F47F52C017821C94305944401E300F99F27F52C05609168733594440E57FF277EF7F52C0EDBAB72231594440A3AA09A2EE7F52C0EA1ED95C355944405D18E945ED7F52C0D3F6AFAC345944401C5DA5BBEB7F52C076DB85E63A5944404BADF71BED7F52C0B1D991EA3B5944401F477364E57F52C0E48409A35959444022179CC1DF7F52C001D8800871594440A4703D0AD77F52C02EC6C03A8E594440457F68E6C97F52C061C26856B659444070404B57B07F52C0FCDEA63FFB594440DC10E335AF7F52C048E00F3FFF59444055F7C8E6AA7F52C02DB4739A055A4440A4E2FF8EA87F52C00CFFE9060A5A44407E8AE3C0AB7F52C0EC4960730E5A444006F2ECF2AD7F52C08CD99255115A444042588D25AC7F52C09BA8A5B9155A44405A9A5B21AC7F52C0F4BF5C8B165A44406762BA10AB7F52C0A5BA8097195A4440E5B7E864A97F52C0B6BDDD921C5A44402B4A09C1AA7F52C0499F56D11F5A4440D48041D2A77F52C0177FDB13245A4440C22FF5F3A67F52C0D55B035B255A4440FE7BF0DAA57F52C0F8FD9B17275A44409A046F48A37F52C04FADBEBA2A5A444045F12A6B9B7F52C0AC1919E42E5A44404BE2AC889A7F52C0A75CE15D2E5A4440462575029A7F52C0965984622B5A4440E75086AA987F52C0906802452C5A44400B2769FE987F52C05FB01BB62D5A444004029D499B7F52C0DD2230D6375A44404301DBC1887F52C0CBF10A444F5A4440D6A88768747F52C0B81E85EB515A44407C0C569C6A7F52C0F6CFD380415A4440CB113290677F52C0A9328CBB415A44407905A227657F52C03D7C9928425A44407EA5F3E1597F52C0787AA52C435A444009F7CABC557F52C0A2410A9E425A44408D23D6E2537F52C00EF8FC30425A444029780AB9527F52C08B19E1ED415A44402992AF04527F52C08B19E1ED415A4440C51A2E724F7F52C08B19E1ED415A4440AC36FFAF3A7F52C01AA6B6D4415A444009522976347F52C0A2410A9E425A4440F25D4A5D327F52C0252026E1425A44408252B4722F7F52C05A61FA5E435A444032E202D0287F52C013B534B7425A4440E0BBCD1B277F52C014E97E4E415A44409352D0ED257F52C0151DC9E53F5A444022F94A20257F52C0B08BA2073E5A4440CF9ECBD4247F52C0F3AE7AC03C5A444077A1B94E237F52C0F3AE7AC03C5A4440DDB419A7217F52C097FBE428405A4440666A12BC217F52C016A243E0485A44408EACFC32187F52C0CD8DE9094B5A44404F05DCF3FC7E52C0B952CF82505A4440D2E0B6B6F07E52C0FFCA4A93525A44404F029B73F07E52C0A7E7DD58505A4440EA3C2AFEEF7E52C020B41EBE4C5A44404A5F0839EF7E52C01AF7E6374C5A4440D462F030ED7E52C055F5F23B4D5A4440825660C8EA7E52C0B5FD2B2B4D5A4440825660C8EA7E52C072DA53724E5A44403C2CD49AE67E52C030B77BB94F5A44400DDC813AE57E52C0D76B7A50505A4440670DDE57E57E52C0072461DF4E5A4440C77DAB75E27E52C0A25EF0694E5A4440ABB2EF8AE07E52C04F04711E4E5A44403A3FC571E07E52C03C65355D4F5A4440643A747ADE7E52C04ED026874F5A444077F35487DC7E52C08A027D224F5A4440F0A5F0A0D97E52C031EBC5504E5A444068588CBAD67E52C0D8D30E7F4D5A444046B3B27DC87E52C06FB9FAB1495A4440B85A272EC77E52C03C821B295B5A444039CE6DC2BD7E52C097016729595A44409A07B0C8AF7E52C07FD93D79585A44407E8AE3C0AB7E52C0EBC37AA3565A4440C1E10511A97E52C0D097DEFE5C5A44401B82E3326E7E52C03F170D198F5A44408A3C49BA667E52C0D619DF17975A444026DF6C73637E52C07A32FFE89B5A4440E78BBD175F7E52C000FE2955A25A4440594DD7135D7E52C040852348A55A4440E36A64575A7E52C03EE94482A95A4440E603029D497E52C067B62BF4C15A4440ED42739D467E52C04701A260C65A4440253ACB2C427E52C03E40F7E5CC5A4440D026874F3A7E52C061C5A9D6C25A44405C5837DE1D7E52C0868F8829915A4440162EABB0197E52C007B5DFDA895A4440B859BC58187E52C083A279008B5A44408FE046CA167E52C011FB04508C5A4440B131AF230E7E52C0D2C43BC0935A44401A4CC3F0117E52C0F0FACC599F5A44401A321EA5127E52C06631B1F9B85A44402B836A83137E52C0E55C8AABCA5A4440C9737D1F0E7E52C0B376DB85E65A4440D3687231067E52C07405DB88275B444009DE9046057E52C09A94826E2F5B4440158C4AEA047E52C08D7E349C325B4440C808A870047E52C0B6114F76335B4440634337FB037E52C00F290648345B4440DAA7E331037E52C03E7958A8355B444082902C60027E52C0DE3CD521375B4440AB5791D1017E52C048BF7D1D385B4440942F6821017E52C095287B4B395B4440268C6665FB7D52C0548A1D8D435B44405C1B2AC6F97D52C065187783685B4440FA0B3D62F47D52C03FE08101845B4440E2E313B2F37D52C03196E997885B444038F4160FEF7D52C05D50DF32A75B4440109546CCEC7D52C07FDB1324B65B44401C261AA4E07D52C0BA641C23D95B444076BF0AF0DD7D52C06AF7AB00DF5B4440DCB8C5FCDC7D52C0B06F2711E15B44405A0EF450DB7D52C0081F4AB4E45B444084D558C2DA7D52C0F57F0EF3E55B4440BBB20B06D77D52C06E693524EE5B4440CE6BEC12D57D52C0FB592C45F25B444073672618CE7D52C09A0645F3005C4440BB7B80EECB7D52C0C7BAB88D065C4440F5F411F8C37D52C057E9EE3A1B5C44407B8670CCB27D52C09AB4A9BA475C4440240B98C0AD7D52C0282A1BD6545C4440E4839ECDAA7D52C0FA5E43705C5C4440E4805D4D9E7D52C08AAA5FE97C5C44401B2AC6F99B7D52C01C2444F9825C4440D3122BA3917D52C059F8FA5A975C4440A7ACA6EB897D52C0FD2D01F8A75C444007B5DFDA897D52C04818062CB95C44401EF7ADD6897D52C0399A232BBF5C444036397CD2897D52C0904946CEC25C444001DE02098A7D52C08A58C4B0C35C4440CB68E4F38A7D52C0527B116DC75C4440AD4F39268B7D52C0AB92C83EC85C4440531EDD088B7D52C0EB19C231CB5C4440C5C551B9897D52C070EB6E9EEA5C444090847D3B897D52C02E5393E00D5D44409C4CDC2A887D52C01D39D219185D4440FC6EBA65877D52C00D87A5811F5D4440D9CC21A9857D52C0641F6459305D44402D7590D7837D52C0DB4FC6F8305D44409354A698837D52C03FE1ECD6325D44402D5BEB8B847D52C05CC64D0D345D44403A3DEFC6827D52C02C0E677E355D44405299620E827D52C0938C9C853D5D444011AAD4EC817D52C0CE8AA8893E5D44407689EAAD817D52C045BB0A293F5D444094A2957B817D52C02C5F97E13F5D4440EDED96E4807D52C060048D99445D44407C7A6CCB807D52C00551F701485D4440BE69FAEC807D52C0999A046F485D44401781B1BE817D52C0ECF483BA485D444028ECA2E8817D52C0F6D214014E5D44403480B740827D52C07024D060535D4440BD35B055827D52C0CEF8BEB8545D44401C3EE944827D52C03F389F3A565D4440FF243E77827D52C0B534B742585D44407B2C7DE8827D52C02AFD84B35B5D44406F7EC344837D52C0535C55F65D5D4440DA006C40847D52C041F163CC5D5D4440459DB987847D52C0CE15A584605D4440FDBCA948857D52C0F4A44C6A685D44408658FD11867D52C097A608707A5D44404FAF9465887D52C03EC91D36915D4440BD38F1D58E7D52C0CFF753E3A55D44406876DD5B917D52C0F1B6D26BB35D44405B7A34D5937D52C0E4F1B4FCC05D4440B6476FB88F7D52C0C0E78711C25D4440743E3C4B907D52C0A5BBEB6CC85D4440D190F128957D52C03A394371C75D4440ADA06989957D52C0512D228AC95D4440D74D29AF957D52C01BB80375CA5D4440307F85CC957D52C0E542E55FCB5D444042EA76F6957D52C049D40B3ECD5D444054556820967D52C0B3226AA2CF5D44408F6D1970967D52C0C189E8D7D65D4440AD6C1FF2967D52C0F71BEDB8E15D4440BED7101C977D52C0C8B4368DED5D4440D47D00529B7D52C0EBE1CB44115E44403F00A94D9C7D52C068774831405E4440F7393E5A9C7D52C04339D1AE425E44409831056B9C7D52C090A2CEDC435E4440984BAAB69B7D52C02384471B475E4440A547533D997D52C04ED026874F5E44403F170D198F7D52C00E661360585E4440545227A0897D52C0E202D0285D5E4440D3139678407D52C026A435069D5E44406C753925207D52C0CA54C1A8A45E44403B1BF2CF0C7D52C0E17CEA58A55E4440FD12F1D6F97C52C078962023A05E444068C9E369F97C52C0A81ABD1AA05E44406FBA6587F87C52C037A79201A05E44407008556AF67C52C0CC24EA059F5E44404CE141B3EB7C52C0F3FE3F4E985E444003CE52B29C7C52C06C239EEC665E44409AB33EE5987C52C020EEEA55645E4440DFC0E446917C52C0CF6394675E5E444014200A664C7C52C07F315BB22A5E44401D8D43FD2E7C52C0D71533C2DB5D4440C4758C2B2E7C52C09C4B7155D95D4440EE08A7052F7C52C0444B1E4FCB5D444091B6F1272A7C52C0A7069ACFB95D444014C95702297C52C0CC785BE9B55D4440807F4A95287C52C0567C43E1B35D44407405DB88277C52C0A0C4E74EB05D44400057B263237C52C07E39B35DA15D4440AC8BDB68007C52C0AB90F2936A5D444025E4839ECD7B52C0395E81E8495D444018265305A37B52C0C2DCEEE53E5D44402781CD39787B52C0685721E5275D4440514832AB777B52C0639AE95E275D4440F2599E07777B52C0EC6987BF265D4440F94A2025767B52C0B16B7BBB255D44409485AFAF757B52C088D860E1245D4440893F8A3A737B52C09622F94A205D44408D0C7217617B52C0BF5E61C1FD5C444026C286A7577B52C0D3DA34B6D75C4440FCDD3B6A4C7B52C0D0967329AE5C444030630AD6387B52C082C64CA25E5C444081E7DEC3257B52C0A33B889D295C4440639AE95E277B52C0D47FD6FCF85B44407EC34483147B52C03A394371C75B4440342A70B20D7B52C0D826158DB55B444099EFE0270E7B52C06762BA10AB5B4440D3F36E2C287B52C0350873BB975B4440D427B9C3267B52C07842AF3F895B4440C4245CC8237B52C030D7A205685B4440880CAB78237B52C08B8A389D645B4440902E36AD147B52C0718C648F505B4440AF928FDD057B52C05169C4CC3E5B44407E8978EBFC7A52C0FC1BB4571F5B44409DF0129CFA7A52C05D86FF74035B4440DCD8EC48F57A52C044A51133FB5A444027BD6F7CED7A52C0D769A4A5F25A44406B9C4D47007B52C0E4F4F57CCD5A4440F29881CAF87A52C095D233BDC45A44403F19E3C3EC7A52C05BEB8B84B65A44403468E89FE07A52C0DF14562AA85A4440E0F08288D47A52C0224F92AE995A44403448C153C87A52C0B8E34D7E8B5A44401155F833BC7A52C06C91B41B7D5A44401DE6CB0BB07A52C050C3B7B06E5A444029779FE3A37A52C0A568E55E605A44400584D6C3977A52C0889AE8F3515A44401215AA9B8B7A52C0DD3F16A2435A4440EE21E17B7F7A52C0C1711937355A4440B3EC4960737A52C0E692AAED265A4440D7BFEB33677A52C0CAC4AD82185A4440E350BF0B5B7A52C04EEE77280A5A4440CE18E6046D7A52C001FA7DFFE6594440DAA9B9DC607A52C0B5A7E49CD8594440B7B6F0BC547A52C0DAC87553CA594440DB899290487A52C0ED7E15E0BB594440CB0EF10F5B7A52C0239D819197594440A25EF0694E7A52C0B340BB438A594440BBEB6CC83F7A52C092E9D0E9795944407F68E6C9357A52C033C4B12E6E594440205D6C5A297A52C05DA27A6B605944401B834E081D7A52C065AA605452594440765089EB187A52C0A27895B54D5944402A357BA0157A52C07B4D0F0A4A5944408A5759DB147A52C0F2B1BB404959444097530262127A52C0D0436D1B465944409E5E29CB107A52C0ADA1D45E445944400A630B410E7A52C07F85CC9541594440DB12B9E00C7A52C00F46EC134059444000378B170B7A52C039419B1C3E5944408A20CEC3097A52C06AF981AB3C59444080423D7D047A52C0670C738236594440CAA48636007A52C034677DCA31594440BF44BC75FE7952C0A051BAF42F594440605628D2FD7952C077BE9F1A2F59444093AAED26F87952C0DF87838428594440CFF6E80DF77952C033164D672759444011346612F57952C07C2AA73D2559444001310917F27952C0E8482EFF21594440730CC85EEF7952C05567B5C01E594440984A3FE1EC7952C0B6D782DE1B5944404CE141B3EB7952C0570394861A594440C91CCBBBEA7952C00B9A9658195944408E1EBFB7E97952C08EACFC3218594440A794D74AE87952C08FE046CA165944409677D503E67952C0B41EBE4C145944402EC55565DF7952C0E2E995B20C5944408F52094FE87952C09DF0129CFA58444052EC681CEA7952C06326512FF8584440E02D90A0F87952C0739EB12FD9584440519E7939EC7952C05C8DEC4ACB584440938AC6DADF7952C0A5846055BD5844401666A19DD37952C07C08AA46AF58444029CE5147C77952C0B3942C27A1584440B2666490BB7952C0AEEE586C935844404E232D95B77952C0EDF0D7648D584440A4198BA6B37952C0FC6EBA65875844401E34BBEEAD7952C0179B560A81584440A297512CB77952C0289831056B5844400DE02D90A07952C0B3D0CE6916584440789961A3AC7952C0A6D1E4620C58444076FEEDB25F7952C015713AC956574440D50627A25F7952C06072A3C85A574440E7A562635E7952C0E08096AE6057444012876C205D7952C05AD2510E6657444072C3EFA65B7952C0C4EC65DB69574440FCC6D79E597952C0374D9F1D7057444051D7DAFB547952C0554FE61F7D574440658D7A88467952C04F1DAB949E57444008556AF6407952C04A7D59DAA95744406F9C14E63D7952C0A5811FD5B0574440A679C7293A7952C09CC0745AB757444061FBC9181F7952C097A608707A574440B0C91AF5107952C03483F8C08E5744402E36AD14027952C0718BF9B9A1574440D4997B48F87852C089D00836AE574440BBD23252EF7852C090BB085394574440EF8E8CD5E67852C01840F850A2574440EACE13CFD97852C0B6847CD0B35744408C48145AD67852C09012BBB6B7574440E690D442C97852C084B53176C257444063F030ED9B7852C090BA9D7DE5574440DFC0E446917852C0DEE2E13D075844403FFD67CD8F7852C0719010E50B5844401C2785798F7852C0764D486B0C584440B1BE81C98D7852C093FE5E0A0F58444037363B527D7852C0093543AA28584440C3D50110777852C09355116E32584440EEE714E4677852C03387A4164A584440717500C45D7852C07EA5F3E1595844407442E8A04B7852C0E108522976584440211CB3EC497852C0CE35CCD0785844405791D101497852C09D7DE5417A584440CB660E492D7852C0056A3178985844401AC1C6F5EF7752C0B9162D40DB5844400F7C0C569C7752C03EE8D9ACFA584440AC1E300F997752C0828AAA5FE9584440A661F888987752C0C2A38D23D6584440DCBC7152987752C042959A3DD0584440A661F888987752C0302AA913D0584440E7FF55478E7752C05DC2A1B7785844402FFA0AD28C7752C0581CCEFC6A584440DCB930D28B7752C021567F8461584440FB20CB82897752C062D7F6764B58444079909E22877752C0D89942E7355844408C63247B847752C0B58993FB1D584440ACE46377817752C0677E350708584440C6C210397D7752C0B2F4A10BEA57444074B680D07A7752C0909DB7B1D9574440DB317557767752C0077767EDB65744409A7631CD747752C02D7B12D89C5744400D6C9560717752C054FEB5BC72574440FC34EECD6F7752C0A3E6ABE4635744409E7AA4C16D7752C0D1949D7E50574440FE9C82FC6C7752C0E046CA16495744401E4FCB0F5C7752C09B53C90050574440D503E621537752C0E063B0E25457444037DC476E4D7752C032569BFF5757444070ED4449487752C0836C59BE2E57444066F50EB7437752C054C554FA0957444032022A1C417752C0713C9F01F55644404487C091407752C01F7EFE7BF05644406E4E2503407752C05D4C33DDEB56444088F546AD307752C03ECBF3E0EE5644401F0F7D772B7752C04835ECF7C4564440A33B889D297752C026AAB706B656444087A4164A267752C0938E72309B5644403B6F63B3237752C050FD834886564440D7F7E120217752C00D6C956071564440132A38BC207752C07A8A1C226E564440315D88D51F7752C07E8E8F1667564440D4F02DAC1B7752C0ADA415DF505644409E95B4E21B7752C09AE8F35146564440B88D06F0167752C0BB46CB811E564440A435069D107752C0C8E88024EC554440C9703C9F017752C0F01307D0EF55444083DE1B43007752C0855D143DF05544404EB4AB90F27652C0A69718CBF45544401ABE8575E37652C0C214E5D2F855444041649126DE7652C0FACE2F4AD0554440293C6876DD7652C0807D74EACA554440FAD170CADC7652C0779FE3A3C55544403FABCC94D67652C0F58079C8945544405AD76839D07652C0B41D537765554440849ECDAACF7652C0272D5C56615544405DA79196CA7652C0D87F9D9B36554440331477BCC97652C06A10E6762F55444060AB048BC37652C062F20698F95444402D23F59ECA7652C05D6919A9F754444011C30E63D27652C0B8E864A9F554444021C9ACDEE17652C073D87DC7F0544440F0F96184F07652C06FB72407EC5444408577B988EF7652C0DFA5D425E3544440A089B0E1E97652C0C8091346B35444403621AD31E87652C0999CDA19A6544440C763062AE37652C0EF3B86C77E5444401F4AB4E4F17652C0E0D4079277544440E2E65432007752C054E4107173544440FF0241800C7752C061FA5E437054444057B26323107752C0F677B6476F5444402026E1421E7752C00FEB8D5A61544440834F73F2227752C0E3361AC05B544440C2F693313E7752C0C05AB56B4254444097900F7A367752C0780C8FFD2C544440F834272F327752C06684B70721544440C4758C2B2E7752C03D0801F9125444408D959867257752C00E4A9869FB534440E68F696D1A7752C02FF99FFCDD53444022C2BF081A7752C0247F30F0DC534440EF1CCA50157752C03599F1B6D2534440C0B2D2A4147752C06551D845D15344409048DBF8137752C09509BFD4CF53444014419C87137752C0FB027AE1CE534440E5F04927127752C01A84B9DDCB53444092B06F27117752C0DAC87553CA5344407EA65EB7087752C0228C9FC6BD534440A3E4D539067752C065170CAEB9534440C2FA3F87F97652C059F5B9DA8A5344408BFA2477D87652C082A62556465344406403E962D37652C03197546D3753444018B49080D17652C0D5928E72305344404A22FB20CB7652C0765089EB185344402A1900AAB87652C0BE0F070951524440E386DF4DB77652C01F63EE5A425244400F7D772B4B7652C005A568E55E524440FB3F87F9F27552C07D224F92AE5144405793A7ACA67552C0D7C0560916514440BEDA519CA37552C0A44FABE80F514440745B22179C7552C0E2CCAFE600514440DCD6169E977552C00B43E4F4F5504440A93121E6927552C05E807D74EA504440D13FC1C58A7552C056ED9A90D6504440096B63EC847552C0AB92C83EC8504440AE80423D7D7552C04127840EBA50444040F7E5CC767552C0D0967329AE50444089CE328B507552C0162D40DB6A504440C8ED974F567552C05646239F57504440211FF46C567552C03674B33F5050444015713AC9567552C059DC7F643A5044404AB20E47577552C028B682A62550444037AB3E575B7552C0F7AE415F7A4F44408D261763607552C0226C787AA54E444045460724617552C0A94885B1854E4440F62686E4647552C02D978DCEF94D444036AE7FD7677552C018AE0E80B84D4440B9E00CFE7E7552C0B01F6283854D4440446B459BE37552C0C5E23785954C444012A27C410B7652C03C1405FA444C4440588B4F01307652C0B058C345EE4B4440A6457D923B7652C07C28D192C74B44402C9CA4F9637652C0A2957B81594B4440A81ABD1AA07652C0300C5872154B4440FBC8AD49B77652C035272F32014B44404127840EBA7652C02AE109BDFE4A44401DCBBBEA017752C02172FA7ABE4A4440130CE71A667752C0C6A2E9EC644A44400A4B3CA06C7752C0BEF8A23D5E4A4440A5D93C0E837752C06473D53C474A4440FDBCA948857752C06B98A1F1444A4440F0C000C2877752C0F0DE5163424A4440D8817346947752C04450357A354A4440BF28417FA17752C08099EFE0274A44400A2DEBFEB17752C0BCAE5FB01B4A44407FF8F9EFC17752C08C0DDDEC0F4A444053C90050C57752C0B14B546F0D4A44402E71E481C87752C0BF61A2410A4A44401EFB592C457852C09F39EB538E494440056D72F8A47852C06D8E739B7049444036AD1402B97852C0D68BA19C68494440F59F353FFE7852C0BAA0BE654E494440289A07B0C87952C0C58F31772D4944406133C005D97952C0D862B7CF2A494440E1783E03EA7952C04DDA54DD2349444046B3B27DC87A52C06A11514CDE4844402F185C73477B52C0FCE25295B6484440A26131EA5A7B52C06A696E85B04844408499B67F657B52C036902E36AD4844404F8F6D19707B52C0C1C760C5A94844402E1D739EB17B52C02BDCF29194484440F9122A38BC7B52C0B5132521914844401021AE9CBD7B52C080D250A39048444081CEA44DD57B52C0431B800D88484440BBB88D06F07B52C076A38FF980484440B5A50EF27A7C52C07780272D5C484440F7C77BD5CA7C52C08AE5965643484440614D6551D87C52C05CFDD8243F484440E84CDA54DD7C52C03F1878EE3D4844409947FE60E07C52C05774EB353D484440AF0793E2E37C52C0FF5C34643C48444065A54929E87C52C0C45E28603B484440EFAB72A1F27C52C01F12BEF737484440D07D39B35D7D52C0075F984C1548444025AB22DC647D52C03D0801F912484440C39E76F86B7D52C0861C5BCF104844401211FE45D07F52C0F2CEA10C55474440B804E09F528252C0785C548B884644407615527E528252C0DB85E63A8D464440E2E5E95C518252C0BB270F0BB546444089B48D3F518252C0A7203F1BB94644400858AB764D8252C0F294D5743D474440CD565EF23F8252C07D7555A0164944401B28F04E3E8252C0E9F010C64F494440AAB4C5353E8252C0BDC117265349444032CB9E04368252C0F6285C8FC24944405111A7936C8252C09FE238F06A4B44402252D32EA68252C0BC02D193324D44404C50C3B7B08252C0F9F36DC1524D444068075C57CC8252C0ECDCB419A74D4440A31F0DA7CC8252C086E3F90CA84D44409D2E8B89CD8252C0438CD7BCAA4D44402BA1BB24CE8252C00726378AAC4D4440DDE9CE13CF8252C035423F53AF4D4440A774B0FECF8252C0C266800BB24D4440A626C11BD28252C007431D56B84D4440EDD286C3D28252C0DC476E4DBA4D44402638F581E48252C04A5F0839EF4D444074779D0DF98252C0E3C281902C4E4440890629780A8352C016DC0F78604E44408315A75A0B8352C0E5EFDE51634E4440EA793716148352C036E84B6F7F4E44404703780B248352C0C24CDBBFB24E44403046240A2D8352C09BE09BA6CF4E4440A4C00298328352C02D776682E14E444055F833BC598352C09F91088D604F4440B3B27DC85B8352C08922A46E674F444075E789E76C8352C066118AADA04F44400D52F014728352C051F355F2B14F4440C5ABAC6D8A8352C0D4D00660035044403D7E6FD39F8352C05C1ABFF04A5044405051F52B9D8352C042B28009DC504440 +(1 row) + +SELECT obs_getboundariesbygeometry(ST_MakeEnvelope(-73.9452409744, 40.6988851644, -73.9280319214, 40.7101254524, 4326), 'us.census.tiger.census_tract'::text); +NOTICE: cdb_dataservices_client._obs_getboundariesbygeometry(6): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getboundariesbygeometry invoked with params (test_user, , 0103000020E61000000100000005000000C7F8FFD37E7C52C0F860AE1175594440C7F8FFD37E7C52C0BF0E0D64E55A4440A70300E0647B52C0BF0E0D64E55A4440A70300E0647B52C0F860AE1175594440C7F8FFD37E7C52C0F860AE1175594440, us.census.tiger.census_tract, , intersects) +CONTEXT: PL/pgSQL function obs_getboundariesbygeometry(geometry,text,text,text) line 16 at RETURN QUERY + obs_getboundariesbygeometry +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + (0106000020E61000000100000001030000000100000019000000DD96C805677C52C0CBD8D0CDFE5A44407A19C5724B7C52C033BF9A03045B4440FF59F3E32F7C52C0CB290131095B4440247EC51A2E7C52C0548B8862F25A44401FF5D72B2C7C52C0CB811E6ADB5A444049F086342A7C52C09CC3B5DAC35A444044679945287C52C01F680586AC5A444012D90759167C52C09430D3F6AF5A44405698BED7107C52C04759BF99985A4440DEE522BE137C52C00664AF777F5A4440F92EA52E197C52C09BA73AE4665A4440C558A65F227C52C0D80DDB16655A4440373465A71F7C52C065A71FD4455A44404AED45B41D7C52C0785DBF60375A444083A3E4D5397C52C09946938B315A4440F2B4FCC0557C52C01FF5D72B2C5A444026C286A7577C52C02BDD5D67435A44405BCF108E597C52C0C651B9895A5A444030D461855B7C52C0D1393FC5715A444065E1EB6B5D7C52C078280AF4895A44403AE63C635F7C52C07D1F0E12A25A44403F6F2A52617C52C05983F755B95A44405C3AE63C637C52C04852D2C3D05A444049810530657C52C0FAEE5696E85A4440DD96C805677C52C0CBD8D0CDFE5A4440,36047049300) +(1 row) + +SELECT obs_getboundariesbypointandradius(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 500, 'us.census.tiger.census_tract'::text); +NOTICE: cdb_dataservices_client._obs_getboundariesbypointandradius(7): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getboundariesbypointandradius invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, 500, us.census.tiger.census_tract, , intersects) +CONTEXT: PL/pgSQL function obs_getboundariesbypointandradius(geometry,numeric,text,text,text) line 16 at RETURN QUERY + obs_getboundariesbypointandradius +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + (0106000020E6100000010000000103000000010000001500000083A3E4D5397C52C09946938B315A44404AED45B41D7C52C0785DBF60375A444099F221A81A7C52C0D0EFFB372F5A4440B9C15087157C52C034643C4A255A4440BB438A01127C52C0DE1CAED51E5A44400FECF82F107C52C0876D8B321B5A4440510FD1E80E7C52C0C4D32B65195A44407FDAA84E077C52C0E0675C38105A444092AD2EA7047C52C08E75711B0D5A4440CF2D7425027C52C0A86DC328085A4440EFFCA204FD7B52C07E384888F259444034BC5983F77B52C0205ED72FD8594440E76F4221027C52C0F3A96395D259444081AD122C0E7C52C00ED6FF39CC594440CB63CDC8207C52C031276893C359444047205ED72F7C52C0287D21E4BC594440BD1C76DF317C52C0F8325184D4594440CD1FD3DA347C52C0B0A9F3A8F8594440C72E51BD357C52C0C3651536035A444043024697377C52C028999CDA195A444083A3E4D5397C52C09946938B315A4440,36047048900) +(1 row) + +SELECT obs_getpointsbygeometry(ST_MakeEnvelope(-73.9452409744, 40.6988851644, -73.9280319214, 40.7101254524, 4326), 'us.census.tiger.census_tract'::text); +NOTICE: cdb_dataservices_client._obs_getpointsbygeometry(6): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getpointsbygeometry invoked with params (test_user, , 0103000020E61000000100000005000000C7F8FFD37E7C52C0F860AE1175594440C7F8FFD37E7C52C0BF0E0D64E55A4440A70300E0647B52C0BF0E0D64E55A4440A70300E0647B52C0F860AE1175594440C7F8FFD37E7C52C0F860AE1175594440, us.census.tiger.census_tract, , intersects) +CONTEXT: PL/pgSQL function obs_getpointsbygeometry(geometry,text,text,text) line 16 at RETURN QUERY + obs_getpointsbygeometry +------------------------------------------------------------------ + (0101000020E610000037CB75821A7C52C0BA8784EFFD594440,36047048900) +(1 row) + +SELECT obs_getpointsbypointandradius(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 500::numeric, 'us.census.tiger.census_tract'::text); +NOTICE: cdb_dataservices_client._obs_getpointsbypointandradius(7): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getpointsbypointandradius invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, 500, us.census.tiger.census_tract, , intersects) +CONTEXT: PL/pgSQL function obs_getpointsbypointandradius(geometry,numeric,text,text,text) line 16 at RETURN QUERY + obs_getpointsbypointandradius +------------------------------------------------------------------ + (0101000020E610000037CB75821A7C52C0BA8784EFFD594440,36047048900) +(1 row) + +SELECT obs_getmeasure(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'us.census.acs.B01001001'::text); +NOTICE: cdb_dataservices_client._obs_getmeasure(7): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getmeasure invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, us.census.acs.B01001001, area, , ) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getmeasure(username, orgname, geom, measure_id, normalize, boundary_id, time_span)" +PL/pgSQL function obs_getmeasure(geometry,text,text,text,text) line 16 at SQL statement + obs_getmeasure +----------------------- + 10923.093200390833950 +(1 row) + +SELECT obs_getcategory(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'us.census.spielman_singleton_segments.X10'::text); +NOTICE: cdb_dataservices_client._obs_getcategory(6): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getcategory invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, us.census.spielman_singleton_segments.X10, , ) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getcategory(username, orgname, geom, category_id, boundary_id, time_span)" +PL/pgSQL function obs_getcategory(geometry,text,text,text) line 16 at SQL statement + obs_getcategory +----------------------------- + Wealthy, urban without Kids +(1 row) + +SELECT obs_getuscensusmeasure(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'male population'::text); +NOTICE: cdb_dataservices_client._obs_getuscensusmeasure(7): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getuscensusmeasure invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, male population, area, , ) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getuscensusmeasure(username, orgname, geom, name, normalize, boundary_id, time_span)" +PL/pgSQL function obs_getuscensusmeasure(geometry,text,text,text,text) line 16 at SQL statement + obs_getuscensusmeasure +------------------------ + 6789.5647735060920500 +(1 row) + +SELECT obs_getuscensuscategory(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'Spielman-Singleton Segments: 10 Clusters'::text); +NOTICE: cdb_dataservices_client._obs_getuscensuscategory(6): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getuscensuscategory invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, Spielman-Singleton Segments: 10 Clusters, , ) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getuscensuscategory(username, orgname, geom, name, boundary_id, time_span)" +PL/pgSQL function obs_getuscensuscategory(geometry,text,text,text) line 16 at SQL statement + obs_getuscensuscategory +----------------------------- + Wealthy, urban without Kids +(1 row) + +SELECT obs_getpopulation(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326)); +NOTICE: cdb_dataservices_client._obs_getpopulation(6): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getpopulation invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, area, , ) +CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getpopulation(username, orgname, geom, normalize, boundary_id, time_span)" +PL/pgSQL function obs_getpopulation(geometry,text,text,text) line 16 at SQL statement + obs_getpopulation +----------------------- + 10923.093200390833950 +(1 row) + +SELECT obs_search('total_pop'::text); +NOTICE: cdb_dataservices_client._obs_search(4): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_search invoked with params (test_user, , total_pop, ) +CONTEXT: PL/pgSQL function obs_search(text,text) line 16 at RETURN QUERY + obs_search +---------------------------------------------------------------------------------------------------------- + (es.ine.total_pop,"The total number of all people living in a geographic area.","Total Population",sum,) +(1 row) + +SELECT obs_getavailableboundaries(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326)); +NOTICE: cdb_dataservices_client._obs_getavailableboundaries(4): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getavailableboundaries invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, ) +CONTEXT: PL/pgSQL function obs_getavailableboundaries(geometry,text) line 16 at RETURN QUERY + obs_getavailableboundaries +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + (us.census.tiger.place,"Incorporated places are those reported to the Census Bureau as legally in existence as of January 1, 2010, as reported in the latest Boundary and Annexation Survey (BAS), under the laws of their respective states.",2014,obs_7c9493c41fa8f4bd178ab993ea3d5891c1977667) +(1 row) + diff --git a/client/test/sql/90_data_observatory_test.sql b/client/test/sql/90_data_observatory_test.sql index dd03800..620c24c 100644 --- a/client/test/sql/90_data_observatory_test.sql +++ b/client/test/sql/90_data_observatory_test.sql @@ -25,7 +25,180 @@ BEGIN END; $$ LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getdemographicsnapshot (username text, orgname text, geom geometry(Geometry, 4326), time_span text DEFAULT '2009 - 2013', geometry_level text DEFAULT '"us.census.tiger".block_group') +RETURNS json AS $$ +DECLARE + ret json; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getdemographicsnapshot invoked with params (%, %, %, %, %)', username, orgname, geom, time_span, geometry_level; + SELECT '{"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null}'::json INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getsegmentsnapshot (username text, orgname text, geom geometry(Geometry, 4326), geometry_level text DEFAULT '"us.census.tiger".census_tract') +RETURNS json AS $$ +DECLARE + ret json; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getsegmentsnapshot invoked with params (%, %, %, %)', username, orgname, geom, geometry_level; + SELECT '{"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null}'::json INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundary (username text, orgname text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry(Geometry, 4326) AS $$ +DECLARE + ret Geometry; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundary invoked with params (%, %, %, %, %)', username, orgname, geom, boundary_id, time_span; + SELECT '0106000020E6100000010000000103000000010000003500000056EF703B347C52C054FF2092215B44401B9AB2D30F7C52C03FE1ECD6325B4440B14B546F0D7C52C0BBCE86FC335B4440730F09DFFB7B52C0B796C9703C5B4440108FC4CBD37B52C0B96C74CE4F5B444001C0B167CF7B52C0ED0BE8853B5B4440C843DFDDCA7B52C05DDDB1D8265B4440A73D25E7C47B52C0D53BDC0E0D5B4440BB5E9A22C07B52C0F8A3A833F75A4440355F251FBB7B52C0B64604E3E05A444008910C39B67B52C098BF42E6CA5A44405227A089B07B52C0F204C24EB15A444024F1F274AE7B52C069E4F38AA75A44402B4A09C1AA7B52C06B63EC84975A4440E199D024B17B52C0546F0D6C955A44403C873254C57B52C02EAC1BEF8E5A44402593533BC37B52C0588AE42B815A4440973AC8EBC17B52C087890629785A44407A6F0C01C07B52C0E1EB6B5D6A5A44401B9B1DA9BE7B52C03F6F2A52615A444088855AD3BC7B52C088669E5C535A4440E1EA0088BB7B52C0E6E95C514A5A44400CE6AF90B97B52C070D05E7D3C5A44401E85EB51B87B52C0B03A72A4335A4440BAF3C473B67B52C09929ADBF255A4440CD920035B57B52C0454AB3791C5A4440F78DAF3DB37B52C0E09BA6CF0E5A4440DBC2F352B17B52C0703FE081015A444015C440D7BE7B52C05E83BEF4F659444041446ADAC57B52C0EFDFBC38F15944405FB1868BDC7B52C0C03E3A75E559444034BC5983F77B52C0205ED72FD8594440EFFCA204FD7B52C07E384888F25944403ACAC16C027C52C00876FC17085A444056478E74067C52C00FECF82F105A44400FECF82F107C52C0876D8B321B5A4440BB438A01127C52C0DE1CAED51E5A4440B9C15087157C52C034643C4A255A444099F221A81A7C52C0D0EFFB372F5A44404AED45B41D7C52C0785DBF60375A4440373465A71F7C52C065A71FD4455A4440C558A65F227C52C0D80DDB16655A4440F92EA52E197C52C09BA73AE4665A4440DEE522BE137C52C00664AF777F5A44405698BED7107C52C04759BF99985A444012D90759167C52C09430D3F6AF5A444044679945287C52C01F680586AC5A444049F086342A7C52C09CC3B5DAC35A44401FF5D72B2C7C52C0CB811E6ADB5A4440247EC51A2E7C52C0548B8862F25A4440FF59F3E32F7C52C0CB290131095B4440F96871C6307C52C09605137F145B444056EF703B347C52C054FF2092215B4440'::geometry INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundaryid (username text, orgname text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundaryid invoked with params (%, %, %, %, %)', username, orgname, geom, boundary_id, time_span; + SELECT '36047048500'::text INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundarybyid (username text, orgname text, geometry_id text, boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry(Geometry, 4326) AS $$ +DECLARE + ret Geometry; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundarybyid invoked with params (%, %, %, %, %)', username, orgname, geometry_id, boundary_id, time_span; + SELECT '0106000020E610000001000000010300000001000000930200005051F52B9D8352C042B28009DC50444093C2BCC7998352C0E89E758D965144402EFD4B52998352C09A07B0C8AF514440E75086AA988352C022FAB5F5D351444027874F3A918352C0A46B26DF6C53444018E945ED7E8352C04D81CCCEA25344401346B3B27D8352C05D50DF32A753444068226C787A8352C08D25AC8DB153444015C8EC2C7A8352C004560E2DB2534440DF8618AF798352C00FD07D39B3534440FEB627486C8352C0DC9E20B1DD534440B98C9B1A688352C05D328E91EC5344408B8A389D648352C0929048DBF853444075CAA31B618352C0986A662D05544440EA758BC0588352C0D6C397892254444048DFA469508352C0151DC9E53F544440B67F65A5498352C0F73DEAAF575444401403249A408352C05E2A36E6755444402367614F3B8352C06DE2E47E8754444011FC6F253B8352C0431B800D885444403E7958A8358352C0DD0A6135965444401D739EB12F8352C093DFA293A5544440FB04508C2C8352C035289A07B05444401EA4A7C8218352C0347F4C6BD3544440D7C05609168352C05053CBD6FA544440AC8E1CE90C8352C0C9AA083719554440FC8D76DCF08252C0BD18CA897655444048895DDBDB8252C0C3B7B06EBC554440698995D1C88252C032207BBDFB55444004A73E90BC8252C0DB4C857824564440BC1FB75F3E8252C08F368E588B574440E15D2EE23B8252C066F4A3E194574440C614AC71368252C0381268B0A9574440CEA44DD53D8152C04F1F813FFC564440A51133FB3C8152C0F607CA6DFB56444070D05E7D3C8152C0CB0C1B65FD564440C5C6BC8E388152C0F303577902574440EA043411368152C03F390A1005574440840B7904378152C0D34ECDE506574440390A1005338152C047E350BF0B5744405D143DF0318152C0D53BDC0E0D5744401D59F965308152C00A4966F50E574440236420CF2E8152C00FD253E41057444084EE92382B8152C0AD2D3C2F15574440E23D0796238152C0A304FD851E574440B3EDB435228152C001D9EBDD1F5744401EBE4C14218152C08BDCD3D51D574440A2D0B2EE1F8152C0FC1BB4571F57444007B0C8AF1F8152C0CC9717601F574440F678211D1E8152C0374E0AF31E5744401A69A9BC1D8152C0793D98141F574440102384471B8152C0CB2F833122574440B7EEE6A90E8152C09F1D705D315744405968E7340B8152C02C0E677E355744400E4A9869FB8052C0C91EA166485744401B2C9CA4F98052C05C001AA54B5744401AF8510DFB8052C0C51A2E724F574440925CFE43FA8052C0309DD66D50574440BB9866BAD78052C0035DFB027A574440A04FE449D28052C02920ED7F80574440DC9BDF30D18052C0E8305F5E80574440B43C0FEECE8052C0D8614CFA7B5744404AEEB089CC8052C0950A2AAA7E5744409A5B21ACC68052C032FE7DC6855744406682E15CC38052C01EF7ADD689574440F78DAF3DB38052C020CD58349D5744402FFA0AD28C8052C00919C8B3CB574440D0251C7A8B8052C00EA2B5A2CD57444001DE02098A8052C030444E5FCF5744404A404CC2858052C0992A1895D45744403480B740828052C0A33CF372D857444028ECA2E8818052C0CD0358E4D7574440F3AACE6A818052C074ECA012D75744402920ED7F808052C0DFA293A5D657444036E84B6F7F8052C092054CE0D6574440AD4CF8A57E8052C0E55FCB2BD757444042CA4FAA7D8052C01AA19FA9D7574440A2EC2DE57C8052C0205ED72FD8574440BB6246787B8052C08BE07F2BD95744405C74B2D47A8052C025E7C41EDA5744405CA8FC6B798052C0F52EDE8FDB574440FF0758AB768052C09AAF928FDD574440A60A4625758052C0C442AD69DE574440A73E90BC738052C05E49F25CDF574440BF9A0304738052C046ED7E15E0574440A19BFD81728052C070B4E386DF5744403D0AD7A3708052C0D0F0660DDE574440680586AC6E8052C04D469561DC57444063963D096C8052C0965AEF37DA574440944E24986A8052C0BA641C23D957444059501894698052C014B01D8CD8574440E21FB6F4688052C0614D6551D85744401895D409688052C0205ED72FD85744406379573D608052C0A4A487A1D55744401878EE3D5C8052C041B5C189E85744402F4FE78A528052C0A580B4FF01584440983270404B8052C0EECEDA6D1758444050357A35408052C0E3C281902C58444086C43D963E8052C0DC9DB5DB2E584440C5E061DA378052C0BFF2203D455844409946938B318052C0C4E9245B5D5844407C478D09318052C040A374E95F584440E3A8DC442D8052C0F92AF9D85D584440919C4CDC2A8052C06BD26D895C584440276893C3278052C0E9279CDD5A58444053B131AF238052C061C092AB5858444055336B29208052C068E55E605658444091990B5C1E8052C082C64CA25E584440AA2688BA0F8052C027F6D03E56584440F488D1730B8052C0D21C59F9655844400C1CD0D2158052C0BB96900F7A584440C6A69542208052C0B77BB94F8E584440D3A23EC91D8052C02EC901BB9A584440B6BDDD921C8052C0BF42E6CAA058444082E49D43198052C036902E36AD58444072FBE593158052C0ACA92C0ABB5844402B4F20EC148052C0EC3026FDBD584440E4BCFF8F138052C04E266E15C4584440C26856B60F8052C06E15C440D7584440C404357C0B8052C00F5EBBB4E1584440397CD289048052C0CA87A06AF4584440FB761211FE7F52C090F7AA9509594440D93C0E83F97F52C03561FBC9185944402828452BF77F52C0F06DFAB31F594440F9BD4D7FF67F52C0DC9A745B225944403AADDBA0F67F52C0BE4D7FF62359444093C49272F77F52C0526342CC25594440450DA661F87F52C0798EC87729594440F2CCCB61F77F52C0067FBF982D5944409B030473F47F52C017821C94305944401E300F99F27F52C05609168733594440E57FF277EF7F52C0EDBAB72231594440A3AA09A2EE7F52C0EA1ED95C355944405D18E945ED7F52C0D3F6AFAC345944401C5DA5BBEB7F52C076DB85E63A5944404BADF71BED7F52C0B1D991EA3B5944401F477364E57F52C0E48409A35959444022179CC1DF7F52C001D8800871594440A4703D0AD77F52C02EC6C03A8E594440457F68E6C97F52C061C26856B659444070404B57B07F52C0FCDEA63FFB594440DC10E335AF7F52C048E00F3FFF59444055F7C8E6AA7F52C02DB4739A055A4440A4E2FF8EA87F52C00CFFE9060A5A44407E8AE3C0AB7F52C0EC4960730E5A444006F2ECF2AD7F52C08CD99255115A444042588D25AC7F52C09BA8A5B9155A44405A9A5B21AC7F52C0F4BF5C8B165A44406762BA10AB7F52C0A5BA8097195A4440E5B7E864A97F52C0B6BDDD921C5A44402B4A09C1AA7F52C0499F56D11F5A4440D48041D2A77F52C0177FDB13245A4440C22FF5F3A67F52C0D55B035B255A4440FE7BF0DAA57F52C0F8FD9B17275A44409A046F48A37F52C04FADBEBA2A5A444045F12A6B9B7F52C0AC1919E42E5A44404BE2AC889A7F52C0A75CE15D2E5A4440462575029A7F52C0965984622B5A4440E75086AA987F52C0906802452C5A44400B2769FE987F52C05FB01BB62D5A444004029D499B7F52C0DD2230D6375A44404301DBC1887F52C0CBF10A444F5A4440D6A88768747F52C0B81E85EB515A44407C0C569C6A7F52C0F6CFD380415A4440CB113290677F52C0A9328CBB415A44407905A227657F52C03D7C9928425A44407EA5F3E1597F52C0787AA52C435A444009F7CABC557F52C0A2410A9E425A44408D23D6E2537F52C00EF8FC30425A444029780AB9527F52C08B19E1ED415A44402992AF04527F52C08B19E1ED415A4440C51A2E724F7F52C08B19E1ED415A4440AC36FFAF3A7F52C01AA6B6D4415A444009522976347F52C0A2410A9E425A4440F25D4A5D327F52C0252026E1425A44408252B4722F7F52C05A61FA5E435A444032E202D0287F52C013B534B7425A4440E0BBCD1B277F52C014E97E4E415A44409352D0ED257F52C0151DC9E53F5A444022F94A20257F52C0B08BA2073E5A4440CF9ECBD4247F52C0F3AE7AC03C5A444077A1B94E237F52C0F3AE7AC03C5A4440DDB419A7217F52C097FBE428405A4440666A12BC217F52C016A243E0485A44408EACFC32187F52C0CD8DE9094B5A44404F05DCF3FC7E52C0B952CF82505A4440D2E0B6B6F07E52C0FFCA4A93525A44404F029B73F07E52C0A7E7DD58505A4440EA3C2AFEEF7E52C020B41EBE4C5A44404A5F0839EF7E52C01AF7E6374C5A4440D462F030ED7E52C055F5F23B4D5A4440825660C8EA7E52C0B5FD2B2B4D5A4440825660C8EA7E52C072DA53724E5A44403C2CD49AE67E52C030B77BB94F5A44400DDC813AE57E52C0D76B7A50505A4440670DDE57E57E52C0072461DF4E5A4440C77DAB75E27E52C0A25EF0694E5A4440ABB2EF8AE07E52C04F04711E4E5A44403A3FC571E07E52C03C65355D4F5A4440643A747ADE7E52C04ED026874F5A444077F35487DC7E52C08A027D224F5A4440F0A5F0A0D97E52C031EBC5504E5A444068588CBAD67E52C0D8D30E7F4D5A444046B3B27DC87E52C06FB9FAB1495A4440B85A272EC77E52C03C821B295B5A444039CE6DC2BD7E52C097016729595A44409A07B0C8AF7E52C07FD93D79585A44407E8AE3C0AB7E52C0EBC37AA3565A4440C1E10511A97E52C0D097DEFE5C5A44401B82E3326E7E52C03F170D198F5A44408A3C49BA667E52C0D619DF17975A444026DF6C73637E52C07A32FFE89B5A4440E78BBD175F7E52C000FE2955A25A4440594DD7135D7E52C040852348A55A4440E36A64575A7E52C03EE94482A95A4440E603029D497E52C067B62BF4C15A4440ED42739D467E52C04701A260C65A4440253ACB2C427E52C03E40F7E5CC5A4440D026874F3A7E52C061C5A9D6C25A44405C5837DE1D7E52C0868F8829915A4440162EABB0197E52C007B5DFDA895A4440B859BC58187E52C083A279008B5A44408FE046CA167E52C011FB04508C5A4440B131AF230E7E52C0D2C43BC0935A44401A4CC3F0117E52C0F0FACC599F5A44401A321EA5127E52C06631B1F9B85A44402B836A83137E52C0E55C8AABCA5A4440C9737D1F0E7E52C0B376DB85E65A4440D3687231067E52C07405DB88275B444009DE9046057E52C09A94826E2F5B4440158C4AEA047E52C08D7E349C325B4440C808A870047E52C0B6114F76335B4440634337FB037E52C00F290648345B4440DAA7E331037E52C03E7958A8355B444082902C60027E52C0DE3CD521375B4440AB5791D1017E52C048BF7D1D385B4440942F6821017E52C095287B4B395B4440268C6665FB7D52C0548A1D8D435B44405C1B2AC6F97D52C065187783685B4440FA0B3D62F47D52C03FE08101845B4440E2E313B2F37D52C03196E997885B444038F4160FEF7D52C05D50DF32A75B4440109546CCEC7D52C07FDB1324B65B44401C261AA4E07D52C0BA641C23D95B444076BF0AF0DD7D52C06AF7AB00DF5B4440DCB8C5FCDC7D52C0B06F2711E15B44405A0EF450DB7D52C0081F4AB4E45B444084D558C2DA7D52C0F57F0EF3E55B4440BBB20B06D77D52C06E693524EE5B4440CE6BEC12D57D52C0FB592C45F25B444073672618CE7D52C09A0645F3005C4440BB7B80EECB7D52C0C7BAB88D065C4440F5F411F8C37D52C057E9EE3A1B5C44407B8670CCB27D52C09AB4A9BA475C4440240B98C0AD7D52C0282A1BD6545C4440E4839ECDAA7D52C0FA5E43705C5C4440E4805D4D9E7D52C08AAA5FE97C5C44401B2AC6F99B7D52C01C2444F9825C4440D3122BA3917D52C059F8FA5A975C4440A7ACA6EB897D52C0FD2D01F8A75C444007B5DFDA897D52C04818062CB95C44401EF7ADD6897D52C0399A232BBF5C444036397CD2897D52C0904946CEC25C444001DE02098A7D52C08A58C4B0C35C4440CB68E4F38A7D52C0527B116DC75C4440AD4F39268B7D52C0AB92C83EC85C4440531EDD088B7D52C0EB19C231CB5C4440C5C551B9897D52C070EB6E9EEA5C444090847D3B897D52C02E5393E00D5D44409C4CDC2A887D52C01D39D219185D4440FC6EBA65877D52C00D87A5811F5D4440D9CC21A9857D52C0641F6459305D44402D7590D7837D52C0DB4FC6F8305D44409354A698837D52C03FE1ECD6325D44402D5BEB8B847D52C05CC64D0D345D44403A3DEFC6827D52C02C0E677E355D44405299620E827D52C0938C9C853D5D444011AAD4EC817D52C0CE8AA8893E5D44407689EAAD817D52C045BB0A293F5D444094A2957B817D52C02C5F97E13F5D4440EDED96E4807D52C060048D99445D44407C7A6CCB807D52C00551F701485D4440BE69FAEC807D52C0999A046F485D44401781B1BE817D52C0ECF483BA485D444028ECA2E8817D52C0F6D214014E5D44403480B740827D52C07024D060535D4440BD35B055827D52C0CEF8BEB8545D44401C3EE944827D52C03F389F3A565D4440FF243E77827D52C0B534B742585D44407B2C7DE8827D52C02AFD84B35B5D44406F7EC344837D52C0535C55F65D5D4440DA006C40847D52C041F163CC5D5D4440459DB987847D52C0CE15A584605D4440FDBCA948857D52C0F4A44C6A685D44408658FD11867D52C097A608707A5D44404FAF9465887D52C03EC91D36915D4440BD38F1D58E7D52C0CFF753E3A55D44406876DD5B917D52C0F1B6D26BB35D44405B7A34D5937D52C0E4F1B4FCC05D4440B6476FB88F7D52C0C0E78711C25D4440743E3C4B907D52C0A5BBEB6CC85D4440D190F128957D52C03A394371C75D4440ADA06989957D52C0512D228AC95D4440D74D29AF957D52C01BB80375CA5D4440307F85CC957D52C0E542E55FCB5D444042EA76F6957D52C049D40B3ECD5D444054556820967D52C0B3226AA2CF5D44408F6D1970967D52C0C189E8D7D65D4440AD6C1FF2967D52C0F71BEDB8E15D4440BED7101C977D52C0C8B4368DED5D4440D47D00529B7D52C0EBE1CB44115E44403F00A94D9C7D52C068774831405E4440F7393E5A9C7D52C04339D1AE425E44409831056B9C7D52C090A2CEDC435E4440984BAAB69B7D52C02384471B475E4440A547533D997D52C04ED026874F5E44403F170D198F7D52C00E661360585E4440545227A0897D52C0E202D0285D5E4440D3139678407D52C026A435069D5E44406C753925207D52C0CA54C1A8A45E44403B1BF2CF0C7D52C0E17CEA58A55E4440FD12F1D6F97C52C078962023A05E444068C9E369F97C52C0A81ABD1AA05E44406FBA6587F87C52C037A79201A05E44407008556AF67C52C0CC24EA059F5E44404CE141B3EB7C52C0F3FE3F4E985E444003CE52B29C7C52C06C239EEC665E44409AB33EE5987C52C020EEEA55645E4440DFC0E446917C52C0CF6394675E5E444014200A664C7C52C07F315BB22A5E44401D8D43FD2E7C52C0D71533C2DB5D4440C4758C2B2E7C52C09C4B7155D95D4440EE08A7052F7C52C0444B1E4FCB5D444091B6F1272A7C52C0A7069ACFB95D444014C95702297C52C0CC785BE9B55D4440807F4A95287C52C0567C43E1B35D44407405DB88277C52C0A0C4E74EB05D44400057B263237C52C07E39B35DA15D4440AC8BDB68007C52C0AB90F2936A5D444025E4839ECD7B52C0395E81E8495D444018265305A37B52C0C2DCEEE53E5D44402781CD39787B52C0685721E5275D4440514832AB777B52C0639AE95E275D4440F2599E07777B52C0EC6987BF265D4440F94A2025767B52C0B16B7BBB255D44409485AFAF757B52C088D860E1245D4440893F8A3A737B52C09622F94A205D44408D0C7217617B52C0BF5E61C1FD5C444026C286A7577B52C0D3DA34B6D75C4440FCDD3B6A4C7B52C0D0967329AE5C444030630AD6387B52C082C64CA25E5C444081E7DEC3257B52C0A33B889D295C4440639AE95E277B52C0D47FD6FCF85B44407EC34483147B52C03A394371C75B4440342A70B20D7B52C0D826158DB55B444099EFE0270E7B52C06762BA10AB5B4440D3F36E2C287B52C0350873BB975B4440D427B9C3267B52C07842AF3F895B4440C4245CC8237B52C030D7A205685B4440880CAB78237B52C08B8A389D645B4440902E36AD147B52C0718C648F505B4440AF928FDD057B52C05169C4CC3E5B44407E8978EBFC7A52C0FC1BB4571F5B44409DF0129CFA7A52C05D86FF74035B4440DCD8EC48F57A52C044A51133FB5A444027BD6F7CED7A52C0D769A4A5F25A44406B9C4D47007B52C0E4F4F57CCD5A4440F29881CAF87A52C095D233BDC45A44403F19E3C3EC7A52C05BEB8B84B65A44403468E89FE07A52C0DF14562AA85A4440E0F08288D47A52C0224F92AE995A44403448C153C87A52C0B8E34D7E8B5A44401155F833BC7A52C06C91B41B7D5A44401DE6CB0BB07A52C050C3B7B06E5A444029779FE3A37A52C0A568E55E605A44400584D6C3977A52C0889AE8F3515A44401215AA9B8B7A52C0DD3F16A2435A4440EE21E17B7F7A52C0C1711937355A4440B3EC4960737A52C0E692AAED265A4440D7BFEB33677A52C0CAC4AD82185A4440E350BF0B5B7A52C04EEE77280A5A4440CE18E6046D7A52C001FA7DFFE6594440DAA9B9DC607A52C0B5A7E49CD8594440B7B6F0BC547A52C0DAC87553CA594440DB899290487A52C0ED7E15E0BB594440CB0EF10F5B7A52C0239D819197594440A25EF0694E7A52C0B340BB438A594440BBEB6CC83F7A52C092E9D0E9795944407F68E6C9357A52C033C4B12E6E594440205D6C5A297A52C05DA27A6B605944401B834E081D7A52C065AA605452594440765089EB187A52C0A27895B54D5944402A357BA0157A52C07B4D0F0A4A5944408A5759DB147A52C0F2B1BB404959444097530262127A52C0D0436D1B465944409E5E29CB107A52C0ADA1D45E445944400A630B410E7A52C07F85CC9541594440DB12B9E00C7A52C00F46EC134059444000378B170B7A52C039419B1C3E5944408A20CEC3097A52C06AF981AB3C59444080423D7D047A52C0670C738236594440CAA48636007A52C034677DCA31594440BF44BC75FE7952C0A051BAF42F594440605628D2FD7952C077BE9F1A2F59444093AAED26F87952C0DF87838428594440CFF6E80DF77952C033164D672759444011346612F57952C07C2AA73D2559444001310917F27952C0E8482EFF21594440730CC85EEF7952C05567B5C01E594440984A3FE1EC7952C0B6D782DE1B5944404CE141B3EB7952C0570394861A594440C91CCBBBEA7952C00B9A9658195944408E1EBFB7E97952C08EACFC3218594440A794D74AE87952C08FE046CA165944409677D503E67952C0B41EBE4C145944402EC55565DF7952C0E2E995B20C5944408F52094FE87952C09DF0129CFA58444052EC681CEA7952C06326512FF8584440E02D90A0F87952C0739EB12FD9584440519E7939EC7952C05C8DEC4ACB584440938AC6DADF7952C0A5846055BD5844401666A19DD37952C07C08AA46AF58444029CE5147C77952C0B3942C27A1584440B2666490BB7952C0AEEE586C935844404E232D95B77952C0EDF0D7648D584440A4198BA6B37952C0FC6EBA65875844401E34BBEEAD7952C0179B560A81584440A297512CB77952C0289831056B5844400DE02D90A07952C0B3D0CE6916584440789961A3AC7952C0A6D1E4620C58444076FEEDB25F7952C015713AC956574440D50627A25F7952C06072A3C85A574440E7A562635E7952C0E08096AE6057444012876C205D7952C05AD2510E6657444072C3EFA65B7952C0C4EC65DB69574440FCC6D79E597952C0374D9F1D7057444051D7DAFB547952C0554FE61F7D574440658D7A88467952C04F1DAB949E57444008556AF6407952C04A7D59DAA95744406F9C14E63D7952C0A5811FD5B0574440A679C7293A7952C09CC0745AB757444061FBC9181F7952C097A608707A574440B0C91AF5107952C03483F8C08E5744402E36AD14027952C0718BF9B9A1574440D4997B48F87852C089D00836AE574440BBD23252EF7852C090BB085394574440EF8E8CD5E67852C01840F850A2574440EACE13CFD97852C0B6847CD0B35744408C48145AD67852C09012BBB6B7574440E690D442C97852C084B53176C257444063F030ED9B7852C090BA9D7DE5574440DFC0E446917852C0DEE2E13D075844403FFD67CD8F7852C0719010E50B5844401C2785798F7852C0764D486B0C584440B1BE81C98D7852C093FE5E0A0F58444037363B527D7852C0093543AA28584440C3D50110777852C09355116E32584440EEE714E4677852C03387A4164A584440717500C45D7852C07EA5F3E1595844407442E8A04B7852C0E108522976584440211CB3EC497852C0CE35CCD0785844405791D101497852C09D7DE5417A584440CB660E492D7852C0056A3178985844401AC1C6F5EF7752C0B9162D40DB5844400F7C0C569C7752C03EE8D9ACFA584440AC1E300F997752C0828AAA5FE9584440A661F888987752C0C2A38D23D6584440DCBC7152987752C042959A3DD0584440A661F888987752C0302AA913D0584440E7FF55478E7752C05DC2A1B7785844402FFA0AD28C7752C0581CCEFC6A584440DCB930D28B7752C021567F8461584440FB20CB82897752C062D7F6764B58444079909E22877752C0D89942E7355844408C63247B847752C0B58993FB1D584440ACE46377817752C0677E350708584440C6C210397D7752C0B2F4A10BEA57444074B680D07A7752C0909DB7B1D9574440DB317557767752C0077767EDB65744409A7631CD747752C02D7B12D89C5744400D6C9560717752C054FEB5BC72574440FC34EECD6F7752C0A3E6ABE4635744409E7AA4C16D7752C0D1949D7E50574440FE9C82FC6C7752C0E046CA16495744401E4FCB0F5C7752C09B53C90050574440D503E621537752C0E063B0E25457444037DC476E4D7752C032569BFF5757444070ED4449487752C0836C59BE2E57444066F50EB7437752C054C554FA0957444032022A1C417752C0713C9F01F55644404487C091407752C01F7EFE7BF05644406E4E2503407752C05D4C33DDEB56444088F546AD307752C03ECBF3E0EE5644401F0F7D772B7752C04835ECF7C4564440A33B889D297752C026AAB706B656444087A4164A267752C0938E72309B5644403B6F63B3237752C050FD834886564440D7F7E120217752C00D6C956071564440132A38BC207752C07A8A1C226E564440315D88D51F7752C07E8E8F1667564440D4F02DAC1B7752C0ADA415DF505644409E95B4E21B7752C09AE8F35146564440B88D06F0167752C0BB46CB811E564440A435069D107752C0C8E88024EC554440C9703C9F017752C0F01307D0EF55444083DE1B43007752C0855D143DF05544404EB4AB90F27652C0A69718CBF45544401ABE8575E37652C0C214E5D2F855444041649126DE7652C0FACE2F4AD0554440293C6876DD7652C0807D74EACA554440FAD170CADC7652C0779FE3A3C55544403FABCC94D67652C0F58079C8945544405AD76839D07652C0B41D537765554440849ECDAACF7652C0272D5C56615544405DA79196CA7652C0D87F9D9B36554440331477BCC97652C06A10E6762F55444060AB048BC37652C062F20698F95444402D23F59ECA7652C05D6919A9F754444011C30E63D27652C0B8E864A9F554444021C9ACDEE17652C073D87DC7F0544440F0F96184F07652C06FB72407EC5444408577B988EF7652C0DFA5D425E3544440A089B0E1E97652C0C8091346B35444403621AD31E87652C0999CDA19A6544440C763062AE37652C0EF3B86C77E5444401F4AB4E4F17652C0E0D4079277544440E2E65432007752C054E4107173544440FF0241800C7752C061FA5E437054444057B26323107752C0F677B6476F5444402026E1421E7752C00FEB8D5A61544440834F73F2227752C0E3361AC05B544440C2F693313E7752C0C05AB56B4254444097900F7A367752C0780C8FFD2C544440F834272F327752C06684B70721544440C4758C2B2E7752C03D0801F9125444408D959867257752C00E4A9869FB534440E68F696D1A7752C02FF99FFCDD53444022C2BF081A7752C0247F30F0DC534440EF1CCA50157752C03599F1B6D2534440C0B2D2A4147752C06551D845D15344409048DBF8137752C09509BFD4CF53444014419C87137752C0FB027AE1CE534440E5F04927127752C01A84B9DDCB53444092B06F27117752C0DAC87553CA5344407EA65EB7087752C0228C9FC6BD534440A3E4D539067752C065170CAEB9534440C2FA3F87F97652C059F5B9DA8A5344408BFA2477D87652C082A62556465344406403E962D37652C03197546D3753444018B49080D17652C0D5928E72305344404A22FB20CB7652C0765089EB185344402A1900AAB87652C0BE0F070951524440E386DF4DB77652C01F63EE5A425244400F7D772B4B7652C005A568E55E524440FB3F87F9F27552C07D224F92AE5144405793A7ACA67552C0D7C0560916514440BEDA519CA37552C0A44FABE80F514440745B22179C7552C0E2CCAFE600514440DCD6169E977552C00B43E4F4F5504440A93121E6927552C05E807D74EA504440D13FC1C58A7552C056ED9A90D6504440096B63EC847552C0AB92C83EC8504440AE80423D7D7552C04127840EBA50444040F7E5CC767552C0D0967329AE50444089CE328B507552C0162D40DB6A504440C8ED974F567552C05646239F57504440211FF46C567552C03674B33F5050444015713AC9567552C059DC7F643A5044404AB20E47577552C028B682A62550444037AB3E575B7552C0F7AE415F7A4F44408D261763607552C0226C787AA54E444045460724617552C0A94885B1854E4440F62686E4647552C02D978DCEF94D444036AE7FD7677552C018AE0E80B84D4440B9E00CFE7E7552C0B01F6283854D4440446B459BE37552C0C5E23785954C444012A27C410B7652C03C1405FA444C4440588B4F01307652C0B058C345EE4B4440A6457D923B7652C07C28D192C74B44402C9CA4F9637652C0A2957B81594B4440A81ABD1AA07652C0300C5872154B4440FBC8AD49B77652C035272F32014B44404127840EBA7652C02AE109BDFE4A44401DCBBBEA017752C02172FA7ABE4A4440130CE71A667752C0C6A2E9EC644A44400A4B3CA06C7752C0BEF8A23D5E4A4440A5D93C0E837752C06473D53C474A4440FDBCA948857752C06B98A1F1444A4440F0C000C2877752C0F0DE5163424A4440D8817346947752C04450357A354A4440BF28417FA17752C08099EFE0274A44400A2DEBFEB17752C0BCAE5FB01B4A44407FF8F9EFC17752C08C0DDDEC0F4A444053C90050C57752C0B14B546F0D4A44402E71E481C87752C0BF61A2410A4A44401EFB592C457852C09F39EB538E494440056D72F8A47852C06D8E739B7049444036AD1402B97852C0D68BA19C68494440F59F353FFE7852C0BAA0BE654E494440289A07B0C87952C0C58F31772D4944406133C005D97952C0D862B7CF2A494440E1783E03EA7952C04DDA54DD2349444046B3B27DC87A52C06A11514CDE4844402F185C73477B52C0FCE25295B6484440A26131EA5A7B52C06A696E85B04844408499B67F657B52C036902E36AD4844404F8F6D19707B52C0C1C760C5A94844402E1D739EB17B52C02BDCF29194484440F9122A38BC7B52C0B5132521914844401021AE9CBD7B52C080D250A39048444081CEA44DD57B52C0431B800D88484440BBB88D06F07B52C076A38FF980484440B5A50EF27A7C52C07780272D5C484440F7C77BD5CA7C52C08AE5965643484440614D6551D87C52C05CFDD8243F484440E84CDA54DD7C52C03F1878EE3D4844409947FE60E07C52C05774EB353D484440AF0793E2E37C52C0FF5C34643C48444065A54929E87C52C0C45E28603B484440EFAB72A1F27C52C01F12BEF737484440D07D39B35D7D52C0075F984C1548444025AB22DC647D52C03D0801F912484440C39E76F86B7D52C0861C5BCF104844401211FE45D07F52C0F2CEA10C55474440B804E09F528252C0785C548B884644407615527E528252C0DB85E63A8D464440E2E5E95C518252C0BB270F0BB546444089B48D3F518252C0A7203F1BB94644400858AB764D8252C0F294D5743D474440CD565EF23F8252C07D7555A0164944401B28F04E3E8252C0E9F010C64F494440AAB4C5353E8252C0BDC117265349444032CB9E04368252C0F6285C8FC24944405111A7936C8252C09FE238F06A4B44402252D32EA68252C0BC02D193324D44404C50C3B7B08252C0F9F36DC1524D444068075C57CC8252C0ECDCB419A74D4440A31F0DA7CC8252C086E3F90CA84D44409D2E8B89CD8252C0438CD7BCAA4D44402BA1BB24CE8252C00726378AAC4D4440DDE9CE13CF8252C035423F53AF4D4440A774B0FECF8252C0C266800BB24D4440A626C11BD28252C007431D56B84D4440EDD286C3D28252C0DC476E4DBA4D44402638F581E48252C04A5F0839EF4D444074779D0DF98252C0E3C281902C4E4440890629780A8352C016DC0F78604E44408315A75A0B8352C0E5EFDE51634E4440EA793716148352C036E84B6F7F4E44404703780B248352C0C24CDBBFB24E44403046240A2D8352C09BE09BA6CF4E4440A4C00298328352C02D776682E14E444055F833BC598352C09F91088D604F4440B3B27DC85B8352C08922A46E674F444075E789E76C8352C066118AADA04F44400D52F014728352C051F355F2B14F4440C5ABAC6D8A8352C0D4D00660035044403D7E6FD39F8352C05C1ABFF04A5044405051F52B9D8352C042B28009DC504440'::geometry INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundariesbypointandradius (username text, orgname text, geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundariesbypointandradius invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, radius, boundary_id, time_span, overlap_type; + RETURN QUERY SELECT '0106000020E6100000010000000103000000010000001500000083A3E4D5397C52C09946938B315A44404AED45B41D7C52C0785DBF60375A444099F221A81A7C52C0D0EFFB372F5A4440B9C15087157C52C034643C4A255A4440BB438A01127C52C0DE1CAED51E5A44400FECF82F107C52C0876D8B321B5A4440510FD1E80E7C52C0C4D32B65195A44407FDAA84E077C52C0E0675C38105A444092AD2EA7047C52C08E75711B0D5A4440CF2D7425027C52C0A86DC328085A4440EFFCA204FD7B52C07E384888F259444034BC5983F77B52C0205ED72FD8594440E76F4221027C52C0F3A96395D259444081AD122C0E7C52C00ED6FF39CC594440CB63CDC8207C52C031276893C359444047205ED72F7C52C0287D21E4BC594440BD1C76DF317C52C0F8325184D4594440CD1FD3DA347C52C0B0A9F3A8F8594440C72E51BD357C52C0C3651536035A444043024697377C52C028999CDA195A444083A3E4D5397C52C09946938B315A4440'::geometry as the_geom, '36047048900'::text as geom_refs; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getpointsbygeometry (username text, orgname text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getpointsbygeometry invoked with params (%, %, %, %, %, %)', username, orgname, geom, boundary_id, time_span, overlap_type; + RETURN QUERY SELECT '0101000020E610000037CB75821A7C52C0BA8784EFFD594440'::geometry as the_geom, '36047048900'::text as geom_refs; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getpointsbypointandradius (username text, orgname text, geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getpointsbypointandradius invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, radius, boundary_id, time_span, overlap_type; + RETURN QUERY SELECT '0101000020E610000037CB75821A7C52C0BA8784EFFD594440'::geometry as the_geom, '36047048900'::text as geom_refs; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getmeasure (username text, orgname text, geom Geometry, measure_id text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getmeasure invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, measure_id, normalize, boundary_id, time_span; + SELECT 10923.093200390833950::numeric INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getcategory (username text, orgname text, geom Geometry, category_id text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getcategory invoked with params (%, %, %, %, %, %)', username, orgname, geom, category_id, boundary_id, time_span; + SELECT 'Wealthy, urban without Kids'::text INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getuscensusmeasure (username text, orgname text, geom Geometry, name text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getuscensusmeasure invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, name, normalize, boundary_id, time_span; + SELECT 6789.5647735060920500::numeric INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getuscensuscategory (username text, orgname text, geom Geometry, name text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getuscensuscategory invoked with params (%, %, %, %, %, %)', username, orgname, geom, name, boundary_id, time_span; + SELECT 'Wealthy, urban without Kids'::text INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getpopulation (username text, orgname text, geom Geometry, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getpopulation invoked with params (%, %, %, %, %, %)', username, orgname, geom, normalize, boundary_id, time_span; + SELECT 10923.093200390833950::numeric INTO ret; + RETURN ret; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_search (username text, orgname text, search_term text, relevant_boundary text DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_search invoked with params (%, %, %, %)', username, orgname, search_term, relevant_boundary; + RETURN QUERY SELECT 'es.ine.total_pop'::text as id, 'The total number of all people living in a geographic area.'::text as description, 'Total Population'::text as name, 'sum'::text as aggregate, NULL::text as source; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getavailableboundaries (username text, orgname text, geom geometry(Geometry, 4326), timespan text DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getavailableboundaries invoked with params (%, %, %, %)', username, orgname, geom, timespan; + RETURN QUERY SELECT 'us.census.tiger.place'::text as boundary_id, 'Incorporated places are those reported to the Census Bureau as legally in existence as of January 1, 2010, as reported in the latest Boundary and Annexation Survey (BAS), under the laws of their respective states.'::text as description, '2014'::text as timespan, 'obs_7c9493c41fa8f4bd178ab993ea3d5891c1977667'::text as tablename; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getboundariesbygeometry (username text, orgname text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +BEGIN + RAISE NOTICE 'cdb_dataservices_server.obs_getboundariesbygeometry invoked with params (%, %, %, %, %, %)', username, orgname, geom, boundary_id, time_span, overlap_type; + RETURN QUERY SELECT '0106000020E61000000100000001030000000100000019000000DD96C805677C52C0CBD8D0CDFE5A44407A19C5724B7C52C033BF9A03045B4440FF59F3E32F7C52C0CB290131095B4440247EC51A2E7C52C0548B8862F25A44401FF5D72B2C7C52C0CB811E6ADB5A444049F086342A7C52C09CC3B5DAC35A444044679945287C52C01F680586AC5A444012D90759167C52C09430D3F6AF5A44405698BED7107C52C04759BF99985A4440DEE522BE137C52C00664AF777F5A4440F92EA52E197C52C09BA73AE4665A4440C558A65F227C52C0D80DDB16655A4440373465A71F7C52C065A71FD4455A44404AED45B41D7C52C0785DBF60375A444083A3E4D5397C52C09946938B315A4440F2B4FCC0557C52C01FF5D72B2C5A444026C286A7577C52C02BDD5D67435A44405BCF108E597C52C0C651B9895A5A444030D461855B7C52C0D1393FC5715A444065E1EB6B5D7C52C078280AF4895A44403AE63C635F7C52C07D1F0E12A25A44403F6F2A52617C52C05983F755B95A44405C3AE63C637C52C04852D2C3D05A444049810530657C52C0FAEE5696E85A4440DD96C805677C52C0CBD8D0CDFE5A4440'::geometry as the_geom, '36047049300'::text as geom_refs; +END; +$$ LANGUAGE 'plpgsql'; -- Exercise the public and the proxied function -SELECT obs_get_demographic_snapshot('POINT(-87.81406 41.89308)'::geometry); -SELECT obs_get_segment_snapshot('POINT(-87.81406 41.89308)'::geometry); \ No newline at end of file +SELECT obs_get_demographic_snapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '2009 - 2013'::text, '"us.census.tiger".block_group'::text); +SELECT obs_get_segment_snapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '"us.census.tiger".block_group'::text); +SELECT obs_getdemographicsnapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '2009 - 2013', '"us.census.tiger".block_group'::text); +SELECT obs_getsegmentsnapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '"us.census.tiger".block_group'::text); +SELECT obs_getboundary(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'us.census.tiger.census_tract'::text); +SELECT obs_getboundaryid(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'us.census.tiger.census_tract'::text); +SELECT obs_getboundarybyid('36047'::text, 'us.census.tiger.county'::text); +SELECT obs_getboundariesbygeometry(ST_MakeEnvelope(-73.9452409744, 40.6988851644, -73.9280319214, 40.7101254524, 4326), 'us.census.tiger.census_tract'::text); +SELECT obs_getboundariesbypointandradius(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 500, 'us.census.tiger.census_tract'::text); +SELECT obs_getpointsbygeometry(ST_MakeEnvelope(-73.9452409744, 40.6988851644, -73.9280319214, 40.7101254524, 4326), 'us.census.tiger.census_tract'::text); +SELECT obs_getpointsbypointandradius(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 500::numeric, 'us.census.tiger.census_tract'::text); +SELECT obs_getmeasure(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'us.census.acs.B01001001'::text); +SELECT obs_getcategory(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'us.census.spielman_singleton_segments.X10'::text); +SELECT obs_getuscensusmeasure(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'male population'::text); +SELECT obs_getuscensuscategory(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), 'Spielman-Singleton Segments: 10 Clusters'::text); +SELECT obs_getpopulation(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326)); +SELECT obs_search('total_pop'::text); +SELECT obs_getavailableboundaries(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326)); From c7c9e6e284a59f11c2ebfecdec795421eecf50c6 Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Wed, 11 May 2016 11:50:21 +0200 Subject: [PATCH 2/7] Server side new data observatory functions (v0.8.0) --- server/extension/Makefile | 4 +- .../cdb_dataservices_server--0.7.4--0.8.0.sql | 862 ++++++++++++++++++ .../cdb_dataservices_server--0.8.0--0.7.4.sql | 112 +++ .../extension/cdb_dataservices_server.control | 2 +- .../cdb_dataservices_server--0.7.3--0.7.4.sql | 0 .../cdb_dataservices_server--0.7.4--0.7.3.sql | 0 .../cdb_dataservices_server--0.7.4.sql | 0 server/extension/sql/110_data_observatory.sql | 115 --- .../sql/110_data_observatory_augmentation.sql | 397 ++++++++ .../sql/115_data_observatory_exploration.sql | 108 +++ .../sql/120_data_observatory_geometries.sql | 374 ++++++++ server/extension/sql/15_config_helper.sql | 14 + .../expected/100_data_observatory_test.out | 176 ++++ .../test/sql/100_data_observatory_test.sql | 114 ++- .../cartodb_services/metrics/__init__.py | 2 +- .../cartodb_services/metrics/config.py | 76 +- .../cartodb_services/metrics/quota.py | 9 +- server/lib/python/cartodb_services/setup.py | 2 +- .../cartodb_services/test/test_config.py | 2 +- .../cartodb_services/test/test_helper.py | 2 +- 20 files changed, 2216 insertions(+), 155 deletions(-) create mode 100644 server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql create mode 100644 server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql rename server/extension/{ => old_versions}/cdb_dataservices_server--0.7.3--0.7.4.sql (100%) rename server/extension/{ => old_versions}/cdb_dataservices_server--0.7.4--0.7.3.sql (100%) rename server/extension/{ => old_versions}/cdb_dataservices_server--0.7.4.sql (100%) delete mode 100644 server/extension/sql/110_data_observatory.sql create mode 100644 server/extension/sql/110_data_observatory_augmentation.sql create mode 100644 server/extension/sql/115_data_observatory_exploration.sql create mode 100644 server/extension/sql/120_data_observatory_geometries.sql diff --git a/server/extension/Makefile b/server/extension/Makefile index 0acc452..1c869fc 100644 --- a/server/extension/Makefile +++ b/server/extension/Makefile @@ -13,8 +13,8 @@ OLD_VERSIONS = $(wildcard old_versions/*.sql) # @see http://www.postgresql.org/docs/current/static/extend-pgxs.html DATA = $(NEW_EXTENSION_ARTIFACT) \ $(OLD_VERSIONS) \ - cdb_dataservices_server--0.7.3--0.7.4.sql \ - cdb_dataservices_server--0.7.4--0.7.3.sql + cdb_dataservices_server--0.7.4--0.8.0.sql \ + cdb_dataservices_server--0.8.0--0.7.4.sql REGRESS = $(notdir $(basename $(wildcard test/sql/*test.sql))) TEST_DIR = test/ diff --git a/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql b/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql new file mode 100644 index 0000000..2b7bf8b --- /dev/null +++ b/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql @@ -0,0 +1,862 @@ +--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.8.0'" to load this file. \quit + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_obs_config(username text, orgname text) +RETURNS boolean AS $$ + cache_key = "user_obs_config_{0}".format(username) + if cache_key in GD: + return False + else: + from cartodb_services.metrics import ObservatoryConfig + plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection'] + obs_config = ObservatoryConfig(redis_conn, plpy, username, orgname) + GD[cache_key] = obs_config + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + return result +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetDemographicSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + obs_plan = plpy.prepare("SELECT cdb_dataservices_server.OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + return result +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetSegmentSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + measure_id TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetMeasure(geom, measure_id, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + measure_id TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetMeasure($1, $2, $3, $4, $5, $6, $7) as measure;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, measure_id, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['measure'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetMeasure: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + category_id TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetCategory(geom, category_id, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + category_id TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetCategory($1, $2, $3, $4, $5, $6) as category;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, category_id, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['category'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetCategory: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetUSCensusMeasure(geom, name, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetUSCensusMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetUSCensusMeasure($1, $2, $3, $4, $5, $6, $7) as census_measure;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, name, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['census_measure'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetUSCensusMeasure: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetUSCensusCategory(geom, name, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetUSCensusCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetUSCensusCategory($1, $2, $3, $4, $5, $6) as census_category;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, name, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['census_category'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetUSCensusCategory: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPopulation( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetPopulation(geom, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPopulation( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetPopulation($1, $2, $3, $4, $5, $6) as population;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['population'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPopulation: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_Search( + username TEXT, + orgname TEXT, + search_term TEXT, + relevant_boundary TEXT DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_Search(search_term, relevant_boundary); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_Search( + username TEXT, + orgname TEXT, + search_term TEXT, + relevant_boundary TEXT DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_Search($1, $2, $3, $4) as search;", ["text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, search_term, relevant_boundary]) + if result: + resp = [] + for element in result: + id = element['id'] + description = element['description'] + name = element['name'] + aggregate = element['aggregate'] + source = element['source'] + resp.append([id, description, name, aggregate, source]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_Search: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetAvailableBoundaries( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetAvailableBoundaries(geom, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetAvailableBoundaries( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetAvailableBoundaries($1, $2, $3, $4) as available_boundaries;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span]) + if result: + resp = [] + for element in result: + id = element['boundary_id'] + description = element['description'] + tspan = element['time_span'] + tablename = element['tablename'] + resp.append([id, description, tspan, tablename]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetAvailableBoundaries: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundary( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetBoundary(geom, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundary( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundary($1, $2, $3, $4) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundary: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryId( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_OBS_GetBoundaryId(geom, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundaryId( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundaryId($1, $2, $3, $4, $5) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use obs_search: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryById( + username TEXT, + orgname TEXT, + geometry_id TEXT, + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetBoundaryById(geometry_id, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundaryById( + username TEXT, + orgname TEXT, + geometry_id TEXT, + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundaryById($1, $2, $3, $4, $5) as boundary;", ["text", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geometry_id, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundaryById: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetBoundariesByGeometry(geom, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundariesByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetBoundariesByGeometry($1, $2, $3, $4, $5, $6) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundariesByGeometry: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetBoundariesByPointAndRadius(geom, radius, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundariesByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius($1, $2, $3, $4, $5, $6, $7) as boundary;", ["text", "text", "geometry(Point, 4326)", "numeric", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, radius, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundariesByPointAndRadius: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetPointsByGeometry(geom, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPointsByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetPointsByGeometry($1, $2, $3, $4, $5, $6) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPointsByGeometry: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetPointsByPointAndRadius(geom, radius, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPointsByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetPointsByPointAndRadius($1, $2, $3, $4, $5, $6, $7) as boundary;", ["text", "text", "geometry(Point, 4326)", "numeric", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, radius, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPointsByPointAndRadius: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + + diff --git a/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql b/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql new file mode 100644 index 0000000..e8a9f91 --- /dev/null +++ b/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql @@ -0,0 +1,112 @@ +--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.7.4'" to load this file. \quit + +DROP FUNCTION IF EXISTS cdb_dataservices_server._get_obs_config(text, text); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetDemographicSnapshot(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetSegmentSnapshot(TEXT, TEXT, geometry(Geometry, 4326), TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetMeasure(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetMeasure(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetCategory(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetCategory(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetUSCensusMeasure(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetUSCensusMeasure(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetUSCensusCategory(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetUSCensusCategory(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetPopulation(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetPopulation(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_Search(TEXT, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_Search(TEXT, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetAvailableBoundaries(TEXT, TEXT, geometry(Geometry, 4326), TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetAvailableBoundaries(TEXT, TEXT, geometry(Geometry, 4326), TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetBoundary(TEXT, TEXT, geometry(Point, 4326), TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetBoundary(TEXT, TEXT, geometry(Point, 4326), TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetBoundaryId(TEXT, TEXT, geometry(Point, 4326), TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetBoundaryId(TEXT, TEXT, geometry(Point, 4326), TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetBoundaryById(TEXT, TEXT, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetBoundaryById(TEXT, TEXT, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetBoundariesByGeometry(TEXT, TEXT, geometry(Point, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetBoundariesByGeometry(TEXT, TEXT, geometry(Point, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetBoundariesByPointAndRadius(TEXT, TEXT, NUMERIC, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius(TEXT, TEXT, NUMERIC, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetPointsByGeometry(TEXT, TEXT, geometry(Point, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetPointsByGeometry(TEXT, TEXT, geometry(Point, 4326), TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetPointsByPointAndRadius(TEXT, TEXT, geometry(Point, 4326), NUMERIC, TEXT, TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetPointsByPointAndRadius(TEXT, TEXT, geometry(Point, 4326), NUMERIC, TEXT, TEXT, TEXT); + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT '2009 - 2013', + geometry_level TEXT DEFAULT '"us.census.tiger".block_group') +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT '"us.census.tiger".block_group') +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; \ No newline at end of file diff --git a/server/extension/cdb_dataservices_server.control b/server/extension/cdb_dataservices_server.control index cc9db8e..19613d1 100644 --- a/server/extension/cdb_dataservices_server.control +++ b/server/extension/cdb_dataservices_server.control @@ -1,5 +1,5 @@ comment = 'CartoDB dataservices server extension' -default_version = '0.7.4' +default_version = '0.8.0' requires = 'plpythonu, plproxy, postgis, cdb_geocoder' superuser = true schema = cdb_dataservices_server diff --git a/server/extension/cdb_dataservices_server--0.7.3--0.7.4.sql b/server/extension/old_versions/cdb_dataservices_server--0.7.3--0.7.4.sql similarity index 100% rename from server/extension/cdb_dataservices_server--0.7.3--0.7.4.sql rename to server/extension/old_versions/cdb_dataservices_server--0.7.3--0.7.4.sql diff --git a/server/extension/cdb_dataservices_server--0.7.4--0.7.3.sql b/server/extension/old_versions/cdb_dataservices_server--0.7.4--0.7.3.sql similarity index 100% rename from server/extension/cdb_dataservices_server--0.7.4--0.7.3.sql rename to server/extension/old_versions/cdb_dataservices_server--0.7.4--0.7.3.sql diff --git a/server/extension/cdb_dataservices_server--0.7.4.sql b/server/extension/old_versions/cdb_dataservices_server--0.7.4.sql similarity index 100% rename from server/extension/cdb_dataservices_server--0.7.4.sql rename to server/extension/old_versions/cdb_dataservices_server--0.7.4.sql diff --git a/server/extension/sql/110_data_observatory.sql b/server/extension/sql/110_data_observatory.sql deleted file mode 100644 index 1f3075b..0000000 --- a/server/extension/sql/110_data_observatory.sql +++ /dev/null @@ -1,115 +0,0 @@ --- --- Observatory connection config --- --- The purpose of this function is provide to the PL/Proxy functions --- the connection string needed to connect with the current production database - -CREATE OR REPLACE FUNCTION cdb_dataservices_server._obs_server_conn_str( - username TEXT, - orgname TEXT) -RETURNS text AS $$ - 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) - user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] - - return user_obs_snapshot_config.connection_str -$$ LANGUAGE plpythonu; - -CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( - username TEXT, - orgname TEXT, - geom geometry(Geometry, 4326), - time_span TEXT DEFAULT '2009 - 2013', - geometry_level TEXT DEFAULT '"us.census.tiger".block_group') -RETURNS json AS $$ - CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); - SELECT cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); -$$ LANGUAGE plproxy; - -CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( - username TEXT, - orgname TEXT, - geom geometry(Geometry, 4326), - time_span TEXT DEFAULT '2009 - 2013', - geometry_level TEXT DEFAULT '"us.census.tiger".block_group') -RETURNS json AS $$ - from cartodb_services.metrics import QuotaService - 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) - user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] - - quota_service = QuotaService(user_obs_snapshot_config, redis_conn) - if not quota_service.check_user_quota(): - plpy.error('You have reached the limit of your quota') - - try: - obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) - result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) - if result: - quota_service.increment_success_service_use() - return result[0]['snapshot'] - else: - quota_service.increment_empty_service_use() - return None - except BaseException as e: - import sys, traceback - type_, value_, traceback_ = sys.exc_info() - quota_service.increment_failed_service_use() - error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) - plpy.notice(traceback.format_tb(traceback_)) - plpy.error(error_msg) - finally: - quota_service.increment_total_service_use() -$$ LANGUAGE plpythonu; - -CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( - username TEXT, - orgname TEXT, - geom geometry(Geometry, 4326), - geometry_level TEXT DEFAULT '"us.census.tiger".block_group') -RETURNS json AS $$ - CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); - SELECT cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); -$$ LANGUAGE plproxy; - -CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( - username TEXT, - orgname TEXT, - geom geometry(Geometry, 4326), - geometry_level TEXT DEFAULT '"us.census.tiger".block_group') -RETURNS json AS $$ - from cartodb_services.metrics import QuotaService - 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) - user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] - - quota_service = QuotaService(user_obs_snapshot_config, redis_conn) - if not quota_service.check_user_quota(): - plpy.error('You have reached the limit of your quota') - - try: - obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) - result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) - if result: - quota_service.increment_success_service_use() - return result[0]['snapshot'] - else: - quota_service.increment_empty_service_use() - return None - except BaseException as e: - import sys, traceback - type_, value_, traceback_ = sys.exc_info() - quota_service.increment_failed_service_use() - error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) - plpy.notice(traceback.format_tb(traceback_)) - plpy.error(error_msg) - finally: - quota_service.increment_total_service_use() -$$ LANGUAGE plpythonu; diff --git a/server/extension/sql/110_data_observatory_augmentation.sql b/server/extension/sql/110_data_observatory_augmentation.sql new file mode 100644 index 0000000..793958d --- /dev/null +++ b/server/extension/sql/110_data_observatory_augmentation.sql @@ -0,0 +1,397 @@ +-- +-- Observatory connection config +-- +-- The purpose of this function is provide to the PL/Proxy functions +-- the connection string needed to connect with the current production database + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._obs_server_conn_str( + username TEXT, + orgname TEXT) +RETURNS text AS $$ + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + return user_obs_snapshot_config.connection_str +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + return result +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetDemographicSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + obs_plan = plpy.prepare("SELECT cdb_dataservices_server.OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + return result +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetSegmentSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + measure_id TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetMeasure(geom, measure_id, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + measure_id TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetMeasure($1, $2, $3, $4, $5, $6, $7) as measure;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, measure_id, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['measure'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetMeasure: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + category_id TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetCategory(geom, category_id, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + category_id TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetCategory($1, $2, $3, $4, $5, $6) as category;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, category_id, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['category'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetCategory: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetUSCensusMeasure(geom, name, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetUSCensusMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetUSCensusMeasure($1, $2, $3, $4, $5, $6, $7) as census_measure;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, name, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['census_measure'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetUSCensusMeasure: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetUSCensusCategory(geom, name, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetUSCensusCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetUSCensusCategory($1, $2, $3, $4, $5, $6) as census_category;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, name, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['census_category'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetUSCensusCategory: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPopulation( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetPopulation(geom, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPopulation( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetPopulation($1, $2, $3, $4, $5, $6) as population;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['population'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPopulation: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; diff --git a/server/extension/sql/115_data_observatory_exploration.sql b/server/extension/sql/115_data_observatory_exploration.sql new file mode 100644 index 0000000..fbf38cc --- /dev/null +++ b/server/extension/sql/115_data_observatory_exploration.sql @@ -0,0 +1,108 @@ +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_Search( + username TEXT, + orgname TEXT, + search_term TEXT, + relevant_boundary TEXT DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_Search(search_term, relevant_boundary); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_Search( + username TEXT, + orgname TEXT, + search_term TEXT, + relevant_boundary TEXT DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_Search($1, $2, $3, $4);", ["text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, search_term, relevant_boundary]) + if result: + resp = [] + for element in result: + id = element['id'] + description = element['description'] + name = element['name'] + aggregate = element['aggregate'] + source = element['source'] + resp.append([id, description, name, aggregate, source]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [None, None, None, None, None] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_Search: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetAvailableBoundaries( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetAvailableBoundaries(geom, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetAvailableBoundaries( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetAvailableBoundaries($1, $2, $3, $4) as available_boundaries;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span]) + if result: + resp = [] + for element in result: + id = element['boundary_id'] + description = element['description'] + tspan = element['time_span'] + tablename = element['tablename'] + resp.append([id, description, tspan, tablename]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetAvailableBoundaries: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; diff --git a/server/extension/sql/120_data_observatory_geometries.sql b/server/extension/sql/120_data_observatory_geometries.sql new file mode 100644 index 0000000..f61d8e1 --- /dev/null +++ b/server/extension/sql/120_data_observatory_geometries.sql @@ -0,0 +1,374 @@ +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundary( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetBoundary(geom, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundary( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundary($1, $2, $3, $4) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundary: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryId( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_OBS_GetBoundaryId(geom, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundaryId( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundaryId($1, $2, $3, $4, $5) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use obs_search: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryById( + username TEXT, + orgname TEXT, + geometry_id TEXT, + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetBoundaryById(geometry_id, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundaryById( + username TEXT, + orgname TEXT, + geometry_id TEXT, + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundaryById($1, $2, $3, $4, $5) as boundary;", ["text", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geometry_id, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundaryById: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetBoundariesByGeometry(geom, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundariesByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetBoundariesByGeometry($1, $2, $3, $4, $5, $6) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundariesByGeometry: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetBoundariesByPointAndRadius(geom, radius, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundariesByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius($1, $2, $3, $4, $5, $6, $7) as boundary;", ["text", "text", "geometry(Point, 4326)", "numeric", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, radius, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundariesByPointAndRadius: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetPointsByGeometry(geom, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPointsByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetPointsByGeometry($1, $2, $3, $4, $5, $6) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPointsByGeometry: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetPointsByPointAndRadius(geom, radius, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPointsByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetPointsByPointAndRadius($1, $2, $3, $4, $5, $6, $7) as boundary;", ["text", "text", "geometry(Point, 4326)", "numeric", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, radius, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPointsByPointAndRadius: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; diff --git a/server/extension/sql/15_config_helper.sql b/server/extension/sql/15_config_helper.sql index eb038fe..68726ff 100644 --- a/server/extension/sql/15_config_helper.sql +++ b/server/extension/sql/15_config_helper.sql @@ -67,3 +67,17 @@ RETURNS boolean AS $$ GD[cache_key] = obs_snapshot_config return True $$ LANGUAGE plpythonu SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_obs_config(username text, orgname text) +RETURNS boolean AS $$ + cache_key = "user_obs_config_{0}".format(username) + if cache_key in GD: + return False + else: + from cartodb_services.metrics import ObservatoryConfig + plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection'] + obs_config = ObservatoryConfig(redis_conn, plpy, username, orgname) + GD[cache_key] = obs_config + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; diff --git a/server/extension/test/expected/100_data_observatory_test.out b/server/extension/test/expected/100_data_observatory_test.out index 225382d..914991f 100644 --- a/server/extension/test/expected/100_data_observatory_test.out +++ b/server/extension/test/expected/100_data_observatory_test.out @@ -20,3 +20,179 @@ SELECT exists(SELECT * t (1 row) +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getdemographicsnapshot' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getsegmentsnapshot' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getmeasure' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getcategory' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getuscensusmeasure' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getuscensuscategory' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getpopulation' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_search' + AND oidvectortypes(p.proargtypes) = 'text, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getavailableboundaries' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundary' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundaryid' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundarybyid' + AND oidvectortypes(p.proargtypes) = 'text, text, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundariesbygeometry' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundariesbypointandradius' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, numeric, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getpointsbygeometry' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + exists +-------- + t +(1 row) + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getpointsbypointandradius' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, numeric, text, text, text'); + exists +-------- + t +(1 row) + diff --git a/server/extension/test/sql/100_data_observatory_test.sql b/server/extension/test/sql/100_data_observatory_test.sql index 7621cb2..227e10b 100644 --- a/server/extension/test/sql/100_data_observatory_test.sql +++ b/server/extension/test/sql/100_data_observatory_test.sql @@ -10,4 +10,116 @@ SELECT exists(SELECT * INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) WHERE ns.nspname = 'cdb_dataservices_server' AND proname = 'obs_get_segment_snapshot' - AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text'); \ No newline at end of file + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getdemographicsnapshot' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getsegmentsnapshot' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getmeasure' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getcategory' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getuscensusmeasure' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getuscensuscategory' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getpopulation' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_search' + AND oidvectortypes(p.proargtypes) = 'text, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getavailableboundaries' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundary' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundaryid' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundarybyid' + AND oidvectortypes(p.proargtypes) = 'text, text, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundariesbygeometry' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getboundariesbypointandradius' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, numeric, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getpointsbygeometry' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text, text'); + +SELECT exists(SELECT * + FROM pg_proc p + INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) + WHERE ns.nspname = 'cdb_dataservices_server' + AND proname = 'obs_getpointsbypointandradius' + AND oidvectortypes(p.proargtypes) = 'text, text, geometry, numeric, text, text, text'); \ No newline at end of file diff --git a/server/lib/python/cartodb_services/cartodb_services/metrics/__init__.py b/server/lib/python/cartodb_services/cartodb_services/metrics/__init__.py index 0807d55..078bbbd 100644 --- a/server/lib/python/cartodb_services/cartodb_services/metrics/__init__.py +++ b/server/lib/python/cartodb_services/cartodb_services/metrics/__init__.py @@ -1,3 +1,3 @@ -from config import GeocoderConfig, IsolinesRoutingConfig, InternalGeocoderConfig, RoutingConfig, ConfigException, ObservatorySnapshotConfig +from config import GeocoderConfig, IsolinesRoutingConfig, InternalGeocoderConfig, RoutingConfig, ConfigException, ObservatorySnapshotConfig, ObservatoryConfig from quota import QuotaService from user import UserMetricsService diff --git a/server/lib/python/cartodb_services/cartodb_services/metrics/config.py b/server/lib/python/cartodb_services/cartodb_services/metrics/config.py index 141aa90..b1f110f 100644 --- a/server/lib/python/cartodb_services/cartodb_services/metrics/config.py +++ b/server/lib/python/cartodb_services/cartodb_services/metrics/config.py @@ -33,32 +33,11 @@ class ServiceConfig(object): def organization(self): return self._orgname - -class ObservatorySnapshotConfig(ServiceConfig): - - SOFT_LIMIT_KEY = 'soft_obs_snapshot_limit' - QUOTA_KEY = 'obs_snapshot_quota' - PERIOD_END_DATE = 'period_end_date' +class DataObservatoryConfig(ServiceConfig): def __init__(self, redis_connection, db_conn, username, orgname=None): - super(ObservatorySnapshotConfig, self).__init__(redis_connection, db_conn, + super(DataObservatoryConfig, self).__init__(redis_connection, db_conn, username, orgname) - self._period_end_date = date_parse(self._redis_config[self.PERIOD_END_DATE]) - if self.SOFT_LIMIT_KEY in self._redis_config and self._redis_config[self.SOFT_LIMIT_KEY].lower() == 'true': - self._soft_limit = True - else: - self._soft_limit = False - # Mixed config between db and redis. If we don't update all the users - # in redis, we could use the db value as default - if self.QUOTA_KEY in self._redis_config: - self._monthly_quota = float(self._redis_config[self.QUOTA_KEY]) - else: - self._monthly_quota = float(self._db_config.data_observatory_monthly_quota) - self._connection_str = self._db_config.data_observatory_connection_str - - @property - def service_type(self): - return 'obs_snapshot' @property def monthly_quota(self): @@ -76,6 +55,52 @@ class ObservatorySnapshotConfig(ServiceConfig): def connection_str(self): return self._connection_str +class ObservatorySnapshotConfig(DataObservatoryConfig): + + SOFT_LIMIT_KEY = 'soft_obs_snapshot_limit' + QUOTA_KEY = 'obs_snapshot_quota' + PERIOD_END_DATE = 'period_end_date' + + def __init__(self, redis_connection, db_conn, username, orgname=None): + super(ObservatorySnapshotConfig, self).__init__(redis_connection, db_conn, + username, orgname) + self._period_end_date = date_parse(self._redis_config[self.PERIOD_END_DATE]) + if self.SOFT_LIMIT_KEY in self._redis_config and self._redis_config[self.SOFT_LIMIT_KEY].lower() == 'true': + self._soft_limit = True + else: + self._soft_limit = False + self._monthly_quota = 0 + if self.QUOTA_KEY in self._redis_config: + self._monthly_quota = float(self._redis_config[self.QUOTA_KEY]) + self._connection_str = self._db_config.data_observatory_connection_str + + @property + def service_type(self): + return 'obs_snapshot' + +class ObservatoryConfig(DataObservatoryConfig): + + SOFT_LIMIT_KEY = 'soft_obs_general_limit' + QUOTA_KEY = 'obs_general_quota' + PERIOD_END_DATE = 'period_end_date' + + def __init__(self, redis_connection, db_conn, username, orgname=None): + super(ObservatoryConfig, self).__init__(redis_connection, db_conn, + username, orgname) + self._period_end_date = date_parse(self._redis_config[self.PERIOD_END_DATE]) + if self.SOFT_LIMIT_KEY in self._redis_config and self._redis_config[self.SOFT_LIMIT_KEY].lower() == 'true': + self._soft_limit = True + else: + self._soft_limit = False + self._monthly_quota = 0 + if self.QUOTA_KEY in self._redis_config: + self._monthly_quota = float(self._redis_config[self.QUOTA_KEY]) + self._connection_str = self._db_config.data_observatory_connection_str + + @property + def service_type(self): + return 'obs_general' + class RoutingConfig(ServiceConfig): PERIOD_END_DATE = 'period_end_date' @@ -370,7 +395,6 @@ class ServicesDBConfig: raise ConfigException('Data Observatory configuration missing') else: do_conf = json.loads(do_conf_json) - self._data_observatory_monthly_quota = do_conf['monthly_quota'] if self._orgname and self._orgname in do_conf['connection']['whitelist']: self._data_observatory_connection_str = do_conf['connection']['staging'] elif self._username in do_conf['connection']['whitelist']: @@ -434,10 +458,6 @@ class ServicesDBConfig: def geocoder_log_path(self): return self._geocoder_log_path - @property - def data_observatory_monthly_quota(self): - return self._data_observatory_monthly_quota - @property def data_observatory_connection_str(self): return self._data_observatory_connection_str diff --git a/server/lib/python/cartodb_services/cartodb_services/metrics/quota.py b/server/lib/python/cartodb_services/cartodb_services/metrics/quota.py index 2460082..c627769 100644 --- a/server/lib/python/cartodb_services/cartodb_services/metrics/quota.py +++ b/server/lib/python/cartodb_services/cartodb_services/metrics/quota.py @@ -73,9 +73,9 @@ class QuotaChecker: elif re.match('routing_mapzen', self._user_service_config.service_type) is not None: return self.__check_routing_quota() - elif re.match('obs_snapshot', + elif re.match('obs_*', self._user_service_config.service_type) is not None: - return self.__check_obs_snapshot_quota() + return self.__check_data_observatory_quota() else: return False @@ -118,13 +118,14 @@ class QuotaChecker: else: return False - def __check_obs_snapshot_quota(self): + def __check_data_observatory_quota(self): user_quota = self._user_service_config.monthly_quota + soft_limit = self._user_service_config.soft_limit today = date.today() service_type = self._user_service_config.service_type current_used = self._user_service.used_quota(service_type, today) - if (user_quota > 0 and current_used <= user_quota): + if soft_limit or (user_quota > 0 and current_used <= user_quota): return True else: return False diff --git a/server/lib/python/cartodb_services/setup.py b/server/lib/python/cartodb_services/setup.py index 5808b69..3254050 100644 --- a/server/lib/python/cartodb_services/setup.py +++ b/server/lib/python/cartodb_services/setup.py @@ -10,7 +10,7 @@ from setuptools import setup, find_packages setup( name='cartodb_services', - version='0.5.3', + version='0.6.0', description='CartoDB Services API Python Library', diff --git a/server/lib/python/cartodb_services/test/test_config.py b/server/lib/python/cartodb_services/test/test_config.py index 8d980d2..4a639ec 100644 --- a/server/lib/python/cartodb_services/test/test_config.py +++ b/server/lib/python/cartodb_services/test/test_config.py @@ -49,7 +49,7 @@ class TestConfig(TestCase): end_date=yesterday) do_config = ObservatorySnapshotConfig(self.redis_conn, self.plpy_mock, 'test_user') - assert do_config.monthly_quota == 100000 + assert do_config.monthly_quota == 0 assert do_config.soft_limit is False assert do_config.period_end_date.date() == yesterday.date() diff --git a/server/lib/python/cartodb_services/test/test_helper.py b/server/lib/python/cartodb_services/test/test_helper.py index 41d58e4..e13fa65 100644 --- a/server/lib/python/cartodb_services/test/test_helper.py +++ b/server/lib/python/cartodb_services/test/test_helper.py @@ -61,4 +61,4 @@ def _plpy_execute_side_effect(*args, **kwargs): elif args[0] == "SELECT cartodb.CDB_Conf_GetConf('logger_conf') as conf": return [{'conf': '{"geocoder_log_path": "/dev/null"}'}] elif args[0] == "SELECT cartodb.CDB_Conf_GetConf('data_observatory_conf') as conf": - return [{'conf': '{"connection": {"whitelist": ["ethervoid"], "production": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}, "monthly_quota": 100000}'}] + return [{'conf': '{"connection": {"whitelist": ["ethervoid"], "production": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}}'}] From f59217779e0fa21ea0782696377b123658df221a Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Thu, 12 May 2016 11:32:59 +0200 Subject: [PATCH 3/7] New integration tests for data observatory functions --- .../cdb_dataservices_server--0.7.4--0.8.0.sql | 4 +- .../sql/110_data_observatory_augmentation.sql | 2 - .../sql/120_data_observatory_geometries.sql | 2 +- .../test_data_observatory_functions.py | 219 +++++++++++++++++- 4 files changed, 217 insertions(+), 10 deletions(-) diff --git a/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql b/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql index 2b7bf8b..3cd3197 100644 --- a/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql +++ b/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql @@ -36,7 +36,6 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetDemographicSnapshot( geometry_level TEXT DEFAULT NULL) RETURNS json AS $$ from cartodb_services.metrics import QuotaService - 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'] @@ -85,7 +84,6 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetSegmentSnapshot( geometry_level TEXT DEFAULT NULL) RETURNS json AS $$ from cartodb_services.metrics import QuotaService - 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'] @@ -541,7 +539,7 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryId( time_span TEXT DEFAULT NULL) RETURNS TEXT AS $$ CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); - SELECT cdb_observatory.OBS_OBS_GetBoundaryId(geom, boundary_id, time_span); + SELECT cdb_observatory.OBS_GetBoundaryId(geom, boundary_id, time_span); $$ LANGUAGE plproxy; CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundaryId( diff --git a/server/extension/sql/110_data_observatory_augmentation.sql b/server/extension/sql/110_data_observatory_augmentation.sql index 793958d..bf57fcd 100644 --- a/server/extension/sql/110_data_observatory_augmentation.sql +++ b/server/extension/sql/110_data_observatory_augmentation.sql @@ -47,7 +47,6 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetDemographicSnapshot( geometry_level TEXT DEFAULT NULL) RETURNS json AS $$ from cartodb_services.metrics import QuotaService - 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'] @@ -106,7 +105,6 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetSegmentSnapshot( geometry_level TEXT DEFAULT NULL) RETURNS json AS $$ from cartodb_services.metrics import QuotaService - 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'] diff --git a/server/extension/sql/120_data_observatory_geometries.sql b/server/extension/sql/120_data_observatory_geometries.sql index f61d8e1..4281220 100644 --- a/server/extension/sql/120_data_observatory_geometries.sql +++ b/server/extension/sql/120_data_observatory_geometries.sql @@ -55,7 +55,7 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryId( time_span TEXT DEFAULT NULL) RETURNS TEXT AS $$ CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); - SELECT cdb_observatory.OBS_OBS_GetBoundaryId(geom, boundary_id, time_span); + SELECT cdb_observatory.OBS_GetBoundaryId(geom, boundary_id, time_span); $$ LANGUAGE plproxy; CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundaryId( diff --git a/test/integration/test_data_observatory_functions.py b/test/integration/test_data_observatory_functions.py index 8955d50..982fa66 100644 --- a/test/integration/test_data_observatory_functions.py +++ b/test/integration/test_data_observatory_functions.py @@ -16,8 +16,11 @@ class TestDataObservatoryFunctions(TestCase): def test_if_get_demographic_snapshot_is_ok(self): query = "SELECT obs_get_demographic_snapshot(CDB_LatLng(40.704512, -73.936669)) as snapshot;&api_key={0}".format(self.env_variables['api_key']) - snapshot = IntegrationTestHelper.execute_query(self.sql_api_url, query) - assert_not_equal(snapshot['snapshot'], None) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['snapshot'], None) + query = "SELECT obs_GetDemographicSnapshot(CDB_LatLng(40.704512, -73.936669)) as snapshot;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['snapshot'], None) def test_if_get_demographic_snapshot_without_api_key_raise_error(self): query = "SELECT obs_get_demographic_snapshot(CDB_LatLng(40.704512, -73.936669));" @@ -25,11 +28,19 @@ class TestDataObservatoryFunctions(TestCase): IntegrationTestHelper.execute_query(self.sql_api_url, query) except Exception as e: assert_equal(e.message[0], "The api_key must be provided") + query = "SELECT obs_GetDemographicSnapshot(CDB_LatLng(40.704512, -73.936669));" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") def test_if_get_segment_snapshot_is_ok(self): query = "SELECT obs_get_segment_snapshot(CDB_LatLng(40.704512, -73.936669)) as snapshot;&api_key={0}".format(self.env_variables['api_key']) - snapshot = IntegrationTestHelper.execute_query(self.sql_api_url, query) - assert_not_equal(snapshot['snapshot'], None) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['snapshot'], None) + query = "SELECT OBS_GetSegmentSnapshot(CDB_LatLng(40.704512, -73.936669)) as snapshot;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['snapshot'], None) def test_if_get_segment_snapshot_without_api_key_raise_error(self): query = "SELECT obs_get_segment_snapshot(CDB_LatLng(40.704512, -73.936669));" @@ -37,3 +48,203 @@ class TestDataObservatoryFunctions(TestCase): IntegrationTestHelper.execute_query(self.sql_api_url, query) except Exception as e: assert_equal(e.message[0], "The api_key must be provided") + query = "SELECT OBS_GetSegmentSnapshot(CDB_LatLng(40.704512, -73.936669));" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_get_measure_with_point_is_ok(self): + query = "SELECT OBS_GetMeasure(CDB_LatLng(40.704512, -73.936669), 'us.census.acs.B01001001') as measure;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['measure'], None) + assert_not_equal(result['measure'], 10923.097048937793740) + + def test_if_get_measure_with_area_is_ok(self): + query = "SELECT OBS_GetMeasure('0103000020E61000000100000021000000BB366F6D917B52C0E7BB6EA82B5A444067224C85937B52C0810205E70E5A4440596D6342997B52C09BED2952F35944400A96386CA27B52C07B6D31F9D95944402B81A0A8AE7B52C0D16B73D5C3594440C34C397FBD7B52C0D8B5B7C0B1594440CFD90A5ECE7B52C0BE8DD86CA45944405C7E229FE07B52C0A904EE5C9C59444017C1F28EF37B52C05E2745E099594440AE8A3873067C52C0FD62540F9D5944402F272292187C52C05502CBCAA5594440C3F17139297C52C0B3FBC4BCB3594440DDAE56C5377C52C00C46175CC6594440E96AB6A6437C52C0355C94F1DC5944402313AE684C7C52C05340159FF6594440B3B90FB5517C52C031F30168125A44407F43B357537C52C0DF95053B2F5A444059C17840517C52C0D9E08EFC4B5A44406580E8834B7C52C046B5B591675A444035736A5A427C52C0AF9A1AEB805A44402E721C1E367C52C0D226550F975A4440506D5C47277C52C0A2968A24A95A4440507C2868167C52C0D51FCE78B65A4440C4438226047C52C02369F888BE5A4440C9F10C36F17B52C027B1B205C15A4440AABE2451DE7B52C0F5E383D6BD5A44402A18B431CC7B52C01785C11AB55A444018320D8ABB7B52C070265B28A75A4440E28A0EFEAC7B52C09E518C88945A44401D08D61CA17B52C09E8195F27D5A4440D7C3405B987B52C0643CB044645A444047B16D0F937B52C04EC9837B485A4440BB366F6D917B52C0E7BB6EA82B5A4440'::geometry, 'us.census.acs.B01001001') as measure;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['measure'], None) + assert_not_equal(result['measure'], 12327.3133495107) + + def test_if_get_measure_without_api_key_raise_error(self): + query = "SELECT OBS_GetMeasure(CDB_LatLng(40.704512, -73.936669), 'us.census.acs.B01001001');" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_get_category_is_ok(self): + query = "SELECT OBS_GetCategory(CDB_LatLng(40.704512, -73.936669), 'us.census.spielman_singleton_segments.X10', 'us.census.tiger.census_tract', '2009 - 2013') as category;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['category'], None) + assert_equal(result['category'], 'Wealthy, urban without Kids') + + def test_if_get_category_without_api_key_raise_error(self): + query = "SELECT OBS_GetCategory(CDB_LatLng(40.704512, -73.936669), 'us.census.spielman_singleton_segments.X10', 'us.census.tiger.census_tract', '2009 - 2013');" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_get_us_census_measure_with_point_is_ok(self): + query = "SELECT OBS_GetUSCensusMeasure(CDB_LatLng(40.704512, -73.936669), 'male population') as measure;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['measure'], None) + assert_equal(result['measure'], 6789.56716568) + + def test_if_get_us_census_measure_with_area_is_ok(self): + query = "SELECT OBS_GetUSCensusMeasure('0103000020E61000000100000021000000BB366F6D917B52C0E7BB6EA82B5A444067224C85937B52C0810205E70E5A4440596D6342997B52C09BED2952F35944400A96386CA27B52C07B6D31F9D95944402B81A0A8AE7B52C0D16B73D5C3594440C34C397FBD7B52C0D8B5B7C0B1594440CFD90A5ECE7B52C0BE8DD86CA45944405C7E229FE07B52C0A904EE5C9C59444017C1F28EF37B52C05E2745E099594440AE8A3873067C52C0FD62540F9D5944402F272292187C52C05502CBCAA5594440C3F17139297C52C0B3FBC4BCB3594440DDAE56C5377C52C00C46175CC6594440E96AB6A6437C52C0355C94F1DC5944402313AE684C7C52C05340159FF6594440B3B90FB5517C52C031F30168125A44407F43B357537C52C0DF95053B2F5A444059C17840517C52C0D9E08EFC4B5A44406580E8834B7C52C046B5B591675A444035736A5A427C52C0AF9A1AEB805A44402E721C1E367C52C0D226550F975A4440506D5C47277C52C0A2968A24A95A4440507C2868167C52C0D51FCE78B65A4440C4438226047C52C02369F888BE5A4440C9F10C36F17B52C027B1B205C15A4440AABE2451DE7B52C0F5E383D6BD5A44402A18B431CC7B52C01785C11AB55A444018320D8ABB7B52C070265B28A75A4440E28A0EFEAC7B52C09E518C88945A44401D08D61CA17B52C09E8195F27D5A4440D7C3405B987B52C0643CB044645A444047B16D0F937B52C04EC9837B485A4440BB366F6D917B52C0E7BB6EA82B5A4440'::geometry, 'male population') as measure;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['measure'], None) + assert_equal(result['measure'], 6043.63061043) + + def test_if_get_us_census_measure_without_api_key_raise_error(self): + query = "SELECT OBS_GetUSCensusMeasure('0103000020E61000000100000021000000BB366F6D917B52C0E7BB6EA82B5A444067224C85937B52C0810205E70E5A4440596D6342997B52C09BED2952F35944400A96386CA27B52C07B6D31F9D95944402B81A0A8AE7B52C0D16B73D5C3594440C34C397FBD7B52C0D8B5B7C0B1594440CFD90A5ECE7B52C0BE8DD86CA45944405C7E229FE07B52C0A904EE5C9C59444017C1F28EF37B52C05E2745E099594440AE8A3873067C52C0FD62540F9D5944402F272292187C52C05502CBCAA5594440C3F17139297C52C0B3FBC4BCB3594440DDAE56C5377C52C00C46175CC6594440E96AB6A6437C52C0355C94F1DC5944402313AE684C7C52C05340159FF6594440B3B90FB5517C52C031F30168125A44407F43B357537C52C0DF95053B2F5A444059C17840517C52C0D9E08EFC4B5A44406580E8834B7C52C046B5B591675A444035736A5A427C52C0AF9A1AEB805A44402E721C1E367C52C0D226550F975A4440506D5C47277C52C0A2968A24A95A4440507C2868167C52C0D51FCE78B65A4440C4438226047C52C02369F888BE5A4440C9F10C36F17B52C027B1B205C15A4440AABE2451DE7B52C0F5E383D6BD5A44402A18B431CC7B52C01785C11AB55A444018320D8ABB7B52C070265B28A75A4440E28A0EFEAC7B52C09E518C88945A44401D08D61CA17B52C09E8195F27D5A4440D7C3405B987B52C0643CB044645A444047B16D0F937B52C04EC9837B485A4440BB366F6D917B52C0E7BB6EA82B5A4440'::geometry, 'male population');" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_get_us_census_category_is_ok(self): + query = "SELECT OBS_GetUSCensusCategory('0103000020E61000000100000021000000BB366F6D917B52C0E7BB6EA82B5A444067224C85937B52C0810205E70E5A4440596D6342997B52C09BED2952F35944400A96386CA27B52C07B6D31F9D95944402B81A0A8AE7B52C0D16B73D5C3594440C34C397FBD7B52C0D8B5B7C0B1594440CFD90A5ECE7B52C0BE8DD86CA45944405C7E229FE07B52C0A904EE5C9C59444017C1F28EF37B52C05E2745E099594440AE8A3873067C52C0FD62540F9D5944402F272292187C52C05502CBCAA5594440C3F17139297C52C0B3FBC4BCB3594440DDAE56C5377C52C00C46175CC6594440E96AB6A6437C52C0355C94F1DC5944402313AE684C7C52C05340159FF6594440B3B90FB5517C52C031F30168125A44407F43B357537C52C0DF95053B2F5A444059C17840517C52C0D9E08EFC4B5A44406580E8834B7C52C046B5B591675A444035736A5A427C52C0AF9A1AEB805A44402E721C1E367C52C0D226550F975A4440506D5C47277C52C0A2968A24A95A4440507C2868167C52C0D51FCE78B65A4440C4438226047C52C02369F888BE5A4440C9F10C36F17B52C027B1B205C15A4440AABE2451DE7B52C0F5E383D6BD5A44402A18B431CC7B52C01785C11AB55A444018320D8ABB7B52C070265B28A75A4440E28A0EFEAC7B52C09E518C88945A44401D08D61CA17B52C09E8195F27D5A4440D7C3405B987B52C0643CB044645A444047B16D0F937B52C04EC9837B485A4440BB366F6D917B52C0E7BB6EA82B5A4440'::geometry, 'Spielman-Singleton Segments: 10 Clusters') as category;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['category'], None) + assert_equal(result['category'], 'Low income, mix of minorities') + + def test_if_get_us_census_category_without_api_key_raise_error(self): + query = "SELECT OBS_GetUSCensusCategory('0103000020E61000000100000021000000BB366F6D917B52C0E7BB6EA82B5A444067224C85937B52C0810205E70E5A4440596D6342997B52C09BED2952F35944400A96386CA27B52C07B6D31F9D95944402B81A0A8AE7B52C0D16B73D5C3594440C34C397FBD7B52C0D8B5B7C0B1594440CFD90A5ECE7B52C0BE8DD86CA45944405C7E229FE07B52C0A904EE5C9C59444017C1F28EF37B52C05E2745E099594440AE8A3873067C52C0FD62540F9D5944402F272292187C52C05502CBCAA5594440C3F17139297C52C0B3FBC4BCB3594440DDAE56C5377C52C00C46175CC6594440E96AB6A6437C52C0355C94F1DC5944402313AE684C7C52C05340159FF6594440B3B90FB5517C52C031F30168125A44407F43B357537C52C0DF95053B2F5A444059C17840517C52C0D9E08EFC4B5A44406580E8834B7C52C046B5B591675A444035736A5A427C52C0AF9A1AEB805A44402E721C1E367C52C0D226550F975A4440506D5C47277C52C0A2968A24A95A4440507C2868167C52C0D51FCE78B65A4440C4438226047C52C02369F888BE5A4440C9F10C36F17B52C027B1B205C15A4440AABE2451DE7B52C0F5E383D6BD5A44402A18B431CC7B52C01785C11AB55A444018320D8ABB7B52C070265B28A75A4440E28A0EFEAC7B52C09E518C88945A44401D08D61CA17B52C09E8195F27D5A4440D7C3405B987B52C0643CB044645A444047B16D0F937B52C04EC9837B485A4440BB366F6D917B52C0E7BB6EA82B5A4440'::geometry, 'Spielman-Singleton Segments: 10 Clusters');" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_get_population_is_ok(self): + query = "SELECT OBS_GetPopulation(CDB_LatLng(40.704512, -73.936669)) as population;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['population'], None) + assert_equal(result['population'], 10923.0970489) + + def test_if_get_population_without_api_key_raise_error(self): + query = "SELECT OBS_GetPopulation(CDB_LatLng(40.704512, -73.936669));" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_search_is_ok(self): + query = "SELECT id FROM OBS_Search('total_pop') LIMIT 1;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['id'], None) + assert_equal(result['id'], 'es.ine.total_pop') + + def test_if_obs_search_without_api_key_raise_error(self): + query = "SELECT id FROM OBS_Search('total_pop') LIMIT 1;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_get_available_boundaries_is_ok(self): + query = "SELECT boundary_id FROM OBS_GetAvailableBoundaries(CDB_LatLng(40.704512, -73.936669)) LIMIT 1;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['boundary_id'], None) + assert_equal(result['boundary_id'], 'us.census.tiger.place') + + def test_if_obs_get_available_boundaries_without_api_key_raise_error(self): + query = "SELECT boundary_id FROM OBS_GetAvailableBoundaries(CDB_LatLng(40.704512, -73.936669)) LIMIT 1;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_get_boundary_is_ok(self): + query = "SELECT OBS_GetBoundary(CDB_LatLng(40.704512, -73.936669), 'us.census.tiger.census_tract') as boundary;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['boundary'], None) + assert_equal(result['boundary'], '0106000020E6100000010000000103000000010000003700000056EF703B347C52C054FF2092215B44401B9AB2D30F7C52C03FE1ECD6325B4440B14B546F0D7C52C0BBCE86FC335B4440730F09DFFB7B52C0B796C9703C5B4440108FC4CBD37B52C0B96C74CE4F5B444001C0B167CF7B52C0ED0BE8853B5B4440C843DFDDCA7B52C05DDDB1D8265B4440A73D25E7C47B52C0D53BDC0E0D5B4440BB5E9A22C07B52C0F8A3A833F75A4440355F251FBB7B52C0B64604E3E05A444008910C39B67B52C098BF42E6CA5A44405227A089B07B52C0F204C24EB15A444024F1F274AE7B52C069E4F38AA75A44402B4A09C1AA7B52C06B63EC84975A4440E199D024B17B52C0546F0D6C955A44403C873254C57B52C02EAC1BEF8E5A44402593533BC37B52C0588AE42B815A4440973AC8EBC17B52C087890629785A44407A6F0C01C07B52C0E1EB6B5D6A5A44401B9B1DA9BE7B52C03F6F2A52615A444088855AD3BC7B52C088669E5C535A4440E1EA0088BB7B52C0E6E95C514A5A44400CE6AF90B97B52C070D05E7D3C5A44401E85EB51B87B52C0B03A72A4335A4440BAF3C473B67B52C09929ADBF255A4440CD920035B57B52C0454AB3791C5A4440F78DAF3DB37B52C0E09BA6CF0E5A4440DBC2F352B17B52C0703FE081015A444015C440D7BE7B52C05E83BEF4F659444041446ADAC57B52C0EFDFBC38F15944405FB1868BDC7B52C0C03E3A75E559444034BC5983F77B52C0205ED72FD8594440EFFCA204FD7B52C07E384888F2594440CF2D7425027C52C0A86DC328085A444092AD2EA7047C52C08E75711B0D5A44407FDAA84E077C52C0E0675C38105A4440510FD1E80E7C52C0C4D32B65195A44400FECF82F107C52C0876D8B321B5A4440BB438A01127C52C0DE1CAED51E5A4440B9C15087157C52C034643C4A255A444099F221A81A7C52C0D0EFFB372F5A44404AED45B41D7C52C0785DBF60375A4440373465A71F7C52C065A71FD4455A4440C558A65F227C52C0D80DDB16655A4440F92EA52E197C52C09BA73AE4665A4440DEE522BE137C52C00664AF777F5A44405698BED7107C52C04759BF99985A444012D90759167C52C09430D3F6AF5A444044679945287C52C01F680586AC5A444049F086342A7C52C09CC3B5DAC35A44401FF5D72B2C7C52C0CB811E6ADB5A4440247EC51A2E7C52C0548B8862F25A4440FF59F3E32F7C52C0CB290131095B4440F96871C6307C52C09605137F145B444056EF703B347C52C054FF2092215B4440') + + def test_if_obs_get_boundary_without_api_key_raise_error(self): + query = "SELECT OBS_GetBoundary(CDB_LatLng(40.704512, -73.936669), 'us.census.tiger.census_tract') as boundary;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_get_boundary_id_is_ok(self): + query = "SELECT OBS_GetBoundaryId(CDB_LatLng(40.704512, -73.936669), 'us.census.tiger.census_tract', '2014') as boundary_id;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['boundary_id'], None) + assert_equal(result['boundary_id'], '36047048500') + + def test_if_obs_get_boundary_id_without_api_key_raise_error(self): + query = "SELECT OBS_GetBoundaryId(CDB_LatLng(40.704512, -73.936669), 'us.census.tiger.census_tract', '2014') as boundary_id;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_get_boundary_by_id_is_ok(self): + query = "SELECT OBS_GetBoundaryById('36047', 'us.census.tiger.county', '2014') as boundary;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['boundary'], None) + assert_equal(result['boundary'], '0106000020E610000001000000010300000001000000930200005051F52B9D8352C042B28009DC50444093C2BCC7998352C0E89E758D965144402EFD4B52998352C09A07B0C8AF514440E75086AA988352C022FAB5F5D351444027874F3A918352C0A46B26DF6C53444018E945ED7E8352C04D81CCCEA25344401346B3B27D8352C05D50DF32A753444068226C787A8352C08D25AC8DB153444015C8EC2C7A8352C004560E2DB2534440DF8618AF798352C00FD07D39B3534440FEB627486C8352C0DC9E20B1DD534440B98C9B1A688352C05D328E91EC5344408B8A389D648352C0929048DBF853444075CAA31B618352C0986A662D05544440EA758BC0588352C0D6C397892254444048DFA469508352C0151DC9E53F544440B67F65A5498352C0F73DEAAF575444401403249A408352C05E2A36E6755444402367614F3B8352C06DE2E47E8754444011FC6F253B8352C0431B800D885444403E7958A8358352C0DD0A6135965444401D739EB12F8352C093DFA293A5544440FB04508C2C8352C035289A07B05444401EA4A7C8218352C0347F4C6BD3544440D7C05609168352C05053CBD6FA544440AC8E1CE90C8352C0C9AA083719554440FC8D76DCF08252C0BD18CA897655444048895DDBDB8252C0C3B7B06EBC554440698995D1C88252C032207BBDFB55444004A73E90BC8252C0DB4C857824564440BC1FB75F3E8252C08F368E588B574440E15D2EE23B8252C066F4A3E194574440C614AC71368252C0381268B0A9574440CEA44DD53D8152C04F1F813FFC564440A51133FB3C8152C0F607CA6DFB56444070D05E7D3C8152C0CB0C1B65FD564440C5C6BC8E388152C0F303577902574440EA043411368152C03F390A1005574440840B7904378152C0D34ECDE506574440390A1005338152C047E350BF0B5744405D143DF0318152C0D53BDC0E0D5744401D59F965308152C00A4966F50E574440236420CF2E8152C00FD253E41057444084EE92382B8152C0AD2D3C2F15574440E23D0796238152C0A304FD851E574440B3EDB435228152C001D9EBDD1F5744401EBE4C14218152C08BDCD3D51D574440A2D0B2EE1F8152C0FC1BB4571F57444007B0C8AF1F8152C0CC9717601F574440F678211D1E8152C0374E0AF31E5744401A69A9BC1D8152C0793D98141F574440102384471B8152C0CB2F833122574440B7EEE6A90E8152C09F1D705D315744405968E7340B8152C02C0E677E355744400E4A9869FB8052C0C91EA166485744401B2C9CA4F98052C05C001AA54B5744401AF8510DFB8052C0C51A2E724F574440925CFE43FA8052C0309DD66D50574440BB9866BAD78052C0035DFB027A574440A04FE449D28052C02920ED7F80574440DC9BDF30D18052C0E8305F5E80574440B43C0FEECE8052C0D8614CFA7B5744404AEEB089CC8052C0950A2AAA7E5744409A5B21ACC68052C032FE7DC6855744406682E15CC38052C01EF7ADD689574440F78DAF3DB38052C020CD58349D5744402FFA0AD28C8052C00919C8B3CB574440D0251C7A8B8052C00EA2B5A2CD57444001DE02098A8052C030444E5FCF5744404A404CC2858052C0992A1895D45744403480B740828052C0A33CF372D857444028ECA2E8818052C0CD0358E4D7574440F3AACE6A818052C074ECA012D75744402920ED7F808052C0DFA293A5D657444036E84B6F7F8052C092054CE0D6574440AD4CF8A57E8052C0E55FCB2BD757444042CA4FAA7D8052C01AA19FA9D7574440A2EC2DE57C8052C0205ED72FD8574440BB6246787B8052C08BE07F2BD95744405C74B2D47A8052C025E7C41EDA5744405CA8FC6B798052C0F52EDE8FDB574440FF0758AB768052C09AAF928FDD574440A60A4625758052C0C442AD69DE574440A73E90BC738052C05E49F25CDF574440BF9A0304738052C046ED7E15E0574440A19BFD81728052C070B4E386DF5744403D0AD7A3708052C0D0F0660DDE574440680586AC6E8052C04D469561DC57444063963D096C8052C0965AEF37DA574440944E24986A8052C0BA641C23D957444059501894698052C014B01D8CD8574440E21FB6F4688052C0614D6551D85744401895D409688052C0205ED72FD85744406379573D608052C0A4A487A1D55744401878EE3D5C8052C041B5C189E85744402F4FE78A528052C0A580B4FF01584440983270404B8052C0EECEDA6D1758444050357A35408052C0E3C281902C58444086C43D963E8052C0DC9DB5DB2E584440C5E061DA378052C0BFF2203D455844409946938B318052C0C4E9245B5D5844407C478D09318052C040A374E95F584440E3A8DC442D8052C0F92AF9D85D584440919C4CDC2A8052C06BD26D895C584440276893C3278052C0E9279CDD5A58444053B131AF238052C061C092AB5858444055336B29208052C068E55E605658444091990B5C1E8052C082C64CA25E584440AA2688BA0F8052C027F6D03E56584440F488D1730B8052C0D21C59F9655844400C1CD0D2158052C0BB96900F7A584440C6A69542208052C0B77BB94F8E584440D3A23EC91D8052C02EC901BB9A584440B6BDDD921C8052C0BF42E6CAA058444082E49D43198052C036902E36AD58444072FBE593158052C0ACA92C0ABB5844402B4F20EC148052C0EC3026FDBD584440E4BCFF8F138052C04E266E15C4584440C26856B60F8052C06E15C440D7584440C404357C0B8052C00F5EBBB4E1584440397CD289048052C0CA87A06AF4584440FB761211FE7F52C090F7AA9509594440D93C0E83F97F52C03561FBC9185944402828452BF77F52C0F06DFAB31F594440F9BD4D7FF67F52C0DC9A745B225944403AADDBA0F67F52C0BE4D7FF62359444093C49272F77F52C0526342CC25594440450DA661F87F52C0798EC87729594440F2CCCB61F77F52C0067FBF982D5944409B030473F47F52C017821C94305944401E300F99F27F52C05609168733594440E57FF277EF7F52C0EDBAB72231594440A3AA09A2EE7F52C0EA1ED95C355944405D18E945ED7F52C0D3F6AFAC345944401C5DA5BBEB7F52C076DB85E63A5944404BADF71BED7F52C0B1D991EA3B5944401F477364E57F52C0E48409A35959444022179CC1DF7F52C001D8800871594440A4703D0AD77F52C02EC6C03A8E594440457F68E6C97F52C061C26856B659444070404B57B07F52C0FCDEA63FFB594440DC10E335AF7F52C048E00F3FFF59444055F7C8E6AA7F52C02DB4739A055A4440A4E2FF8EA87F52C00CFFE9060A5A44407E8AE3C0AB7F52C0EC4960730E5A444006F2ECF2AD7F52C08CD99255115A444042588D25AC7F52C09BA8A5B9155A44405A9A5B21AC7F52C0F4BF5C8B165A44406762BA10AB7F52C0A5BA8097195A4440E5B7E864A97F52C0B6BDDD921C5A44402B4A09C1AA7F52C0499F56D11F5A4440D48041D2A77F52C0177FDB13245A4440C22FF5F3A67F52C0D55B035B255A4440FE7BF0DAA57F52C0F8FD9B17275A44409A046F48A37F52C04FADBEBA2A5A444045F12A6B9B7F52C0AC1919E42E5A44404BE2AC889A7F52C0A75CE15D2E5A4440462575029A7F52C0965984622B5A4440E75086AA987F52C0906802452C5A44400B2769FE987F52C05FB01BB62D5A444004029D499B7F52C0DD2230D6375A44404301DBC1887F52C0CBF10A444F5A4440D6A88768747F52C0B81E85EB515A44407C0C569C6A7F52C0F6CFD380415A4440CB113290677F52C0A9328CBB415A44407905A227657F52C03D7C9928425A44407EA5F3E1597F52C0787AA52C435A444009F7CABC557F52C0A2410A9E425A44408D23D6E2537F52C00EF8FC30425A444029780AB9527F52C08B19E1ED415A44402992AF04527F52C08B19E1ED415A4440C51A2E724F7F52C08B19E1ED415A4440AC36FFAF3A7F52C01AA6B6D4415A444009522976347F52C0A2410A9E425A4440F25D4A5D327F52C0252026E1425A44408252B4722F7F52C05A61FA5E435A444032E202D0287F52C013B534B7425A4440E0BBCD1B277F52C014E97E4E415A44409352D0ED257F52C0151DC9E53F5A444022F94A20257F52C0B08BA2073E5A4440CF9ECBD4247F52C0F3AE7AC03C5A444077A1B94E237F52C0F3AE7AC03C5A4440DDB419A7217F52C097FBE428405A4440666A12BC217F52C016A243E0485A44408EACFC32187F52C0CD8DE9094B5A44404F05DCF3FC7E52C0B952CF82505A4440D2E0B6B6F07E52C0FFCA4A93525A44404F029B73F07E52C0A7E7DD58505A4440EA3C2AFEEF7E52C020B41EBE4C5A44404A5F0839EF7E52C01AF7E6374C5A4440D462F030ED7E52C055F5F23B4D5A4440825660C8EA7E52C0B5FD2B2B4D5A4440825660C8EA7E52C072DA53724E5A44403C2CD49AE67E52C030B77BB94F5A44400DDC813AE57E52C0D76B7A50505A4440670DDE57E57E52C0072461DF4E5A4440C77DAB75E27E52C0A25EF0694E5A4440ABB2EF8AE07E52C04F04711E4E5A44403A3FC571E07E52C03C65355D4F5A4440643A747ADE7E52C04ED026874F5A444077F35487DC7E52C08A027D224F5A4440F0A5F0A0D97E52C031EBC5504E5A444068588CBAD67E52C0D8D30E7F4D5A444046B3B27DC87E52C06FB9FAB1495A4440B85A272EC77E52C03C821B295B5A444039CE6DC2BD7E52C097016729595A44409A07B0C8AF7E52C07FD93D79585A44407E8AE3C0AB7E52C0EBC37AA3565A4440C1E10511A97E52C0D097DEFE5C5A44401B82E3326E7E52C03F170D198F5A44408A3C49BA667E52C0D619DF17975A444026DF6C73637E52C07A32FFE89B5A4440E78BBD175F7E52C000FE2955A25A4440594DD7135D7E52C040852348A55A4440E36A64575A7E52C03EE94482A95A4440E603029D497E52C067B62BF4C15A4440ED42739D467E52C04701A260C65A4440253ACB2C427E52C03E40F7E5CC5A4440D026874F3A7E52C061C5A9D6C25A44405C5837DE1D7E52C0868F8829915A4440162EABB0197E52C007B5DFDA895A4440B859BC58187E52C083A279008B5A44408FE046CA167E52C011FB04508C5A4440B131AF230E7E52C0D2C43BC0935A44401A4CC3F0117E52C0F0FACC599F5A44401A321EA5127E52C06631B1F9B85A44402B836A83137E52C0E55C8AABCA5A4440C9737D1F0E7E52C0B376DB85E65A4440D3687231067E52C07405DB88275B444009DE9046057E52C09A94826E2F5B4440158C4AEA047E52C08D7E349C325B4440C808A870047E52C0B6114F76335B4440634337FB037E52C00F290648345B4440DAA7E331037E52C03E7958A8355B444082902C60027E52C0DE3CD521375B4440AB5791D1017E52C048BF7D1D385B4440942F6821017E52C095287B4B395B4440268C6665FB7D52C0548A1D8D435B44405C1B2AC6F97D52C065187783685B4440FA0B3D62F47D52C03FE08101845B4440E2E313B2F37D52C03196E997885B444038F4160FEF7D52C05D50DF32A75B4440109546CCEC7D52C07FDB1324B65B44401C261AA4E07D52C0BA641C23D95B444076BF0AF0DD7D52C06AF7AB00DF5B4440DCB8C5FCDC7D52C0B06F2711E15B44405A0EF450DB7D52C0081F4AB4E45B444084D558C2DA7D52C0F57F0EF3E55B4440BBB20B06D77D52C06E693524EE5B4440CE6BEC12D57D52C0FB592C45F25B444073672618CE7D52C09A0645F3005C4440BB7B80EECB7D52C0C7BAB88D065C4440F5F411F8C37D52C057E9EE3A1B5C44407B8670CCB27D52C09AB4A9BA475C4440240B98C0AD7D52C0282A1BD6545C4440E4839ECDAA7D52C0FA5E43705C5C4440E4805D4D9E7D52C08AAA5FE97C5C44401B2AC6F99B7D52C01C2444F9825C4440D3122BA3917D52C059F8FA5A975C4440A7ACA6EB897D52C0FD2D01F8A75C444007B5DFDA897D52C04818062CB95C44401EF7ADD6897D52C0399A232BBF5C444036397CD2897D52C0904946CEC25C444001DE02098A7D52C08A58C4B0C35C4440CB68E4F38A7D52C0527B116DC75C4440AD4F39268B7D52C0AB92C83EC85C4440531EDD088B7D52C0EB19C231CB5C4440C5C551B9897D52C070EB6E9EEA5C444090847D3B897D52C02E5393E00D5D44409C4CDC2A887D52C01D39D219185D4440FC6EBA65877D52C00D87A5811F5D4440D9CC21A9857D52C0641F6459305D44402D7590D7837D52C0DB4FC6F8305D44409354A698837D52C03FE1ECD6325D44402D5BEB8B847D52C05CC64D0D345D44403A3DEFC6827D52C02C0E677E355D44405299620E827D52C0938C9C853D5D444011AAD4EC817D52C0CE8AA8893E5D44407689EAAD817D52C045BB0A293F5D444094A2957B817D52C02C5F97E13F5D4440EDED96E4807D52C060048D99445D44407C7A6CCB807D52C00551F701485D4440BE69FAEC807D52C0999A046F485D44401781B1BE817D52C0ECF483BA485D444028ECA2E8817D52C0F6D214014E5D44403480B740827D52C07024D060535D4440BD35B055827D52C0CEF8BEB8545D44401C3EE944827D52C03F389F3A565D4440FF243E77827D52C0B534B742585D44407B2C7DE8827D52C02AFD84B35B5D44406F7EC344837D52C0535C55F65D5D4440DA006C40847D52C041F163CC5D5D4440459DB987847D52C0CE15A584605D4440FDBCA948857D52C0F4A44C6A685D44408658FD11867D52C097A608707A5D44404FAF9465887D52C03EC91D36915D4440BD38F1D58E7D52C0CFF753E3A55D44406876DD5B917D52C0F1B6D26BB35D44405B7A34D5937D52C0E4F1B4FCC05D4440B6476FB88F7D52C0C0E78711C25D4440743E3C4B907D52C0A5BBEB6CC85D4440D190F128957D52C03A394371C75D4440ADA06989957D52C0512D228AC95D4440D74D29AF957D52C01BB80375CA5D4440307F85CC957D52C0E542E55FCB5D444042EA76F6957D52C049D40B3ECD5D444054556820967D52C0B3226AA2CF5D44408F6D1970967D52C0C189E8D7D65D4440AD6C1FF2967D52C0F71BEDB8E15D4440BED7101C977D52C0C8B4368DED5D4440D47D00529B7D52C0EBE1CB44115E44403F00A94D9C7D52C068774831405E4440F7393E5A9C7D52C04339D1AE425E44409831056B9C7D52C090A2CEDC435E4440984BAAB69B7D52C02384471B475E4440A547533D997D52C04ED026874F5E44403F170D198F7D52C00E661360585E4440545227A0897D52C0E202D0285D5E4440D3139678407D52C026A435069D5E44406C753925207D52C0CA54C1A8A45E44403B1BF2CF0C7D52C0E17CEA58A55E4440FD12F1D6F97C52C078962023A05E444068C9E369F97C52C0A81ABD1AA05E44406FBA6587F87C52C037A79201A05E44407008556AF67C52C0CC24EA059F5E44404CE141B3EB7C52C0F3FE3F4E985E444003CE52B29C7C52C06C239EEC665E44409AB33EE5987C52C020EEEA55645E4440DFC0E446917C52C0CF6394675E5E444014200A664C7C52C07F315BB22A5E44401D8D43FD2E7C52C0D71533C2DB5D4440C4758C2B2E7C52C09C4B7155D95D4440EE08A7052F7C52C0444B1E4FCB5D444091B6F1272A7C52C0A7069ACFB95D444014C95702297C52C0CC785BE9B55D4440807F4A95287C52C0567C43E1B35D44407405DB88277C52C0A0C4E74EB05D44400057B263237C52C07E39B35DA15D4440AC8BDB68007C52C0AB90F2936A5D444025E4839ECD7B52C0395E81E8495D444018265305A37B52C0C2DCEEE53E5D44402781CD39787B52C0685721E5275D4440514832AB777B52C0639AE95E275D4440F2599E07777B52C0EC6987BF265D4440F94A2025767B52C0B16B7BBB255D44409485AFAF757B52C088D860E1245D4440893F8A3A737B52C09622F94A205D44408D0C7217617B52C0BF5E61C1FD5C444026C286A7577B52C0D3DA34B6D75C4440FCDD3B6A4C7B52C0D0967329AE5C444030630AD6387B52C082C64CA25E5C444081E7DEC3257B52C0A33B889D295C4440639AE95E277B52C0D47FD6FCF85B44407EC34483147B52C03A394371C75B4440342A70B20D7B52C0D826158DB55B444099EFE0270E7B52C06762BA10AB5B4440D3F36E2C287B52C0350873BB975B4440D427B9C3267B52C07842AF3F895B4440C4245CC8237B52C030D7A205685B4440880CAB78237B52C08B8A389D645B4440902E36AD147B52C0718C648F505B4440AF928FDD057B52C05169C4CC3E5B44407E8978EBFC7A52C0FC1BB4571F5B44409DF0129CFA7A52C05D86FF74035B4440DCD8EC48F57A52C044A51133FB5A444027BD6F7CED7A52C0D769A4A5F25A44406B9C4D47007B52C0E4F4F57CCD5A4440F29881CAF87A52C095D233BDC45A44403F19E3C3EC7A52C05BEB8B84B65A44403468E89FE07A52C0DF14562AA85A4440E0F08288D47A52C0224F92AE995A44403448C153C87A52C0B8E34D7E8B5A44401155F833BC7A52C06C91B41B7D5A44401DE6CB0BB07A52C050C3B7B06E5A444029779FE3A37A52C0A568E55E605A44400584D6C3977A52C0889AE8F3515A44401215AA9B8B7A52C0DD3F16A2435A4440EE21E17B7F7A52C0C1711937355A4440B3EC4960737A52C0E692AAED265A4440D7BFEB33677A52C0CAC4AD82185A4440E350BF0B5B7A52C04EEE77280A5A4440CE18E6046D7A52C001FA7DFFE6594440DAA9B9DC607A52C0B5A7E49CD8594440B7B6F0BC547A52C0DAC87553CA594440DB899290487A52C0ED7E15E0BB594440CB0EF10F5B7A52C0239D819197594440A25EF0694E7A52C0B340BB438A594440BBEB6CC83F7A52C092E9D0E9795944407F68E6C9357A52C033C4B12E6E594440205D6C5A297A52C05DA27A6B605944401B834E081D7A52C065AA605452594440765089EB187A52C0A27895B54D5944402A357BA0157A52C07B4D0F0A4A5944408A5759DB147A52C0F2B1BB404959444097530262127A52C0D0436D1B465944409E5E29CB107A52C0ADA1D45E445944400A630B410E7A52C07F85CC9541594440DB12B9E00C7A52C00F46EC134059444000378B170B7A52C039419B1C3E5944408A20CEC3097A52C06AF981AB3C59444080423D7D047A52C0670C738236594440CAA48636007A52C034677DCA31594440BF44BC75FE7952C0A051BAF42F594440605628D2FD7952C077BE9F1A2F59444093AAED26F87952C0DF87838428594440CFF6E80DF77952C033164D672759444011346612F57952C07C2AA73D2559444001310917F27952C0E8482EFF21594440730CC85EEF7952C05567B5C01E594440984A3FE1EC7952C0B6D782DE1B5944404CE141B3EB7952C0570394861A594440C91CCBBBEA7952C00B9A9658195944408E1EBFB7E97952C08EACFC3218594440A794D74AE87952C08FE046CA165944409677D503E67952C0B41EBE4C145944402EC55565DF7952C0E2E995B20C5944408F52094FE87952C09DF0129CFA58444052EC681CEA7952C06326512FF8584440E02D90A0F87952C0739EB12FD9584440519E7939EC7952C05C8DEC4ACB584440938AC6DADF7952C0A5846055BD5844401666A19DD37952C07C08AA46AF58444029CE5147C77952C0B3942C27A1584440B2666490BB7952C0AEEE586C935844404E232D95B77952C0EDF0D7648D584440A4198BA6B37952C0FC6EBA65875844401E34BBEEAD7952C0179B560A81584440A297512CB77952C0289831056B5844400DE02D90A07952C0B3D0CE6916584440789961A3AC7952C0A6D1E4620C58444076FEEDB25F7952C015713AC956574440D50627A25F7952C06072A3C85A574440E7A562635E7952C0E08096AE6057444012876C205D7952C05AD2510E6657444072C3EFA65B7952C0C4EC65DB69574440FCC6D79E597952C0374D9F1D7057444051D7DAFB547952C0554FE61F7D574440658D7A88467952C04F1DAB949E57444008556AF6407952C04A7D59DAA95744406F9C14E63D7952C0A5811FD5B0574440A679C7293A7952C09CC0745AB757444061FBC9181F7952C097A608707A574440B0C91AF5107952C03483F8C08E5744402E36AD14027952C0718BF9B9A1574440D4997B48F87852C089D00836AE574440BBD23252EF7852C090BB085394574440EF8E8CD5E67852C01840F850A2574440EACE13CFD97852C0B6847CD0B35744408C48145AD67852C09012BBB6B7574440E690D442C97852C084B53176C257444063F030ED9B7852C090BA9D7DE5574440DFC0E446917852C0DEE2E13D075844403FFD67CD8F7852C0719010E50B5844401C2785798F7852C0764D486B0C584440B1BE81C98D7852C093FE5E0A0F58444037363B527D7852C0093543AA28584440C3D50110777852C09355116E32584440EEE714E4677852C03387A4164A584440717500C45D7852C07EA5F3E1595844407442E8A04B7852C0E108522976584440211CB3EC497852C0CE35CCD0785844405791D101497852C09D7DE5417A584440CB660E492D7852C0056A3178985844401AC1C6F5EF7752C0B9162D40DB5844400F7C0C569C7752C03EE8D9ACFA584440AC1E300F997752C0828AAA5FE9584440A661F888987752C0C2A38D23D6584440DCBC7152987752C042959A3DD0584440A661F888987752C0302AA913D0584440E7FF55478E7752C05DC2A1B7785844402FFA0AD28C7752C0581CCEFC6A584440DCB930D28B7752C021567F8461584440FB20CB82897752C062D7F6764B58444079909E22877752C0D89942E7355844408C63247B847752C0B58993FB1D584440ACE46377817752C0677E350708584440C6C210397D7752C0B2F4A10BEA57444074B680D07A7752C0909DB7B1D9574440DB317557767752C0077767EDB65744409A7631CD747752C02D7B12D89C5744400D6C9560717752C054FEB5BC72574440FC34EECD6F7752C0A3E6ABE4635744409E7AA4C16D7752C0D1949D7E50574440FE9C82FC6C7752C0E046CA16495744401E4FCB0F5C7752C09B53C90050574440D503E621537752C0E063B0E25457444037DC476E4D7752C032569BFF5757444070ED4449487752C0836C59BE2E57444066F50EB7437752C054C554FA0957444032022A1C417752C0713C9F01F55644404487C091407752C01F7EFE7BF05644406E4E2503407752C05D4C33DDEB56444088F546AD307752C03ECBF3E0EE5644401F0F7D772B7752C04835ECF7C4564440A33B889D297752C026AAB706B656444087A4164A267752C0938E72309B5644403B6F63B3237752C050FD834886564440D7F7E120217752C00D6C956071564440132A38BC207752C07A8A1C226E564440315D88D51F7752C07E8E8F1667564440D4F02DAC1B7752C0ADA415DF505644409E95B4E21B7752C09AE8F35146564440B88D06F0167752C0BB46CB811E564440A435069D107752C0C8E88024EC554440C9703C9F017752C0F01307D0EF55444083DE1B43007752C0855D143DF05544404EB4AB90F27652C0A69718CBF45544401ABE8575E37652C0C214E5D2F855444041649126DE7652C0FACE2F4AD0554440293C6876DD7652C0807D74EACA554440FAD170CADC7652C0779FE3A3C55544403FABCC94D67652C0F58079C8945544405AD76839D07652C0B41D537765554440849ECDAACF7652C0272D5C56615544405DA79196CA7652C0D87F9D9B36554440331477BCC97652C06A10E6762F55444060AB048BC37652C062F20698F95444402D23F59ECA7652C05D6919A9F754444011C30E63D27652C0B8E864A9F554444021C9ACDEE17652C073D87DC7F0544440F0F96184F07652C06FB72407EC5444408577B988EF7652C0DFA5D425E3544440A089B0E1E97652C0C8091346B35444403621AD31E87652C0999CDA19A6544440C763062AE37652C0EF3B86C77E5444401F4AB4E4F17652C0E0D4079277544440E2E65432007752C054E4107173544440FF0241800C7752C061FA5E437054444057B26323107752C0F677B6476F5444402026E1421E7752C00FEB8D5A61544440834F73F2227752C0E3361AC05B544440C2F693313E7752C0C05AB56B4254444097900F7A367752C0780C8FFD2C544440F834272F327752C06684B70721544440C4758C2B2E7752C03D0801F9125444408D959867257752C00E4A9869FB534440E68F696D1A7752C02FF99FFCDD53444022C2BF081A7752C0247F30F0DC534440EF1CCA50157752C03599F1B6D2534440C0B2D2A4147752C06551D845D15344409048DBF8137752C09509BFD4CF53444014419C87137752C0FB027AE1CE534440E5F04927127752C01A84B9DDCB53444092B06F27117752C0DAC87553CA5344407EA65EB7087752C0228C9FC6BD534440A3E4D539067752C065170CAEB9534440C2FA3F87F97652C059F5B9DA8A5344408BFA2477D87652C082A62556465344406403E962D37652C03197546D3753444018B49080D17652C0D5928E72305344404A22FB20CB7652C0765089EB185344402A1900AAB87652C0BE0F070951524440E386DF4DB77652C01F63EE5A425244400F7D772B4B7652C005A568E55E524440FB3F87F9F27552C07D224F92AE5144405793A7ACA67552C0D7C0560916514440BEDA519CA37552C0A44FABE80F514440745B22179C7552C0E2CCAFE600514440DCD6169E977552C00B43E4F4F5504440A93121E6927552C05E807D74EA504440D13FC1C58A7552C056ED9A90D6504440096B63EC847552C0AB92C83EC8504440AE80423D7D7552C04127840EBA50444040F7E5CC767552C0D0967329AE50444089CE328B507552C0162D40DB6A504440C8ED974F567552C05646239F57504440211FF46C567552C03674B33F5050444015713AC9567552C059DC7F643A5044404AB20E47577552C028B682A62550444037AB3E575B7552C0F7AE415F7A4F44408D261763607552C0226C787AA54E444045460724617552C0A94885B1854E4440F62686E4647552C02D978DCEF94D444036AE7FD7677552C018AE0E80B84D4440B9E00CFE7E7552C0B01F6283854D4440446B459BE37552C0C5E23785954C444012A27C410B7652C03C1405FA444C4440588B4F01307652C0B058C345EE4B4440A6457D923B7652C07C28D192C74B44402C9CA4F9637652C0A2957B81594B4440A81ABD1AA07652C0300C5872154B4440FBC8AD49B77652C035272F32014B44404127840EBA7652C02AE109BDFE4A44401DCBBBEA017752C02172FA7ABE4A4440130CE71A667752C0C6A2E9EC644A44400A4B3CA06C7752C0BEF8A23D5E4A4440A5D93C0E837752C06473D53C474A4440FDBCA948857752C06B98A1F1444A4440F0C000C2877752C0F0DE5163424A4440D8817346947752C04450357A354A4440BF28417FA17752C08099EFE0274A44400A2DEBFEB17752C0BCAE5FB01B4A44407FF8F9EFC17752C08C0DDDEC0F4A444053C90050C57752C0B14B546F0D4A44402E71E481C87752C0BF61A2410A4A44401EFB592C457852C09F39EB538E494440056D72F8A47852C06D8E739B7049444036AD1402B97852C0D68BA19C68494440F59F353FFE7852C0BAA0BE654E494440289A07B0C87952C0C58F31772D4944406133C005D97952C0D862B7CF2A494440E1783E03EA7952C04DDA54DD2349444046B3B27DC87A52C06A11514CDE4844402F185C73477B52C0FCE25295B6484440A26131EA5A7B52C06A696E85B04844408499B67F657B52C036902E36AD4844404F8F6D19707B52C0C1C760C5A94844402E1D739EB17B52C02BDCF29194484440F9122A38BC7B52C0B5132521914844401021AE9CBD7B52C080D250A39048444081CEA44DD57B52C0431B800D88484440BBB88D06F07B52C076A38FF980484440B5A50EF27A7C52C07780272D5C484440F7C77BD5CA7C52C08AE5965643484440614D6551D87C52C05CFDD8243F484440E84CDA54DD7C52C03F1878EE3D4844409947FE60E07C52C05774EB353D484440AF0793E2E37C52C0FF5C34643C48444065A54929E87C52C0C45E28603B484440EFAB72A1F27C52C01F12BEF737484440D07D39B35D7D52C0075F984C1548444025AB22DC647D52C03D0801F912484440C39E76F86B7D52C0861C5BCF104844401211FE45D07F52C0F2CEA10C55474440B804E09F528252C0785C548B884644407615527E528252C0DB85E63A8D464440E2E5E95C518252C0BB270F0BB546444089B48D3F518252C0A7203F1BB94644400858AB764D8252C0F294D5743D474440CD565EF23F8252C07D7555A0164944401B28F04E3E8252C0E9F010C64F494440AAB4C5353E8252C0BDC117265349444032CB9E04368252C0F6285C8FC24944405111A7936C8252C09FE238F06A4B44402252D32EA68252C0BC02D193324D44404C50C3B7B08252C0F9F36DC1524D444068075C57CC8252C0ECDCB419A74D4440A31F0DA7CC8252C086E3F90CA84D44409D2E8B89CD8252C0438CD7BCAA4D44402BA1BB24CE8252C00726378AAC4D4440DDE9CE13CF8252C035423F53AF4D4440A774B0FECF8252C0C266800BB24D4440A626C11BD28252C007431D56B84D4440EDD286C3D28252C0DC476E4DBA4D44402638F581E48252C04A5F0839EF4D444074779D0DF98252C0E3C281902C4E4440890629780A8352C016DC0F78604E44408315A75A0B8352C0E5EFDE51634E4440EA793716148352C036E84B6F7F4E44404703780B248352C0C24CDBBFB24E44403046240A2D8352C09BE09BA6CF4E4440A4C00298328352C02D776682E14E444055F833BC598352C09F91088D604F4440B3B27DC85B8352C08922A46E674F444075E789E76C8352C066118AADA04F44400D52F014728352C051F355F2B14F4440C5ABAC6D8A8352C0D4D00660035044403D7E6FD39F8352C05C1ABFF04A5044405051F52B9D8352C042B28009DC504440') + + def test_if_obs_get_boundary_by_id_without_api_key_raise_error(self): + query = "SELECT OBS_GetBoundaryById('36047', 'us.census.tiger.county', '2014') as boundary_id;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_get_boundaries_by_geometry_is_ok(self): + query = "SELECT geom_refs FROM OBS_GetBoundariesByGeometry(ST_MakeEnvelope(-73.9452409744,40.6988851644,-73.9280319214,40.7101254524,4326), 'us.census.tiger.census_tract') ORDER BY geom_refs ASC LIMIT 1;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['geom_refs'], None) + assert_equal(result['geom_refs'], '36047025700') + + def test_if_obs_get_boundaries_by_geometry_without_api_key_raise_error(self): + query = "SELECT geom_refs FROM OBS_GetBoundariesByGeometry(ST_MakeEnvelope(-73.9452409744,40.6988851644,-73.9280319214,40.7101254524,4326), 'us.census.tiger.census_tract') ORDER BY geom_refs ASC LIMIT 1;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_get_boundaries_by_point_and_radius_is_ok(self): + query = "SELECT geom_refs FROM OBS_GetBoundariesByPointAndRadius(CDB_LatLng(40.704512, -73.936669), 500, 'us.census.tiger.census_tract') ORDER BY geom_refs ASC LIMIT 1;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['geom_refs'], None) + assert_equal(result['geom_refs'], '36047038900') + + def test_if_obs_get_boundaries_by_point_and_radius_without_api_key_raise_error(self): + query = "SELECT geom_refs FROM OBS_GetBoundariesByPointAndRadius(CDB_LatLng(40.704512, -73.936669), 500, 'us.census.tiger.census_tract') ORDER BY geom_refs ASC LIMIT 1;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_get_points_by_geometry_is_ok(self): + query = "SELECT geom_refs FROM OBS_GetPointsByGeometry(ST_MakeEnvelope(-73.9452409744,40.6988851644,-73.9280319214,40.7101254524,4326), 'us.census.tiger.census_tract') ORDER BY geom_refs ASC LIMIT 1;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['geom_refs'], None) + assert_equal(result['geom_refs'], '36047025700') + + def test_if_obs_get_points_by_geometry_without_api_key_raise_error(self): + query = "SELECT geom_refs FROM OBS_GetPointsByGeometry(ST_MakeEnvelope(-73.9452409744,40.6988851644,-73.9280319214,40.7101254524,4326), 'us.census.tiger.census_tract') ORDER BY geom_refs ASC LIMIT 1;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + + def test_if_obs_get_points_by_point_and_radius_is_ok(self): + query = "SELECT geom_refs FROM OBS_GetPointsByPointAndRadius(CDB_LatLng(40.704512, -73.936669), 500, 'us.census.tiger.census_tract', '2014') ORDER BY geom_refs ASC LIMIT 1;&api_key={0}".format(self.env_variables['api_key']) + result = IntegrationTestHelper.execute_query(self.sql_api_url, query) + assert_not_equal(result['geom_refs'], None) + assert_equal(result['geom_refs'], '36047038900') + + def test_if_obs_get_points_by_point_and_radius_without_api_key_raise_error(self): + query = "SELECT geom_refs FROM OBS_GetPointsByPointAndRadius(CDB_LatLng(40.704512, -73.936669), 500, 'us.census.tiger.census_tract', '2014') ORDER BY geom_refs ASC LIMIT 1;" + try: + IntegrationTestHelper.execute_query(self.sql_api_url, query) + except Exception as e: + assert_equal(e.message[0], "The api_key must be provided") + From 8680c9cbd093f9d18543cf00bc2f0faed500c8dd Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Thu, 12 May 2016 18:17:26 +0200 Subject: [PATCH 4/7] We let the old qlik snapshots functions but we make new ones with the new snapshot part from observatory' --- .../cdb_dataservices_client--0.4.0--0.5.0.sql | 20 ++--- .../cdb_dataservices_client--0.5.0--0.4.0.sql | 19 +++++ client/renderer/interface.yaml | 6 +- .../expected/90_data_observatory_test.out | 6 +- .../cdb_dataservices_server--0.7.4--0.8.0.sql | 46 +++++++----- .../cdb_dataservices_server--0.8.0--0.7.4.sql | 75 +++---------------- .../sql/110_data_observatory_augmentation.sql | 53 +++++-------- .../expected/100_data_observatory_test.out | 22 ------ .../test/sql/100_data_observatory_test.sql | 14 ---- .../test_data_observatory_functions.py | 16 ---- 10 files changed, 92 insertions(+), 185 deletions(-) diff --git a/client/cdb_dataservices_client--0.4.0--0.5.0.sql b/client/cdb_dataservices_client--0.4.0--0.5.0.sql index ac927b7..d200158 100644 --- a/client/cdb_dataservices_client--0.4.0--0.5.0.sql +++ b/client/cdb_dataservices_client--0.4.0--0.5.0.sql @@ -9,9 +9,9 @@ -- and should also be the only ones with SECURITY DEFINER CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getdemographicsnapshot (geom geometry(Geometry, 4326), time_span text DEFAULT NULL, geometry_level text DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF JSON AS $$ DECLARE - ret json; + username text; orgname text; BEGIN @@ -24,8 +24,8 @@ BEGIN RAISE EXCEPTION 'Username is a mandatory argument, check it out'; END IF; - SELECT cdb_dataservices_client._obs_getdemographicsnapshot(username, orgname, geom, time_span, geometry_level) INTO ret; - RETURN ret; + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getdemographicsnapshot(username, orgname, geom, time_span, geometry_level); END; $$ LANGUAGE 'plpgsql' SECURITY DEFINER; @@ -37,9 +37,9 @@ $$ LANGUAGE 'plpgsql' SECURITY DEFINER; -- and should also be the only ones with SECURITY DEFINER CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getsegmentsnapshot (geom geometry(Geometry, 4326), geometry_level text DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF JSON AS $$ DECLARE - ret json; + username text; orgname text; BEGIN @@ -52,8 +52,8 @@ BEGIN RAISE EXCEPTION 'Username is a mandatory argument, check it out'; END IF; - SELECT cdb_dataservices_client._obs_getsegmentsnapshot(username, orgname, geom, geometry_level) INTO ret; - RETURN ret; + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getsegmentsnapshot(username, orgname, geom, geometry_level); END; $$ LANGUAGE 'plpgsql' SECURITY DEFINER; @@ -452,7 +452,7 @@ $$ LANGUAGE 'plpgsql' SECURITY DEFINER; CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getdemographicsnapshot (username text, organization_name text, geom geometry(Geometry, 4326), time_span text DEFAULT NULL, geometry_level text DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF JSON AS $$ CONNECT cdb_dataservices_client._server_conn_str(); SELECT cdb_dataservices_server.obs_getdemographicsnapshot (username, organization_name, geom, time_span, geometry_level); @@ -460,7 +460,7 @@ RETURNS json AS $$ $$ LANGUAGE plproxy; CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getsegmentsnapshot (username text, organization_name text, geom geometry(Geometry, 4326), geometry_level text DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF JSON AS $$ CONNECT cdb_dataservices_client._server_conn_str(); SELECT cdb_dataservices_server.obs_getsegmentsnapshot (username, organization_name, geom, geometry_level); diff --git a/client/cdb_dataservices_client--0.5.0--0.4.0.sql b/client/cdb_dataservices_client--0.5.0--0.4.0.sql index b8a01be..c412da1 100644 --- a/client/cdb_dataservices_client--0.5.0--0.4.0.sql +++ b/client/cdb_dataservices_client--0.5.0--0.4.0.sql @@ -1,6 +1,25 @@ --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.4.0'" to load this file. \quit +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_get_demographic_snapshot(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_get_segment_snapshot(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getdemographicsnapshot(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getsegmentsnapshot(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundary(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundaryid(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundarybyid(text, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundariesbygeometry(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundariesbypointandradius(geometry, numeric, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getpointsbygeometry(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getpointsbypointandradius(geometry, numeric, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getmeasure(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getcategory(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getuscensusmeasure(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getuscensuscategory(geometry, text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getpopulation(geometry); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_search(text); +DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getavailableboundaries(geometry); + DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_get_demographic_snapshot(geometry); DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_get_segment_snapshot(geometry); DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getdemographicsnapshot(geometry); diff --git a/client/renderer/interface.yaml b/client/renderer/interface.yaml index 7a3ace5..bb0a213 100644 --- a/client/renderer/interface.yaml +++ b/client/renderer/interface.yaml @@ -103,14 +103,16 @@ - { name: geometry_level, type: text, default: 'NULL' } - name: obs_getdemographicsnapshot - return_type: json + return_type: SETOF JSON + multi_row: true params: - { name: geom, type: "geometry(Geometry, 4326)" } - { name: time_span, type: "text", default: 'NULL' } - { name: geometry_level, type: text, default: 'NULL' } - name: obs_getsegmentsnapshot - return_type: json + return_type: SETOF JSON + multi_row: true params: - { name: geom, type: "geometry(Geometry, 4326)" } - { name: geometry_level, type: text, default: 'NULL' } diff --git a/client/test/expected/90_data_observatory_test.out b/client/test/expected/90_data_observatory_test.out index 5e8f8b2..dcbed19 100644 --- a/client/test/expected/90_data_observatory_test.out +++ b/client/test/expected/90_data_observatory_test.out @@ -184,8 +184,7 @@ PL/pgSQL function obs_get_segment_snapshot(geometry,text) line 16 at SQL stateme SELECT obs_getdemographicsnapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '2009 - 2013', '"us.census.tiger".block_group'::text); NOTICE: cdb_dataservices_client._obs_getdemographicsnapshot(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getdemographicsnapshot invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, 2009 - 2013, "us.census.tiger".block_group) -CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getdemographicsnapshot(username, orgname, geom, time_span, geometry_level)" -PL/pgSQL function obs_getdemographicsnapshot(geometry,text,text) line 16 at SQL statement +CONTEXT: PL/pgSQL function obs_getdemographicsnapshot(geometry,text,text) line 16 at RETURN QUERY obs_getdemographicsnapshot ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null} @@ -193,8 +192,7 @@ PL/pgSQL function obs_getdemographicsnapshot(geometry,text,text) line 16 at SQL SELECT obs_getsegmentsnapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '"us.census.tiger".block_group'::text); NOTICE: cdb_dataservices_client._obs_getsegmentsnapshot(4): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getsegmentsnapshot invoked with params (test_user, , 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, "us.census.tiger".block_group) -CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getsegmentsnapshot(username, orgname, geom, geometry_level)" -PL/pgSQL function obs_getsegmentsnapshot(geometry,text) line 16 at SQL statement +CONTEXT: PL/pgSQL function obs_getsegmentsnapshot(geometry,text) line 16 at RETURN QUERY obs_getsegmentsnapshot ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {"total_pop":9516.27915900609,"male_pop":6152.51885204623,"female_pop":3363.76030695986,"median_age":28.8,"white_pop":5301.51624447348,"black_pop":149.500458087105,"asian_pop":230.000704749392,"hispanic_pop":3835.26175169611,"amerindian_pop":0,"other_race_pop":0,"two_or_more_races_pop":0,"not_hispanic_pop":5681.01740730998,"households":3323.51018362871,"pop_25_years_over":7107.02177675621,"high_school_diploma":1040.753188991,"less_one_year_college":69.0002114248176,"one_year_more_college":793.502431385402,"associates_degree":327.751004267883,"bachelors_degree":2742.7584041365,"masters_degree":931.502854235037,"median_income":66304,"gini_index":0.3494,"income_per_capita":28291,"housing_units":3662.76122313407,"vacant_housing_units":339.251039505353,"vacant_housing_units_for_rent":120.750369993431,"vacant_housing_units_for_sale":0,"median_rent":1764,"percent_income_spent_on_rent":35.3,"owner_occupied_housing_units":339.251039505353,"million_dollar_housing_units":0,"mortgaged_housing_units":224.250687130657,"commuters_16_over":6549.27006773893,"commute_less_10_mins":327.751004267883,"commute_10_14_mins":28.750088093674,"commute_15_19_mins":201.250616655718,"commute_20_24_mins":621.001902823358,"commute_25_29_mins":373.751145217762,"commute_30_34_mins":1851.5056732326,"commute_35_44_mins":1414.50433420876,"commute_45_59_mins":1115.50341803455,"commute_60_more_mins":615.251885204623,"aggregate_travel_time_to_work":null,"income_less_10000":57.500176187348,"income_10000_14999":0,"income_15000_19999":212.750651893187,"income_20000_24999":408.251250930171,"income_25000_29999":0,"income_30000_34999":155.25047570584,"income_35000_39999":109.250334755961,"income_40000_44999":92.0002818997568,"income_45000_49999":63.2501938060828,"income_50000_59999":184.000563799514,"income_60000_74999":621.001902823358,"income_75000_99999":552.001691398541,"income_100000_124999":327.751004267883,"income_125000_149999":333.501021886618,"income_150000_199999":126.500387612166,"income_200000_or_more":null,"land_area":null} diff --git a/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql b/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql index 3cd3197..b37b11d 100644 --- a/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql +++ b/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql @@ -1,6 +1,8 @@ --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.8.0'" to load this file. \quit +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetDemographicSnapshot(text, text, geometry(Geometry, 4326), text, text); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetSegmentSnapshot(text, text, geometry(Geometry, 4326), text); CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_obs_config(username text, orgname text) RETURNS boolean AS $$ @@ -16,17 +18,16 @@ RETURNS boolean AS $$ return True $$ LANGUAGE plpythonu SECURITY DEFINER; -CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( username TEXT, orgname TEXT, geom geometry(Geometry, 4326), time_span TEXT DEFAULT NULL, geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ - obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) - result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) - return result -$$ LANGUAGE plpythonu; +RETURNS SETOF json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); +$$ LANGUAGE plproxy; CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetDemographicSnapshot( username TEXT, @@ -34,7 +35,7 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetDemographicSnapshot( geom geometry(Geometry, 4326), time_span TEXT DEFAULT NULL, geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF JSON AS $$ from cartodb_services.metrics import QuotaService plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) @@ -50,11 +51,15 @@ RETURNS json AS $$ obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) if result: + resp = [] + for element in result: + value = element['snapshot'] + resp.append(value) quota_service.increment_success_service_use() - return result[0]['snapshot'] + return resp else: quota_service.increment_empty_service_use() - return None + return [] except BaseException as e: import sys, traceback type_, value_, traceback_ = sys.exc_info() @@ -66,23 +71,22 @@ RETURNS json AS $$ quota_service.increment_total_service_use() $$ LANGUAGE plpythonu; -CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( username TEXT, orgname TEXT, geom geometry(Geometry, 4326), geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ - obs_plan = plpy.prepare("SELECT cdb_dataservices_server.OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) - result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) - return result -$$ LANGUAGE plpythonu; +RETURNS SETOF json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); +$$ LANGUAGE plproxy; CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetSegmentSnapshot( username TEXT, orgname TEXT, geom geometry(Geometry, 4326), geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF JSON AS $$ from cartodb_services.metrics import QuotaService plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) @@ -95,14 +99,18 @@ RETURNS json AS $$ plpy.error('You have reached the limit of your quota') try: - obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) if result: + resp = [] + for element in result: + value = element['snapshot'] + resp.append(value) quota_service.increment_success_service_use() - return result[0]['snapshot'] + return resp else: quota_service.increment_empty_service_use() - return None + return [] except BaseException as e: import sys, traceback type_, value_, traceback_ = sys.exc_info() diff --git a/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql b/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql index e8a9f91..c171819 100644 --- a/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql +++ b/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql @@ -3,7 +3,9 @@ \echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.7.4'" to load this file. \quit DROP FUNCTION IF EXISTS cdb_dataservices_server._get_obs_config(text, text); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetDemographicSnapshot(text, text, geometry(Geometry, 4326), text, text); DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetDemographicSnapshot(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetSegmentSnapshot(text, text, geometry(Geometry, 4326), text); DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetSegmentSnapshot(TEXT, TEXT, geometry(Geometry, 4326), TEXT); DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetMeasure(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT, TEXT); DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetMeasure(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT, TEXT); @@ -34,79 +36,24 @@ DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetPointsByGeometry(TEXT, T DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetPointsByPointAndRadius(TEXT, TEXT, geometry(Point, 4326), NUMERIC, TEXT, TEXT, TEXT); DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetPointsByPointAndRadius(TEXT, TEXT, geometry(Point, 4326), NUMERIC, TEXT, TEXT, TEXT); -CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( username TEXT, orgname TEXT, geom geometry(Geometry, 4326), time_span TEXT DEFAULT '2009 - 2013', geometry_level TEXT DEFAULT '"us.census.tiger".block_group') RETURNS json AS $$ - from cartodb_services.metrics import QuotaService - import json + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); +$$ LANGUAGE plproxy; - 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) - user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] - - quota_service = QuotaService(user_obs_snapshot_config, redis_conn) - if not quota_service.check_user_quota(): - plpy.error('You have reached the limit of your quota') - - try: - obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) - result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) - if result: - quota_service.increment_success_service_use() - return result[0]['snapshot'] - else: - quota_service.increment_empty_service_use() - return None - except BaseException as e: - import sys, traceback - type_, value_, traceback_ = sys.exc_info() - quota_service.increment_failed_service_use() - error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) - plpy.notice(traceback.format_tb(traceback_)) - plpy.error(error_msg) - finally: - quota_service.increment_total_service_use() -$$ LANGUAGE plpythonu; - -CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( username TEXT, orgname TEXT, geom geometry(Geometry, 4326), geometry_level TEXT DEFAULT '"us.census.tiger".block_group') RETURNS json AS $$ - from cartodb_services.metrics import QuotaService - 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) - user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] - - quota_service = QuotaService(user_obs_snapshot_config, redis_conn) - if not quota_service.check_user_quota(): - plpy.error('You have reached the limit of your quota') - - try: - obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) - result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) - if result: - quota_service.increment_success_service_use() - return result[0]['snapshot'] - else: - quota_service.increment_empty_service_use() - return None - except BaseException as e: - import sys, traceback - type_, value_, traceback_ = sys.exc_info() - quota_service.increment_failed_service_use() - error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) - plpy.notice(traceback.format_tb(traceback_)) - plpy.error(error_msg) - finally: - quota_service.increment_total_service_use() -$$ LANGUAGE plpythonu; \ No newline at end of file + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); +$$ LANGUAGE plproxy; \ No newline at end of file diff --git a/server/extension/sql/110_data_observatory_augmentation.sql b/server/extension/sql/110_data_observatory_augmentation.sql index bf57fcd..7b43e79 100644 --- a/server/extension/sql/110_data_observatory_augmentation.sql +++ b/server/extension/sql/110_data_observatory_augmentation.sql @@ -22,30 +22,18 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( geom geometry(Geometry, 4326), time_span TEXT DEFAULT NULL, geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF json AS $$ CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); - SELECT cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); + SELECT * FROM cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); $$ LANGUAGE plproxy; -CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( - username TEXT, - orgname TEXT, - geom geometry(Geometry, 4326), - time_span TEXT DEFAULT NULL, - geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ - obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) - result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) - return result -$$ LANGUAGE plpythonu; - CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetDemographicSnapshot( username TEXT, orgname TEXT, geom geometry(Geometry, 4326), time_span TEXT DEFAULT NULL, geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF JSON AS $$ from cartodb_services.metrics import QuotaService plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) @@ -61,11 +49,15 @@ RETURNS json AS $$ obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) if result: + resp = [] + for element in result: + value = element['snapshot'] + resp.append(value) quota_service.increment_success_service_use() - return result[0]['snapshot'] + return resp else: quota_service.increment_empty_service_use() - return None + return [] except BaseException as e: import sys, traceback type_, value_, traceback_ = sys.exc_info() @@ -82,28 +74,17 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( orgname TEXT, geom geometry(Geometry, 4326), geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF json AS $$ CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); - SELECT cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); + SELECT * FROM cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); $$ LANGUAGE plproxy; -CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( - username TEXT, - orgname TEXT, - geom geometry(Geometry, 4326), - geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ - obs_plan = plpy.prepare("SELECT cdb_dataservices_server.OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) - result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) - return result -$$ LANGUAGE plpythonu; - CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetSegmentSnapshot( username TEXT, orgname TEXT, geom geometry(Geometry, 4326), geometry_level TEXT DEFAULT NULL) -RETURNS json AS $$ +RETURNS SETOF JSON AS $$ from cartodb_services.metrics import QuotaService plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) @@ -116,14 +97,18 @@ RETURNS json AS $$ plpy.error('You have reached the limit of your quota') try: - obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) if result: + resp = [] + for element in result: + value = element['snapshot'] + resp.append(value) quota_service.increment_success_service_use() - return result[0]['snapshot'] + return resp else: quota_service.increment_empty_service_use() - return None + return [] except BaseException as e: import sys, traceback type_, value_, traceback_ = sys.exc_info() diff --git a/server/extension/test/expected/100_data_observatory_test.out b/server/extension/test/expected/100_data_observatory_test.out index 914991f..0cc1ac8 100644 --- a/server/extension/test/expected/100_data_observatory_test.out +++ b/server/extension/test/expected/100_data_observatory_test.out @@ -1,25 +1,3 @@ -SELECT exists(SELECT * - FROM pg_proc p - INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) - WHERE ns.nspname = 'cdb_dataservices_server' - AND proname = 'obs_get_demographic_snapshot' - AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text'); - exists --------- - t -(1 row) - -SELECT exists(SELECT * - FROM pg_proc p - INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) - WHERE ns.nspname = 'cdb_dataservices_server' - AND proname = 'obs_get_segment_snapshot' - AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text'); - exists --------- - t -(1 row) - SELECT exists(SELECT * FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) diff --git a/server/extension/test/sql/100_data_observatory_test.sql b/server/extension/test/sql/100_data_observatory_test.sql index 227e10b..e8b9d85 100644 --- a/server/extension/test/sql/100_data_observatory_test.sql +++ b/server/extension/test/sql/100_data_observatory_test.sql @@ -1,17 +1,3 @@ -SELECT exists(SELECT * - FROM pg_proc p - INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) - WHERE ns.nspname = 'cdb_dataservices_server' - AND proname = 'obs_get_demographic_snapshot' - AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text, text'); - -SELECT exists(SELECT * - FROM pg_proc p - INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) - WHERE ns.nspname = 'cdb_dataservices_server' - AND proname = 'obs_get_segment_snapshot' - AND oidvectortypes(p.proargtypes) = 'text, text, geometry, text'); - SELECT exists(SELECT * FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid) diff --git a/test/integration/test_data_observatory_functions.py b/test/integration/test_data_observatory_functions.py index 982fa66..1ebe647 100644 --- a/test/integration/test_data_observatory_functions.py +++ b/test/integration/test_data_observatory_functions.py @@ -15,19 +15,11 @@ class TestDataObservatoryFunctions(TestCase): ) def test_if_get_demographic_snapshot_is_ok(self): - query = "SELECT obs_get_demographic_snapshot(CDB_LatLng(40.704512, -73.936669)) as snapshot;&api_key={0}".format(self.env_variables['api_key']) - result = IntegrationTestHelper.execute_query(self.sql_api_url, query) - assert_not_equal(result['snapshot'], None) query = "SELECT obs_GetDemographicSnapshot(CDB_LatLng(40.704512, -73.936669)) as snapshot;&api_key={0}".format(self.env_variables['api_key']) result = IntegrationTestHelper.execute_query(self.sql_api_url, query) assert_not_equal(result['snapshot'], None) def test_if_get_demographic_snapshot_without_api_key_raise_error(self): - query = "SELECT obs_get_demographic_snapshot(CDB_LatLng(40.704512, -73.936669));" - try: - IntegrationTestHelper.execute_query(self.sql_api_url, query) - except Exception as e: - assert_equal(e.message[0], "The api_key must be provided") query = "SELECT obs_GetDemographicSnapshot(CDB_LatLng(40.704512, -73.936669));" try: IntegrationTestHelper.execute_query(self.sql_api_url, query) @@ -35,19 +27,11 @@ class TestDataObservatoryFunctions(TestCase): assert_equal(e.message[0], "The api_key must be provided") def test_if_get_segment_snapshot_is_ok(self): - query = "SELECT obs_get_segment_snapshot(CDB_LatLng(40.704512, -73.936669)) as snapshot;&api_key={0}".format(self.env_variables['api_key']) - result = IntegrationTestHelper.execute_query(self.sql_api_url, query) - assert_not_equal(result['snapshot'], None) query = "SELECT OBS_GetSegmentSnapshot(CDB_LatLng(40.704512, -73.936669)) as snapshot;&api_key={0}".format(self.env_variables['api_key']) result = IntegrationTestHelper.execute_query(self.sql_api_url, query) assert_not_equal(result['snapshot'], None) def test_if_get_segment_snapshot_without_api_key_raise_error(self): - query = "SELECT obs_get_segment_snapshot(CDB_LatLng(40.704512, -73.936669));" - try: - IntegrationTestHelper.execute_query(self.sql_api_url, query) - except Exception as e: - assert_equal(e.message[0], "The api_key must be provided") query = "SELECT OBS_GetSegmentSnapshot(CDB_LatLng(40.704512, -73.936669));" try: IntegrationTestHelper.execute_query(self.sql_api_url, query) From 5d6c3d7b11e18b9807dff5a7787e068dd24e57a2 Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Mon, 16 May 2016 10:24:22 +0200 Subject: [PATCH 5/7] Maintain old snapshot functions to avoid break compatibility --- client/renderer/interface.yaml | 6 +- .../cdb_dataservices_server--0.7.4--0.8.0.sql | 98 +++++++++++++++++++ .../cdb_dataservices_server--0.8.0--0.7.4.sql | 81 ++++++++++++++- .../sql/110_data_observatory_augmentation.sql | 98 +++++++++++++++++++ 4 files changed, 279 insertions(+), 4 deletions(-) diff --git a/client/renderer/interface.yaml b/client/renderer/interface.yaml index bb0a213..bb5de02 100644 --- a/client/renderer/interface.yaml +++ b/client/renderer/interface.yaml @@ -93,14 +93,14 @@ return_type: json params: - { name: geom, type: "geometry(Geometry, 4326)" } - - { name: time_span, type: "text", default: 'NULL' } - - { name: geometry_level, type: text, default: 'NULL' } + - { name: time_span, type: "text", default: "'2009 - 2013'::text" } + - { name: geometry_level, type: text, default: "'\"us.census.tiger\".block_group'::text" } - name: obs_get_segment_snapshot return_type: json params: - { name: geom, type: "geometry(Geometry, 4326)" } - - { name: geometry_level, type: text, default: 'NULL' } + - { name: geometry_level, type: text, default: "'\"us.census.tiger\".census_tract'::text" } - name: obs_getdemographicsnapshot return_type: SETOF JSON diff --git a/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql b/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql index b37b11d..718f858 100644 --- a/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql +++ b/server/extension/cdb_dataservices_server--0.7.4--0.8.0.sql @@ -18,6 +18,56 @@ RETURNS boolean AS $$ return True $$ LANGUAGE plpythonu SECURITY DEFINER; +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshotJSON( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshotJSON($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( username TEXT, orgname TEXT, @@ -71,6 +121,54 @@ RETURNS SETOF JSON AS $$ quota_service.increment_total_service_use() $$ LANGUAGE plpythonu; +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshotJSON( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshotJSON($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( username TEXT, orgname TEXT, diff --git a/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql b/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql index c171819..f907e15 100644 --- a/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql +++ b/server/extension/cdb_dataservices_server--0.8.0--0.7.4.sql @@ -4,8 +4,10 @@ DROP FUNCTION IF EXISTS cdb_dataservices_server._get_obs_config(text, text); DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetDemographicSnapshot(text, text, geometry(Geometry, 4326), text, text); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetDemographicSnapshotJSON(text, text, geometry(Geometry, 4326), text, text); DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetDemographicSnapshot(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT); DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetSegmentSnapshot(text, text, geometry(Geometry, 4326), text); +DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetSegmentSnapshotJSON(text, text, geometry(Geometry, 4326), text); DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetSegmentSnapshot(TEXT, TEXT, geometry(Geometry, 4326), TEXT); DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetMeasure(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT, TEXT); DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetMeasure(TEXT, TEXT, geometry(Geometry, 4326), TEXT, TEXT, TEXT, TEXT); @@ -56,4 +58,81 @@ CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( RETURNS json AS $$ CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); SELECT cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); -$$ LANGUAGE plproxy; \ No newline at end of file +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT '2009 - 2013', + geometry_level TEXT DEFAULT '"us.census.tiger".block_group') +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT '"us.census.tiger".block_group') +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; \ No newline at end of file diff --git a/server/extension/sql/110_data_observatory_augmentation.sql b/server/extension/sql/110_data_observatory_augmentation.sql index 7b43e79..6ad4042 100644 --- a/server/extension/sql/110_data_observatory_augmentation.sql +++ b/server/extension/sql/110_data_observatory_augmentation.sql @@ -16,6 +16,56 @@ RETURNS text AS $$ return user_obs_snapshot_config.connection_str $$ LANGUAGE plpythonu; +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshotJSON( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_demographic_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshotJSON($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( username TEXT, orgname TEXT, @@ -69,6 +119,54 @@ RETURNS SETOF JSON AS $$ quota_service.increment_total_service_use() $$ LANGUAGE plpythonu; +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshotJSON( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_get_segment_snapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS json AS $$ + from cartodb_services.metrics import QuotaService + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetSegmentSnapshotJSON($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + if result: + quota_service.increment_success_service_use() + return result[0]['snapshot'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( username TEXT, orgname TEXT, From 22883352e13036c536ba14afd67896e757aede8f Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Mon, 16 May 2016 11:03:57 +0200 Subject: [PATCH 6/7] Version file for client 0.5.0 --- client/cdb_dataservices_client--0.5.0.sql | 1219 +++++++++++++++++++++ 1 file changed, 1219 insertions(+) create mode 100644 client/cdb_dataservices_client--0.5.0.sql diff --git a/client/cdb_dataservices_client--0.5.0.sql b/client/cdb_dataservices_client--0.5.0.sql new file mode 100644 index 0000000..f9fa969 --- /dev/null +++ b/client/cdb_dataservices_client--0.5.0.sql @@ -0,0 +1,1219 @@ +--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 "CREATE EXTENSION cdb_dataservices_client" to load this file. \quit +-- +-- Geocoder server connection config +-- +-- The purpose of this function is provide to the PL/Proxy functions +-- the connection string needed to connect with the server + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._server_conn_str() +RETURNS text AS $$ +DECLARE + db_connection_str text; +BEGIN + SELECT cartodb.cdb_conf_getconf('geocoder_server_config')->'connection_str' INTO db_connection_str; + SELECT trim(both '"' FROM db_connection_str) INTO db_connection_str; + RETURN db_connection_str; +END; +$$ LANGUAGE 'plpgsql';CREATE TYPE cdb_dataservices_client._entity_config AS ( + username text, + organization_name text +); + +-- +-- Get entity config function +-- +-- The purpose of this function is to retrieve the username and organization name from +-- a) schema where he/her is the owner in case is an organization user +-- b) entity_name from the cdb_conf database in case is a non organization user +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_entity_config() +RETURNS record AS $$ +DECLARE + result cdb_dataservices_client._entity_config; + is_organization boolean; + username text; + organization_name text; +BEGIN + SELECT cartodb.cdb_conf_getconf('user_config')->'is_organization' INTO is_organization; + IF is_organization IS NULL THEN + RAISE EXCEPTION 'User must have user configuration in the config table'; + ELSIF is_organization = TRUE THEN + SELECT nspname + FROM pg_namespace s + LEFT JOIN pg_roles r ON s.nspowner = r.oid + WHERE r.rolname = session_user INTO username; + SELECT cartodb.cdb_conf_getconf('user_config')->>'entity_name' INTO organization_name; + ELSE + SELECT cartodb.cdb_conf_getconf('user_config')->>'entity_name' INTO username; + organization_name = NULL; + END IF; + result.username = username; + result.organization_name = organization_name; + RETURN result; +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER;CREATE TYPE cdb_dataservices_client.isoline AS ( + center geometry(Geometry,4326), + data_range integer, + the_geom geometry(Multipolygon,4326) +); + +CREATE TYPE cdb_dataservices_client.simple_route AS ( + shape geometry(LineString,4326), + length real, + duration integer +);-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_admin0_polygon (country_name text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_admin0_polygon(username, orgname, country_name) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_admin1_polygon (admin1_name text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_admin1_polygon(username, orgname, admin1_name) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_admin1_polygon (admin1_name text, country_name text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_admin1_polygon(username, orgname, admin1_name, country_name) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_namedplace_point (city_name text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_namedplace_point(username, orgname, city_name) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_namedplace_point (city_name text, country_name text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_namedplace_point(username, orgname, city_name, country_name) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_namedplace_point (city_name text, admin1_name text, country_name text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_namedplace_point(username, orgname, city_name, admin1_name, country_name) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_postalcode_polygon (postal_code text, country_name text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_postalcode_polygon(username, orgname, postal_code, country_name) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_postalcode_point (postal_code text, country_name text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_postalcode_point(username, orgname, postal_code, country_name) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_ipaddress_point (ip_address text) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_ipaddress_point(username, orgname, ip_address) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_geocode_street_point (searchtext text, city text DEFAULT NULL, state_province text DEFAULT NULL, country text DEFAULT NULL) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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_geocode_street_point(username, orgname, searchtext, city, state_province, country) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_isodistance (source geometry(Geometry, 4326), mode text, range integer[], options text[] DEFAULT ARRAY[]::text[]) +RETURNS SETOF cdb_dataservices_client.isoline AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._cdb_isodistance(username, orgname, source, mode, range, options); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_isochrone (source geometry(Geometry, 4326), mode text, range integer[], options text[] DEFAULT ARRAY[]::text[]) +RETURNS SETOF cdb_dataservices_client.isoline AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._cdb_isochrone(username, orgname, source, mode, range, options); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_route_point_to_point (origin geometry(Point, 4326), destination geometry(Point, 4326), mode text, options text[] DEFAULT ARRAY[]::text[], units text DEFAULT 'kilometers') +RETURNS cdb_dataservices_client.simple_route AS $$ +DECLARE + ret cdb_dataservices_client.simple_route; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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 * FROM cdb_dataservices_client._cdb_route_point_to_point(username, orgname, origin, destination, mode, options, units) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_get_demographic_snapshot (geom geometry(Geometry, 4326), time_span text DEFAULT NULL, geometry_level text DEFAULT NULL) +RETURNS json AS $$ +DECLARE + ret json; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_get_demographic_snapshot(username, orgname, geom, time_span, geometry_level) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_get_segment_snapshot (geom geometry(Geometry, 4326), geometry_level text DEFAULT NULL) +RETURNS json AS $$ +DECLARE + ret json; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_get_segment_snapshot(username, orgname, geom, geometry_level) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getdemographicsnapshot (geom geometry(Geometry, 4326), time_span text DEFAULT NULL, geometry_level text DEFAULT NULL) +RETURNS SETOF JSON AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getdemographicsnapshot(username, orgname, geom, time_span, geometry_level); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getsegmentsnapshot (geom geometry(Geometry, 4326), geometry_level text DEFAULT NULL) +RETURNS SETOF JSON AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getsegmentsnapshot(username, orgname, geom, geometry_level); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundary (geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getboundary(username, orgname, geom, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundaryid (geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getboundaryid(username, orgname, geom, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundarybyid (geometry_id text, boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry AS $$ +DECLARE + ret Geometry; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getboundarybyid(username, orgname, geometry_id, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundariesbygeometry (geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getboundariesbygeometry(username, orgname, geom, boundary_id, time_span, overlap_type); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getboundariesbypointandradius (geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getboundariesbypointandradius(username, orgname, geom, radius, boundary_id, time_span, overlap_type); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getpointsbygeometry (geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getpointsbygeometry(username, orgname, geom, boundary_id, time_span, overlap_type); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getpointsbypointandradius (geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getpointsbypointandradius(username, orgname, geom, radius, boundary_id, time_span, overlap_type); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getmeasure (geom Geometry, measure_id text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getmeasure(username, orgname, geom, measure_id, normalize, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getcategory (geom Geometry, category_id text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getcategory(username, orgname, geom, category_id, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getuscensusmeasure (geom Geometry, name text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getuscensusmeasure(username, orgname, geom, name, normalize, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getuscensuscategory (geom Geometry, name text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ +DECLARE + ret text; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getuscensuscategory(username, orgname, geom, name, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getpopulation (geom Geometry, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ +DECLARE + ret numeric; + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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._obs_getpopulation(username, orgname, geom, normalize, boundary_id, time_span) INTO ret; + RETURN ret; + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_search (search_term text, relevant_boundary text DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_search(username, orgname, search_term, relevant_boundary); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +-- +-- Public dataservices API function +-- +-- These are the only ones with permissions to publicuser role +-- and should also be the only ones with SECURITY DEFINER + +CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getavailableboundaries (geom Geometry, timespan text DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ +DECLARE + + username text; + orgname text; +BEGIN + IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN + RAISE EXCEPTION 'The api_key must be provided'; + END IF; + SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text); + -- 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; + + RETURN QUERY + SELECT * FROM cdb_dataservices_client._obs_getavailableboundaries(username, orgname, geom, timespan); + +END; +$$ LANGUAGE 'plpgsql' SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_admin0_polygon (username text, organization_name text, country_name text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_admin0_polygon (username, organization_name, country_name); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_admin1_polygon (username text, organization_name text, admin1_name text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_admin1_polygon (username, organization_name, admin1_name); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_admin1_polygon (username text, organization_name text, admin1_name text, country_name text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_admin1_polygon (username, organization_name, admin1_name, country_name); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_namedplace_point (username text, organization_name text, city_name text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_namedplace_point (username, organization_name, city_name); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_namedplace_point (username text, organization_name text, city_name text, country_name text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_namedplace_point (username, organization_name, city_name, country_name); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_namedplace_point (username text, organization_name text, city_name text, admin1_name text, country_name text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_namedplace_point (username, organization_name, city_name, admin1_name, country_name); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_postalcode_polygon (username text, organization_name text, postal_code text, country_name text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_postalcode_polygon (username, organization_name, postal_code, country_name); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_postalcode_point (username text, organization_name text, postal_code text, country_name text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_postalcode_point (username, organization_name, postal_code, country_name); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_ipaddress_point (username text, organization_name text, ip_address text) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.cdb_geocode_ipaddress_point (username, organization_name, ip_address); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_geocode_street_point (username text, organization_name 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_geocode_street_point (username, organization_name, searchtext, city, state_province, country); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_isodistance (username text, organization_name text, source geometry(Geometry, 4326), mode text, range integer[], options text[] DEFAULT ARRAY[]::text[]) +RETURNS SETOF cdb_dataservices_client.isoline AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.cdb_isodistance (username, organization_name, source, mode, range, options); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_isochrone (username text, organization_name text, source geometry(Geometry, 4326), mode text, range integer[], options text[] DEFAULT ARRAY[]::text[]) +RETURNS SETOF cdb_dataservices_client.isoline AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.cdb_isochrone (username, organization_name, source, mode, range, options); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_route_point_to_point (username text, organization_name text, origin geometry(Point, 4326), destination geometry(Point, 4326), mode text, options text[] DEFAULT ARRAY[]::text[], units text DEFAULT 'kilometers') +RETURNS cdb_dataservices_client.simple_route AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.cdb_route_point_to_point (username, organization_name, origin, destination, mode, options, units); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_get_demographic_snapshot (username text, organization_name text, geom geometry(Geometry, 4326), time_span text DEFAULT NULL, geometry_level text DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_get_demographic_snapshot (username, organization_name, geom, time_span, geometry_level); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_get_segment_snapshot (username text, organization_name text, geom geometry(Geometry, 4326), geometry_level text DEFAULT NULL) +RETURNS json AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_get_segment_snapshot (username, organization_name, geom, geometry_level); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getdemographicsnapshot (username text, organization_name text, geom geometry(Geometry, 4326), time_span text DEFAULT NULL, geometry_level text DEFAULT NULL) +RETURNS SETOF JSON AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getdemographicsnapshot (username, organization_name, geom, time_span, geometry_level); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getsegmentsnapshot (username text, organization_name text, geom geometry(Geometry, 4326), geometry_level text DEFAULT NULL) +RETURNS SETOF JSON AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getsegmentsnapshot (username, organization_name, geom, geometry_level); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundary (username text, organization_name text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getboundary (username, organization_name, geom, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundaryid (username text, organization_name text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL) +RETURNS text AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getboundaryid (username, organization_name, geom, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundarybyid (username text, organization_name text, geometry_id text, boundary_id text, time_span text DEFAULT NULL) +RETURNS Geometry AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getboundarybyid (username, organization_name, geometry_id, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundariesbygeometry (username text, organization_name text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getboundariesbygeometry (username, organization_name, geom, boundary_id, time_span, overlap_type); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getboundariesbypointandradius (username text, organization_name text, geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getboundariesbypointandradius (username, organization_name, geom, radius, boundary_id, time_span, overlap_type); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getpointsbygeometry (username text, organization_name text, geom geometry(Geometry, 4326), boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getpointsbygeometry (username, organization_name, geom, boundary_id, time_span, overlap_type); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getpointsbypointandradius (username text, organization_name text, geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text DEFAULT NULL, overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getpointsbypointandradius (username, organization_name, geom, radius, boundary_id, time_span, overlap_type); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getmeasure (username text, organization_name text, geom Geometry, measure_id text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getmeasure (username, organization_name, geom, measure_id, normalize, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getcategory (username text, organization_name text, geom Geometry, category_id text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getcategory (username, organization_name, geom, category_id, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getuscensusmeasure (username text, organization_name text, geom Geometry, name text, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getuscensusmeasure (username, organization_name, geom, name, normalize, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getuscensuscategory (username text, organization_name text, geom Geometry, name text, boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS text AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getuscensuscategory (username, organization_name, geom, name, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getpopulation (username text, organization_name text, geom Geometry, normalize text DEFAULT 'area', boundary_id text DEFAULT NULL, time_span text DEFAULT NULL) +RETURNS numeric AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT cdb_dataservices_server.obs_getpopulation (username, organization_name, geom, normalize, boundary_id, time_span); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_search (username text, organization_name text, search_term text, relevant_boundary text DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_search (username, organization_name, search_term, relevant_boundary); + +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getavailableboundaries (username text, organization_name text, geom Geometry, timespan text DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ + CONNECT cdb_dataservices_client._server_conn_str(); + + SELECT * FROM cdb_dataservices_server.obs_getavailableboundaries (username, organization_name, geom, timespan); + +$$ LANGUAGE plproxy; + +-- Make sure by default there are no permissions for publicuser +-- NOTE: this happens at extension creation time, as part of an implicit transaction. +REVOKE ALL PRIVILEGES ON SCHEMA cdb_dataservices_client FROM PUBLIC, publicuser CASCADE; + +-- Grant permissions on the schema to publicuser (but just the schema) +GRANT USAGE ON SCHEMA cdb_dataservices_client TO publicuser; + +-- Revoke execute permissions on all functions in the schema by default +REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_dataservices_client FROM PUBLIC, publicuser;GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_admin0_polygon(country_name text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_admin1_polygon(admin1_name text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_admin1_polygon(admin1_name text, country_name text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_namedplace_point(city_name text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_namedplace_point(city_name text, country_name text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_postalcode_polygon(postal_code text, country_name text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_postalcode_point(postal_code text, country_name text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_ipaddress_point(ip_address text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_geocode_street_point(searchtext text, city text, state_province text, country text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_isodistance(source geometry(Geometry, 4326), mode text, range integer[], options text[]) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_isochrone(source geometry(Geometry, 4326), mode text, range integer[], options text[]) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_route_point_to_point(origin geometry(Point, 4326), destination geometry(Point, 4326), mode text, options text[], units text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_get_demographic_snapshot(geom geometry(Geometry, 4326), time_span text, geometry_level text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_get_segment_snapshot(geom geometry(Geometry, 4326), geometry_level text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getdemographicsnapshot(geom geometry(Geometry, 4326), time_span text, geometry_level text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getsegmentsnapshot(geom geometry(Geometry, 4326), geometry_level text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundary(geom geometry(Geometry, 4326), boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundaryid(geom geometry(Geometry, 4326), boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundarybyid(geometry_id text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundariesbygeometry(geom geometry(Geometry, 4326), boundary_id text, time_span text, overlap_type text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getboundariesbypointandradius(geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text, overlap_type text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getpointsbygeometry(geom geometry(Geometry, 4326), boundary_id text, time_span text, overlap_type text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getpointsbypointandradius(geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text, overlap_type text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getmeasure(geom Geometry, measure_id text, normalize text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getcategory(geom Geometry, category_id text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getuscensusmeasure(geom Geometry, name text, normalize text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getuscensuscategory(geom Geometry, name text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getpopulation(geom Geometry, normalize text, boundary_id text, time_span text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_search(search_term text, relevant_boundary text) TO publicuser; +GRANT EXECUTE ON FUNCTION cdb_dataservices_client.obs_getavailableboundaries(geom Geometry, timespan text) TO publicuser; From 86dabe1c3559e03ef2fbe7b2f37a10d6a1b7f706 Mon Sep 17 00:00:00 2001 From: Mario de Frutos Date: Mon, 16 May 2016 11:04:07 +0200 Subject: [PATCH 7/7] Version file for server 0.8.0 --- .../cdb_dataservices_server--0.8.0.sql | 1911 +++++++++++++++++ 1 file changed, 1911 insertions(+) create mode 100644 server/extension/cdb_dataservices_server--0.8.0.sql diff --git a/server/extension/cdb_dataservices_server--0.8.0.sql b/server/extension/cdb_dataservices_server--0.8.0.sql new file mode 100644 index 0000000..fe71923 --- /dev/null +++ b/server/extension/cdb_dataservices_server--0.8.0.sql @@ -0,0 +1,1911 @@ +--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 "CREATE EXTENSION cdb_dataservices_server" to load this file. \quit +CREATE TYPE cdb_dataservices_server.simple_route AS ( + shape geometry(LineString,4326), + length real, + duration integer +); + + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_route_point_to_point( + username TEXT, + orgname TEXT, + origin geometry(Point, 4326), + destination geometry(Point, 4326), + mode TEXT, + options text[] DEFAULT ARRAY[]::text[], + units text DEFAULT 'kilometers') +RETURNS cdb_dataservices_server.simple_route AS $$ + import json + from cartodb_services.mapzen import MapzenRouting, MapzenRoutingResponse + from cartodb_services.mapzen.types import polyline_to_linestring + from cartodb_services.metrics import QuotaService + from cartodb_services.tools import Coordinate + + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection'] + user_routing_config = GD["user_routing_config_{0}".format(username)] + + quota_service = QuotaService(user_routing_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + client = MapzenRouting(user_routing_config.mapzen_api_key) + + if not origin or not destination: + plpy.notice("Empty origin or destination") + quota_service.increment_empty_service_use() + return [None, None, None] + + orig_lat = plpy.execute("SELECT ST_Y('%s') AS lat" % origin)[0]['lat'] + orig_lon = plpy.execute("SELECT ST_X('%s') AS lon" % origin)[0]['lon'] + origin_coordinates = Coordinate(orig_lon, orig_lat) + dest_lat = plpy.execute("SELECT ST_Y('%s') AS lat" % destination)[0]['lat'] + dest_lon = plpy.execute("SELECT ST_X('%s') AS lon" % destination)[0]['lon'] + dest_coordinates = Coordinate(dest_lon, dest_lat) + + resp = client.calculate_route_point_to_point(origin_coordinates, dest_coordinates, mode, options, units) + + if resp and resp.shape: + shape_linestring = polyline_to_linestring(resp.shape) + if shape_linestring: + quota_service.increment_success_service_use() + return [shape_linestring, resp.length, resp.duration] + else: + quota_service.increment_empty_service_use() + return [None, None, None] + else: + quota_service.increment_empty_service_use() + return [None, None, None] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to obtain route using mapzen provider: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu SECURITY DEFINER; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_route_point_to_point( + username TEXT, + orgname TEXT, + origin geometry(Point, 4326), + destination geometry(Point, 4326), + mode TEXT, + options text[] DEFAULT ARRAY[]::text[], + units text DEFAULT 'kilometers') +RETURNS cdb_dataservices_server.simple_route AS $$ + 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_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_routing_config = GD["user_routing_config_{0}".format(username)] + + mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_route_point_to_point($1, $2, $3, $4, $5, $6, $7) as route;", ["text", "text", "geometry(Point, 4326)", "geometry(Point, 4326)", "text", "text[]", "text"]) + result = plpy.execute(mapzen_plan, [username, orgname, origin, destination, mode, options, units]) + return [result[0]['shape'],result[0]['length'], result[0]['duration']] +$$ LANGUAGE plpythonu; +-- Get the connection to redis from cache or create a new one +CREATE OR REPLACE FUNCTION cdb_dataservices_server._connect_to_redis(user_id text) +RETURNS boolean AS $$ + cache_key = "redis_connection_{0}".format(user_id) + if cache_key in GD: + return False + else: + from cartodb_services.tools import RedisConnection, RedisDBConfig + metadata_config = RedisDBConfig('redis_metadata_config', plpy) + metrics_config = RedisDBConfig('redis_metrics_config', plpy) + redis_metadata_connection = RedisConnection(metadata_config).redis_connection() + redis_metrics_connection = RedisConnection(metrics_config).redis_connection() + GD[cache_key] = { + 'redis_metadata_connection': redis_metadata_connection, + 'redis_metrics_connection': redis_metrics_connection, + } + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; +-- +-- Observatory connection config +-- +-- The purpose of this function is provide to the PL/Proxy functions +-- the connection string needed to connect with the current production database + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._obs_server_conn_str( + username TEXT, + orgname TEXT) +RETURNS text AS $$ + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + return user_obs_snapshot_config.connection_str +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetDemographicSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS SETOF json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetDemographicSnapshot(geom, time_span, geometry_level); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetDemographicSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL, + geometry_level TEXT DEFAULT NULL) +RETURNS SETOF JSON AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetDemographicSnapshot($1, $2, $3, $4, $5) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span, geometry_level]) + if result: + resp = [] + for element in result: + value = element['snapshot'] + resp.append(value) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_geographic_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetSegmentSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS SETOF json AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetSegmentSnapshot(geom, geometry_level); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetSegmentSnapshot( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + geometry_level TEXT DEFAULT NULL) +RETURNS SETOF JSON AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_snapshot_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_snapshot_config = GD["user_obs_snapshot_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_snapshot_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetSegmentSnapshot($1, $2, $3, $4) as snapshot;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, geometry_level]) + if result: + resp = [] + for element in result: + value = element['snapshot'] + resp.append(value) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use get_segment_snapshot: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + measure_id TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetMeasure(geom, measure_id, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + measure_id TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetMeasure($1, $2, $3, $4, $5, $6, $7) as measure;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, measure_id, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['measure'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetMeasure: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + category_id TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetCategory(geom, category_id, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + category_id TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetCategory($1, $2, $3, $4, $5, $6) as category;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, category_id, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['category'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetCategory: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetUSCensusMeasure(geom, name, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetUSCensusMeasure( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetUSCensusMeasure($1, $2, $3, $4, $5, $6, $7) as census_measure;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, name, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['census_measure'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetUSCensusMeasure: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetUSCensusCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetUSCensusCategory(geom, name, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetUSCensusCategory( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + name TEXT, + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetUSCensusCategory($1, $2, $3, $4, $5, $6) as census_category;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, name, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['census_category'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetUSCensusCategory: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPopulation( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetPopulation(geom, normalize, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPopulation( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + normalize TEXT DEFAULT 'area', + boundary_id TEXT DEFAULT NULL, + time_span TEXT DEFAULT NULL) +RETURNS NUMERIC AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetPopulation($1, $2, $3, $4, $5, $6) as population;", ["text", "text", "geometry(Geometry, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, normalize, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['population'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPopulation: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_Search( + username TEXT, + orgname TEXT, + search_term TEXT, + relevant_boundary TEXT DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_Search(search_term, relevant_boundary); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_Search( + username TEXT, + orgname TEXT, + search_term TEXT, + relevant_boundary TEXT DEFAULT NULL) +RETURNS TABLE(id text, description text, name text, aggregate text, source text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_Search($1, $2, $3, $4);", ["text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, search_term, relevant_boundary]) + if result: + resp = [] + for element in result: + id = element['id'] + description = element['description'] + name = element['name'] + aggregate = element['aggregate'] + source = element['source'] + resp.append([id, description, name, aggregate, source]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [None, None, None, None, None] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_Search: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetAvailableBoundaries( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetAvailableBoundaries(geom, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetAvailableBoundaries( + username TEXT, + orgname TEXT, + geom geometry(Geometry, 4326), + time_span TEXT DEFAULT NULL) +RETURNS TABLE(boundary_id text, description text, time_span text, tablename text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetAvailableBoundaries($1, $2, $3, $4) as available_boundaries;", ["text", "text", "geometry(Geometry, 4326)", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, time_span]) + if result: + resp = [] + for element in result: + id = element['boundary_id'] + description = element['description'] + tspan = element['time_span'] + tablename = element['tablename'] + resp.append([id, description, tspan, tablename]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetAvailableBoundaries: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundary( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetBoundary(geom, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundary( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundary($1, $2, $3, $4) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundary: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryId( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetBoundaryId(geom, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundaryId( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS TEXT AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundaryId($1, $2, $3, $4, $5) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use obs_search: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundaryById( + username TEXT, + orgname TEXT, + geometry_id TEXT, + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT cdb_observatory.OBS_GetBoundaryById(geometry_id, boundary_id, time_span); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundaryById( + username TEXT, + orgname TEXT, + geometry_id TEXT, + boundary_id TEXT, + time_span TEXT DEFAULT NULL) +RETURNS geometry(Geometry, 4326) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetBoundaryById($1, $2, $3, $4, $5) as boundary;", ["text", "text", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geometry_id, boundary_id, time_span]) + if result: + quota_service.increment_success_service_use() + return result[0]['boundary'] + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundaryById: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type text DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetBoundariesByGeometry(geom, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundariesByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetBoundariesByGeometry($1, $2, $3, $4, $5, $6) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundariesByGeometry: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetBoundariesByPointAndRadius(geom, radius, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetBoundariesByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetBoundariesByPointAndRadius($1, $2, $3, $4, $5, $6, $7) as boundary;", ["text", "text", "geometry(Point, 4326)", "numeric", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, radius, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetBoundariesByPointAndRadius: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetPointsByGeometry(geom, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPointsByGeometry( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetPointsByGeometry($1, $2, $3, $4, $5, $6) as boundary;", ["text", "text", "geometry(Point, 4326)", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPointsByGeometry: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetPointsByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname); + SELECT * FROM cdb_observatory.OBS_GetPointsByPointAndRadius(geom, radius, boundary_id, time_span, overlap_type); +$$ LANGUAGE plproxy; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetPointsByPointAndRadius( + username TEXT, + orgname TEXT, + geom geometry(Point, 4326), + radius NUMERIC, + boundary_id TEXT, + time_span TEXT DEFAULT NULL, + overlap_type TEXT DEFAULT 'intersects') +RETURNS TABLE(the_geom geometry, geom_refs text) AS $$ + from cartodb_services.metrics import QuotaService + + 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_obs_config = GD["user_obs_config_{0}".format(username)] + + quota_service = QuotaService(user_obs_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetPointsByPointAndRadius($1, $2, $3, $4, $5, $6, $7) as boundary;", ["text", "text", "geometry(Point, 4326)", "numeric", "text", "text", "text"]) + result = plpy.execute(obs_plan, [username, orgname, geom, radius, boundary_id, time_span, overlap_type]) + if result: + resp = [] + for element in result: + the_geom = element['the_geom'] + geom_refs = element['geom_refs'] + resp.append([the_geom, geom_refs]) + quota_service.increment_success_service_use() + return resp + else: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to use OBS_GetPointsByPointAndRadius: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; +CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_geocoder_config(username text, orgname text) +RETURNS boolean AS $$ + cache_key = "user_geocoder_config_{0}".format(username) + if cache_key in GD: + return False + else: + from cartodb_services.metrics import GeocoderConfig + plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection'] + geocoder_config = GeocoderConfig(redis_conn, plpy, username, orgname) + GD[cache_key] = geocoder_config + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_internal_geocoder_config(username text, orgname text) +RETURNS boolean AS $$ + cache_key = "user_internal_geocoder_config_{0}".format(username) + if cache_key in GD: + return False + else: + from cartodb_services.metrics import InternalGeocoderConfig + plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection'] + geocoder_config = InternalGeocoderConfig(redis_conn, plpy, username, orgname) + GD[cache_key] = geocoder_config + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_isolines_routing_config(username text, orgname text) +RETURNS boolean AS $$ + cache_key = "user_isolines_routing_config_{0}".format(username) + if cache_key in GD: + return False + else: + from cartodb_services.metrics import IsolinesRoutingConfig + plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection'] + isolines_routing_config = IsolinesRoutingConfig(redis_conn, plpy, username, orgname) + GD[cache_key] = isolines_routing_config + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_routing_config(username text, orgname text) +RETURNS boolean AS $$ + cache_key = "user_routing_config_{0}".format(username) + if cache_key in GD: + return False + else: + from cartodb_services.metrics import RoutingConfig + plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection'] + routing_config = RoutingConfig(redis_conn, plpy, username, orgname) + GD[cache_key] = routing_config + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_obs_snapshot_config(username text, orgname text) +RETURNS boolean AS $$ + cache_key = "user_obs_snapshot_config_{0}".format(username) + if cache_key in GD: + return False + else: + from cartodb_services.metrics import ObservatorySnapshotConfig + plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection'] + obs_snapshot_config = ObservatorySnapshotConfig(redis_conn, plpy, username, orgname) + GD[cache_key] = obs_snapshot_config + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_obs_config(username text, orgname text) +RETURNS boolean AS $$ + cache_key = "user_obs_config_{0}".format(username) + if cache_key in GD: + return False + else: + from cartodb_services.metrics import ObservatoryConfig + plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username)) + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metadata_connection'] + obs_config = ObservatoryConfig(redis_conn, plpy, username, orgname) + GD[cache_key] = obs_config + return True +$$ LANGUAGE plpythonu SECURITY DEFINER; +-- Geocodes a street address given a searchtext and a state and/or country +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 $$ + 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)] + + 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'] + else: + plpy.error('Requested geocoder is not available') + +$$ LANGUAGE plpythonu; + +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 $$ + from cartodb_services.here import HereMapsGeocoder + from cartodb_services.metrics import QuotaService + + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection'] + user_geocoder_config = GD["user_geocoder_config_{0}".format(username)] + + # -- Check the quota + quota_service = QuotaService(user_geocoder_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + geocoder = HereMapsGeocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code) + coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country) + if coordinates: + 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: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using here maps geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +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 $$ + from cartodb_services.google import GoogleMapsGeocoder + from cartodb_services.metrics import QuotaService + + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection'] + user_geocoder_config = GD["user_geocoder_config_{0}".format(username)] + quota_service = QuotaService(user_geocoder_config, redis_conn) + + try: + geocoder = GoogleMapsGeocoder(user_geocoder_config.google_client_id, user_geocoder_config.google_api_key) + coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country) + if coordinates: + 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: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using google maps geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +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 $$ + from cartodb_services.mapzen import MapzenGeocoder + from cartodb_services.mapzen.types import country_to_iso3 + from cartodb_services.metrics import QuotaService + + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection'] + user_geocoder_config = GD["user_geocoder_config_{0}".format(username)] + quota_service = QuotaService(user_geocoder_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + geocoder = MapzenGeocoder(user_geocoder_config.mapzen_api_key) + country_iso3 = None + if country: + country_iso3 = country_to_iso3(country) + coordinates = geocoder.geocode(searchtext=searchtext, city=city, + state_province=state_province, + country=country_iso3) + if coordinates: + 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: + quota_service.increment_empty_service_use() + return None + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using mapzen geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; +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 + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + + +-------------------------------------------------------------------------------- + +-- Implementation of the server extension +-- Note: these functions depend on the cdb_geocoder extension +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_admin0_polygon(country_name text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT n.the_geom as geom INTO ret + FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x + FROM (SELECT country_name q) g) d + LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x + LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.the_geom, s.adm0_a3; + + RETURN ret; + END +$$ LANGUAGE plpgsql; +---- cdb_geocode_admin1_polygon(admin1_name text) +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_admin1_polygon(username text, orgname text, admin1_name text) +RETURNS Geometry AS $$ + from cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_admin1_polygon(trim($1)) AS mypolygon", ["text"]) + rv = plpy.execute(plan, [admin1_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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +---- 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) +RETURNS Geometry AS $$ + from cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_admin1_polygon(trim($1), trim($2)) AS mypolygon", ["text", "text"]) + rv = plpy.execute(plan, [admin1_name, 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +-------------------------------------------------------------------------------- + +-- Implementation of the server extension +-- Note: these functions depend on the cdb_geocoder extension + +---- cdb_geocode_admin1_polygon(admin1_name text) +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_admin1_polygon(admin1_name text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT geom INTO ret + FROM ( + SELECT q, ( + SELECT the_geom + FROM global_province_polygons + WHERE d.c = ANY (synonyms) + ORDER BY frequency DESC LIMIT 1 + ) geom + FROM ( + SELECT + trim(replace(lower(admin1_name),'.',' ')) c, admin1_name q + ) d + ) v; + + RETURN ret; + END +$$ LANGUAGE plpgsql; + +---- cdb_geocode_admin1_polygon(admin1_name text, country_name text) +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_admin1_polygon(admin1_name text, country_name text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + WITH p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(country_name) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(admin1_name),'.',' ')) c, country_name q) r) + SELECT + geom INTO ret + FROM ( + SELECT + q, ( + SELECT the_geom + FROM global_province_polygons + WHERE p.c = ANY (synonyms) + AND iso3 = p.i + ORDER BY frequency DESC LIMIT 1 + ) geom + FROM p) n; + + RETURN ret; + END +$$ LANGUAGE plpgsql; + +---- 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 cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_namedplace_point(trim($1)) AS mypoint", ["text"]) + rv = plpy.execute(plan, [city_name], 1) + result = rv[0]["mypoint"] + 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +---- 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 cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_namedplace_point(trim($1), trim($2)) AS mypoint", ["text", "text"]) + rv = plpy.execute(plan, [city_name, country_name], 1) + result = rv[0]["mypoint"] + 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +---- 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 cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_namedplace_point(trim($1), trim($2), trim($3)) AS mypoint", ["text", "text", "text"]) + rv = plpy.execute(plan, [city_name, admin1_name, country_name], 1) + result = rv[0]["mypoint"] + 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +-------------------------------------------------------------------------------- + +-- Implementation of the server extension +-- Note: these functions depend on the cdb_geocoder extension + +---- cdb_geocode_namedplace_point(city_name text) +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_namedplace_point(city_name text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT geom INTO ret + FROM ( + WITH best AS (SELECT s AS q, (SELECT the_geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT city_name as s) p), + next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT city_name as s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL)) + SELECT q, geom, TRUE AS success FROM best WHERE geom IS NOT NULL + UNION ALL + SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next + ) v; + + RETURN ret; + END +$$ LANGUAGE plpgsql; + +---- cdb_geocode_namedplace_point(city_name text, country_name text) +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_namedplace_point(city_name text, country_name text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT geom INTO ret + FROM ( + WITH p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT city_name AS s, country_name::text AS c) r), + best AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p), + next AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE c = p.c AND geom IS NOT NULL)) + SELECT geom FROM best WHERE geom IS NOT NULL + UNION ALL + SELECT geom FROM next + ) v; + + RETURN ret; + END +$$ LANGUAGE plpgsql; + +---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text) +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT geom INTO ret + FROM ( + WITH inputcountry AS ( + SELECT iso2 as isoTwo FROM country_decoder WHERE lower(country_name) = ANY (synonyms) LIMIT 1 + ), + p AS ( + SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder, inputcountry WHERE lower(r.a1) = ANY (synonyms) AND admin1_decoder.iso2 = inputcountry.isoTwo LIMIT 1) i FROM (SELECT city_name AS s, admin1_name::text AS a1) r), + best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p), + next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL)) + SELECT geom FROM best WHERE geom IS NOT NULL + UNION ALL + SELECT geom FROM next + ) v; + + RETURN ret; + END +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_point(username text, orgname text, code text) +RETURNS Geometry AS $$ + from cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_postalcode_point(trim($1)) AS mypoint", ["text"]) + rv = plpy.execute(plan, [code], 1) + result = rv[0]["mypoint"] + 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_point(username text, orgname text, code text, country text) +RETURNS Geometry AS $$ + from cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_postalcode_point(trim($1), trim($2)) AS mypoint", ["TEXT", "TEXT"]) + rv = plpy.execute(plan, [code, country], 1) + result = rv[0]["mypoint"] + 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text) +RETURNS Geometry AS $$ + from cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_postalcode_polygon(trim($1)) AS mypolygon", ["text"]) + rv = plpy.execute(plan, [code], 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_postalcode_polygon(username text, orgname text, code text, country text) +RETURNS Geometry AS $$ + from cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_postalcode_polygon(trim($1), trim($2)) AS mypolygon", ["TEXT", "TEXT"]) + rv = plpy.execute(plan, [code, country], 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +-------------------------------------------------------------------------------- + +-- Implementation of the server extension +-- Note: these functions depend on the cdb_geocoder extension +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_postalcode_point(code text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT geom INTO ret + FROM ( + SELECT + q, ( + SELECT the_geom + FROM global_postal_code_points + WHERE postal_code = upper(d.q) + LIMIT 1 + ) geom + FROM (SELECT code q) d + ) v; + + RETURN ret; +END +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_postalcode_point(code text, country text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT geom INTO ret + FROM ( + SELECT + q, ( + SELECT the_geom + FROM global_postal_code_points + WHERE postal_code = upper(d.q) + AND iso3 = ( + SELECT iso3 FROM country_decoder WHERE + lower(country) = ANY (synonyms) LIMIT 1 + ) + LIMIT 1 + ) geom + FROM (SELECT code q) d + ) v; + + RETURN ret; +END +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_postalcode_polygon(code text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT geom INTO ret + FROM ( + SELECT + q, ( + SELECT the_geom + FROM global_postal_code_polygons + WHERE postal_code = upper(d.q) + LIMIT 1 + ) geom + FROM (SELECT code q) d + ) v; + + RETURN ret; +END +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_postalcode_polygon(code text, country text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + BEGIN + SELECT geom INTO ret + FROM ( + SELECT + q, ( + SELECT the_geom + FROM global_postal_code_polygons + WHERE postal_code = upper(d.q) + AND iso3 = ( + SELECT iso3 FROM country_decoder WHERE + lower(country) = ANY (synonyms) LIMIT 1 + ) + LIMIT 1 + ) geom + FROM (SELECT code q) d + ) v; + + RETURN ret; +END +$$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_ipaddress_point(username text, orgname text, ip text) +RETURNS Geometry AS $$ + from cartodb_services.metrics import QuotaService + from cartodb_services.metrics import InternalGeocoderConfig + + 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)] + + quota_service = QuotaService(user_geocoder_config, redis_conn) + try: + plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_geocode_ipaddress_point(trim($1)) AS mypoint", ["TEXT"]) + rv = plpy.execute(plan, [ip], 1) + result = rv[0]["mypoint"] + 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, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to geocode using admin0 geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu; + +-------------------------------------------------------------------------------- + +-- Implementation of the server extension +-- Note: these functions depend on the cdb_geocoder extension +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_geocode_ipaddress_point(ip text) +RETURNS Geometry AS $$ + DECLARE + ret Geometry; + + new_ip INET; + BEGIN + BEGIN + IF family(ip::inet) = 6 THEN + new_ip := ip::inet; + ELSE + new_ip := ('::ffff:' || ip)::inet; + END IF; + EXCEPTION WHEN OTHERS THEN + SELECT NULL as geom INTO ret; + RETURN ret; + END; + + WITH + ips AS (SELECT ip s, new_ip net), + matches AS (SELECT s, (SELECT the_geom FROM ip_address_locations WHERE network_start_ip <= ips.net ORDER BY network_start_ip DESC LIMIT 1) geom FROM ips) + SELECT geom INTO ret + FROM matches; + RETURN ret; +END +$$ LANGUAGE plpgsql; +CREATE TYPE cdb_dataservices_server.isoline AS (center geometry(Geometry,4326), data_range integer, the_geom geometry(Multipolygon,4326)); + +CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_here_routing_isolines(username TEXT, orgname TEXT, type TEXT, source geometry(Geometry, 4326), mode TEXT, data_range integer[], options text[]) +RETURNS SETOF cdb_dataservices_server.isoline AS $$ + import json + from cartodb_services.here import HereMapsRoutingIsoline + from cartodb_services.metrics import QuotaService + from cartodb_services.here.types import geo_polyline_to_multipolygon + + redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection'] + user_isolines_routing_config = GD["user_isolines_routing_config_{0}".format(username)] + + # -- Check the quota + quota_service = QuotaService(user_isolines_routing_config, redis_conn) + if not quota_service.check_user_quota(): + plpy.error('You have reached the limit of your quota') + + try: + client = HereMapsRoutingIsoline(user_isolines_routing_config.heremaps_app_id, user_isolines_routing_config.heremaps_app_code, base_url = HereMapsRoutingIsoline.PRODUCTION_ROUTING_BASE_URL) + + 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'] + source_str = 'geo!%f,%f' % (lat, lon) + else: + source_str = None + + if type == 'isodistance': + resp = client.calculate_isodistance(source_str, mode, data_range, options) + elif type == 'isochrone': + resp = client.calculate_isochrone(source_str, mode, data_range, options) + + if resp: + result = [] + for isoline in resp: + data_range_n = isoline['range'] + polyline = isoline['geom'] + multipolygon = geo_polyline_to_multipolygon(polyline) + result.append([source, data_range_n, multipolygon]) + quota_service.increment_success_service_use() + quota_service.increment_isolines_service_use(len(resp)) + return result + else: + quota_service.increment_empty_service_use() + return [] + except BaseException as e: + import sys, traceback + type_, value_, traceback_ = sys.exc_info() + quota_service.increment_failed_service_use() + error_msg = 'There was an error trying to obtain isodistances using here maps geocoder: {0}'.format(e) + plpy.notice(traceback.format_tb(traceback_)) + plpy.error(error_msg) + finally: + quota_service.increment_total_service_use() +$$ LANGUAGE plpythonu SECURITY DEFINER; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) +RETURNS SETOF cdb_dataservices_server.isoline AS $$ + 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_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)] + type = 'isodistance' + + if user_isolines_config.google_services_user: + plpy.error('This service is not available for google service users.') + + here_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_here_routing_isolines($1, $2, $3, $4, $5, $6, $7) as isoline; ", ["text", "text", "text", "geometry(Geometry, 4326)", "text", "integer[]", "text[]"]) + result = plpy.execute(here_plan, [username, orgname, type, source, mode, range, options]) + isolines = [] + for element in result: + isoline = element['isoline'] + isoline = isoline.translate(None, "()").split(',') + isolines.append(isoline) + + return isolines +$$ LANGUAGE plpythonu; +CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[]) +RETURNS SETOF cdb_dataservices_server.isoline AS $$ + 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_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname))) + user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)] + type = 'isochrone' + + if user_isolines_config.google_services_user: + plpy.error('This service is not available for google service users.') + + here_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_here_routing_isolines($1, $2, $3, $4, $5, $6, $7) as isoline; ", ["text", "text", "text", "geometry(Geometry, 4326)", "text", "integer[]", "text[]"]) + result = plpy.execute(here_plan, [username, orgname, type, source, mode, range, options]) + isolines = [] + for element in result: + isoline = element['isoline'] + isoline = isoline.translate(None, "()").split(',') + isolines.append(isoline) + + return isolines +$$ LANGUAGE plpythonu; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT * + FROM pg_catalog.pg_user + WHERE usename = 'geocoder_api') THEN + + CREATE USER geocoder_api; + END IF; + GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_dataservices_server TO geocoder_api; + GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO geocoder_api; + GRANT USAGE ON SCHEMA cdb_dataservices_server TO geocoder_api; + GRANT USAGE ON SCHEMA public TO geocoder_api; + GRANT SELECT ON ALL TABLES IN SCHEMA public TO geocoder_api; +END$$;