From 6076457b90920da3f179cdd29c47ba83b1b018ab Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Wed, 1 Mar 2023 15:45:00 +0100 Subject: [PATCH] fix(explore): Dashboard filters on adhoc cols not working in Explore (#23239) --- .../components/ControlPanelsContainer.tsx | 3 +- .../DndFilterSelect.test.tsx | 5 +- .../DndFilterSelect.tsx | 6 +- .../AdhocFilter/AdhocFilter.test.js | 6 +- .../FilterControl/AdhocFilter/index.js | 51 +------------ .../AdhocFilterControl.test.jsx | 6 +- .../AdhocFilterControl/index.jsx | 6 +- .../AdhocFilterEditPopover.test.jsx | 6 +- .../AdhocFilterEditPopover/index.jsx | 5 +- ...FilterEditPopoverSimpleTabContent.test.tsx | 6 +- .../index.tsx | 6 +- ...hocFilterEditPopoverSqlTabContent.test.jsx | 6 +- .../index.jsx | 6 +- .../AdhocFilterOption.test.tsx | 6 +- .../AdhocFilterPopoverTrigger.test.tsx | 6 +- .../controls/FilterControl/adhocFilterType.js | 2 +- .../controls/FilterControl/types.ts | 28 +++++++ .../FilterControl/utils/translateToSQL.ts | 76 +++++++++++++++++++ .../utils/useGetTimeRangeLabel.test.ts | 3 +- .../utils/useGetTimeRangeLabel.tsx | 3 +- .../getFormDataFromDashboardContext.test.ts | 36 +++++++++ .../getFormDataWithDashboardContext.ts | 56 ++++++++++---- superset-frontend/src/filters/utils.ts | 8 +- 23 files changed, 221 insertions(+), 121 deletions(-) create mode 100644 superset-frontend/src/explore/components/controls/FilterControl/types.ts create mode 100644 superset-frontend/src/explore/components/controls/FilterControl/utils/translateToSQL.ts diff --git a/superset-frontend/src/explore/components/ControlPanelsContainer.tsx b/superset-frontend/src/explore/components/ControlPanelsContainer.tsx index 60aac1948b..018f0b0ac3 100644 --- a/superset-frontend/src/explore/components/ControlPanelsContainer.tsx +++ b/superset-frontend/src/explore/components/ControlPanelsContainer.tsx @@ -70,6 +70,7 @@ import Control from './Control'; import { ExploreAlert } from './ExploreAlert'; import { RunQueryButton } from './RunQueryButton'; import { Operators } from '../constants'; +import { CLAUSES } from './controls/FilterControl/types'; const { confirm } = Modal; @@ -317,7 +318,7 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { setControlValue('adhoc_filters', [ ...(adhoc_filters || []), { - clause: 'WHERE', + clause: CLAUSES.WHERE, subject: x_axis, operator: Operators.TEMPORAL_RANGE, comparator: defaultTimeFilter || NO_TIME_RANGE, diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.test.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.test.tsx index b6f6c6fb9c..5bf79a3b83 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.test.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.test.tsx @@ -32,14 +32,13 @@ import { TimeseriesDefaultFormData } from '@superset-ui/plugin-chart-echarts'; import { render, screen } from 'spec/helpers/testing-library'; import AdhocMetric from 'src/explore/components/controls/MetricControl/AdhocMetric'; -import AdhocFilter, { - EXPRESSION_TYPES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import { DndFilterSelect, DndFilterSelectProps, } from 'src/explore/components/controls/DndColumnSelectControl/DndFilterSelect'; import { PLACEHOLDER_DATASOURCE } from 'src/dashboard/constants'; +import { EXPRESSION_TYPES } from '../FilterControl/types'; const defaultProps: DndFilterSelectProps = { type: 'DndFilterSelect', diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx index 134678aa6f..b7d5232c20 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx @@ -43,10 +43,7 @@ import { Datasource, OptionSortType } from 'src/explore/types'; import { OptionValueType } from 'src/explore/components/controls/DndColumnSelectControl/types'; import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger'; import DndSelectLabel from 'src/explore/components/controls/DndColumnSelectControl/DndSelectLabel'; -import AdhocFilter, { - CLAUSES, - EXPRESSION_TYPES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import AdhocMetric from 'src/explore/components/controls/MetricControl/AdhocMetric'; import { DatasourcePanelDndItem, @@ -58,6 +55,7 @@ import { ControlComponentProps } from 'src/explore/components/Control'; import AdhocFilterControl from '../FilterControl/AdhocFilterControl'; import DndAdhocFilterOption from './DndAdhocFilterOption'; import { useDefaultTimeFilter } from '../DateFilterControl/utils'; +import { CLAUSES, EXPRESSION_TYPES } from '../FilterControl/types'; const { warning } = Modal; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/AdhocFilter.test.js b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/AdhocFilter.test.js index f3e08d7a28..20f9576a47 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/AdhocFilter.test.js +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/AdhocFilter.test.js @@ -16,11 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import { Operators } from 'src/explore/constants'; +import { EXPRESSION_TYPES, CLAUSES } from '../types'; describe('AdhocFilter', () => { it('sets filterOptionName in constructor', () => { diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/index.js b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/index.js index 3b54a7dc1a..f00491b89f 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/index.js +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilter/index.js @@ -21,60 +21,13 @@ import { Operators, OPERATOR_ENUM_TO_OPERATOR_TYPE, } from 'src/explore/constants'; -import { getSimpleSQLExpression } from 'src/explore/exploreUtils'; - -export const EXPRESSION_TYPES = { - SIMPLE: 'SIMPLE', - SQL: 'SQL', -}; - -export const CLAUSES = { - HAVING: 'HAVING', - WHERE: 'WHERE', -}; - -const OPERATORS_TO_SQL = { - '==': '=', - '!=': '<>', - '>': '>', - '<': '<', - '>=': '>=', - '<=': '<=', - IN: 'IN', - 'NOT IN': 'NOT IN', - LIKE: 'LIKE', - ILIKE: 'ILIKE', - REGEX: 'REGEX', - 'IS NOT NULL': 'IS NOT NULL', - 'IS NULL': 'IS NULL', - 'IS TRUE': 'IS TRUE', - 'IS FALSE': 'IS FALSE', - 'LATEST PARTITION': ({ datasource }) => - `= '{{ presto.latest_partition('${datasource.schema}.${datasource.datasource_name}') }}'`, -}; +import { translateToSql } from '../utils/translateToSQL'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const CUSTOM_OPERATIONS = [...CUSTOM_OPERATORS].map( op => OPERATOR_ENUM_TO_OPERATOR_TYPE[op].operation, ); -function translateToSql(adhocMetric, { useSimple } = {}) { - if (adhocMetric.expressionType === EXPRESSION_TYPES.SIMPLE || useSimple) { - const { subject, comparator } = adhocMetric; - const operator = - adhocMetric.operator && - // 'LATEST PARTITION' supported callback only - adhocMetric.operator === - OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.LATEST_PARTITION].operation - ? OPERATORS_TO_SQL[adhocMetric.operator](adhocMetric) - : OPERATORS_TO_SQL[adhocMetric.operator]; - return getSimpleSQLExpression(subject, operator, comparator); - } - if (adhocMetric.expressionType === EXPRESSION_TYPES.SQL) { - return adhocMetric.sqlExpression; - } - return ''; -} - export default class AdhocFilter { constructor(adhocFilter) { this.expressionType = adhocFilter.expressionType || EXPRESSION_TYPES.SIMPLE; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/AdhocFilterControl.test.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/AdhocFilterControl.test.jsx index c7b13d55fa..964f0def00 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/AdhocFilterControl.test.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/AdhocFilterControl.test.jsx @@ -22,10 +22,7 @@ import sinon from 'sinon'; import { shallow } from 'enzyme'; import { supersetTheme } from '@superset-ui/core'; -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import { LabelsContainer } from 'src/explore/components/controls/OptionControls'; import { AGGREGATES, @@ -34,6 +31,7 @@ import { } from 'src/explore/constants'; import AdhocMetric from 'src/explore/components/controls/MetricControl/AdhocMetric'; import AdhocFilterControl from '.'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const simpleAdhocFilter = new AdhocFilter({ expressionType: EXPRESSION_TYPES.SIMPLE, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx index c0750c7805..c1a95bc8f2 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl/index.jsx @@ -45,12 +45,10 @@ import Icons from 'src/components/Icons'; import Modal from 'src/components/Modal'; import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger'; import AdhocFilterOption from 'src/explore/components/controls/FilterControl/AdhocFilterOption'; -import AdhocFilter, { - CLAUSES, - EXPRESSION_TYPES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import adhocFilterType from 'src/explore/components/controls/FilterControl/adhocFilterType'; import columnType from 'src/explore/components/controls/FilterControl/columnType'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const { warning } = Modal; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/AdhocFilterEditPopover.test.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/AdhocFilterEditPopover.test.jsx index 3fec073f94..d81abdc079 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/AdhocFilterEditPopover.test.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/AdhocFilterEditPopover.test.jsx @@ -24,15 +24,13 @@ import Button from 'src/components/Button'; import ErrorBoundary from 'src/components/ErrorBoundary'; import Tabs from 'src/components/Tabs'; -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import { AGGREGATES } from 'src/explore/constants'; import AdhocFilterEditPopoverSimpleTabContent from 'src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent'; import AdhocFilterEditPopoverSqlTabContent from 'src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent'; import AdhocMetric from 'src/explore/components/controls/MetricControl/AdhocMetric'; import AdhocFilterEditPopover from '.'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const simpleAdhocFilter = new AdhocFilter({ expressionType: EXPRESSION_TYPES.SIMPLE, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx index 98c6da8f1c..7820ceb9d4 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.jsx @@ -24,9 +24,7 @@ import { styled, t } from '@superset-ui/core'; import ErrorBoundary from 'src/components/ErrorBoundary'; import Tabs from 'src/components/Tabs'; import adhocMetricType from 'src/explore/components/controls/MetricControl/adhocMetricType'; -import AdhocFilter, { - EXPRESSION_TYPES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import AdhocFilterEditPopoverSimpleTabContent from 'src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent'; import AdhocFilterEditPopoverSqlTabContent from 'src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent'; import columnType from 'src/explore/components/controls/FilterControl/columnType'; @@ -34,6 +32,7 @@ import { POPOVER_INITIAL_HEIGHT, POPOVER_INITIAL_WIDTH, } from 'src/explore/constants'; +import { EXPRESSION_TYPES } from '../types'; const propTypes = { adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx index 9d1b68bc6f..9ad90167b5 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx @@ -25,10 +25,7 @@ import thunk from 'redux-thunk'; import { Provider } from 'react-redux'; import configureStore from 'redux-mock-store'; -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import { AGGREGATES, Operators, @@ -46,6 +43,7 @@ import AdhocFilterEditPopoverSimpleTabContent, { useSimpleTabFilterProps, Props, } from '.'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const simpleAdhocFilter = new AdhocFilter({ expressionType: EXPRESSION_TYPES.SIMPLE, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx index f0b05d8f1f..84feb448f6 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx @@ -38,10 +38,7 @@ import { OPERATOR_ENUM_TO_OPERATOR_TYPE, } from 'src/explore/constants'; import FilterDefinitionOption from 'src/explore/components/controls/MetricControl/FilterDefinitionOption'; -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import { Tooltip } from 'src/components/Tooltip'; import { Input } from 'src/components/Input'; import { optionLabel } from 'src/utils/common'; @@ -54,6 +51,7 @@ import { import useAdvancedDataTypes from './useAdvancedDataTypes'; import { useDatePickerInAdhocFilter } from '../utils'; import { useDefaultTimeFilter } from '../../DateFilterControl/utils'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const StyledInput = styled(Input)` margin-bottom: ${({ theme }) => theme.gridUnit * 4}px; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/AdhocFilterEditPopoverSqlTabContent.test.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/AdhocFilterEditPopoverSqlTabContent.test.jsx index 00969225f6..c0837fdb48 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/AdhocFilterEditPopoverSqlTabContent.test.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/AdhocFilterEditPopoverSqlTabContent.test.jsx @@ -21,11 +21,9 @@ import React from 'react'; import sinon from 'sinon'; import { shallow } from 'enzyme'; -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import AdhocFilterEditPopoverSqlTabContent from '.'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const sqlAdhocFilter = new AdhocFilter({ expressionType: EXPRESSION_TYPES.SQL, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx index 2c897c0994..2e46e07255 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.jsx @@ -25,10 +25,8 @@ import sqlKeywords from 'src/SqlLab/utils/sqlKeywords'; import adhocMetricType from 'src/explore/components/controls/MetricControl/adhocMetricType'; import columnType from 'src/explore/components/controls/FilterControl/columnType'; -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const propTypes = { adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/AdhocFilterOption.test.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/AdhocFilterOption.test.tsx index 8513f452e5..514a10094d 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/AdhocFilterOption.test.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption/AdhocFilterOption.test.tsx @@ -19,11 +19,9 @@ import React from 'react'; import { render, screen, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import AdhocFilterOption, { AdhocFilterOptionProps } from '.'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const simpleAdhocFilter = new AdhocFilter({ expressionType: EXPRESSION_TYPES.SIMPLE, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/AdhocFilterPopoverTrigger.test.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/AdhocFilterPopoverTrigger.test.tsx index 36c711ebf0..b983c413ea 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/AdhocFilterPopoverTrigger.test.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger/AdhocFilterPopoverTrigger.test.tsx @@ -19,11 +19,9 @@ import React from 'react'; import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import AdhocFilter, { - EXPRESSION_TYPES, - CLAUSES, -} from 'src/explore/components/controls/FilterControl/AdhocFilter'; +import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter'; import AdhocFilterPopoverTrigger from '.'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; const simpleAdhocFilter = new AdhocFilter({ expressionType: EXPRESSION_TYPES.SIMPLE, diff --git a/superset-frontend/src/explore/components/controls/FilterControl/adhocFilterType.js b/superset-frontend/src/explore/components/controls/FilterControl/adhocFilterType.js index c9eef05926..df9f43a5d6 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/adhocFilterType.js +++ b/superset-frontend/src/explore/components/controls/FilterControl/adhocFilterType.js @@ -17,7 +17,7 @@ * under the License. */ import PropTypes from 'prop-types'; -import { EXPRESSION_TYPES, CLAUSES } from './AdhocFilter'; +import { CLAUSES, EXPRESSION_TYPES } from './types'; export default PropTypes.oneOfType([ PropTypes.shape({ diff --git a/superset-frontend/src/explore/components/controls/FilterControl/types.ts b/superset-frontend/src/explore/components/controls/FilterControl/types.ts new file mode 100644 index 0000000000..4adceab217 --- /dev/null +++ b/superset-frontend/src/explore/components/controls/FilterControl/types.ts @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export enum EXPRESSION_TYPES { + SIMPLE = 'SIMPLE', + SQL = 'SQL', +} + +export enum CLAUSES { + HAVING = 'HAVING', + WHERE = 'WHERE', +} diff --git a/superset-frontend/src/explore/components/controls/FilterControl/utils/translateToSQL.ts b/superset-frontend/src/explore/components/controls/FilterControl/utils/translateToSQL.ts new file mode 100644 index 0000000000..e041a30fba --- /dev/null +++ b/superset-frontend/src/explore/components/controls/FilterControl/utils/translateToSQL.ts @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + AdhocFilter, + isFreeFormAdhocFilter, + isSimpleAdhocFilter, + SimpleAdhocFilter, +} from '@superset-ui/core'; +import { + OPERATOR_ENUM_TO_OPERATOR_TYPE, + Operators, +} from 'src/explore/constants'; +import { getSimpleSQLExpression } from 'src/explore/exploreUtils'; + +export const OPERATORS_TO_SQL = { + '==': '=', + '!=': '<>', + '>': '>', + '<': '<', + '>=': '>=', + '<=': '<=', + IN: 'IN', + 'NOT IN': 'NOT IN', + LIKE: 'LIKE', + ILIKE: 'ILIKE', + REGEX: 'REGEX', + 'IS NOT NULL': 'IS NOT NULL', + 'IS NULL': 'IS NULL', + 'IS TRUE': 'IS TRUE', + 'IS FALSE': 'IS FALSE', + 'LATEST PARTITION': ({ + datasource, + }: { + datasource: { schema: string; datasource_name: string }; + }) => + `= '{{ presto.latest_partition('${datasource.schema}.${datasource.datasource_name}') }}'`, +}; + +export const translateToSql = ( + adhocFilter: AdhocFilter, + { useSimple }: { useSimple: boolean } = { useSimple: false }, +) => { + if (isSimpleAdhocFilter(adhocFilter) || useSimple) { + const { subject, operator } = adhocFilter as SimpleAdhocFilter; + const comparator = + 'comparator' in adhocFilter ? adhocFilter.comparator : undefined; + const op = + operator && + // 'LATEST PARTITION' supported callback only + operator === + OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.LATEST_PARTITION].operation + ? OPERATORS_TO_SQL[operator](adhocFilter) + : OPERATORS_TO_SQL[operator]; + return getSimpleSQLExpression(subject, op, comparator); + } + if (isFreeFormAdhocFilter(adhocFilter)) { + return adhocFilter.sqlExpression; + } + return ''; +}; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts index 0d39ef8a27..4deb8fbc6a 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts +++ b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.test.ts @@ -21,7 +21,8 @@ import { NO_TIME_RANGE } from '@superset-ui/core'; import { Operators } from 'src/explore/constants'; import * as FetchTimeRangeModule from 'src/explore/components/controls/DateFilterControl'; import { useGetTimeRangeLabel } from './useGetTimeRangeLabel'; -import AdhocFilter, { CLAUSES, EXPRESSION_TYPES } from '../AdhocFilter'; +import AdhocFilter from '../AdhocFilter'; +import { CLAUSES, EXPRESSION_TYPES } from '../types'; test('should return empty object if operator is not TEMPORAL_RANGE', () => { const adhocFilter = new AdhocFilter({ diff --git a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx index abc2ad5b27..f06743ed5c 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/utils/useGetTimeRangeLabel.tsx @@ -20,7 +20,8 @@ import { useEffect, useState } from 'react'; import { NO_TIME_RANGE } from '@superset-ui/core'; import { fetchTimeRange } from 'src/explore/components/controls/DateFilterControl'; import { Operators } from 'src/explore/constants'; -import AdhocFilter, { EXPRESSION_TYPES } from '../AdhocFilter'; +import AdhocFilter from '../AdhocFilter'; +import { EXPRESSION_TYPES } from '../types'; interface Results { actualTimeRange?: string; diff --git a/superset-frontend/src/explore/controlUtils/getFormDataFromDashboardContext.test.ts b/superset-frontend/src/explore/controlUtils/getFormDataFromDashboardContext.test.ts index f3584e1c70..ca10ae1193 100644 --- a/superset-frontend/src/explore/controlUtils/getFormDataFromDashboardContext.test.ts +++ b/superset-frontend/src/explore/controlUtils/getFormDataFromDashboardContext.test.ts @@ -129,6 +129,15 @@ const getDashboardFormData = (overrides: JsonObject = {}) => ({ op: '<=', val: 10000, }, + { + col: { + sqlExpression: 'totally viable sql expression', + expressionType: 'SQL', + label: 'My column', + }, + op: 'IN', + val: ['Value1', 'Value2'], + }, ], granularity_sqla: 'ds', time_range: 'Last month', @@ -179,6 +188,7 @@ const getExpectedResultFormData = (overrides: JsonObject = {}) => ({ clause: 'WHERE', expressionType: 'SIMPLE', operator: 'IN', + operatorId: 'IN', subject: 'name', comparator: ['Aaron'], isExtra: true, @@ -188,11 +198,19 @@ const getExpectedResultFormData = (overrides: JsonObject = {}) => ({ clause: 'WHERE', expressionType: 'SIMPLE', operator: '<=', + operatorId: 'LESS_THAN_OR_EQUAL', subject: 'num_boys', comparator: 10000, isExtra: true, filterOptionName: expect.any(String), }, + { + clause: 'WHERE', + expressionType: 'SQL', + sqlExpression: `(totally viable sql expression) IN ('Value1', 'Value2')`, + filterOptionName: expect.any(String), + isExtra: true, + }, ], adhoc_filters_b: [ { @@ -208,6 +226,7 @@ const getExpectedResultFormData = (overrides: JsonObject = {}) => ({ clause: 'WHERE', expressionType: 'SIMPLE', operator: 'IN', + operatorId: 'IN', subject: 'name', comparator: ['Aaron'], isExtra: true, @@ -217,11 +236,19 @@ const getExpectedResultFormData = (overrides: JsonObject = {}) => ({ clause: 'WHERE', expressionType: 'SIMPLE', operator: '<=', + operatorId: 'LESS_THAN_OR_EQUAL', subject: 'num_boys', comparator: 10000, isExtra: true, filterOptionName: expect.any(String), }, + { + clause: 'WHERE', + expressionType: 'SQL', + sqlExpression: `(totally viable sql expression) IN ('Value1', 'Value2')`, + filterOptionName: expect.any(String), + isExtra: true, + }, ], applied_time_extras: { __time_grain: 'P1D', @@ -282,6 +309,15 @@ const getExpectedResultFormData = (overrides: JsonObject = {}) => ({ op: '<=', val: 10000, }, + { + col: { + expressionType: 'SQL', + label: 'My column', + sqlExpression: 'totally viable sql expression', + }, + op: 'IN', + val: ['Value1', 'Value2'], + }, ], granularity_sqla: 'ds', time_range: 'Last month', diff --git a/superset-frontend/src/explore/controlUtils/getFormDataWithDashboardContext.ts b/superset-frontend/src/explore/controlUtils/getFormDataWithDashboardContext.ts index 9565b48ddf..d686b70013 100644 --- a/superset-frontend/src/explore/controlUtils/getFormDataWithDashboardContext.ts +++ b/superset-frontend/src/explore/controlUtils/getFormDataWithDashboardContext.ts @@ -18,31 +18,55 @@ */ import isEqual from 'lodash/isEqual'; import { - EXTRA_FORM_DATA_OVERRIDE_REGULAR_MAPPINGS, - EXTRA_FORM_DATA_OVERRIDE_EXTRA_KEYS, - isDefined, - JsonObject, - ensureIsArray, - QueryObjectFilterClause, - SimpleAdhocFilter, - QueryFormData, AdhocFilter, + ensureIsArray, + EXTRA_FORM_DATA_OVERRIDE_EXTRA_KEYS, + EXTRA_FORM_DATA_OVERRIDE_REGULAR_MAPPINGS, + isAdhocColumn, + isDefined, isFreeFormAdhocFilter, isSimpleAdhocFilter, + JsonObject, NO_TIME_RANGE, + QueryFormData, + QueryObjectFilterClause, + SimpleAdhocFilter, } from '@superset-ui/core'; +import { OPERATOR_ENUM_TO_OPERATOR_TYPE } from '../constants'; +import { translateToSql } from '../components/controls/FilterControl/utils/translateToSQL'; +import { + CLAUSES, + EXPRESSION_TYPES, +} from '../components/controls/FilterControl/types'; const simpleFilterToAdhoc = ( filterClause: QueryObjectFilterClause, - clause = 'where', + clause: CLAUSES = CLAUSES.WHERE, ) => { - const result = { - clause: clause.toUpperCase(), - expressionType: 'SIMPLE', - operator: filterClause.op, - subject: filterClause.col, - comparator: 'val' in filterClause ? filterClause.val : undefined, - } as SimpleAdhocFilter; + let result: AdhocFilter; + if (isAdhocColumn(filterClause.col)) { + result = { + expressionType: 'SQL', + clause, + sqlExpression: translateToSql({ + expressionType: EXPRESSION_TYPES.SIMPLE, + subject: `(${filterClause.col.sqlExpression})`, + operator: filterClause.op, + comparator: 'val' in filterClause ? filterClause.val : undefined, + } as SimpleAdhocFilter), + }; + } else { + result = { + expressionType: 'SIMPLE', + clause, + operator: filterClause.op, + operatorId: Object.entries(OPERATOR_ENUM_TO_OPERATOR_TYPE).find( + operatorEntry => operatorEntry[1].operation === filterClause.op, + )?.[0], + subject: filterClause.col, + comparator: 'val' in filterClause ? filterClause.val : undefined, + } as SimpleAdhocFilter; + } if (filterClause.isExtra) { Object.assign(result, { isExtra: true, diff --git a/superset-frontend/src/filters/utils.ts b/superset-frontend/src/filters/utils.ts index 4908f1a289..69ca82f58e 100644 --- a/superset-frontend/src/filters/utils.ts +++ b/superset-frontend/src/filters/utils.ts @@ -25,6 +25,10 @@ import { ExtraFormData, } from '@superset-ui/core'; import { FALSE_STRING, NULL_STRING, TRUE_STRING } from 'src/utils/common'; +import { + CLAUSES, + EXPRESSION_TYPES, +} from '../explore/components/controls/FilterControl/types'; export const getSelectExtraFormData = ( col: string, @@ -36,8 +40,8 @@ export const getSelectExtraFormData = ( if (emptyFilter) { extra.adhoc_filters = [ { - expressionType: 'SQL', - clause: 'WHERE', + expressionType: EXPRESSION_TYPES.SQL, + clause: CLAUSES.WHERE, sqlExpression: '1 = 0', }, ];