diff --git a/_duckdb-stubs/__init__.pyi b/_duckdb-stubs/__init__.pyi index 124a5d5a..1d256a10 100644 --- a/_duckdb-stubs/__init__.pyi +++ b/_duckdb-stubs/__init__.pyi @@ -884,6 +884,7 @@ class Expression: def otherwise(self, value: Expression) -> Expression: ... def show(self) -> None: ... def when(self, condition: Expression, value: Expression) -> Expression: ... + def try_(self, condition: Expression, value: Expression) -> Expression: ... class FatalException(DatabaseError): ... diff --git a/src/duckdb_py/include/duckdb_python/expression/pyexpression.hpp b/src/duckdb_py/include/duckdb_python/expression/pyexpression.hpp index 39dd252f..c8668e27 100644 --- a/src/duckdb_py/include/duckdb_python/expression/pyexpression.hpp +++ b/src/duckdb_py/include/duckdb_python/expression/pyexpression.hpp @@ -83,6 +83,10 @@ struct DuckDBPyExpression : public enable_shared_from_this { shared_ptr In(const py::args &args); shared_ptr NotIn(const py::args &args); + // TRY + + shared_ptr Try(); + // Order modifiers shared_ptr Ascending(); diff --git a/src/duckdb_py/pyexpression.cpp b/src/duckdb_py/pyexpression.cpp index 5dd551a1..e65b1c19 100644 --- a/src/duckdb_py/pyexpression.cpp +++ b/src/duckdb_py/pyexpression.cpp @@ -226,6 +226,12 @@ shared_ptr DuckDBPyExpression::NotIn(const py::args &args) { return CreateCompareExpression(ExpressionType::COMPARE_NOT_IN, args); } +// TRY + +shared_ptr DuckDBPyExpression::Try() { + return DuckDBPyExpression::InternalUnaryOperator(ExpressionType::OPERATOR_TRY, *this); +} + // COALESCE shared_ptr DuckDBPyExpression::Coalesce(const py::args &args) { diff --git a/src/duckdb_py/pyexpression/initialize.cpp b/src/duckdb_py/pyexpression/initialize.cpp index 11cf5dc3..57383db6 100644 --- a/src/duckdb_py/pyexpression/initialize.cpp +++ b/src/duckdb_py/pyexpression/initialize.cpp @@ -367,6 +367,14 @@ void DuckDBPyExpression::Initialize(py::module_ &m) { )"; expression.def("isnotin", &DuckDBPyExpression::NotIn, docs); + docs = R"( + Create a TRY expression from self + + Returns: + DuckDBPyExpression: TRY(self) + )"; + expression.def("try_", &DuckDBPyExpression::Try, docs); + docs = R"( Return the stringified version of the expression. diff --git a/tests/fast/test_expression.py b/tests/fast/test_expression.py index c7eee6c1..a30955f6 100644 --- a/tests/fast/test_expression.py +++ b/tests/fast/test_expression.py @@ -928,6 +928,24 @@ def test_null(self): res2 = rel.filter(b.isnotnull()).fetchall() assert res2 == [(1, "a"), (2, "b"), (4, "c"), (5, "a")] + def test_try(self): + con = duckdb.connect() + rel = con.sql( + """ + select * from (VALUES + (-1.0), + (0.0), + (1.0), + (NULL), + ) tbl(a) + """ + ) + + expr = FunctionExpression("sqrt", ColumnExpression("a")) + + res = rel.select(expr.try_()).fetchall() + assert res == [(None,), (0.0,), (1.0,), (None,)] + def test_sort(self): con = duckdb.connect() rel = con.sql(