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

feat(hogql): tuple access #15130

Merged
merged 30 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f66b735
feat(hogql): rename refs to types
mariusandra Apr 17, 2023
87f142c
add constant types, fix macro types
mariusandra Apr 17, 2023
2d28640
bool types
mariusandra Apr 17, 2023
a463581
datetimes and uuids
mariusandra Apr 17, 2023
3b935d7
array
mariusandra Apr 17, 2023
0a390da
generate types for some nodes
mariusandra Apr 17, 2023
f1e75ae
rename fields in ast.SelectQueryAliasType
mariusandra Apr 17, 2023
83f35c2
rename ast fields
mariusandra Apr 17, 2023
5282051
not "type"
mariusandra Apr 17, 2023
8e7cbe9
rename name to "alias"
mariusandra Apr 17, 2023
341a257
rename types to ops
mariusandra Apr 17, 2023
997504a
Update query snapshots
github-actions[bot] Apr 17, 2023
2a5cdc5
Update query snapshots
github-actions[bot] Apr 17, 2023
3c1f616
feat(hogql): type class refactor
mariusandra Apr 18, 2023
7845c2a
annotate
mariusandra Apr 18, 2023
2841a55
array
mariusandra Apr 18, 2023
618baf2
add tuple access
mariusandra Apr 18, 2023
2c09532
feat(hogql): type class refactor
mariusandra Apr 18, 2023
9232749
annotate
mariusandra Apr 18, 2023
0136a50
array
mariusandra Apr 18, 2023
ecfc6ab
Update query snapshots
github-actions[bot] Apr 18, 2023
55cbecc
Update query snapshots
github-actions[bot] Apr 18, 2023
a8eb5d2
Update query snapshots
github-actions[bot] Apr 18, 2023
e4d5176
Merge branch 'hogql-types-improved' of github.com:PostHog/posthog int…
mariusandra Apr 18, 2023
11dd2a7
Merge branch 'master' into hogql-types-improved
mariusandra Apr 18, 2023
966870c
Merge branch 'master' into hogql-types-improved
mariusandra Apr 18, 2023
da10db5
Merge branch 'hogql-types-improved' into hogql-tuple-access-enabled
mariusandra Apr 18, 2023
05fc925
stable sort
mariusandra Apr 18, 2023
b2f8690
Update query snapshots
github-actions[bot] Apr 18, 2023
d34b5de
Merge branch 'master' into hogql-tuple-access-enabled
mariusandra Apr 18, 2023
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
263 changes: 169 additions & 94 deletions posthog/hogql/ast.py

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion posthog/hogql/constants.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# HogQL -> ClickHouse allowed transformations
from typing import Optional, Dict, Tuple
from typing import Optional, Dict, Tuple, Literal

from pydantic import BaseModel, Extra

ConstantDataType = Literal["int", "float", "str", "bool", "array", "tuple", "date", "datetime", "uuid", "unknown"]

CLICKHOUSE_FUNCTIONS: Dict[str, Tuple[str, int | None, int | None]] = {
# arithmetic
"plus": ("plus", 2, 2),
Expand Down Expand Up @@ -501,6 +503,8 @@
"argMax": 2,
"argMin": 2,
# TODO: more aggregate functions?
"groupArray": 1,
"sumMap": 2,
}
ADD_TIMEZONE_TO_FUNCTIONS = ("now", "now64", "NOW", "toDateTime")
# Keywords passed to ClickHouse without transformation
Expand Down
8 changes: 4 additions & 4 deletions posthog/hogql/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def select_from_persons_table(requested_fields: Dict[str, Any]):
select_from=ast.JoinExpr(table=ast.Field(chain=["raw_persons"])),
group_by=[id],
having=ast.CompareOperation(
op=ast.CompareOperationType.Eq,
op=ast.CompareOperationOp.Eq,
left=argmax_version(ast.Field(chain=["is_deleted"])),
right=ast.Constant(value=0),
),
Expand All @@ -142,7 +142,7 @@ def join_with_persons_table(from_table: str, to_table: str, requested_fields: Di
join_expr.join_type = "INNER JOIN"
join_expr.alias = to_table
join_expr.constraint = ast.CompareOperation(
op=ast.CompareOperationType.Eq,
op=ast.CompareOperationOp.Eq,
left=ast.Field(chain=[from_table, "person_id"]),
right=ast.Field(chain=[to_table, "id"]),
)
Expand Down Expand Up @@ -203,7 +203,7 @@ def select_from_person_distinct_ids_table(requested_fields: Dict[str, Any]):
select_from=ast.JoinExpr(table=ast.Field(chain=["raw_person_distinct_ids"])),
group_by=[distinct_id],
having=ast.CompareOperation(
op=ast.CompareOperationType.Eq,
op=ast.CompareOperationOp.Eq,
left=argmax_version(ast.Field(chain=["is_deleted"])),
right=ast.Constant(value=0),
),
Expand All @@ -219,7 +219,7 @@ def join_with_person_distinct_ids_table(from_table: str, to_table: str, requeste
join_expr.join_type = "INNER JOIN"
join_expr.alias = to_table
join_expr.constraint = ast.CompareOperation(
op=ast.CompareOperationType.Eq,
op=ast.CompareOperationOp.Eq,
left=ast.Field(chain=[from_table, "distinct_id"]),
right=ast.Field(chain=[to_table, "distinct_id"]),
)
Expand Down
4 changes: 2 additions & 2 deletions posthog/hogql/hogql.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ def translate_hogql(query: str, context: HogQLContext, dialect: Literal["hogql",
try:
# Create a fake query that selects from "events" to have fields to select from.
context.database = context.database or create_hogql_database(context.team_id)
select_query_ref = ast.SelectQueryRef(tables={"events": ast.TableRef(table=context.database.events)})
select_query_type = ast.SelectQueryType(tables={"events": ast.TableType(table=context.database.events)})
node = parse_expr(query, no_placeholders=True)
select_query = ast.SelectQuery(
select=[node], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), ref=select_query_ref
select=[node], select_from=ast.JoinExpr(table=ast.Field(chain=["events"])), type=select_query_type
)
prepared_ast: ast.SelectQuery = cast(
ast.SelectQuery,
Expand Down
2 changes: 1 addition & 1 deletion posthog/hogql/parse_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def parse_string(text: str) -> str:
text = text.replace("{{", "{")
text = text.replace("\\{", "{")
else:
raise HogQLException(f"Invalid string literal, must start and end with the same quote ref: {text}")
raise HogQLException(f"Invalid string literal, must start and end with the same quote type: {text}")

# copied from clickhouse_driver/util/escape.py
text = text.replace("\\b", "\b")
Expand Down
46 changes: 23 additions & 23 deletions posthog/hogql/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def get_parser(query: str) -> HogQLParser:


class HogQLErrorListener(ErrorListener):
def syntaxError(self, recognizer, offendingRef, line, column, msg, e):
def syntaxError(self, recognizer, offendingType, line, column, msg, e):
raise SyntaxException(msg, line=line, column=column)


Expand Down Expand Up @@ -372,7 +372,7 @@ def visitColumnExprExtract(self, ctx: HogQLParser.ColumnExprExtractContext):

def visitColumnExprNegate(self, ctx: HogQLParser.ColumnExprNegateContext):
return ast.BinaryOperation(
op=ast.BinaryOperationType.Sub, left=ast.Constant(value=0), right=self.visit(ctx.columnExpr())
op=ast.BinaryOperationOp.Sub, left=ast.Constant(value=0), right=self.visit(ctx.columnExpr())
)

def visitColumnExprSubquery(self, ctx: HogQLParser.ColumnExprSubqueryContext):
Expand All @@ -392,11 +392,11 @@ def visitColumnExprCast(self, ctx: HogQLParser.ColumnExprCastContext):

def visitColumnExprPrecedence1(self, ctx: HogQLParser.ColumnExprPrecedence1Context):
if ctx.SLASH():
op = ast.BinaryOperationType.Div
op = ast.BinaryOperationOp.Div
elif ctx.ASTERISK():
op = ast.BinaryOperationType.Mult
op = ast.BinaryOperationOp.Mult
elif ctx.PERCENT():
op = ast.BinaryOperationType.Mod
op = ast.BinaryOperationOp.Mod
else:
raise NotImplementedException(f"Unsupported ColumnExprPrecedence1: {ctx.operator.text}")
left = self.visit(ctx.left)
Expand All @@ -405,9 +405,9 @@ def visitColumnExprPrecedence1(self, ctx: HogQLParser.ColumnExprPrecedence1Conte

def visitColumnExprPrecedence2(self, ctx: HogQLParser.ColumnExprPrecedence2Context):
if ctx.PLUS():
op = ast.BinaryOperationType.Add
op = ast.BinaryOperationOp.Add
elif ctx.DASH():
op = ast.BinaryOperationType.Sub
op = ast.BinaryOperationOp.Sub
elif ctx.CONCAT():
raise NotImplementedException(f"Yet unsupported text concat operation: {ctx.operator.text}")
else:
Expand All @@ -418,34 +418,34 @@ def visitColumnExprPrecedence2(self, ctx: HogQLParser.ColumnExprPrecedence2Conte

def visitColumnExprPrecedence3(self, ctx: HogQLParser.ColumnExprPrecedence3Context):
if ctx.EQ_SINGLE() or ctx.EQ_DOUBLE():
op = ast.CompareOperationType.Eq
op = ast.CompareOperationOp.Eq
elif ctx.NOT_EQ():
op = ast.CompareOperationType.NotEq
op = ast.CompareOperationOp.NotEq
elif ctx.LT():
op = ast.CompareOperationType.Lt
op = ast.CompareOperationOp.Lt
elif ctx.LE():
op = ast.CompareOperationType.LtE
op = ast.CompareOperationOp.LtE
elif ctx.GT():
op = ast.CompareOperationType.Gt
op = ast.CompareOperationOp.Gt
elif ctx.GE():
op = ast.CompareOperationType.GtE
op = ast.CompareOperationOp.GtE
elif ctx.LIKE():
if ctx.NOT():
op = ast.CompareOperationType.NotLike
op = ast.CompareOperationOp.NotLike
else:
op = ast.CompareOperationType.Like
op = ast.CompareOperationOp.Like
elif ctx.ILIKE():
if ctx.NOT():
op = ast.CompareOperationType.NotILike
op = ast.CompareOperationOp.NotILike
else:
op = ast.CompareOperationType.ILike
op = ast.CompareOperationOp.ILike
elif ctx.IN():
if ctx.GLOBAL():
raise NotImplementedException(f"Unsupported node: IN GLOBAL")
if ctx.NOT():
op = ast.CompareOperationType.NotIn
op = ast.CompareOperationOp.NotIn
else:
op = ast.CompareOperationType.In
op = ast.CompareOperationOp.In
else:
raise NotImplementedException(f"Unsupported ColumnExprPrecedence3: {ctx.getText()}")
return ast.CompareOperation(left=self.visit(ctx.left), right=self.visit(ctx.right), op=op)
Expand Down Expand Up @@ -476,7 +476,7 @@ def visitColumnExprIsNull(self, ctx: HogQLParser.ColumnExprIsNullContext):
return ast.CompareOperation(
left=self.visit(ctx.columnExpr()),
right=ast.Constant(value=None),
op=ast.CompareOperationType.NotEq if ctx.NOT() else ast.CompareOperationType.Eq,
op=ast.CompareOperationOp.NotEq if ctx.NOT() else ast.CompareOperationOp.Eq,
)

def visitColumnExprWinFunctionTarget(self, ctx: HogQLParser.ColumnExprWinFunctionTargetContext):
Expand Down Expand Up @@ -536,7 +536,7 @@ def visitColumnExprOr(self, ctx: HogQLParser.ColumnExprOrContext):
return ast.Or(exprs=left_array + right_array)

def visitColumnExprTupleAccess(self, ctx: HogQLParser.ColumnExprTupleAccessContext):
raise NotImplementedException(f"Unsupported node: ColumnExprTupleAccess")
return ast.TupleAccess(tuple=self.visit(ctx.columnExpr()), index=int(ctx.DECIMAL_LITERAL().getText()))

def visitColumnExprCase(self, ctx: HogQLParser.ColumnExprCaseContext):
raise NotImplementedException(f"Unsupported node: ColumnExprCase")
Expand Down Expand Up @@ -588,12 +588,12 @@ def visitWithExprList(self, ctx: HogQLParser.WithExprListContext):
def visitWithExprSubquery(self, ctx: HogQLParser.WithExprSubqueryContext):
subquery = self.visit(ctx.selectUnionStmt())
name = self.visit(ctx.identifier())
return ast.Macro(name=name, expr=subquery, type="subquery")
return ast.Macro(name=name, expr=subquery, macro_format="subquery")

def visitWithExprColumn(self, ctx: HogQLParser.WithExprColumnContext):
expr = self.visit(ctx.columnExpr())
name = self.visit(ctx.identifier())
return ast.Macro(name=name, expr=expr, type="column")
return ast.Macro(name=name, expr=expr, macro_format="column")

def visitColumnIdentifier(self, ctx: HogQLParser.ColumnIdentifierContext):
if ctx.PLACEHOLDER():
Expand Down
Loading