-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement ordering of results (default order and through QueryParameters argument) #171
Comments
Note: If ordering should be possible 1. via query parameters and 2. We discussed possible ordering by all scalar fields, i.e. also scalar fields of potentially nested models. This introduces the significant problem of how to handle alias name clashes though. So I am for restricting order-able fields to the top model scalar fields. It is still possible to order by arbitrary SPARQL bindings through the model then, i.e. by using excluded fields in the top model. See e.g. the ungrouped wikidata example. |
The prototype/ordering branch implements an experimental feature that allows to parametrize the E.g. given a model class Work(BaseModel):
model_config = ConfigDict(group_by="name")
name: Annotated[str, SPARQLBinding("workName")]
viafs: Annotated[list[str], SPARQLBinding("viaf")]
class Author(BaseModel):
model_config = ConfigDict(group_by="gnd")
gnd: str
surname: Annotated[str, SPARQLBinding("nameLabel")]
works: list[Work] one could parametrize @app.get("/")
def base_route(
query_parameters: Annotated[QueryParameters[Author], Query()],
) -> Page[Author]:
return adapter.query(query_parameters) This would yield the following additional OpenAPI docs field: See the initial draft of this: https://gist.github.com/lu-pl/718ebf86f5b81f68f2f88005c3663be6 Note: The most recent implementation does not use a metaclass for this anymore but the metaclass-ish |
For the above described order-able feature it is necessary to provide namespacing, because given the Basically, there a two ways of going about namespacing in this case:
The current namespacing mechanism uses model name namespacing, i.e any order-able model fields are unambiguously referenced using the model name and the field name. A good example for this is wikidata_ungrouped_person_fastapi_example.py. Here, the model defines two ambiguous class Work(BaseModel):
name: Annotated[str, SPARQLBinding("title")]
class Person(BaseModel):
name: str
work: Work Which With the currently implemented model name namespacing, the |
@katharinawuensche made an excellent point in arguing that model name namespacing could still be ambiguous in the case where two fields in a model refer to the same nested model. class Place(BaseModel):
name: str
class Author(BaseModel):
birth_place: Place
death_place: Place This however is a model that will never work in By design and intent, I nonetheless implemented a mapper for model field namespacing: class NamespacedFieldBindingsMap(FieldsBindingsMap):
"""Recursive FieldBindingsMap that generates namespaced key entries."""
@staticmethod
def _get_field_binding_mapping(model: type[_TModelInstance]) -> dict[str, str]:
"""Resolve model fields against rdfproxy.SPARQLBindings."""
def _construct_bindings(model, _namespace: str = ""):
bindings_map = FieldsBindingsMap(model)
for k, v in model.model_fields.items():
if isinstance(v.annotation, type(BaseModel)):
_namespace += f"{k}."
yield from _construct_bindings(v.annotation, _namespace=_namespace)
if _is_scalar_type(v.annotation):
yield (
k if not _namespace else f"{_namespace}{k}",
bindings_map[k],
)
return dict(_construct_bindings(model))h For a model class ReallyDeeplyNestedModel(BaseModel):
field: Annotated[str, SPARQLBinding("alias_field")]
class DeeplyNestedModel(BaseModel):
really_deeply_nested: ReallyDeeplyNestedModel
class NestedModel(BaseModel):
deeply_nested: DeeplyNestedModel
class TopModel(BaseModel):
nested: NestedModel this would generate {'nested.deeply_nested.really_deeply_nested.field': 'alias_field'} as order-able field. I am more in favor of model name namespacing, as it is much more concise and will always suffice for |
There already are semantics in place for default ordering (see #128), so "default order via The fact that grouped models are default-ordered by the grouping binding and ungrouped models are default-ordered by the first binding of the projection must be prominently documented however! |
Ordering of results should be possible based on a single scalar field of the root model.
The text was updated successfully, but these errors were encountered: