Skip to content

Commit

Permalink
feat(hogql): Allow lazy joins on lazy tables with requested fields (#…
Browse files Browse the repository at this point in the history
…20731)

* WIP

* Clean up and tests

* Updated mypy

* Updated lazy tables to work without resolving types twice

* Update UI snapshots for `chromium` (2)

* Update query snapshots

* Update UI snapshots for `chromium` (2)

* Update query snapshots

* Update UI snapshots for `chromium` (2)

* Updated mypy

* Fixed cohort people and joining multiple lazy tables

* Fixed infinite recursion

* Dont use an extra column for hogql expressions

* Update query snapshots

* Update UI snapshots for `chromium` (2)

* Update UI snapshots for `webkit` (2)

* Update UI snapshots for `webkit` (2)

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
Gilbert09 and github-actions[bot] authored Mar 8, 2024
1 parent 6d1eb0f commit 4a60cad
Show file tree
Hide file tree
Showing 32 changed files with 710 additions and 254 deletions.
2 changes: 1 addition & 1 deletion cypress/e2e/auth.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('Auth', () => {
cy.visit('/signup')
cy.location('pathname').should('eq', '/project/1')
})

it('Logout in another tab results in logout in the current tab too', () => {
cy.window().then(async (win) => {
// Hit /logout *in the background* by using fetch()
Expand Down
6 changes: 3 additions & 3 deletions cypress/productAnalytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,14 @@ export const dashboard = {
cy.get('[data-attr="prop-val-0"]').click({ force: true })
cy.get('.PropertyFilterButton').should('have.length', 1)
},
addPropertyFilter(type: string = "Browser", value: string = "Chrome"): void {
addPropertyFilter(type: string = 'Browser', value: string = 'Chrome'): void {
cy.get('.PropertyFilterButton').should('have.length', 0)
cy.get('[data-attr="property-filter-0"]').click()
cy.get('[data-attr="taxonomic-filter-searchfield"]').click().type("Browser").wait(1000)
cy.get('[data-attr="taxonomic-filter-searchfield"]').click().type('Browser').wait(1000)
cy.get('[data-attr="prop-filter-event_properties-0"]').click({ force: true })
cy.get('.ant-select-selector').type(value)
cy.get('.ant-select-item-option-content').click({ force: true })
}
},
}

export function createInsight(insightName: string): void {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 96 additions & 14 deletions frontend/src/scenes/data-warehouse/ViewLinkModal.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import './ViewLinkModal.scss'

import { IconTrash } from '@posthog/icons'
import { LemonButton, LemonDivider, LemonInput, LemonModal, LemonSelect, LemonTag } from '@posthog/lemon-ui'
import {
LemonButton,
LemonDivider,
LemonDropdown,
LemonInput,
LemonModal,
LemonSelect,
LemonTag,
} from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { Field, Form } from 'kea-forms'
import { CodeSnippet, Language } from 'lib/components/CodeSnippet'
import { HogQLEditor } from 'lib/components/HogQLEditor/HogQLEditor'
import { IconSwapHoriz } from 'lib/lemon-ui/icons'
import { useState } from 'react'
import { viewLinkLogic } from 'scenes/data-warehouse/viewLinkLogic'

import { DatabaseSchemaQueryResponseField } from '~/queries/schema'
Expand Down Expand Up @@ -44,8 +54,19 @@ export function ViewLinkForm(): JSX.Element {
error,
fieldName,
isNewJoin,
selectedSourceKey,
selectedJoiningKey,
sourceIsUsingHogQLExpression,
joiningIsUsingHogQLExpression,
} = useValues(viewLinkLogic)
const { selectJoiningTable, toggleJoinTableModal, selectSourceTable, setFieldName } = useActions(viewLinkLogic)
const {
selectJoiningTable,
toggleJoinTableModal,
selectSourceTable,
setFieldName,
selectSourceKey,
selectJoiningKey,
} = useActions(viewLinkLogic)

return (
<Form logic={viewLinkLogic} formKey="viewLink" enableFormOnSubmit>
Expand Down Expand Up @@ -82,12 +103,22 @@ export function ViewLinkForm(): JSX.Element {
<div className="w-50">
<span className="l4">Source Table Key</span>
<Field name="source_table_key">
<LemonSelect
fullWidth
disabledReason={selectedSourceTableName ? '' : 'Select a table to choose join key'}
options={sourceTableKeys}
placeholder="Select a key"
/>
<>
<LemonSelect
fullWidth
onSelect={selectSourceKey}
value={sourceIsUsingHogQLExpression ? '' : selectedSourceKey ?? undefined}
disabledReason={selectedSourceTableName ? '' : 'Select a table to choose join key'}
options={[...sourceTableKeys, { value: '', label: <span>HogQL Expression</span> }]}
placeholder="Select a key"
/>
{sourceIsUsingHogQLExpression && (
<HogQLDropdown
hogQLValue={selectedSourceKey ?? ''}
onHogQLValueChange={selectSourceKey}
/>
)}
</>
</Field>
</div>
<div className="mt-5">
Expand All @@ -96,12 +127,22 @@ export function ViewLinkForm(): JSX.Element {
<div className="w-50">
<span className="l4">Joining Table Key</span>
<Field name="joining_table_key">
<LemonSelect
fullWidth
disabledReason={selectedJoiningTable ? '' : 'Select a table to choose join key'}
options={joiningTableKeys}
placeholder="Select a key"
/>
<>
<LemonSelect
fullWidth
onSelect={selectJoiningKey}
value={joiningIsUsingHogQLExpression ? '' : selectedJoiningKey ?? undefined}
disabledReason={selectedJoiningTable ? '' : 'Select a table to choose join key'}
options={[...joiningTableKeys, { value: '', label: <span>HogQL Expression</span> }]}
placeholder="Select a key"
/>
{joiningIsUsingHogQLExpression && (
<HogQLDropdown
hogQLValue={selectedJoiningKey ?? ''}
onHogQLValueChange={selectJoiningKey}
/>
)}
</>
</Field>
</div>
</div>
Expand Down Expand Up @@ -151,6 +192,47 @@ export function ViewLinkForm(): JSX.Element {
)
}

const HogQLDropdown = ({
hogQLValue,
onHogQLValueChange,
}: {
hogQLValue: string
onHogQLValueChange: (hogQLValue: string) => void
}): JSX.Element => {
const [isHogQLDropdownVisible, setIsHogQLDropdownVisible] = useState(false)

return (
<div className="flex-auto overflow-hidden">
<LemonDropdown
visible={isHogQLDropdownVisible}
closeOnClickInside={false}
onClickOutside={() => setIsHogQLDropdownVisible(false)}
overlay={
// eslint-disable-next-line react/forbid-dom-props
<div className="w-120" style={{ maxWidth: 'max(60vw, 20rem)' }}>
<HogQLEditor
disablePersonProperties
value={hogQLValue}
onChange={(currentValue) => {
onHogQLValueChange(currentValue)
setIsHogQLDropdownVisible(false)
}}
/>
</div>
}
>
<LemonButton
fullWidth
type="secondary"
onClick={() => setIsHogQLDropdownVisible(!isHogQLDropdownVisible)}
>
<code>{hogQLValue}</code>
</LemonButton>
</LemonDropdown>
</div>
)
}

interface ViewLinkDeleteButtonProps {
table: string
column: string
Expand Down
77 changes: 44 additions & 33 deletions frontend/src/scenes/data-warehouse/viewLinkLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import { ViewLinkKeyLabel } from './ViewLinkModal'
const NEW_VIEW_LINK: DataWarehouseViewLink = {
id: 'new',
source_table_name: undefined,
source_table_key: undefined,
joining_table_name: undefined,
joining_table_key: undefined,
field_name: undefined,
}

Expand All @@ -37,9 +35,11 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
],
actions: [databaseTableListLogic, ['loadDatabase'], dataWarehouseJoinsLogic, ['loadJoins']],
}),
actions({
actions(({ values }) => ({
selectJoiningTable: (selectedTableName: string) => ({ selectedTableName }),
selectSourceTable: (selectedTableName: string) => ({ selectedTableName }),
selectSourceKey: (selectedKey: string) => ({ selectedKey, sourceTable: values.selectedSourceTable }),
selectJoiningKey: (selectedKey: string) => ({ selectedKey, joiningTable: values.selectedJoiningTable }),
toggleJoinTableModal: true,
toggleEditJoinModal: (join: DataWarehouseViewLink) => ({ join }),
toggleNewJoinModal: true,
Expand All @@ -48,7 +48,7 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
setError: (error: string) => ({ error }),
setFieldName: (fieldName: string) => ({ fieldName }),
clearModalFields: true,
}),
})),
reducers({
joinToEdit: [
null as DataWarehouseViewLink | null,
Expand Down Expand Up @@ -84,6 +84,20 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
clearModalFields: () => null,
},
],
selectedSourceKey: [
null as string | null,
{
selectSourceKey: (_, { selectedKey }) => selectedKey,
toggleEditJoinModal: (_, { join }) => join.source_table_key ?? null,
},
],
selectedJoiningKey: [
null as string | null,
{
selectJoiningKey: (_, { selectedKey }) => selectedKey,
toggleEditJoinModal: (_, { join }) => join.joining_table_key ?? null,
},
],
fieldName: [
'' as string,
{
Expand Down Expand Up @@ -112,44 +126,21 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
forms(({ actions, values }) => ({
viewLink: {
defaults: NEW_VIEW_LINK,
errors: ({ source_table_name, joining_table_name, joining_table_key, source_table_key }) => {
let joining_table_key_err: string | undefined = undefined
let source_table_key_err: string | undefined = undefined

if (!joining_table_key) {
joining_table_key_err = 'Must select a join key'
}

if (!source_table_key) {
source_table_key_err = 'Must select a join key'
}

if (
joining_table_key &&
source_table_key &&
values.selectedJoiningTable?.columns?.find((n) => n.key == joining_table_key)?.type !==
values.selectedSourceTable?.columns?.find((n) => n.key == source_table_key)?.type
) {
joining_table_key_err = 'Join key types must match'
source_table_key_err = 'Join key types must match'
}

errors: ({ source_table_name, joining_table_name }) => {
return {
source_table_name: values.isNewJoin && !source_table_name ? 'Must select a table' : undefined,
joining_table_name: !joining_table_name ? 'Must select a table' : undefined,
source_table_key: source_table_key_err,
joining_table_key: joining_table_key_err,
}
},
submit: async ({ joining_table_name, source_table_name, source_table_key, joining_table_key }) => {
submit: async ({ joining_table_name, source_table_name }) => {
if (values.joinToEdit?.id && values.selectedSourceTable) {
// Edit join
try {
await api.dataWarehouseViewLinks.update(values.joinToEdit.id, {
source_table_name: source_table_name ?? values.selectedSourceTable.name,
source_table_key,
source_table_key: values.selectedSourceKey ?? undefined,
joining_table_name,
joining_table_key,
joining_table_key: values.selectedJoiningKey ?? undefined,
field_name: values.fieldName,
})

Expand All @@ -164,9 +155,9 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
try {
await api.dataWarehouseViewLinks.create({
source_table_name: source_table_name ?? values.selectedSourceTable.name,
source_table_key,
source_table_key: values.selectedSourceKey ?? undefined,
joining_table_name,
joining_table_key,
joining_table_key: values.selectedJoiningKey ?? undefined,
field_name: values.fieldName,
})

Expand Down Expand Up @@ -222,6 +213,26 @@ export const viewLinkLogic = kea<viewLinkLogicType>([
(s) => [s.selectedJoiningTableName, s.tables],
(selectedJoiningTableName, tables) => tables.find((row) => row.name === selectedJoiningTableName),
],
sourceIsUsingHogQLExpression: [
(s) => [s.selectedSourceKey, s.selectedSourceTable],
(sourceKey, sourceTable) => {
if (sourceKey === null) {
return false
}
const column = sourceTable?.columns.find((n) => n.key == sourceKey)
return !column
},
],
joiningIsUsingHogQLExpression: [
(s) => [s.selectedJoiningKey, s.selectedJoiningTable],
(joiningKey, joiningTable) => {
if (joiningKey === null) {
return false
}
const column = joiningTable?.columns.find((n) => n.key == joiningKey)
return !column
},
],
tableOptions: [
(s) => [s.tables],
(tables) =>
Expand Down
Loading

0 comments on commit 4a60cad

Please sign in to comment.