Skip to content

Commit dfea28f

Browse files
committed
all tests working
1 parent 9b68b54 commit dfea28f

5 files changed

Lines changed: 73 additions & 24 deletions

File tree

abstra_json_sql/apply.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Dict, Optional, Union
1+
from typing import List, Dict, Optional
22
from .tables import ITablesSnapshot
33
from .field_name import field_name, expression_name
44
from .ast import (

abstra_json_sql/lexer.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,24 @@ def extract_name(code: str):
4040
raise Exception(f"Not a valid name, code: {code}")
4141
result = ""
4242
for idx, char in enumerate(code):
43-
if start_with_name(char) or any(
44-
k.startswith((result + char).upper()) for k in keywords
45-
):
43+
if start_with_name(char):
4644
result = result + char
47-
elif result.upper() in keywords:
48-
return Token("keyword", result), code[idx:]
4945
else:
5046
return Token("name", result), code[idx:]
51-
if code.upper() in keywords:
52-
return Token("keyword", code), ""
53-
else:
54-
return Token("name", code), ""
47+
return Token("name", code), ""
48+
49+
50+
def start_with_keyword(code: str):
51+
for keyword in keywords:
52+
if code.upper().startswith(keyword.upper()):
53+
return True
54+
return False
55+
56+
57+
def extract_keyword(code: str):
58+
for keyword in keywords:
59+
if code.upper().startswith(keyword.upper()):
60+
return Token("keyword", code[: len(keyword)]), code[len(keyword) :]
5561

5662

5763
def start_with_quoted_name(code: str):
@@ -131,6 +137,9 @@ def scan(code: str) -> List[Token]:
131137
elif start_with_number(code):
132138
token, code = extract_number(code)
133139
result.append(token)
140+
elif start_with_keyword(code):
141+
token, code = extract_keyword(code)
142+
result.append(token)
134143
elif start_with_name(code):
135144
token, code = extract_name(code)
136145
result.append(token)

abstra_json_sql/parser.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,8 @@ def parse_expression(tokens: List[Token]) -> Tuple[Expression, List[Token]]:
9696
stack.append(NotExpression(expression=expression))
9797
elif next_token.value.upper() == "TRUE":
9898
stack.append(TrueExpression())
99-
tokens = tokens[1:]
10099
elif next_token.value.upper() == "FALSE":
101100
stack.append(FalseExpression())
102-
tokens = tokens[1:]
103101
elif next_token.value.upper() == "IS":
104102
left = stack.pop()
105103
right, tokens = parse_expression(tokens)
@@ -112,7 +110,7 @@ def parse_expression(tokens: List[Token]) -> Tuple[Expression, List[Token]]:
112110
stack.append(NullExpression())
113111
else:
114112
tokens = [next_token] + tokens
115-
break
113+
break
116114
if next_token.type == "int":
117115
stack.append(IntExpression(value=int(next_token.value)))
118116
elif next_token.type == "float":
@@ -240,21 +238,34 @@ def parse_group_by(tokens: List[Token]) -> Tuple[Optional[GroupBy], List[Token]]
240238
group_fields.append(exp)
241239
return GroupBy(fields=group_fields), tokens
242240

241+
243242
def parse_join(tokens: List[Token]) -> Tuple[Optional[Join], List[Token]]:
244243
if len(tokens) == 0:
245244
return None, tokens
246-
245+
247246
# JOIN
248-
if tokens[0].type == "keyword" and tokens[0].value.upper() in ["INNER JOIN", "JOIN"]:
247+
if tokens[0].type == "keyword" and tokens[0].value.upper() in [
248+
"INNER JOIN",
249+
"JOIN",
250+
]:
249251
join_type = "INNER"
250252
tokens = tokens[1:]
251-
elif tokens[0].type == "keyword" and tokens[0].value.upper() in ["LEFT JOIN", "LEFT OUTER JOIN"]:
253+
elif tokens[0].type == "keyword" and tokens[0].value.upper() in [
254+
"LEFT JOIN",
255+
"LEFT OUTER JOIN",
256+
]:
252257
join_type = "LEFT"
253258
tokens = tokens[1:]
254-
elif tokens[0].type == "keyword" and tokens[0].value.upper() in ["RIGHT JOIN", "RIGHT OUTER JOIN"]:
259+
elif tokens[0].type == "keyword" and tokens[0].value.upper() in [
260+
"RIGHT JOIN",
261+
"RIGHT OUTER JOIN",
262+
]:
255263
join_type = "RIGHT"
256264
tokens = tokens[1:]
257-
elif tokens[0].type == "keyword" and tokens[0].value.upper() in ["FULL JOIN", "FULL OUTER JOIN"]:
265+
elif tokens[0].type == "keyword" and tokens[0].value.upper() in [
266+
"FULL JOIN",
267+
"FULL OUTER JOIN",
268+
]:
258269
join_type = "FULL"
259270
tokens = tokens[1:]
260271
elif tokens[0].type == "keyword" and tokens[0].value.upper() in ["CROSS JOIN"]:
@@ -265,12 +276,12 @@ def parse_join(tokens: List[Token]) -> Tuple[Optional[Join], List[Token]]:
265276
tokens = tokens[1:]
266277
else:
267278
return None, tokens
268-
279+
269280
# Table
270281
table = tokens[0]
271282
assert table.type == "name", f"Expected table name, got {table}"
272283
tokens = tokens[1:]
273-
284+
274285
# AS
275286
if (
276287
len(tokens) > 0
@@ -283,7 +294,7 @@ def parse_join(tokens: List[Token]) -> Tuple[Optional[Join], List[Token]]:
283294
tokens = tokens[1:]
284295
else:
285296
alias_token = None
286-
297+
287298
# ON
288299
if (
289300
len(tokens) > 0
@@ -334,7 +345,7 @@ def parse_from(tokens: List[Token]) -> Tuple[Optional[From], List[Token]]:
334345
if j is None:
335346
break
336347
join.append(j)
337-
348+
338349
if len(join) == 0:
339350
return From(table=table.value), tokens
340351
else:

abstra_json_sql/parser_test.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
SelectField,
1212
IntExpression,
1313
NameExpression,
14+
IsExpression,
1415
EqualExpression,
16+
NullExpression,
1517
StringExpression,
1618
Where,
1719
OrderBy,
@@ -201,6 +203,33 @@ def test_limit_with_offset(self):
201203
self.assertEqual(tokens, [])
202204

203205

206+
class IsTest(TestCase):
207+
def test_is_expression(self):
208+
tokens = scan("name IS NULL")
209+
ast, tokens = parse_expression(tokens)
210+
self.assertEqual(
211+
ast,
212+
IsExpression(
213+
left=NameExpression(name="name"),
214+
right=NullExpression(),
215+
),
216+
)
217+
self.assertEqual(tokens, [])
218+
219+
def test_is_not_expression(self):
220+
tokens = scan("name IS NOT NULL")
221+
ast, tokens = parse_expression(tokens)
222+
self.assertEqual(
223+
ast,
224+
IsExpression(
225+
left=NameExpression(name="name"),
226+
right=NullExpression(),
227+
is_not=True,
228+
),
229+
)
230+
self.assertEqual(tokens, [])
231+
232+
204233
class AcceptKeywordTest(TestCase):
205234
def test_accept_keyword(self):
206235
tokens = [

abstra_json_sql/tokens.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
"AND",
2424
"AS",
2525
"ON",
26-
"OR",
2726
"NOT",
2827
"IN",
2928
"LIKE",
@@ -40,6 +39,7 @@
4039
"HAVING",
4140
"ASC",
4241
"DESC",
42+
"OR",
4343
"INNER JOIN",
4444
"RIGHT OUTER JOIN",
4545
"LEFT OUTER JOIN",
@@ -52,8 +52,8 @@
5252
"LIMIT",
5353
"TRUE",
5454
"FALSE",
55-
"NULL"
5655
]
56+
keywords.sort(reverse=True)
5757

5858

5959
@dataclass

0 commit comments

Comments
 (0)