From 7244ee2db4fc3291aaa0bfeaa4e2beed39ba584b Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 26 Mar 2024 14:42:15 -0400 Subject: [PATCH 1/9] make separate property type in popup --- .../components/TaxonomicPropertyFilter.tsx | 4 +- .../taxonomicPropertyFilterLogic.ts | 12 +++-- .../lib/components/PropertyFilters/utils.ts | 4 ++ .../TaxonomicFilter/InfiniteList.tsx | 4 +- .../TaxonomicFilter/taxonomicFilterLogic.tsx | 13 ++++++ .../lib/components/TaxonomicFilter/types.ts | 1 + .../nodes/InsightViz/GlobalAndOrFilters.tsx | 1 + frontend/src/queries/schema.json | 3 ++ .../external/dataWarehouseJoinsLogic.ts | 44 ++++++++++++++++++- frontend/src/types.ts | 4 ++ plugin-server/src/types.ts | 1 + posthog/hogql/property.py | 5 ++- posthog/models/property/property.py | 3 ++ posthog/schema.py | 1 + 14 files changed, 88 insertions(+), 12 deletions(-) diff --git a/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx b/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx index d416c1e0502c3..acfcb0c8d7566 100644 --- a/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx +++ b/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx @@ -9,6 +9,7 @@ import { propertyFilterLogic } from 'lib/components/PropertyFilters/propertyFilt import { PropertyFilterInternalProps } from 'lib/components/PropertyFilters/types' import { isGroupPropertyFilter, + isPersonPropertyFilter, isPropertyFilterWithOperator, PROPERTY_FILTER_TYPE_TO_TAXONOMIC_FILTER_GROUP_TYPE, propertyFilterTypeToTaxonomicFilterType, @@ -63,7 +64,7 @@ export function TaxonomicPropertyFilter({ value, item ) => { - selectItem(taxonomicGroup, value, item?.propertyFilterType) + selectItem(taxonomicGroup, value, item) if ( taxonomicGroup.type === TaxonomicFilterGroupType.Cohorts || taxonomicGroup.type === TaxonomicFilterGroupType.HogQLExpression @@ -217,6 +218,7 @@ export function TaxonomicPropertyFilter({ ...(isGroupPropertyFilter(filter) ? { group_type_index: filter.group_type_index } : {}), + ...(isPersonPropertyFilter(filter) ? { table: filter?.table } : {}), } as AnyPropertyFilter) } if ( diff --git a/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts b/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts index aa1a1ca685cc7..283e74a76b223 100644 --- a/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts @@ -51,14 +51,10 @@ export const taxonomicPropertyFilterLogic = kea ({ + selectItem: (taxonomicGroup: TaxonomicFilterGroup, propertyKey?: TaxonomicFilterValue, item?: any) => ({ taxonomicGroup, propertyKey, - itemPropertyFilterType, + item, }), openDropdown: true, closeDropdown: true, @@ -93,7 +89,8 @@ export const taxonomicPropertyFilterLogic = kea ({ - selectItem: ({ taxonomicGroup, propertyKey, itemPropertyFilterType }) => { + selectItem: ({ taxonomicGroup, propertyKey, item }) => { + const itemPropertyFilterType = item?.propertyFilterType as PropertyFilterType const propertyType = itemPropertyFilterType ?? taxonomicFilterTypeToPropertyFilterType(taxonomicGroup.type) if (propertyKey && propertyType) { if (propertyType === PropertyFilterType.Cohort) { @@ -142,6 +139,7 @@ export const taxonomicPropertyFilterLogic = kea v === filterType)?.[0] as | PropertyFilterType | undefined diff --git a/frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx b/frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx index 8e0237d36f252..ab03c6f9721c0 100644 --- a/frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx +++ b/frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx @@ -222,7 +222,9 @@ export function InfiniteList({ popupAnchorElement }: InfiniteListProps): JSX.Ele
canSelectItem(listGroupType) && selectItem(group, itemValue ?? null, item)} + onClick={() => { + return canSelectItem(listGroupType) && selectItem(group, itemValue ?? null, item) + }} > {renderItemContents({ item, diff --git a/frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.tsx b/frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.tsx index cc3e727f7b10d..966b33c5527ed 100644 --- a/frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.tsx +++ b/frontend/src/lib/components/TaxonomicFilter/taxonomicFilterLogic.tsx @@ -15,6 +15,7 @@ import { IconCohort } from 'lib/lemon-ui/icons' import { CORE_FILTER_DEFINITIONS_BY_GROUP } from 'lib/taxonomy' import { capitalizeFirstLetter, pluralize, toParams } from 'lib/utils' import { getEventDefinitionIcon, getPropertyDefinitionIcon } from 'scenes/data-management/events/DefinitionHeader' +import { dataWarehouseJoinsLogic } from 'scenes/data-warehouse/external/dataWarehouseJoinsLogic' import { dataWarehouseSceneLogic } from 'scenes/data-warehouse/external/dataWarehouseSceneLogic' import { DataWarehouseTableType } from 'scenes/data-warehouse/types' import { experimentsLogic } from 'scenes/experiments/experimentsLogic' @@ -86,6 +87,8 @@ export const taxonomicFilterLogic = kea([ ['allGroupProperties'], dataWarehouseSceneLogic, ['externalTables'], + dataWarehouseJoinsLogic, + ['columnsJoinedToPersons'], ], }), actions(() => ({ @@ -225,6 +228,16 @@ export const taxonomicFilterLogic = kea([ getPopoverHeader: () => 'Data Warehouse Column', getIcon: () => , }, + { + name: 'Data Warehouse Person Properties', + searchPlaceholder: 'person properties from data warehouse tables', + type: TaxonomicFilterGroupType.DataWarehousePersonProperties, + logic: dataWarehouseJoinsLogic, + value: 'columnsJoinedToPersons', + getName: (personProperty: PersonProperty) => personProperty.name, + getValue: (personProperty: PersonProperty) => personProperty.id, + getPopoverHeader: () => 'Data Warehouse Person Property', + }, { name: 'Autocapture elements', searchPlaceholder: 'autocapture elements', diff --git a/frontend/src/lib/components/TaxonomicFilter/types.ts b/frontend/src/lib/components/TaxonomicFilter/types.ts index 964847c6eacaf..8b46784a19b7e 100644 --- a/frontend/src/lib/components/TaxonomicFilter/types.ts +++ b/frontend/src/lib/components/TaxonomicFilter/types.ts @@ -85,6 +85,7 @@ export enum TaxonomicFilterGroupType { CohortsWithAllUsers = 'cohorts_with_all', DataWarehouse = 'data_warehouse', DataWarehouseProperties = 'data_warehouse_properties', + DataWarehousePersonProperties = 'data_warehouse_person_properties', Elements = 'elements', Events = 'events', EventProperties = 'event_properties', diff --git a/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx b/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx index bd755cb3bd5e7..91f0a1924ec3c 100644 --- a/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx +++ b/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx @@ -26,6 +26,7 @@ export function GlobalAndOrFilters({ insightProps }: EditorFilterProps): JSX.Ele TaxonomicFilterGroupType.Elements, ...(isTrends ? [TaxonomicFilterGroupType.Sessions] : []), TaxonomicFilterGroupType.HogQLExpression, + TaxonomicFilterGroupType.DataWarehousePersonProperties, ] return ( diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index eeac4bb951269..bb6e2256a43c8 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -3460,6 +3460,9 @@ "operator": { "$ref": "#/definitions/PropertyOperator" }, + "table": { + "type": "string" + }, "type": { "const": "person", "description": "Person properties", diff --git a/frontend/src/scenes/data-warehouse/external/dataWarehouseJoinsLogic.ts b/frontend/src/scenes/data-warehouse/external/dataWarehouseJoinsLogic.ts index b5f493b2d7f17..377049900b37c 100644 --- a/frontend/src/scenes/data-warehouse/external/dataWarehouseJoinsLogic.ts +++ b/frontend/src/scenes/data-warehouse/external/dataWarehouseJoinsLogic.ts @@ -1,10 +1,13 @@ -import { afterMount, kea, path } from 'kea' +import { afterMount, connect, kea, path, selectors } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' +import { capitalizeFirstLetter } from 'lib/utils' -import { DataWarehouseViewLink } from '~/types' +import { DatabaseSchemaQueryResponseField } from '~/queries/schema' +import { DataWarehouseViewLink, PropertyDefinition, PropertyType } from '~/types' import type { dataWarehouseJoinsLogicType } from './dataWarehouseJoinsLogicType' +import { dataWarehouseSceneLogic } from './dataWarehouseSceneLogic' export const dataWarehouseJoinsLogic = kea([ path(['scenes', 'data-warehouse', 'external', 'dataWarehouseJoinsLogic']), @@ -19,6 +22,43 @@ export const dataWarehouseJoinsLogic = kea([ }, ], }), + connect(() => ({ + values: [dataWarehouseSceneLogic, ['externalTablesMap']], + })), + selectors({ + personTableJoins: [(s) => [s.joins], (joins) => joins.filter((join) => join.source_table_name === 'persons')], + tablesJoinedToPersons: [ + (s) => [s.externalTablesMap, s.personTableJoins], + (externalTablesMap, personTableJoins) => { + return personTableJoins.map((join: DataWarehouseViewLink) => { + // valid join should have a joining table name + const table = externalTablesMap[join.joining_table_name as string] + return { + table, + join, + } + }) + }, + ], + columnsJoinedToPersons: [ + (s) => [s.tablesJoinedToPersons], + (tablesJoinedToPersons) => { + return tablesJoinedToPersons.reduce((acc, { table, join }) => { + if (table) { + acc.push( + ...table.columns.map((column: DatabaseSchemaQueryResponseField) => ({ + id: column.key, + name: join.field_name + ': ' + column.key, + table: join.field_name, + property_type: capitalizeFirstLetter(column.type) as PropertyType, + })) + ) + } + return acc + }, [] as PropertyDefinition[]) + }, + ], + }), afterMount(({ actions }) => { actions.loadJoins() }), diff --git a/frontend/src/types.ts b/frontend/src/types.ts index a583fe34c26d2..c34634faf691f 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -672,6 +672,7 @@ export interface EventPropertyFilter extends BasePropertyFilter { export interface PersonPropertyFilter extends BasePropertyFilter { type: PropertyFilterType.Person operator: PropertyOperator + table?: string } export interface DataWarehousePropertyFilter extends BasePropertyFilter { @@ -2812,6 +2813,9 @@ export interface PropertyDefinition { verified?: boolean verified_at?: string verified_by?: string + + // For Data warehouse person properties + table?: string } export enum PropertyDefinitionState { diff --git a/plugin-server/src/types.ts b/plugin-server/src/types.ts index d70238307eaac..114547cfe605f 100644 --- a/plugin-server/src/types.ts +++ b/plugin-server/src/types.ts @@ -868,6 +868,7 @@ export interface EventPropertyFilter extends PropertyFilterWithOperator { /** Sync with posthog/frontend/src/types.ts */ export interface PersonPropertyFilter extends PropertyFilterWithOperator { type: 'person' + table?: string } /** Sync with posthog/frontend/src/types.ts */ diff --git a/posthog/hogql/property.py b/posthog/hogql/property.py index 98019cdaa54b7..ba9f92443b4e8 100644 --- a/posthog/hogql/property.py +++ b/posthog/hogql/property.py @@ -147,7 +147,10 @@ def property_to_expr( value = property.value if property.type == "person" and scope != "person": - chain = ["person", "properties"] + if property.table: + chain = ["person", property.table] + else: + chain = ["person", "properties"] elif property.type == "group": chain = [f"group_{property.group_type_index}", "properties"] elif property.type == "data_warehouse": diff --git a/posthog/models/property/property.py b/posthog/models/property/property.py index d0e0f94439cf5..4bd44646ec4a9 100644 --- a/posthog/models/property/property.py +++ b/posthog/models/property/property.py @@ -202,6 +202,7 @@ class Property: total_periods: Optional[int] min_periods: Optional[int] negation: Optional[bool] = False + table: Optional[str] _data: Dict def __init__( @@ -224,6 +225,7 @@ def __init__( seq_time_value: Optional[int] = None, seq_time_interval: Optional[OperatorInterval] = None, negation: Optional[bool] = None, + table: Optional[str] = None, **kwargs, ) -> None: self.key = key @@ -241,6 +243,7 @@ def __init__( self.seq_time_value = seq_time_value self.seq_time_interval = seq_time_interval self.negation = None if negation is None else str_to_bool(negation) + self.table = table if value is None and self.operator in ["is_set", "is_not_set"]: self.value = self.operator diff --git a/posthog/schema.py b/posthog/schema.py index 17ad11fc4f236..7068c39090a2f 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -1369,6 +1369,7 @@ class PersonPropertyFilter(BaseModel): key: str label: Optional[str] = None operator: PropertyOperator + table: Optional[str] = None type: Literal["person"] = Field(default="person", description="Person properties") value: Optional[Union[str, float, List[Union[str, float]]]] = None From 18f3d48f9cdc4d7a5154a7851a7f3d5165c55d7b Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 26 Mar 2024 14:49:21 -0400 Subject: [PATCH 2/9] add flag --- frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx | 5 ++++- frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx b/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx index 91f0a1924ec3c..1767209b1d3bc 100644 --- a/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx +++ b/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx @@ -1,5 +1,7 @@ import { useActions, useValues } from 'kea' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' +import { FEATURE_FLAGS } from 'lib/constants' +import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { insightVizDataLogic } from 'scenes/insights/insightVizDataLogic' import { keyForInsightLogicProps } from 'scenes/insights/sharedUtils' @@ -16,6 +18,7 @@ export function GlobalAndOrFilters({ insightProps }: EditorFilterProps): JSX.Ele const { groupsTaxonomicTypes } = useValues(groupsModel) const { isTrends, querySource, isDataWarehouseSeries } = useValues(insightVizDataLogic(insightProps)) const { updateQuerySource } = useActions(insightVizDataLogic(insightProps)) + const { featureFlags } = useValues(featureFlagLogic) const taxonomicGroupTypes = [ TaxonomicFilterGroupType.EventProperties, @@ -26,7 +29,7 @@ export function GlobalAndOrFilters({ insightProps }: EditorFilterProps): JSX.Ele TaxonomicFilterGroupType.Elements, ...(isTrends ? [TaxonomicFilterGroupType.Sessions] : []), TaxonomicFilterGroupType.HogQLExpression, - TaxonomicFilterGroupType.DataWarehousePersonProperties, + ...(featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] ? [TaxonomicFilterGroupType.DataWarehousePersonProperties] : []), ] return ( diff --git a/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx b/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx index 4136358dac1dc..06280b5c07add 100644 --- a/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx +++ b/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx @@ -37,6 +37,7 @@ export function TrendsSeries(): JSX.Element | null { ...(isTrends ? [TaxonomicFilterGroupType.Sessions] : []), TaxonomicFilterGroupType.HogQLExpression, TaxonomicFilterGroupType.DataWarehouseProperties, + ...(featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] ? [TaxonomicFilterGroupType.DataWarehousePersonProperties] : []), ] if (!isInsightQueryNode(querySource)) { From d10c779820406efbdc2e731f6c5ec79df617881e Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 28 Mar 2024 13:08:09 -0400 Subject: [PATCH 3/9] change type --- frontend/src/lib/components/PropertyFilters/utils.ts | 2 +- frontend/src/types.ts | 1 + posthog/models/property/property.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/components/PropertyFilters/utils.ts b/frontend/src/lib/components/PropertyFilters/utils.ts index 25d71fb95ed52..ee44d0e6425b8 100644 --- a/frontend/src/lib/components/PropertyFilters/utils.ts +++ b/frontend/src/lib/components/PropertyFilters/utils.ts @@ -333,7 +333,7 @@ export function taxonomicFilterTypeToPropertyFilterType( } if (filterType == TaxonomicFilterGroupType.DataWarehousePersonProperties) { - return PropertyFilterType.Person + return PropertyFilterType.DataWarehousePersonProperty } return Object.entries(propertyFilterMapping).find(([, v]) => v === filterType)?.[0] as diff --git a/frontend/src/types.ts b/frontend/src/types.ts index c34634faf691f..36fb223d5d876 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -652,6 +652,7 @@ export enum PropertyFilterType { Group = 'group', HogQL = 'hogql', DataWarehouse = 'data_warehouse', + DataWarehousePersonProperty = 'data_warehouse_person_property', } /** Sync with plugin-server/src/types.ts */ diff --git a/posthog/models/property/property.py b/posthog/models/property/property.py index 4bd44646ec4a9..43c8c3b07d743 100644 --- a/posthog/models/property/property.py +++ b/posthog/models/property/property.py @@ -42,6 +42,7 @@ class BehavioralPropertyType(str, Enum): "session", "hogql", "data_warehouse", + "data_warehouse_person_property", ] PropertyName = str From a5fe496c27052fc648e5a6950a35a3f013c0cebd Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 28 Mar 2024 14:35:02 -0400 Subject: [PATCH 4/9] use separate filter type --- .../taxonomicPropertyFilterLogic.ts | 1 - frontend/src/queries/schema.json | 32 ++++++++++++-- .../external/dataWarehouseJoinsLogic.ts | 2 +- frontend/src/types.ts | 10 +++-- posthog/hogql/property.py | 10 ++--- posthog/schema.py | 43 ++++++++++++++++++- 6 files changed, 82 insertions(+), 16 deletions(-) diff --git a/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts b/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts index 283e74a76b223..0b43ac9fe72d7 100644 --- a/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts @@ -139,7 +139,6 @@ export const taxonomicPropertyFilterLogic = kea([ if (table) { acc.push( ...table.columns.map((column: DatabaseSchemaQueryResponseField) => ({ - id: column.key, + id: join.field_name + ': ' + column.key, name: join.field_name + ': ' + column.key, table: join.field_name, property_type: capitalizeFirstLetter(column.type) as PropertyType, diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 36fb223d5d876..273953fad0a1f 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -673,7 +673,6 @@ export interface EventPropertyFilter extends BasePropertyFilter { export interface PersonPropertyFilter extends BasePropertyFilter { type: PropertyFilterType.Person operator: PropertyOperator - table?: string } export interface DataWarehousePropertyFilter extends BasePropertyFilter { @@ -681,6 +680,11 @@ export interface DataWarehousePropertyFilter extends BasePropertyFilter { operator: PropertyOperator } +export interface DataWarehousePersonPropertyFilter extends BasePropertyFilter { + type: PropertyFilterType.DataWarehousePersonProperty + operator: PropertyOperator +} + /** Sync with plugin-server/src/types.ts */ export interface ElementPropertyFilter extends BasePropertyFilter { type: PropertyFilterType.Element @@ -737,6 +741,7 @@ export type AnyPropertyFilter = | HogQLPropertyFilter | EmptyPropertyFilter | DataWarehousePropertyFilter + | DataWarehousePersonPropertyFilter export type AnyFilterLike = AnyPropertyFilter | PropertyGroupFilter | PropertyGroupFilterValue @@ -2814,9 +2819,6 @@ export interface PropertyDefinition { verified?: boolean verified_at?: string verified_by?: string - - // For Data warehouse person properties - table?: string } export enum PropertyDefinitionState { diff --git a/posthog/hogql/property.py b/posthog/hogql/property.py index ba9f92443b4e8..154b47e363269 100644 --- a/posthog/hogql/property.py +++ b/posthog/hogql/property.py @@ -138,6 +138,7 @@ def property_to_expr( or property.type == "person" or property.type == "group" or property.type == "data_warehouse" + or property.type == "data_warehouse_person_property" ): if scope == "person" and property.type != "person": raise NotImplementedException( @@ -145,12 +146,11 @@ def property_to_expr( ) operator = cast(Optional[PropertyOperator], property.operator) or PropertyOperator.exact value = property.value - if property.type == "person" and scope != "person": - if property.table: - chain = ["person", property.table] - else: - chain = ["person", "properties"] + chain = ["person", "properties"] + elif property.type == "data_warehouse_person_property": + table, value = property.value.split(": ") + chain = ["person", table] elif property.type == "group": chain = [f"group_{property.group_type_index}", "properties"] elif property.type == "data_warehouse": diff --git a/posthog/schema.py b/posthog/schema.py index 7068c39090a2f..3eb52d355d2d4 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -651,6 +651,7 @@ class PropertyFilterType(str, Enum): group = "group" hogql = "hogql" data_warehouse = "data_warehouse" + data_warehouse_person_property = "data_warehouse_person_property" class PropertyMathType(str, Enum): @@ -1131,6 +1132,17 @@ class ChartSettings(BaseModel): yAxis: Optional[List[ChartAxis]] = None +class DataWarehousePersonPropertyFilter(BaseModel): + model_config = ConfigDict( + extra="forbid", + ) + key: str + label: Optional[str] = None + operator: PropertyOperator + type: Literal["data_warehouse_person_property"] = "data_warehouse_person_property" + value: Optional[Union[str, float, List[Union[str, float]]]] = None + + class DataWarehousePropertyFilter(BaseModel): model_config = ConfigDict( extra="forbid", @@ -1369,7 +1381,6 @@ class PersonPropertyFilter(BaseModel): key: str label: Optional[str] = None operator: PropertyOperator - table: Optional[str] = None type: Literal["person"] = Field(default="person", description="Person properties") value: Optional[Union[str, float, List[Union[str, float]]]] = None @@ -1746,6 +1757,7 @@ class DashboardFilter(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = None @@ -1771,6 +1783,7 @@ class DataWarehouseNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field( @@ -1801,6 +1814,7 @@ class DataWarehouseNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field(default=None, description="Properties configurable in the interface") @@ -1838,6 +1852,7 @@ class EntityNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field( @@ -1866,6 +1881,7 @@ class EntityNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field(default=None, description="Properties configurable in the interface") @@ -1892,6 +1908,7 @@ class EventsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field( @@ -1922,6 +1939,7 @@ class EventsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field(default=None, description="Properties configurable in the interface") @@ -1951,6 +1969,7 @@ class EventsQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field( @@ -1976,6 +1995,7 @@ class EventsQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field(default=None, description="Properties configurable in the interface") @@ -2003,6 +2023,7 @@ class FunnelExclusionActionsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field( @@ -2034,6 +2055,7 @@ class FunnelExclusionActionsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field(default=None, description="Properties configurable in the interface") @@ -2060,6 +2082,7 @@ class FunnelExclusionEventsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field( @@ -2092,6 +2115,7 @@ class FunnelExclusionEventsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field(default=None, description="Properties configurable in the interface") @@ -2118,6 +2142,7 @@ class HogQLFilters(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = None @@ -2158,6 +2183,7 @@ class PersonsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field( @@ -2181,6 +2207,7 @@ class PersonsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field(default=None, description="Properties configurable in the interface") @@ -2208,6 +2235,7 @@ class PropertyGroupFilterValue(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ], ] ] @@ -2315,6 +2343,7 @@ class ActionsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field( @@ -2344,6 +2373,7 @@ class ActionsNode(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = Field(default=None, description="Properties configurable in the interface") @@ -2435,6 +2465,7 @@ class RetentionQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ], PropertyGroupFilter, @@ -2472,6 +2503,7 @@ class StickinessQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ], PropertyGroupFilter, @@ -2515,6 +2547,7 @@ class TrendsQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ], PropertyGroupFilter, @@ -2571,6 +2604,7 @@ class FilterType(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ], PropertyGroupFilter, @@ -2611,6 +2645,7 @@ class FunnelsQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ], PropertyGroupFilter, @@ -2647,6 +2682,7 @@ class InsightsQueryBase(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ], PropertyGroupFilter, @@ -2685,6 +2721,7 @@ class LifecycleQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ], PropertyGroupFilter, @@ -2730,6 +2767,7 @@ class PathsQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ], PropertyGroupFilter, @@ -2845,6 +2883,7 @@ class FunnelCorrelationActorsQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = None @@ -2881,6 +2920,7 @@ class ActorsQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = None @@ -2902,6 +2942,7 @@ class ActorsQuery(BaseModel): HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] ] ] = None From e9ccfe1f807dea0d8e3c8c9685f3d7f0580b5e6d Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 28 Mar 2024 14:41:53 -0400 Subject: [PATCH 5/9] add types --- .../components/TaxonomicPropertyFilter.tsx | 2 -- .../nodes/InsightViz/GlobalAndOrFilters.tsx | 4 +++- .../queries/nodes/InsightViz/TrendsSeries.tsx | 4 +++- plugin-server/src/types.ts | 17 +++++++++++++++-- posthog/models/property/property.py | 3 --- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx b/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx index acfcb0c8d7566..8121572020b4b 100644 --- a/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx +++ b/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx @@ -9,7 +9,6 @@ import { propertyFilterLogic } from 'lib/components/PropertyFilters/propertyFilt import { PropertyFilterInternalProps } from 'lib/components/PropertyFilters/types' import { isGroupPropertyFilter, - isPersonPropertyFilter, isPropertyFilterWithOperator, PROPERTY_FILTER_TYPE_TO_TAXONOMIC_FILTER_GROUP_TYPE, propertyFilterTypeToTaxonomicFilterType, @@ -218,7 +217,6 @@ export function TaxonomicPropertyFilter({ ...(isGroupPropertyFilter(filter) ? { group_type_index: filter.group_type_index } : {}), - ...(isPersonPropertyFilter(filter) ? { table: filter?.table } : {}), } as AnyPropertyFilter) } if ( diff --git a/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx b/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx index 1767209b1d3bc..8485b9a71ee84 100644 --- a/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx +++ b/frontend/src/queries/nodes/InsightViz/GlobalAndOrFilters.tsx @@ -29,7 +29,9 @@ export function GlobalAndOrFilters({ insightProps }: EditorFilterProps): JSX.Ele TaxonomicFilterGroupType.Elements, ...(isTrends ? [TaxonomicFilterGroupType.Sessions] : []), TaxonomicFilterGroupType.HogQLExpression, - ...(featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] ? [TaxonomicFilterGroupType.DataWarehousePersonProperties] : []), + ...(featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] && featureFlags[FEATURE_FLAGS.HOGQL_INSIGHTS] + ? [TaxonomicFilterGroupType.DataWarehousePersonProperties] + : []), ] return ( diff --git a/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx b/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx index 06280b5c07add..9ed56187b11a4 100644 --- a/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx +++ b/frontend/src/queries/nodes/InsightViz/TrendsSeries.tsx @@ -37,7 +37,9 @@ export function TrendsSeries(): JSX.Element | null { ...(isTrends ? [TaxonomicFilterGroupType.Sessions] : []), TaxonomicFilterGroupType.HogQLExpression, TaxonomicFilterGroupType.DataWarehouseProperties, - ...(featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] ? [TaxonomicFilterGroupType.DataWarehousePersonProperties] : []), + ...(featureFlags[FEATURE_FLAGS.DATA_WAREHOUSE] && featureFlags[FEATURE_FLAGS.HOGQL_INSIGHTS] + ? [TaxonomicFilterGroupType.DataWarehousePersonProperties] + : []), ] if (!isInsightQueryNode(querySource)) { diff --git a/plugin-server/src/types.ts b/plugin-server/src/types.ts index 114547cfe605f..225d24b68f81e 100644 --- a/plugin-server/src/types.ts +++ b/plugin-server/src/types.ts @@ -868,7 +868,14 @@ export interface EventPropertyFilter extends PropertyFilterWithOperator { /** Sync with posthog/frontend/src/types.ts */ export interface PersonPropertyFilter extends PropertyFilterWithOperator { type: 'person' - table?: string +} + +export interface DataWarehousePropertyFilter extends PropertyFilterWithOperator { + type: 'data_warehouse' +} + +export interface DataWarehousePersonPropertyFilter extends PropertyFilterWithOperator { + type: 'data_warehouse_person_property' } /** Sync with posthog/frontend/src/types.ts */ @@ -886,7 +893,13 @@ export interface CohortPropertyFilter extends PropertyFilterBase { } /** Sync with posthog/frontend/src/types.ts */ -export type PropertyFilter = EventPropertyFilter | PersonPropertyFilter | ElementPropertyFilter | CohortPropertyFilter +export type PropertyFilter = + | EventPropertyFilter + | PersonPropertyFilter + | ElementPropertyFilter + | CohortPropertyFilter + | DataWarehousePropertyFilter + | DataWarehousePersonPropertyFilter /** Sync with posthog/frontend/src/types.ts */ export enum StringMatching { diff --git a/posthog/models/property/property.py b/posthog/models/property/property.py index 43c8c3b07d743..cf5402f5afbdb 100644 --- a/posthog/models/property/property.py +++ b/posthog/models/property/property.py @@ -203,7 +203,6 @@ class Property: total_periods: Optional[int] min_periods: Optional[int] negation: Optional[bool] = False - table: Optional[str] _data: Dict def __init__( @@ -226,7 +225,6 @@ def __init__( seq_time_value: Optional[int] = None, seq_time_interval: Optional[OperatorInterval] = None, negation: Optional[bool] = None, - table: Optional[str] = None, **kwargs, ) -> None: self.key = key @@ -244,7 +242,6 @@ def __init__( self.seq_time_value = seq_time_value self.seq_time_interval = seq_time_interval self.negation = None if negation is None else str_to_bool(negation) - self.table = table if value is None and self.operator in ["is_set", "is_not_set"]: self.value = self.operator From 6e1d01bc5100611c9ba7b8fb9c207a7c6b45b9ed Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 28 Mar 2024 15:36:43 -0400 Subject: [PATCH 6/9] more types --- posthog/types.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/posthog/types.py b/posthog/types.py index 3b434f16417ac..466b537bdea6b 100644 --- a/posthog/types.py +++ b/posthog/types.py @@ -13,6 +13,7 @@ EventPropertyFilter, EventsNode, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, FeaturePropertyFilter, FunnelCorrelationActorsQuery, FunnelExclusionActionsNode, @@ -58,6 +59,7 @@ HogQLPropertyFilter, EmptyPropertyFilter, DataWarehousePropertyFilter, + DataWarehousePersonPropertyFilter, ] EntityNode: TypeAlias = Union[EventsNode, ActionsNode, DataWarehouseNode] From ee612ac05dece2c39b3562d62ba8cd2a9583f565 Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 28 Mar 2024 15:43:56 -0400 Subject: [PATCH 7/9] more typing --- posthog/hogql/property.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/posthog/hogql/property.py b/posthog/hogql/property.py index 84ff784cce39f..c56ca7fc3aef7 100644 --- a/posthog/hogql/property.py +++ b/posthog/hogql/property.py @@ -150,8 +150,11 @@ def property_to_expr( if property.type == "person" and scope != "person": chain = ["person", "properties"] elif property.type == "data_warehouse_person_property": - table, value = property.value.split(": ") - chain = ["person", table] + if isinstance(property.value, str): + table, value = property.value.split(": ") + chain = ["person", table] + else: + raise NotImplementedException("Data warehouse person property filter value must be a string") elif property.type == "group": chain = [f"group_{property.group_type_index}", "properties"] elif property.type == "data_warehouse": From 5537fe7b8c5bec3238013591dd3509337ca9f7be Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 28 Mar 2024 15:52:02 -0400 Subject: [PATCH 8/9] more types --- frontend/src/lib/components/PropertyFilters/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/lib/components/PropertyFilters/utils.ts b/frontend/src/lib/components/PropertyFilters/utils.ts index ee44d0e6425b8..255c8428ba8ba 100644 --- a/frontend/src/lib/components/PropertyFilters/utils.ts +++ b/frontend/src/lib/components/PropertyFilters/utils.ts @@ -101,6 +101,7 @@ export const PROPERTY_FILTER_TYPE_TO_TAXONOMIC_FILTER_GROUP_TYPE: Omit< [PropertyFilterType.HogQL]: TaxonomicFilterGroupType.HogQLExpression, [PropertyFilterType.Group]: TaxonomicFilterGroupType.GroupsPrefix, [PropertyFilterType.DataWarehouse]: TaxonomicFilterGroupType.DataWarehouse, + [PropertyFilterType.DataWarehousePersonProperty]: TaxonomicFilterGroupType.DataWarehousePersonProperties, } export function formatPropertyLabel( From 9dc5f30a8da6fa5b9296ced13ed1131a363a75e8 Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 28 Mar 2024 16:15:08 -0400 Subject: [PATCH 9/9] restore --- .../components/TaxonomicPropertyFilter.tsx | 2 +- .../components/taxonomicPropertyFilterLogic.ts | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx b/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx index 8121572020b4b..d416c1e0502c3 100644 --- a/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx +++ b/frontend/src/lib/components/PropertyFilters/components/TaxonomicPropertyFilter.tsx @@ -63,7 +63,7 @@ export function TaxonomicPropertyFilter({ value, item ) => { - selectItem(taxonomicGroup, value, item) + selectItem(taxonomicGroup, value, item?.propertyFilterType) if ( taxonomicGroup.type === TaxonomicFilterGroupType.Cohorts || taxonomicGroup.type === TaxonomicFilterGroupType.HogQLExpression diff --git a/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts b/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts index 0b43ac9fe72d7..aa1a1ca685cc7 100644 --- a/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts @@ -51,10 +51,14 @@ export const taxonomicPropertyFilterLogic = kea ({ + selectItem: ( + taxonomicGroup: TaxonomicFilterGroup, + propertyKey?: TaxonomicFilterValue, + itemPropertyFilterType?: PropertyFilterType + ) => ({ taxonomicGroup, propertyKey, - item, + itemPropertyFilterType, }), openDropdown: true, closeDropdown: true, @@ -89,8 +93,7 @@ export const taxonomicPropertyFilterLogic = kea ({ - selectItem: ({ taxonomicGroup, propertyKey, item }) => { - const itemPropertyFilterType = item?.propertyFilterType as PropertyFilterType + selectItem: ({ taxonomicGroup, propertyKey, itemPropertyFilterType }) => { const propertyType = itemPropertyFilterType ?? taxonomicFilterTypeToPropertyFilterType(taxonomicGroup.type) if (propertyKey && propertyType) { if (propertyType === PropertyFilterType.Cohort) {