diff --git a/odata_query/grammar.py b/odata_query/grammar.py index 8d83ee4..338497a 100644 --- a/odata_query/grammar.py +++ b/odata_query/grammar.py @@ -52,6 +52,7 @@ "round": 1, "floor": 1, "ceiling": 1, + "aboutequal": 3, # Geo functions "geo.distance": 2, "geo.length": 1, diff --git a/odata_query/sqlalchemy/common.py b/odata_query/sqlalchemy/common.py index 23151d0..e75a593 100644 --- a/odata_query/sqlalchemy/common.py +++ b/odata_query/sqlalchemy/common.py @@ -2,6 +2,7 @@ from typing import Any, Callable, Optional, Union from sqlalchemy.sql import functions +from sqlalchemy import func from sqlalchemy.sql.expression import ( BinaryExpression, BindParameter, @@ -301,6 +302,13 @@ def func_ceiling(self, field: ast._Node) -> functions.Function: def func_floor(self, field: ast._Node) -> functions.Function: ":meta private:" return functions_ext.floor(self.visit(field)) + + def func_aboutequal(self, field: ast._Node, value: ast._Node, tolerance: ast._Node) -> functions.Function: + ":meta private:" + field = self.visit(field) + value = self.visit(value) + tolerance = self.visit(tolerance) + return operator.lt(func.abs(operator.sub(field, value)), tolerance) def func_round(self, field: ast._Node) -> functions.Function: ":meta private:" diff --git a/odata_query/typing.py b/odata_query/typing.py index f80e88a..6c77c0a 100644 --- a/odata_query/typing.py +++ b/odata_query/typing.py @@ -95,6 +95,7 @@ def infer_return_type(node: ast.Call) -> Optional[Type[ast._Node]]: "ceiling", "floor", "round", + "aboutequal", "geo.distance", "geo.length", ):