diff --git a/docs/source/language.rst b/docs/source/language.rst index f2a8653..9faa37c 100644 --- a/docs/source/language.rst +++ b/docs/source/language.rst @@ -229,7 +229,7 @@ An example Python code block for a custom provider with a language-aware ``query def __init__(self, provider_def): super().__init__(provider_def) - def query(self, startindex=0, limit=10, resulttype='results', bbox=[], + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, language=None): LOGGER.debug(f'Provider queried in {language.english_name} language') diff --git a/docs/source/plugins.rst b/docs/source/plugins.rst index 9b04691..ad65b4e 100644 --- a/docs/source/plugins.rst +++ b/docs/source/plugins.rst @@ -68,7 +68,7 @@ The below template provides a minimal example (let's call the file ``mycoolvecto 'field2': 'string' } - def query(self,startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, **kwargs): diff --git a/pygeoapi-config.yml b/pygeoapi-config.yml index bfe3732..66bea2b 100644 --- a/pygeoapi-config.yml +++ b/pygeoapi-config.yml @@ -269,6 +269,44 @@ resources: time_field: recordCreated title_field: title + dbossh: + type: collection + title: DBOSSH + description: The database for DASSH + keywords: + - observations + - monitoring + context: + - datetime: https://schema.org/DateTime + - vocab: https://example.com/vocab# + stn_id: "vocab:stn_id" + value: "vocab:value" + links: + - type: text/csv + rel: canonical + title: data + href: https://github.com/mapserver/mapserver/blob/branch-7-0/msautotest/wxs/data/obs.csv + hreflang: en-US + - type: text/csv + rel: alternate + title: data + href: https://raw.githubusercontent.com/mapserver/mapserver/branch-7-0/msautotest/wxs/data/obs.csv + hreflang: en-US + extents: + spatial: + bbox: [-180,-90,180,90] + crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84 + temporal: + begin: 2000-10-30T18:24:39Z + end: 2021-10-30T08:57:29Z + providers: + - type: edr + name: xarray-edr + data: tests/data/coads_sst.nc + format: + name: netcdf + mimetype: application/x-netcdf + hello-world: type: process processor: diff --git a/pygeoapi/api.py b/pygeoapi/api.py index d36f2d9..8406764 100644 --- a/pygeoapi/api.py +++ b/pygeoapi/api.py @@ -1236,7 +1236,7 @@ class API: headers = request.get_response_headers(SYSTEM_LOCALE) properties = [] - reserved_fieldnames = ['bbox', 'f', 'lang', 'limit', 'startindex', + reserved_fieldnames = ['bbox', 'f', 'lang', 'limit', 'offset', 'resulttype', 'datetime', 'sortby', 'properties', 'skipGeometry', 'q'] @@ -1250,18 +1250,18 @@ class API: LOGGER.debug('Processing query parameters') - LOGGER.debug('Processing startindex parameter') + LOGGER.debug('Processing offset parameter') try: - startindex = int(request.params.get('startindex')) - if startindex < 0: - msg = 'startindex value should be positive or zero' + offset = int(request.params.get('offset')) + if offset < 0: + msg = 'offset value should be positive or zero' return self.get_exception( 400, headers, request.format, 'InvalidParameterValue', msg) except TypeError as err: LOGGER.warning(err) - startindex = 0 + offset = 0 except ValueError: - msg = 'startindex value should be an integer' + msg = 'offset value should be an integer' return self.get_exception( 400, headers, request.format, 'InvalidParameterValue', msg) @@ -1394,7 +1394,7 @@ class API: prv_locale = l10n.get_plugin_locale(provider_def, request.raw_locale) LOGGER.debug('Querying provider') - LOGGER.debug('startindex: {}'.format(startindex)) + LOGGER.debug('offset: {}'.format(offset)) LOGGER.debug('limit: {}'.format(limit)) LOGGER.debug('resulttype: {}'.format(resulttype)) LOGGER.debug('sortby: {}'.format(sortby)) @@ -1407,7 +1407,7 @@ class API: LOGGER.debug('q: {}'.format(q)) try: - content = p.query(startindex=startindex, limit=limit, + content = p.query(offset=offset, limit=limit, resulttype=resulttype, bbox=bbox, datetime_=datetime_, properties=properties, sortby=sortby, @@ -1432,7 +1432,7 @@ class API: serialized_query_params = '' for k, v in request.params.items(): - if k not in ('f', 'startindex'): + if k not in ('f', 'offset'): serialized_query_params += '&' serialized_query_params += urllib.parse.quote(k, safe='') serialized_query_params += '=' @@ -1462,26 +1462,26 @@ class API: serialized_query_params) }] - if startindex > 0: - prev = max(0, startindex - limit) + if offset > 0: + prev = max(0, offset - limit) content['links'].append( { 'type': 'application/geo+json', 'rel': 'prev', 'title': 'items (prev)', - 'href': '{}/collections/{}/items?startindex={}{}' + 'href': '{}/collections/{}/items?offset={}{}' .format(self.config['server']['url'], dataset, prev, serialized_query_params) }) if len(content['features']) == limit: - next_ = startindex + limit + next_ = offset + limit content['links'].append( { 'type': 'application/geo+json', 'rel': 'next', 'title': 'items (next)', - 'href': '{}/collections/{}/items?startindex={}{}' + 'href': '{}/collections/{}/items?offset={}{}' .format( self.config['server']['url'], dataset, next_, serialized_query_params) @@ -1514,7 +1514,7 @@ class API: content['items_path'] = path_info content['dataset_path'] = '/'.join(path_info.split('/')[:-1]) content['collections_path'] = '/'.join(path_info.split('/')[:-2]) - content['startindex'] = startindex + content['offset'] = offset content['id_field'] = p.id_field if p.uri_field is not None: @@ -1590,7 +1590,7 @@ class API: headers = request.get_response_headers(SYSTEM_LOCALE) properties = [] - reserved_fieldnames = ['bbox', 'f', 'limit', 'startindex', + reserved_fieldnames = ['bbox', 'f', 'limit', 'offset', 'resulttype', 'datetime', 'sortby', 'properties', 'skipGeometry', 'q', 'filter-lang'] @@ -1605,18 +1605,18 @@ class API: LOGGER.debug('Processing query parameters') - LOGGER.debug('Processing startindex parameter') + LOGGER.debug('Processing offset parameter') try: - startindex = int(request.params.get('startindex')) - if startindex < 0: - msg = 'startindex value should be positive or zero' + offset = int(request.params.get('offset')) + if offset < 0: + msg = 'offset value should be positive or zero' return self.get_exception( 400, headers, request.format, 'InvalidParameterValue', msg) except TypeError as err: LOGGER.warning(err) - startindex = 0 + offset = 0 except ValueError: - msg = 'startindex value should be an integer' + msg = 'offset value should be an integer' return self.get_exception( 400, headers, request.format, 'InvalidParameterValue', msg) @@ -1757,7 +1757,7 @@ class API: 400, headers, request.format, 'InvalidParameterValue', msg) LOGGER.debug('Querying provider') - LOGGER.debug('startindex: {}'.format(startindex)) + LOGGER.debug('offset: {}'.format(offset)) LOGGER.debug('limit: {}'.format(limit)) LOGGER.debug('resulttype: {}'.format(resulttype)) LOGGER.debug('sortby: {}'.format(sortby)) @@ -1793,7 +1793,7 @@ class API: filter_ = None if val: filter_ = CQLModel.parse_raw(data) - content = p.query(startindex=startindex, limit=limit, + content = p.query(offset=offset, limit=limit, resulttype=resulttype, bbox=bbox, datetime_=datetime_, properties=properties, sortby=sortby, diff --git a/pygeoapi/openapi.py b/pygeoapi/openapi.py index ad2b492..e2555d8 100644 --- a/pygeoapi/openapi.py +++ b/pygeoapi/openapi.py @@ -334,10 +334,10 @@ def get_oas_30(cfg): 'default': False } }, - 'startindex': { - 'name': 'startindex', + 'offset': { + 'name': 'offset', 'in': 'query', - 'description': 'The optional startindex parameter indicates the index within the result set from which the server shall begin presenting results in the response document. The first element has an index of 0 (default).', # noqa + 'description': 'The optional offset parameter indicates the index within the result set from which the server shall begin presenting results in the response document. The first element has an index of 0 (default).', # noqa 'required': False, 'schema': { 'type': 'integer', @@ -484,7 +484,7 @@ def get_oas_30(cfg): coll_properties, {'$ref': '#/components/parameters/skipGeometry'}, {'$ref': '{}/parameters/sortby.yaml'.format(OPENAPI_YAML['oapir'])}, # noqa - {'$ref': '#/components/parameters/startindex'}, + {'$ref': '#/components/parameters/offset'}, ], 'responses': { '200': {'$ref': '{}#/components/responses/Features'.format(OPENAPI_YAML['oapif'])}, # noqa diff --git a/pygeoapi/provider/csv_.py b/pygeoapi/provider/csv_.py index 809a49a..efd5852 100644 --- a/pygeoapi/provider/csv_.py +++ b/pygeoapi/provider/csv_.py @@ -71,13 +71,13 @@ class CSVProvider(BaseProvider): fields[f] = {'type': 'string'} return fields - def _load(self, startindex=0, limit=10, resulttype='results', + def _load(self, offset=0, limit=10, resulttype='results', identifier=None, bbox=[], datetime_=None, properties=[], select_properties=[], skip_geometry=False, q=None): """ Load CSV data - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param datetime_: temporal (datestamp or extent) :param resulttype: return results or hit limit (default results) @@ -109,7 +109,7 @@ class CSVProvider(BaseProvider): feature_collection['numberMatched'] = len(list(data_)) return feature_collection LOGGER.debug('Slicing CSV rows') - for row in itertools.islice(data_, startindex, startindex+limit): + for row in itertools.islice(data_, offset, offset+limit): feature = {'type': 'Feature'} feature['id'] = row.pop(self.id_field) if not skip_geometry: @@ -150,13 +150,13 @@ class CSVProvider(BaseProvider): return feature_collection - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, **kwargs): """ CSV query - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -170,7 +170,7 @@ class CSVProvider(BaseProvider): :returns: dict of GeoJSON FeatureCollection """ - return self._load(startindex, limit, resulttype, + return self._load(offset, limit, resulttype, properties=properties, select_properties=select_properties, skip_geometry=skip_geometry) diff --git a/pygeoapi/provider/elasticsearch_.py b/pygeoapi/provider/elasticsearch_.py index 2dc8442..e6e3bbd 100644 --- a/pygeoapi/provider/elasticsearch_.py +++ b/pygeoapi/provider/elasticsearch_.py @@ -153,14 +153,14 @@ class ElasticsearchProvider(BaseProvider): return fields_ - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, filterq=None, **kwargs): """ query Elasticsearch index - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -316,24 +316,24 @@ class ElasticsearchProvider(BaseProvider): LOGGER.debug(json.dumps(query, indent=4)) LOGGER.debug('Testing for ES scrolling') - if startindex + limit > 10000: + if offset + limit > 10000: gen = helpers.scan(client=self.es, query=query, preserve_order=True, index=self.index_name) results = {'hits': {'total': limit, 'hits': []}} - for i in range(startindex + limit): + for i in range(offset + limit): try: - if i >= startindex: + if i >= offset: results['hits']['hits'].append(next(gen)) else: next(gen) except StopIteration: break results['hits']['total'] = \ - len(results['hits']['hits']) + startindex + len(results['hits']['hits']) + offset else: results = self.es.search(index=self.index_name, - from_=startindex, size=limit, + from_=offset, size=limit, body=query) results['hits']['total'] = results['hits']['total']['value'] @@ -496,13 +496,13 @@ class ElasticsearchCatalogueProvider(ElasticsearchProvider): return fields - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, filterq=None, **kwargs): records = super().query( - startindex=startindex, limit=limit, + offset=offset, limit=limit, resulttype=resulttype, bbox=bbox, datetime_=datetime_, properties=properties, sortby=sortby, diff --git a/pygeoapi/provider/geojson.py b/pygeoapi/provider/geojson.py index e841ad6..b271fd5 100644 --- a/pygeoapi/provider/geojson.py +++ b/pygeoapi/provider/geojson.py @@ -120,13 +120,13 @@ class GeoJSONProvider(BaseProvider): if k in set(self.properties) | set(select_properties)} # noqa return data - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, **kwargs): """ query the provider - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -149,7 +149,7 @@ class GeoJSONProvider(BaseProvider): if resulttype == 'hits': data['features'] = [] else: - data['features'] = data['features'][startindex:startindex+limit] + data['features'] = data['features'][offset:offset+limit] data['numberReturned'] = len(data['features']) return data diff --git a/pygeoapi/provider/mongo.py b/pygeoapi/provider/mongo.py index c15fe65..1fb55cc 100644 --- a/pygeoapi/provider/mongo.py +++ b/pygeoapi/provider/mongo.py @@ -96,7 +96,7 @@ class MongoProvider(BaseProvider): return featurelist, matchCount - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, **kwargs): """ @@ -128,7 +128,7 @@ class MongoProvider(BaseProvider): featurelist, matchcount = self._get_feature_list(filterobj, sortList=sort_list, - skip=startindex, + skip=offset, maxitems=limit) if resulttype == 'hits': diff --git a/pygeoapi/provider/ogr.py b/pygeoapi/provider/ogr.py index 7773288..6a635c8 100644 --- a/pygeoapi/provider/ogr.py +++ b/pygeoapi/provider/ogr.py @@ -289,13 +289,13 @@ class OGRProvider(BaseProvider): return fields - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, **kwargs): """ Query OGR source - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -311,7 +311,7 @@ class OGRProvider(BaseProvider): result = None try: if self.source_capabilities['paging']: - self.source_helper.enable_paging(startindex, limit) + self.source_helper.enable_paging(offset, limit) layer = self._get_layer() @@ -570,7 +570,7 @@ class SourceHelper: return layer - def enable_paging(self, startindex=-1, limit=-1): + def enable_paging(self, offset=-1, limit=-1): """ Enable paged access to dataset (OGR Driver-specific) @@ -602,7 +602,7 @@ class CommonSourceHelper(SourceHelper): super().__init__(provider) - self.startindex = -1 + self.offset = -1 self.limit = -1 self.result_set = None @@ -626,14 +626,14 @@ class CommonSourceHelper(SourceHelper): finally: self.result_set = None - def enable_paging(self, startindex=-1, limit=-1): + def enable_paging(self, offset=-1, limit=-1): """ Enable paged access to dataset (OGR Driver-specific) using OGR SQL https://gdal.org/user/ogr_sql_dialect.html e.g. SELECT * FROM poly LIMIT 10 OFFSET 30 """ - self.startindex = startindex + self.offset = offset self.limit = limit def disable_paging(self): @@ -646,12 +646,12 @@ class CommonSourceHelper(SourceHelper): def get_layer(self): """ Gets OGR Layer from opened OGR dataset. - When startindex defined 1 or greater will invoke + When offset defined 1 or greater will invoke OGR SQL SELECT with LIMIT and OFFSET and return as Layer as ResultSet from ExecuteSQL on dataset. :return: OGR layer object """ - if self.startindex <= 0: + if self.offset <= 0: return SourceHelper.get_layer(self) self.close() @@ -659,11 +659,11 @@ class CommonSourceHelper(SourceHelper): sql = 'SELECT * FROM "{ds_name}" LIMIT {limit} OFFSET {offset}'.format( ds_name=self.provider.layer_name, limit=self.limit, - offset=self.startindex) + offset=self.offset) self.result_set = self.provider.conn.ExecuteSQL(sql) # Reset since needs to be set each time explicitly - self.startindex = -1 + self.offset = -1 self.limit = -1 if not self.result_set: @@ -688,16 +688,16 @@ class ESRIJSONHelper(CommonSourceHelper): super().__init__(provider) - def enable_paging(self, startindex=-1, limit=-1): + def enable_paging(self, offset=-1, limit=-1): """ Enable paged access to dataset (OGR Driver-specific) """ - if startindex < 0: + if offset < 0: return self.provider.open_options.update(FEATURE_SERVER_PAGING=True) - self.startindex = startindex + self.offset = offset self.limit = limit def disable_paging(self): @@ -710,12 +710,12 @@ class ESRIJSONHelper(CommonSourceHelper): def get_layer(self): """ Gets OGR Layer from opened OGR dataset. - When startindex defined 1 or greater will invoke + When offset defined 1 or greater will invoke OGR SQL SELECT with LIMIT and OFFSET and return as Layer as ResultSet from ExecuteSQL on dataset. :return: OGR layer object """ - if self.startindex <= 0: + if self.offset <= 0: return CommonSourceHelper.get_layer(self) self.close() @@ -723,11 +723,11 @@ class ESRIJSONHelper(CommonSourceHelper): sql = "SELECT * FROM {ds_name} LIMIT {limit} OFFSET {offset}".format( ds_name=self.provider.layer_name, limit=self.limit, - offset=self.startindex) + offset=self.offset) self.result_set = self.provider.conn.ExecuteSQL(sql) # Reset since needs to be set each time explicitly - self.startindex = -1 + self.offset = -1 self.limit = -1 if not self.result_set: @@ -752,19 +752,19 @@ class WFSHelper(SourceHelper): super().__init__(provider) - def enable_paging(self, startindex=-1, limit=-1): + def enable_paging(self, offset=-1, limit=-1): """ Enable paged access to dataset (OGR Driver-specific) """ - if startindex < 0: + if offset < 0: return self.provider.gdal.SetConfigOption( 'OGR_WFS_PAGING_ALLOWED', 'ON') self.provider.gdal.SetConfigOption( - 'OGR_WFS_BASE_START_INDEX', str(startindex)) + 'OGR_WFS_BASE_START_INDEX', str(offset)) self.provider.gdal.SetConfigOption( 'OGR_WFS_PAGE_SIZE', str(limit)) diff --git a/pygeoapi/provider/postgresql.py b/pygeoapi/provider/postgresql.py index 394ffcb..0fa0e39 100644 --- a/pygeoapi/provider/postgresql.py +++ b/pygeoapi/provider/postgresql.py @@ -237,7 +237,7 @@ class PostgreSQLProvider(BaseProvider): ret.append(f"{_['property']} {_map[_['order']]}") return SQL(f"ORDER BY {','.join(ret)}") - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, **kwargs): """ @@ -245,7 +245,7 @@ class PostgreSQLProvider(BaseProvider): e,g: http://localhost:5000/collections/hotosm_bdi_waterways/items? limit=1&resulttype=results - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -283,7 +283,7 @@ class PostgreSQLProvider(BaseProvider): return self.__response_feature_hits(hits) - end_index = startindex + limit + end_index = offset + limit with DatabaseConnection(self.conn_dic, self.table, @@ -310,11 +310,11 @@ class PostgreSQLProvider(BaseProvider): orderby) LOGGER.debug('SQL Query: {}'.format(sql_query.as_string(cursor))) - LOGGER.debug('Start Index: {}'.format(startindex)) + LOGGER.debug('Start Index: {}'.format(offset)) LOGGER.debug('End Index: {}'.format(end_index)) try: cursor.execute(sql_query) - for index in [startindex, limit]: + for index in [offset, limit]: cursor.execute("fetch forward {} from geo_cursor" .format(index)) except Exception as err: diff --git a/pygeoapi/provider/sensorthings.py b/pygeoapi/provider/sensorthings.py index 8aed5ed..d045cc4 100644 --- a/pygeoapi/provider/sensorthings.py +++ b/pygeoapi/provider/sensorthings.py @@ -132,13 +132,13 @@ class SensorThingsProvider(BaseProvider): return self.fields - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, **kwargs): """ STA query - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -152,7 +152,7 @@ class SensorThingsProvider(BaseProvider): :returns: dict of GeoJSON FeatureCollection """ - return self._load(startindex, limit, resulttype, bbox=bbox, + return self._load(offset, limit, resulttype, bbox=bbox, datetime_=datetime_, properties=properties, sortby=sortby, select_properties=select_properties, skip_geometry=skip_geometry) @@ -202,13 +202,13 @@ class SensorThingsProvider(BaseProvider): 'n': name, 'u': uri }) - def _load(self, startindex=0, limit=10, resulttype='results', + def _load(self, offset=0, limit=10, resulttype='results', identifier=None, bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None): """ Private function: Load STA data - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -227,7 +227,7 @@ class SensorThingsProvider(BaseProvider): # Make params params = { '$expand': EXPAND[self.entity], - '$skip': str(startindex), + '$skip': str(offset), '$top': str(limit), '$count': 'true' } diff --git a/pygeoapi/provider/sqlite.py b/pygeoapi/provider/sqlite.py index 4a3c4f1..53698b3 100644 --- a/pygeoapi/provider/sqlite.py +++ b/pygeoapi/provider/sqlite.py @@ -249,16 +249,16 @@ class SQLiteGPKGProvider(BaseProvider): return cursor - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, **kwargs): """ Query SQLite/GPKG for all the content. e,g: http://localhost:5000/collections/countries/items? - limit=5&startindex=2&resulttype=results&continent=Europe&admin=Albania&bbox=29.3373,-3.4099,29.3761,-3.3924 + limit=5&offset=2&resulttype=results&continent=Europe&admin=Albania&bbox=29.3373,-3.4099,29.3761,-3.3924 http://localhost:5000/collections/countries/items?continent=Africa&bbox=29.3373,-3.4099,29.3761,-3.3924 - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -290,14 +290,14 @@ class SQLiteGPKGProvider(BaseProvider): {} {} limit ? offset ?".format( self.columns, self.table, where_clause) - end_index = startindex + limit + end_index = offset + limit LOGGER.debug('SQL Query: {}'.format(sql_query)) - LOGGER.debug('Start Index: {}'.format(startindex)) + LOGGER.debug('Start Index: {}'.format(offset)) LOGGER.debug('End Index: {}'.format(end_index)) row_data = self.cursor.execute( - sql_query, where_values + (limit, startindex)) + sql_query, where_values + (limit, offset)) feature_collection = { 'type': 'FeatureCollection', diff --git a/pygeoapi/provider/tinydb_.py b/pygeoapi/provider/tinydb_.py index 44b9fbe..00ab56e 100644 --- a/pygeoapi/provider/tinydb_.py +++ b/pygeoapi/provider/tinydb_.py @@ -92,13 +92,13 @@ class TinyDBCatalogueProvider(BaseProvider): return fields - def query(self, startindex=0, limit=10, resulttype='results', + def query(self, offset=0, limit=10, resulttype='results', bbox=[], datetime_=None, properties=[], sortby=[], select_properties=[], skip_geometry=False, q=None, **kwargs): """ query TinyDB document store - :param startindex: starting record to return (default 0) + :param offset: starting record to return (default 0) :param limit: number of records to return (default 10) :param resulttype: return results or hit limit (default results) :param bbox: bounding box [minx,miny,maxx,maxy] @@ -201,7 +201,7 @@ class TinyDBCatalogueProvider(BaseProvider): results.sort(key=lambda k: k['properties'][sortby[0]['property']], reverse=sort_reverse) - feature_collection['features'] = results[startindex:startindex + limit] + feature_collection['features'] = results[offset:offset + limit] return feature_collection diff --git a/pygeoapi/templates/collections/items/index.html b/pygeoapi/templates/collections/items/index.html index bbafa58..458787c 100644 --- a/pygeoapi/templates/collections/items/index.html +++ b/pygeoapi/templates/collections/items/index.html @@ -58,7 +58,7 @@
{% for link in data['links'] %} - {% if link['rel'] == 'prev' and data['startindex'] > 0 %} + {% if link['rel'] == 'prev' and data['offset'] > 0 %} {% trans %}Prev{% endtrans %} {% elif link['rel'] == 'next' and data['features'] %} {% trans %}Next{% endtrans %} diff --git a/tests/cite/ogcapi-features/canada-hydat-daily-mean-02HC003.geojson b/tests/cite/ogcapi-features/canada-hydat-daily-mean-02HC003.geojson index 202f7b1..13f5344 100644 --- a/tests/cite/ogcapi-features/canada-hydat-daily-mean-02HC003.geojson +++ b/tests/cite/ogcapi-features/canada-hydat-daily-mean-02HC003.geojson @@ -1215,13 +1215,13 @@ "type": "text/html" }, { - "href": "https://geo.weather.gc.ca/geomet/features/collections/hydrometric-daily-mean/items/?startindex=0", + "href": "https://geo.weather.gc.ca/geomet/features/collections/hydrometric-daily-mean/items/?offset=0", "rel": "prev", "title": "items (prev)", "type": "application/geo+json" }, { - "href": "https://geo.weather.gc.ca/geomet/features/collections/hydrometric-daily-mean/items/?startindex=500", + "href": "https://geo.weather.gc.ca/geomet/features/collections/hydrometric-daily-mean/items/?offset=500", "rel": "next", "title": "items (next)", "type": "application/geo+json" diff --git a/tests/pygeoapi-test-openapi.yml b/tests/pygeoapi-test-openapi.yml index ca04377..809d18f 100644 --- a/tests/pygeoapi-test-openapi.yml +++ b/tests/pygeoapi-test-openapi.yml @@ -56,13 +56,13 @@ components: pattern: "[+|-][A-Za-z_][A-Za-z_0-9]*" explode: false style: form - startindex: - description: The optional startindex parameter indicates the index within the + offset: + description: The optional offset parameter indicates the index within the result set from which the server shall begin presenting results in the response document. The first element has an index of 0 (default). explode: false in: query - name: startindex + name: offset required: false schema: default: 0 @@ -180,7 +180,7 @@ paths: - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/limit - $ref: '#/components/parameters/sortby' - - $ref: '#/components/parameters/startindex' + - $ref: '#/components/parameters/offset' responses: '200': $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features diff --git a/tests/test_api.py b/tests/test_api.py index f5ec2a2..67a35a6 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -637,19 +637,19 @@ def test_get_collection_items(config, api_): assert links[1]['rel'] == 'alternate' assert '/collections/obs/items?f=html' in links[2]['href'] assert links[2]['rel'] == 'alternate' - assert '/collections/obs/items?startindex=2&limit=2' in links[3]['href'] + assert '/collections/obs/items?offset=2&limit=2' in links[3]['href'] assert links[3]['rel'] == 'next' assert '/collections/obs' in links[4]['href'] assert links[4]['rel'] == 'collection' - # Invalid startindex - req = mock_request({'startindex': -1}) + # Invalid offset + req = mock_request({'offset': -1}) rsp_headers, code, response = api_.get_collection_items(req, 'obs') features = json.loads(response) assert code == 400 - req = mock_request({'startindex': 2}) + req = mock_request({'offset': 2}) rsp_headers, code, response = api_.get_collection_items(req, 'obs') features = json.loads(response) @@ -664,13 +664,13 @@ def test_get_collection_items(config, api_): assert links[1]['rel'] == 'alternate' assert '/collections/obs/items?f=html' in links[2]['href'] assert links[2]['rel'] == 'alternate' - assert '/collections/obs/items?startindex=0' in links[3]['href'] + assert '/collections/obs/items?offset=0' in links[3]['href'] assert links[3]['rel'] == 'prev' assert '/collections/obs' in links[4]['href'] assert links[4]['rel'] == 'collection' req = mock_request({ - 'startindex': 1, + 'offset': 1, 'limit': 1, 'bbox': '-180,90,180,90' }) @@ -690,10 +690,10 @@ def test_get_collection_items(config, api_): assert '/collections/obs/items?f=html&limit=1&bbox=-180,90,180,90' in \ links[2]['href'] assert links[2]['rel'] == 'alternate' - assert '/collections/obs/items?startindex=0&limit=1&bbox=-180,90,180,90' \ + assert '/collections/obs/items?offset=0&limit=1&bbox=-180,90,180,90' \ in links[3]['href'] assert links[3]['rel'] == 'prev' - assert '/collections/obs/items?startindex=2&limit=1&bbox=-180,90,180,90' \ + assert '/collections/obs/items?offset=2&limit=1&bbox=-180,90,180,90' \ in links[4]['href'] assert links[4]['rel'] == 'next' assert '/collections/obs' in links[5]['href'] diff --git a/tests/test_csv__provider.py b/tests/test_csv__provider.py index 2325469..7e2610a 100644 --- a/tests/test_csv__provider.py +++ b/tests/test_csv__provider.py @@ -73,7 +73,7 @@ def test_query(config): assert len(results['features']) == 1 assert results['features'][0]['id'] == '371' - results = p.query(startindex=2, limit=1) + results = p.query(offset=2, limit=1) assert len(results['features']) == 1 assert results['features'][0]['id'] == '238' diff --git a/tests/test_elasticsearch__provider.py b/tests/test_elasticsearch__provider.py index ce1d931..9fe1c13 100644 --- a/tests/test_elasticsearch__provider.py +++ b/tests/test_elasticsearch__provider.py @@ -170,7 +170,7 @@ def test_query(config): assert len(results['features']) == 1 assert results['features'][0]['id'] == 6691831 - results = p.query(startindex=2, limit=1) + results = p.query(offset=2, limit=1) assert len(results['features']) == 1 assert results['features'][0]['id'] == 3042030 diff --git a/tests/test_mongo_provider.py b/tests/test_mongo_provider.py index dfdff10..c91e8b2 100644 --- a/tests/test_mongo_provider.py +++ b/tests/test_mongo_provider.py @@ -78,7 +78,7 @@ def test_query(config): assert len(results['features']) == 1 assert results['features'][0]['properties']['nameascii'] == 'Vatican City' - results = p.query(startindex=2, limit=1) + results = p.query(offset=2, limit=1) assert len(results['features']) == 1 assert results['features'][0]['properties']['nameascii'] == 'Vaduz' diff --git a/tests/test_ogr_csv_provider.py b/tests/test_ogr_csv_provider.py index 8b2fdb6..914beb7 100644 --- a/tests/test_ogr_csv_provider.py +++ b/tests/test_ogr_csv_provider.py @@ -143,11 +143,11 @@ def test_query_with_limit_vsicurl(config_vsicurl_csv): assert geometry is not None -def test_query_with_startindex_vsicurl(config_vsicurl_csv): +def test_query_with_offset_vsicurl(config_vsicurl_csv): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_vsicurl_csv) - feature_collection = p.query(startindex=20, limit=10, resulttype='results') + feature_collection = p.query(offset=20, limit=10, resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) assert len(features) == 10 @@ -167,7 +167,7 @@ def test_query_with_property_vsicurl(config_vsicurl_csv): p = OGRProvider(config_vsicurl_csv) feature_collection = p.query( - startindex=20, limit=10, resulttype='results', + offset=20, limit=10, resulttype='results', properties=[('denominazione_regione', 'Lazio')]) assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) diff --git a/tests/test_ogr_esrijson_provider.py b/tests/test_ogr_esrijson_provider.py index ef2e745..a8af71e 100644 --- a/tests/test_ogr_esrijson_provider.py +++ b/tests/test_ogr_esrijson_provider.py @@ -74,7 +74,7 @@ def config_ArcGIS_ESRIJSON(): def config_random_id(config_ArcGIS_ESRIJSON): p = OGRProvider(config_ArcGIS_ESRIJSON) # Get bunch of features to randomly have an id - feature_collection = p.query(startindex=0, limit=10, resulttype='results') + feature_collection = p.query(offset=0, limit=10, resulttype='results') features = feature_collection.get('features', None) features_list = [] for feature in features: @@ -158,11 +158,11 @@ def test_query_with_limit_agol(config_ArcGIS_ESRIJSON): assert geometry is not None -def test_query_with_startindex(config_ArcGIS_ESRIJSON): +def test_query_with_offset(config_ArcGIS_ESRIJSON): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_ArcGIS_ESRIJSON) - feature_collection = p.query(startindex=10, limit=10, resulttype='results') + feature_collection = p.query(offset=10, limit=10, resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) assert len(features) == 10 diff --git a/tests/test_ogr_gpkg_provider.py b/tests/test_ogr_gpkg_provider.py index 3bd09ca..51c61eb 100644 --- a/tests/test_ogr_gpkg_provider.py +++ b/tests/test_ogr_gpkg_provider.py @@ -294,11 +294,11 @@ def test_query_with_limit_4326(config_gpkg_4326): assert geometry is not None -def test_query_with_startindex_28992(config_gpkg_28992): +def test_query_with_offset_28992(config_gpkg_28992): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_gpkg_28992) - feature_collection = p.query(startindex=20, limit=5, resulttype='results') + feature_collection = p.query(offset=20, limit=5, resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) assert len(features) == 5 @@ -313,11 +313,11 @@ def test_query_with_startindex_28992(config_gpkg_28992): assert geometry is not None -def test_query_with_startindex_4326(config_gpkg_4326): +def test_query_with_offset_4326(config_gpkg_4326): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_gpkg_4326) - feature_collection = p.query(startindex=20, limit=5, resulttype='results') + feature_collection = p.query(offset=20, limit=5, resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) assert len(features) == 5 @@ -332,12 +332,12 @@ def test_query_with_startindex_4326(config_gpkg_4326): assert geometry is not None -def test_query_bbox_with_startindex_28992(config_gpkg_28992): +def test_query_bbox_with_offset_28992(config_gpkg_28992): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_gpkg_28992) feature_collection = p.query( - startindex=10, limit=5, + offset=10, limit=5, bbox=(5.742, 52.053, 5.773, 52.098), resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' @@ -354,12 +354,12 @@ def test_query_bbox_with_startindex_28992(config_gpkg_28992): assert properties['huisnummer'] == '4' -def test_query_bbox_with_startindex_4326(config_gpkg_4326): +def test_query_bbox_with_offset_4326(config_gpkg_4326): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_gpkg_4326) feature_collection = p.query( - startindex=1, limit=5, + offset=1, limit=5, bbox=(5.742, 52.053, 5.773, 52.098), resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' diff --git a/tests/test_ogr_shapefile_provider.py b/tests/test_ogr_shapefile_provider.py index bec77d4..5bf7b42 100644 --- a/tests/test_ogr_shapefile_provider.py +++ b/tests/test_ogr_shapefile_provider.py @@ -250,11 +250,11 @@ def test_query_with_limit_4326(config_shapefile_4326): assert geometry is not None -def test_query_with_startindex_28992(config_shapefile_28992): +def test_query_with_offset_28992(config_shapefile_28992): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_shapefile_28992) - feature_collection = p.query(startindex=20, limit=5, resulttype='results') + feature_collection = p.query(offset=20, limit=5, resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) assert len(features) == 5 @@ -269,11 +269,11 @@ def test_query_with_startindex_28992(config_shapefile_28992): assert geometry is not None -def test_query_with_startindex_4326(config_shapefile_4326): +def test_query_with_offset_4326(config_shapefile_4326): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_shapefile_4326) - feature_collection = p.query(startindex=20, limit=5, resulttype='results') + feature_collection = p.query(offset=20, limit=5, resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) assert len(features) == 5 @@ -288,12 +288,12 @@ def test_query_with_startindex_4326(config_shapefile_4326): assert geometry is not None -def test_query_bbox_with_startindex_28992(config_shapefile_28992): +def test_query_bbox_with_offset_28992(config_shapefile_28992): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_shapefile_28992) feature_collection = p.query( - startindex=10, limit=5, + offset=10, limit=5, bbox=(5.742, 52.053, 5.773, 52.098), resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' @@ -310,12 +310,12 @@ def test_query_bbox_with_startindex_28992(config_shapefile_28992): assert properties['huisnummer'] == '4' -def test_query_bbox_with_startindex_4326(config_shapefile_4326): +def test_query_bbox_with_offset_4326(config_shapefile_4326): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_shapefile_4326) feature_collection = p.query( - startindex=1, limit=5, + offset=1, limit=5, bbox=(5.742, 52.053, 5.773, 52.098), resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' diff --git a/tests/test_ogr_sqlite_provider.py b/tests/test_ogr_sqlite_provider.py index 2996ecd..fda95d8 100644 --- a/tests/test_ogr_sqlite_provider.py +++ b/tests/test_ogr_sqlite_provider.py @@ -154,11 +154,11 @@ def test_query_with_limit_4326(config_sqlite_4326): assert geometry is not None -def test_query_with_startindex_4326(config_sqlite_4326): +def test_query_with_offset_4326(config_sqlite_4326): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_sqlite_4326) - feature_collection = p.query(startindex=20, limit=5, resulttype='results') + feature_collection = p.query(offset=20, limit=5, resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) assert len(features) == 5 @@ -173,12 +173,12 @@ def test_query_with_startindex_4326(config_sqlite_4326): assert geometry is not None -def test_query_bbox_with_startindex_4326(config_sqlite_4326): +def test_query_bbox_with_offset_4326(config_sqlite_4326): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_sqlite_4326) feature_collection = p.query( - startindex=1, limit=50, + offset=1, limit=50, bbox=(5.742, 52.053, 5.773, 52.098), resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' diff --git a/tests/test_ogr_wfs_provider.py b/tests/test_ogr_wfs_provider.py index 91aced3..9e98327 100644 --- a/tests/test_ogr_wfs_provider.py +++ b/tests/test_ogr_wfs_provider.py @@ -418,11 +418,11 @@ def test_query_with_limit_ms(config_MapServer_WFS_cities): assert geometry is not None -def test_query_with_startindex(config_MapServer_WFS_cities): +def test_query_with_offset(config_MapServer_WFS_cities): """Testing query for a valid JSON object with geometry""" p = OGRProvider(config_MapServer_WFS_cities) - feature_collection = p.query(startindex=20, limit=5, resulttype='results') + feature_collection = p.query(offset=20, limit=5, resulttype='results') assert feature_collection.get('type', None) == 'FeatureCollection' features = feature_collection.get('features', None) assert len(features) == 5 diff --git a/tests/test_sensorthings_provider.py b/tests/test_sensorthings_provider.py index d91ed9e..046decf 100644 --- a/tests/test_sensorthings_provider.py +++ b/tests/test_sensorthings_provider.py @@ -67,7 +67,7 @@ def test_query_datastreams(config): assert len(results['features']) == 1 assert results['features'][0]['id'] == '9' - results = p.query(startindex=2, limit=1) + results = p.query(offset=2, limit=1) assert len(results['features']) == 1 assert results['features'][0]['id'] == '11' diff --git a/tests/test_tinydb_catalogue_provider.py b/tests/test_tinydb_catalogue_provider.py index 03d0225..bab4030 100644 --- a/tests/test_tinydb_catalogue_provider.py +++ b/tests/test_tinydb_catalogue_provider.py @@ -95,11 +95,11 @@ def test_query(config): assert len(results['features']) == 10 assert results['features'][0]['id'] == 'e5a71860-827c-453f-990e-0e0ba0ee67bb' # noqa - results = p.query(startindex=1, limit=1) + results = p.query(offset=1, limit=1) assert len(results['features']) == 1 assert results['features'][0]['id'] == '64e70d29-57a3-44a8-b55c-d465639d1e2e' # noqa - results = p.query(startindex=2, limit=2) + results = p.query(offset=2, limit=2) assert len(results['features']) == 2 assert results['features'][0]['id'] == 'd3028ad0-b0d0-47ff-bcc3-d383881e17cd' # noqa