diff --git a/src/pg/sql/41_observatory_augmentation.sql b/src/pg/sql/41_observatory_augmentation.sql index da37e74..2fbaaa8 100644 --- a/src/pg/sql/41_observatory_augmentation.sql +++ b/src/pg/sql/41_observatory_augmentation.sql @@ -386,12 +386,20 @@ BEGIN (unnest($1))->>'geom_type' geom_type, (unnest($1))->>'geom_timespan' geom_timespan, (unnest($1))->>'numer_timespan' numer_timespan, - (unnest($1))->>'normalization' normalization + (unnest($1))->>'normalization' normalization, + (unnest($1))->>'api_method' api_method, + (unnest($1))->'api_args' api_args ) SELECT String_Agg( -- numeric - '(''{' || CASE WHEN LOWER(numer_type) LIKE 'numeric' THEN - '"value": '' || ' || CASE + 'JSON_Build_Object(' || CASE + WHEN api_method IS NOT NULL THEN + '''value'', ' || + 'cdb_observatory.FIRST( ' || + api_method || '.' || numer_colname || ')::' || numer_type + -- numeric internal values + WHEN LOWER(numer_type) LIKE 'numeric' THEN + '''value'', ' || CASE -- denominated WHEN LOWER(normalization) LIKE 'denom%' OR (normalization IS NULL AND denom_id IS NOT NULL) THEN 'cdb_observatory.FIRST(' || numer_tablename || '.' || numer_colname || @@ -406,30 +414,34 @@ BEGIN -- categorical/text WHEN LOWER(numer_type) LIKE 'text' THEN - '"value": "'' || ' || 'cdb_observatory.FIRST(' || numer_tablename || '.' || numer_colname || ') || ''"''' + '''value'', ' || 'cdb_observatory.FIRST(' || numer_tablename || '.' || numer_colname || ') ' -- geometry WHEN numer_id IS NULL THEN - '"geomref": "'' || ' || 'cdb_observatory.FIRST(' || geom_tablename || - '.' || geom_geomref_colname || ') || ''", ' || - '"value": "'' || ' || 'cdb_observatory.FIRST(' || geom_tablename || - '.' || geom_colname || ')::TEXT || ''"''' + '''geomref'', ' || 'cdb_observatory.FIRST(' || geom_tablename || + '.' || geom_geomref_colname || '), ' || + '''value'', ' || 'cdb_observatory.FIRST(' || geom_tablename || + '.' || geom_colname || ')' ELSE '' - END || ' || ''}'')::JSON', ', ') + END || ')', ', ') AS colspecs, (SELECT String_Agg(DISTINCT CASE -- External API WHEN tablename LIKE 'cdb_observatory.%' THEN - 'LATERAL (SELECT * FROM ' || tablename || - '(_geoms.geom)) ' || REPLACE(tablename, 'cdb_observatory.', '') + 'LATERAL (SELECT * FROM ' || tablename || ') ' || + REPLACE(split_part(tablename, '(', 1), 'cdb_observatory.', '') -- Internal obs_ table ELSE 'observatory.' || tablename END, ', ') FROM ( SELECT DISTINCT UNNEST(tablenames_ary) tablename FROM ( SELECT ARRAY_AGG(numer_tablename) || ARRAY_AGG(denom_tablename) || - ARRAY_AGG(geom_tablename) + ARRAY_AGG(geom_tablename) || + ARRAY_AGG('cdb_observatory.' || api_method || '(_geomrefs.id' || COALESCE(', ' || + (SELECT STRING_AGG(REPLACE(val::text, '"', ''''), ', ') + FROM (SELECT json_array_elements(api_args) as val) as vals), + '') || ')') tablenames_ary ) tablenames_inner ) tablenames_outer) tablenames, @@ -451,12 +463,13 @@ BEGIN RETURN QUERY EXECUTE format($query$ WITH _geomrefs AS (SELECT UNNEST($1) as id) - SELECT _geomrefs.id, Array_to_JSON(ARRAY[%s]) - FROM %s, _geomrefs - WHERE %s %s + SELECT _geomrefs.id, Array_to_JSON(ARRAY[%s]::JSON[]) + FROM _geomrefs, %s + %s GROUP BY _geomrefs.id ORDER BY _geomrefs.id - $query$, colspecs, tables, NULLIF(obs_wheres, '') || ' AND ', user_wheres) + $query$, colspecs, tables, + 'WHERE ' || NULLIF(ARRAY_TO_STRING(ARRAY[obs_wheres, user_wheres], ' AND '), '')) USING geomrefs; RETURN; END; @@ -510,18 +523,20 @@ BEGIN (unnest($1))->>'geom_type' geom_type, (unnest($1))->>'numer_timespan' numer_timespan, (unnest($1))->>'geom_timespan' geom_timespan, - (unnest($1))->>'normalization' normalization + (unnest($1))->>'normalization' normalization, + (unnest($1))->>'api_method' api_method, + (unnest($1))->'api_args' api_args ) SELECT String_Agg( - '(''{' || CASE + 'JSON_Build_Object(' || CASE -- api-delivered values - WHEN numer_tablename LIKE 'cdb_observatory.%' THEN - '"value": "'' || ' || - '(cdb_observatory.FIRST( ' || - REPLACE(numer_tablename, 'cdb_observatory.', '') || '.' || numer_colname || '))::TEXT || ''"''' + WHEN api_method IS NOT NULL THEN + '''value'', ' || + 'cdb_observatory.FIRST( ' || + api_method || '.' || numer_colname || ')::' || numer_type -- numeric internal values WHEN LOWER(numer_type) LIKE 'numeric' THEN - '"value": '' || ' || CASE + '''value'', ' || CASE -- denominated WHEN LOWER(normalization) LIKE 'denom%' OR (normalization IS NULL AND denom_id IS NOT NULL) THEN ' CASE ' || @@ -592,36 +607,45 @@ BEGIN -- categorical/text WHEN LOWER(numer_type) LIKE 'text' THEN - '"value": "'' || ' || 'MODE() WITHIN GROUP (ORDER BY ' || numer_tablename || '.' || numer_colname || ') || ''"''' + '''value'', ' || 'MODE() WITHIN GROUP (ORDER BY ' || numer_tablename || '.' || numer_colname || ') ' -- geometry WHEN numer_id IS NULL THEN - '"geomref": "'' || ' || geom_tablename || '.' || geom_geomref_colname || ' || ''", ' || - '"value": "'' || ' || 'cdb_observatory.FIRST(' || geom_tablename || - '.' || geom_colname || ')::TEXT || ''"''' + '''geomref'', ' || geom_tablename || '.' || geom_geomref_colname || ', ' || + '''value'', ' || 'cdb_observatory.FIRST(' || geom_tablename || + '.' || geom_colname || ')::TEXT' -- code below will return the intersection of the user's geom and the -- OBS geom --'"value": "'' || ' || 'cdb_observatory.FIRST(ST_Intersection(_geoms.geom, ' || geom_tablename || -- '.' || geom_colname || '))::TEXT || ''"''' ELSE '' - END || ' || ''}'')::JSON', ', ') + END || ')', ', ') AS colspecs, - STRING_AGG(REPLACE(geom_tablename, 'cdb_observatory.', '') || + -- geomrefs, used to separate out rows in case we don't want to merge + -- results by user input IDs + -- + -- api_method and geom_tablename are interchangeable since when an + -- api_method is passed, geom_tablename is ignored + STRING_AGG(COALESCE(geom_tablename, api_method) || '.' || geom_geomref_colname, ', ') AS geomrefs, (SELECT String_Agg(DISTINCT CASE -- External API WHEN tablename LIKE 'cdb_observatory.%' THEN - 'LATERAL (SELECT * FROM ' || tablename || - '(_geoms.geom)) ' || REPLACE(tablename, 'cdb_observatory.', '') + 'LATERAL (SELECT * FROM ' || tablename || ') ' || + REPLACE(split_part(tablename, '(', 1), 'cdb_observatory.', '') -- Internal obs_ table ELSE 'observatory.' || tablename END, ', ') FROM ( SELECT DISTINCT UNNEST(tablenames_ary) tablename FROM ( SELECT ARRAY_AGG(numer_tablename) || ARRAY_AGG(denom_tablename) || - ARRAY_AGG(geom_tablename) + ARRAY_AGG(geom_tablename) || + ARRAY_AGG('cdb_observatory.' || api_method || '(_geoms.geom' || COALESCE(', ' || + (SELECT STRING_AGG(REPLACE(val::text, '"', ''''), ', ') + FROM (SELECT json_array_elements(api_args) as val) as vals), + '') || ')') tablenames_ary ) tablenames_inner ) tablenames_outer) tablenames, diff --git a/src/pg/test/expected/41_observatory_augmentation_test.out b/src/pg/test/expected/41_observatory_augmentation_test.out index e2225b9..16d7260 100644 --- a/src/pg/test/expected/41_observatory_augmentation_test.out +++ b/src/pg/test/expected/41_observatory_augmentation_test.out @@ -105,6 +105,18 @@ t obs_getmeasurebyid_null_id t (1 row) -obs_getdata_api +obs_getdata_api_geomvals_no_args +t +(1 row) +obs_getdata_api_geomvals_args_numer_return +t +(1 row) +obs_getdata_api_geomvals_args_string_return +t +(1 row) +obs_getdata_api_geomrefs_args_numer_return +t +(1 row) +obs_getdata_api_geomrefs_args_string_return t (1 row) diff --git a/src/pg/test/sql/41_observatory_augmentation_test.sql b/src/pg/test/sql/41_observatory_augmentation_test.sql index 491a015..b298517 100644 --- a/src/pg/test/sql/41_observatory_augmentation_test.sql +++ b/src/pg/test/sql/41_observatory_augmentation_test.sql @@ -217,9 +217,28 @@ SELECT cdb_observatory.OBS_GetMeasureById( '2010 - 2014' ) IS NULL As OBS_GetMeasureById_null_id; --- OBS_GetData with an API -SELECT ARRAY['us.census.tiger.census_tract'] <@ array_agg(data->0->>'value') AS OBS_GetData_API +-- OBS_GetData with an API + geomvals, no args +SELECT ARRAY['us.census.tiger.census_tract'] <@ array_agg(data->0->>'value') AS OBS_GetData_API_geomvals_no_args FROM cdb_observatory.obs_getdata(array[(cdb_observatory._testarea(), 1)::geomval], - '[{"numer_coltype": "text", "numer_colname": "boundary_id", "numer_tablename": "cdb_observatory.obs_getavailableboundaries", "geom_tablename": "cdb_observatory.obs_getavailableboundaries", "geom_geomref_colname": "boundary_id"}]', + '[{"numer_type": "text", "numer_colname": "boundary_id", "api_method": "obs_getavailableboundaries", "geom_geomref_colname": "boundary_id"}]', false); +-- OBS_GetData with an API + geomvals, args, numeric +SELECT json_typeof(data->0->'value') = 'number' AS OBS_GetData_API_geomvals_args_numer_return +FROM cdb_observatory.obs_getdata(array[(cdb_observatory._testarea(), 1)::geomval], + '[{"numer_type": "numeric", "numer_colname": "obs_getmeasure", "api_method": "obs_getmeasure", "api_args": ["us.census.acs.B01003001"]}]', false); + +-- OBS_GetData with an API + geomvals, args, text +SELECT json_typeof(data->0->'value') = 'string' AS OBS_GetData_API_geomvals_args_string_return +FROM cdb_observatory.obs_getdata(array[(cdb_observatory._testarea(), 1)::geomval], + '[{"numer_type": "text", "numer_colname": "obs_getcategory", "api_method": "obs_getcategory", "api_args": ["us.census.spielman_singleton_segments.X55"]}]', false); + +-- OBS_GetData with an API + geomrefs, args, numeric +SELECT json_typeof(data->0->'value') = 'number' AS OBS_GetData_API_geomrefs_args_numer_return +FROM cdb_observatory.obs_getdata(array['36047076200'], + '[{"numer_type": "numeric", "numer_colname": "obs_getmeasurebyid", "api_method": "obs_getmeasurebyid", "api_args": ["us.census.acs.B01003001", "us.census.tiger.census_tract"]}]'); + +-- OBS_GetData with an API + geomrefs, args, text +SELECT json_typeof(data->0->'value') = 'string' AS OBS_GetData_API_geomrefs_args_string_return +FROM cdb_observatory.obs_getdata(array['36047'], + '[{"numer_type": "text", "numer_colname": "obs_getboundarybyid", "api_method": "obs_getboundarybyid", "api_args": ["us.census.tiger.county"]}]');