Skip to content
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

fix/issue 105/support additional operators #112

Merged
merged 4 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file.
### Fixes

- adds "cross join" to list of supported join types. No longer merges the "cross" keyword with the previous statement ([#110](https://github.com/tconbeer/sqlfmt/issues/110) - thank you [@rdeese](https://github.com/rdeese)!)
- add support for every valid operator in postgresql, even the weird ones, like `@>`, `||/`, `?-|` ([#105](https://github.com/tconbeer/sqlfmt/issues/105))

## [0.4.3] - 2022-01-31

Expand Down
4 changes: 3 additions & 1 deletion src/sqlfmt/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from typing import List, Optional

from sqlfmt.analyzer import MAYBE_WHITESPACES, Analyzer, group
from sqlfmt.comment import Comment
from sqlfmt.exception import SqlfmtBracketError, StopJinjaLexing
from sqlfmt.line import Comment, Line, Node
from sqlfmt.line import Line
from sqlfmt.node import Node
from sqlfmt.token import Token, TokenType


Expand Down
4 changes: 3 additions & 1 deletion src/sqlfmt/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from dataclasses import dataclass, field
from typing import Callable, Dict, List, Optional

from sqlfmt.comment import Comment
from sqlfmt.exception import SqlfmtBracketError, SqlfmtParsingError
from sqlfmt.line import Comment, Line, Node
from sqlfmt.line import Line
from sqlfmt.node import Node
from sqlfmt.query import Query


Expand Down
43 changes: 36 additions & 7 deletions src/sqlfmt/dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,33 @@ def __init__(self) -> None:
name="operator",
priority=910,
pattern=group(
r"\|\|?\/", # square or cube root ||/
r"~=", # geo compare
r"!?~\*?", # posix like/not like
r"\?(=|!|<=|<!)", # regex lookahead/behind
r"\?(-\||\|\||-|\|)", # regex lookahead/behind
r"@-@", # length operator
r"@@@?", # center point operator; also text match
r"##", # closest point
r"<->", # distance operator
r"@>", # contains
r"<@", # contained by
r"<>",
r"!=",
r"\|?>>=?",
r"<<(=|\|)?",
r"=>",
r"(-|#)>>?", # json extraction
r"&&",
r"&<\|?", # not extends
r"\|?&>", # not extends
r"<\^", # below
r">\^", # above
r"\?#", # intersect
r"\|\|",
r"[+\-*/%&@|^=<>:]=?",
r"~",
r"-\|-",
r"[*+?]?\?", # regex greedy/non-greedy, also ?
r"!!", # negate text match
r"[+\-*/%&|^=<>:#!]=?", # singles
),
action=partial(
actions.add_node_to_buffer, token_type=TokenType.OPERATOR
Expand All @@ -235,16 +256,24 @@ def __init__(self) -> None:
name="word_operator",
priority=920,
pattern=group(
r"all",
r"any",
r"between",
r"cube",
r"exists",
r"grouping sets",
r"ilike",
r"in",
r"is",
r"isnull",
r"like",
r"not",
r"like(\s+any)?",
r"notnull",
r"not",
r"over",
r"similar",
r"rollup",
r"rlike",
r"some",
r"similar\s+to",
)
+ group(r"\W", r"$"),
action=partial(
Expand Down Expand Up @@ -311,7 +340,7 @@ def __init__(self) -> None:
r"having",
r"qualify",
r"window",
r"(union|intersect|except)(\s+all|distinct)?",
r"(union|intersect|except|minus)(\s+all|distinct)?",
r"order\s+by",
r"limit",
r"offset",
Expand Down
3 changes: 2 additions & 1 deletion src/sqlfmt/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
from typing import List, Optional

from sqlfmt.jinjafmt import JinjaFormatter
from sqlfmt.line import Line, Node
from sqlfmt.line import Line
from sqlfmt.merger import LineMerger
from sqlfmt.mode import Mode
from sqlfmt.node import Node
from sqlfmt.query import Query
from sqlfmt.splitter import LineSplitter

Expand Down
3 changes: 2 additions & 1 deletion src/sqlfmt/jinjafmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from types import ModuleType
from typing import Optional

from sqlfmt.line import Line, Node
from sqlfmt.line import Line
from sqlfmt.mode import Mode
from sqlfmt.node import Node


class BlackWrapper:
Expand Down
4 changes: 3 additions & 1 deletion src/sqlfmt/merger.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from dataclasses import dataclass
from typing import List

from sqlfmt.comment import Comment
from sqlfmt.exception import CannotMergeException
from sqlfmt.line import Comment, Line, Node
from sqlfmt.line import Line
from sqlfmt.mode import Mode
from sqlfmt.node import Node
from sqlfmt.token import TokenType


Expand Down
3 changes: 2 additions & 1 deletion src/sqlfmt/query.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from dataclasses import dataclass, field
from typing import List

from sqlfmt.line import Line, Node
from sqlfmt.line import Line
from sqlfmt.node import Node
from sqlfmt.token import Token


Expand Down
4 changes: 1 addition & 3 deletions tests/data/errors/900_bad_token.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
select ?
from my_table
where no_question_mark is true
select $
4 changes: 2 additions & 2 deletions tests/unit_tests/test_analyzer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import pytest

from sqlfmt.analyzer import Analyzer, SqlfmtParsingError
from sqlfmt.comment import Comment
from sqlfmt.exception import SqlfmtBracketError
from sqlfmt.line import Comment
from sqlfmt.mode import Mode
from sqlfmt.token import Token, TokenType
from tests.util import read_test_data
Expand Down Expand Up @@ -88,7 +88,7 @@ def test_simple_query_parsing(all_output_modes: Mode) -> None:


def test_parsing_error(default_analyzer: Analyzer) -> None:
source_string = "select !"
source_string = "select $"
with pytest.raises(SqlfmtParsingError):
_ = default_analyzer.parse_query(source_string=source_string)

Expand Down
2 changes: 0 additions & 2 deletions tests/unit_tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import pytest

from sqlfmt.analyzer import SqlfmtParsingError
from sqlfmt.api import (
_format_many,
_generate_matched_paths,
Expand Down Expand Up @@ -51,7 +50,6 @@ def test_format_empty_string(all_output_modes: Mode) -> None:
@pytest.mark.parametrize(
"source,exception",
[
("?\n", SqlfmtParsingError),
("select )\n", SqlfmtBracketError),
("{{\n", SqlfmtBracketError),
],
Expand Down
64 changes: 64 additions & 0 deletions tests/unit_tests/test_dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,70 @@ def test_rule_props_are_unique(self, polyglot: Polyglot) -> None:
("main", "double_colon", "::"),
("main", "colon", ":"),
("main", "semicolon", ";"),
("main", "operator", "+"),
("main", "operator", "-"),
("main", "operator", "/"),
("main", "operator", "<>"),
("main", "operator", "||"),
("main", "operator", "=>"),
("main", "operator", "||/"),
("main", "operator", "|/"),
("main", "operator", "#"),
("main", "operator", ">>"),
("main", "operator", "<<"),
("main", "operator", "!"),
("main", "operator", "!="),
# posix like/ not like
("main", "operator", "~"),
("main", "operator", "!~"),
("main", "operator", "~*"),
("main", "operator", "!~*"),
# postgresql geo operators
# see: https://www.postgresql.org/docs/current/functions-geometry.html
("main", "operator", "@-@"),
("main", "operator", "@@"),
("main", "operator", "##"),
("main", "operator", "<->"),
("main", "operator", "<@"),
("main", "operator", "@>"),
("main", "operator", "&&"),
("main", "operator", "&<"),
("main", "operator", "&>"),
("main", "operator", "<<|"),
("main", "operator", "|>>"),
("main", "operator", "&<|"),
("main", "operator", "|&>"),
("main", "operator", "<^"),
("main", "operator", ">^"),
("main", "operator", "?#"),
("main", "operator", "?-"),
("main", "operator", "?|"),
("main", "operator", "?-|"),
("main", "operator", "?||"),
("main", "operator", "~="),
# network operators
# see https://www.postgresql.org/docs/current/functions-net.html
("main", "operator", "<<="),
("main", "operator", ">>="),
# json operators
# see https://www.postgresql.org/docs/current/functions-json.html
("main", "operator", "->"),
("main", "operator", "->>"),
("main", "operator", "#>"),
("main", "operator", "#>>"),
("main", "operator", "-|-"), # range adjacency
("main", "word_operator", "is"),
("main", "word_operator", "in"),
("main", "word_operator", "like"),
("main", "word_operator", "ilike"),
("main", "word_operator", "like any"),
("main", "word_operator", "any"),
("main", "word_operator", "some"),
("main", "word_operator", "exists"),
("main", "word_operator", "all"),
("main", "word_operator", "grouping sets"),
("main", "word_operator", "cube"),
("main", "word_operator", "rollup"),
("main", "as", "as"),
("main", "on", "on"),
("main", "boolean_operator", "AND"),
Expand All @@ -101,6 +160,11 @@ def test_rule_props_are_unique(self, polyglot: Polyglot) -> None:
("main", "unterm_keyword", "left join"),
("main", "unterm_keyword", "cross join"),
("main", "unterm_keyword", "join"),
("main", "unterm_keyword", "union"),
("main", "unterm_keyword", "union all"),
("main", "unterm_keyword", "intersect"),
("main", "unterm_keyword", "minus"),
("main", "unterm_keyword", "except"),
("main", "name", "my_table_45"),
("main", "newline", "\n"),
("jinja", "jinja_comment", "{# my comment #}"),
Expand Down
3 changes: 2 additions & 1 deletion tests/unit_tests/test_jinjafmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import pytest

from sqlfmt.jinjafmt import JinjaFormatter, JinjaTag
from sqlfmt.line import Line, Node
from sqlfmt.line import Line
from sqlfmt.mode import Mode
from sqlfmt.node import Node
from sqlfmt.token import Token, TokenType


Expand Down