Skip to content

Commit

Permalink
feat(insights): edit as sql (PostHog#18055)
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusandra authored and Justicea83 committed Oct 25, 2023
1 parent e77037b commit 3f9638b
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 63 deletions.
141 changes: 82 additions & 59 deletions frontend/src/scenes/insights/InsightPageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { AddToDashboardModal } from 'lib/components/AddToDashboard/AddToDashboar
import { useState } from 'react'
import { NewDashboardModal } from 'scenes/dashboard/NewDashboardModal'
import { NotebookSelectButton } from 'scenes/notebooks/NotebookSelectButton/NotebookSelectButton'
import { NodeKind } from '~/queries/schema'
import { DataTableNode, NodeKind } from '~/queries/schema'

export function InsightPageHeader({ insightLogicProps }: { insightLogicProps: InsightLogicProps }): JSX.Element {
// insightSceneLogic
Expand All @@ -67,7 +67,7 @@ export function InsightPageHeader({ insightLogicProps }: { insightLogicProps: In
const { duplicateInsight, loadInsights } = useActions(savedInsightsLogic)

// insightDataLogic
const { query, queryChanged, showQueryEditor } = useValues(insightDataLogic(insightProps))
const { query, queryChanged, showQueryEditor, hogQL } = useValues(insightDataLogic(insightProps))
const { saveInsight: saveQueryBasedInsight, toggleQueryEditorPanel } = useActions(insightDataLogic(insightProps))

// other logics
Expand Down Expand Up @@ -137,10 +137,10 @@ export function InsightPageHeader({ insightLogicProps }: { insightLogicProps: In
}
buttons={
<div className="flex justify-between items-center gap-2">
{hasDashboardItemId && (
<>
<More
overlay={
<More
overlay={
<>
{hasDashboardItemId && (
<>
<LemonButton
status="stealth"
Expand Down Expand Up @@ -181,55 +181,78 @@ export function InsightPageHeader({ insightLogicProps }: { insightLogicProps: In
>
Share or embed
</LemonButton>
{insight.short_id && (
<>
<SubscribeButton insightShortId={insight.short_id} />
{exporterResourceParams ? (
<ExportButton
fullWidth
items={[
{
export_format: ExporterFormat.PNG,
insight: insight.id,
},
{
export_format: ExporterFormat.CSV,
export_context: exporterResourceParams,
},
]}
/>
) : null}
{isInsightVizNode(query) ? (
<LemonButton
data-attr={`${
showQueryEditor ? 'hide' : 'show'
}-insight-source`}
status="stealth"
onClick={() => {
// for an existing insight in view mode
if (
hasDashboardItemId &&
insightMode !== ItemMode.Edit
) {
// enter edit mode
setInsightMode(ItemMode.Edit, null)

// exit early if query editor doesn't need to be toggled
if (showQueryEditor !== false) {
return
}
}
toggleQueryEditorPanel()
}}
fullWidth
>
{showQueryEditor ? 'Hide source' : 'View source'}
</LemonButton>
) : null}
<LemonDivider />
</>
)}
</>
)}
{insight.short_id && (
<>
<SubscribeButton insightShortId={insight.short_id} />
{exporterResourceParams ? (
<ExportButton
fullWidth
items={[
{
export_format: ExporterFormat.PNG,
insight: insight.id,
},
{
export_format: ExporterFormat.CSV,
export_context: exporterResourceParams,
},
]}
/>
) : null}
</>
)}
{isInsightVizNode(query) ? (
<LemonButton
data-attr={`${showQueryEditor ? 'hide' : 'show'}-insight-source`}
status="stealth"
onClick={() => {
// for an existing insight in view mode
if (hasDashboardItemId && insightMode !== ItemMode.Edit) {
// enter edit mode
setInsightMode(ItemMode.Edit, null)

// exit early if query editor doesn't need to be toggled
if (showQueryEditor !== false) {
return
}
}
toggleQueryEditorPanel()
}}
fullWidth
>
{showQueryEditor ? 'Hide source' : 'View source'}
</LemonButton>
) : null}
{hogQL && (
<LemonButton
data-attr={`edit-insight-sql`}
status="stealth"
onClick={() => {
router.actions.push(
urls.insightNew(
undefined,
undefined,
JSON.stringify({
kind: NodeKind.DataTableNode,
source: {
kind: NodeKind.HogQLQuery,
query: hogQL,
},
full: true,
} as DataTableNode)
)
)
}}
fullWidth
>
Edit SQL directly
</LemonButton>
)}
{hasDashboardItemId && (
<>
<LemonDivider />
<LemonButton
status="danger"
onClick={() =>
Expand All @@ -247,11 +270,11 @@ export function InsightPageHeader({ insightLogicProps }: { insightLogicProps: In
Delete insight
</LemonButton>
</>
}
/>
<LemonDivider vertical />
</>
)}
)}
</>
}
/>
<LemonDivider vertical />

{insightMode === ItemMode.Edit && hasDashboardItemId && (
<LemonButton type="secondary" onClick={() => setInsightMode(ItemMode.View, null)}>
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/scenes/insights/insightDataLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ export const insightDataLogic = kea<insightDataLogicType>([
return { ...insightDataRaw, result: insightDataRaw?.results ?? insightDataRaw?.result }
},
],

hogQL: [
(s) => [s.insightData],
(insightData): string | null => {
if (insightData && 'hogql' in insightData && insightData.hogql !== '') {
return insightData.hogql
}
return null
},
],
}),

listeners(({ actions, values }) => ({
Expand Down
9 changes: 8 additions & 1 deletion posthog/hogql/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from posthog.hogql.resolver import ResolverException, lookup_field_by_name, resolve_types
from posthog.hogql.transforms.lazy_tables import resolve_lazy_tables
from posthog.hogql.transforms.property_types import resolve_property_types
from posthog.hogql.visitor import Visitor
from posthog.hogql.visitor import Visitor, clone_expr
from posthog.models.property import PropertyName, TableColumn
from posthog.models.team.team import WeekStartDay
from posthog.models.utils import UUIDT
Expand All @@ -53,6 +53,13 @@ def team_id_guard_for_table(table_type: Union[ast.TableType, ast.TableAliasType]
)


def to_printed_hogql(query: ast.Expr, team_id: int) -> str:
"""Prints the HogQL query without mutating the node"""
return print_ast(
clone_expr(query), dialect="hogql", context=HogQLContext(team_id=team_id, enable_select_queries=True)
)


def print_ast(
node: ast.Expr,
context: HogQLContext,
Expand Down
7 changes: 6 additions & 1 deletion posthog/hogql/test/test_printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from posthog.hogql.errors import HogQLException
from posthog.hogql.hogql import translate_hogql
from posthog.hogql.parser import parse_select
from posthog.hogql.printer import print_ast
from posthog.hogql.printer import print_ast, to_printed_hogql
from posthog.models.team.team import WeekStartDay
from posthog.schema import HogQLQueryModifiers, PersonsArgMaxVersion
from posthog.test.base import BaseTest
Expand Down Expand Up @@ -50,6 +50,11 @@ def _assert_select_error(self, statement, expected_error):
raise AssertionError(f"Expected '{expected_error}' in '{str(context.exception)}'")
self.assertTrue(expected_error in str(context.exception))

def test_to_printed_hogql(self):
expr = parse_select("select 1 + 2, 3 from events")
repsponse = to_printed_hogql(expr, self.team.pk)
self.assertEqual(repsponse, "SELECT plus(1, 2), 3 FROM events LIMIT 10000")

def test_literals(self):
self.assertEqual(self._expr("1 + 2"), "plus(1, 2)")
self.assertEqual(self._expr("-1 + 2"), "plus(-1, 2)")
Expand Down
8 changes: 6 additions & 2 deletions posthog/hogql_queries/insights/lifecycle_query_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from posthog.hogql import ast
from posthog.hogql.parser import parse_expr, parse_select
from posthog.hogql.printer import to_printed_hogql
from posthog.hogql.property import property_to_expr, action_to_expr
from posthog.hogql.query import execute_hogql_query
from posthog.hogql.timings import HogQLTimings
Expand Down Expand Up @@ -92,9 +93,12 @@ def to_persons_query(self) -> ast.SelectQuery | ast.SelectUnionQuery:
)

def calculate(self):
query = self.to_query()
hogql = to_printed_hogql(query, self.team.pk)

response = execute_hogql_query(
query_type="LifecycleQuery",
query=self.to_query(),
query=query,
team=self.team,
timings=self.timings,
)
Expand Down Expand Up @@ -130,7 +134,7 @@ def calculate(self):
}
)

return LifecycleQueryResponse(results=res, timings=response.timings)
return LifecycleQueryResponse(results=res, timings=response.timings, hogql=hogql)

@cached_property
def query_date_range(self):
Expand Down

0 comments on commit 3f9638b

Please sign in to comment.