diff --git a/frontend/src/queries/nodes/DataNode/dataNodeLogic.ts b/frontend/src/queries/nodes/DataNode/dataNodeLogic.ts index bcb30766fe827..e9c8aa4d70842 100644 --- a/frontend/src/queries/nodes/DataNode/dataNodeLogic.ts +++ b/frontend/src/queries/nodes/DataNode/dataNodeLogic.ts @@ -66,7 +66,10 @@ export const dataNodeLogic = kea([ actions.clearResponse() } if (!queryEqual(props.query, oldProps.query)) { - if (!props.cachedResults || (isInsightQueryNode(props.query) && !props.cachedResults['result'])) { + if ( + !props.cachedResults || + (isInsightQueryNode(props.query) && !props.cachedResults['result'] && !props.cachedResults['results']) + ) { actions.loadData() } else { actions.setResponse(props.cachedResults) diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index 404038c58b04d..c3fec7bc69a98 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -1424,7 +1424,7 @@ "next_allowed_client_refresh": { "type": "string" }, - "result": { + "results": { "items": { "type": "object" }, @@ -1437,7 +1437,7 @@ "type": "array" } }, - "required": ["result"], + "required": ["results"], "type": "object" }, "LifecycleToggle": { @@ -2288,7 +2288,7 @@ "next_allowed_client_refresh": { "type": "string" }, - "result": { + "results": { "items": { "type": "object" }, @@ -2301,7 +2301,7 @@ "type": "array" } }, - "required": ["result"], + "required": ["results"], "type": "object" }, "WebAnalyticsFilters": {}, @@ -2341,7 +2341,7 @@ "next_allowed_client_refresh": { "type": "string" }, - "result": { + "results": { "items": {}, "type": "array" }, @@ -2356,7 +2356,7 @@ "type": "array" } }, - "required": ["result"], + "required": ["results"], "type": "object" }, "WebTopClicksQuery": { @@ -2395,7 +2395,7 @@ "next_allowed_client_refresh": { "type": "string" }, - "result": { + "results": { "items": {}, "type": "array" }, @@ -2410,7 +2410,7 @@ "type": "array" } }, - "required": ["result"], + "required": ["results"], "type": "object" }, "WebTopPagesQuery": { @@ -2449,7 +2449,7 @@ "next_allowed_client_refresh": { "type": "string" }, - "result": { + "results": { "items": {}, "type": "array" }, @@ -2464,7 +2464,7 @@ "type": "array" } }, - "required": ["result"], + "required": ["results"], "type": "object" }, "WebTopSourcesQuery": { @@ -2503,7 +2503,7 @@ "next_allowed_client_refresh": { "type": "string" }, - "result": { + "results": { "items": {}, "type": "array" }, @@ -2518,7 +2518,7 @@ "type": "array" } }, - "required": ["result"], + "required": ["results"], "type": "object" } } diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index 52373a5e3cdd5..c671ff8183a4b 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -402,7 +402,7 @@ export type TrendsFilter = Omit< > export interface TrendsQueryResponse extends QueryResponse { - result: Record[] + results: Record[] } export interface TrendsQuery extends InsightsQueryBase { @@ -486,7 +486,7 @@ export type LifecycleFilter = Omit & { } // using everything except what it inherits from FilterType export interface QueryResponse { - result: unknown + results: unknown timings?: QueryTiming[] is_cached?: boolean last_refresh?: string @@ -494,7 +494,7 @@ export interface QueryResponse { } export interface LifecycleQueryResponse extends QueryResponse { - result: Record[] + results: Record[] } export interface LifecycleQuery extends InsightsQueryBase { @@ -521,7 +521,7 @@ export interface WebOverviewStatsQuery extends WebAnalyticsQueryBase { } export interface WebOverviewStatsQueryResponse extends QueryResponse { - result: unknown[] + results: unknown[] types?: unknown[] columns?: unknown[] } @@ -531,7 +531,7 @@ export interface WebTopSourcesQuery extends WebAnalyticsQueryBase { response?: WebTopSourcesQueryResponse } export interface WebTopSourcesQueryResponse extends QueryResponse { - result: unknown[] + results: unknown[] types?: unknown[] columns?: unknown[] } @@ -542,7 +542,7 @@ export interface WebTopClicksQuery extends WebAnalyticsQueryBase { response?: WebTopClicksQueryResponse } export interface WebTopClicksQueryResponse extends QueryResponse { - result: unknown[] + results: unknown[] types?: unknown[] columns?: unknown[] } @@ -553,7 +553,7 @@ export interface WebTopPagesQuery extends WebAnalyticsQueryBase { response?: WebTopPagesQueryResponse } export interface WebTopPagesQueryResponse extends QueryResponse { - result: unknown[] + results: unknown[] types?: unknown[] columns?: unknown[] } diff --git a/frontend/src/scenes/insights/insightDataLogic.ts b/frontend/src/scenes/insights/insightDataLogic.ts index f90717643bbc2..02ebede5c40dd 100644 --- a/frontend/src/scenes/insights/insightDataLogic.ts +++ b/frontend/src/scenes/insights/insightDataLogic.ts @@ -41,7 +41,7 @@ export const insightDataLogic = kea([ dataNodeLogic({ key: insightVizDataNodeKey(props) } as DataNodeLogicProps), [ 'query as insightQuery', - 'response as insightData', + 'response as insightDataRaw', 'dataLoading as insightDataLoading', 'responseErrorObject as insightDataError', 'getInsightRefreshButtonDisabledReason', @@ -147,6 +147,14 @@ export const insightDataLogic = kea([ } }, ], + + insightData: [ + (s) => [s.insightDataRaw], + (insightDataRaw): Record => { + // :TRICKY: The queries return results as `results`, but insights expect `result` + return { ...insightDataRaw, result: insightDataRaw?.results ?? insightDataRaw?.result } + }, + ], }), listeners(({ actions, values }) => ({ diff --git a/posthog/hogql_queries/insights/lifecycle_query_runner.py b/posthog/hogql_queries/insights/lifecycle_query_runner.py index c7bebc76be062..e1cf92e731472 100644 --- a/posthog/hogql_queries/insights/lifecycle_query_runner.py +++ b/posthog/hogql_queries/insights/lifecycle_query_runner.py @@ -124,7 +124,7 @@ def calculate(self): } ) - return LifecycleQueryResponse(result=res, timings=response.timings) + return LifecycleQueryResponse(results=res, timings=response.timings) @cached_property def query_date_range(self): diff --git a/posthog/hogql_queries/insights/test/test_lifecycle_hogql_query.py b/posthog/hogql_queries/insights/test/test_lifecycle_hogql_query.py index fc1f75d77c248..cb46d0f24b388 100644 --- a/posthog/hogql_queries/insights/test/test_lifecycle_hogql_query.py +++ b/posthog/hogql_queries/insights/test/test_lifecycle_hogql_query.py @@ -9,7 +9,7 @@ from posthog.test.base import APIBaseTest, ClickhouseTestMixin, _create_event, _create_person, flush_persons_and_events -class TestQuery(ClickhouseTestMixin, APIBaseTest): +class TestLifecycleHogQLQuery(ClickhouseTestMixin, APIBaseTest): maxDiff = None def _create_random_events(self) -> str: @@ -98,7 +98,7 @@ def test_lifecycle_query_whole_range(self): response = self._run_lifecycle_query(date_from, date_to, IntervalType.day) - statuses = [res["status"] for res in response.result] + statuses = [res["status"] for res in response.results] self.assertEqual(["new", "returning", "resurrecting", "dormant"], statuses) self.assertEqual( @@ -280,7 +280,7 @@ def test_lifecycle_query_whole_range(self): "status": "dormant", }, ], - response.result, + response.results, ) def test_events_query_whole_range(self): diff --git a/posthog/hogql_queries/insights/trends_query_runner.py b/posthog/hogql_queries/insights/trends_query_runner.py index 373b55b32790b..219c57e617a6f 100644 --- a/posthog/hogql_queries/insights/trends_query_runner.py +++ b/posthog/hogql_queries/insights/trends_query_runner.py @@ -146,7 +146,7 @@ def calculate(self): if self.query.trendsFilter is not None and self.query.trendsFilter.formula is not None: res = self.apply_formula(self.query.trendsFilter.formula, res) - return TrendsQueryResponse(result=res, timings=timings) + return TrendsQueryResponse(results=res, timings=timings) def build_series_response(self, response: HogQLQueryResponse, series: SeriesWithExtras): if response.results is None: diff --git a/posthog/hogql_queries/query_runner.py b/posthog/hogql_queries/query_runner.py index 915fd79de9ee3..cb6e341a3d597 100644 --- a/posthog/hogql_queries/query_runner.py +++ b/posthog/hogql_queries/query_runner.py @@ -44,7 +44,7 @@ class QueryResponse(BaseModel, Generic[DataT]): model_config = ConfigDict( extra="forbid", ) - result: DataT + results: DataT timings: Optional[List[QueryTiming]] = None types: Optional[List[Tuple[str, str]]] = None columns: Optional[List[str]] = None diff --git a/posthog/hogql_queries/test/test_query_runner.py b/posthog/hogql_queries/test/test_query_runner.py index 85258fefd380a..17a38727bb407 100644 --- a/posthog/hogql_queries/test/test_query_runner.py +++ b/posthog/hogql_queries/test/test_query_runner.py @@ -25,7 +25,7 @@ class TestQueryRunner(QueryRunner): query_type = query_class def calculate(self) -> QueryResponse: - return QueryResponse(result=list()) + return QueryResponse(results=list()) def _refresh_frequency(self) -> timedelta: return timedelta(minutes=4) diff --git a/posthog/hogql_queries/web_analytics/overview_stats.py b/posthog/hogql_queries/web_analytics/overview_stats.py index 810cab5111ffe..8632eaa781216 100644 --- a/posthog/hogql_queries/web_analytics/overview_stats.py +++ b/posthog/hogql_queries/web_analytics/overview_stats.py @@ -51,7 +51,7 @@ def calculate(self): ) return WebOverviewStatsQueryResponse( - columns=response.columns, result=response.results, timings=response.timings, types=response.types + columns=response.columns, results=response.results, timings=response.timings, types=response.types ) @cached_property diff --git a/posthog/hogql_queries/web_analytics/top_clicks.py b/posthog/hogql_queries/web_analytics/top_clicks.py index c1d7c9ee6ab29..8521e35f461bf 100644 --- a/posthog/hogql_queries/web_analytics/top_clicks.py +++ b/posthog/hogql_queries/web_analytics/top_clicks.py @@ -45,7 +45,7 @@ def calculate(self): ) return WebTopClicksQueryResponse( - columns=response.columns, result=response.results, timings=response.timings, types=response.types + columns=response.columns, results=response.results, timings=response.timings, types=response.types ) @cached_property diff --git a/posthog/hogql_queries/web_analytics/top_pages.py b/posthog/hogql_queries/web_analytics/top_pages.py index 3c2db51de8504..a17febefdd31a 100644 --- a/posthog/hogql_queries/web_analytics/top_pages.py +++ b/posthog/hogql_queries/web_analytics/top_pages.py @@ -60,7 +60,7 @@ def calculate(self): ) return WebTopPagesQueryResponse( - columns=response.columns, result=response.results, timings=response.timings, types=response.types + columns=response.columns, results=response.results, timings=response.timings, types=response.types ) @cached_property diff --git a/posthog/hogql_queries/web_analytics/top_sources.py b/posthog/hogql_queries/web_analytics/top_sources.py index 2071eae4d5472..ba61c6ab82698 100644 --- a/posthog/hogql_queries/web_analytics/top_sources.py +++ b/posthog/hogql_queries/web_analytics/top_sources.py @@ -48,7 +48,7 @@ def calculate(self): ) return WebTopSourcesQueryResponse( - columns=response.columns, result=response.results, timings=response.timings, types=response.types + columns=response.columns, results=response.results, timings=response.timings, types=response.types ) @cached_property diff --git a/posthog/schema.py b/posthog/schema.py index 8a2da426b1786..705267fdf9cdc 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -464,7 +464,7 @@ class TrendsQueryResponse(BaseModel): is_cached: Optional[bool] = None last_refresh: Optional[str] = None next_allowed_client_refresh: Optional[str] = None - result: List[Dict[str, Any]] + results: List[Dict[str, Any]] timings: Optional[List[QueryTiming]] = None @@ -476,7 +476,7 @@ class WebOverviewStatsQueryResponse(BaseModel): is_cached: Optional[bool] = None last_refresh: Optional[str] = None next_allowed_client_refresh: Optional[str] = None - result: List + results: List timings: Optional[List[QueryTiming]] = None types: Optional[List] = None @@ -489,7 +489,7 @@ class WebTopClicksQueryResponse(BaseModel): is_cached: Optional[bool] = None last_refresh: Optional[str] = None next_allowed_client_refresh: Optional[str] = None - result: List + results: List timings: Optional[List[QueryTiming]] = None types: Optional[List] = None @@ -502,7 +502,7 @@ class WebTopPagesQueryResponse(BaseModel): is_cached: Optional[bool] = None last_refresh: Optional[str] = None next_allowed_client_refresh: Optional[str] = None - result: List + results: List timings: Optional[List[QueryTiming]] = None types: Optional[List] = None @@ -515,7 +515,7 @@ class WebTopSourcesQueryResponse(BaseModel): is_cached: Optional[bool] = None last_refresh: Optional[str] = None next_allowed_client_refresh: Optional[str] = None - result: List + results: List timings: Optional[List[QueryTiming]] = None types: Optional[List] = None @@ -669,7 +669,7 @@ class LifecycleQueryResponse(BaseModel): is_cached: Optional[bool] = None last_refresh: Optional[str] = None next_allowed_client_refresh: Optional[str] = None - result: List[Dict[str, Any]] + results: List[Dict[str, Any]] timings: Optional[List[QueryTiming]] = None