Skip to content

Commit eabb708

Browse files
authored
Feat(prql): add filter, set operations (#3291)
* filter for prql * add todo * add todo and test * add append * update set op * update * update CONJUCTION * update FILTER
1 parent 4cda01e commit eabb708

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

sqlglot/dialects/prql.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77
from sqlglot.tokens import TokenType
88

99

10+
def _select_all(table: exp.Expression) -> t.Optional[exp.Select]:
11+
return exp.select("*").from_(table, copy=False) if table else None
12+
13+
1014
class PRQL(Dialect):
15+
DPIPE_IS_STRING_CONCAT = False
16+
1117
class Tokenizer(tokens.Tokenizer):
1218
IDENTIFIERS = ["`"]
1319
QUOTES = ["'", '"']
@@ -26,10 +32,26 @@ class Tokenizer(tokens.Tokenizer):
2632
}
2733

2834
class Parser(parser.Parser):
35+
CONJUNCTION = {
36+
**parser.Parser.CONJUNCTION,
37+
TokenType.DAMP: exp.And,
38+
TokenType.DPIPE: exp.Or,
39+
}
40+
2941
TRANSFORM_PARSERS = {
3042
"DERIVE": lambda self, query: self._parse_selection(query),
3143
"SELECT": lambda self, query: self._parse_selection(query, append=False),
3244
"TAKE": lambda self, query: self._parse_take(query),
45+
"FILTER": lambda self, query: query.where(self._parse_conjunction()),
46+
"APPEND": lambda self, query: query.union(
47+
_select_all(self._parse_table()), distinct=False, copy=False
48+
),
49+
"REMOVE": lambda self, query: query.except_(
50+
_select_all(self._parse_table()), distinct=False, copy=False
51+
),
52+
"INTERSECT": lambda self, query: query.intersect(
53+
_select_all(self._parse_table()), distinct=False, copy=False
54+
),
3355
}
3456

3557
def _parse_statement(self) -> t.Optional[exp.Expression]:

tests/dialects/test_prql.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,35 @@ def test_prql(self):
1010
self.validate_identity("FROM x DERIVE x = a + 1", "SELECT *, a + 1 AS x FROM x")
1111
self.validate_identity("FROM x DERIVE {a + 1}", "SELECT *, a + 1 FROM x")
1212
self.validate_identity("FROM x DERIVE {x = a + 1, b}", "SELECT *, a + 1 AS x, b FROM x")
13+
self.validate_identity(
14+
"FROM x DERIVE {x = a + 1, b} SELECT {y = x, 2}", "SELECT a + 1 AS y, 2 FROM x"
15+
)
1316
self.validate_identity("FROM x TAKE 10", "SELECT * FROM x LIMIT 10")
1417
self.validate_identity("FROM x TAKE 10 TAKE 5", "SELECT * FROM x LIMIT 5")
18+
self.validate_identity("FROM x FILTER age > 25", "SELECT * FROM x WHERE age > 25")
1519
self.validate_identity(
16-
"FROM x DERIVE {x = a + 1, b} SELECT {y = x, 2}", "SELECT a + 1 AS y, 2 FROM x"
20+
"FROM x DERIVE {x = a + 1, b} FILTER age > 25",
21+
"SELECT *, a + 1 AS x, b FROM x WHERE age > 25",
22+
)
23+
self.validate_identity("FROM x FILTER dept != 'IT'", "SELECT * FROM x WHERE dept <> 'IT'")
24+
self.validate_identity(
25+
"FROM x FILTER p == 'product' SELECT { a, b }", "SELECT a, b FROM x WHERE p = 'product'"
26+
)
27+
self.validate_identity(
28+
"FROM x FILTER age > 25 FILTER age < 27", "SELECT * FROM x WHERE age > 25 AND age < 27"
29+
)
30+
self.validate_identity(
31+
"FROM x FILTER (age > 25 && age < 27)", "SELECT * FROM x WHERE (age > 25 AND age < 27)"
32+
)
33+
self.validate_identity(
34+
"FROM x FILTER (age > 25 || age < 27)", "SELECT * FROM x WHERE (age > 25 OR age < 27)"
35+
)
36+
self.validate_identity(
37+
"FROM x FILTER (age > 25 || age < 22) FILTER age > 26 FILTER age < 27",
38+
"SELECT * FROM x WHERE ((age > 25 OR age < 22) AND age > 26) AND age < 27",
39+
)
40+
self.validate_identity("FROM x APPEND y", "SELECT * FROM x UNION ALL SELECT * FROM y")
41+
self.validate_identity("FROM x REMOVE y", "SELECT * FROM x EXCEPT ALL SELECT * FROM y")
42+
self.validate_identity(
43+
"FROM x INTERSECT y", "SELECT * FROM x INTERSECT ALL SELECT * FROM y"
1744
)

0 commit comments

Comments
 (0)