From 0df5890e1824d58ceb3a7a643180fa105ad87193 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Thu, 15 Aug 2024 14:37:07 +0100 Subject: [PATCH] WIP goals query --- frontend/src/queries/schema.json | 358 ++++++++++++++++++ frontend/src/queries/schema.ts | 22 +- .../web-analytics/webAnalyticsLogic.tsx | 60 ++- posthog/hogql_queries/query_runner.py | 13 + .../web_analytics_query_runner.py | 3 +- .../hogql_queries/web_analytics/web_goals.py | 134 +++++++ posthog/schema.py | 245 ++++++++++-- 7 files changed, 784 insertions(+), 51 deletions(-) create mode 100644 posthog/hogql_queries/web_analytics/web_goals.py diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index 4f563cdd9d788e..d0fa643d526c9e 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -252,6 +252,9 @@ { "$ref": "#/definitions/WebTopClicksQuery" }, + { + "$ref": "#/definitions/WebGoalsQuery" + }, { "$ref": "#/definitions/SessionAttributionExplorerQuery" }, @@ -1778,6 +1781,92 @@ ], "type": "object" }, + "CachedWebGoalsQueryResponse": { + "additionalProperties": false, + "properties": { + "cache_key": { + "type": "string" + }, + "cache_target_age": { + "format": "date-time", + "type": "string" + }, + "calculation_trigger": { + "description": "What triggered the calculation of the query, leave empty if user/immediate", + "type": "string" + }, + "columns": { + "items": {}, + "type": "array" + }, + "error": { + "description": "Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + "type": "string" + }, + "hasMore": { + "type": "boolean" + }, + "hogql": { + "description": "Generated HogQL query.", + "type": "string" + }, + "is_cached": { + "type": "boolean" + }, + "last_refresh": { + "format": "date-time", + "type": "string" + }, + "limit": { + "type": "integer" + }, + "modifiers": { + "$ref": "#/definitions/HogQLQueryModifiers", + "description": "Modifiers used when performing the query" + }, + "next_allowed_client_refresh": { + "format": "date-time", + "type": "string" + }, + "offset": { + "type": "integer" + }, + "query_status": { + "$ref": "#/definitions/QueryStatus", + "description": "Query status indicates whether next to the provided data, a query is still running." + }, + "results": { + "items": {}, + "type": "array" + }, + "samplingRate": { + "$ref": "#/definitions/SamplingRate" + }, + "timezone": { + "type": "string" + }, + "timings": { + "description": "Measured timings for different parts of the query generation process", + "items": { + "$ref": "#/definitions/QueryTiming" + }, + "type": "array" + }, + "types": { + "items": {}, + "type": "array" + } + }, + "required": [ + "cache_key", + "is_cached", + "last_refresh", + "next_allowed_client_refresh", + "results", + "timezone" + ], + "type": "object" + }, "CachedWebOverviewQueryResponse": { "additionalProperties": false, "properties": { @@ -2600,6 +2689,60 @@ "required": ["results"], "type": "object" }, + { + "additionalProperties": false, + "properties": { + "columns": { + "items": {}, + "type": "array" + }, + "error": { + "description": "Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + "type": "string" + }, + "hasMore": { + "type": "boolean" + }, + "hogql": { + "description": "Generated HogQL query.", + "type": "string" + }, + "limit": { + "type": "integer" + }, + "modifiers": { + "$ref": "#/definitions/HogQLQueryModifiers", + "description": "Modifiers used when performing the query" + }, + "offset": { + "type": "integer" + }, + "query_status": { + "$ref": "#/definitions/QueryStatus", + "description": "Query status indicates whether next to the provided data, a query is still running." + }, + "results": { + "items": {}, + "type": "array" + }, + "samplingRate": { + "$ref": "#/definitions/SamplingRate" + }, + "timings": { + "description": "Measured timings for different parts of the query generation process", + "items": { + "$ref": "#/definitions/QueryTiming" + }, + "type": "array" + }, + "types": { + "items": {}, + "type": "array" + } + }, + "required": ["results"], + "type": "object" + }, { "additionalProperties": false, "properties": { @@ -2801,6 +2944,9 @@ { "$ref": "#/definitions/WebTopClicksQuery" }, + { + "$ref": "#/definitions/WebGoalsQuery" + }, { "$ref": "#/definitions/SessionAttributionExplorerQuery" }, @@ -5991,6 +6137,7 @@ "WebOverviewQuery", "WebTopClicksQuery", "WebStatsTableQuery", + "WebGoalsQuery", "DatabaseSchemaQuery" ], "type": "string" @@ -6998,6 +7145,60 @@ "required": ["results"], "type": "object" }, + { + "additionalProperties": false, + "properties": { + "columns": { + "items": {}, + "type": "array" + }, + "error": { + "description": "Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + "type": "string" + }, + "hasMore": { + "type": "boolean" + }, + "hogql": { + "description": "Generated HogQL query.", + "type": "string" + }, + "limit": { + "type": "integer" + }, + "modifiers": { + "$ref": "#/definitions/HogQLQueryModifiers", + "description": "Modifiers used when performing the query" + }, + "offset": { + "type": "integer" + }, + "query_status": { + "$ref": "#/definitions/QueryStatus", + "description": "Query status indicates whether next to the provided data, a query is still running." + }, + "results": { + "items": {}, + "type": "array" + }, + "samplingRate": { + "$ref": "#/definitions/SamplingRate" + }, + "timings": { + "description": "Measured timings for different parts of the query generation process", + "items": { + "$ref": "#/definitions/QueryTiming" + }, + "type": "array" + }, + "types": { + "items": {}, + "type": "array" + } + }, + "required": ["results"], + "type": "object" + }, { "additionalProperties": false, "properties": { @@ -7435,6 +7636,60 @@ "required": ["results"], "type": "object" }, + { + "additionalProperties": false, + "properties": { + "columns": { + "items": {}, + "type": "array" + }, + "error": { + "description": "Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + "type": "string" + }, + "hasMore": { + "type": "boolean" + }, + "hogql": { + "description": "Generated HogQL query.", + "type": "string" + }, + "limit": { + "type": "integer" + }, + "modifiers": { + "$ref": "#/definitions/HogQLQueryModifiers", + "description": "Modifiers used when performing the query" + }, + "offset": { + "type": "integer" + }, + "query_status": { + "$ref": "#/definitions/QueryStatus", + "description": "Query status indicates whether next to the provided data, a query is still running." + }, + "results": { + "items": {}, + "type": "array" + }, + "samplingRate": { + "$ref": "#/definitions/SamplingRate" + }, + "timings": { + "description": "Measured timings for different parts of the query generation process", + "items": { + "$ref": "#/definitions/QueryTiming" + }, + "type": "array" + }, + "types": { + "items": {}, + "type": "array" + } + }, + "required": ["results"], + "type": "object" + }, { "additionalProperties": false, "properties": { @@ -7882,6 +8137,9 @@ { "$ref": "#/definitions/WebTopClicksQuery" }, + { + "$ref": "#/definitions/WebGoalsQuery" + }, { "$ref": "#/definitions/SessionAttributionExplorerQuery" }, @@ -9284,6 +9542,106 @@ }, "type": "array" }, + "WebGoalsQuery": { + "additionalProperties": false, + "properties": { + "dateRange": { + "$ref": "#/definitions/DateRange" + }, + "filterTestAccounts": { + "type": "boolean" + }, + "kind": { + "const": "WebGoalsQuery", + "type": "string" + }, + "limit": { + "type": "integer" + }, + "modifiers": { + "$ref": "#/definitions/HogQLQueryModifiers", + "description": "Modifiers used when performing the query" + }, + "properties": { + "$ref": "#/definitions/WebAnalyticsPropertyFilters" + }, + "response": { + "$ref": "#/definitions/WebGoalsQueryResponse" + }, + "sampling": { + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "forceSamplingRate": { + "$ref": "#/definitions/SamplingRate" + } + }, + "type": "object" + }, + "useSessionsTable": { + "deprecated": "ignored, always treated as enabled *", + "type": "boolean" + } + }, + "required": ["kind", "properties"], + "type": "object" + }, + "WebGoalsQueryResponse": { + "additionalProperties": false, + "properties": { + "columns": { + "items": {}, + "type": "array" + }, + "error": { + "description": "Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + "type": "string" + }, + "hasMore": { + "type": "boolean" + }, + "hogql": { + "description": "Generated HogQL query.", + "type": "string" + }, + "limit": { + "type": "integer" + }, + "modifiers": { + "$ref": "#/definitions/HogQLQueryModifiers", + "description": "Modifiers used when performing the query" + }, + "offset": { + "type": "integer" + }, + "query_status": { + "$ref": "#/definitions/QueryStatus", + "description": "Query status indicates whether next to the provided data, a query is still running." + }, + "results": { + "items": {}, + "type": "array" + }, + "samplingRate": { + "$ref": "#/definitions/SamplingRate" + }, + "timings": { + "description": "Measured timings for different parts of the query generation process", + "items": { + "$ref": "#/definitions/QueryTiming" + }, + "type": "array" + }, + "types": { + "items": {}, + "type": "array" + } + }, + "required": ["results"], + "type": "object" + }, "WebOverviewItem": { "additionalProperties": false, "properties": { diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index 1e80dc0c83ea16..a8278c7d742b45 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -86,6 +86,7 @@ export enum NodeKind { WebOverviewQuery = 'WebOverviewQuery', WebTopClicksQuery = 'WebTopClicksQuery', WebStatsTableQuery = 'WebStatsTableQuery', + WebGoalsQuery = 'WebGoalsQuery', // Database metadata DatabaseSchemaQuery = 'DatabaseSchemaQuery', @@ -107,6 +108,7 @@ export type AnyDataNode = | WebOverviewQuery | WebStatsTableQuery | WebTopClicksQuery + | WebGoalsQuery | SessionAttributionExplorerQuery | ErrorTrackingQuery @@ -131,6 +133,7 @@ export type QuerySchema = | WebOverviewQuery | WebStatsTableQuery | WebTopClicksQuery + | WebGoalsQuery | SessionAttributionExplorerQuery | ErrorTrackingQuery @@ -522,6 +525,7 @@ export interface DataTableNode | WebOverviewQuery | WebStatsTableQuery | WebTopClicksQuery + | WebGoalsQuery | SessionAttributionExplorerQuery | ErrorTrackingQuery )['response'] @@ -539,6 +543,7 @@ export interface DataTableNode | WebOverviewQuery | WebStatsTableQuery | WebTopClicksQuery + | WebGoalsQuery | SessionAttributionExplorerQuery | ErrorTrackingQuery /** Columns shown in the table, unless the `source` provides them. */ @@ -1290,9 +1295,24 @@ export interface WebStatsTableQueryResponse extends AnalyticsQueryResponseBase +export interface WebGoalsQuery extends WebAnalyticsQueryBase { + kind: NodeKind.WebGoalsQuery + limit?: integer +} + +export interface WebGoalsQueryResponse extends AnalyticsQueryResponseBase { + types?: unknown[] + columns?: unknown[] + hogql?: string + samplingRate?: SamplingRate + hasMore?: boolean + limit?: integer + offset?: integer +} +export type CachedWebGoalsQueryResponse = CachedQueryResponse + export enum SessionAttributionGroupBy { ChannelType = 'ChannelType', Medium = 'Medium', diff --git a/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx b/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx index 226aa5c4f2e7fa..b7b6420f16eb41 100644 --- a/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx +++ b/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx @@ -59,6 +59,7 @@ export enum TileId { RETENTION = 'RETENTION', REPLAY = 'REPLAY', ERROR_TRACKING = 'ERROR_TRACKING', + GOALS = 'GOALS', } const loadPriorityMap: Record = { @@ -71,6 +72,7 @@ const loadPriorityMap: Record = { [TileId.RETENTION]: 7, [TileId.REPLAY]: 8, [TileId.ERROR_TRACKING]: 9, + [TileId.GOALS]: 10, } interface BaseTile { @@ -1103,35 +1105,24 @@ export const webAnalyticsLogic = kea([ : null, { kind: 'query', - tileId: TileId.RETENTION, + tileId: TileId.GOALS, title: 'Retention', layout: { colSpanClassName: 'md:col-span-2', }, query: { - kind: NodeKind.InsightVizNode, + full: true, + kind: NodeKind.DataTableNode, source: { - kind: NodeKind.RetentionQuery, + kind: NodeKind.WebGoalsQuery, properties: webAnalyticsFilters, dateRange, + sampling, + limit: 10, filterTestAccounts, - retentionFilter: { - retentionType: RETENTION_FIRST_TIME, - retentionReference: 'total', - totalIntervals: isGreaterThanMd ? 8 : 5, - period: RetentionPeriod.Week, - }, - }, - vizSpecificOptions: { - [InsightType.RETENTION]: { - hideLineGraph: true, - hideSizeColumn: !isGreaterThanMd, - useSmallLayout: !isGreaterThanMd, - }, }, - embedded: true, }, - insightProps: createInsightProps(TileId.RETENTION), + insightProps: createInsightProps(TileId.GOALS), canOpenInsight: true, canOpenModal: false, }, @@ -1162,6 +1153,39 @@ export const webAnalyticsLogic = kea([ }), } : null, + { + kind: 'query', + tileId: TileId.RETENTION, + layout: { + colSpanClassName: 'md:col-span-1', + }, + canOpenInsight: false, + canOpenModal: true, + query: { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.RetentionQuery, + properties: webAnalyticsFilters, + dateRange, + filterTestAccounts, + retentionFilter: { + retentionType: RETENTION_FIRST_TIME, + retentionReference: 'total', + totalIntervals: isGreaterThanMd ? 8 : 5, + period: RetentionPeriod.Week, + }, + }, + vizSpecificOptions: { + [InsightType.RETENTION]: { + hideLineGraph: true, + hideSizeColumn: !isGreaterThanMd, + useSmallLayout: !isGreaterThanMd, + }, + }, + embedded: true, + }, + insightProps: createInsightProps(TileId.RETENTION), + }, ] return allTiles.filter(isNotNil) }, diff --git a/posthog/hogql_queries/query_runner.py b/posthog/hogql_queries/query_runner.py index c42142898240bb..f4548656146b05 100644 --- a/posthog/hogql_queries/query_runner.py +++ b/posthog/hogql_queries/query_runner.py @@ -52,6 +52,7 @@ GenericCachedQueryResponse, QueryStatus, SessionAttributionExplorerQuery, + WebGoalsQuery, ) from posthog.schema_helpers import to_dict, to_json from posthog.utils import generate_cache_key, get_from_dict_or_attr @@ -136,6 +137,7 @@ def shared_insights_execution_mode(execution_mode: ExecutionMode) -> ExecutionMo WebOverviewQuery, WebStatsTableQuery, WebTopClicksQuery, + WebGoalsQuery, SessionAttributionExplorerQuery, ] @@ -317,6 +319,17 @@ def get_query_runner( limit_context=limit_context, ) + if kind == "WebGoalsQuery": + from .web_analytics.web_goals import WebGoalsQueryRunner + + return WebGoalsQueryRunner( + query=query, + team=team, + timings=timings, + modifiers=modifiers, + limit_context=limit_context, + ) + if kind == "SessionAttributionExplorerQuery": from .web_analytics.session_attribution_explorer_query_runner import SessionAttributionExplorerQueryRunner diff --git a/posthog/hogql_queries/web_analytics/web_analytics_query_runner.py b/posthog/hogql_queries/web_analytics/web_analytics_query_runner.py index 75a3d8cc4e8203..7f0f2790fd5b23 100644 --- a/posthog/hogql_queries/web_analytics/web_analytics_query_runner.py +++ b/posthog/hogql_queries/web_analytics/web_analytics_query_runner.py @@ -24,10 +24,11 @@ PersonPropertyFilter, SamplingRate, SessionPropertyFilter, + WebGoalsQuery, ) from posthog.utils import generate_cache_key, get_safe_cache -WebQueryNode = Union[WebOverviewQuery, WebTopClicksQuery, WebStatsTableQuery] +WebQueryNode = Union[WebOverviewQuery, WebTopClicksQuery, WebStatsTableQuery, WebGoalsQuery] class WebAnalyticsQueryRunner(QueryRunner, ABC): diff --git a/posthog/hogql_queries/web_analytics/web_goals.py b/posthog/hogql_queries/web_analytics/web_goals.py new file mode 100644 index 00000000000000..640be7ca85de4f --- /dev/null +++ b/posthog/hogql_queries/web_analytics/web_goals.py @@ -0,0 +1,134 @@ +from typing import Optional + +from django.utils.timezone import datetime + +from posthog.hogql import ast +from posthog.hogql.parser import parse_select +from posthog.hogql.property import property_to_expr, get_property_type, action_to_expr +from posthog.hogql.query import execute_hogql_query +from posthog.hogql_queries.utils.query_date_range import QueryDateRange +from posthog.hogql_queries.web_analytics.web_analytics_query_runner import ( + WebAnalyticsQueryRunner, +) +from posthog.models import Action +from posthog.models.filters.mixins.utils import cached_property +from posthog.schema import WebGoalsQueryResponse, WebGoalsQuery, CachedWebGoalsQueryResponse + + +class WebGoalsQueryRunner(WebAnalyticsQueryRunner): + query: WebGoalsQuery + response: WebGoalsQueryResponse + cached_response: CachedWebGoalsQueryResponse + + def to_query(self) -> ast.SelectQuery | ast.SelectUnionQuery: + with self.timings.measure("date_expr"): + start = self.query_date_range.date_from_as_hogql() + end = self.query_date_range.date_to_as_hogql() + + actions = Action.objects.filter(team=self.team).order_by("pinned_at", "-last_calculated_at")[:5] + action = actions[0] + + return parse_select( + """ +SELECT + sum(action_count) as count, + uniq(person_id) as total_people, + uniq(action_person_id) as uniques, + uniques/total_people as rate +FROM ( + SELECT + any(events.person_id) as person_id, + session.session_id as session_id, + countIf({action_where}) as action_count, + if (action_count > 0, person_id, NULL) as action_person_id, + FROM events + WHERE and( + events.`$session_id` IS NOT NULL, + event = '$pageview' OR {action_where}, + timestamp >= {start}, + timestamp < {end}, + {event_properties}, + {session_properties} + ) + GROUP BY session_id +) + """, + placeholders={ + "start": start, + "end": end, + "event_properties": self.event_properties(), + "session_properties": self.session_properties(), + "action_where": action_to_expr(action), + }, + ) + + def calculate(self): + response = execute_hogql_query( + query_type="web_goals_query", + query=self.to_query(), + team=self.team, + timings=self.timings, + modifiers=self.modifiers, + limit_context=self.limit_context, + ) + assert response.results + + row = response.results[0] + + return WebGoalsQueryResponse( + results=[ + [row[0], row[1], row[2], row[3]], + ], + samplingRate=self._sample_rate, + modifiers=self.modifiers, + ) + + @cached_property + def query_date_range(self): + return QueryDateRange( + date_range=self.query.dateRange, + team=self.team, + interval=None, + now=datetime.now(), + ) + + def all_properties(self) -> ast.Expr: + properties = self.query.properties + self._test_account_filters + return property_to_expr(properties, team=self.team) + + def event_properties(self) -> ast.Expr: + properties = [ + p for p in self.query.properties + self._test_account_filters if get_property_type(p) in ["event", "person"] + ] + return property_to_expr(properties, team=self.team, scope="event") + + def session_properties(self) -> ast.Expr: + properties = [ + p for p in self.query.properties + self._test_account_filters if get_property_type(p) == "session" + ] + return property_to_expr(properties, team=self.team, scope="event") + + +def to_data( + key: str, + kind: str, + value: Optional[float], + previous: Optional[float], + is_increase_bad: Optional[bool] = None, +) -> dict: + if kind == "percentage": + if value is not None: + value = value * 100 + if previous is not None: + previous = previous * 100 + + return { + "key": key, + "kind": kind, + "isIncreaseBad": is_increase_bad, + "value": value, + "previous": previous, + "changeFromPreviousPct": round(100 * (value - previous) / previous) + if value is not None and previous is not None and previous != 0 + else None, + } diff --git a/posthog/schema.py b/posthog/schema.py index 3c4604f8f84f57..4c5cf7fec6aa45 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -749,6 +749,7 @@ class NodeKind(StrEnum): WEB_OVERVIEW_QUERY = "WebOverviewQuery" WEB_TOP_CLICKS_QUERY = "WebTopClicksQuery" WEB_STATS_TABLE_QUERY = "WebStatsTableQuery" + WEB_GOALS_QUERY = "WebGoalsQuery" DATABASE_SCHEMA_QUERY = "DatabaseSchemaQuery" @@ -1274,6 +1275,41 @@ class VizSpecificOptions(BaseModel): RETENTION: Optional[RETENTION] = None +class Sampling(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + enabled: Optional[bool] = None + forceSamplingRate: Optional[SamplingRate] = None + + +class WebGoalsQueryResponse(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + columns: Optional[list] = None + error: Optional[str] = Field( + default=None, + description="Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + ) + hasMore: Optional[bool] = None + hogql: Optional[str] = Field(default=None, description="Generated HogQL query.") + limit: Optional[int] = None + modifiers: Optional[HogQLQueryModifiers] = Field( + default=None, description="Modifiers used when performing the query" + ) + offset: Optional[int] = None + query_status: Optional[QueryStatus] = Field( + default=None, description="Query status indicates whether next to the provided data, a query is still running." + ) + results: list + samplingRate: Optional[SamplingRate] = None + timings: Optional[list[QueryTiming]] = Field( + default=None, description="Measured timings for different parts of the query generation process" + ) + types: Optional[list] = None + + class Kind2(StrEnum): UNIT = "unit" DURATION_S = "duration_s" @@ -1292,14 +1328,6 @@ class WebOverviewItem(BaseModel): value: Optional[float] = None -class Sampling(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - enabled: Optional[bool] = None - forceSamplingRate: Optional[SamplingRate] = None - - class WebOverviewQueryResponse(BaseModel): model_config = ConfigDict( extra="forbid", @@ -1833,6 +1861,42 @@ class CachedTrendsQueryResponse(BaseModel): ) +class CachedWebGoalsQueryResponse(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + cache_key: str + cache_target_age: Optional[AwareDatetime] = None + calculation_trigger: Optional[str] = Field( + default=None, description="What triggered the calculation of the query, leave empty if user/immediate" + ) + columns: Optional[list] = None + error: Optional[str] = Field( + default=None, + description="Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + ) + hasMore: Optional[bool] = None + hogql: Optional[str] = Field(default=None, description="Generated HogQL query.") + is_cached: bool + last_refresh: AwareDatetime + limit: Optional[int] = None + modifiers: Optional[HogQLQueryModifiers] = Field( + default=None, description="Modifiers used when performing the query" + ) + next_allowed_client_refresh: AwareDatetime + offset: Optional[int] = None + query_status: Optional[QueryStatus] = Field( + default=None, description="Query status indicates whether next to the provided data, a query is still running." + ) + results: list + samplingRate: Optional[SamplingRate] = None + timezone: str + timings: Optional[list[QueryTiming]] = Field( + default=None, description="Measured timings for different parts of the query generation process" + ) + types: Optional[list] = None + + class CachedWebOverviewQueryResponse(BaseModel): model_config = ConfigDict( extra="forbid", @@ -2113,7 +2177,8 @@ class Response6(BaseModel): query_status: Optional[QueryStatus] = Field( default=None, description="Query status indicates whether next to the provided data, a query is still running." ) - results: Any + results: list + samplingRate: Optional[SamplingRate] = None timings: Optional[list[QueryTiming]] = Field( default=None, description="Measured timings for different parts of the query generation process" ) @@ -2121,6 +2186,32 @@ class Response6(BaseModel): class Response7(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + columns: Optional[list] = None + error: Optional[str] = Field( + default=None, + description="Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + ) + hasMore: Optional[bool] = None + hogql: Optional[str] = Field(default=None, description="Generated HogQL query.") + limit: Optional[int] = None + modifiers: Optional[HogQLQueryModifiers] = Field( + default=None, description="Modifiers used when performing the query" + ) + offset: Optional[int] = None + query_status: Optional[QueryStatus] = Field( + default=None, description="Query status indicates whether next to the provided data, a query is still running." + ) + results: Any + timings: Optional[list[QueryTiming]] = Field( + default=None, description="Measured timings for different parts of the query generation process" + ) + types: Optional[list] = None + + +class Response8(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2766,7 +2857,8 @@ class QueryResponseAlternative12(BaseModel): query_status: Optional[QueryStatus] = Field( default=None, description="Query status indicates whether next to the provided data, a query is still running." ) - results: Any + results: list + samplingRate: Optional[SamplingRate] = None timings: Optional[list[QueryTiming]] = Field( default=None, description="Measured timings for different parts of the query generation process" ) @@ -2774,6 +2866,32 @@ class QueryResponseAlternative12(BaseModel): class QueryResponseAlternative13(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + columns: Optional[list] = None + error: Optional[str] = Field( + default=None, + description="Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + ) + hasMore: Optional[bool] = None + hogql: Optional[str] = Field(default=None, description="Generated HogQL query.") + limit: Optional[int] = None + modifiers: Optional[HogQLQueryModifiers] = Field( + default=None, description="Modifiers used when performing the query" + ) + offset: Optional[int] = None + query_status: Optional[QueryStatus] = Field( + default=None, description="Query status indicates whether next to the provided data, a query is still running." + ) + results: Any + timings: Optional[list[QueryTiming]] = Field( + default=None, description="Measured timings for different parts of the query generation process" + ) + types: Optional[list] = None + + +class QueryResponseAlternative14(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2798,7 +2916,7 @@ class QueryResponseAlternative13(BaseModel): ) -class QueryResponseAlternative14(BaseModel): +class QueryResponseAlternative15(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2824,7 +2942,7 @@ class QueryResponseAlternative14(BaseModel): types: list[str] -class QueryResponseAlternative15(BaseModel): +class QueryResponseAlternative16(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2851,7 +2969,7 @@ class QueryResponseAlternative15(BaseModel): types: list[str] -class QueryResponseAlternative16(BaseModel): +class QueryResponseAlternative17(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2881,7 +2999,7 @@ class QueryResponseAlternative16(BaseModel): types: Optional[list] = Field(default=None, description="Types of returned columns") -class QueryResponseAlternative17(BaseModel): +class QueryResponseAlternative18(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2905,7 +3023,7 @@ class QueryResponseAlternative17(BaseModel): ) -class QueryResponseAlternative18(BaseModel): +class QueryResponseAlternative19(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2932,7 +3050,7 @@ class QueryResponseAlternative18(BaseModel): types: Optional[list] = None -class QueryResponseAlternative19(BaseModel): +class QueryResponseAlternative20(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2956,7 +3074,34 @@ class QueryResponseAlternative19(BaseModel): types: Optional[list] = None -class QueryResponseAlternative20(BaseModel): +class QueryResponseAlternative21(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + columns: Optional[list] = None + error: Optional[str] = Field( + default=None, + description="Query error. Returned only if 'explain' or `modifiers.debug` is true. Throws an error otherwise.", + ) + hasMore: Optional[bool] = None + hogql: Optional[str] = Field(default=None, description="Generated HogQL query.") + limit: Optional[int] = None + modifiers: Optional[HogQLQueryModifiers] = Field( + default=None, description="Modifiers used when performing the query" + ) + offset: Optional[int] = None + query_status: Optional[QueryStatus] = Field( + default=None, description="Query status indicates whether next to the provided data, a query is still running." + ) + results: list + samplingRate: Optional[SamplingRate] = None + timings: Optional[list[QueryTiming]] = Field( + default=None, description="Measured timings for different parts of the query generation process" + ) + types: Optional[list] = None + + +class QueryResponseAlternative22(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -2982,7 +3127,7 @@ class QueryResponseAlternative20(BaseModel): types: Optional[list] = None -class QueryResponseAlternative21(BaseModel): +class QueryResponseAlternative23(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -3007,7 +3152,7 @@ class QueryResponseAlternative21(BaseModel): ) -class QueryResponseAlternative22(BaseModel): +class QueryResponseAlternative24(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -3029,7 +3174,7 @@ class QueryResponseAlternative22(BaseModel): ) -class QueryResponseAlternative23(BaseModel): +class QueryResponseAlternative25(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -3050,7 +3195,7 @@ class QueryResponseAlternative23(BaseModel): ) -class QueryResponseAlternative25(BaseModel): +class QueryResponseAlternative27(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -3071,7 +3216,7 @@ class QueryResponseAlternative25(BaseModel): ) -class QueryResponseAlternative28(BaseModel): +class QueryResponseAlternative30(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -3241,6 +3386,23 @@ class TableSettings(BaseModel): columns: Optional[list[ChartAxis]] = None +class WebGoalsQuery(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + dateRange: Optional[DateRange] = None + filterTestAccounts: Optional[bool] = None + kind: Literal["WebGoalsQuery"] = "WebGoalsQuery" + limit: Optional[int] = None + modifiers: Optional[HogQLQueryModifiers] = Field( + default=None, description="Modifiers used when performing the query" + ) + properties: list[Union[EventPropertyFilter, PersonPropertyFilter, SessionPropertyFilter]] + response: Optional[WebGoalsQueryResponse] = None + sampling: Optional[Sampling] = None + useSessionsTable: Optional[bool] = None + + class WebOverviewQuery(BaseModel): model_config = ConfigDict( extra="forbid", @@ -3982,7 +4144,7 @@ class PropertyGroupFilterValue(BaseModel): ] -class QueryResponseAlternative24(BaseModel): +class QueryResponseAlternative26(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -4599,7 +4761,7 @@ class LifecycleQuery(BaseModel): ) -class QueryResponseAlternative29(BaseModel): +class QueryResponseAlternative31(BaseModel): model_config = ConfigDict( extra="forbid", ) @@ -4631,8 +4793,8 @@ class QueryResponseAlternative( QueryResponseAlternative11, QueryResponseAlternative12, QueryResponseAlternative13, - Any, QueryResponseAlternative14, + Any, QueryResponseAlternative15, QueryResponseAlternative16, QueryResponseAlternative17, @@ -4644,8 +4806,10 @@ class QueryResponseAlternative( QueryResponseAlternative23, QueryResponseAlternative24, QueryResponseAlternative25, - QueryResponseAlternative28, - QueryResponseAlternative29, + QueryResponseAlternative26, + QueryResponseAlternative27, + QueryResponseAlternative30, + QueryResponseAlternative31, ] ] ): @@ -4664,8 +4828,8 @@ class QueryResponseAlternative( QueryResponseAlternative11, QueryResponseAlternative12, QueryResponseAlternative13, - Any, QueryResponseAlternative14, + Any, QueryResponseAlternative15, QueryResponseAlternative16, QueryResponseAlternative17, @@ -4677,8 +4841,10 @@ class QueryResponseAlternative( QueryResponseAlternative23, QueryResponseAlternative24, QueryResponseAlternative25, - QueryResponseAlternative28, - QueryResponseAlternative29, + QueryResponseAlternative26, + QueryResponseAlternative27, + QueryResponseAlternative30, + QueryResponseAlternative31, ] @@ -4957,7 +5123,18 @@ class DataTableNode(BaseModel): kind: Literal["DataTableNode"] = "DataTableNode" propertiesViaUrl: Optional[bool] = Field(default=None, description="Link properties via the URL (default: false)") response: Optional[ - Union[dict[str, Any], Response, Response1, Response2, Response3, Response4, Response5, Response6, Response7] + Union[ + dict[str, Any], + Response, + Response1, + Response2, + Response3, + Response4, + Response5, + Response6, + Response7, + Response8, + ] ] = None showActions: Optional[bool] = Field(default=None, description="Show the kebab menu at the end of the row") showColumnConfigurator: Optional[bool] = Field( @@ -4994,6 +5171,7 @@ class DataTableNode(BaseModel): WebOverviewQuery, WebStatsTableQuery, WebTopClicksQuery, + WebGoalsQuery, SessionAttributionExplorerQuery, ErrorTrackingQuery, ] = Field(..., description="Source of the events") @@ -5030,6 +5208,7 @@ class HogQLAutocomplete(BaseModel): WebOverviewQuery, WebStatsTableQuery, WebTopClicksQuery, + WebGoalsQuery, SessionAttributionExplorerQuery, ErrorTrackingQuery, ] @@ -5070,6 +5249,7 @@ class HogQLMetadata(BaseModel): WebOverviewQuery, WebStatsTableQuery, WebTopClicksQuery, + WebGoalsQuery, SessionAttributionExplorerQuery, ErrorTrackingQuery, ] @@ -5112,6 +5292,7 @@ class QueryRequest(BaseModel): WebOverviewQuery, WebStatsTableQuery, WebTopClicksQuery, + WebGoalsQuery, SessionAttributionExplorerQuery, ErrorTrackingQuery, DataVisualizationNode, @@ -5158,6 +5339,7 @@ class QuerySchemaRoot( WebOverviewQuery, WebStatsTableQuery, WebTopClicksQuery, + WebGoalsQuery, SessionAttributionExplorerQuery, ErrorTrackingQuery, DataVisualizationNode, @@ -5192,6 +5374,7 @@ class QuerySchemaRoot( WebOverviewQuery, WebStatsTableQuery, WebTopClicksQuery, + WebGoalsQuery, SessionAttributionExplorerQuery, ErrorTrackingQuery, DataVisualizationNode,