Compare commits
173 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9e809c061 | ||
|
|
43e83751ae | ||
|
|
4c13434b9a | ||
|
|
8785639ece | ||
|
|
f991f5a1e6 | ||
|
|
e4b4ebf72d | ||
|
|
20f56c98de | ||
|
|
e4ea90835a | ||
|
|
8f2c8f571c | ||
|
|
e9857e89fb | ||
|
|
8ed2135a7f | ||
|
|
af69b44f25 | ||
|
|
e12b729c51 | ||
|
|
a42827a3c9 | ||
|
|
948cdbff19 | ||
|
|
1c7c73f948 | ||
|
|
360adc47df | ||
|
|
571f1f343a | ||
|
|
186c57efbd | ||
|
|
b139a24012 | ||
|
|
260704327e | ||
|
|
252610673a | ||
|
|
d054f37528 | ||
|
|
3d58fd284a | ||
|
|
efcea9be7b | ||
|
|
cf242515e3 | ||
|
|
4c434f5448 | ||
|
|
59dd09c554 | ||
|
|
8187ab4bbe | ||
|
|
e54d95fa8f | ||
|
|
d766f08b03 | ||
|
|
8f345fd508 | ||
|
|
383c3eb6ec | ||
|
|
798c0a73a1 | ||
|
|
bfa57f4971 | ||
|
|
e7a16f4b4d | ||
|
|
540ff68a90 | ||
|
|
6a1df2abd1 | ||
|
|
dc9ed2de33 | ||
|
|
acaa434118 | ||
|
|
173d7c0aec | ||
|
|
970d5d2119 | ||
|
|
a3681062cb | ||
|
|
a179a46b86 | ||
|
|
4c434ffb8d | ||
|
|
b041821fc0 | ||
|
|
876515f9aa | ||
|
|
25570e5b11 | ||
|
|
1054443117 | ||
|
|
d93752efa3 | ||
|
|
588cda3262 | ||
|
|
e43d0ca4cf | ||
|
|
987c4c5b76 | ||
|
|
51ce13f8b9 | ||
|
|
25f4dbc416 | ||
|
|
c09e0b6e83 | ||
|
|
748428ace1 | ||
|
|
10a0dc9b26 | ||
|
|
9245de84b0 | ||
|
|
514e1e4c5b | ||
|
|
7bb1bbd804 | ||
|
|
1d008ccbe9 | ||
|
|
f581278b8a | ||
|
|
cbf1c5e67d | ||
|
|
adc663b563 | ||
|
|
3a37b98b72 | ||
|
|
a4a20e9c1d | ||
|
|
f485426085 | ||
|
|
75e765f256 | ||
|
|
b690478aff | ||
|
|
6fa9d5c96a | ||
|
|
fc6317161f | ||
|
|
c07d9f6833 | ||
|
|
ff173a0152 | ||
|
|
a7de1f2228 | ||
|
|
86529ada5a | ||
|
|
80cdc5e8ca | ||
|
|
7c8c5cca0a | ||
|
|
a946ab9d03 | ||
|
|
da127baa3c | ||
|
|
e89a88aa83 | ||
|
|
af2259bb0a | ||
|
|
fb083f4b9e | ||
|
|
976e119abb | ||
|
|
bbc6f9ef36 | ||
|
|
5229279ee9 | ||
|
|
0090e537fc | ||
|
|
e4052ed565 | ||
|
|
2107796f07 | ||
|
|
2463623658 | ||
|
|
91797918c1 | ||
|
|
6a39bedee7 | ||
|
|
6ce0e5a8d9 | ||
|
|
81176d1df2 | ||
|
|
f22854b4e9 | ||
|
|
54701d595a | ||
|
|
4b26eeda65 | ||
|
|
4fc02f99e2 | ||
|
|
5bb4285528 | ||
|
|
1e9c3fb860 | ||
|
|
62a2c259a7 | ||
|
|
61854a070d | ||
|
|
8654c22c87 | ||
|
|
62c08864af | ||
|
|
af39a37b43 | ||
|
|
26b61a6ddb | ||
|
|
965fb94704 | ||
|
|
84dec8bdf4 | ||
|
|
568996930b | ||
|
|
ebc27dbbb7 | ||
|
|
56fa19118b | ||
|
|
4f3baac10a | ||
|
|
b512985b46 | ||
|
|
329b4dbca3 | ||
|
|
897cf38d42 | ||
|
|
fe6343c73f | ||
|
|
26ee8aedb1 | ||
|
|
66e2c6be54 | ||
|
|
6b41994a87 | ||
|
|
d3d5cbdbbd | ||
|
|
4d51ecc12e | ||
|
|
c0030acb0c | ||
|
|
e938ee0c7b | ||
|
|
8fa2d642bf | ||
|
|
926435a908 | ||
|
|
80073aa213 | ||
|
|
3f78797e14 | ||
|
|
11dbb860ab | ||
|
|
9ade6588e2 | ||
|
|
5ef1427bc3 | ||
|
|
3f63f6f138 | ||
|
|
3d59adc452 | ||
|
|
50c5f01f3f | ||
|
|
0dad5427c4 | ||
|
|
71c098c1c3 | ||
|
|
4057f76fc1 | ||
|
|
17aeb5187b | ||
|
|
cf7c115a76 | ||
|
|
4e8341daab | ||
|
|
ca4327d3cd | ||
|
|
bac48d7bea | ||
|
|
91383fe933 | ||
|
|
446bdec30d | ||
|
|
f362e97f88 | ||
|
|
975137641d | ||
|
|
9379224629 | ||
|
|
7733529ff5 | ||
|
|
5a68f77b64 | ||
|
|
63448d6214 | ||
|
|
a18b07fa84 | ||
|
|
11b05877f4 | ||
|
|
62b23be2e0 | ||
|
|
eefdae8a58 | ||
|
|
563c31a77f | ||
|
|
3334e60ab8 | ||
|
|
da6aac4a18 | ||
|
|
5e99b60329 | ||
|
|
67d735af03 | ||
|
|
e960f3e097 | ||
|
|
8fbb9ebbcc | ||
|
|
389823d4fd | ||
|
|
076e285ed7 | ||
|
|
43dc37f62b | ||
|
|
49d584822c | ||
|
|
02ca484719 | ||
|
|
3502282835 | ||
|
|
f9ecf1595c | ||
|
|
b5267c14bf | ||
|
|
afb548c75d | ||
|
|
94756a2377 | ||
|
|
2e312464aa | ||
|
|
3f77a384c7 | ||
|
|
1ba7299fe4 |
129
NEWS.md
129
NEWS.md
@@ -1,3 +1,128 @@
|
||||
0.0.1 (open date)
|
||||
1.0.5 (2016-08-12)
|
||||
|
||||
__Improvements__
|
||||
|
||||
* Integration tests moved to `src/python/test/`, and can be run without hitting
|
||||
any HTTP SQL API.
|
||||
|
||||
1.0.4 (2016-07-26)
|
||||
|
||||
__Bugfixes__
|
||||
|
||||
* Always default arguments to `NULL`, which prevents duplication & overwrite by
|
||||
dataservices-api
|
||||
([#173](https://github.com/CartoDB/observatory-extension/issues/173))
|
||||
|
||||
1.0.3 (2016-07-25)
|
||||
|
||||
__Bugfixes__
|
||||
|
||||
* Raise exception instead of crashing when `OBS_GetMeasure` is passed a polygon
|
||||
in combination with a non-summable measure ([cartodb/issues
|
||||
#9063](https://github.com/CartoDB/cartodb/issues/9063))
|
||||
* Unnecessary dependencies on cartodb and plpythonu removed
|
||||
([#161](https://github.com/CartoDB/observatory-extension/issues/161))
|
||||
* Tests forced to run in-order on all systems
|
||||
([#162](https://github.com/CartoDB/observatory-extension/issues/162))
|
||||
* Area normalization done by square kilometer instead of square meter for
|
||||
polygons ([#158](https://github.com/CartoDB/observatory-extension/issues/158))
|
||||
* `postgres-fdw` installed as required in unit test environment
|
||||
([#166](https://github.com/CartoDB/observatory-extension/issues/166))
|
||||
|
||||
__Improvements__
|
||||
|
||||
* Added tests to make sure all functions can handle explicit NULL as default
|
||||
([#159](https://github.com/CartoDB/observatory-extension/issues/159))
|
||||
* Buffer and snaptogrid used to be far more liberal accepting problem geoms
|
||||
([#170](https://github.com/CartoDB/observatory-extension/issues/160))
|
||||
|
||||
|
||||
1.0.2 (2016-07-12)
|
||||
---
|
||||
|
||||
__Bugfixes__
|
||||
|
||||
* Fix for `OBS_GetCategory` outside the US ([#135](https://github.com/CartoDB/observatory-extension/pull/137))
|
||||
* `OBS_GetMeasure` now respects the `normalize` parameter even when passed
|
||||
a multi/polygon. Previously, no normalization was erroneously assumed.
|
||||
|
||||
__Improvements__
|
||||
|
||||
* Automated tests cover Mexico data
|
||||
* `obs_meta` is now provisioned during unit tests
|
||||
* `obs_meta` is now used during end-to-end tests
|
||||
* `OBS_GetMeasureByID` uses `obs_meta` internally, which should help
|
||||
performance
|
||||
* `OBS_GetCategory` uses `obs_meta` internally, which should help perfromance
|
||||
* `OBS_GetCategory` will pick the correct category for an arbitrary polygon
|
||||
(the category covering the highest % of that polygon)
|
||||
* `OBS_GetMeasure` has been updated to use `obs_meta` internally, which should
|
||||
help performance
|
||||
* `OBS_GetMeasure` now can be passed "none" and skip normalization by area or
|
||||
denominator for points
|
||||
* Fixtures are only loaded at the start of the unit test suite, and dropped at the end,
|
||||
instead of at the start/end of each individual test file
|
||||
* Comment noisy NOTICEs ([#73](https://github.com/CartoDB/observatory-extension/issues/73))
|
||||
|
||||
1.0.1 (2016-07-01)
|
||||
---
|
||||
|
||||
__Bugfixes__
|
||||
|
||||
* Fix for ERROR: Operation on mixed SRID geometries #130
|
||||
|
||||
|
||||
1.0.0 (6/27/2016)
|
||||
-----
|
||||
|
||||
* Incremented to 1.0.0 to be in compliance with [SemVer](http://semver.org/),
|
||||
which disallows use of 0.x.x versions. This also reflects that we are
|
||||
already in production.
|
||||
|
||||
__API Changes__
|
||||
|
||||
* Added `OBS_DumpVersion` to look up version data ([#118](https://github.com/CartoDB/observatory-extension/pull/118))
|
||||
|
||||
__Improvements__
|
||||
|
||||
* Whether data exists for a geom now determined by polygon intersection instead of
|
||||
BBOX overlap ([#119](https://github.com/CartoDB/observatory-extension/pull/119))
|
||||
* Automated tests cover Spanish and UK data
|
||||
([#115](https://github.com/CartoDB/observatory-extension/pull/115))
|
||||
* Automated tests cover `OBS_GetUSCensusMeasure`
|
||||
([#105](https://github.com/CartoDB/observatory-extension/pull/105))
|
||||
|
||||
__Bugfixes__
|
||||
|
||||
* Geom table can have different `geomref_colname` than the data table
|
||||
([#123](https://github.com/CartoDB/observatory-extension/pull/123))
|
||||
|
||||
|
||||
0.0.5 (5/27/2016)
|
||||
-----
|
||||
* Adds new function `OBS_GetMeasureById` ([#96](https://github.com/CartoDB/observatory-extension/pull/96))
|
||||
|
||||
0.0.4 (5/25/2016)
|
||||
-----
|
||||
* Updates queries involving US Census measure tags to be more generic ([#95](https://github.com/CartoDB/observatory-extension/pull/95))
|
||||
* Fixes tests which relied on an erroneous subset of block groups ([#95](https://github.com/CartoDB/observatory-extension/pull/95))
|
||||
|
||||
0.0.3 (5/24/2016)
|
||||
-----
|
||||
* Generalizes internal queries to properly pull from multiple named geometry references
|
||||
* Adds tests for Who's on First boundaries
|
||||
* Improves automatic fixtures testing script
|
||||
|
||||
0.0.2 (5/19/2016)
|
||||
-----
|
||||
* Adds Data Observatory exploration functions
|
||||
* Adds Data Observatory boundary functions
|
||||
* Adds Data Observatory measure functions
|
||||
* Adds script to generate fixtures for tests
|
||||
* Adds script for the automatic testing of metadata
|
||||
* Adds full documentation for all included functions
|
||||
* removes `cartodb` extension dependency
|
||||
|
||||
0.0.1 (5/19/2016)
|
||||
------------------
|
||||
* First iteration of `OBS_GetDemographicSnapshot(location Geometry(Point,4326))`;
|
||||
* First iteration of `OBS_GetDemographicSnapshot(location Geometry(Point,4326))`
|
||||
|
||||
@@ -20,12 +20,6 @@ script for the new release, `release/observatory--X.Y.Z.sql`:
|
||||
make release
|
||||
```
|
||||
|
||||
Then, the release manager shall produce upgrade and downgrade scripts
|
||||
to migrate to/from the previous release. In the case of minor/patch
|
||||
releases this simply consist in extracting the functions that have changed
|
||||
and placing them in the proper `release/observatory--X.Y.Z--A.B.C.sql`
|
||||
file.
|
||||
|
||||
The new release can be deployed for staging/smoke tests with this command:
|
||||
|
||||
```
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Data Observatory Documentation
|
||||
|
||||
This file is for reference purposes only. It is intended for tracking the Data Observatory functions that should be displayed from the live Docs site. Like all API doc, the golden source of this code will live in this observatory-extension repo, and will be edited in this repo.
|
||||
This file is for reference purposes only. It is intended for tracking the Data Observatory functions that should be pulled into the live Docs site. Like all API doc, the golden source of this code will live in this observatory-extension repo, and will be edited in this repo. Other non-code related content will live as a local file in the Docs repo.
|
||||
|
||||
## Documentation
|
||||
|
||||
* Overview (local file in the Docs repo)
|
||||
* Accessing the Data Observatory (local file in the Docs repo)
|
||||
* [Measures Functions](measures_functions.md)
|
||||
* [Boundary Functions](boundary_functions.md)
|
||||
* [Discovery Functions](discovery_functions.md)
|
||||
* [Glossary](glossary.md)
|
||||
* [License](license.md)
|
||||
* [Glossary](local file in the Docs repo)
|
||||
* [License](local file in the Docs repo)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Boundary Functions
|
||||
|
||||
Use the following functions to retrieve [Boundary](/cartodb-platform/data/overview/#boundary-data) data. Data ranges from small areas (e.g. US Census Block Groups) to large areas (e.g. Countries). You can access boundaries by point location lookup, bounding box lookup, direct ID access and several other methods described below.
|
||||
Use the following functions to retrieve [Boundary](https://carto.com/docs/carto-engine/data/overview/#boundary-data) data. Data ranges from small areas (e.g. US Census Block Groups) to large areas (e.g. Countries). You can access boundaries by point location lookup, bounding box lookup, direct ID access and several other methods described below.
|
||||
|
||||
You can [access](/cartodb-platform/data/accessing/#accessing-the-data-observatory) boundaries through the CartoDB Editor. The same methods will work if you are using the CartoDB Platform to develop your application. We [encourage you](/cartodb-platform/data/accessing/#best-practices) to use table modifying methods (UPDATE and INSERT) over dynamic methods (SELECT).
|
||||
You can [access](https://carto.com/docs/carto-engine/data/accessing) boundaries through the CARTO Editor. The same methods will work if you are using the CARTO Engine to develop your application. We [encourage you](http://docs/carto-engine/data/accessing/#best-practices) to use table modifying methods (UPDATE and INSERT) over dynamic methods (SELECT).
|
||||
|
||||
## OBS_GetBoundariesByGeometry(polygon geometry, geometry_id text)
|
||||
|
||||
@@ -91,14 +91,14 @@ FROM OBS_GetPointsByGeometry(
|
||||
|
||||
## OBS_GetBoundary(point_geometry, boundary_id)
|
||||
|
||||
The ```OBS_GetBoundary(point_geometry, boundary_id)``` method returns a boundary geometry defined as overlapping the point geometry and from the desired boundary set (e.g. Census Tracts). See the [Boundary ID glossary table below](below). This is a useful method for performing aggregations of points.
|
||||
The ```OBS_GetBoundary(point_geometry, boundary_id)``` method returns a boundary geometry defined as overlapping the point geometry and from the desired boundary set (e.g. Census Tracts). See the [Boundary ID Glossary](https://carto.com/docs/carto-engine/data/glossary/#boundary-ids). This is a useful method for performing aggregations of points.
|
||||
|
||||
#### Arguments
|
||||
|
||||
Name | Description
|
||||
--- | ---
|
||||
point_geometry | a WGS84 polygon geometry (the_geom)
|
||||
boundary_id | a boundary identifier from the [Boundary ID glossary table below](below)
|
||||
boundary_id | a boundary identifier from the [Boundary ID Glossary](https://carto.com/docs/carto-engine/data/glossary/#boundary-ids)
|
||||
timespan (optional) | year(s) to request from (`NULL` (default) gives most recent)
|
||||
|
||||
#### Returns
|
||||
@@ -124,14 +124,14 @@ SET the_geom = OBS_GetBoundary(the_geom, 'us.census.tiger.block_group')
|
||||
|
||||
## OBS_GetBoundaryId(point_geometry, boundary_id)
|
||||
|
||||
The ```OBS_GetBoundaryId(point_geometry, boundary_id)``` returns a unique geometry_id for the boundary geometry that contains a given point geometry. See the [Boundary ID glossary table below](below). The method can be combined with ```OBS_GetBoundaryById(geometry_id)``` to create a point aggregation workflow.
|
||||
The ```OBS_GetBoundaryId(point_geometry, boundary_id)``` returns a unique geometry_id for the boundary geometry that contains a given point geometry. See the [Boundary ID Glossary](http://docs/carto-engine/data/glossary/#boundary-ids). The method can be combined with ```OBS_GetBoundaryById(geometry_id)``` to create a point aggregation workflow.
|
||||
|
||||
#### Arguments
|
||||
|
||||
Name |Description
|
||||
--- | ---
|
||||
point_geometry | a WGS84 point geometry (the_geom)
|
||||
boundary_id | a boundary identifier from the [Boundary ID glossary table below](below)
|
||||
boundary_id | a boundary identifier from the [Boundary ID Glossary](https://carto.com/docs/carto-engine/data/glossary/#boundary-ids)
|
||||
timespan (optional) | year(s) to request from (`NULL` (default) gives most recent)
|
||||
|
||||
#### Returns
|
||||
@@ -164,7 +164,7 @@ The ```OBS_GetBoundaryById(geometry_id, boundary_id)``` returns the boundary geo
|
||||
Name | Description
|
||||
--- | ---
|
||||
geometry_id | a string identifier for a Boundary geometry
|
||||
boundary_id | a boundary identifier from the [Boundary ID glossary table below](below)
|
||||
boundary_id | a boundary identifier from the [Boundary ID Glossary](https://carto.com/docs/carto-engine/data/glossary/#boundary-ids)
|
||||
timespan (optional) | year(s) to request from (`NULL` (default) gives most recent)
|
||||
|
||||
#### Returns
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Discovery Functions
|
||||
|
||||
If you are using the [discovery methods](/cartodb-platform/data/overview/#discovery-methods) from the Data Observatory, use the following functions to retrieve [boundary](/cartodb-platform/data/overview/#boundary-data) and [measures](/cartodb-platform/data/overview/#measures-data) data.
|
||||
If you are using the [discovery methods](https://carto.com/docs/carto-engine/data/overview/#discovery-methods) from the Data Observatory, use the following functions to retrieve [boundary](https://carto.com/docs/carto-engine/data/overview/#boundary-data) and [measures](https://carto.com/docs/carto-engine/data/overview/#measures-data) data.
|
||||
|
||||
## OBS_Search(search_term)
|
||||
|
||||
@@ -47,7 +47,7 @@ A TABLE containing the following properties
|
||||
|
||||
Key | Description
|
||||
--- | ---
|
||||
boundary_id | a boundary identifier from the [boundary ID glossary](/cartodb-platform/data/glossary/#boundary-ids)
|
||||
boundary_id | a boundary identifier from the [Boundary ID Glossary](https://carto.com/docs/carto-engine/data/glossary/#boundary-ids)
|
||||
description | a brief description of the boundary dataset
|
||||
time_span | the timespan attached the boundary. this does not mean that the boundary is invalid outside of the timespan, but is the explicit timespan published with the geometry.
|
||||
|
||||
|
||||
126
doc/glossary.md
126
doc/glossary.md
@@ -1,126 +0,0 @@
|
||||
# Glossary
|
||||
|
||||
A list of boundary ids and measure_names for Data Observatory functions. For US based boundaries, the Shoreline Clipped version provides a high-quality shoreline clipping for mapping uses.
|
||||
|
||||
## Boundary IDs
|
||||
|
||||
Boundary name | Boundary ID | Shoreline Clipped Boundary ID
|
||||
--------------------- | --------------------- | ---
|
||||
US States | us.census.tiger.state | us.census.tiger.state_clipped
|
||||
US County | us.census.tiger.county | us.census.tiger.county_clipped
|
||||
US Census Zip Code Tabulation Areas | us.census.tiger.zcta5 | us.census.tiger.zcta5_clipped
|
||||
US Census Tracts | us.census.tiger.census_tract | us.census.tiger.census_tract_clipped
|
||||
US Elementary School District | us.census.tiger.school_district_elementary | us.census.tiger.school_district_elementary_clipped
|
||||
US Secondary School District | us.census.tiger.school_district_secondary | us.census.tiger.school_district_secondary_clipped
|
||||
US Unified School District | us.census.tiger.school_district_unified | us.census.tiger.school_district_unified_clipped
|
||||
US Congressional Districts | us.census.tiger.congressional_district | us.census.tiger.congressional_district_clipped
|
||||
US Census Blocks | us.census.tiger.block | us.census.tiger.block_clipped
|
||||
US Census Block Groups | us.census.tiger.block_group | us.census.tiger.block_group_clipped
|
||||
US Census PUMAs | us.census.tiger.puma | us.census.tiger.puma_clipped
|
||||
US Incorporated Places | us.census.tiger.place | us.census.tiger.place_clipped
|
||||
ES Sección Censal | es.ine.geom | none
|
||||
Regions (First-level Administrative) | whosonfirst.wof_region_geom | none
|
||||
Continents | whosonfirst.wof_continent_geom | none
|
||||
Countries | whosonfirst.wof_country_geom | none
|
||||
Marine Areas | whosonfirst.wof_marinearea_geom | none
|
||||
Disputed Areas | whosonfirst.wof_disputed_geom | none
|
||||
|
||||
|
||||
|
||||
## OBS_GetUSCensusMeasure Names Table
|
||||
|
||||
This list contains human readable names accepted in the ```OBS_GetUSCensusMeasure``` function. For the more comprehensive list of columns available to the ```OBS_GetMeasure``` function, see the [Data Observatory Catalog](https://cartodb.github.io/bigmetadata/observatory.pdf).
|
||||
|
||||
Measure name | Measure description
|
||||
------------------------ | --------------------
|
||||
Male Population | The number of people within each geography who are male.
|
||||
Female Population | The number of people within each geography who are female.
|
||||
Median Age | The median age of all people in a given geographic area.
|
||||
Total Population | The total number of all people living in a given geographic area. This is a very useful catch-all denominator when calculating rates.
|
||||
Population not Hispanic | The number of people not identifying as Hispanic or Latino in each geography.
|
||||
White Population | The number of people identifying as white, non-Hispanic in each geography.
|
||||
Black or African American Population | The number of people identifying as black or African American, non-Hispanic in each geography.
|
||||
American Indian and Alaska Native Population | The number of people identifying as American Indian or Alaska native in each geography.
|
||||
Asian Population | The number of people identifying as Asian, non-Hispanic in each geography.
|
||||
Other Race population | The number of people identifying as another race in each geography.
|
||||
Two or more races population | The number of people identifying as two or more races in each geography.
|
||||
Hispanic Population | The number of people identifying as Hispanic or Latino in each geography.
|
||||
Not a U.S. Citizen Population | The number of people within each geography who indicated that they are not U.S. citizens.
|
||||
Workers over the Age of 16 | The number of people in each geography who work. Workers include those employed at private for-profit companies, the self-employed, government workers and non-profit employees.
|
||||
Commuters by Car, Truck, or Van | The number of workers age 16 years and over within a geographic area who primarily traveled to work by car, truck or van. This is the principal mode of travel or type of conveyance, by distance rather than time, that the worker usually used to get from home to work.
|
||||
Commuters who drove alone | The number of workers age 16 years and over within a geographic area who primarily traveled by car driving alone. This is the principal mode of travel or type of conveyance, by distance rather than time, that the worker usually used to get from home to work.
|
||||
Commuters by Carpool | The number of workers age 16 years and over within a geographic area who primarily traveled to work by carpool. This is the principal mode of travel or type of conveyance, by distance rather than time, that the worker usually used to get from home to work.
|
||||
Commuters by Bus | The number of workers age 16 years and over within a geographic area who primarily traveled to work by bus. This is the principal mode of travel or type of conveyance, by distance rather than time, that the worker usually used to get from home to work. This is a subset of workers who commuted by public transport.
|
||||
Commuters by Subway or Elevated | The number of workers age 16 years and over within a geographic area who primarily traveled to work by subway or elevated train. This is the principal mode of travel or type of conveyance, by distance rather than time, that the worker usually used to get from home to work. This is a subset of workers who commuted by public transport.
|
||||
Walked to Work | The number of workers age 16 years and over within a geographic area who primarily walked to work. This would mean that of any way of getting to work, they travelled the most distance walking.
|
||||
Worked at Home | The count within a geographical area of workers over the age of 16 who worked at home.
|
||||
Workers age 16 and over who do not work from home | The number of workers over the age of 16 who do not work from home in a geographic area.
|
||||
Number of workers with less than 10 minute commute | The number of workers over the age of 16 who do not work from home and commute in less than 10 minutes in a geographic area.
|
||||
Number of workers with a commute between 35 and 44 minutes | The number of workers over the age of 16 who do not work from home and commute in between 35 and 44 minutes in a geographic area.
|
||||
Number of workers with a commute of over 60 minutes | The number of workers over the age of 16 who do not work from home and commute in over 60 minutes in a geographic area.
|
||||
Aggregate travel time to work | The total number of minutes every worker over the age of 16 who did not work from home spent spent commuting to work in one day in a geographic area.
|
||||
Commuters by Public Transportation | The number of workers age 16 years and over within a geographic area who primarily traveled to work by public transportation. This is the principal mode of travel or type of conveyance, by distance rather than time, that the worker usually used to get from home to work.
|
||||
Number of workers with a commute between 10 and 14 minutes | The number of workers over the age of 16 who do not work from home and commute in between 10 and 14 minutes in a geographic area.
|
||||
Number of workers with a commute between 15 and 19 minutes | The number of workers over the age of 16 who do not work from home and commute in between 15 and 19 minutes in a geographic area.
|
||||
Number of workers with a commute between 20 and 24 minutes | The number of workers over the age of 16 who do not work from home and commute in between 20 and 24 minutes in a geographic area.
|
||||
Number of workers with a commute between 25 and 29 minutes | The number of workers over the age of 16 who do not work from home and commute in between 25 and 29 minutes in a geographic area.
|
||||
Number of workers with a commute between 30 and 34 minutes | The number of workers over the age of 16 who do not work from home and commute in between 30 and 34 minutes in a geographic area.
|
||||
Number of workers with a commute between 45 and 59 minutes | The number of workers over the age of 16 who do not work from home and commute in between 45 and 59 minutes in a geographic area.
|
||||
Children under 18 Years of Age | The number of people within each geography who are under 18 years of age.
|
||||
Households | A count of the number of households in each geography. A household consists of one or more people who live in the same dwelling and also share at meals or living accommodation, and may consist of a single family or some other grouping of people.
|
||||
Population 15 Years and Over | The number of people in a geographic area who are over the age of 15. This is used mostly as a denominator of marital status.
|
||||
Never Married | The number of people in a geographic area who have never been married.
|
||||
Currently married | The number of people in a geographic area who are currently married.
|
||||
Married but separated | The number of people in a geographic area who are married but separated.
|
||||
Widowed | The number of people in a geographic area who are widowed.
|
||||
Divorced | The number of people in a geographic area who are divorced.
|
||||
Population 3 Years and Over | The total number of people in each geography age 3 years and over. This denominator is mostly used to calculate rates of school enrollment.
|
||||
Students Enrolled in School | The total number of people in each geography currently enrolled at any level of school, from nursery or pre-school to advanced post-graduate education. Only includes those over the age of 3.
|
||||
Students Enrolled in Grades 1 to 4 | The total number of people in each geography currently enrolled in grades 1 through 4 inclusive. This corresponds roughly to elementary school.
|
||||
Students Enrolled in Grades 5 to 8 | The total number of people in each geography currently enrolled in grades 5 through 8 inclusive. This corresponds roughly to middle school.
|
||||
Students Enrolled in Grades 9 to 12 | The total number of people in each geography currently enrolled in grades 9 through 12 inclusive. This corresponds roughly to high school.
|
||||
Students Enrolled as Undergraduate in College | The number of people in a geographic area who are enrolled in college at the undergraduate level. Enrollment refers to being registered or listed as a student in an educational program leading to a college degree. This may be a public school or college, a private school or college.
|
||||
Population 25 Years and Over | The number of people in a geographic area who are over the age of 25. This is used mostly as a denominator of educational attainment.
|
||||
Population Completed High School | The number of people in a geographic area over the age of 25 who completed high school, and did not complete a more advanced degree.
|
||||
Population completed less than one year of college, no degree | The number of people in a geographic area over the age of 25 who attended college for less than one year and no further.
|
||||
Population completed more than one year of college, no degree | The number of people in a geographic area over the age of 25 who attended college for more than one year but did not obtain a degree.
|
||||
Population Completed Associate's Degree | The number of people in a geographic area over the age of 25 who obtained a associate's degree, and did not complete a more advanced degree.
|
||||
Population Completed Bachelor's Degree | The number of people in a geographic area over the age of 25 who obtained a bachelor's degree, and did not complete a more advanced degree.
|
||||
Population Completed Master's Degree | The number of people in a geographic area over the age of 25 who obtained a master's degree, but did not complete a more advanced degree.
|
||||
Population 5 Years and Over | The number of people in a geographic area who are over the age of 5. This is primarily used as a denominator of measures of language spoken at home.
|
||||
Speaks only English at Home | The number of people in a geographic area over age 5 who speak only English at home.
|
||||
Speaks Spanish at Home | The number of people in a geographic area over age 5 who speak Spanish at home, possibly in addition to other languages.
|
||||
Population for Whom Poverty Status Determined | The number of people in each geography who could be identified as either living in poverty or not. This should be used as the denominator when calculating poverty rates, as it excludes people for whom it was not possible to determine poverty.
|
||||
Income In The Past 12 Months Below Poverty Level | The number of people in a geographic area who are part of a family (which could be just them as an individual) determined to be in poverty following the Office of Management and Budget's Directive 14. (https://www.census.gov/hhes/povmeas/methodology/ombdir14.html)
|
||||
Households with income less than $10,000 | The number of households in a geographic area whose annual income was less than $10,000.
|
||||
Households with income of $10,000 to $14,999 | The number of households in a geographic area whose annual income was between $10,000 and $14,999.
|
||||
Households with income of $15,000 to $19,999 | The number of households in a geographic area whose annual income was between $15,000 and $19,999.
|
||||
Households with income of $20,000 To $24,999 | The number of households in a geographic area whose annual income was between $20,000 and $24,999.
|
||||
Households with income of $25,000 To $29,999 | The number of households in a geographic area whose annual income was between $20,000 and $24,999.
|
||||
Households with income of $30,000 To $34,999 | The number of households in a geographic area whose annual income was between $30,000 and $34,999.
|
||||
Households with income of $35,000 To $39,999 | The number of households in a geographic area whose annual income was between $35,000 and $39,999.
|
||||
Households with income of $40,000 To $44,999 | The number of households in a geographic area whose annual income was between $40,000 and $44,999.
|
||||
Households with income of $45,000 To $49,999 | The number of households in a geographic area whose annual income was between $45,000 and $49,999.
|
||||
Households with income of $50,000 To $59,999 | The number of households in a geographic area whose annual income was between $50,000 and $59,999.
|
||||
Households with income of $60,000 To $74,999 | The number of households in a geographic area whose annual income was between $60,000 and $74,999.
|
||||
Households with income of $75,000 To $99,999 | The number of households in a geographic area whose annual income was between $75,000 and $99,999.
|
||||
Households with income of $100,000 To $124,999 | The number of households in a geographic area whose annual income was between $100,000 and $124,999.
|
||||
Households with income of $125,000 To $149,999 | The number of households in a geographic area whose annual income was between $125,000 and $149,999.
|
||||
Households with income of $150,000 To $199,999 | The number of households in a geographic area whose annual income was between $150,000 and $1999,999.
|
||||
Households with income of $200,000 Or More | The number of households in a geographic area whose annual income was more than $200,000.
|
||||
Median Household Income in the past 12 Months | Within a geographic area, the median income received by every household on a regular basis before payments for personal income taxes, social security, union dues, medicare deductions, etc. It includes income received from wages, salary, commissions, bonuses, and tips; self-employment income from own nonfarm or farm businesses, including proprietorships and partnerships; interest, dividends, net rental income, royalty income, or income from estates and trusts; Social Security or Railroad Retirement income; Supplemental Security Income (SSI); any cash public assistance or welfare payments from the state or local welfare office; retirement, survivor, or disability benefits; and any other sources of income received regularly such as Veterans' (VA) payments, unemployment and/or worker's compensation, child support, and alimony.
|
||||
Population age 16 and over | The number of people in each geography who are age 16 or over.
|
||||
Population in Labor Force | The number of people in each geography who are either in the civilian labor force or are members of the U.S. Armed Forces (people on active duty with the United States Army, Air Force, Navy, Marine Corps, or Coast Guard).
|
||||
Population in Civilian Labor Force | The number of civilians 16 years and over in each geography who can be classified as either employed or unemployed below.
|
||||
Employed Population | The number of civilians 16 years old and over in each geography who either (1) were at work, that is, those who did any work at all during the reference week as paid employees, worked in their own business or profession, worked on their own farm, or worked 15 hours or more as unpaid workers on a family farm or in a family business; or (2) were with a job but not at work, that is, those who did not work during the reference week but had jobs or businesses from which they were temporarily absent due to illness, bad weather, industrial dispute, vacation, or other personal reasons. Excluded from the employed are people whose only activity consisted of work around the house or unpaid volunteer work for religious, charitable, and similar organizations; also excluded are all institutionalized people and people on active duty in the United States Armed Forces.
|
||||
Unemployed Population | The number of civilians in each geography who are 16 years old and over and are classified as unemployed.
|
||||
Population in Armed Forces | The number of people in each geography who are members of the U.S. Armed Forces (people on active duty with the United States Army, Air Force, Navy, Marine Corps, or Coast Guard).
|
||||
Population Not in Labor Force | The number of people in each geography who are 16 years old and over who are not classified as members of the labor force. This category consists mainly of students, homemakers, retired workers, seasonal workers interviewed in an off season who were not looking for work, institutionalized people, and people doing only incidental unpaid family work.
|
||||
Housing Units | A count of housing units in each geography. A housing unit is a house, an apartment, a mobile home or trailer, a group of rooms, or a single room occupied as separate living quarters, or if vacant, intended for occupancy as separate living quarters.
|
||||
Vacant Housing Units | The count of vacant housing units in a geographic area. A housing unit is vacant if no one is living in it at the time of enumeration, unless its occupants are only temporarily absent. Units temporarily occupied at the time of enumeration entirely by people who have a usual residence elsewhere are also classified as vacant.
|
||||
Vacant Housing Units for Rent | The count of vacant housing units in a geographic area that are for rent. A housing unit is vacant if no one is living in it at the time of enumeration, unless its occupants are only temporarily absent. Units temporarily occupied at the time of enumeration entirely by people who have a usual residence elsewhere are also classified as vacant.
|
||||
Vacant Housing Units for Sale | The count of vacant housing units in a geographic area that are for sale. A housing unit is vacant if no one is living in it at the time of enumeration, unless its occupants are only temporarily absent. Units temporarily occupied at the time of enumeration entirely by people who have a usual residence elsewhere are also classified as vacant.
|
||||
Median Rent | The median contract rent within a geographic area. The contract rent is the monthly rent agreed to or contracted for, regardless of any furnishings, utilities, fees, meals, or services that may be included. For vacant units, it is the monthly rent asked for the rental unit at the time of interview.
|
||||
Percent of Household Income Spent on Rent | Within a geographic area, the median percentage of household income which was spent on gross rent. Gross rent is the amount of the contract rent plus the estimated average monthly cost of utilities (electricity, gas, water, sewer etc.) and fuels (oil, coal, wood, etc.) if these are paid by the renter. Household income is the sum of the income of all people 15 years and older living in the household.
|
||||
Owner-occupied Housing Units valued at $1,000,000 or more. | The count of owner occupied housing units in a geographic area that are valued at $1,000,000 or more. Value is the respondent's estimate of how much the property (house and lot, mobile home and lot, or condominium unit) would sell for if it were for sale.
|
||||
Owner-occupied Housing Units with a Mortgage | The count of housing units within a geographic area that are mortagaged. Mortgage refers to all forms of debt where the property is pledged as security for repayment of the debt, including deeds of trust, trust deed, contracts to purchase, land contracts, junior mortgages, and home equity loans.
|
||||
@@ -1,18 +0,0 @@
|
||||
# License
|
||||
|
||||
The Data Observatory is a collection of various sources of data with varying licenses. We have worked hard to find you data that will work for the broadest set of use-cases. For competency, please still review the terms for any dataset you use and respect the rights of the owners for each dataset. The following third-party data sources are used in the Data Observatory, and we have included the links to the terms governing their use.
|
||||
|
||||
Name | Terms link
|
||||
-------|---------
|
||||
ACS | [https://www.usa.gov/government-works](https://www.usa.gov/government-works)
|
||||
TIGER | [https://www.usa.gov/government-works](https://www.usa.gov/government-works)
|
||||
Zillow Home Value Index | This data is "Aggregate Data", per the Zillow Terms of Use<br /><br />[http://www.zillow.com/corp/Terms.htm](http://www.zillow.com/corp/Terms.htm)
|
||||
Who's on First | [http://whosonfirst.mapzen.com#License](http://whosonfirst.mapzen.com#License)
|
||||
GeoNames | [http://www.geonames.org/](http://www.geonames.org/)
|
||||
GeoPlanet | [https://developer.yahoo.com/geo/geoplanet/](https://developer.yahoo.com/geo/geoplanet/)
|
||||
Natural Earth | [http://www.naturalearthdata.com/about/terms-of-use/](http://www.naturalearthdata.com/about/terms-of-use/)
|
||||
Quattroshapes | [https://github.com/foursquare/quattroshapes/blob/master/LICENSE.md](https://github.com/foursquare/quattroshapes/blob/master/LICENSE.md)
|
||||
Zetashapes | [http://zetashapes.com/license](http://zetashapes.com/license)
|
||||
Spielman & Singleton | [https://www.openicpsr.org/repoEntity/show/41329](https://www.openicpsr.org/repoEntity/show/41329)
|
||||
Instituto Nacional de Estadistica | [http://www.ine.es/ss/Satellite?L=0&c=Page&cid=1254735849170&p=1254735849170&pagename=Ayuda%2FINELayout](http://www.ine.es/ss/Satellite?L=0&c=Page&cid=1254735849170&p=1254735849170&pagename=Ayuda%2FINELayout)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Measures Functions
|
||||
|
||||
[Data Observatory Measures](/cartodb-platform/data/overview/#measures-methods) are the numerical location data you can access. The measure functions allow you to access individual measures to augment your own data or integrate in your analysis workflows. Measures are used by sending an identifier or a geometry (point or polygon) and receiving back a measure (an absolute value) for that location.
|
||||
[Data Observatory Measures](https://carto.com/docs/carto-engine/data/overview/#measures-methods) are the numerical location data you can access. The measure functions allow you to access individual measures to augment your own data or integrate in your analysis workflows. Measures are used by sending an identifier or a geometry (point or polygon) and receiving back a measure (an absolute value) for that location.
|
||||
|
||||
There are hundreds of measures and the list is growing with each release. You can currently discover and learn about measures contained in the Data Observatory by downloading our [Data Catalog](https://cartodb.github.io/bigmetadata/observatory.pdf).
|
||||
There are hundreds of measures and the list is growing with each release. You can currently discover and learn about measures contained in the Data Observatory by downloading our [Data Catalog](http://data-observatory.s3.amazonaws.com/observatory.pdf).
|
||||
|
||||
You can [access](/cartodb-platform/data/accessing/#accessing-the-data-observatory) measures through the CartoDB Editor. The same methods will work if you are using the CartoDB Platform to develop your application. We [encourage you](/cartodb-platform/data/accessing/#best-practices) to use table modifying methods (UPDATE and INSERT) over dynamic methods (SELECT).
|
||||
You can [access](https://carto.com/docs/carto-engine/data/accessing) measures through the CARTO Editor. The same methods will work if you are using the CARTO Engine to develop your application. We [encourage you](https://carto.com/docs/carto-engine/data/accessing/#best-practices) to use table modifying methods (UPDATE and INSERT) over dynamic methods (SELECT).
|
||||
|
||||
## OBS_GetUSCensusMeasure(point geometry, measure_name text)
|
||||
|
||||
@@ -15,8 +15,8 @@ The ```OBS_GetUSCensusMeasure(point, measure_name)``` function returns a measure
|
||||
Name |Description
|
||||
--- | ---
|
||||
point | a WGS84 point geometry (the_geom)
|
||||
measure_name | a human readable name of a US Census variable. The list of measure_names is [available in the glossary](/cartodb-platform/data/glossary/#obsgetuscensusmeasure-names-table).
|
||||
normalize | for measures that are are **sums** (e.g. population) the default normalization is 'area' and response comes back as a rate per square kilometer. Other options are 'denominator', which will use the denominator specified in the [Data Catalog](http://cartodb.github.io/bigmetadata/index.html) (optional)
|
||||
measure_name | a human readable name of a US Census variable. The list of measure_names is [available in the Glossary](https://carto.com/docs/carto-engine/data/glossary/#obsgetuscensusmeasure-names-table).
|
||||
normalize | for measures that are are **sums** (e.g. population) the default normalization is 'area' and response comes back as a rate per square kilometer. Other options are 'denominator', which will use the denominator specified in the [Data Catalog](http://data-observatory.s3.amazonaws.com/observatory.pdf) (optional)
|
||||
boundary_id | source of geometries to pull measure from (e.g., 'us.census.tiger.census_tract')
|
||||
time_span | time span of interest (e.g., 2010 - 2014)
|
||||
|
||||
@@ -46,8 +46,8 @@ The ```OBS_GetUSCensusMeasure(point, measure_name)``` function returns a measure
|
||||
Name |Description
|
||||
--- | ---
|
||||
polygon | a WGS84 polygon geometry (the_geom)
|
||||
measure_name | a human readable string name of a US Census variable. The list of measure_names is [available in the glossary](/cartodb-platform/data/glossary/#obsgetuscensusmeasure-names-table).
|
||||
normalize | for measures that are **sums** (e.g. population) the default normalization is 'none' and response comes back as a raw value. Other options are 'denominator', which will use the denominator specified in the [Data Catalog](https://cartodb.github.io/bigmetadata/observatory.pdf) (optional)
|
||||
measure_name | a human readable string name of a US Census variable. The list of measure_names is [available in the Glossary](https://carto.com/docs/carto-engine/data/glossary/#obsgetuscensusmeasure-names-table).
|
||||
normalize | for measures that are **sums** (e.g. population) the default normalization is 'none' and response comes back as a raw value. Other options are 'denominator', which will use the denominator specified in the [Data Catalog](http://data-observatory.s3.amazonaws.com/observatory.pdf) (optional)
|
||||
boundary_id | source of geometries to pull measure from (e.g., 'us.census.tiger.census_tract')
|
||||
time_span | time span of interest (e.g., 2010 - 2014)
|
||||
|
||||
@@ -70,7 +70,7 @@ SET local_male_population = OBS_GetUSCensusMeasure(the_geom, 'Male Population')
|
||||
|
||||
## OBS_GetMeasure(point geometry, measure_id text)
|
||||
|
||||
The ```OBS_GetMeasure(point, measure_id)``` function returns any Data Observatory measure at a point location. You can browse all available Measures in the [Catalog](https://cartodb.github.io/bigmetadata/observatory.pdf)).
|
||||
The ```OBS_GetMeasure(point, measure_id)``` function returns any Data Observatory measure at a point location. You can browse all available Measures in the [Catalog](http://data-observatory.s3.amazonaws.com/observatory.pdf).
|
||||
|
||||
#### Arguments
|
||||
|
||||
@@ -78,7 +78,7 @@ Name |Description
|
||||
--- | ---
|
||||
point | a WGS84 point geometry (the_geom)
|
||||
measure_id | a measure identifier from the Data Observatory ([see available measures](https://cartodb.github.io/bigmetadata/observatory.pdf)). It is important to note that these are different than 'measure_name' used in the Census based functions above.
|
||||
normalize | for measures that are are **sums** (e.g. population) the default normalization is 'area' and response comes back as a rate per square kilometer. The other option is 'denominator', which will use the denominator specified in the [Data Catalog](https://cartodb.github.io/bigmetadata/observatory.pdf). (optional)
|
||||
normalize | for measures that are are **sums** (e.g. population) the default normalization is 'area' and response comes back as a rate per square kilometer. The other option is 'denominator', which will use the denominator specified in the [Data Catalog](http://data-observatory.s3.amazonaws.com/observatory.pdf). (optional)
|
||||
boundary_id | source of geometries to pull measure from (e.g., 'us.census.tiger.census_tract')
|
||||
time_span | time span of interest (e.g., 2010 - 2014)
|
||||
|
||||
@@ -109,7 +109,7 @@ Name |Description
|
||||
--- | ---
|
||||
polygon_geometry | a WGS84 polygon geometry (the_geom)
|
||||
measure_id | a measure identifier from the Data Observatory ([see available measures](https://cartodb.github.io/bigmetadata/observatory.pdf))
|
||||
normalize | for measures that are are **sums** (e.g. population) the default normalization is 'none' and response comes back as a raw value. Other options are 'denominator', which will use the denominator specified in the [Data Catalog](https://cartodb.github.io/bigmetadata/observatory.pdf) (optional)
|
||||
normalize | for measures that are are **sums** (e.g. population) the default normalization is 'none' and response comes back as a raw value. Other options are 'denominator', which will use the denominator specified in the [Data Catalog](http://data-observatory.s3.amazonaws.com/observatory.pdf) (optional)
|
||||
boundary_id | source of geometries to pull measure from (e.g., 'us.census.tiger.census_tract')
|
||||
time_span | time span of interest (e.g., 2010 - 2014)
|
||||
|
||||
@@ -134,9 +134,43 @@ SET household_count = OBS_GetMeasure(the_geom, 'us.census.acs.B11001001')
|
||||
|
||||
* If an unrecognized normalization type is input, raise an error: `'Only valid inputs for "normalize" are "area" (default) and "denominator".`
|
||||
|
||||
## OBS_GetMeasureById(geom_ref text, measure_id text, boundary_id text)
|
||||
|
||||
The ```OBS_GetMeasureById(geom_ref, measure_id, boundary_id)``` function returns any Data Observatory measure that corresponds to the boundary in ```boundary_id``` that has a geometry reference of ```geom_ref```.
|
||||
|
||||
#### Arguments
|
||||
|
||||
Name |Description
|
||||
--- | ---
|
||||
geom_ref | a geometry reference (e.g., a US Census geoid)
|
||||
measure_id | a measure identifier from the Data Observatory ([see available measures](https://cartodb.github.io/bigmetadata/observatory.pdf))
|
||||
boundary_id | source of geometries to pull measure from (e.g., 'us.census.tiger.census_tract')
|
||||
time_span (optional) | time span of interest (e.g., 2010 - 2014). If `NULL` is passed, the measure from the most recent data will be used.
|
||||
|
||||
#### Returns
|
||||
|
||||
A NUMERIC value
|
||||
|
||||
Key | Description
|
||||
--- | ---
|
||||
value | the raw measure associated with `geom_ref`
|
||||
|
||||
#### Example
|
||||
|
||||
Add a measure to an empty column based on county geoids in your table
|
||||
|
||||
```SQL
|
||||
UPDATE tablename
|
||||
SET household_count = OBS_GetMeasureById(geoid_column, 'us.census.acs.B11001001', 'us.census.tiger.county')
|
||||
```
|
||||
|
||||
#### Errors
|
||||
|
||||
* Returns `NULL` if there is a mismatch between the geometry reference and the boundary id such as using the geoid of a county with the boundary of block groups
|
||||
|
||||
## OBS_GetCategory(point geometry, category_id text)
|
||||
|
||||
The ```OBS_GetCategory(point, category_id)``` function returns any Data Observatory Category value at a point location. The Categories available are currently limited to Segmentation categories. See the Segmentation section of the [Catalog](https://cartodb.github.io/bigmetadata/observatory.pdf) for more detail.
|
||||
The ```OBS_GetCategory(point, category_id)``` function returns any Data Observatory Category value at a point location. The Categories available are currently limited to Segmentation categories. See the Segmentation section of the [Catalog](http://data-observatory.s3.amazonaws.com/observatory.pdf) for more detail.
|
||||
|
||||
#### Arguments
|
||||
|
||||
|
||||
1799
release/observatory--0.0.5.sql
Normal file
1799
release/observatory--0.0.5.sql
Normal file
File diff suppressed because it is too large
Load Diff
1816
release/observatory--1.0.0.sql
Normal file
1816
release/observatory--1.0.0.sql
Normal file
File diff suppressed because it is too large
Load Diff
1816
release/observatory--1.0.1.sql
Normal file
1816
release/observatory--1.0.1.sql
Normal file
File diff suppressed because it is too large
Load Diff
2140
release/observatory--1.0.2.sql
Normal file
2140
release/observatory--1.0.2.sql
Normal file
File diff suppressed because it is too large
Load Diff
2151
release/observatory--1.0.3.sql
Normal file
2151
release/observatory--1.0.3.sql
Normal file
File diff suppressed because one or more lines are too long
2153
release/observatory--1.0.4.sql
Normal file
2153
release/observatory--1.0.4.sql
Normal file
File diff suppressed because one or more lines are too long
2153
release/observatory--1.0.5.sql
Normal file
2153
release/observatory--1.0.5.sql
Normal file
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
comment = 'CartoDB Observatory backend extension'
|
||||
default_version = '0.0.4'
|
||||
requires = 'postgis'
|
||||
default_version = '1.0.5'
|
||||
requires = 'postgis, postgres_fdw'
|
||||
superuser = true
|
||||
schema = cdb_observatory
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
from nose.tools import assert_equal, assert_is_not_none
|
||||
from nose_parameterized import parameterized
|
||||
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
|
||||
HOSTNAME = os.environ['OBS_HOSTNAME']
|
||||
API_KEY = os.environ['OBS_API_KEY']
|
||||
META_HOSTNAME = os.environ.get('OBS_META_HOSTNAME', HOSTNAME)
|
||||
META_API_KEY = os.environ.get('OBS_META_API_KEY', API_KEY)
|
||||
USE_SCHEMA = 'OBS_USE_SCHEMA' in os.environ
|
||||
|
||||
|
||||
def query(q, is_meta=False, **options):
|
||||
'''
|
||||
Query the account. Returned is the response, wrapped by the requests
|
||||
library.
|
||||
'''
|
||||
url = 'https://{hostname}/api/v2/sql'.format(
|
||||
hostname=META_HOSTNAME if is_meta else HOSTNAME)
|
||||
params = options.copy()
|
||||
params['q'] = re.sub(r'\s+', ' ', q)
|
||||
params['api_key'] = META_API_KEY if is_meta else API_KEY
|
||||
return requests.get(url, params=params)
|
||||
|
||||
MEASURE_COLUMNS = [(r['id'], ) for r in query('''
|
||||
SELECT id FROM obs_column
|
||||
WHERE type ILIKE 'numeric'
|
||||
AND weight > 0
|
||||
''', is_meta=True).json()['rows']]
|
||||
|
||||
CATEGORY_COLUMNS = [(r['id'], ) for r in query('''
|
||||
SELECT id FROM obs_column
|
||||
WHERE type ILIKE 'text'
|
||||
AND weight > 0
|
||||
''', is_meta=True).json()['rows']]
|
||||
|
||||
BOUNDARY_COLUMNS = [(r['id'], ) for r in query('''
|
||||
SELECT id FROM obs_column
|
||||
WHERE type ILIKE 'geometry'
|
||||
AND weight > 0
|
||||
''', is_meta=True).json()['rows']]
|
||||
|
||||
def default_point(column_id):
|
||||
'''
|
||||
Returns default test point for the column_id.
|
||||
'''
|
||||
if column_id == 'whosonfirst.wof_disputed_geom':
|
||||
return 'CDB_LatLng(33.78, 76.57)'
|
||||
elif column_id == 'whosonfirst.wof_marinearea_geom':
|
||||
return 'CDB_LatLng(43.33, -68.47)'
|
||||
elif column_id in ('us.census.tiger.school_district_elementary',
|
||||
'us.census.tiger.school_district_secondary',
|
||||
'us.census.tiger.school_district_elementary_clipped',
|
||||
'us.census.tiger.school_district_secondary_clipped'):
|
||||
return 'CDB_LatLng(40.7025, -73.7067)'
|
||||
elif column_id.startswith('es.ine'):
|
||||
return 'CDB_LatLng(42.8226119029222, -2.51141249535454)'
|
||||
elif column_id.startswith('us.zillow'):
|
||||
return 'CDB_LatLng(28.3305906291771, -81.3544048197256)'
|
||||
else:
|
||||
return 'CDB_LatLng(40.7, -73.9)'
|
||||
|
||||
|
||||
@parameterized(MEASURE_COLUMNS)
|
||||
def test_measure_points(column_id):
|
||||
resp = query('''
|
||||
SELECT * FROM {schema}OBS_GetMeasure({point}, '{column_id}')
|
||||
'''.format(column_id=column_id,
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
point=default_point(column_id)))
|
||||
assert_equal(resp.status_code, 200)
|
||||
rows = resp.json()['rows']
|
||||
assert_equal(1, len(rows))
|
||||
assert_is_not_none(rows[0].values()[0])
|
||||
|
||||
@parameterized(CATEGORY_COLUMNS)
|
||||
def test_category_points(column_id):
|
||||
resp = query('''
|
||||
SELECT * FROM {schema}OBS_GetCategory({point}, '{column_id}')
|
||||
'''.format(column_id=column_id,
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
point=default_point(column_id)))
|
||||
assert_equal(resp.status_code, 200)
|
||||
rows = resp.json()['rows']
|
||||
assert_equal(1, len(rows))
|
||||
assert_is_not_none(rows[0].values()[0])
|
||||
|
||||
@parameterized(BOUNDARY_COLUMNS)
|
||||
def test_boundary_points(column_id):
|
||||
resp = query('''
|
||||
SELECT * FROM {schema}OBS_GetBoundary({point}, '{column_id}')
|
||||
'''.format(column_id=column_id,
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
point=default_point(column_id)))
|
||||
assert_equal(resp.status_code, 200)
|
||||
rows = resp.json()['rows']
|
||||
assert_equal(1, len(rows))
|
||||
assert_is_not_none(rows[0].values()[0])
|
||||
@@ -33,7 +33,8 @@ def select_star(tablename):
|
||||
|
||||
cdb = Dumpr('observatory.cartodb.com','')
|
||||
|
||||
metadata = ['obs_table', 'obs_column_table', 'obs_column', 'obs_column_tag', 'obs_tag', 'obs_column_to_column']
|
||||
metadata = ['obs_table', 'obs_column_table', 'obs_column', 'obs_column_tag',
|
||||
'obs_tag', 'obs_column_to_column', 'obs_dump_version', ]
|
||||
|
||||
fixtures = [
|
||||
('us.census.tiger.census_tract', 'us.census.tiger.census_tract', '2014'),
|
||||
@@ -89,3 +90,124 @@ with open('src/pg/test/fixtures/load_fixtures.sql', 'w') as outfile:
|
||||
cdb.dump(' '.join([select_star(tablename), "WHERE {}::text {} {}".format(colname, compare, where)]),
|
||||
tablename, outfile, schema='observatory')
|
||||
dropfiles.write('DROP TABLE IF EXISTS observatory.{};\n'.format(tablename))
|
||||
|
||||
|
||||
outfile.write('''
|
||||
ALTER TABLE observatory.obs_table
|
||||
ADD PRIMARY KEY (id);
|
||||
ALTER TABLE observatory.obs_column_table
|
||||
ADD PRIMARY KEY (column_id, table_id);
|
||||
CREATE UNIQUE INDEX ON observatory.obs_column_table (table_id, column_id);
|
||||
CREATE UNIQUE INDEX ON observatory.obs_column_table (table_id, colname);
|
||||
ALTER TABLE observatory.obs_column
|
||||
ADD PRIMARY KEY (id);
|
||||
ALTER TABLE observatory.obs_column_to_column
|
||||
ADD PRIMARY KEY (source_id, target_id, reltype);
|
||||
CREATE UNIQUE INDEX ON observatory.obs_column_to_column (target_id, source_id, reltype);
|
||||
CREATE INDEX ON observatory.obs_column_to_column (reltype);
|
||||
ALTER TABLE observatory.obs_column_tag
|
||||
ADD PRIMARY KEY (column_id, tag_id);
|
||||
CREATE UNIQUE INDEX ON observatory.obs_column_tag (tag_id, column_id);
|
||||
ALTER TABLE observatory.obs_tag
|
||||
ADD PRIMARY KEY (id);
|
||||
CREATE INDEX ON observatory.obs_tag (type);
|
||||
|
||||
VACUUM ANALYZE observatory.obs_table;
|
||||
VACUUM ANALYZE observatory.obs_column_table;
|
||||
VACUUM ANALYZE observatory.obs_column;
|
||||
VACUUM ANALYZE observatory.obs_column_to_column;
|
||||
VACUUM ANALYZE observatory.obs_column_tag;
|
||||
VACUUM ANALYZE observatory.obs_tag;
|
||||
|
||||
CREATE TABLE observatory.obs_meta AS
|
||||
SELECT numer_c.id numer_id,
|
||||
denom_c.id denom_id,
|
||||
geom_c.id geom_id,
|
||||
MAX(numer_c.name) numer_name,
|
||||
MAX(denom_c.name) denom_name,
|
||||
MAX(geom_c.name) geom_name,
|
||||
MAX(numer_c.description) numer_description,
|
||||
MAX(denom_c.description) denom_description,
|
||||
MAX(geom_c.description) geom_description,
|
||||
MAX(numer_c.aggregate) numer_aggregate,
|
||||
MAX(denom_c.aggregate) denom_aggregate,
|
||||
MAX(geom_c.aggregate) geom_aggregate,
|
||||
MAX(numer_c.type) numer_type,
|
||||
MAX(denom_c.type) denom_type,
|
||||
MAX(geom_c.type) geom_type,
|
||||
MAX(numer_data_ct.colname) numer_colname,
|
||||
MAX(denom_data_ct.colname) denom_colname,
|
||||
MAX(geom_geom_ct.colname) geom_colname,
|
||||
MAX(numer_geomref_ct.colname) numer_geomref_colname,
|
||||
MAX(denom_geomref_ct.colname) denom_geomref_colname,
|
||||
MAX(geom_geomref_ct.colname) geom_geomref_colname,
|
||||
MAX(numer_t.tablename) numer_tablename,
|
||||
MAX(denom_t.tablename) denom_tablename,
|
||||
MAX(geom_t.tablename) geom_tablename,
|
||||
MAX(numer_t.timespan) numer_timespan,
|
||||
MAX(denom_t.timespan) denom_timespan,
|
||||
MAX(numer_c.weight) numer_weight,
|
||||
MAX(denom_c.weight) denom_weight,
|
||||
MAX(geom_c.weight) geom_weight,
|
||||
MAX(geom_t.timespan) geom_timespan,
|
||||
MAX(geom_t.the_geom_webmercator)::geometry AS the_geom_webmercator,
|
||||
ARRAY_AGG(DISTINCT s_tag.id) section_tags,
|
||||
ARRAY_AGG(DISTINCT ss_tag.id) subsection_tags,
|
||||
ARRAY_AGG(DISTINCT unit_tag.id) unit_tags
|
||||
FROM observatory.obs_column_table numer_data_ct,
|
||||
observatory.obs_table numer_t,
|
||||
observatory.obs_column_table numer_geomref_ct,
|
||||
observatory.obs_column geomref_c,
|
||||
observatory.obs_column_to_column geomref_c2c,
|
||||
observatory.obs_column geom_c,
|
||||
observatory.obs_column_table geom_geom_ct,
|
||||
observatory.obs_column_table geom_geomref_ct,
|
||||
observatory.obs_table geom_t,
|
||||
observatory.obs_column_tag ss_ctag,
|
||||
observatory.obs_tag ss_tag,
|
||||
observatory.obs_column_tag s_ctag,
|
||||
observatory.obs_tag s_tag,
|
||||
observatory.obs_column_tag unit_ctag,
|
||||
observatory.obs_tag unit_tag,
|
||||
observatory.obs_column numer_c
|
||||
LEFT JOIN (
|
||||
observatory.obs_column_to_column denom_c2c
|
||||
JOIN observatory.obs_column denom_c ON denom_c2c.target_id = denom_c.id
|
||||
JOIN observatory.obs_column_table denom_data_ct ON denom_data_ct.column_id = denom_c.id
|
||||
JOIN observatory.obs_table denom_t ON denom_data_ct.table_id = denom_t.id
|
||||
JOIN observatory.obs_column_table denom_geomref_ct ON denom_geomref_ct.table_id = denom_t.id
|
||||
) ON denom_c2c.source_id = numer_c.id
|
||||
WHERE numer_c.id = numer_data_ct.column_id
|
||||
AND numer_data_ct.table_id = numer_t.id
|
||||
AND numer_t.id = numer_geomref_ct.table_id
|
||||
AND numer_geomref_ct.column_id = geomref_c.id
|
||||
AND geomref_c2c.reltype = 'geom_ref'
|
||||
AND geomref_c.id = geomref_c2c.source_id
|
||||
AND geom_c.id = geomref_c2c.target_id
|
||||
AND geom_geomref_ct.column_id = geomref_c.id
|
||||
AND geom_geomref_ct.table_id = geom_t.id
|
||||
AND geom_geom_ct.column_id = geom_c.id
|
||||
AND geom_geom_ct.table_id = geom_t.id
|
||||
AND geom_c.type ILIKE 'geometry'
|
||||
AND numer_c.type NOT ILIKE 'geometry'
|
||||
AND numer_t.id != geom_t.id
|
||||
AND numer_c.id != geomref_c.id
|
||||
AND unit_tag.type = 'unit'
|
||||
AND ss_tag.type = 'subsection'
|
||||
AND s_tag.type = 'section'
|
||||
AND unit_ctag.column_id = numer_c.id
|
||||
AND unit_ctag.tag_id = unit_tag.id
|
||||
AND ss_ctag.column_id = numer_c.id
|
||||
AND ss_ctag.tag_id = ss_tag.id
|
||||
AND s_ctag.column_id = numer_c.id
|
||||
AND s_ctag.tag_id = s_tag.id
|
||||
AND (denom_c2c.reltype = 'denominator' OR denom_c2c.reltype IS NULL)
|
||||
AND (denom_geomref_ct.column_id = geomref_c.id OR denom_geomref_ct.column_id IS NULL)
|
||||
AND (denom_t.timespan = numer_t.timespan OR denom_t.timespan IS NULL)
|
||||
GROUP BY numer_c.id, denom_c.id, geom_c.id,
|
||||
numer_t.id, denom_t.id, geom_t.id;
|
||||
''')
|
||||
|
||||
dropfiles.write('''
|
||||
DROP TABLE IF EXISTS observatory.obs_meta;
|
||||
''')
|
||||
|
||||
@@ -24,7 +24,7 @@ $(DATA): $(SOURCES_DATA)
|
||||
$(SED) $(REPLACEMENTS) $(SOURCES_DATA_DIR)/*.sql > $@
|
||||
|
||||
TEST_DIR = test
|
||||
REGRESS = $(notdir $(basename $(wildcard $(TEST_DIR)/sql/*test.sql)))
|
||||
REGRESS = $(sort $(notdir $(basename $(wildcard $(TEST_DIR)/sql/*test.sql))))
|
||||
REGRESS_OPTS = --inputdir='$(TEST_DIR)' --outputdir='$(TEST_DIR)'
|
||||
|
||||
PG_CONFIG = pg_config
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
comment = 'CartoDB Observatory backend extension'
|
||||
default_version = '0.0.4'
|
||||
requires = 'postgis'
|
||||
default_version = '1.0.5'
|
||||
requires = 'postgis, postgres_fdw'
|
||||
superuser = true
|
||||
schema = cdb_observatory
|
||||
|
||||
67
src/pg/sql/15_fdw_utilities.sql
Normal file
67
src/pg/sql/15_fdw_utilities.sql
Normal file
@@ -0,0 +1,67 @@
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory._OBS_ConnectRemoteTable(fdw_name text, schema_name text, user_dbname text, user_hostname text, username text, user_tablename text, user_schema text)
|
||||
RETURNS void
|
||||
AS $$
|
||||
DECLARE
|
||||
row record;
|
||||
option record;
|
||||
connection_str json;
|
||||
BEGIN
|
||||
-- Build connection string
|
||||
connection_str := '{"server":{"extensions":"postgis", "dbname":"'
|
||||
|| user_dbname ||'", "host":"' || user_hostname ||'", "port":"6432"}, "users":{"public"'
|
||||
|| ':{"user":"' || username ||'", "password":""} } }';
|
||||
|
||||
-- This function tries to be as idempotent as possible, by not creating anything more than once
|
||||
-- (not even using IF NOT EXIST to avoid throwing warnings)
|
||||
IF NOT EXISTS ( SELECT * FROM pg_extension WHERE extname = 'postgres_fdw') THEN
|
||||
CREATE EXTENSION postgres_fdw;
|
||||
END IF;
|
||||
-- Create FDW first if it does not exist
|
||||
IF NOT EXISTS ( SELECT * FROM pg_foreign_server WHERE srvname = fdw_name)
|
||||
THEN
|
||||
EXECUTE FORMAT('CREATE SERVER %I FOREIGN DATA WRAPPER postgres_fdw', fdw_name);
|
||||
END IF;
|
||||
|
||||
-- Set FDW settings
|
||||
FOR row IN SELECT p.key, p.value from lateral json_each_text(connection_str->'server') p
|
||||
LOOP
|
||||
IF NOT EXISTS (WITH a AS (select split_part(unnest(srvoptions), '=', 1) as options from pg_foreign_server where srvname=fdw_name) SELECT * from a where options = row.key)
|
||||
THEN
|
||||
EXECUTE FORMAT('ALTER SERVER %I OPTIONS (ADD %I %L)', fdw_name, row.key, row.value);
|
||||
ELSE
|
||||
EXECUTE FORMAT('ALTER SERVER %I OPTIONS (SET %I %L)', fdw_name, row.key, row.value);
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
-- Create user mappings
|
||||
FOR row IN SELECT p.key, p.value from lateral json_each(connection_str->'users') p LOOP
|
||||
-- Check if entry on pg_user_mappings exists
|
||||
IF NOT EXISTS ( SELECT * FROM pg_user_mappings WHERE srvname = fdw_name AND usename = row.key ) THEN
|
||||
EXECUTE FORMAT ('CREATE USER MAPPING FOR %I SERVER %I', row.key, fdw_name);
|
||||
END IF;
|
||||
|
||||
-- Update user mapping settings
|
||||
FOR option IN SELECT o.key, o.value from lateral json_each_text(row.value) o LOOP
|
||||
IF NOT EXISTS (WITH a AS (select split_part(unnest(umoptions), '=', 1) as options from pg_user_mappings WHERE srvname = fdw_name AND usename = row.key) SELECT * from a where options = option.key) THEN
|
||||
EXECUTE FORMAT('ALTER USER MAPPING FOR %I SERVER %I OPTIONS (ADD %I %L)', row.key, fdw_name, option.key, option.value);
|
||||
ELSE
|
||||
EXECUTE FORMAT('ALTER USER MAPPING FOR %I SERVER %I OPTIONS (SET %I %L)', row.key, fdw_name, option.key, option.value);
|
||||
END IF;
|
||||
END LOOP;
|
||||
END LOOP;
|
||||
|
||||
-- Create schema if it does not exist.
|
||||
IF NOT EXISTS ( SELECT * from pg_namespace WHERE nspname=fdw_name) THEN
|
||||
EXECUTE FORMAT ('CREATE SCHEMA %I', fdw_name);
|
||||
END IF;
|
||||
|
||||
-- Bring the remote cdb_tablemetadata
|
||||
IF NOT EXISTS ( SELECT * FROM PG_CLASS WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname=fdw_name) and relname='cdb_tablemetadata') THEN
|
||||
EXECUTE FORMAT ('CREATE FOREIGN TABLE %I.cdb_tablemetadata (tabname text, updated_at timestamp with time zone) SERVER %I OPTIONS (table_name ''cdb_tablemetadata_text'', schema_name ''public'', updatable ''false'')', fdw_name, fdw_name);
|
||||
END IF;
|
||||
|
||||
-- Import target table
|
||||
EXECUTE FORMAT ('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I) from SERVER %I INTO %I', user_schema, user_tablename, fdw_name, schema_name);
|
||||
|
||||
END;
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
File diff suppressed because one or more lines are too long
@@ -169,19 +169,19 @@ BEGIN
|
||||
|
||||
IF geom_table_name IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'Point % is outside of the data region', ST_AsText(geom);
|
||||
--raise notice 'Point % is outside of the data region', ST_AsText(geom);
|
||||
-- TODO this should return JSON
|
||||
RETURN QUERY SELECT '{}'::json;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
IF data_table_info IS NULL THEN
|
||||
RAISE NOTICE 'Cannot find data table for boundary ID %, column_ids %, and time_span %', geometry_level, column_ids, time_span;
|
||||
--raise notice 'Cannot find data table for boundary ID %, column_ids %, and time_span %', geometry_level, column_ids, time_span;
|
||||
END IF;
|
||||
|
||||
IF ST_GeometryType(geom) = 'ST_Point'
|
||||
THEN
|
||||
RAISE NOTICE 'geom_table_name %, data_table_info %', geom_table_name, data_table_info::json[];
|
||||
--raise notice 'geom_table_name %, data_table_info %', geom_table_name, data_table_info::json[];
|
||||
results := cdb_observatory._OBS_GetPoints(geom,
|
||||
geom_table_name,
|
||||
data_table_info);
|
||||
@@ -260,7 +260,7 @@ BEGIN
|
||||
USING geom
|
||||
INTO geoid;
|
||||
|
||||
RAISE NOTICE 'geoid is %, geometry table is % ', geoid, geom_table_name;
|
||||
--raise notice 'geoid is %, geometry table is % ', geoid, geom_table_name;
|
||||
|
||||
EXECUTE
|
||||
format('SELECT ST_Area(the_geom::geography) / (1000 * 1000)
|
||||
@@ -273,7 +273,7 @@ BEGIN
|
||||
|
||||
IF area IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'No geometry at %', ST_AsText(geom);
|
||||
--raise notice 'No geometry at %', ST_AsText(geom);
|
||||
END IF;
|
||||
|
||||
query := 'SELECT Array[';
|
||||
@@ -338,48 +338,223 @@ $$ LANGUAGE plpgsql;
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetMeasure(
|
||||
geom geometry(Geometry, 4326),
|
||||
measure_id TEXT,
|
||||
normalize TEXT DEFAULT 'area', -- TODO none/null
|
||||
normalize TEXT DEFAULT NULL,
|
||||
boundary_id TEXT DEFAULT NULL,
|
||||
time_span TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS NUMERIC
|
||||
AS $$
|
||||
DECLARE
|
||||
geom_type TEXT;
|
||||
map_type TEXT;
|
||||
numer_aggregate TEXT;
|
||||
numer_colname TEXT;
|
||||
numer_geomref_colname TEXT;
|
||||
numer_tablename TEXT;
|
||||
denom_colname TEXT;
|
||||
denom_geomref_colname TEXT;
|
||||
denom_tablename TEXT;
|
||||
geom_colname TEXT;
|
||||
geom_geomref_colname TEXT;
|
||||
geom_tablename TEXT;
|
||||
result NUMERIC;
|
||||
measure_ids TEXT[];
|
||||
denominator_id TEXT;
|
||||
vals NUMERIC[];
|
||||
sql TEXT;
|
||||
numer_name TEXT;
|
||||
BEGIN
|
||||
geom := ST_SnapToGrid(geom, 0.000001);
|
||||
|
||||
IF normalize ILIKE 'area' THEN
|
||||
measure_ids := ARRAY[measure_id];
|
||||
EXECUTE
|
||||
$query$
|
||||
SELECT numer_aggregate, numer_colname, numer_geomref_colname, numer_tablename,
|
||||
denom_colname, denom_geomref_colname, denom_tablename,
|
||||
geom_colname, geom_geomref_colname, geom_tablename, numer_name
|
||||
FROM observatory.obs_meta
|
||||
WHERE (geom_id = $1 OR ($1 = ''))
|
||||
AND numer_id = $2
|
||||
AND (numer_timespan = $3 OR ($3 = ''))
|
||||
ORDER BY geom_weight DESC, numer_timespan DESC
|
||||
LIMIT 1
|
||||
$query$
|
||||
INTO numer_aggregate, numer_colname, numer_geomref_colname, numer_tablename,
|
||||
denom_colname, denom_geomref_colname, denom_tablename,
|
||||
geom_colname, geom_geomref_colname, geom_tablename, numer_name
|
||||
USING COALESCE(boundary_id, ''), measure_id, COALESCE(time_span, '');
|
||||
|
||||
IF ST_GeometryType(geom) = 'ST_Point' THEN
|
||||
geom_type := 'point';
|
||||
ELSIF ST_GeometryType(geom) IN ('ST_Polygon', 'ST_MultiPolygon') THEN
|
||||
geom_type := 'polygon';
|
||||
geom := ST_Buffer(geom, 0.000001);
|
||||
ELSE
|
||||
RAISE EXCEPTION 'Invalid geometry type (%), can only handle ''ST_Point'', ''ST_Polygon'', and ''ST_MultiPolygon''',
|
||||
ST_GeometryType(geom);
|
||||
END IF;
|
||||
|
||||
IF normalize ILIKE 'area' AND numer_aggregate ILIKE 'sum' THEN
|
||||
map_type := 'areaNormalized';
|
||||
ELSIF normalize ILIKE 'denominator' THEN
|
||||
EXECUTE 'SELECT (cdb_observatory._OBS_GetRelatedColumn(ARRAY[$1], ''denominator''))[1]
|
||||
' INTO denominator_id
|
||||
USING measure_id;
|
||||
measure_ids := ARRAY[measure_id, denominator_id];
|
||||
ELSIF normalize ILIKE 'none' THEN
|
||||
-- TODO we need a switch on obs_get to disable area normalization
|
||||
RAISE EXCEPTION 'No normalization not yet supported.';
|
||||
map_type := 'denominated';
|
||||
ELSE
|
||||
RAISE EXCEPTION 'Only valid inputs for "normalize" are "area" (default) and "denominator".';
|
||||
-- defaults: area normalization for point if it's possible and none for
|
||||
-- polygon or non-summable point
|
||||
IF geom_type = 'point' AND numer_aggregate ILIKE 'sum' THEN
|
||||
map_type := 'areaNormalized';
|
||||
ELSE
|
||||
map_type := 'predenominated';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
EXECUTE '
|
||||
SELECT ARRAY_AGG(val) FROM (SELECT (cdb_observatory._OBS_Get($1, $2, $3, $4)->>''value'')::NUMERIC val) b
|
||||
'
|
||||
INTO vals
|
||||
USING geom, measure_ids, time_span, boundary_id;
|
||||
|
||||
IF normalize ILIKE 'denominator' THEN
|
||||
RETURN (vals)[1]/(vals)[2];
|
||||
ELSE
|
||||
RETURN (vals)[1];
|
||||
IF geom_type = 'point' THEN
|
||||
IF map_type = 'areaNormalized' THEN
|
||||
sql = format('WITH _geom AS (SELECT ST_Area(geom.%I::Geography) / 1000000 area, geom.%I geom_ref
|
||||
FROM observatory.%I geom
|
||||
WHERE ST_Within(%L, geom.%I)
|
||||
LIMIT 1)
|
||||
SELECT numer.%I / (SELECT area FROM _geom)
|
||||
FROM observatory.%I numer
|
||||
WHERE numer.%I = (SELECT geom_ref FROM _geom)',
|
||||
geom_colname, geom_geomref_colname, geom_tablename,
|
||||
geom, geom_colname, numer_colname, numer_tablename,
|
||||
numer_geomref_colname);
|
||||
ELSIF map_type = 'denominated' THEN
|
||||
sql = format('SELECT numer.%I / NULLIF((SELECT denom.%I FROM observatory.%I denom WHERE denom.%I = numer.%I LIMIT 1), 0)
|
||||
FROM observatory.%I numer
|
||||
WHERE numer.%I = (SELECT geom.%I FROM observatory.%I geom WHERE ST_Within(%L, geom.%I) LIMIT 1)',
|
||||
numer_colname, denom_colname, denom_tablename,
|
||||
denom_geomref_colname, numer_geomref_colname,
|
||||
numer_tablename,
|
||||
numer_geomref_colname, geom_geomref_colname,
|
||||
geom_tablename, geom, geom_colname);
|
||||
ELSIF map_type = 'predenominated' THEN
|
||||
sql = format('SELECT numer.%I
|
||||
FROM observatory.%I numer
|
||||
WHERE numer.%I = (SELECT geom.%I FROM observatory.%I geom WHERE ST_Within(%L, geom.%I) LIMIT 1)',
|
||||
numer_colname, numer_tablename,
|
||||
numer_geomref_colname, geom_geomref_colname, geom_tablename,
|
||||
geom, geom_colname);
|
||||
END IF;
|
||||
ELSIF geom_type = 'polygon' THEN
|
||||
IF map_type = 'areaNormalized' THEN
|
||||
sql = format('WITH _geom AS (SELECT ST_Area(ST_Intersection(%L, geom.%I))
|
||||
/ ST_Area(geom.%I) overlap, geom.%I geom_ref
|
||||
FROM observatory.%I geom
|
||||
WHERE ST_Intersects(%L, geom.%I)
|
||||
AND ST_Area(ST_Intersection(%L, geom.%I)) / ST_Area(geom.%I) > 0)
|
||||
SELECT SUM(numer.%I * (SELECT _geom.overlap FROM _geom WHERE _geom.geom_ref = numer.%I)) /
|
||||
(ST_Area(%L::Geography) / 1000000)
|
||||
FROM observatory.%I numer
|
||||
WHERE numer.%I = ANY ((SELECT ARRAY_AGG(geom_ref) FROM _geom)::TEXT[])',
|
||||
geom, geom_colname, geom_colname,
|
||||
geom_geomref_colname, geom_tablename,
|
||||
geom, geom_colname,
|
||||
geom, geom_colname, geom_colname,
|
||||
numer_colname, numer_geomref_colname,
|
||||
geom, numer_tablename,
|
||||
numer_geomref_colname);
|
||||
ELSIF map_type = 'denominated' THEN
|
||||
sql = format('WITH _geom AS (SELECT ST_Area(ST_Intersection(%L, geom.%I))
|
||||
/ ST_Area(geom.%I) overlap, geom.%I geom_ref
|
||||
FROM observatory.%I geom
|
||||
WHERE ST_Intersects(%L, geom.%I)
|
||||
AND ST_Area(ST_Intersection(%L, geom.%I)) / ST_Area(geom.%I) > 0),
|
||||
_denom AS (SELECT denom.%I, denom.%I geom_ref
|
||||
FROM observatory.%I denom
|
||||
WHERE denom.%I = ANY ((SELECT ARRAY_AGG(geom_ref) FROM _geom)::TEXT[]))
|
||||
SELECT SUM(numer.%I * (SELECT _geom.overlap FROM _geom WHERE _geom.geom_ref = numer.%I)) /
|
||||
SUM((SELECT _denom.%I * (SELECT _geom.overlap
|
||||
FROM _geom
|
||||
WHERE _geom.geom_ref = _denom.geom_ref)
|
||||
FROM _denom WHERE _denom.geom_ref = numer.%I))
|
||||
FROM observatory.%I numer
|
||||
WHERE numer.%I = ANY ((SELECT ARRAY_AGG(geom_ref) FROM _geom)::TEXT[])',
|
||||
geom, geom_colname,
|
||||
geom_colname, geom_geomref_colname,
|
||||
geom_tablename,
|
||||
geom, geom_colname,
|
||||
geom, geom_colname, geom_colname,
|
||||
denom_colname, denom_geomref_colname,
|
||||
denom_tablename,
|
||||
denom_geomref_colname,
|
||||
numer_colname, numer_geomref_colname,
|
||||
denom_colname,
|
||||
numer_geomref_colname,
|
||||
numer_tablename,
|
||||
numer_geomref_colname);
|
||||
ELSIF map_type = 'predenominated' THEN
|
||||
IF numer_aggregate NOT ILIKE 'sum' THEN
|
||||
RAISE EXCEPTION 'Cannot calculate "%" (%) for custom area as it cannot be summed, use ST_PointOnSurface instead',
|
||||
numer_name, measure_id;
|
||||
ELSE
|
||||
sql = format('WITH _geom AS (SELECT ST_Area(ST_Intersection(%L, geom.%I))
|
||||
/ ST_Area(geom.%I) overlap, geom.%I geom_ref
|
||||
FROM observatory.%I geom
|
||||
WHERE ST_Intersects(%L, geom.%I)
|
||||
AND ST_Area(ST_Intersection(%L, geom.%I)) / ST_Area(geom.%I) > 0)
|
||||
SELECT SUM(numer.%I * (SELECT _geom.overlap FROM _geom WHERE _geom.geom_ref = numer.%I))
|
||||
FROM observatory.%I numer
|
||||
WHERE numer.%I = ANY ((SELECT ARRAY_AGG(geom_ref) FROM _geom)::TEXT[])',
|
||||
geom, geom_colname, geom_colname,
|
||||
geom_geomref_colname, geom_tablename,
|
||||
geom, geom_colname,
|
||||
geom, geom_colname, geom_colname,
|
||||
numer_colname, numer_geomref_colname,
|
||||
numer_tablename,
|
||||
numer_geomref_colname);
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
EXECUTE sql INTO result;
|
||||
RETURN result;
|
||||
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetMeasureById(
|
||||
geom_ref TEXT,
|
||||
measure_id TEXT,
|
||||
boundary_id TEXT,
|
||||
time_span TEXT DEFAULT NULL
|
||||
)
|
||||
RETURNS NUMERIC
|
||||
AS $$
|
||||
DECLARE
|
||||
target_table TEXT;
|
||||
colname TEXT;
|
||||
measure_val NUMERIC;
|
||||
data_geoid_colname TEXT;
|
||||
BEGIN
|
||||
|
||||
EXECUTE
|
||||
$query$
|
||||
SELECT numer_colname, numer_geomref_colname, numer_tablename
|
||||
FROM observatory.obs_meta
|
||||
WHERE (geom_id = $1 OR ($1 = ''))
|
||||
AND numer_id = $2
|
||||
AND (numer_timespan = $3 OR ($3 = ''))
|
||||
ORDER BY geom_weight DESC, numer_timespan DESC
|
||||
LIMIT 1
|
||||
$query$
|
||||
INTO colname, data_geoid_colname, target_table
|
||||
USING COALESCE(boundary_id, ''), measure_id, COALESCE(time_span, '');
|
||||
|
||||
--RAISE DEBUG 'target_table %, colname %', target_table, colname;
|
||||
|
||||
EXECUTE format(
|
||||
'SELECT %I
|
||||
FROM observatory.%I data
|
||||
WHERE data.%I = %L',
|
||||
colname,
|
||||
target_table,
|
||||
data_geoid_colname, geom_ref)
|
||||
INTO measure_val;
|
||||
|
||||
RETURN measure_val;
|
||||
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetCategory(
|
||||
geom geometry(Geometry, 4326),
|
||||
category_id TEXT,
|
||||
@@ -389,27 +564,61 @@ CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetCategory(
|
||||
RETURNS TEXT
|
||||
AS $$
|
||||
DECLARE
|
||||
denominator_id TEXT;
|
||||
categories TEXT[];
|
||||
data_table TEXT;
|
||||
geom_table TEXT;
|
||||
colname TEXT;
|
||||
data_geomref_colname TEXT;
|
||||
geom_geomref_colname TEXT;
|
||||
geom_colname TEXT;
|
||||
category_val TEXT;
|
||||
category_share NUMERIC;
|
||||
BEGIN
|
||||
|
||||
IF boundary_id IS NULL THEN
|
||||
-- TODO we should determine best boundary for this geom
|
||||
boundary_id := 'us.census.tiger.census_tract';
|
||||
EXECUTE
|
||||
$query$
|
||||
SELECT numer_colname, numer_geomref_colname, numer_tablename,
|
||||
geom_geomref_colname, geom_colname, geom_tablename
|
||||
FROM observatory.obs_meta
|
||||
WHERE (geom_id = $1 OR ($1 = ''))
|
||||
AND numer_id = $2
|
||||
AND (numer_timespan = $3 OR ($3 = ''))
|
||||
ORDER BY geom_weight DESC, numer_timespan DESC
|
||||
LIMIT 1
|
||||
$query$
|
||||
INTO colname, data_geomref_colname, data_table,
|
||||
geom_geomref_colname, geom_colname, geom_table
|
||||
USING COALESCE(boundary_id, ''), category_id, COALESCE(time_span, '');
|
||||
|
||||
IF ST_GeometryType(geom) = 'ST_Point' THEN
|
||||
EXECUTE format(
|
||||
'SELECT data.%I
|
||||
FROM observatory.%I data, observatory.%I geom
|
||||
WHERE data.%I = geom.%I
|
||||
AND ST_WITHIN(%L, geom.%I) ',
|
||||
colname, data_table, geom_table, data_geomref_colname,
|
||||
geom_geomref_colname, geom, geom_colname)
|
||||
INTO category_val;
|
||||
ELSE
|
||||
-- favor the category with the most area
|
||||
EXECUTE format(
|
||||
'SELECT data.%I category, SUM(overlap_fraction) category_share
|
||||
FROM observatory.%I data, (
|
||||
SELECT ST_Area(
|
||||
ST_Intersection(%L, a.%I)
|
||||
) / ST_Area(%L) AS overlap_fraction, a.%I geomref
|
||||
FROM observatory.%I as a
|
||||
WHERE %L && a.%I) _overlaps
|
||||
WHERE data.%I = _overlaps.geomref
|
||||
GROUP BY category
|
||||
ORDER BY SUM(overlap_fraction) DESC
|
||||
LIMIT 1',
|
||||
colname, data_table,
|
||||
geom, geom_colname, geom, geom_geomref_colname,
|
||||
geom_table, geom, geom_colname, data_geomref_colname)
|
||||
INTO category_val, category_share;
|
||||
END IF;
|
||||
|
||||
IF time_span IS NULL THEN
|
||||
-- TODO we should determine latest timespan for this measure
|
||||
time_span := '2010 - 2014';
|
||||
END IF;
|
||||
|
||||
EXECUTE '
|
||||
SELECT ARRAY_AGG(val) FROM (SELECT (cdb_observatory._OBS_GetCategories($1, $2, $3, $4))->>''category'' val LIMIT 1) b
|
||||
'
|
||||
INTO categories
|
||||
USING geom, ARRAY[category_id], boundary_id, time_span;
|
||||
|
||||
RETURN (categories)[1];
|
||||
RETURN category_val;
|
||||
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
@@ -417,7 +626,7 @@ $$ LANGUAGE plpgsql;
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetUSCensusMeasure(
|
||||
geom geometry(Geometry, 4326),
|
||||
name TEXT,
|
||||
normalize TEXT DEFAULT 'area',
|
||||
normalize TEXT DEFAULT NULL,
|
||||
boundary_id TEXT DEFAULT NULL,
|
||||
time_span TEXT DEFAULT NULL
|
||||
)
|
||||
@@ -483,7 +692,7 @@ $$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetPopulation(
|
||||
geom geometry(Geometry, 4326),
|
||||
normalize TEXT DEFAULT 'area',
|
||||
normalize TEXT DEFAULT NULL,
|
||||
boundary_id TEXT DEFAULT NULL,
|
||||
time_span TEXT DEFAULT NULL
|
||||
)
|
||||
@@ -586,7 +795,7 @@ BEGIN
|
||||
q := q || q_select || format('FROM observatory.%I ', ((data_table_info)[1]->>'tablename'));
|
||||
|
||||
q := format(q || ' ) ' || q_sum || ' ]::numeric[] FROM _overlaps, values
|
||||
WHERE values.%I = _overlaps.%I', geom_geoid_colname, geom_geoid_colname);
|
||||
WHERE values.%I = _overlaps.%I', data_geoid_colname, geom_geoid_colname);
|
||||
|
||||
EXECUTE
|
||||
q
|
||||
@@ -749,7 +958,7 @@ BEGIN
|
||||
|
||||
IF geom_table_name IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'Point % is outside of the data region', ST_AsText(geom);
|
||||
--raise notice 'Point % is outside of the data region', ST_AsText(geom);
|
||||
RETURN QUERY SELECT '{}'::text[], '{}'::text[];
|
||||
RETURN;
|
||||
END IF;
|
||||
@@ -763,7 +972,7 @@ BEGIN
|
||||
|
||||
IF data_table_info IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'No data table found for this location';
|
||||
--raise notice 'No data table found for this location';
|
||||
RETURN QUERY SELECT NULL::json;
|
||||
RETURN;
|
||||
END IF;
|
||||
@@ -778,7 +987,7 @@ BEGIN
|
||||
|
||||
IF geoid IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'No geometry id for this location';
|
||||
--raise notice 'No geometry id for this location';
|
||||
RETURN QUERY SELECT NULL::json;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
@@ -114,7 +114,7 @@ BEGIN
|
||||
AND
|
||||
observatory.OBS_column.type = 'Geometry'
|
||||
AND
|
||||
$1 && bounds::box2d
|
||||
ST_Intersects($1, st_setsrid(observatory.obs_table.the_geom, 4326))
|
||||
$string$ || timespan_query
|
||||
USING geom;
|
||||
RETURN;
|
||||
|
||||
@@ -64,11 +64,11 @@ BEGIN
|
||||
-- if no tables are found, raise notice and return null
|
||||
IF target_table IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'No boundaries found for ''%'' in ''%''', ST_AsText(geom), boundary_id;
|
||||
--RAISE NOTICE 'No boundaries found for ''%'' in ''%''', ST_AsText(geom), boundary_id;
|
||||
RETURN NULL::geometry;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE 'target_table: %', target_table;
|
||||
--RAISE NOTICE 'target_table: %', target_table;
|
||||
|
||||
-- return the first boundary in intersections
|
||||
EXECUTE format(
|
||||
@@ -143,7 +143,7 @@ BEGIN
|
||||
-- if no tables are found, raise notice and return null
|
||||
IF target_table IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'Warning: No boundaries found for ''%''', boundary_id;
|
||||
--RAISE NOTICE 'Warning: No boundaries found for ''%''', boundary_id;
|
||||
RETURN NULL::text;
|
||||
END IF;
|
||||
|
||||
@@ -159,7 +159,7 @@ BEGIN
|
||||
, target_table)
|
||||
INTO geoid_colname;
|
||||
|
||||
RAISE NOTICE 'target_table: %, geoid_colname: %', target_table, geoid_colname;
|
||||
--RAISE NOTICE 'target_table: %, geoid_colname: %', target_table, geoid_colname;
|
||||
|
||||
-- return geometry id column value
|
||||
EXECUTE format(
|
||||
@@ -212,11 +212,11 @@ BEGIN
|
||||
SELECT * INTO geoid_colname, target_table, geom_colname
|
||||
FROM cdb_observatory._OBS_GetGeometryMetadata(boundary_id);
|
||||
|
||||
RAISE NOTICE '%', target_table;
|
||||
--RAISE NOTICE '%', target_table;
|
||||
|
||||
IF target_table IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'No geometries found';
|
||||
--RAISE NOTICE 'No geometries found';
|
||||
RETURN NULL::geometry;
|
||||
END IF;
|
||||
|
||||
@@ -244,7 +244,7 @@ CREATE OR REPLACE FUNCTION cdb_observatory._OBS_GetBoundariesByGeometry(
|
||||
geom geometry(Geometry, 4326),
|
||||
boundary_id text,
|
||||
time_span text DEFAULT NULL,
|
||||
overlap_type text DEFAULT 'intersects')
|
||||
overlap_type text DEFAULT NULL)
|
||||
RETURNS TABLE(the_geom geometry, geom_refs text)
|
||||
AS $$
|
||||
DECLARE
|
||||
@@ -253,7 +253,7 @@ DECLARE
|
||||
geoid_colname text;
|
||||
target_table text;
|
||||
BEGIN
|
||||
|
||||
overlap_type := COALESCE(overlap_type, 'intersects');
|
||||
-- check inputs
|
||||
IF lower(overlap_type) NOT IN ('contains', 'intersects', 'within')
|
||||
THEN
|
||||
@@ -272,12 +272,12 @@ BEGIN
|
||||
-- if no tables are found, raise notice and return null
|
||||
IF target_table IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'No boundaries found for bounding box ''%'' in ''%''', ST_AsText(geom), boundary_id;
|
||||
--RAISE NOTICE 'No boundaries found for bounding box ''%'' in ''%''', ST_AsText(geom), boundary_id;
|
||||
RETURN QUERY SELECT NULL::geometry, NULL::text;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE 'target_table: %', target_table;
|
||||
--RAISE NOTICE 'target_table: %', target_table;
|
||||
|
||||
-- return first boundary in intersections
|
||||
RETURN QUERY
|
||||
@@ -318,7 +318,7 @@ CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetBoundariesByGeometry(
|
||||
geom geometry(Geometry, 4326),
|
||||
boundary_id text,
|
||||
time_span text DEFAULT NULL,
|
||||
overlap_type text DEFAULT 'intersects')
|
||||
overlap_type text DEFAULT NULL)
|
||||
RETURNS TABLE(the_geom geometry, geom_refs text)
|
||||
AS $$
|
||||
BEGIN
|
||||
@@ -364,7 +364,7 @@ CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetBoundariesByPointAndRadius(
|
||||
radius numeric, -- radius in meters
|
||||
boundary_id text,
|
||||
time_span text DEFAULT NULL,
|
||||
overlap_type text DEFAULT 'intersects')
|
||||
overlap_type text DEFAULT NULL)
|
||||
RETURNS TABLE(the_geom geometry, geom_refs text)
|
||||
AS $$
|
||||
DECLARE
|
||||
@@ -382,7 +382,8 @@ BEGIN
|
||||
FROM cdb_observatory._OBS_GetBoundariesByGeometry(
|
||||
circle_boundary,
|
||||
boundary_id,
|
||||
time_span);
|
||||
time_span,
|
||||
overlap_type);
|
||||
RETURN;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
@@ -394,7 +395,7 @@ CREATE OR REPLACE FUNCTION cdb_observatory._OBS_GetPointsByGeometry(
|
||||
geom geometry(Geometry, 4326),
|
||||
boundary_id text,
|
||||
time_span text DEFAULT NULL,
|
||||
overlap_type text DEFAULT 'intersects')
|
||||
overlap_type text DEFAULT NULL)
|
||||
RETURNS TABLE(the_geom geometry, geom_refs text)
|
||||
AS $$
|
||||
DECLARE
|
||||
@@ -403,6 +404,7 @@ DECLARE
|
||||
geoid_colname text;
|
||||
target_table text;
|
||||
BEGIN
|
||||
overlap_type := COALESCE(overlap_type, 'intersects');
|
||||
|
||||
IF lower(overlap_type) NOT IN ('contains', 'within', 'intersects')
|
||||
THEN
|
||||
@@ -418,12 +420,12 @@ BEGIN
|
||||
-- if no tables are found, raise notice and return null
|
||||
IF target_table IS NULL
|
||||
THEN
|
||||
RAISE NOTICE 'No boundaries found for bounding box ''%'' in ''%''', ST_AsText(geom), boundary_id;
|
||||
--RAISE NOTICE 'No boundaries found for bounding box ''%'' in ''%''', ST_AsText(geom), boundary_id;
|
||||
RETURN QUERY SELECT NULL::geometry, NULL::text;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE 'target_table: %', target_table;
|
||||
--RAISE NOTICE 'target_table: %', target_table;
|
||||
|
||||
-- return first boundary in intersections
|
||||
RETURN QUERY
|
||||
@@ -464,7 +466,7 @@ CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetPointsByGeometry(
|
||||
geom geometry(Geometry, 4326),
|
||||
boundary_id text,
|
||||
time_span text DEFAULT NULL,
|
||||
overlap_type text DEFAULT 'intersects')
|
||||
overlap_type text DEFAULT NULL)
|
||||
RETURNS TABLE(the_geom geometry, geom_refs text)
|
||||
AS $$
|
||||
BEGIN
|
||||
@@ -509,7 +511,7 @@ CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetPointsByPointAndRadius(
|
||||
radius numeric, -- radius in meters
|
||||
boundary_id text,
|
||||
time_span text DEFAULT NULL,
|
||||
overlap_type text DEFAULT 'intersects')
|
||||
overlap_type text DEFAULT NULL)
|
||||
RETURNS TABLE(the_geom geometry, geom_refs text)
|
||||
AS $$
|
||||
DECLARE
|
||||
|
||||
119
src/pg/sql/50_table_level_functions.sql
Normal file
119
src/pg/sql/50_table_level_functions.sql
Normal file
@@ -0,0 +1,119 @@
|
||||
CREATE TYPE cdb_observatory.ds_fdw_metadata as (schemaname text, tabname text, servername text);
|
||||
CREATE TYPE cdb_observatory.ds_return_metadata as (colnames text[], coltypes text[]);
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory._OBS_ConnectUserTable(username text, orgname text, user_db_role text, input_schema text, dbname text, host_addr text, table_name text)
|
||||
RETURNS cdb_observatory.ds_fdw_metadata
|
||||
AS $$
|
||||
DECLARE
|
||||
fdw_server text;
|
||||
fdw_import_schema text;
|
||||
connection_str json;
|
||||
import_foreign_schema_q text;
|
||||
epoch_timestamp text;
|
||||
BEGIN
|
||||
|
||||
SELECT extract(epoch from now() at time zone 'utc')::int INTO epoch_timestamp;
|
||||
fdw_server := 'fdw_server_' || username || '_' || epoch_timestamp;
|
||||
fdw_import_schema:= fdw_server;
|
||||
|
||||
-- Import foreign table
|
||||
EXECUTE FORMAT ('SELECT cdb_observatory._OBS_ConnectRemoteTable(%L, %L, %L, %L, %L, %L, %L)', fdw_server, fdw_import_schema, dbname, host_addr, user_db_role, table_name, input_schema);
|
||||
|
||||
RETURN (fdw_import_schema::text, table_name::text, fdw_server::text);
|
||||
|
||||
EXCEPTION
|
||||
WHEN others THEN
|
||||
-- Disconnect user imported table. Delete schema and FDW server.
|
||||
EXECUTE 'DROP FOREIGN TABLE IF EXISTS ' || fdw_import_schema || '.' || table_name;
|
||||
EXECUTE 'DROP SCHEMA IF EXISTS ' || fdw_import_schema || ' CASCADE';
|
||||
EXECUTE 'DROP SERVER IF EXISTS ' || fdw_server || ' CASCADE;';
|
||||
RETURN (null, null, null);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory._OBS_GetReturnMetadata(username text, orgname text, function_name text, params json)
|
||||
RETURNS cdb_observatory.ds_return_metadata
|
||||
AS $$
|
||||
DECLARE
|
||||
colnames text[];
|
||||
coltypes text[];
|
||||
requested_measures text[];
|
||||
measure text;
|
||||
BEGIN
|
||||
|
||||
-- Simple mock, there should be real logic in here.
|
||||
|
||||
IF $3 NOT ILIKE 'GetMeasure' OR $3 IS NULL THEN
|
||||
RAISE 'This function is not supported yet: %', $3;
|
||||
END IF;
|
||||
|
||||
SELECT translate($4::json->>'tag_name','[]', '{}')::text[] INTO requested_measures;
|
||||
|
||||
FOREACH measure IN ARRAY requested_measures
|
||||
LOOP
|
||||
IF NOT measure ILIKE ANY (Array['total_pop', 'pop_16_over']::text[]) THEN
|
||||
RAISE 'This measure is not supported yet: %', measure;
|
||||
END IF;
|
||||
SELECT array_append(colnames, measure) INTO colnames;
|
||||
SELECT array_append(coltypes, 'double precision'::text) INTO coltypes;
|
||||
|
||||
END LOOP;
|
||||
|
||||
RETURN (colnames::text[], coltypes::text[]);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory._OBS_FetchJoinFdwTableData(username text, orgname text, table_schema text, table_name text, function_name text, params json)
|
||||
RETURNS SETOF record
|
||||
AS $$
|
||||
DECLARE
|
||||
data_query text;
|
||||
tag_name text[];
|
||||
tag text;
|
||||
tags_list text;
|
||||
tags_query text;
|
||||
rec RECORD;
|
||||
BEGIN
|
||||
SELECT translate($6::json->>'tag_name','[]', '{}')::text[] INTO tag_name;
|
||||
SELECT array_to_string(tag_name, ',') INTO tags_list;
|
||||
tags_query := '';
|
||||
|
||||
FOREACH tag IN ARRAY tag_name
|
||||
LOOP
|
||||
SELECT tags_query || ' sum(' || tag || '/fraction)::double precision as ' || tag || ', ' INTO tags_query;
|
||||
|
||||
END LOOP;
|
||||
|
||||
-- Simple mock, there should be real logic in here.
|
||||
data_query := '(WITH _areas AS(SELECT ST_Area(a.the_geom::geography)'
|
||||
|| '/ (1000 * 1000) as fraction, a.geoid, b.cartodb_id FROM '
|
||||
|| 'observatory.obs_c6fb99c47d61289fbb8e561ff7773799d3fcc308 as a, '
|
||||
|| table_schema || '.' || table_name || ' AS b '
|
||||
|| 'WHERE b.the_geom && a.the_geom ), values AS (SELECT geoid, '
|
||||
|| tags_list
|
||||
|| ' FROM observatory.obs_1a098da56badf5f32e336002b0a81708c40d29cd ) '
|
||||
|| 'SELECT '
|
||||
|| tags_query
|
||||
|| ' cartodb_id::int FROM _areas, values '
|
||||
|| 'WHERE values.geoid = _areas.geoid GROUP BY cartodb_id);';
|
||||
|
||||
|
||||
FOR rec IN EXECUTE data_query
|
||||
LOOP
|
||||
RETURN NEXT rec;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_observatory._OBS_DisconnectUserTable(username text, orgname text, table_schema text, table_name text, servername text)
|
||||
RETURNS boolean
|
||||
AS $$
|
||||
BEGIN
|
||||
EXECUTE 'DROP FOREIGN TABLE IF EXISTS "' || table_schema || '".' || table_name;
|
||||
EXECUTE 'DROP SCHEMA IF EXISTS ' || table_schema || ' CASCADE';
|
||||
EXECUTE 'DROP SERVER IF EXISTS ' || servername || ' CASCADE;';
|
||||
RETURN true;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
@@ -1,6 +1,5 @@
|
||||
-- Install dependencies
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
CREATE EXTENSION postgres_fdw;
|
||||
-- Install the extension
|
||||
CREATE EXTENSION observatory VERSION 'dev';
|
||||
|
||||
@@ -9,21 +9,15 @@ t
|
||||
_obs_geomtable_with_null_response
|
||||
t
|
||||
(1 row)
|
||||
test_get_obs_column_with_geoid_and_census_1|test_get_obs_column_with_geoid_and_census_2
|
||||
t|t
|
||||
(1 row)
|
||||
obs_getcolumndata_missing_measure
|
||||
t
|
||||
(1 row)
|
||||
_obs_buildsnapshotquery_test_1
|
||||
t
|
||||
(1 row)
|
||||
_obs_buildsnapshotquery_test_2
|
||||
t
|
||||
(1 row)
|
||||
_obs_getrelatedcolumn_test
|
||||
t
|
||||
(1 row)
|
||||
_obs_standardizemeasurename_test
|
||||
t
|
||||
(1 row)
|
||||
obs_dumpversion_notnull
|
||||
t
|
||||
(1 row)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
\i test/fixtures/load_fixtures.sql
|
||||
SET client_min_messages TO WARNING;
|
||||
\pset format unaligned
|
||||
\set ECHO none
|
||||
obs_getdemographicsnapshot_test_no_returns
|
||||
t
|
||||
@@ -43,15 +42,30 @@ t
|
||||
obs_getmeasure_total_pop_point_test
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasure_total_pop_point_null_normalization_test
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasure_total_pop_point_area_test
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasure_total_pop_polygon_test
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasure_total_pop_polygon_null_normalization_test
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasure_total_pop_polygon_area_test
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasure_total_male_point_denominator
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasure_total_male_poly_denominator
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasure_bad_geometry
|
||||
t
|
||||
(1 row)
|
||||
obs_getcategory_point
|
||||
t
|
||||
(1 row)
|
||||
@@ -64,15 +78,33 @@ t
|
||||
obs_getpopulation_polygon_test
|
||||
t
|
||||
(1 row)
|
||||
obs_getpopulation_polygon_null_test
|
||||
t
|
||||
(1 row)
|
||||
obs_getuscensusmeasure_point_male_pop
|
||||
t
|
||||
(1 row)
|
||||
obs_getuscensusmeasure
|
||||
t
|
||||
(1 row)
|
||||
obs_getuscensusmeasure_null
|
||||
t
|
||||
(1 row)
|
||||
obs_getuscensuscategory_point
|
||||
t
|
||||
(1 row)
|
||||
obs_getuscensuscategory_polygon
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasurebyid_cartodb_census_tract
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasurebyid_null_boundary_null_timespan
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasurebyid_cartodb_block_group
|
||||
t
|
||||
(1 row)
|
||||
obs_getmeasurebyid_nulls
|
||||
t
|
||||
(1 row)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
\i test/fixtures/load_fixtures.sql
|
||||
SET client_min_messages TO WARNING;
|
||||
\pset format unaligned
|
||||
\set ECHO none
|
||||
_obs_searchtables_tables_match|_obs_searchtables_timespan_matches
|
||||
t|t
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
\pset format unaligned
|
||||
\set ECHO all
|
||||
\i test/fixtures/load_fixtures.sql
|
||||
SET client_min_messages TO WARNING;
|
||||
\set ECHO none
|
||||
obs_getboundary_cartodb_census_tract
|
||||
t
|
||||
|
||||
3
src/pg/test/fixtures/drop_fixtures.sql
vendored
3
src/pg/test/fixtures/drop_fixtures.sql
vendored
@@ -6,6 +6,7 @@ DROP TABLE IF EXISTS observatory.obs_column;
|
||||
DROP TABLE IF EXISTS observatory.obs_column_tag;
|
||||
DROP TABLE IF EXISTS observatory.obs_tag;
|
||||
DROP TABLE IF EXISTS observatory.obs_column_to_column;
|
||||
DROP TABLE IF EXISTS observatory.obs_dump_version;
|
||||
DROP TABLE IF EXISTS observatory.obs_65f29658e096ca1485bf683f65fdbc9f05ec3c5d;
|
||||
DROP TABLE IF EXISTS observatory.obs_1746e37b7cd28cb131971ea4187d42d71f09c5f3;
|
||||
DROP TABLE IF EXISTS observatory.obs_1a098da56badf5f32e336002b0a81708c40d29cd;
|
||||
@@ -19,3 +20,5 @@ DROP TABLE IF EXISTS observatory.obs_6c1309a64d8f3e6986061f4d1ca7b57743e75e74;
|
||||
DROP TABLE IF EXISTS observatory.obs_d39f7fe5959891c8296490d83c22ded31c54af13;
|
||||
DROP TABLE IF EXISTS observatory.obs_144e8b4f906885b2e057ac4842644a553ae49c6e;
|
||||
DROP TABLE IF EXISTS observatory.obs_c6fb99c47d61289fbb8e561ff7773799d3fcc308;
|
||||
|
||||
DROP TABLE IF EXISTS observatory.obs_meta;
|
||||
|
||||
22437
src/pg/test/fixtures/load_fixtures.sql
vendored
22437
src/pg/test/fixtures/load_fixtures.sql
vendored
File diff suppressed because one or more lines are too long
@@ -1,7 +1,6 @@
|
||||
-- Install dependencies
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
CREATE EXTENSION postgres_fdw;
|
||||
|
||||
-- Install the extension
|
||||
CREATE EXTENSION observatory VERSION 'dev';
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
\pset format unaligned
|
||||
\set ECHO all
|
||||
\i test/fixtures/load_fixtures.sql
|
||||
SET client_min_messages TO WARNING;
|
||||
\set ECHO none
|
||||
|
||||
-- OBS_GeomTable
|
||||
-- get table with known geometry_id
|
||||
@@ -27,29 +29,6 @@ SELECT
|
||||
-- 'us.census.tiger.census_tract'
|
||||
-- );
|
||||
|
||||
WITH result as (
|
||||
SELECT
|
||||
array_agg(a) expected from cdb_observatory._OBS_GetColumnData(
|
||||
'us.census.tiger.census_tract',
|
||||
Array['us.census.spielman_singleton_segments.X55', 'us.census.acs.B01003001'],
|
||||
'2010 - 2014') a
|
||||
)
|
||||
select
|
||||
(expected)[1]::text = '{"colname":"x55","tablename":"obs_65f29658e096ca1485bf683f65fdbc9f05ec3c5d","aggregate":null,"name":"Spielman-Singleton Segments: 55 Clusters","type":"Text","description":"Sociodemographic classes from Spielman and Singleton 2015, 55 clusters","boundary_id":"us.census.tiger.census_tract"}' as test_get_obs_column_with_geoid_and_census_1,
|
||||
(expected)[2]::text = '{"colname":"total_pop","tablename":"obs_b393b5b88c6adda634b2071a8005b03c551b609a","aggregate":"sum","name":"Total Population","type":"Numeric","description":"The total number of all people living in a given geographic area. This is a very useful catch-all denominator when calculating rates.","boundary_id":"us.census.tiger.census_tract"}' as test_get_obs_column_with_geoid_and_census_2
|
||||
from result;
|
||||
|
||||
-- should be null-valued
|
||||
WITH result as (
|
||||
SELECT
|
||||
array_agg(a) expected from cdb_observatory._OBS_GetColumnData(
|
||||
'us.census.tiger.census_tract',
|
||||
Array['us.census.tiger.baloney'],
|
||||
'2010 - 2014') a
|
||||
)
|
||||
select expected is null as OBS_GetColumnData_missing_measure
|
||||
from result;
|
||||
|
||||
-- OBS_BuildSnapshotQuery
|
||||
-- Should give back: SELECT vals[1] As total_pop, vals[2] As male_pop, vals[3] As female_pop, vals[4] As median_age
|
||||
SELECT
|
||||
@@ -63,16 +42,8 @@ SELECT
|
||||
Array['mandarin_orange']
|
||||
) = 'SELECT vals[1] As mandarin_orange' As _OBS_BuildSnapshotQuery_test_2;
|
||||
|
||||
SELECT cdb_observatory._OBS_GetRelatedColumn(
|
||||
Array[
|
||||
'es.ine.t3_1',
|
||||
'us.census.acs.B01003001',
|
||||
'us.census.acs.B01001002'
|
||||
],
|
||||
'denominator'
|
||||
) = '{es.ine.t1_1,NULL,us.census.acs.B01003001}' As _OBS_GetRelatedColumn_test;
|
||||
|
||||
-- should give back a standardized measure name
|
||||
SELECT cdb_observatory._OBS_StandardizeMeasureName('test 343 %% 2 qqq }}{{}}') = 'test_343_2_qqq' As _OBS_StandardizeMeasureName_test;
|
||||
|
||||
\i test/fixtures/drop_fixtures.sql
|
||||
SELECT cdb_observatory.OBS_DumpVersion()
|
||||
IS NOT NULL AS OBS_DumpVersion_notnull;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
\i test/fixtures/load_fixtures.sql
|
||||
\pset format unaligned
|
||||
\set ECHO none
|
||||
SET client_min_messages TO WARNING;
|
||||
|
||||
--
|
||||
WITH result as(
|
||||
@@ -131,7 +131,7 @@ WITH result as (
|
||||
-- Point-based OBS_GetMeasure with zillow
|
||||
SELECT abs(OBS_GetMeasure_zhvi_point - 583600) / 583600 < 0.001 AS OBS_GetMeasure_zhvi_point_test FROM cdb_observatory.OBS_GetMeasure(
|
||||
ST_SetSRID(ST_Point(-73.94602417945862, 40.6768220087458), 4326),
|
||||
'us.zillow.AllHomes_Zhvi', 'area', 'us.census.tiger.zcta5', '2014-01'
|
||||
'us.zillow.AllHomes_Zhvi', null, 'us.census.tiger.zcta5', '2014-01'
|
||||
) As t(OBS_GetMeasure_zhvi_point);
|
||||
|
||||
-- Point-based OBS_GetMeasure with zillow default to latest
|
||||
@@ -148,6 +148,22 @@ SELECT abs(OBS_GetMeasure_total_pop_point - 10923.093200390833950) / 10923.09320
|
||||
'us.census.acs.B01003001'
|
||||
) As t(OBS_GetMeasure_total_pop_point);
|
||||
|
||||
-- Point-based OBS_GetMeasure, default normalization by NULL (area)
|
||||
-- is result within 0.1% of expected
|
||||
SELECT abs(OBS_GetMeasure_total_pop_point_null_normalization - 10923.093200390833950) / 10923.093200390833950 < 0.001 As OBS_GetMeasure_total_pop_point_null_normalization_test FROM
|
||||
cdb_observatory.OBS_GetMeasure(
|
||||
cdb_observatory._TestPoint(),
|
||||
'us.census.acs.B01003001', NULL
|
||||
) As t(OBS_GetMeasure_total_pop_point_null_normalization);
|
||||
|
||||
-- Point-based OBS_GetMeasure, explicit area normalization area
|
||||
-- is result within 0.1% of expected
|
||||
SELECT abs(OBS_GetMeasure_total_pop_point_area - 10923.093200390833950) / 10923.093200390833950 < 0.001 As OBS_GetMeasure_total_pop_point_area_test FROM
|
||||
cdb_observatory.OBS_GetMeasure(
|
||||
cdb_observatory._TestPoint(),
|
||||
'us.census.acs.B01003001', 'area'
|
||||
) As t(OBS_GetMeasure_total_pop_point_area);
|
||||
|
||||
-- Poly-based OBS_GetMeasure, default normalization (none)
|
||||
-- is result within 0.1% of expected
|
||||
SELECT abs(OBS_GetMeasure_total_pop_polygon - 12327.3133495107) / 12327.3133495107 < 0.001 As OBS_GetMeasure_total_pop_polygon_test FROM
|
||||
@@ -156,6 +172,22 @@ SELECT abs(OBS_GetMeasure_total_pop_polygon - 12327.3133495107) / 12327.31334951
|
||||
'us.census.acs.B01003001'
|
||||
) As t(OBS_GetMeasure_total_pop_polygon);
|
||||
|
||||
-- Poly-based OBS_GetMeasure, default normalization by NULL (none)
|
||||
-- is result within 0.1% of expected
|
||||
SELECT abs(OBS_GetMeasure_total_pop_polygon_null_normalization - 12327.3133495107) / 12327.3133495107 < 0.001 As OBS_GetMeasure_total_pop_polygon_null_normalization_test FROM
|
||||
cdb_observatory.OBS_GetMeasure(
|
||||
cdb_observatory._TestArea(),
|
||||
'us.census.acs.B01003001', NULL
|
||||
) As t(OBS_GetMeasure_total_pop_polygon_null_normalization);
|
||||
|
||||
-- Poly-based OBS_GetMeasure, explicit area normalization
|
||||
-- is result within 0.1% of expected
|
||||
SELECT abs(OBS_GetMeasure_total_pop_polygon_area - 15787.4325563538) / 15787.4325563538 < 0.001 As OBS_GetMeasure_total_pop_polygon_area_test FROM
|
||||
cdb_observatory.OBS_GetMeasure(
|
||||
cdb_observatory._TestArea(),
|
||||
'us.census.acs.B01003001', 'area'
|
||||
) As t(OBS_GetMeasure_total_pop_polygon_area);
|
||||
|
||||
-- Point-based OBS_GetMeasure with denominator normalization
|
||||
SELECT (abs(cdb_observatory.OBS_GetMeasure(
|
||||
cdb_observatory._TestPoint(),
|
||||
@@ -166,13 +198,18 @@ SELECT abs(cdb_observatory.OBS_GetMeasure(
|
||||
cdb_observatory._TestArea(),
|
||||
'us.census.acs.B01001002', 'denominator') - 0.49026340444793965457) / 0.49026340444793965457 < 0.001 As OBS_GetMeasure_total_male_poly_denominator;
|
||||
|
||||
-- Poly-based OBS_GetMeasure with one very bad geom
|
||||
SELECT abs(cdb_observatory.OBS_GetMeasure(
|
||||
cdb_observatory._ProblemTestArea(),
|
||||
'us.census.acs.B01003001') - 96230.2929825897) / 96230.2929825897 < 0.001 As OBS_GetMeasure_bad_geometry;
|
||||
|
||||
-- Point-based OBS_GetCategory
|
||||
SELECT cdb_observatory.OBS_GetCategory(
|
||||
cdb_observatory._TestPoint(), 'us.census.spielman_singleton_segments.X10') = 'Wealthy, urban without Kids' As OBS_GetCategory_point;
|
||||
|
||||
-- Poly-based OBS_GetCategory
|
||||
SELECT cdb_observatory.OBS_GetCategory(
|
||||
cdb_observatory._TestArea(), 'us.census.spielman_singleton_segments.X10') = 'Low income, mix of minorities' As obs_getcategory_polygon;
|
||||
cdb_observatory._TestArea(), 'us.census.spielman_singleton_segments.X10') = 'Wealthy, urban without Kids' As obs_getcategory_polygon;
|
||||
|
||||
-- Point-based OBS_GetPopulation, default normalization (area)
|
||||
SELECT (abs(OBS_GetPopulation - 10923.093200390833950) / 10923.093200390833950) < 0.001 As OBS_GetPopulation FROM
|
||||
@@ -187,6 +224,13 @@ FROM
|
||||
cdb_observatory._TestArea()
|
||||
) As m(obs_getpopulation_polygon);
|
||||
|
||||
-- Poly-based OBS_GetPopulation, default normalization (none) specified as NULL
|
||||
SELECT (abs(obs_getpopulation_polygon_null - 12327.3133495107) / 12327.3133495107) < 0.001 As obs_getpopulation_polygon_null_test
|
||||
FROM
|
||||
cdb_observatory.OBS_GetPopulation(
|
||||
cdb_observatory._TestArea(), NULL
|
||||
) As m(obs_getpopulation_polygon_null);
|
||||
|
||||
-- Point-based OBS_GetUSCensusMeasure, default normalization (area)
|
||||
SELECT (abs(cdb_observatory.obs_getuscensusmeasure(
|
||||
cdb_observatory._testpoint(), 'male population') - 6789.5647735060920500) / 6789.5647735060920500) < 0.001 As obs_getuscensusmeasure_point_male_pop;
|
||||
@@ -195,13 +239,49 @@ SELECT (abs(cdb_observatory.obs_getuscensusmeasure(
|
||||
SELECT (abs(cdb_observatory.obs_getuscensusmeasure(
|
||||
cdb_observatory._testarea(), 'male population') - 6043.63061042765) / 6043.63061042765) < 0.001 As obs_getuscensusmeasure;
|
||||
|
||||
-- Poly-based OBS_GetUSCensusMeasure, default normalization (none) specified
|
||||
-- with NULL
|
||||
SELECT (abs(cdb_observatory.obs_getuscensusmeasure(
|
||||
cdb_observatory._testarea(), 'male population', NULL) - 6043.63061042765) / 6043.63061042765) < 0.001 As obs_getuscensusmeasure_null;
|
||||
|
||||
-- Point-based OBS_GetUSCensusCategory
|
||||
SELECT cdb_observatory.OBS_GetUSCensusCategory(
|
||||
cdb_observatory._testpoint(), 'Spielman-Singleton Segments: 10 Clusters') = 'Wealthy, urban without Kids' As OBS_GetUSCensusCategory_point;
|
||||
|
||||
-- Area-based OBS_GetUSCensusCategory
|
||||
SELECT cdb_observatory.OBS_GetUSCensusCategory(
|
||||
cdb_observatory._testarea(), 'Spielman-Singleton Segments: 10 Clusters') = 'Low income, mix of minorities' As OBS_GetUSCensusCategory_polygon;
|
||||
cdb_observatory._testarea(), 'Spielman-Singleton Segments: 10 Clusters') = 'Wealthy, urban without Kids' As OBS_GetUSCensusCategory_polygon;
|
||||
|
||||
|
||||
\i test/fixtures/drop_fixtures.sql
|
||||
-- OBS_GetMeasureById tests
|
||||
-- typical query
|
||||
SELECT (cdb_observatory.OBS_GetMeasureById(
|
||||
'36047048500',
|
||||
'us.census.acs.B01003001',
|
||||
'us.census.tiger.census_tract',
|
||||
'2010 - 2014'
|
||||
) - 3241) / 3241 < 0.0001 As OBS_GetMeasureById_cartodb_census_tract;
|
||||
|
||||
-- no boundary_id should give null
|
||||
SELECT cdb_observatory.OBS_GetMeasureById(
|
||||
'36047048500',
|
||||
'us.census.acs.B01003001',
|
||||
NULL,
|
||||
NULL
|
||||
) IS NULL As OBS_GetMeasureById_null_boundary_null_timespan;
|
||||
|
||||
-- query at block_group level
|
||||
SELECT (cdb_observatory.OBS_GetMeasureById(
|
||||
'360470485002',
|
||||
'us.census.acs.B01003001',
|
||||
'us.census.tiger.block_group',
|
||||
'2010 - 2014'
|
||||
) - 1900) / 1900 < 0.0001 As OBS_GetMeasureById_cartodb_block_group;
|
||||
|
||||
-- geom ref / boundary mismatch
|
||||
SELECT cdb_observatory.OBS_GetMeasureById(
|
||||
'36047048500',
|
||||
'us.census.acs.B01003001',
|
||||
'us.census.tiger.block_group',
|
||||
'2010 - 2014'
|
||||
) IS NULL As OBS_GetMeasureById_nulls;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
\i test/fixtures/load_fixtures.sql
|
||||
\pset format unaligned
|
||||
\set ECHO none
|
||||
SET client_min_messages TO WARNING;
|
||||
|
||||
-- set up variables for use in testing
|
||||
|
||||
@@ -32,5 +33,3 @@ SELECT COUNT(*) > 0 AS _OBS_GetAvailableBoundariesExist
|
||||
FROM cdb_observatory.OBS_GetAvailableBoundaries(
|
||||
cdb_observatory._TestPoint()
|
||||
) AS t(boundary_id, description, time_span, tablename);
|
||||
|
||||
\i test/fixtures/drop_fixtures.sql
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
\pset format unaligned
|
||||
\set ECHO all
|
||||
\i test/fixtures/load_fixtures.sql
|
||||
\set ECHO none
|
||||
SET client_min_messages TO WARNING;
|
||||
|
||||
-- set up variables for use in testing
|
||||
|
||||
@@ -34,7 +34,7 @@ SELECT cdb_observatory.OBS_GetBoundary(
|
||||
-- expect null geometry since there are no census tracts at null island
|
||||
-- timespan implictly null
|
||||
SELECT cdb_observatory.OBS_GetBoundary(
|
||||
CDB_LatLng(0, 0),
|
||||
ST_SetSRID(ST_MakePoint(0, 0), 4326),
|
||||
'us.census.tiger.census_tract'
|
||||
) IS NULL As OBS_GetBoundary_null_island_census_tract;
|
||||
|
||||
@@ -78,7 +78,7 @@ SELECT cdb_observatory.OBS_GetBoundaryId(
|
||||
|
||||
-- should give back null since there is not a census tract at null island
|
||||
SELECT cdb_observatory.OBS_GetBoundaryId(
|
||||
CDB_LatLng(0, 0),
|
||||
ST_SetSRID(ST_MakePoint(0, 0), 4326),
|
||||
'us.census.tiger.census_tract'
|
||||
) IS NULL As OBS_GetBoundaryId_null_island;
|
||||
|
||||
|
||||
3
src/python/requirements.txt
Normal file
3
src/python/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
nose
|
||||
nose_parameterized
|
||||
psycopg2
|
||||
14
src/python/test/README.md
Normal file
14
src/python/test/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
### Integration/performance tests
|
||||
|
||||
Tests here are meant to be run on a box with an Observatory meta/data dump
|
||||
loaded and ready to be tested against the API.
|
||||
|
||||
The local Python needs the requirements in `src/python/requirements.txt`.
|
||||
|
||||
In order to find and access the correct database, the `PGUSER`, `PGPASSWORD`,
|
||||
`PGHOST`, `PGPORT` and `PGDATABASE` env variables should be set.
|
||||
|
||||
Tests should be executed as follows:
|
||||
|
||||
nosetests test/autotest.py
|
||||
nosetests -s test/perftest.py
|
||||
248
src/python/test/autotest.py
Normal file
248
src/python/test/autotest.py
Normal file
@@ -0,0 +1,248 @@
|
||||
from nose.tools import assert_equal, assert_is_not_none
|
||||
from nose.plugins.skip import SkipTest
|
||||
from nose_parameterized import parameterized
|
||||
|
||||
from util import query
|
||||
|
||||
USE_SCHEMA = True
|
||||
|
||||
MEASURE_COLUMNS = query('''
|
||||
SELECT distinct numer_id, numer_aggregate NOT ILIKE 'sum' as point_only
|
||||
FROM observatory.obs_meta
|
||||
WHERE numer_type ILIKE 'numeric'
|
||||
AND numer_weight > 0
|
||||
''').fetchall()
|
||||
|
||||
CATEGORY_COLUMNS = query('''
|
||||
SELECT distinct numer_id
|
||||
FROM observatory.obs_meta
|
||||
WHERE numer_type ILIKE 'text'
|
||||
AND numer_weight > 0
|
||||
''').fetchall()
|
||||
|
||||
BOUNDARY_COLUMNS = query('''
|
||||
SELECT id FROM observatory.obs_column
|
||||
WHERE type ILIKE 'geometry'
|
||||
AND weight > 0
|
||||
''').fetchall()
|
||||
|
||||
US_CENSUS_MEASURE_COLUMNS = query('''
|
||||
SELECT distinct numer_name
|
||||
FROM observatory.obs_meta
|
||||
WHERE numer_type ILIKE 'numeric'
|
||||
AND 'us.census.acs.acs' = ANY (subsection_tags)
|
||||
AND numer_weight > 0
|
||||
''').fetchall()
|
||||
|
||||
SKIP_COLUMNS = set([
|
||||
u'mx.inegi_columns.INDI18',
|
||||
u'mx.inegi_columns.ECO40',
|
||||
u'mx.inegi_columns.POB34',
|
||||
u'mx.inegi_columns.POB63',
|
||||
u'mx.inegi_columns.INDI7',
|
||||
u'mx.inegi_columns.EDU28',
|
||||
u'mx.inegi_columns.SCONY10',
|
||||
u'mx.inegi_columns.EDU31',
|
||||
u'mx.inegi_columns.POB7',
|
||||
u'mx.inegi_columns.VIV30',
|
||||
u'mx.inegi_columns.INDI12',
|
||||
u'mx.inegi_columns.EDU13',
|
||||
u'mx.inegi_columns.ECO43',
|
||||
u'mx.inegi_columns.VIV9',
|
||||
u'mx.inegi_columns.HOGAR25',
|
||||
u'mx.inegi_columns.POB32',
|
||||
u'mx.inegi_columns.ECO7',
|
||||
u'mx.inegi_columns.INDI19',
|
||||
u'mx.inegi_columns.INDI16',
|
||||
u'mx.inegi_columns.POB65',
|
||||
u'mx.inegi_columns.INDI3',
|
||||
u'mx.inegi_columns.INDI9',
|
||||
u'mx.inegi_columns.POB36',
|
||||
u'mx.inegi_columns.POB33',
|
||||
u'mx.inegi_columns.POB58',
|
||||
])
|
||||
|
||||
def default_geometry_id(column_id):
|
||||
'''
|
||||
Returns default test point for the column_id.
|
||||
'''
|
||||
if column_id == 'whosonfirst.wof_disputed_geom':
|
||||
return 'ST_SetSRID(ST_MakePoint(76.57, 33.78), 4326)'
|
||||
elif column_id == 'whosonfirst.wof_marinearea_geom':
|
||||
return 'ST_SetSRID(ST_MakePoint(-68.47, 43.33), 4326)'
|
||||
elif column_id in ('us.census.tiger.school_district_elementary',
|
||||
'us.census.tiger.school_district_secondary',
|
||||
'us.census.tiger.school_district_elementary_clipped',
|
||||
'us.census.tiger.school_district_secondary_clipped'):
|
||||
return 'ST_SetSRID(ST_MakePoint(-73.7067, 40.7025), 4326)'
|
||||
elif column_id.startswith('es.ine'):
|
||||
return 'ST_SetSRID(ST_MakePoint(-2.51141249535454, 42.8226119029222), 4326)'
|
||||
elif column_id.startswith('us.zillow'):
|
||||
return 'ST_SetSRID(ST_MakePoint(-81.3544048197256, 28.3305906291771), 4326)'
|
||||
else:
|
||||
return 'ST_SetSRID(ST_MakePoint(-73.9, 40.7), 4326)'
|
||||
|
||||
|
||||
def default_point(column_id):
|
||||
'''
|
||||
Returns default test point for the column_id.
|
||||
'''
|
||||
if column_id == 'whosonfirst.wof_disputed_geom':
|
||||
return 'ST_SetSRID(ST_MakePoint(76.57, 33.78), 4326)'
|
||||
elif column_id == 'whosonfirst.wof_marinearea_geom':
|
||||
return 'ST_SetSRID(ST_MakePoint(-68.47, 43.33), 4326)'
|
||||
elif column_id in ('us.census.tiger.school_district_elementary',
|
||||
'us.census.tiger.school_district_secondary',
|
||||
'us.census.tiger.school_district_elementary_clipped',
|
||||
'us.census.tiger.school_district_secondary_clipped'):
|
||||
return 'ST_SetSRID(ST_MakePoint(-73.7067, 40.7025), 4326)'
|
||||
elif column_id.startswith('uk'):
|
||||
if 'WA' in column_id:
|
||||
return 'ST_SetSRID(ST_MakePoint(-3.184833526611328, 51.46844551219723), 4326)'
|
||||
else:
|
||||
return 'ST_SetSRID(ST_MakePoint(-0.08883476257324219, 51.51461834694225), 4326)'
|
||||
elif column_id.startswith('es'):
|
||||
return 'ST_SetSRID(ST_MakePoint(-2.51141249535454, 42.8226119029222), 4326)'
|
||||
elif column_id.startswith('us.zillow'):
|
||||
return 'ST_SetSRID(ST_MakePoint(-81.3544048197256, 28.3305906291771), 4326)'
|
||||
elif column_id.startswith('mx.'):
|
||||
return 'ST_SetSRID(ST_MakePoint(-99.17019367218018, 19.41347699386547), 4326)'
|
||||
else:
|
||||
return 'ST_SetSRID(ST_MakePoint(-73.9, 40.7), 4326)'
|
||||
|
||||
|
||||
def default_area(column_id):
|
||||
'''
|
||||
Returns default test area for the column_id
|
||||
'''
|
||||
point = default_point(column_id)
|
||||
area = 'ST_Transform(ST_Buffer(ST_Transform({point}, 3857), 1000), 4326)'.format(
|
||||
point=point)
|
||||
return area
|
||||
|
||||
@parameterized(US_CENSUS_MEASURE_COLUMNS)
|
||||
def test_get_us_census_measure_points(name):
|
||||
resp = query('''
|
||||
SELECT * FROM {schema}OBS_GetUSCensusMeasure({point}, '{name}')
|
||||
'''.format(name=name.replace("'", "''"),
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
point=default_point('')))
|
||||
rows = resp.fetchall()
|
||||
assert_equal(1, len(rows))
|
||||
assert_is_not_none(rows[0][0])
|
||||
|
||||
|
||||
@parameterized(MEASURE_COLUMNS)
|
||||
def test_get_measure_areas(column_id, point_only):
|
||||
if column_id in SKIP_COLUMNS:
|
||||
raise SkipTest('Column {} should be skipped'.format(column_id))
|
||||
if point_only:
|
||||
return
|
||||
resp = query('''
|
||||
SELECT * FROM {schema}OBS_GetMeasure({area}, '{column_id}')
|
||||
'''.format(column_id=column_id,
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
area=default_area(column_id)))
|
||||
rows = resp.fetchall()
|
||||
assert_equal(1, len(rows))
|
||||
assert_is_not_none(rows[0][0])
|
||||
|
||||
|
||||
@parameterized(MEASURE_COLUMNS)
|
||||
def test_get_measure_points(column_id, point_only):
|
||||
if column_id in SKIP_COLUMNS:
|
||||
raise SkipTest('Column {} should be skipped'.format(column_id))
|
||||
resp = query('''
|
||||
SELECT * FROM {schema}OBS_GetMeasure({point}, '{column_id}')
|
||||
'''.format(column_id=column_id,
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
point=default_point(column_id)))
|
||||
rows = resp.fetchall()
|
||||
assert_equal(1, len(rows))
|
||||
assert_is_not_none(rows[0][0])
|
||||
|
||||
#@parameterized(CATEGORY_COLUMNS)
|
||||
#def test_get_category_areas(column_id):
|
||||
# resp = query('''
|
||||
#SELECT * FROM {schema}OBS_GetCategory({area}, '{column_id}')
|
||||
# '''.format(column_id=column_id,
|
||||
# schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
# area=default_area(column_id)))
|
||||
# assert_equal(resp.status_code, 200)
|
||||
# rows = resp.json()['rows']
|
||||
# assert_equal(1, len(rows))
|
||||
# assert_is_not_none(rows[0][0])
|
||||
|
||||
@parameterized(CATEGORY_COLUMNS)
|
||||
def test_get_category_points(column_id):
|
||||
if column_id in SKIP_COLUMNS:
|
||||
raise SkipTest('Column {} should be skipped'.format(column_id))
|
||||
resp = query('''
|
||||
SELECT * FROM {schema}OBS_GetCategory({point}, '{column_id}')
|
||||
'''.format(column_id=column_id,
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
point=default_point(column_id)))
|
||||
rows = resp.fetchall()
|
||||
assert_equal(1, len(rows))
|
||||
assert_is_not_none(rows[0][0])
|
||||
|
||||
#@parameterized(BOUNDARY_COLUMNS)
|
||||
#def test_get_boundaries_by_geometry(column_id):
|
||||
# resp = query('''
|
||||
#SELECT * FROM {schema}OBS_GetBoundariesByGeometry({area}, '{column_id}')
|
||||
# '''.format(column_id=column_id,
|
||||
# schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
# area=default_area(column_id)))
|
||||
# assert_equal(resp.status_code, 200)
|
||||
# rows = resp.json()['rows']
|
||||
# assert_equal(1, len(rows))
|
||||
# assert_is_not_none(rows[0][0])
|
||||
|
||||
#@parameterized(BOUNDARY_COLUMNS)
|
||||
#def test_get_points_by_geometry(column_id):
|
||||
# resp = query('''
|
||||
#SELECT * FROM {schema}OBS_GetPointsByGeometry({area}, '{column_id}')
|
||||
# '''.format(column_id=column_id,
|
||||
# schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
# area=default_area(column_id)))
|
||||
# assert_equal(resp.status_code, 200)
|
||||
# rows = resp.json()['rows']
|
||||
# assert_equal(1, len(rows))
|
||||
# assert_is_not_none(rows[0][0])
|
||||
|
||||
#@parameterized(BOUNDARY_COLUMNS)
|
||||
#def test_get_boundary_points(column_id):
|
||||
# resp = query('''
|
||||
#SELECT * FROM {schema}OBS_GetBoundary({point}, '{column_id}')
|
||||
# '''.format(column_id=column_id,
|
||||
# schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
# point=default_point(column_id)))
|
||||
# assert_equal(resp.status_code, 200)
|
||||
# rows = resp.json()['rows']
|
||||
# assert_equal(1, len(rows))
|
||||
# assert_is_not_none(rows[0][0])
|
||||
|
||||
#@parameterized(BOUNDARY_COLUMNS)
|
||||
#def test_get_boundary_id(column_id):
|
||||
# resp = query('''
|
||||
#SELECT * FROM {schema}OBS_GetBoundaryId({point}, '{column_id}')
|
||||
# '''.format(column_id=column_id,
|
||||
# schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
# point=default_point(column_id)))
|
||||
# assert_equal(resp.status_code, 200)
|
||||
# rows = resp.json()['rows']
|
||||
# assert_equal(1, len(rows))
|
||||
# assert_is_not_none(rows[0][0])
|
||||
|
||||
#@parameterized(BOUNDARY_COLUMNS)
|
||||
#def test_get_boundary_by_id(column_id):
|
||||
# resp = query('''
|
||||
#SELECT * FROM {schema}OBS_GetBoundaryById({geometry_id}, '{column_id}')
|
||||
# '''.format(column_id=column_id,
|
||||
# schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
# geometry_id=default_geometry_id(column_id)))
|
||||
# assert_equal(resp.status_code, 200)
|
||||
# rows = resp.json()['rows']
|
||||
# assert_equal(1, len(rows))
|
||||
# assert_is_not_none(rows[0][0])
|
||||
|
||||
62
src/python/test/perftest.py
Normal file
62
src/python/test/perftest.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from nose.tools import assert_equal, assert_is_not_none
|
||||
from nose_parameterized import parameterized
|
||||
|
||||
from util import query, commit
|
||||
|
||||
from time import time
|
||||
|
||||
USE_SCHEMA = True
|
||||
|
||||
for q in (
|
||||
'DROP TABLE IF EXISTS obs_censustest',
|
||||
'''CREATE TABLE obs_censustest (cartodb_id SERIAL PRIMARY KEY,
|
||||
the_geom GEOMETRY, name TEXT, measure NUMERIC, category TEXT)''',
|
||||
'''INSERT INTO obs_censustest (the_geom, name)
|
||||
SELECT * FROM {schema}OBS_GetBoundariesByGeometry(
|
||||
st_makeenvelope(-74.05437469482422,40.66319159533881,
|
||||
-73.81885528564453,40.745696344339564, 4326),
|
||||
'us.census.tiger.block_group_clipped') As m(the_geom, geoid)'''
|
||||
):
|
||||
query(q.format(
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
))
|
||||
commit()
|
||||
|
||||
|
||||
ARGS = {
|
||||
'OBS_GetMeasureByID': "name, 'us.census.acs.B01001002', '{}'",
|
||||
'OBS_GetMeasure': "{}, 'us.census.acs.B01001002'",
|
||||
'OBS_GetCategory': "{}, 'us.census.spielman_singleton_segments.X10'",
|
||||
}
|
||||
|
||||
GEOMS = {
|
||||
'point': 'ST_PointOnSurface(the_geom)',
|
||||
'polygon_match': 'the_geom',
|
||||
'polygon_buffered': 'ST_Buffer(the_geom::GEOGRAPHY, 1000)::GEOMETRY(GEOMETRY, 4326)',
|
||||
}
|
||||
|
||||
|
||||
@parameterized([
|
||||
('OBS_GetMeasureByID', 'us.census.tiger.block_group_clipped'),
|
||||
('OBS_GetMeasureByID', 'us.census.tiger.county'),
|
||||
('OBS_GetMeasure', GEOMS['point']),
|
||||
('OBS_GetMeasure', GEOMS['polygon_match']),
|
||||
('OBS_GetMeasure', GEOMS['polygon_buffered']),
|
||||
('OBS_GetCategory', GEOMS['point']),
|
||||
('OBS_GetCategory', GEOMS['polygon_match']),
|
||||
('OBS_GetCategory', GEOMS['polygon_buffered']),
|
||||
])
|
||||
def test_performance(api_method, arg):
|
||||
print api_method, arg
|
||||
col = 'measure' if 'measure' in api_method.lower() else 'category'
|
||||
for rows in (1, 10, 50, 100):
|
||||
q = 'UPDATE obs_censustest SET {col} = {schema}{api_method}({args}) WHERE cartodb_id < {n}'.format(
|
||||
col=col,
|
||||
schema='cdb_observatory.' if USE_SCHEMA else '',
|
||||
api_method=api_method,
|
||||
args=ARGS[api_method].format(arg),
|
||||
n=rows+1)
|
||||
start = time()
|
||||
query(q)
|
||||
end = time()
|
||||
print rows, ': ', (rows / (end - start)), ' QPS'
|
||||
31
src/python/test/util.py
Normal file
31
src/python/test/util.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
import psycopg2
|
||||
|
||||
DB_CONN = psycopg2.connect('postgres://{user}:{password}@{host}:{port}/{database}'.format(
|
||||
user=os.environ.get('PGUSER', 'postgres'),
|
||||
password=os.environ.get('PGPASSWORD', ''),
|
||||
host=os.environ.get('PGHOST', 'localhost'),
|
||||
port=os.environ.get('PGPORT', '5432'),
|
||||
database=os.environ.get('PGDATABASE', 'postgres'),
|
||||
))
|
||||
CURSOR = DB_CONN.cursor()
|
||||
|
||||
|
||||
def query(q):
|
||||
'''
|
||||
Query the database.
|
||||
'''
|
||||
try:
|
||||
CURSOR.execute(q)
|
||||
return CURSOR
|
||||
except:
|
||||
DB_CONN.rollback()
|
||||
raise
|
||||
|
||||
|
||||
def commit():
|
||||
try:
|
||||
DB_CONN.commit()
|
||||
except:
|
||||
DB_CONN.rollback()
|
||||
raise
|
||||
Reference in New Issue
Block a user