Skip to content

Commit

Permalink
Web console: Fix order-by-delta in explore view table (#16417) (#16453)
Browse files Browse the repository at this point in the history
* change to using measure name

* Implment order by delta

* less paring, stricter types

* safeDivide0

* fix no query

* new DTQ alows parsing JSON_VALUE(...RETURNING...)
  • Loading branch information
vogievetsky committed May 15, 2024
1 parent fabf58f commit 7313903
Show file tree
Hide file tree
Showing 22 changed files with 553 additions and 177 deletions.
2 changes: 1 addition & 1 deletion licenses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5108,7 +5108,7 @@ license_category: binary
module: web-console
license_name: Apache License version 2.0
copyright: Imply Data
version: 0.22.11
version: 0.22.13

---

Expand Down
14 changes: 7 additions & 7 deletions web-console/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion web-console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"@blueprintjs/datetime2": "^0.9.35",
"@blueprintjs/icons": "^4.16.0",
"@blueprintjs/popover2": "^1.14.9",
"@druid-toolkit/query": "^0.22.11",
"@druid-toolkit/query": "^0.22.13",
"@druid-toolkit/visuals-core": "^0.3.3",
"@druid-toolkit/visuals-react": "^0.3.3",
"ace-builds": "~1.4.14",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const RecordTablePane = React.memo(function RecordTablePane(props: Record
const finalPage =
hasMoreResults && Math.floor(queryResult.rows.length / pagination.pageSize) === pagination.page; // on the last page

const numericColumnBraces = getNumericColumnBraces(queryResult, pagination);
const numericColumnBraces = getNumericColumnBraces(queryResult, undefined, pagination);
return (
<div className={classNames('record-table-pane', { 'more-results': hasMoreResults })}>
{finalPage ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export interface AsyncActionDialogProps {
className?: string;
icon?: IconName;
intent?: Intent;
successText: string;
failText: string;
successText: ReactNode;
failText: ReactNode;
warningChecks?: ReactNode[];
children?: ReactNode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ export const KillDatasourceDialog = function KillDatasourceDialog(
return resp.data;
}}
confirmButtonText="Permanently delete unused segments"
successText="Kill task was issued. Unused segments in datasource will be deleted"
successText={
<>
Kill task was issued. Unused segments in datasource <Tag minimal>{datasource}</Tag> will
be deleted
</>
}
failText="Failed submit kill task"
intent={Intent.DANGER}
onClose={onClose}
Expand Down
10 changes: 8 additions & 2 deletions web-console/src/druid-models/execution/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,10 @@ export class Execution {
value.queryContext = queryContext;
const parsedQuery = parseSqlQuery(sqlQuery);
if (value.result && (parsedQuery || queryContext)) {
value.result = value.result.attachQuery({ context: queryContext }, parsedQuery);
value.result = value.result.attachQuery(
{ ...this.nativeQuery, context: queryContext },
parsedQuery,
);
}

return new Execution(value);
Expand All @@ -463,7 +466,10 @@ export class Execution {
public changeResult(result: QueryResult): Execution {
return new Execution({
...this.valueOf(),
result: result.attachQuery({}, this.sqlQuery ? parseSqlQuery(this.sqlQuery) : undefined),
result: result.attachQuery(
this.nativeQuery,
this.sqlQuery ? parseSqlQuery(this.sqlQuery) : undefined,
),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import type {
QueryParameter,
QueryPayload,
SqlClusteredByClause,
SqlExpression,
SqlPartitionedByClause,
Expand Down Expand Up @@ -446,7 +447,7 @@ export class WorkbenchQuery {

public getApiQuery(makeQueryId: () => string = uuidv4): {
engine: DruidEngine;
query: Record<string, any>;
query: QueryPayload;
prefixLines: number;
cancelQueryId?: string;
} {
Expand Down Expand Up @@ -478,7 +479,7 @@ export class WorkbenchQuery {
};
}

let apiQuery: Record<string, any> = {};
let apiQuery: QueryPayload;
if (this.isJsonLike()) {
try {
apiQuery = Hjson.parse(queryString);
Expand Down
16 changes: 16 additions & 0 deletions web-console/src/utils/general.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,22 @@ export function pluralIfNeeded(n: NumberLike, singular: string, plural?: string)

// ----------------------------

export function partition<T>(xs: T[], predicate: (x: T, i: number) => boolean): [T[], T[]] {
const match: T[] = [];
const nonMatch: T[] = [];

for (let i = 0; i < xs.length; i++) {
const x = xs[i];
if (predicate(x, i)) {
match.push(x);
} else {
nonMatch.push(x);
}
}

return [match, nonMatch];
}

export function filterMap<T, Q>(xs: readonly T[], f: (x: T, i: number) => Q | undefined): Q[] {
return xs.map(f).filter((x: Q | undefined) => typeof x !== 'undefined') as Q[];
}
Expand Down
12 changes: 10 additions & 2 deletions web-console/src/utils/table-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,16 @@ export function changePage(pagination: Pagination, page: number): Pagination {
return deepSet(pagination, 'page', page);
}

export interface ColumnHint {
displayName?: string;
group?: string;
formatter?: (x: any) => string;
}

export function getNumericColumnBraces(
queryResult: QueryResult,
pagination?: Pagination,
columnHints: Map<string, ColumnHint> | undefined,
pagination: Pagination | undefined,
): Record<number, string[]> {
let rows = queryResult.rows;

Expand All @@ -47,8 +54,9 @@ export function getNumericColumnBraces(
if (rows.length) {
queryResult.header.forEach((column, i) => {
if (!oneOf(column.nativeType, 'LONG', 'FLOAT', 'DOUBLE')) return;
const formatter = columnHints?.get(column.name)?.formatter || formatNumber;
const brace = filterMap(rows, row =>
oneOf(typeof row[i], 'number', 'bigint') ? formatNumber(row[i]) : undefined,
oneOf(typeof row[i], 'number', 'bigint') ? formatter(row[i]) : undefined,
);
if (rows.length === brace.length) {
numericColumnBraces[i] = brace;
Expand Down
31 changes: 26 additions & 5 deletions web-console/src/views/datasources-view/datasources-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* limitations under the License.
*/

import { FormGroup, InputGroup, Intent, MenuItem, Switch } from '@blueprintjs/core';
import { FormGroup, InputGroup, Intent, MenuItem, Switch, Tag } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { SqlQuery, T } from '@druid-toolkit/query';
import classNames from 'classnames';
Expand Down Expand Up @@ -651,8 +651,18 @@ GROUP BY 1, 2`;
return resp.data;
}}
confirmButtonText="Mark as unused all segments"
successText="All segments in datasource have been marked as unused"
failText="Failed to mark as unused all segments in datasource"
successText={
<>
All segments in datasource <Tag minimal>{datasourceToMarkAsUnusedAllSegmentsIn}</Tag>{' '}
have been marked as unused
</>
}
failText={
<>
Failed to mark as unused all segments in datasource{' '}
<Tag minimal>{datasourceToMarkAsUnusedAllSegmentsIn}</Tag>
</>
}
intent={Intent.DANGER}
onClose={() => {
this.setState({ datasourceToMarkAsUnusedAllSegmentsIn: undefined });
Expand Down Expand Up @@ -684,8 +694,19 @@ GROUP BY 1, 2`;
return resp.data;
}}
confirmButtonText="Mark as used all segments"
successText="All non-overshadowed segments in datasource have been marked as used"
failText="Failed to mark as used all non-overshadowed segments in datasource"
successText={
<>
All non-overshadowed segments in datasource{' '}
<Tag minimal>{datasourceToMarkAllNonOvershadowedSegmentsAsUsedIn}</Tag> have been marked
as used
</>
}
failText={
<>
Failed to mark as used all non-overshadowed segments in datasource{' '}
<Tag minimal>{datasourceToMarkAllNonOvershadowedSegmentsAsUsedIn}</Tag>
</>
}
intent={Intent.PRIMARY}
onClose={() => {
this.setState({ datasourceToMarkAllNonOvershadowedSegmentsAsUsedIn: undefined });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import ReactTable from 'react-table';
import { BracedText, Deferred, TableCell } from '../../../../../components';
import { possibleDruidFormatForValues, TIME_COLUMN } from '../../../../../druid-models';
import { SMALL_TABLE_PAGE_SIZE, SMALL_TABLE_PAGE_SIZE_OPTIONS } from '../../../../../react-table';
import type { Pagination, QueryAction } from '../../../../../utils';
import type { ColumnHint, Pagination, QueryAction } from '../../../../../utils';
import {
columnToIcon,
columnToWidth,
Expand Down Expand Up @@ -60,30 +60,34 @@ function isComparable(x: unknown): boolean {
return x !== null && x !== '';
}

function columnNester(columns: TableColumn[], groupHints: string[] | undefined): TableColumn[] {
if (!groupHints) return columns;
function columnNester(
tableColumns: TableColumn[],
resultColumns: readonly Column[],
columnHints: Map<string, ColumnHint> | undefined,
): TableColumn[] {
if (!columnHints) return tableColumns;

const ret: TableColumn[] = [];
let currentGroupHint: string | null = null;
let currentGroupName: string | null = null;
let currentColumnGroup: TableColumn | null = null;
for (let i = 0; i < columns.length; i++) {
const column = columns[i];
const groupHint = groupHints[i];
if (groupHint) {
if (currentGroupHint === groupHint) {
currentColumnGroup!.columns!.push(column);
for (let i = 0; i < tableColumns.length; i++) {
const tableColumn = tableColumns[i];
const group = columnHints.get(resultColumns[i].name)?.group;
if (group) {
if (currentGroupName === group) {
currentColumnGroup!.columns!.push(tableColumn);
} else {
currentGroupHint = groupHint;
currentGroupName = group;
ret.push(
(currentColumnGroup = {
Header: <div className="group-cell">{currentGroupHint}</div>,
columns: [column],
Header: <div className="group-cell">{currentGroupName}</div>,
columns: [tableColumn],
}),
);
}
} else {
ret.push(column);
currentGroupHint = null;
ret.push(tableColumn);
currentGroupName = null;
currentColumnGroup = null;
}
}
Expand All @@ -94,12 +98,12 @@ function columnNester(columns: TableColumn[], groupHints: string[] | undefined):
export interface GenericOutputTableProps {
queryResult: QueryResult;
onQueryAction(action: QueryAction): void;
onOrderByChange?(columnIndex: number, desc: boolean): void;
onOrderByChange?(columnName: string, desc: boolean): void;
onExport?(): void;
runeMode: boolean;
showTypeIcons: boolean;
initPageSize?: number;
groupHints?: string[];
columnHints?: Map<string, ColumnHint>;
}

export const GenericOutputTable = React.memo(function GenericOutputTable(
Expand All @@ -113,7 +117,7 @@ export const GenericOutputTable = React.memo(function GenericOutputTable(
runeMode,
showTypeIcons,
initPageSize,
groupHints,
columnHints,
} = props;
const parsedQuery = queryResult.sqlQuery;
const [pagination, setPagination] = useState<Pagination>({
Expand Down Expand Up @@ -159,7 +163,7 @@ export const GenericOutputTable = React.memo(function GenericOutputTable(
icon={reverseOrderByDirection === 'ASC' ? IconNames.SORT_ASC : IconNames.SORT_DESC}
text={`Order ${reverseOrderByDirection === 'ASC' ? 'ascending' : 'descending'}`}
onClick={() => {
onOrderByChange(headerIndex, reverseOrderByDirection !== 'ASC');
onOrderByChange(header, reverseOrderByDirection !== 'ASC');
}}
/>,
);
Expand All @@ -170,15 +174,15 @@ export const GenericOutputTable = React.memo(function GenericOutputTable(
icon={IconNames.SORT_DESC}
text="Order descending"
onClick={() => {
onOrderByChange(headerIndex, true);
onOrderByChange(header, true);
}}
/>,
<MenuItem
key="order_asc"
icon={IconNames.SORT_ASC}
text="Order ascending"
onClick={() => {
onOrderByChange(headerIndex, false);
onOrderByChange(header, false);
}}
/>,
);
Expand Down Expand Up @@ -426,7 +430,7 @@ export const GenericOutputTable = React.memo(function GenericOutputTable(
const finalPage =
hasMoreResults && Math.floor(queryResult.rows.length / pagination.pageSize) === pagination.page; // on the last page

const numericColumnBraces = getNumericColumnBraces(queryResult, pagination);
const numericColumnBraces = getNumericColumnBraces(queryResult, columnHints, pagination);
return (
<div className={classNames('generic-output-table', { 'more-results': hasMoreResults })}>
{finalPage ? (
Expand Down Expand Up @@ -479,7 +483,7 @@ export const GenericOutputTable = React.memo(function GenericOutputTable(
<div className="clickable-cell">
<div className="output-name">
{icon && <Icon className="type-icon" icon={icon} size={12} />}
{h}
{columnHints?.get(h)?.displayName ?? h}
{hasFilterOnHeader(h, i) && <Icon icon={IconNames.FILTER} size={14} />}
</div>
</div>
Expand All @@ -490,6 +494,7 @@ export const GenericOutputTable = React.memo(function GenericOutputTable(
accessor: String(i),
Cell(row) {
const value = row.value;
const formatter = columnHints?.get(h)?.formatter || formatNumber;
return (
<div>
<Popover2
Expand All @@ -498,7 +503,7 @@ export const GenericOutputTable = React.memo(function GenericOutputTable(
{numericColumnBraces[i] ? (
<BracedText
className="table-padding"
text={formatNumber(value)}
text={formatter(value)}
braces={numericColumnBraces[i]}
padFractionalPart
/>
Expand All @@ -516,7 +521,8 @@ export const GenericOutputTable = React.memo(function GenericOutputTable(
: undefined,
};
}),
groupHints,
queryResult.header,
columnHints,
)}
/>
)}
Expand Down

0 comments on commit 7313903

Please sign in to comment.