From dda4d121e283ddd742b13394dfb78569d26b38e6 Mon Sep 17 00:00:00 2001 From: totycro Date: Tue, 4 Jul 2023 13:44:17 +0200 Subject: [PATCH] =?UTF-8?q?Make=20sure=20that=20PostgreSQLProvider.get=5Ff?= =?UTF-8?q?ields=20returns=20valid=20json=20schem=E2=80=A6=20(#1312)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make sure that PostgreSQLProvider.get_fields returns valid json schema types * Log warnings when postgres provider encounters unknown types * Update postgresql.py --------- Co-authored-by: Tom Kralidis --- pygeoapi/provider/base.py | 4 +++- pygeoapi/provider/postgresql.py | 34 ++++++++++++++++++++++++++----- tests/test_postgresql_provider.py | 24 +++++++++++----------- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/pygeoapi/provider/base.py b/pygeoapi/provider/base.py index 0d0b44e..6bdc225 100644 --- a/pygeoapi/provider/base.py +++ b/pygeoapi/provider/base.py @@ -82,7 +82,9 @@ class BaseProvider: """ Get provider field information (names, types) - :returns: dict of fields + Example response: {'field1': 'string', 'field2': 'number'}} + + :returns: dict of field names and their associated JSON Schema typess """ raise NotImplementedError() diff --git a/pygeoapi/provider/postgresql.py b/pygeoapi/provider/postgresql.py index e44729c..1524580 100644 --- a/pygeoapi/provider/postgresql.py +++ b/pygeoapi/provider/postgresql.py @@ -187,13 +187,37 @@ class PostgreSQLProvider(BaseProvider): """ LOGGER.debug('Get available fields/properties') - fields = {} - for column in self.table_model.__table__.columns: - fields[str(column.name)] = {'type': str(column.type)} + # sql-schema only allows these types, so we need to map from sqlalchemy + # string, number, integer, object, array, boolean, null, + # https://json-schema.org/understanding-json-schema/reference/type.html + column_type_map = { + str: 'string', + float: 'number', + int: 'integer', + bool: 'boolean', + } + default_value = 'string' - fields.pop(self.geom) # Exclude geometry column + def _column_type_to_json_schema_type(column_type): + try: + python_type = column_type.python_type + except NotImplementedError: + LOGGER.warning(f'Unsupported column type {column_type}') + return default_value + else: + try: + return column_type_map[python_type] + except KeyError: + LOGGER.warning(f'Unsupported column type {column_type}') + return default_value - return fields + return { + str(column.name): { + 'type': _column_type_to_json_schema_type(column.type) + } + for column in self.table_model.__table__.columns + if column.name != self.geom # Exclude geometry column + } def get(self, identifier, crs_transform_spec=None, **kwargs): """ diff --git a/tests/test_postgresql_provider.py b/tests/test_postgresql_provider.py index e8d8471..0bff90e 100644 --- a/tests/test_postgresql_provider.py +++ b/tests/test_postgresql_provider.py @@ -308,18 +308,18 @@ def test_query_cql_properties_bbox_filters(config): def test_get_fields(config): # Arrange expected_fields = { - 'blockage': {'type': 'VARCHAR(80)'}, - 'covered': {'type': 'VARCHAR(80)'}, - 'depth': {'type': 'VARCHAR(80)'}, - 'layer': {'type': 'VARCHAR(80)'}, - 'name': {'type': 'VARCHAR(80)'}, - 'natural': {'type': 'VARCHAR(80)'}, - 'osm_id': {'type': 'INTEGER'}, - 'tunnel': {'type': 'VARCHAR(80)'}, - 'water': {'type': 'VARCHAR(80)'}, - 'waterway': {'type': 'VARCHAR(80)'}, - 'width': {'type': 'VARCHAR(80)'}, - 'z_index': {'type': 'VARCHAR(80)'} + 'blockage': {'type': 'string'}, + 'covered': {'type': 'string'}, + 'depth': {'type': 'string'}, + 'layer': {'type': 'string'}, + 'name': {'type': 'string'}, + 'natural': {'type': 'string'}, + 'osm_id': {'type': 'integer'}, + 'tunnel': {'type': 'string'}, + 'water': {'type': 'string'}, + 'waterway': {'type': 'string'}, + 'width': {'type': 'string'}, + 'z_index': {'type': 'string'} } # Act