-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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): placeholders and cleanup #14116
Changes from 8 commits
db3603d
8bd6d2e
cabb6de
407113c
993cd51
da97e92
49f469f
7b2b84a
35e7f04
ded84ab
0ca7290
55c6ec5
b009a90
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# fields you can select from in the events query | ||
EVENT_FIELDS = [ | ||
"id", | ||
"uuid", | ||
"event", | ||
"timestamp", | ||
"properties", | ||
"elements_chain", | ||
"created_at", | ||
"distinct_id", | ||
"team_id", | ||
] | ||
# "person.*" fields you can select from in the events query | ||
EVENT_PERSON_FIELDS = ["id", "created_at", "properties"] | ||
|
||
# HogQL -> ClickHouse allowed transformations | ||
CLICKHOUSE_FUNCTIONS = { | ||
# arithmetic | ||
"abs": "abs", | ||
"max2": "max2", | ||
"min2": "min2", | ||
# type conversions | ||
"toInt": "toInt64OrNull", | ||
"toFloat": "toFloat64OrNull", | ||
"toDecimal": "toDecimal64OrNull", | ||
"toDate": "toDateOrNull", | ||
"toDateTime": "parseDateTimeBestEffort", | ||
"toIntervalSecond": "toIntervalSecond", | ||
"toIntervalMinute": "toIntervalMinute", | ||
"toIntervalHour": "toIntervalHour", | ||
"toIntervalDay": "toIntervalDay", | ||
"toIntervalWeek": "toIntervalWeek", | ||
"toIntervalMonth": "toIntervalMonth", | ||
"toIntervalQuarter": "toIntervalQuarter", | ||
"toIntervalYear": "toIntervalYear", | ||
"toString": "toString", | ||
# date functions | ||
"now": "now", | ||
"NOW": "now", | ||
"toMonday": "toMonday", | ||
"toStartOfYear": "toStartOfYear", | ||
"toStartOfQuarter": "toStartOfQuarter", | ||
"toStartOfMonth": "toStartOfMonth", | ||
"toStartOfWeek": "toStartOfWeek", | ||
"toStartOfDay": "toStartOfDay", | ||
"toStartOfHour": "toStartOfHour", | ||
"toStartOfMinute": "toStartOfMinute", | ||
"toStartOfSecond": "toStartOfSecond", | ||
"toStartOfFiveMinutes": "toStartOfFiveMinutes", | ||
"toStartOfTenMinutes": "toStartOfTenMinutes", | ||
"toStartOfFifteenMinutes": "toStartOfFifteenMinutes", | ||
"toTimezone": "toTimezone", | ||
"age": "age", | ||
"dateDiff": "dateDiff", | ||
"dateTrunc": "dateTrunc", | ||
"formatDateTime": "formatDateTime", | ||
# string functions | ||
"length": "lengthUTF8", | ||
"empty": "empty", | ||
"notEmpty": "notEmpty", | ||
"leftPad": "leftPad", | ||
"rightPad": "rightPad", | ||
"lower": "lower", | ||
"upper": "upper", | ||
"repeat": "repeat", | ||
"format": "format", | ||
"concat": "concat", | ||
"coalesce": "coalesce", | ||
"substring": "substringUTF8", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm if the route we're taking is having these little bits of magic then somewhere they should be made pretty explicit. As a suggestion if we want to keep this as is I'd at least put the "magic mappings" at the top and explain in a comment why we do so (even though I see why reading this!) Just want to be very explicit about where we're diverging the dialects There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we should document and clean this up. I'm not sure which "magic shortcuts" we want to take. I'm very very happy to revisit this list and make a real decision on each case. The current list was composed in a 20min runthrough of the clickhouse docs, explicitly without having full sql statements in mind. Things have changed enough. |
||
"appendTrailingCharIfAbsent": "appendTrailingCharIfAbsent", | ||
"endsWith": "endsWith", | ||
"startsWith": "startsWith", | ||
"trim": "trimBoth", | ||
"trimLeft": "trimLeft", | ||
"trimRight": "trimRight", | ||
"extractTextFromHTML": "extractTextFromHTML", | ||
"like": "like", | ||
"ilike": "ilike", | ||
"notLike": "notLike", | ||
"replace": "replace", | ||
"replaceOne": "replaceOne", | ||
# array functions | ||
"tuple": "tuple", | ||
# conditional | ||
"ifElse": "if", | ||
"multiIf": "multiIf", | ||
# rounding | ||
"round": "round", | ||
"floor": "floor", | ||
"ceil": "ceil", | ||
"trunc": "trunc", | ||
} | ||
# Permitted HogQL aggregations | ||
HOGQL_AGGREGATIONS = { | ||
"count": 0, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I take it these are the number of arguments each function takes? Wasn't immediately obvious to me There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, and this will need to be changed: count can take 0..1 arguments |
||
"countIf": 1, | ||
"countDistinct": 1, | ||
"countDistinctIf": 2, | ||
"min": 1, | ||
"minIf": 2, | ||
"max": 1, | ||
"maxIf": 2, | ||
"sum": 1, | ||
"sumIf": 2, | ||
"avg": 1, | ||
"avgIf": 2, | ||
"any": 1, | ||
"anyIf": 2, | ||
} | ||
# Keywords passed to ClickHouse without transformation | ||
KEYWORDS = ["true", "false", "null"] | ||
|
||
# Allow-listed fields returned when you select "*" from events. Person and group fields will be nested later. | ||
SELECT_STAR_FROM_EVENTS_FIELDS = [ | ||
"uuid", | ||
"event", | ||
"properties", | ||
"timestamp", | ||
"team_id", | ||
"distinct_id", | ||
"elements_chain", | ||
"created_at", | ||
"person.id", | ||
"person.created_at", | ||
"person.properties", | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from dataclasses import dataclass, field | ||
from typing import Dict, List, Literal, Optional | ||
|
||
|
||
@dataclass | ||
class HogQLFieldAccess: | ||
input: List[str] | ||
type: Optional[Literal["event", "event.properties", "person", "person.properties"]] | ||
field: Optional[str] | ||
sql: str | ||
Comment on lines
+5
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This
|
||
|
||
|
||
@dataclass | ||
class HogQLContext: | ||
"""Context given to a HogQL expression printer""" | ||
|
||
# If set, will save string constants to this dict. Inlines strings into the query if None. | ||
values: Dict = field(default_factory=dict) | ||
# List of field and property accesses found in the expression | ||
field_access_logs: List[HogQLFieldAccess] = field(default_factory=list) | ||
# Did the last calls to translate_hogql since setting these to False contain any of the following | ||
found_aggregation: bool = False | ||
using_person_on_events: bool = True |
Large diffs are not rendered by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't exist on the schema