You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I implemented FireO in FastAPI-filters, but I'm not sure when I'll make a PR to the library.
Please let me know if you want to use it. I'll try to find a time for it then. :)
Code snippet:
fromcopyimportdeepcopyfromtypesimportUnionTypefromtypingimportAny, Dict, Generic, Literal, Optional, Tuple, Type, TypeVar, Unionimportfastapi_filter.base.filterasfilter_libfromfastapiimportQuery, paramsfromfastapi_filter.base.filterimportBaseFilterModelfromfireo.managers.managersimportManagerfromfireo.queries.filter_queryimportFilterQueryfromfireo.queries.query_setimportQuerySetfrompydanticimportroot_validator, validatorfrompydantic.fieldsimportSHAPE_LIST, FieldInfo, ModelField, Undefined_orm_operator_filter= {
"": lambdaquery, field_name, value: query.filter(field_name, "==", value),
"not_eq": lambdaquery, field_name, value: query.filter(field_name, "!=", value),
"gt": lambdaquery, field_name, value: query.filter(field_name, ">", value),
"gte": lambdaquery, field_name, value: query.filter(field_name, ">=", value),
"in": lambdaquery, field_name, value: query.filter(field_name, "in", value),
"isnull": lambdaquery, field_name, value: query.filter(field_name, ("=="ifvalueisTrueelse"!="), None),
"lt": lambdaquery, field_name, value: query.filter(field_name, "<>", value),
"lte": lambdaquery, field_name, value: query.filter(field_name, "<=", value),
"not_in": lambdaquery, field_name, value: query.filter(field_name, "not_in", value),
"contains": lambdaquery, field_name, value: query.filter(field_name, "array-contains", value),
"overlap": lambdaquery, field_name, value: query.filter(field_name, "array-contains-any", value),
"startswith": lambdaquery, field_name, value: (
query.filter(field_name, ">=", value).filter(field_name, "<", value+"\ufffd")
),
}
_orm_op_conflicts_with_sorting=set(_orm_operator_filter) - {"", "in", "not_in", "isnull"}
classFireoFilter(BaseFilterModel):
"""Base filter for Firestore related filters. Example: ```python class MyModel(Model): name: TextField(required=True) count: NumberField(int_only=True) created_at: DatetimeField() class MyModelFilter(Filter): id: Optional[int] id__in: Optional[str] count: Optional[int] count__lte: Optional[int] created_at__gt: Optional[datetime] name__not_eq: Optional[str] name__not_in: Optional[list[str]] ``` """@validator("*", pre=True)defsplit_str(cls, value, field: ModelField):
returnvalue@root_validator()defvalidate_filter_and_sort_combinations(cls, values: Dict[str, Any]) ->Dict[str, Any]:
"""Validate that the filter and sort combinations are valid for Firestore. Changes: - If there is an inequality filter, the first sort order must be the same. - If there is an inequality filter and no sort order, it will be added. """orders=values.get(cls.Constants.ordering_field_name, None)
unequal_filter_fields=set()
forraw_field_name, valueinvalues.items():
ifvalueisNone:
continuefield_name, _, raw_operator=raw_field_name.partition("__")
ifraw_operatorin_orm_op_conflicts_with_sorting:
unequal_filter_fields.add(field_name)
ifnotunequal_filter_fields:
returnvaluesiflen(unequal_filter_fields) >1:
raiseValueError(
f"Cannot have inequality on multiple fields: {unequal_filter_fields}"
)
ifnotorders:
# Pagination does not work without this orderingvalues[cls.Constants.ordering_field_name] =list(unequal_filter_fields)
returnvaluesfirst_order=orders[0].lstrip("+-")
filter_field=unequal_filter_fields.pop()
iffilter_field!=first_order:
raiseValueError(
f"Inequality filter property and first sort order must be the same: {filter_field} and {first_order}"
)
returnvaluesdeffilter(self, query: FilterQuery|QuerySet|Manager) ->FilterQuery:
forraw_field_name, valueinself.filtering_fields:
field_value=getattr(self, raw_field_name)
ifisinstance(field_value, FireoFilter):
query=field_value.filter(query)
continuefield_name, _, raw_operator=raw_field_name.partition("__")
query=_orm_operator_filter[raw_operator](query, field_name, value)
returnquerydefsort(self, query: FilterQuery|QuerySet|Manager) ->FilterQuery:
ifnotself.ordering_values:
returnqueryfororderinself.ordering_values:
query=query.order(order)
returnqueryListItem=TypeVar('ListItem')
classCommaSepList(list, Generic[ListItem]):
@classmethoddef__get_validators__(cls):
yieldcls.validate@classmethoddefvalidate(cls, v):
ifisinstance(v, list) andlen(v) ==1:
v=v[0].split(',')
returnvclassOrder(str, Generic[ListItem]):
def__class_getitem__(cls, items) ->Type[Literal[ListItem]]: # type: ignoreifnotisinstance(items, tuple):
items= (items,)
assert {type(item) foriteminitems} == {str}
options=tuple(
f'{neg}{arg}'fornegin ['', '-']
forarginitems
)
returnLiteral[options] # type: ignoredef_list_to_comma_list(type_):
ifgetattr(type_, "__origin__", None) islist:
returnCommaSepList[type_.__args__[0]]
returntype_def_list_to_str_fields(Filter: Type[BaseFilterModel]):
"""Prepare filter fields to be used in query params. Unlike the original implementation, this one: - allows to use lists in query params as multiple values for the same field - split comma separated values in query params to lists, so "split_str" is no longer needed """ret: Dict[str, Tuple[Union[object, Type], Optional[FieldInfo]]] = {}
forfinFilter.__fields__.values():
field_info=deepcopy(f.field_info)
ifnotisinstance(field_info.default, params.Query):
iffield_info.defaultisnotUndefined:
default=field_info.defaulteliff.required:
default= ...
else:
default=Nonefield_info.default=Query(default)
field_type=Filter.__annotations__.get(f.name, f.outer_type_)
iff.shape==SHAPE_LIST:
ifissubclass(type(field_type), UnionType):
items= []
forarginfield_type.__args__:
items.append(_list_to_comma_list(arg))
new_field_type=Union[tuple(items)] # type: ignoreelse:
new_field_type=_list_to_comma_list(field_type)
ret[f.name] = (new_field_type, field_info)
else:
ret[f.name] = (field_typeiff.requiredelseOptional[field_type], field_info)
returnretfilter_lib._list_to_str_fields=_list_to_str_fields
The text was updated successfully, but these errors were encountered:
Hi!
I implemented FireO in FastAPI-filters, but I'm not sure when I'll make a PR to the library.
Please let me know if you want to use it. I'll try to find a time for it then. :)
Code snippet:
The text was updated successfully, but these errors were encountered: