From 3969fc0b194fab976b2027e74970510eceda2d82 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Mon, 6 Dec 2021 12:58:39 +0000 Subject: [PATCH] Add support for config file properties to PostgreSQL provider (#829) * :bug: Add support for the properties keyword from the config file * :rotating_light: Fixed flake8 errors * :white_check_mark: Added a test for config properties --- pygeoapi/provider/postgresql.py | 24 ++++++++++++++++++------ tests/test_postgresql_provider.py | 24 ++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/pygeoapi/provider/postgresql.py b/pygeoapi/provider/postgresql.py index a512691..5f26e1d 100644 --- a/pygeoapi/provider/postgresql.py +++ b/pygeoapi/provider/postgresql.py @@ -60,7 +60,7 @@ class DatabaseConnection: The class returns a connection object. """ - def __init__(self, conn_dic, table, context="query"): + def __init__(self, conn_dic, table, properties=[], context="query"): """ PostgreSQLProvider Class constructor returning @@ -81,15 +81,17 @@ class DatabaseConnection: :param table: table name containing the data. This variable is used to assemble column information + :param properties: User-specified subset of column names to expose :param context: query or hits, if query then it will determine table column otherwise will not do it - :returns: psycopg2.extensions.connection + :returns: DatabaseConnection """ self.conn_dic = conn_dic self.table = table self.context = context self.columns = None + self.properties = properties self.fields = {} # Dict of columns. Key is col name, value is type self.conn = None @@ -117,6 +119,8 @@ class DatabaseConnection: self.cur.execute(query_cols) result = self.cur.fetchall() + if self.properties: + result = [res for res in result if res[0] in self.properties] self.columns = SQL(', ').join( [Identifier(item[0]) for item in result] ) @@ -173,7 +177,9 @@ class PostgreSQLProvider(BaseProvider): :returns: dict of fields """ if not self.fields: - with DatabaseConnection(self.conn_dic, self.table) as db: + with DatabaseConnection(self.conn_dic, + self.table, + properties=self.properties) as db: self.fields = db.fields return self.fields @@ -246,7 +252,9 @@ class PostgreSQLProvider(BaseProvider): if resulttype == 'hits': with DatabaseConnection(self.conn_dic, - self.table, context="hits") as db: + self.table, + properties=self.properties, + context="hits") as db: cursor = db.conn.cursor(cursor_factory=RealDictCursor) where_clause = self.__get_where_clauses( @@ -266,7 +274,9 @@ class PostgreSQLProvider(BaseProvider): end_index = startindex + limit - with DatabaseConnection(self.conn_dic, self.table) as db: + with DatabaseConnection(self.conn_dic, + self.table, + properties=self.properties) as db: cursor = db.conn.cursor(cursor_factory=RealDictCursor) props = db.columns if select_properties == [] else \ @@ -364,7 +374,9 @@ class PostgreSQLProvider(BaseProvider): """ LOGGER.debug('Get item from Postgis') - with DatabaseConnection(self.conn_dic, self.table) as db: + with DatabaseConnection(self.conn_dic, + self.table, + properties=self.properties) as db: cursor = db.conn.cursor(cursor_factory=RealDictCursor) sql_query = SQL("SELECT {},ST_AsGeoJSON({}) \ diff --git a/tests/test_postgresql_provider.py b/tests/test_postgresql_provider.py index 34ea1bf..9fc81df 100644 --- a/tests/test_postgresql_provider.py +++ b/tests/test_postgresql_provider.py @@ -57,9 +57,15 @@ def config(): } +@pytest.fixture() +def config_with_properties(config): + config_ = {'properties': ['name', 'waterway', 'width', 'does_not_exist']} + config_.update(config) + return config_ + + def test_query(config): """Testing query for a valid JSON object with geometry""" - p = PostgreSQLProvider(config) feature_collection = p.query() assert feature_collection.get('type', None) == 'FeatureCollection' @@ -73,7 +79,7 @@ def test_query(config): def test_query_with_property_filter(config): - """Test query valid features when filtering by property""" + """Test query valid features when filtering by property""" p = PostgreSQLProvider(config) feature_collection = p.query(properties=[("waterway", "stream")]) features = feature_collection.get('features', None) @@ -94,6 +100,20 @@ def test_query_with_property_filter(config): assert (len(other_features) != 0) +def test_query_with_config_properties(config_with_properties): + """ + Test that query is restricted by properties in the config. + No properties should be returned that are not requested. + Note that not all requested properties have to exist in the query result. + """ + p = PostgreSQLProvider(config_with_properties) + feature_collection = p.query() + feature = feature_collection.get('features', None)[0] + properties = feature.get('properties', None) + for property_name in properties.keys(): + assert property_name in config_with_properties["properties"] + + def test_query_hits(config): """Test query resulttype=hits with properties""" psp = PostgreSQLProvider(config)