From d0310b77cc96346c1b06301e0333338d4865e6a8 Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Tue, 3 Oct 2023 16:40:38 +0200 Subject: [PATCH] feat(hogql): support constant values in HogQLQuery (#17733) --- frontend/src/queries/schema.json | 4 ++++ frontend/src/queries/schema.ts | 2 ++ posthog/api/query.py | 7 +++++++ posthog/api/test/test_query.py | 19 +++++++++++++++++++ posthog/schema.py | 3 +++ 5 files changed, 35 insertions(+) diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index 0dd784cffced8..cb13caa4be23e 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -1201,6 +1201,10 @@ "response": { "$ref": "#/definitions/HogQLQueryResponse", "description": "Cached query response" + }, + "values": { + "description": "Constant values that can be referenced with the {placeholder} syntax in the query", + "type": "object" } }, "required": ["kind", "query"], diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index f1f803c41e886..3ce97fb670b76 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -144,6 +144,8 @@ export interface HogQLQuery extends DataNode { kind: NodeKind.HogQLQuery query: string filters?: HogQLFilters + /** Constant values that can be referenced with the {placeholder} syntax in the query */ + values?: Record response?: HogQLQueryResponse } diff --git a/posthog/api/query.py b/posthog/api/query.py index 20812b8313201..cb3ea78fad090 100644 --- a/posthog/api/query.py +++ b/posthog/api/query.py @@ -20,6 +20,7 @@ from posthog.api.routing import StructuredViewSetMixin from posthog.clickhouse.query_tagging import tag_queries from posthog.errors import ExposedCHQueryError +from posthog.hogql import ast from posthog.hogql.ai import PromptUnclear, write_sql_from_prompt from posthog.hogql.database.database import create_hogql_database, serialize_database from posthog.hogql.errors import HogQLException @@ -222,11 +223,17 @@ def process_query( return _unwrap_pydantic_dict(events_response) elif query_kind == "HogQLQuery": hogql_query = HogQLQuery.model_validate(query_json) + values = ( + {key: ast.Constant(value=value) for key, value in hogql_query.values.items()} + if hogql_query.values + else None + ) hogql_response = execute_hogql_query( query_type="HogQLQuery", query=hogql_query.query, team=team, filters=hogql_query.filters, + placeholders=values, default_limit=default_limit, ) return _unwrap_pydantic_dict(hogql_response) diff --git a/posthog/api/test/test_query.py b/posthog/api/test/test_query.py index cde8de9c22196..a98cc0816d902 100644 --- a/posthog/api/test/test_query.py +++ b/posthog/api/test/test_query.py @@ -522,3 +522,22 @@ def test_full_hogql_query_view(self): ["sign out", "4", "test_val3"], ], ) + + def test_full_hogql_query_values(self): + random_uuid = str(UUIDT()) + with freeze_time("2020-01-10 12:00:00"): + for _ in range(20): + _create_event(team=self.team, event="sign up", distinct_id=random_uuid, properties={"key": "test_val1"}) + flush_persons_and_events() + + with freeze_time("2020-01-10 12:14:00"): + response = process_query( + team=self.team, + query_json={ + "kind": "HogQLQuery", + "query": "select count() from events where distinct_id = {random_uuid}", + "values": {"random_uuid": random_uuid}, + }, + ) + + self.assertEqual(response.get("results", [])[0][0], 20) diff --git a/posthog/schema.py b/posthog/schema.py index 094f194ac0fc1..d1a0244579bcf 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -882,6 +882,9 @@ class HogQLQuery(BaseModel): kind: Literal["HogQLQuery"] = "HogQLQuery" query: str response: Optional[HogQLQueryResponse] = Field(default=None, description="Cached query response") + values: Optional[Dict[str, Any]] = Field( + default=None, description="Constant values that can be referenced with the {placeholder} syntax in the query" + ) class PersonsNode(BaseModel):