Skip to content

Commit ad85158

Browse files
committed
add queryables endpoint
1 parent 40262b8 commit ad85158

File tree

4 files changed

+132
-2
lines changed

4 files changed

+132
-2
lines changed

tifeatures/factory.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,16 @@ def landing(
179179
type=MediaType.json,
180180
rel="data",
181181
),
182+
model.Link(
183+
title="Collection queryables",
184+
href=self.url_for(
185+
request,
186+
"queryables",
187+
collectionId="{collectionId}",
188+
),
189+
type=MediaType.schemajson,
190+
rel="queryables",
191+
),
182192
model.Link(
183193
title="Collection Features",
184194
href=self.url_for(
@@ -245,6 +255,7 @@ def conformance(
245255
"http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections",
246256
"http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/simple-query",
247257
"http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter,",
258+
"http://www.opengis.net/def/rel/ogc/1.0/queryables",
248259
]
249260
)
250261
if output_type and output_type == ResponseType.html:
@@ -323,6 +334,15 @@ def collections(
323334
rel="items",
324335
type=MediaType.geojson,
325336
),
337+
model.Link(
338+
href=self.url_for(
339+
request,
340+
"queryables",
341+
collectionId=collection.id,
342+
),
343+
rel="queryables",
344+
type=MediaType.schemajson,
345+
),
326346
],
327347
}
328348
)
@@ -378,6 +398,15 @@ def collection(
378398
rel="items",
379399
type=MediaType.geojson,
380400
),
401+
model.Link(
402+
href=self.url_for(
403+
request,
404+
"queryables",
405+
collectionId=collection.id,
406+
),
407+
rel="queryables",
408+
type=MediaType.schemajson,
409+
),
381410
],
382411
}
383412
)
@@ -391,6 +420,51 @@ def collection(
391420

392421
return data
393422

423+
@self.router.get(
424+
"/collections/{collectionId}/queryables",
425+
response_model=model.Queryables,
426+
response_model_exclude_none=True,
427+
response_model_by_alias=True,
428+
responses={
429+
200: {
430+
"content": {
431+
"text/html": {},
432+
"application/schema+json": {},
433+
}
434+
},
435+
},
436+
)
437+
def queryables(
438+
request: Request,
439+
collection=Depends(self.collection_dependency),
440+
output_type: Optional[ResponseType] = Depends(OutputType),
441+
):
442+
"""Queryables for a feature collection.
443+
444+
ref: http://docs.ogc.org/DRAFTS/19-079r1.html#filter-queryables
445+
"""
446+
qs = "?" + str(request.query_params) if request.query_params else ""
447+
448+
data = model.Queryables(
449+
**{
450+
"title": collection.id,
451+
"$id": self.url_for(
452+
request, "queryables", collectionId=collection.id
453+
)
454+
+ qs,
455+
"properties": collection.queryables,
456+
}
457+
)
458+
459+
if output_type and output_type == ResponseType.html:
460+
return create_html_response(
461+
request,
462+
data.json(exclude_none=True),
463+
template_name="collection",
464+
)
465+
466+
return data
467+
394468
@self.router.get(
395469
"/collections/{collectionId}/items",
396470
response_model=model.Items,

tifeatures/layer.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@
2424
from tifeatures.filter.evaluate import to_filter
2525
from tifeatures.filter.filters import bbox_to_wkt
2626

27+
# Links to geojson schema
28+
geojson_schema = {
29+
"GEOMETRY": "https://geojson.org/schema/Geometry.json",
30+
"POINT": "https://geojson.org/schema/Point.json",
31+
"MULTIPOINT": "https://geojson.org/schema/MultiPoint.json",
32+
"LINESTRING": "https://geojson.org/schema/LineString.json",
33+
"MULTILINESTRING": "https://geojson.org/schema/MultiLineString.json",
34+
"POLYGON": "https://geojson.org/schema/Polygon.json",
35+
"MULTIPOLYGON": "https://geojson.org/schema/MultiPolygon.json",
36+
"GEOMETRYCOLLECTION": "https://geojson.org/schema/GeometryCollection.json",
37+
}
38+
2739

2840
class CollectionLayer(BaseModel, metaclass=abc.ABCMeta):
2941
"""Layer's Abstract BaseClass.
@@ -69,6 +81,11 @@ async def feature(
6981
"""Return a Feature."""
7082
...
7183

84+
@property
85+
def queryables(self) -> Dict:
86+
"""Return the queryables."""
87+
...
88+
7289

7390
class Table(CollectionLayer, DBTable):
7491
"""Table Reader.
@@ -412,6 +429,22 @@ async def feature(
412429

413430
return None
414431

432+
@property
433+
def queryables(self) -> Dict:
434+
"""Return the queryables."""
435+
geometries = self.geometry_columns or []
436+
print(geometries)
437+
geoms = {
438+
col.name: {"$ref": geojson_schema.get(col.geometry_type.upper(), "")}
439+
for col in geometries
440+
}
441+
props = {
442+
col.name: {"name": col.name, "type": col.type}
443+
for col in self.properties
444+
if col.name not in geoms
445+
}
446+
return {**geoms, **props}
447+
415448

416449
class Function(CollectionLayer):
417450
"""Function Reader.
@@ -475,6 +508,12 @@ async def feature(
475508
# TODO
476509
pass
477510

511+
@property
512+
def queryables(self) -> Dict:
513+
"""Return the queryables."""
514+
# TODO
515+
pass
516+
478517

479518
@dataclass
480519
class FunctionRegistry:

tifeatures/model.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""tifeatures models."""
22

3-
from typing import List, Optional
3+
from typing import Dict, List, Optional
44

55
from geojson_pydantic import Feature, FeatureCollection
6-
from pydantic import BaseModel
6+
from pydantic import BaseModel, Field
77

88
from tifeatures.resources.enums import MediaType
99

@@ -154,3 +154,19 @@ class Landing(BaseModel):
154154
title: Optional[str]
155155
description: Optional[str]
156156
links: List[Link]
157+
158+
159+
class Queryables(BaseModel):
160+
"""Queryables model.
161+
162+
Ref: https://docs.ogc.org/DRAFTS/19-079r1.html#filter-queryables
163+
164+
"""
165+
166+
title: str
167+
properties: Dict[str, Dict[str, str]]
168+
type: str = "object"
169+
schema_name: str = Field(
170+
"https://json-schema.org/draft/2019-09/schema", alias="$schema"
171+
)
172+
link: str = Field(..., alias="$id")

tifeatures/resources/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class MediaType(str, Enum):
2424
xml = "application/xml"
2525
json = "application/json"
2626
geojson = "application/geo+json"
27+
schemajson = "application/schema+json"
2728
html = "text/html"
2829
text = "text/plain"
2930
openapi30_json = "application/vnd.oai.openapi+json;version=3.0"

0 commit comments

Comments
 (0)