You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by vo...@apache.org on 2020/04/17 00:52:12 UTC
[druid] branch master updated: add joins to column tree menu (#9705)
This is an automated email from the ASF dual-hosted git repository.
vogievetsky pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new b7fdb29 add joins to column tree menu (#9705)
b7fdb29 is described below
commit b7fdb294237eccc39149da3fd7751ddd31e2fc2d
Author: mcbrewster <37...@users.noreply.github.com>
AuthorDate: Thu Apr 16 18:51:59 2020 -0600
add joins to column tree menu (#9705)
* add joins to column tree menu
* fix capitalization
* add keyword, keep columns if replaced
* actually fix capitalization
* add keywords
---
web-console/lib/keywords.js | 7 ++
web-console/package-lock.json | 6 +-
web-console/package.json | 2 +-
.../number-menu-items/number-menu-items.spec.tsx | 4 +
.../number-menu-items/number-menu-items.tsx | 94 ++++++++++++++++--
.../string-menu-items/string-menu-items.spec.tsx | 4 +
.../string-menu-items/string-menu-items.tsx | 81 +++++++++++++++-
.../time-menu-items/time-menu-items.spec.tsx | 4 +
.../time-menu-items/time-menu-items.tsx | 105 +++++++++++++++++----
.../views/query-view/column-tree/column-tree.tsx | 101 +++++++++++++++++++-
10 files changed, 373 insertions(+), 35 deletions(-)
diff --git a/web-console/lib/keywords.js b/web-console/lib/keywords.js
index c7261cd..a0ec6fe 100644
--- a/web-console/lib/keywords.js
+++ b/web-console/lib/keywords.js
@@ -34,6 +34,13 @@ exports.SQL_KEYWORDS = [
'DESC',
'LIMIT',
'UNION ALL',
+ 'JOIN',
+ 'LEFT',
+ 'INNER',
+ 'ON',
+ 'RIGHT',
+ 'OUTER',
+ 'FULL'
];
exports.SQL_EXPRESSION_PARTS = [
diff --git a/web-console/package-lock.json b/web-console/package-lock.json
index 534b6dd..94954ef 100644
--- a/web-console/package-lock.json
+++ b/web-console/package-lock.json
@@ -4243,9 +4243,9 @@
}
},
"druid-query-toolkit": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.4.3.tgz",
- "integrity": "sha512-g2xHaD9lhpTZjM9UEiOQBpgBvO1hm0/cVgqymbUIUf6cgBCm7C1o20fHQzCEK4FBhVmWQSt63pjhRaQ+OM4FGQ==",
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.5.1.tgz",
+ "integrity": "sha512-oI1YddnzIbkcelI93qaRtonu3PLGw65fDqLLK6e35gD4Ef/Yf8bOZvFK9wDYNAXcA6SDy7UDarfWsgD2dDWsjg==",
"requires": {
"tslib": "^1.10.0"
}
diff --git a/web-console/package.json b/web-console/package.json
index 105fddc..4bf2d91 100644
--- a/web-console/package.json
+++ b/web-console/package.json
@@ -68,7 +68,7 @@
"d3-axis": "^1.0.12",
"d3-scale": "^3.2.0",
"d3-selection": "^1.4.0",
- "druid-query-toolkit": "^0.4.3",
+ "druid-query-toolkit": "^0.5.1",
"file-saver": "^2.0.2",
"has-own-prop": "^2.0.0",
"hjson": "^3.2.1",
diff --git a/web-console/src/views/query-view/column-tree/column-tree-menu/number-menu-items/number-menu-items.spec.tsx b/web-console/src/views/query-view/column-tree/column-tree-menu/number-menu-items/number-menu-items.spec.tsx
index 3ca046e..491ecdd 100644
--- a/web-console/src/views/query-view/column-tree/column-tree-menu/number-menu-items/number-menu-items.spec.tsx
+++ b/web-console/src/views/query-view/column-tree/column-tree-menu/number-menu-items/number-menu-items.spec.tsx
@@ -28,6 +28,8 @@ describe('number menu', () => {
it('matches snapshot when menu is opened for column not inside group by', () => {
const numberMenu = (
<NumberMenuItems
+ schema="schema"
+ table="table"
columnName={'added'}
parsedQuery={parser(`SELECT channel, count(*) as cnt FROM wikipedia GROUP BY 1`)}
onQueryChange={() => {}}
@@ -41,6 +43,8 @@ describe('number menu', () => {
it('matches snapshot when menu is opened for column inside group by', () => {
const numberMenu = (
<NumberMenuItems
+ schema="schema"
+ table="table"
columnName={'added'}
parsedQuery={parser(`SELECT added, count(*) as cnt FROM wikipedia GROUP BY 1`)}
onQueryChange={() => {}}
diff --git a/web-console/src/views/query-view/column-tree/column-tree-menu/number-menu-items/number-menu-items.tsx b/web-console/src/views/query-view/column-tree/column-tree-menu/number-menu-items/number-menu-items.tsx
index db54853..ca8dc28 100644
--- a/web-console/src/views/query-view/column-tree/column-tree-menu/number-menu-items/number-menu-items.tsx
+++ b/web-console/src/views/query-view/column-tree/column-tree-menu/number-menu-items/number-menu-items.tsx
@@ -18,10 +18,21 @@
import { MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
-import { SqlAliasRef, SqlFunction, SqlLiteral, SqlQuery, SqlRef } from 'druid-query-toolkit';
+import {
+ SqlAliasRef,
+ SqlFunction,
+ SqlLiteral,
+ SqlMulti,
+ SqlQuery,
+ SqlRef,
+} from 'druid-query-toolkit';
import React from 'react';
+import { getCurrentColumns } from '../../column-tree';
+
export interface NumberMenuItemsProps {
+ table: string;
+ schema: string;
columnName: string;
parsedQuery: SqlQuery;
onQueryChange: (queryString: SqlQuery, run?: boolean) => void;
@@ -38,7 +49,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
onClick={() => {
onQueryChange(
parsedQuery.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'>',
SqlLiteral.fromInput(100),
),
@@ -50,7 +61,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
onClick={() => {
onQueryChange(
parsedQuery.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'<=',
SqlLiteral.fromInput(100),
),
@@ -100,7 +111,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
text={`"${columnName}"`}
onClick={() => {
onQueryChange(
- parsedQuery.addToGroupBy(SqlRef.fromNameWithDoubleQuotes(columnName)),
+ parsedQuery.addToGroupBy(SqlRef.fromStringWithDoubleQuotes(columnName)),
true,
);
}}
@@ -112,7 +123,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
parsedQuery.addToGroupBy(
SqlAliasRef.sqlAliasFactory(
SqlFunction.sqlFunctionFactory('TRUNC', [
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
SqlLiteral.fromInput(-1),
]),
`${columnName}_truncated`,
@@ -137,7 +148,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
onClick={() => {
onQueryChange(
parsedQuery.addAggregateColumn(
- [SqlRef.fromName(columnName)],
+ [SqlRef.fromString(columnName)],
'SUM',
`sum_${columnName}`,
),
@@ -150,7 +161,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
onClick={() => {
onQueryChange(
parsedQuery.addAggregateColumn(
- [SqlRef.fromName(columnName)],
+ [SqlRef.fromString(columnName)],
'MAX',
`max_${columnName}`,
),
@@ -163,7 +174,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
onClick={() => {
onQueryChange(
parsedQuery.addAggregateColumn(
- [SqlRef.fromName(columnName)],
+ [SqlRef.fromString(columnName)],
'MIN',
`min_${columnName}`,
),
@@ -175,6 +186,72 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
);
}
+ function renderJoinMenu(): JSX.Element | undefined {
+ const { schema, table, columnName, parsedQuery, onQueryChange } = props;
+ if (schema !== 'lookup' || !parsedQuery) return;
+
+ const { originalTableColumn, lookupColumn } = getCurrentColumns(parsedQuery, table);
+
+ return (
+ <>
+ <MenuItem
+ icon={IconNames.JOIN_TABLE}
+ text={parsedQuery.joinTable ? `Replace join` : `Join`}
+ >
+ <MenuItem
+ icon={IconNames.LEFT_JOIN}
+ text={`Left join`}
+ onClick={() => {
+ onQueryChange(
+ parsedQuery.addJoin(
+ 'LEFT',
+ SqlRef.fromString(table, schema).upgrade(),
+ SqlMulti.sqlMultiFactory('=', [
+ SqlRef.fromString(columnName, table, 'lookup'),
+ SqlRef.fromString(
+ lookupColumn === columnName ? originalTableColumn : 'XXX',
+ parsedQuery.getTableName(),
+ ),
+ ]),
+ ),
+ false,
+ );
+ }}
+ />
+ <MenuItem
+ icon={IconNames.INNER_JOIN}
+ text={`Inner join`}
+ onClick={() => {
+ onQueryChange(
+ parsedQuery.addJoin(
+ 'INNER',
+ SqlRef.fromString(table, schema).upgrade(),
+ SqlMulti.sqlMultiFactory('=', [
+ SqlRef.fromString(columnName, table, 'lookup'),
+ SqlRef.fromString(
+ lookupColumn === columnName ? originalTableColumn : 'XXX',
+ parsedQuery.getTableName(),
+ ),
+ ]),
+ ),
+ false,
+ );
+ }}
+ />
+ </MenuItem>
+ {parsedQuery.onExpression &&
+ parsedQuery.onExpression instanceof SqlMulti &&
+ parsedQuery.onExpression.containsColumn(columnName) && (
+ <MenuItem
+ icon={IconNames.EXCHANGE}
+ text={`Remove join`}
+ onClick={() => onQueryChange(parsedQuery.removeJoin())}
+ />
+ )}
+ </>
+ );
+ }
+
return (
<>
{renderFilterMenu()}
@@ -182,6 +259,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
{renderGroupByMenu()}
{renderRemoveGroupBy()}
{renderAggregateMenu()}
+ {renderJoinMenu()}
</>
);
});
diff --git a/web-console/src/views/query-view/column-tree/column-tree-menu/string-menu-items/string-menu-items.spec.tsx b/web-console/src/views/query-view/column-tree/column-tree-menu/string-menu-items/string-menu-items.spec.tsx
index e952810..3f3c54f 100644
--- a/web-console/src/views/query-view/column-tree/column-tree-menu/string-menu-items/string-menu-items.spec.tsx
+++ b/web-console/src/views/query-view/column-tree/column-tree-menu/string-menu-items/string-menu-items.spec.tsx
@@ -28,6 +28,8 @@ describe('string menu', () => {
it('matches snapshot when menu is opened for column not inside group by', () => {
const stringMenu = (
<StringMenuItems
+ table={'table'}
+ schema={'schema'}
columnName={'cityName'}
parsedQuery={parser(`SELECT channel, count(*) as cnt FROM wikipedia GROUP BY 1`)}
onQueryChange={() => {}}
@@ -41,6 +43,8 @@ describe('string menu', () => {
it('matches snapshot when menu is opened for column inside group by', () => {
const stringMenu = (
<StringMenuItems
+ table={'table'}
+ schema={'schema'}
columnName={'channel'}
parsedQuery={parser(`SELECT channel, count(*) as cnt FROM wikipedia GROUP BY 1`)}
onQueryChange={() => {}}
diff --git a/web-console/src/views/query-view/column-tree/column-tree-menu/string-menu-items/string-menu-items.tsx b/web-console/src/views/query-view/column-tree/column-tree-menu/string-menu-items/string-menu-items.tsx
index 25b8233..dcba6f0 100644
--- a/web-console/src/views/query-view/column-tree/column-tree-menu/string-menu-items/string-menu-items.tsx
+++ b/web-console/src/views/query-view/column-tree/column-tree-menu/string-menu-items/string-menu-items.tsx
@@ -28,7 +28,11 @@ import {
} from 'druid-query-toolkit';
import React from 'react';
+import { getCurrentColumns } from '../../column-tree';
+
export interface StringMenuItemsProps {
+ schema: string;
+ table: string;
columnName: string;
parsedQuery: SqlQuery;
onQueryChange: (queryString: SqlQuery, run?: boolean) => void;
@@ -95,7 +99,7 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
text={`"${columnName}"`}
onClick={() => {
onQueryChange(
- parsedQuery.addToGroupBy(SqlRef.fromNameWithDoubleQuotes(columnName)),
+ parsedQuery.addToGroupBy(SqlRef.fromStringWithDoubleQuotes(columnName)),
true,
);
}}
@@ -107,7 +111,7 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
parsedQuery.addToGroupBy(
SqlAliasRef.sqlAliasFactory(
SqlFunction.sqlFunctionFactory('SUBSTRING', [
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
SqlLiteral.fromInput(1),
SqlLiteral.fromInput(2),
]),
@@ -133,7 +137,7 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
onClick={() =>
onQueryChange(
parsedQuery.addAggregateColumn(
- [SqlRef.fromNameWithDoubleQuotes(columnName)],
+ [SqlRef.fromStringWithDoubleQuotes(columnName)],
'COUNT',
`dist_${columnName}`,
undefined,
@@ -148,11 +152,11 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
onClick={() => {
onQueryChange(
parsedQuery.addAggregateColumn(
- [SqlRef.fromName('*')],
+ [SqlRef.fromString('*')],
'COUNT',
`${columnName}_filtered_count`,
SqlMulti.sqlMultiFactory('=', [
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
SqlLiteral.fromInput('xxx'),
]),
),
@@ -163,6 +167,72 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
);
}
+ function renderJoinMenu(): JSX.Element | undefined {
+ const { schema, table, columnName, parsedQuery, onQueryChange } = props;
+ if (schema !== 'lookup' || !parsedQuery) return;
+
+ const { originalTableColumn, lookupColumn } = getCurrentColumns(parsedQuery, table);
+
+ return (
+ <>
+ <MenuItem
+ icon={IconNames.JOIN_TABLE}
+ text={parsedQuery.joinTable ? `Replace join` : `Join`}
+ >
+ <MenuItem
+ icon={IconNames.LEFT_JOIN}
+ text={`Left join`}
+ onClick={() => {
+ onQueryChange(
+ parsedQuery.addJoin(
+ 'LEFT',
+ SqlRef.fromString(table, schema).upgrade(),
+ SqlMulti.sqlMultiFactory('=', [
+ SqlRef.fromString(columnName, table, 'lookup'),
+ SqlRef.fromString(
+ lookupColumn === columnName ? originalTableColumn : 'XXX',
+ parsedQuery.getTableName(),
+ ),
+ ]),
+ ),
+ false,
+ );
+ }}
+ />
+ <MenuItem
+ icon={IconNames.INNER_JOIN}
+ text={`Inner join`}
+ onClick={() => {
+ onQueryChange(
+ parsedQuery.addJoin(
+ 'INNER',
+ SqlRef.fromString(table, schema).upgrade(),
+ SqlMulti.sqlMultiFactory('=', [
+ SqlRef.fromString(columnName, table, 'lookup'),
+ SqlRef.fromString(
+ lookupColumn === columnName ? originalTableColumn : 'XXX',
+ parsedQuery.getTableName(),
+ ),
+ ]),
+ ),
+ false,
+ );
+ }}
+ />
+ </MenuItem>
+ {parsedQuery.onExpression &&
+ parsedQuery.onExpression instanceof SqlMulti &&
+ parsedQuery.onExpression.containsColumn(columnName) && (
+ <MenuItem
+ icon={IconNames.EXCHANGE}
+ text={`Remove join`}
+ onClick={() => onQueryChange(parsedQuery.removeJoin())}
+ />
+ )}
+ </>
+ );
+ }
+
return (
<>
{renderFilterMenu()}
@@ -170,6 +240,7 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
{renderGroupByMenu()}
{renderRemoveGroupBy()}
{renderAggregateMenu()}
+ {renderJoinMenu()}
</>
);
});
diff --git a/web-console/src/views/query-view/column-tree/column-tree-menu/time-menu-items/time-menu-items.spec.tsx b/web-console/src/views/query-view/column-tree/column-tree-menu/time-menu-items/time-menu-items.spec.tsx
index a6a1c9a..a8d5ee7 100644
--- a/web-console/src/views/query-view/column-tree/column-tree-menu/time-menu-items/time-menu-items.spec.tsx
+++ b/web-console/src/views/query-view/column-tree/column-tree-menu/time-menu-items/time-menu-items.spec.tsx
@@ -28,6 +28,8 @@ describe('time menu', () => {
it('matches snapshot when menu is opened for column not inside group by', () => {
const timeMenu = (
<TimeMenuItems
+ table={'table'}
+ schema={'schema'}
columnName={'__time'}
parsedQuery={parser(`SELECT channel, count(*) as cnt FROM wikipedia GROUP BY 1`)}
onQueryChange={() => {}}
@@ -41,6 +43,8 @@ describe('time menu', () => {
it('matches snapshot when menu is opened for column inside group by', () => {
const timeMenu = (
<TimeMenuItems
+ table={'table'}
+ schema={'schema'}
columnName={'__time'}
parsedQuery={parser(`SELECT __time, count(*) as cnt FROM wikipedia GROUP BY 1`)}
onQueryChange={() => {}}
diff --git a/web-console/src/views/query-view/column-tree/column-tree-menu/time-menu-items/time-menu-items.tsx b/web-console/src/views/query-view/column-tree/column-tree-menu/time-menu-items/time-menu-items.tsx
index 310fea8..e2e7e18 100644
--- a/web-console/src/views/query-view/column-tree/column-tree-menu/time-menu-items/time-menu-items.tsx
+++ b/web-console/src/views/query-view/column-tree/column-tree-menu/time-menu-items/time-menu-items.tsx
@@ -30,6 +30,8 @@ import {
} from 'druid-query-toolkit';
import React from 'react';
+import { getCurrentColumns } from '../../column-tree';
+
function dateToTimestamp(date: Date): SqlTimestamp {
return SqlTimestamp.sqlTimestampFactory(
date
@@ -91,6 +93,8 @@ function nextYear(dt: Date): Date {
}
export interface TimeMenuItemsProps {
+ table: string;
+ schema: string;
columnName: string;
parsedQuery: SqlQuery;
onQueryChange: (queryString: SqlQuery, run?: boolean) => void;
@@ -113,7 +117,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
- SqlRef.fromName('CURRENT_TIMESTAMP'),
+ SqlRef.fromString('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('HOUR', 1),
]),
),
@@ -131,7 +135,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
- SqlRef.fromName('CURRENT_TIMESTAMP'),
+ SqlRef.fromString('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('Day', 1),
]),
),
@@ -149,7 +153,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
- SqlRef.fromName('CURRENT_TIMESTAMP'),
+ SqlRef.fromString('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('Day', 7),
]),
),
@@ -167,7 +171,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
- SqlRef.fromName('CURRENT_TIMESTAMP'),
+ SqlRef.fromString('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('MONTH', 1),
]),
),
@@ -185,7 +189,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
- SqlRef.fromName('CURRENT_TIMESTAMP'),
+ SqlRef.fromString('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('YEAR', 1),
]),
),
@@ -202,12 +206,12 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
parsedQuery
.removeFilter(columnName)
.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'>=',
dateToTimestamp(hourStart),
)
.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'<',
dateToTimestamp(nextHour(hourStart)),
),
@@ -223,12 +227,12 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
parsedQuery
.removeFilter(columnName)
.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'>=',
dateToTimestamp(dayStart),
)
.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'<',
dateToTimestamp(nextDay(dayStart)),
),
@@ -244,12 +248,12 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
parsedQuery
.removeFilter(columnName)
.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'>=',
dateToTimestamp(monthStart),
)
.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'<',
dateToTimestamp(nextMonth(monthStart)),
),
@@ -265,7 +269,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
parsedQuery
.removeFilter(columnName)
.addWhereFilter(
- SqlRef.fromNameWithDoubleQuotes(columnName),
+ SqlRef.fromStringWithDoubleQuotes(columnName),
'<=',
dateToTimestamp(yearStart),
)
@@ -324,7 +328,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
parsedQuery.addToGroupBy(
SqlAliasRef.sqlAliasFactory(
SqlFunction.sqlFunctionFactory('TIME_FLOOR', [
- SqlRef.fromName(columnName),
+ SqlRef.fromString(columnName),
SqlLiteral.fromInput('PT1h'),
]),
`${columnName}_time_floor`,
@@ -341,7 +345,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
parsedQuery.addToGroupBy(
SqlAliasRef.sqlAliasFactory(
SqlFunction.sqlFunctionFactory('TIME_FLOOR', [
- SqlRef.fromName(columnName),
+ SqlRef.fromString(columnName),
SqlLiteral.fromInput('P1D'),
]),
`${columnName}_time_floor`,
@@ -358,7 +362,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
parsedQuery.addToGroupBy(
SqlAliasRef.sqlAliasFactory(
SqlFunction.sqlFunctionFactory('TIME_FLOOR', [
- SqlRef.fromName(columnName),
+ SqlRef.fromString(columnName),
SqlLiteral.fromInput('P7D'),
]),
`${columnName}_time_floor`,
@@ -383,7 +387,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
onClick={() => {
onQueryChange(
parsedQuery.addAggregateColumn(
- [SqlRef.fromNameWithDoubleQuotes(columnName)],
+ [SqlRef.fromStringWithDoubleQuotes(columnName)],
'MAX',
`max_${columnName}`,
),
@@ -396,7 +400,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
onClick={() => {
onQueryChange(
parsedQuery.addAggregateColumn(
- [SqlRef.fromNameWithDoubleQuotes(columnName)],
+ [SqlRef.fromStringWithDoubleQuotes(columnName)],
'MIN',
`min_${columnName}`,
),
@@ -408,6 +412,72 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
);
}
+ function renderJoinMenu(): JSX.Element | undefined {
+ const { schema, table, columnName, parsedQuery, onQueryChange } = props;
+ if (schema !== 'lookup' || !parsedQuery) return;
+
+ const { originalTableColumn, lookupColumn } = getCurrentColumns(parsedQuery, table);
+
+ return (
+ <>
+ <MenuItem
+ icon={IconNames.JOIN_TABLE}
+ text={parsedQuery.joinTable ? `Replace join` : `Join`}
+ >
+ <MenuItem
+ icon={IconNames.LEFT_JOIN}
+ text={`Left join`}
+ onClick={() => {
+ onQueryChange(
+ parsedQuery.addJoin(
+ 'LEFT',
+ SqlRef.fromString(table, schema).upgrade(),
+ SqlMulti.sqlMultiFactory('=', [
+ SqlRef.fromString(columnName, table, 'lookup'),
+ SqlRef.fromString(
+ lookupColumn === columnName ? originalTableColumn : 'XXX',
+ parsedQuery.getTableName(),
+ ),
+ ]),
+ ),
+ false,
+ );
+ }}
+ />
+ <MenuItem
+ icon={IconNames.INNER_JOIN}
+ text={`Inner join`}
+ onClick={() => {
+ onQueryChange(
+ parsedQuery.addJoin(
+ 'INNER',
+ SqlRef.fromString(table, schema).upgrade(),
+ SqlMulti.sqlMultiFactory('=', [
+ SqlRef.fromString(columnName, table, 'lookup'),
+ SqlRef.fromString(
+ lookupColumn === columnName ? originalTableColumn : 'XXX',
+ parsedQuery.getTableName(),
+ ),
+ ]),
+ ),
+ false,
+ );
+ }}
+ />
+ </MenuItem>
+ {parsedQuery.onExpression &&
+ parsedQuery.onExpression instanceof SqlMulti &&
+ parsedQuery.onExpression.containsColumn(columnName) && (
+ <MenuItem
+ icon={IconNames.EXCHANGE}
+ text={`Remove join`}
+ onClick={() => onQueryChange(parsedQuery.removeJoin())}
+ />
+ )}
+ </>
+ );
+ }
+
return (
<>
{renderFilterMenu()}
@@ -415,6 +485,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
{renderGroupByMenu()}
{renderRemoveGroupBy()}
{renderAggregateMenu()}
+ {renderJoinMenu()}
</>
);
});
diff --git a/web-console/src/views/query-view/column-tree/column-tree.tsx b/web-console/src/views/query-view/column-tree/column-tree.tsx
index fd98ccf..d672b07 100644
--- a/web-console/src/views/query-view/column-tree/column-tree.tsx
+++ b/web-console/src/views/query-view/column-tree/column-tree.tsx
@@ -27,7 +27,7 @@ import {
Tree,
} from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
-import { SqlQuery } from 'druid-query-toolkit';
+import { SqlMulti, SqlQuery, SqlRef } from 'druid-query-toolkit';
import React, { ChangeEvent } from 'react';
import { Loader } from '../../../components';
@@ -125,6 +125,32 @@ export interface ColumnTreeState {
selectedTreeIndex: number;
}
+export function getCurrentColumns(parsedQuery: SqlQuery, table: string) {
+ let lookupColumn;
+ let originalTableColumn;
+ if (
+ parsedQuery.joinTable &&
+ parsedQuery.joinTable.table === table &&
+ parsedQuery.onExpression &&
+ parsedQuery.onExpression instanceof SqlMulti
+ ) {
+ parsedQuery.onExpression.arguments.map(argument => {
+ if (argument instanceof SqlRef) {
+ if (argument.namespace === 'lookup') {
+ lookupColumn = argument.column;
+ } else {
+ originalTableColumn = argument.column;
+ }
+ }
+ });
+ }
+
+ return {
+ lookupColumn: lookupColumn || 'XXX',
+ originalTableColumn: originalTableColumn || 'XXX',
+ };
+}
+
export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeState> {
static getDerivedStateFromProps(props: ColumnTreeProps, state: ColumnTreeState) {
const { columnMetadata, defaultSchema, defaultTable } = props;
@@ -188,6 +214,73 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
}}
/>
)}
+ {parsedQuery && schema === 'lookup' && (
+ <MenuItem
+ popoverProps={{ openOnTargetFocus: false }}
+ icon={IconNames.JOIN_TABLE}
+ text={parsedQuery.joinTable ? `Replace join` : `Join`}
+ >
+ <MenuItem
+ icon={IconNames.LEFT_JOIN}
+ text={`Left join`}
+ onClick={() => {
+ const { lookupColumn, originalTableColumn } = getCurrentColumns(
+ parsedQuery,
+ table,
+ );
+ props.onQueryStringChange(
+ parsedQuery.addJoin(
+ 'LEFT',
+ SqlRef.fromString(table, schema).upgrade(),
+ SqlMulti.sqlMultiFactory('=', [
+ SqlRef.fromString(lookupColumn, table, 'lookup'),
+ SqlRef.fromString(
+ originalTableColumn,
+ parsedQuery.getTableName(),
+ ),
+ ]),
+ ),
+ false,
+ );
+ }}
+ />
+ <MenuItem
+ icon={IconNames.INNER_JOIN}
+ text={`Inner join`}
+ onClick={() => {
+ const { lookupColumn, originalTableColumn } = getCurrentColumns(
+ parsedQuery,
+ table,
+ );
+ props.onQueryStringChange(
+ parsedQuery.addJoin(
+ 'INNER',
+ SqlRef.fromString(table, schema).upgrade(),
+ SqlMulti.sqlMultiFactory('=', [
+ SqlRef.fromString(lookupColumn, table, 'lookup'),
+ SqlRef.fromString(
+ originalTableColumn,
+ parsedQuery.getTableName(),
+ ),
+ ]),
+ ),
+ false,
+ );
+ }}
+ />
+ </MenuItem>
+ )}
+ {parsedQuery &&
+ parsedQuery.joinTable &&
+ parsedQuery.joinTable.table === table && (
+ <MenuItem
+ icon={IconNames.EXCHANGE}
+ text={`Remove join`}
+ onClick={() =>
+ props.onQueryStringChange(parsedQuery.removeJoin())
+ }
+ />
+ )}
</Menu>
);
}}
@@ -234,6 +327,8 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
(columnData.DATA_TYPE === 'BIGINT' ||
columnData.DATA_TYPE === 'FLOAT') && (
<NumberMenuItems
+ table={table}
+ schema={schema}
columnName={columnData.COLUMN_NAME}
parsedQuery={parsedQuery}
onQueryChange={props.onQueryStringChange}
@@ -241,6 +336,8 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
)}
{parsedQuery && columnData.DATA_TYPE === 'VARCHAR' && (
<StringMenuItems
+ table={table}
+ schema={schema}
columnName={columnData.COLUMN_NAME}
parsedQuery={parsedQuery}
onQueryChange={props.onQueryStringChange}
@@ -248,6 +345,8 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
)}
{parsedQuery && columnData.DATA_TYPE === 'TIMESTAMP' && (
<TimeMenuItems
+ table={table}
+ schema={schema}
columnName={columnData.COLUMN_NAME}
parsedQuery={parsedQuery}
onQueryChange={props.onQueryStringChange}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org