-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(data-warehouse): Views backend (#16573)
* backend basics for a view * view parsing "working" * add tests and make view name unique * adjust tests * api tests and edge cases * typing * try comment * fix migration check * rename * block overlapping names at api level * add model validator * more naming changes and full integration test * update migration * update migration * remove repeat * ClickHouse * regex * update validator name * update migration * update constraint * casing --------- Co-authored-by: Michael Matloka <[email protected]>
- Loading branch information
Showing
18 changed files
with
564 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -473,3 +473,50 @@ def test_invalid_query_kind(self): | |
assert api_response.json()["code"] == "parse_error" | ||
assert "validation errors for Model" in api_response.json()["detail"] | ||
assert "type=value_error.const; given=Tomato Soup" in api_response.json()["detail"] | ||
|
||
@snapshot_clickhouse_queries | ||
def test_full_hogql_query_view(self): | ||
with freeze_time("2020-01-10 12:00:00"): | ||
_create_person( | ||
properties={"email": "[email protected]"}, | ||
distinct_ids=["2", "some-random-uid"], | ||
team=self.team, | ||
immediate=True, | ||
) | ||
_create_event(team=self.team, event="sign up", distinct_id="2", properties={"key": "test_val1"}) | ||
with freeze_time("2020-01-10 12:11:00"): | ||
_create_event(team=self.team, event="sign out", distinct_id="2", properties={"key": "test_val2"}) | ||
with freeze_time("2020-01-10 12:12:00"): | ||
_create_event(team=self.team, event="sign out", distinct_id="3", properties={"key": "test_val2"}) | ||
with freeze_time("2020-01-10 12:13:00"): | ||
_create_event( | ||
team=self.team, event="sign out", distinct_id="4", properties={"key": "test_val3", "path": "a/b/c"} | ||
) | ||
flush_persons_and_events() | ||
|
||
with freeze_time("2020-01-10 12:14:00"): | ||
|
||
self.client.post( | ||
f"/api/projects/{self.team.id}/warehouse_view/", | ||
{ | ||
"name": "event_view", | ||
"query": { | ||
"kind": "HogQLQuery", | ||
"query": f"select event AS event, distinct_id as distinct_id, properties.key as key from events order by timestamp", | ||
}, | ||
}, | ||
) | ||
query = HogQLQuery(query="select * from event_view") | ||
api_response = self.client.post(f"/api/projects/{self.team.id}/query/", {"query": query.dict()}).json() | ||
query.response = HogQLQueryResponse.parse_obj(api_response) | ||
|
||
self.assertEqual(query.response.results and len(query.response.results), 4) | ||
self.assertEqual( | ||
query.response.results, | ||
[ | ||
["sign up", "2", "test_val1"], | ||
["sign out", "2", "test_val2"], | ||
["sign out", "3", "test_val2"], | ||
["sign out", "4", "test_val3"], | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from posthog.hogql.context import HogQLContext | ||
from posthog.hogql.database.database import create_hogql_database | ||
from posthog.hogql.parser import parse_select | ||
from posthog.hogql.printer import print_ast | ||
from posthog.test.base import BaseTest | ||
from posthog.hogql.database.test.tables import ( | ||
create_aapl_stock_table_view, | ||
create_aapl_stock_s3_table, | ||
create_nested_aapl_stock_view, | ||
create_aapl_stock_table_self_referencing, | ||
) | ||
|
||
|
||
class TestSavedQuery(BaseTest): | ||
maxDiff = None | ||
|
||
def _init_database(self): | ||
self.database = create_hogql_database(self.team.pk) | ||
self.database.aapl_stock_view = create_aapl_stock_table_view() | ||
self.database.aapl_stock = create_aapl_stock_s3_table() | ||
self.database.aapl_stock_nested_view = create_nested_aapl_stock_view() | ||
self.database.aapl_stock_self = create_aapl_stock_table_self_referencing() | ||
self.context = HogQLContext(team_id=self.team.pk, enable_select_queries=True, database=self.database) | ||
|
||
def _select(self, query: str, dialect: str = "clickhouse") -> str: | ||
return print_ast(parse_select(query), self.context, dialect=dialect) | ||
|
||
def test_saved_query_table_select(self): | ||
self._init_database() | ||
|
||
hogql = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="hogql") | ||
self.assertEqual(hogql, "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10") | ||
|
||
clickhouse = self._select(query="SELECT * FROM aapl_stock_view LIMIT 10", dialect="clickhouse") | ||
|
||
self.assertEqual( | ||
clickhouse, | ||
"SELECT aapl_stock_view.Date, aapl_stock_view.Open, aapl_stock_view.High, aapl_stock_view.Low, aapl_stock_view.Close, aapl_stock_view.Volume, aapl_stock_view.OpenInt FROM (WITH aapl_stock AS (SELECT * FROM s3Cluster('posthog', %(hogql_val_0_sensitive)s, %(hogql_val_1)s)) SELECT aapl_stock.Date, aapl_stock.Open, aapl_stock.High, aapl_stock.Low, aapl_stock.Close, aapl_stock.Volume, aapl_stock.OpenInt FROM aapl_stock) AS aapl_stock_view LIMIT 10", | ||
) | ||
|
||
def test_nested_saved_queries(self): | ||
self._init_database() | ||
|
||
hogql = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="hogql") | ||
self.assertEqual(hogql, "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10") | ||
|
||
clickhouse = self._select(query="SELECT * FROM aapl_stock_nested_view LIMIT 10", dialect="clickhouse") | ||
|
||
self.assertEqual( | ||
clickhouse, | ||
"SELECT aapl_stock_nested_view.Date, aapl_stock_nested_view.Open, aapl_stock_nested_view.High, aapl_stock_nested_view.Low, aapl_stock_nested_view.Close, aapl_stock_nested_view.Volume, aapl_stock_nested_view.OpenInt FROM (SELECT aapl_stock_view.Date, aapl_stock_view.Open, aapl_stock_view.High, aapl_stock_view.Low, aapl_stock_view.Close, aapl_stock_view.Volume, aapl_stock_view.OpenInt FROM (WITH aapl_stock AS (SELECT * FROM s3Cluster('posthog', %(hogql_val_0_sensitive)s, %(hogql_val_1)s)) SELECT aapl_stock.Date, aapl_stock.Open, aapl_stock.High, aapl_stock.Low, aapl_stock.Close, aapl_stock.Volume, aapl_stock.OpenInt FROM aapl_stock) AS aapl_stock_view) AS aapl_stock_nested_view LIMIT 10", | ||
) | ||
|
||
def test_saved_query_with_alias(self): | ||
self._init_database() | ||
|
||
hogql = self._select(query="SELECT * FROM aapl_stock LIMIT 10", dialect="hogql") | ||
self.assertEqual(hogql, "SELECT Date, Open, High, Low, Close, Volume, OpenInt FROM aapl_stock LIMIT 10") | ||
|
||
clickhouse = self._select(query="SELECT * FROM aapl_stock_view AS some_alias LIMIT 10", dialect="clickhouse") | ||
|
||
self.assertEqual( | ||
clickhouse, | ||
"SELECT some_alias.Date, some_alias.Open, some_alias.High, some_alias.Low, some_alias.Close, some_alias.Volume, some_alias.OpenInt FROM (WITH aapl_stock AS (SELECT * FROM s3Cluster('posthog', %(hogql_val_0_sensitive)s, %(hogql_val_1)s)) SELECT aapl_stock.Date, aapl_stock.Open, aapl_stock.High, aapl_stock.Low, aapl_stock.Close, aapl_stock.Volume, aapl_stock.OpenInt FROM aapl_stock) AS some_alias LIMIT 10", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.