Web console: update druid-query-toolkit to version 0.4.x (#9500)

* add support for new version of DQT

* update druid-query-toolkit

* fix direction css

* fix remove

* update package

* remove useless conditional

* bump package

* jest -u

Co-authored-by: Maggie Brewster <maggiebrewster@implydata20sMBP.attlocal.net>
This commit is contained in:
mcbrewster 2020-03-13 18:09:47 -07:00 committed by GitHub
parent 6afd55c8f4
commit bcb9a632c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 247 additions and 178 deletions

View File

@ -4237,9 +4237,9 @@
} }
}, },
"druid-query-toolkit": { "druid-query-toolkit": {
"version": "0.3.29", "version": "0.4.3",
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.3.29.tgz", "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.4.3.tgz",
"integrity": "sha512-WKpsmmqgZd5vgOGCyWZ+2h0aNpTbd82h0svC5GBbhqmXB++vkJchYPGjPmmHkNMV2JI2f40ztxel3hpZv5zSQg==", "integrity": "sha512-g2xHaD9lhpTZjM9UEiOQBpgBvO1hm0/cVgqymbUIUf6cgBCm7C1o20fHQzCEK4FBhVmWQSt63pjhRaQ+OM4FGQ==",
"requires": { "requires": {
"tslib": "^1.10.0" "tslib": "^1.10.0"
} }

View File

@ -65,7 +65,7 @@
"d3-axis": "^1.0.12", "d3-axis": "^1.0.12",
"d3-scale": "^3.2.0", "d3-scale": "^3.2.0",
"d3-selection": "^1.4.0", "d3-selection": "^1.4.0",
"druid-query-toolkit": "^0.3.29", "druid-query-toolkit": "^0.4.3",
"file-saver": "^2.0.2", "file-saver": "^2.0.2",
"has-own-prop": "^2.0.0", "has-own-prop": "^2.0.0",
"hjson": "^3.2.1", "hjson": "^3.2.1",

View File

@ -18,8 +18,7 @@
import { MenuItem } from '@blueprintjs/core'; import { MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons';
import { SqlQuery, StringType } from 'druid-query-toolkit'; import { SqlAliasRef, SqlFunction, SqlLiteral, SqlQuery, SqlRef } from 'druid-query-toolkit';
import { aliasFactory } from 'druid-query-toolkit/build/ast/sql-query/helpers';
import React from 'react'; import React from 'react';
export interface NumberMenuItemsProps { export interface NumberMenuItemsProps {
@ -37,13 +36,25 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
<MenuItem <MenuItem
text={`"${columnName}" > 100`} text={`"${columnName}" > 100`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.filterRow(columnName, 100, '>')); onQueryChange(
parsedQuery.addWhereFilter(
SqlRef.fromNameWithDoubleQuotes(columnName),
'>',
SqlLiteral.fromInput(100),
),
);
}} }}
/> />
<MenuItem <MenuItem
text={`"${columnName}" <= 100`} text={`"${columnName}" <= 100`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.filterRow(columnName, 100, '<=')); onQueryChange(
parsedQuery.addWhereFilter(
SqlRef.fromNameWithDoubleQuotes(columnName),
'<=',
SqlLiteral.fromInput(100),
),
);
}} }}
/> />
</MenuItem> </MenuItem>
@ -52,7 +63,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
function renderRemoveFilter(): JSX.Element | undefined { function renderRemoveFilter(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasFilterForColumn(columnName)) return; if (!parsedQuery.getCurrentFilters().includes(columnName)) return;
return ( return (
<MenuItem <MenuItem
@ -67,13 +78,13 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
function renderRemoveGroupBy(): JSX.Element | undefined { function renderRemoveGroupBy(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasGroupByForColumn(columnName)) return; if (!parsedQuery.hasGroupByColumn(columnName)) return;
return ( return (
<MenuItem <MenuItem
icon={IconNames.UNGROUP_OBJECTS} icon={IconNames.UNGROUP_OBJECTS}
text={'Remove group by'} text={'Remove group by'}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.removeGroupBy(columnName), true); onQueryChange(parsedQuery.removeFromGroupBy(columnName), true);
}} }}
/> />
); );
@ -81,32 +92,31 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
function renderGroupByMenu(): JSX.Element | undefined { function renderGroupByMenu(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.groupByClause) return; if (!parsedQuery.groupByExpression) return;
return ( return (
<MenuItem icon={IconNames.GROUP_OBJECTS} text={`Group by`}> <MenuItem icon={IconNames.GROUP_OBJECTS} text={`Group by`}>
<MenuItem <MenuItem
text={`"${columnName}"`} text={`"${columnName}"`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.addToGroupBy(columnName), true); onQueryChange(
parsedQuery.addToGroupBy(SqlRef.fromNameWithDoubleQuotes(columnName)),
true,
);
}} }}
/> />
<MenuItem <MenuItem
text={`TRUNC("${columnName}", -1) AS "${columnName}_trunc"`} text={`TRUNC("${columnName}", -1) AS "${columnName}_trunc"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addFunctionToGroupBy( parsedQuery.addToGroupBy(
'TRUNC', SqlAliasRef.sqlAliasFactory(
[' '], SqlFunction.sqlFunctionFactory('TRUNC', [
[ SqlRef.fromNameWithDoubleQuotes(columnName),
new StringType({ SqlLiteral.fromInput(-1),
spacing: [], ]),
chars: columnName, `${columnName}_truncated`,
quote: '"', ),
}),
-1,
],
aliasFactory(`${columnName}_truncated`),
), ),
true, true,
); );
@ -118,7 +128,7 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
function renderAggregateMenu(): JSX.Element | undefined { function renderAggregateMenu(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.groupByClause) return; if (!parsedQuery.groupByExpression) return;
return ( return (
<MenuItem icon={IconNames.FUNCTION} text={`Aggregate`}> <MenuItem icon={IconNames.FUNCTION} text={`Aggregate`}>
@ -126,7 +136,11 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
text={`SUM(${columnName}) AS "sum_${columnName}"`} text={`SUM(${columnName}) AS "sum_${columnName}"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addAggregateColumn(columnName, 'SUM', aliasFactory(`sum_${columnName}`)), parsedQuery.addAggregateColumn(
[SqlRef.fromName(columnName)],
'SUM',
`sum_${columnName}`,
),
true, true,
); );
}} }}
@ -135,7 +149,11 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
text={`MAX(${columnName}) AS "max_${columnName}"`} text={`MAX(${columnName}) AS "max_${columnName}"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addAggregateColumn(columnName, 'MAX', aliasFactory(`max_${columnName}`)), parsedQuery.addAggregateColumn(
[SqlRef.fromName(columnName)],
'MAX',
`max_${columnName}`,
),
true, true,
); );
}} }}
@ -144,7 +162,11 @@ export const NumberMenuItems = React.memo(function NumberMenuItems(props: Number
text={`MIN(${columnName}) AS "min_${columnName}"`} text={`MIN(${columnName}) AS "min_${columnName}"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addAggregateColumn(columnName, 'MIN', aliasFactory(`min_${columnName}`)), parsedQuery.addAggregateColumn(
[SqlRef.fromName(columnName)],
'MIN',
`min_${columnName}`,
),
true, true,
); );
}} }}

View File

@ -19,14 +19,13 @@
import { MenuItem } from '@blueprintjs/core'; import { MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons';
import { import {
ComparisonExpression, SqlAliasRef,
ComparisonExpressionRhs, SqlFunction,
FilterClause, SqlLiteral,
refExpressionFactory, SqlMulti,
SqlQuery, SqlQuery,
WhereClause, SqlRef,
} from 'druid-query-toolkit'; } from 'druid-query-toolkit';
import { aliasFactory, stringFactory } from 'druid-query-toolkit/build/ast/sql-query/helpers';
import React from 'react'; import React from 'react';
export interface StringMenuItemsProps { export interface StringMenuItemsProps {
@ -44,13 +43,13 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
<MenuItem <MenuItem
text={`"${columnName}" = 'xxx'`} text={`"${columnName}" = 'xxx'`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.filterRow(columnName, 'xxx', '='), false); onQueryChange(parsedQuery.addWhereFilter(columnName, '=', 'xxx'), false);
}} }}
/> />
<MenuItem <MenuItem
text={`"${columnName}" LIKE '%xxx%'`} text={`"${columnName}" LIKE '%xxx%'`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.filterRow(columnName, '%xxx%', 'LIKE'), false); onQueryChange(parsedQuery.addWhereFilter(columnName, 'LIKE', '%xxx%'), false);
}} }}
/> />
</MenuItem> </MenuItem>
@ -59,7 +58,7 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
function renderRemoveFilter(): JSX.Element | undefined { function renderRemoveFilter(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasFilterForColumn(columnName)) return; if (!parsedQuery.getCurrentFilters().includes(columnName)) return;
return ( return (
<MenuItem <MenuItem
@ -74,13 +73,13 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
function renderRemoveGroupBy(): JSX.Element | undefined { function renderRemoveGroupBy(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasGroupByForColumn(columnName)) return; if (!parsedQuery.hasGroupByColumn(columnName)) return;
return ( return (
<MenuItem <MenuItem
icon={IconNames.UNGROUP_OBJECTS} icon={IconNames.UNGROUP_OBJECTS}
text={'Remove group by'} text={'Remove group by'}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.removeGroupBy(columnName), true); onQueryChange(parsedQuery.removeFromGroupBy(columnName), true);
}} }}
/> />
); );
@ -88,26 +87,32 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
function renderGroupByMenu(): JSX.Element | undefined { function renderGroupByMenu(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasGroupBy()) return; if (!parsedQuery.groupByExpression) return;
return ( return (
<MenuItem icon={IconNames.GROUP_OBJECTS} text={`Group by`}> <MenuItem icon={IconNames.GROUP_OBJECTS} text={`Group by`}>
<MenuItem <MenuItem
text={`"${columnName}"`} text={`"${columnName}"`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.addToGroupBy(columnName), true); onQueryChange(
parsedQuery.addToGroupBy(SqlRef.fromNameWithDoubleQuotes(columnName)),
true,
);
}} }}
/> />
<MenuItem <MenuItem
text={`SUBSTRING("${columnName}", 1, 2) AS "${columnName}_substring"`} text={`SUBSTRING("${columnName}", 1, 2) AS "${columnName}_substring"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addFunctionToGroupBy( parsedQuery.addToGroupBy(
'SUBSTRING', SqlAliasRef.sqlAliasFactory(
[' ', ' '], SqlFunction.sqlFunctionFactory('SUBSTRING', [
[stringFactory(columnName, `"`), 1, 2], SqlRef.fromNameWithDoubleQuotes(columnName),
SqlLiteral.fromInput(1),
aliasFactory(`${columnName}_substring`), SqlLiteral.fromInput(2),
]),
`${columnName}_substring`,
),
), ),
true, true,
); );
@ -119,7 +124,7 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
function renderAggregateMenu(): JSX.Element | undefined { function renderAggregateMenu(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasGroupBy()) return; if (!parsedQuery.groupByExpression) return;
return ( return (
<MenuItem icon={IconNames.FUNCTION} text={`Aggregate`}> <MenuItem icon={IconNames.FUNCTION} text={`Aggregate`}>
@ -128,9 +133,11 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
onClick={() => onClick={() =>
onQueryChange( onQueryChange(
parsedQuery.addAggregateColumn( parsedQuery.addAggregateColumn(
columnName, [SqlRef.fromNameWithDoubleQuotes(columnName)],
'COUNT', 'COUNT',
aliasFactory(`dist_${columnName}`), `dist_${columnName}`,
undefined,
'DISTINCT',
), ),
true, true,
) )
@ -141,28 +148,13 @@ export const StringMenuItems = React.memo(function StringMenuItems(props: String
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addAggregateColumn( parsedQuery.addAggregateColumn(
refExpressionFactory('*'), [SqlRef.fromName('*')],
'COUNT', 'COUNT',
aliasFactory(`${columnName}_filtered_count`), `${columnName}_filtered_count`,
false, SqlMulti.sqlMultiFactory('=', [
new FilterClause({ SqlRef.fromNameWithDoubleQuotes(columnName),
keyword: 'FILTER', SqlLiteral.fromInput('xxx'),
spacing: [' '], ]),
ex: new WhereClause({
keyword: 'WHERE',
spacing: [' '],
filter: new ComparisonExpression({
parens: [],
ex: stringFactory(columnName, '"'),
rhs: new ComparisonExpressionRhs({
parens: [],
op: '=',
rhs: stringFactory('xxx', `'`),
spacing: [' ', ' '],
}),
}),
}),
}),
), ),
); );
}} }}

View File

@ -18,17 +18,20 @@
import { MenuDivider, MenuItem } from '@blueprintjs/core'; import { MenuDivider, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons';
import { AdditiveExpression, SqlQuery, Timestamp, timestampFactory } from 'druid-query-toolkit';
import { import {
aliasFactory, SqlAliasRef,
intervalFactory, SqlFunction,
refExpressionFactory, SqlInterval,
stringFactory, SqlLiteral,
} from 'druid-query-toolkit/build/ast/sql-query/helpers'; SqlMulti,
SqlQuery,
SqlRef,
SqlTimestamp,
} from 'druid-query-toolkit';
import React from 'react'; import React from 'react';
function dateToTimestamp(date: Date): Timestamp { function dateToTimestamp(date: Date): SqlTimestamp {
return timestampFactory( return SqlTimestamp.sqlTimestampFactory(
date date
.toISOString() .toISOString()
.split('.')[0] .split('.')[0]
@ -103,14 +106,17 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
<MenuItem <MenuItem
text={`Latest hour`} text={`Latest hour`}
onClick={() => { onClick={() => {
const additiveExpression = new AdditiveExpression({
parens: [],
op: ['-'],
ex: [refExpressionFactory('CURRENT_TIMESTAMP'), intervalFactory('HOUR', '1')],
spacing: [' ', ' '],
});
onQueryChange( onQueryChange(
parsedQuery.removeFilter(columnName).filterRow(columnName, additiveExpression, '>='), parsedQuery
.removeFilter(columnName)
.addWhereFilter(
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
SqlRef.fromName('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('HOUR', 1),
]),
),
true, true,
); );
}} }}
@ -118,14 +124,17 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
<MenuItem <MenuItem
text={`Latest day`} text={`Latest day`}
onClick={() => { onClick={() => {
const additiveExpression = new AdditiveExpression({
parens: [],
op: ['-'],
ex: [refExpressionFactory('CURRENT_TIMESTAMP'), intervalFactory('DAY', '1')],
spacing: [' ', ' '],
});
onQueryChange( onQueryChange(
parsedQuery.removeFilter(columnName).filterRow(columnName, additiveExpression, '>='), parsedQuery
.removeFilter(columnName)
.addWhereFilter(
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
SqlRef.fromName('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('Day', 1),
]),
),
true, true,
); );
}} }}
@ -133,14 +142,17 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
<MenuItem <MenuItem
text={`Latest week`} text={`Latest week`}
onClick={() => { onClick={() => {
const additiveExpression = new AdditiveExpression({
parens: [],
op: ['-'],
ex: [refExpressionFactory('CURRENT_TIMESTAMP'), intervalFactory('DAY', '7')],
spacing: [' ', ' '],
});
onQueryChange( onQueryChange(
parsedQuery.removeFilter(columnName).filterRow(columnName, additiveExpression, '>='), parsedQuery
.removeFilter(columnName)
.addWhereFilter(
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
SqlRef.fromName('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('Day', 7),
]),
),
true, true,
); );
}} }}
@ -148,14 +160,17 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
<MenuItem <MenuItem
text={`Latest month`} text={`Latest month`}
onClick={() => { onClick={() => {
const additiveExpression = new AdditiveExpression({
parens: [],
op: ['-'],
ex: [refExpressionFactory('CURRENT_TIMESTAMP'), intervalFactory('MONTH', '1')],
spacing: [' ', ' '],
});
onQueryChange( onQueryChange(
parsedQuery.removeFilter(columnName).filterRow(columnName, additiveExpression, '>='), parsedQuery
.removeFilter(columnName)
.addWhereFilter(
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
SqlRef.fromName('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('MONTH', 1),
]),
),
true, true,
); );
}} }}
@ -163,14 +178,17 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
<MenuItem <MenuItem
text={`Latest year`} text={`Latest year`}
onClick={() => { onClick={() => {
const additiveExpression = new AdditiveExpression({
parens: [],
op: ['-'],
ex: [refExpressionFactory('CURRENT_TIMESTAMP'), intervalFactory('YEAR', '1')],
spacing: [' ', ' '],
});
onQueryChange( onQueryChange(
parsedQuery.removeFilter(columnName).filterRow(columnName, additiveExpression, '>='), parsedQuery
.removeFilter(columnName)
.addWhereFilter(
columnName,
'>=',
SqlMulti.sqlMultiFactory('-', [
SqlRef.fromName('CURRENT_TIMESTAMP'),
SqlInterval.sqlIntervalFactory('YEAR', 1),
]),
),
true, true,
); );
}} }}
@ -183,8 +201,16 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
onQueryChange( onQueryChange(
parsedQuery parsedQuery
.removeFilter(columnName) .removeFilter(columnName)
.filterRow(dateToTimestamp(hourStart), stringFactory(columnName, `"`), '<=') .addWhereFilter(
.filterRow(columnName, dateToTimestamp(nextHour(hourStart)), '<'), SqlRef.fromNameWithDoubleQuotes(columnName),
'>=',
dateToTimestamp(hourStart),
)
.addWhereFilter(
SqlRef.fromNameWithDoubleQuotes(columnName),
'<',
dateToTimestamp(nextHour(hourStart)),
),
true, true,
); );
}} }}
@ -196,8 +222,16 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
onQueryChange( onQueryChange(
parsedQuery parsedQuery
.removeFilter(columnName) .removeFilter(columnName)
.filterRow(dateToTimestamp(dayStart), stringFactory(columnName, `"`), '<=') .addWhereFilter(
.filterRow(columnName, dateToTimestamp(nextDay(dayStart)), '<'), SqlRef.fromNameWithDoubleQuotes(columnName),
'>=',
dateToTimestamp(dayStart),
)
.addWhereFilter(
SqlRef.fromNameWithDoubleQuotes(columnName),
'<',
dateToTimestamp(nextDay(dayStart)),
),
true, true,
); );
}} }}
@ -209,8 +243,16 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
onQueryChange( onQueryChange(
parsedQuery parsedQuery
.removeFilter(columnName) .removeFilter(columnName)
.filterRow(dateToTimestamp(monthStart), stringFactory(columnName, `"`), '<=') .addWhereFilter(
.filterRow(columnName, dateToTimestamp(nextMonth(monthStart)), '<'), SqlRef.fromNameWithDoubleQuotes(columnName),
'>=',
dateToTimestamp(monthStart),
)
.addWhereFilter(
SqlRef.fromNameWithDoubleQuotes(columnName),
'<',
dateToTimestamp(nextMonth(monthStart)),
),
true, true,
); );
}} }}
@ -222,8 +264,16 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
onQueryChange( onQueryChange(
parsedQuery parsedQuery
.removeFilter(columnName) .removeFilter(columnName)
.filterRow(dateToTimestamp(yearStart), stringFactory(columnName, `"`), '<=') .addWhereFilter(
.filterRow(columnName, dateToTimestamp(nextYear(yearStart)), '<'), SqlRef.fromNameWithDoubleQuotes(columnName),
'<=',
dateToTimestamp(yearStart),
)
.addWhereFilter(
dateToTimestamp(yearStart),
'<',
dateToTimestamp(nextYear(yearStart)),
),
true, true,
); );
}} }}
@ -234,7 +284,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
function renderRemoveFilter(): JSX.Element | undefined { function renderRemoveFilter(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasFilterForColumn(columnName)) return; if (!parsedQuery.getCurrentFilters().includes(columnName)) return;
return ( return (
<MenuItem <MenuItem
@ -249,13 +299,13 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
function renderRemoveGroupBy(): JSX.Element | undefined { function renderRemoveGroupBy(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasGroupByForColumn(columnName)) return; if (!parsedQuery.hasGroupByColumn(columnName)) return;
return ( return (
<MenuItem <MenuItem
icon={IconNames.UNGROUP_OBJECTS} icon={IconNames.UNGROUP_OBJECTS}
text={'Remove group by'} text={'Remove group by'}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.removeGroupBy(columnName), true); onQueryChange(parsedQuery.removeFromGroupBy(columnName), true);
}} }}
/> />
); );
@ -263,7 +313,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
function renderGroupByMenu(): JSX.Element | undefined { function renderGroupByMenu(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasGroupBy()) return; if (!parsedQuery.groupByExpression) return;
return ( return (
<MenuItem icon={IconNames.GROUP_OBJECTS} text={`Group by`}> <MenuItem icon={IconNames.GROUP_OBJECTS} text={`Group by`}>
@ -271,11 +321,14 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
text={`TIME_FLOOR("${columnName}", 'PT1H') AS "${columnName}_time_floor"`} text={`TIME_FLOOR("${columnName}", 'PT1H') AS "${columnName}_time_floor"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addFunctionToGroupBy( parsedQuery.addToGroupBy(
'TIME_FLOOR', SqlAliasRef.sqlAliasFactory(
[' '], SqlFunction.sqlFunctionFactory('TIME_FLOOR', [
[stringFactory(columnName, `"`), stringFactory('PT1H', `'`)], SqlRef.fromName(columnName),
aliasFactory(`${columnName}_time_floor`), SqlLiteral.fromInput('PT1h'),
]),
`${columnName}_time_floor`,
),
), ),
true, true,
); );
@ -285,11 +338,14 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
text={`TIME_FLOOR("${columnName}", 'P1D') AS "${columnName}_time_floor"`} text={`TIME_FLOOR("${columnName}", 'P1D') AS "${columnName}_time_floor"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addFunctionToGroupBy( parsedQuery.addToGroupBy(
'TIME_FLOOR', SqlAliasRef.sqlAliasFactory(
[' '], SqlFunction.sqlFunctionFactory('TIME_FLOOR', [
[stringFactory(columnName, `"`), stringFactory('P1D', `'`)], SqlRef.fromName(columnName),
aliasFactory(`${columnName}_time_floor`), SqlLiteral.fromInput('P1D'),
]),
`${columnName}_time_floor`,
),
), ),
true, true,
); );
@ -299,11 +355,14 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
text={`TIME_FLOOR("${columnName}", 'P7D') AS "${columnName}_time_floor"`} text={`TIME_FLOOR("${columnName}", 'P7D') AS "${columnName}_time_floor"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addFunctionToGroupBy( parsedQuery.addToGroupBy(
'TIME_FLOOR', SqlAliasRef.sqlAliasFactory(
[' '], SqlFunction.sqlFunctionFactory('TIME_FLOOR', [
[stringFactory(columnName, `"`), stringFactory('P7D', `'`)], SqlRef.fromName(columnName),
aliasFactory(`${columnName}_time_floor`), SqlLiteral.fromInput('P7D'),
]),
`${columnName}_time_floor`,
),
), ),
true, true,
); );
@ -315,7 +374,7 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
function renderAggregateMenu(): JSX.Element | undefined { function renderAggregateMenu(): JSX.Element | undefined {
const { columnName, parsedQuery, onQueryChange } = props; const { columnName, parsedQuery, onQueryChange } = props;
if (!parsedQuery.hasGroupBy()) return; if (!parsedQuery.groupByExpression) return;
return ( return (
<MenuItem icon={IconNames.FUNCTION} text={`Aggregate`}> <MenuItem icon={IconNames.FUNCTION} text={`Aggregate`}>
@ -323,7 +382,11 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
text={`MAX("${columnName}") AS "max_${columnName}"`} text={`MAX("${columnName}") AS "max_${columnName}"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addAggregateColumn(columnName, 'MAX', aliasFactory(`max_${columnName}`)), parsedQuery.addAggregateColumn(
[SqlRef.fromNameWithDoubleQuotes(columnName)],
'MAX',
`max_${columnName}`,
),
true, true,
); );
}} }}
@ -332,7 +395,11 @@ export const TimeMenuItems = React.memo(function TimeMenuItems(props: TimeMenuIt
text={`MIN("${columnName}") AS "min_${columnName}"`} text={`MIN("${columnName}") AS "min_${columnName}"`}
onClick={() => { onClick={() => {
onQueryChange( onQueryChange(
parsedQuery.addAggregateColumn(columnName, 'MIN', aliasFactory(`min_${columnName}`)), parsedQuery.addAggregateColumn(
[SqlRef.fromNameWithDoubleQuotes(columnName)],
'MIN',
`min_${columnName}`,
),
true, true,
); );
}} }}

View File

@ -27,7 +27,7 @@ import {
Tree, Tree,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons';
import { refExpressionFactory, SqlQuery, stringFactory } from 'druid-query-toolkit'; import { SqlQuery } from 'druid-query-toolkit';
import React, { ChangeEvent } from 'react'; import React, { ChangeEvent } from 'react';
import { Loader } from '../../../components'; import { Loader } from '../../../components';
@ -184,12 +184,7 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
icon={IconNames.EXCHANGE} icon={IconNames.EXCHANGE}
text={`Replace FROM with: ${table}`} text={`Replace FROM with: ${table}`}
onClick={() => { onClick={() => {
props.onQueryStringChange( props.onQueryStringChange(parsedQuery.replaceFrom(table), true);
parsedQuery.replaceFrom(
refExpressionFactory(stringFactory(table, `"`)),
),
true,
);
}} }}
/> />
)} )}

View File

@ -74,7 +74,7 @@ exports[`query output matches snapshot 1`] = `
/> />
</div> </div>
<div <div
class="rt-th aggregate-header rt-resizable-header" class="rt-th aggregate-header rt-resizable-header"
role="columnheader" role="columnheader"
style="flex: 100 0 auto; width: 100px;" style="flex: 100 0 auto; width: 100px;"
tabindex="-1" tabindex="-1"
@ -101,7 +101,7 @@ exports[`query output matches snapshot 1`] = `
/> />
</div> </div>
<div <div
class="rt-th aggregate-header rt-resizable-header" class="rt-th aggregate-header rt-resizable-header"
role="columnheader" role="columnheader"
style="flex: 100 0 auto; width: 100px;" style="flex: 100 0 auto; width: 100px;"
tabindex="-1" tabindex="-1"

View File

@ -19,10 +19,7 @@
import { Menu, MenuItem, Popover } from '@blueprintjs/core'; import { Menu, MenuItem, Popover } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons';
import { HeaderRows, SqlQuery } from 'druid-query-toolkit'; import { HeaderRows, SqlQuery } from 'druid-query-toolkit';
import { import { basicIdentifierEscape, basicLiteralEscape } from 'druid-query-toolkit/build/sql/helpers';
basicIdentifierEscape,
basicLiteralEscape,
} from 'druid-query-toolkit/build/ast/sql-query/helpers';
import React, { useState } from 'react'; import React, { useState } from 'react';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
@ -94,7 +91,7 @@ export const QueryOutput = React.memo(function QueryOutput(props: QueryOutputPro
icon: IconNames.CROSS, icon: IconNames.CROSS,
title: `Remove: ${trimValue(header)}`, title: `Remove: ${trimValue(header)}`,
onAction: () => { onAction: () => {
onQueryChange(parsedQuery.excludeColumn(header), true); onQueryChange(parsedQuery.remove(header), true);
}, },
}); });
@ -161,14 +158,14 @@ export const QueryOutput = React.memo(function QueryOutput(props: QueryOutputPro
icon={IconNames.FILTER_KEEP} icon={IconNames.FILTER_KEEP}
text={`Filter by: ${trimValue(header)} = ${trimValue(value)}`} text={`Filter by: ${trimValue(header)} = ${trimValue(value)}`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.filterRow(header, value, '='), true); onQueryChange(parsedQuery.addWhereFilter(header, '=', value), true);
}} }}
/> />
<MenuItem <MenuItem
icon={IconNames.FILTER_REMOVE} icon={IconNames.FILTER_REMOVE}
text={`Filter by: ${trimValue(header)} != ${trimValue(value)}`} text={`Filter by: ${trimValue(header)} != ${trimValue(value)}`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.filterRow(header, value, '!='), true); onQueryChange(parsedQuery.addWhereFilter(header, '!=', value), true);
}} }}
/> />
{!isNaN(Number(value)) && ( {!isNaN(Number(value)) && (
@ -177,14 +174,14 @@ export const QueryOutput = React.memo(function QueryOutput(props: QueryOutputPro
icon={IconNames.FILTER_KEEP} icon={IconNames.FILTER_KEEP}
text={`Filter by: ${trimValue(header)} >= ${trimValue(value)}`} text={`Filter by: ${trimValue(header)} >= ${trimValue(value)}`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.filterRow(header, value, '>='), true); onQueryChange(parsedQuery.addWhereFilter(header, '>=', value), true);
}} }}
/> />
<MenuItem <MenuItem
icon={IconNames.FILTER_KEEP} icon={IconNames.FILTER_KEEP}
text={`Filter by: ${trimValue(header)} <= ${trimValue(value)}`} text={`Filter by: ${trimValue(header)} <= ${trimValue(value)}`}
onClick={() => { onClick={() => {
onQueryChange(parsedQuery.filterRow(header, value, '<='), true); onQueryChange(parsedQuery.addWhereFilter(header, '<=', value), true);
}} }}
/> />
</> </>
@ -236,27 +233,23 @@ export const QueryOutput = React.memo(function QueryOutput(props: QueryOutputPro
function getHeaderClassName(header: string) { function getHeaderClassName(header: string) {
const { parsedQuery } = props; const { parsedQuery } = props;
if (!parsedQuery) return;
const className = []; const className = [];
if (parsedQuery) { const sorted = parsedQuery.getSorted();
const sorted = parsedQuery.getSorted(); const aggregateColumns = parsedQuery.getAggregateColumns();
if (sorted) {
className.push(
sorted.map(sorted => {
if (sorted.id === header) {
return sorted.desc ? '-sort-desc' : '-sort-asc';
}
return '';
})[0],
);
}
const aggregateColumns = parsedQuery.getAggregateColumns(); if (sorted) {
if (aggregateColumns && aggregateColumns.includes(header)) { const sortedColumnNames = sorted.map(column => column.id);
className.push('aggregate-header'); if (sortedColumnNames.includes(header)) {
className.push(sorted[sortedColumnNames.indexOf(header)].desc ? '-sort-desc' : '-sort-asc');
} }
} }
if (aggregateColumns && aggregateColumns.includes(header)) {
className.push('aggregate-header');
}
return className.join(' '); return className.join(' ');
} }