Skip to content

Commit 5183b8f

Browse files
committed
Add support for fields query parameter to index endpoint to filter returned filter attributes
1 parent b9f7dc2 commit 5183b8f

File tree

3 files changed

+31
-16
lines changed

3 files changed

+31
-16
lines changed

src/data_service.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def __init__(self, tenant, logger, config):
3535
self.attachments_service = AttachmentsService(tenant, logger)
3636
self.db_engine = DatabaseEngine()
3737

38-
def index(self, identity, translator, dataset, bbox, crs, filterexpr, filter_geom):
38+
def index(self, identity, translator, dataset, bbox, crs, filterexpr, filter_geom, filter_fields):
3939
"""Find dataset features inside bounding box.
4040
4141
:param str|obj identity: User identity
@@ -46,6 +46,7 @@ def index(self, identity, translator, dataset, bbox, crs, filterexpr, filter_geo
4646
:param str filterexpr: JSON serialized array of filter expressions:
4747
[["<attr>", "<op>", "<value>"], "and|or", ["<attr>", "<op>", "<value>"]]
4848
:param str filter_geom: JSON serialized GeoJSON geometry
49+
:param list[string] filter_fields: Field names to return
4950
"""
5051
dataset_features_provider = self.dataset_features_provider(
5152
identity, translator, dataset, False
@@ -88,7 +89,7 @@ def index(self, identity, translator, dataset, bbox, crs, filterexpr, filter_geo
8889

8990
try:
9091
feature_collection = dataset_features_provider.index(
91-
bbox, srid, filterexpr, filter_geom
92+
bbox, srid, filterexpr, filter_geom, filter_fields
9293
)
9394
except (DataError, ProgrammingError) as e:
9495
self.logger.error(e)

src/dataset_features_provider.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def deletable(self):
8484
"""Return whether dataset can be deleted."""
8585
return self.__deletable
8686

87-
def index(self, bbox, client_srid, filterexpr, filter_geom):
87+
def index(self, bbox, client_srid, filterexpr, filter_geom, filter_fields):
8888
"""Find features inside bounding box.
8989
9090
:param list[float] bbox: Bounding box as [<minx>,<miny>,<maxx>,<maxy>]
@@ -93,11 +93,16 @@ def index(self, bbox, client_srid, filterexpr, filter_geom):
9393
:param (sql, params) filterexpr: A filter expression as a tuple
9494
(sql_expr, bind_params)
9595
:param str filter_geom: JSON serialized GeoJSON geometry
96+
:param list[string] filter_fields: Field names to return
9697
"""
9798
srid = client_srid or self.srid
9899

99100
own_attributes, join_attributes = self.__extract_join_attributes()
100101

102+
if filter_fields:
103+
own_attributes = [attr for attr in own_attributes if attr in filter_fields or attr == self.primary_key]
104+
join_attributes = [attr for attr in join_attributes if attr in filter_fields]
105+
101106
# build query SQL
102107

103108
# select id and permitted attributes
@@ -146,13 +151,15 @@ def index(self, bbox, client_srid, filterexpr, filter_geom):
146151
if where_clauses:
147152
where_clause = "WHERE (" + ") AND (".join(where_clauses) + ")"
148153

149-
geom_sql = self.geom_column_sql(srid, with_bbox=False)
150-
if self.geometry_column:
151-
# select overall extent
152-
geom_sql += (
153-
', ST_Extent(%s) OVER () AS _overall_bbox_' %
154-
self.transform_geom_sql('"{geom}"', self.srid, srid)
155-
)
154+
geom_sql = ""
155+
if not filter_fields or "geometry" in filter_fields:
156+
geom_sql = self.geom_column_sql(srid, with_bbox=False)
157+
if self.geometry_column:
158+
# select overall extent
159+
geom_sql += (
160+
', ST_Extent(%s) OVER () AS _overall_bbox_' %
161+
self.transform_geom_sql('"{geom}"', self.srid, srid)
162+
)
156163

157164
sql = sql_text(("""
158165
SELECT {columns}%s
@@ -179,7 +186,7 @@ def index(self, bbox, client_srid, filterexpr, filter_geom):
179186
join_attribute_values = self.__query_join_attributes(join_attributes, attribute_values)
180187
attribute_values.update(join_attribute_values)
181188

182-
features.append(self.feature_from_query(attribute_values, srid))
189+
features.append(self.feature_from_query(attribute_values, srid, filter_fields))
183190
if '_overall_bbox_' in row:
184191
overall_bbox = row['_overall_bbox_']
185192

@@ -1060,14 +1067,16 @@ def transform_geom_sql(self, geom_sql, geom_srid, target_srid):
10601067

10611068
return geom_sql
10621069

1063-
def feature_from_query(self, row, client_srid):
1070+
def feature_from_query(self, row, client_srid, filter_fields=None):
10641071
"""Build GeoJSON Feature from query result row.
10651072
10661073
:param obj row: Row result from query
10671074
:param int client_srid: Client SRID or None for dataset SRID
10681075
"""
10691076
props = OrderedDict()
10701077
for attr in self.attributes:
1078+
if filter_fields and not attr in filter_fields:
1079+
continue
10711080
# Omit hidden fields
10721081
if self.fields.get(attr, {}).get('constraints', {}).get('hidden', False) == True:
10731082
continue
@@ -1085,7 +1094,7 @@ def feature_from_query(self, row, client_srid):
10851094
geometry = None
10861095
crs = None
10871096
bbox = None
1088-
if self.geometry_column:
1097+
if self.geometry_column and (not filter_fields or "geometry" in filter_fields):
10891098
if row['json_geom'] is not None:
10901099
geometry = json.loads(row['json_geom'])
10911100
else:

src/server.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ def output(self, key, obj, **kwargs):
258258
index_parser.add_argument('crs')
259259
index_parser.add_argument('filter')
260260
index_parser.add_argument('filter_geom')
261+
index_parser.add_argument('fields')
261262

262263
feature_multipart_parser = reqparse.RequestParser(argument_class=CaseInsensitiveArgument)
263264
feature_multipart_parser.add_argument('feature', help='Feature', required=True, location='form')
@@ -292,6 +293,9 @@ class FeatureCollection(Resource):
292293
'`[["<name>", "<op>", <value>],"and|or",["<name>","<op>",<value>]]`')
293294
@api.param(
294295
'filter_geom', 'GeoJSON serialized geometry, used as intersection geometry filter')
296+
@api.param(
297+
'fields', 'Comma separated list of field names to return'
298+
)
295299
@api.expect(index_parser)
296300
@api.marshal_with(geojson_feature_collection, skip_none=True)
297301
@optional_auth
@@ -308,10 +312,11 @@ def get(self, dataset):
308312
crs = args['crs']
309313
filterexpr = args['filter']
310314
filter_geom = args['filter_geom']
315+
filter_fields = (args['fields'] or "").split(",")
311316

312317
data_service = data_service_handler()
313318
result = data_service.index(
314-
get_identity(), translator, dataset, bbox, crs, filterexpr, filter_geom
319+
get_identity(), translator, dataset, bbox, crs, filterexpr, filter_geom, filter_fields
315320
)
316321
if 'error' not in result:
317322
return result['feature_collection']
@@ -646,7 +651,7 @@ def get(self, dataset, id):
646651
except:
647652
continue
648653
result = data_service.index(
649-
get_identity(), translator, table, None, crs, '[["%s", "=", "%s"]]' % (fk_field_name, id), None
654+
get_identity(), translator, table, None, crs, '[["%s", "=", "%s"]]' % (fk_field_name, id), None, None
650655
)
651656
ret[table] = {
652657
"fk": fk_field_name,
@@ -688,7 +693,7 @@ def get(self):
688693
continue
689694
ret[table] = []
690695
result = data_service.index(
691-
get_identity(), translator, table, None, None, json.dumps(filterexpr[idx]) if filterexpr and len(filterexpr) > idx and filterexpr[idx] else None, None
696+
get_identity(), translator, table, None, None, json.dumps(filterexpr[idx]) if filterexpr and len(filterexpr) > idx and filterexpr[idx] else None, None, None
692697
)
693698
if 'feature_collection' in result:
694699
for feature in result['feature_collection']['features']:

0 commit comments

Comments
 (0)