diff --git a/src/sqlfmt/rules/__init__.py b/src/sqlfmt/rules/__init__.py index 490808c..23c6dea 100644 --- a/src/sqlfmt/rules/__init__.py +++ b/src/sqlfmt/rules/__init__.py @@ -44,6 +44,24 @@ ), ), ), + Rule( + # There are some function names in some dialects that are the same as + # word operators in other dialects. Here we lex those as function + # names IFF the name is immediately followed by a `(` (with no space + # after the name. Otherwise they are lexed as word_operators by the + # next rule. + name="functions_that_overlap_with_word_operators", + priority=1099, + pattern=group( + r"filter", + r"isnull", + ) + + group(r"\("), + action=partial( + actions.handle_reserved_keyword, + action=partial(actions.add_node_to_buffer, token_type=TokenType.NAME), + ), + ), Rule( name="word_operator", priority=1100, diff --git a/tests/unit_tests/test_rule.py b/tests/unit_tests/test_rule.py index cd03258..3af0ae3 100644 --- a/tests/unit_tests/test_rule.py +++ b/tests/unit_tests/test_rule.py @@ -419,6 +419,13 @@ def test_regex_anti_match( (MAIN, "frame_clause", "range 1 following", "range "), (MAIN, "frame_clause", "range current row", "range "), (MAIN, "frame_clause", "groups between 1 preceding", "groups "), + (MAIN, "functions_that_overlap_with_word_operators", "filter(foo)", "filter"), + ( + MAIN, + "functions_that_overlap_with_word_operators", + "isnull(bar, baz)", + "isnull", + ), ], ) def test_regex_partial_match(