mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-09 22:51:02 +00:00
add sort option to GroupBy query builder
This commit is contained in:
parent
383b0a69d1
commit
46016fce4a
5 changed files with 188 additions and 6 deletions
|
|
@ -0,0 +1,8 @@
|
|||
.sortSelectRow {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
|
||||
.fieldSelect {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
118
lattice/src/App/QueryBuilder/GroupBySort/GroupBySort.tsx
Normal file
118
lattice/src/App/QueryBuilder/GroupBySort/GroupBySort.tsx
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
import React, { FC } from 'react';
|
||||
import { Select } from 'shared/Select';
|
||||
import css from './GroupBySort.module.scss';
|
||||
|
||||
export type SortOption = {
|
||||
sortValue: string;
|
||||
field?: string;
|
||||
};
|
||||
|
||||
type GroupBySortProps = {
|
||||
sort: SortOption[];
|
||||
fields: { label: string; value: string }[];
|
||||
showErrors: boolean;
|
||||
onUpdate: (sort: SortOption[]) => void;
|
||||
};
|
||||
|
||||
export const GroupBySort: FC<GroupBySortProps> = ({
|
||||
sort,
|
||||
fields,
|
||||
showErrors,
|
||||
onUpdate
|
||||
}) => {
|
||||
const hasPrimary = sort.length > 0;
|
||||
const primary = hasPrimary ? sort[0].sortValue.split(' ')[0] : '';
|
||||
const hasSecondary = sort.length > 1;
|
||||
const secondary = hasSecondary ? sort[1].sortValue.split(' ')[0] : '';
|
||||
const sortOptions = [
|
||||
{ label: 'Count (desc)', value: 'count desc' },
|
||||
{ label: 'Count (asc)', value: 'count asc' },
|
||||
{ label: 'Sum (desc)', value: 'sum desc' },
|
||||
{ label: 'Sum (asc)', value: 'sum asc' }
|
||||
];
|
||||
|
||||
const onPrimaryChange = (value: string) => {
|
||||
const split = value.split(' ');
|
||||
const isSum = split[0] === 'sum';
|
||||
const fieldValue = hasPrimary ? sort[0].field : undefined;
|
||||
|
||||
if (!hasSecondary) {
|
||||
onUpdate([{ sortValue: value, field: isSum ? fieldValue : undefined }]);
|
||||
} else if (hasSecondary && sort[1].sortValue.includes(split[0])) {
|
||||
onUpdate([{ sortValue: value, field: isSum ? fieldValue : undefined }]);
|
||||
} else {
|
||||
onUpdate([
|
||||
{ sortValue: value, field: isSum ? fieldValue : undefined },
|
||||
sort[1]
|
||||
]);
|
||||
}
|
||||
};
|
||||
const onSecondaryChange = (value: string) => {
|
||||
let sortOp = { sortValue: value };
|
||||
|
||||
if (hasSecondary) {
|
||||
sortOp = { ...sort[1], ...sortOp };
|
||||
}
|
||||
onUpdate([sort[0], sortOp]);
|
||||
};
|
||||
|
||||
const onUpdateSumField = (isPrimary: boolean, value: string) => {
|
||||
let clone = [...sort];
|
||||
|
||||
if (isPrimary) {
|
||||
clone[0].field = value;
|
||||
} else {
|
||||
clone[1].field = value;
|
||||
}
|
||||
|
||||
onUpdate(clone);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={css.sortSelectRow}>
|
||||
<Select
|
||||
label="Primary Sort"
|
||||
value={hasPrimary ? sort[0].sortValue : ''}
|
||||
options={sortOptions}
|
||||
onChange={(value) => onPrimaryChange(value)}
|
||||
/>
|
||||
|
||||
{primary.includes('sum') ? (
|
||||
<Select
|
||||
className={css.fieldSelect}
|
||||
label="Field"
|
||||
value={sort[0].field ? sort[0].field : ''}
|
||||
options={fields}
|
||||
onChange={(value) => onUpdateSumField(true, value)}
|
||||
error={showErrors ? !sort[0].field : false}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{hasPrimary ? (
|
||||
<div className={css.sortSelectRow}>
|
||||
<Select
|
||||
label="Secondary Sort"
|
||||
value={hasSecondary ? sort[1].sortValue : ''}
|
||||
options={sortOptions.filter(
|
||||
(option) => !option.value.includes(primary)
|
||||
)}
|
||||
onChange={(value) => onSecondaryChange(value)}
|
||||
/>
|
||||
|
||||
{secondary.includes('sum') ? (
|
||||
<Select
|
||||
className={css.fieldSelect}
|
||||
label="Field"
|
||||
value={sort[0].field ? sort[0].field : ''}
|
||||
options={fields}
|
||||
onChange={(value) => onUpdateSumField(false, value)}
|
||||
error={showErrors ? !sort[1].field : false}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
1
lattice/src/App/QueryBuilder/GroupBySort/index.ts
Normal file
1
lattice/src/App/QueryBuilder/GroupBySort/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './GroupBySort';
|
||||
|
|
@ -30,6 +30,7 @@ import { ResultType } from 'App/Query/QueryContainer';
|
|||
import { RowCall } from './RowCall';
|
||||
import { SavedQueries } from './SavedQueries';
|
||||
import { Select } from 'shared/Select';
|
||||
import { GroupBySort, SortOption } from './GroupBySort';
|
||||
import { stringifyRowData } from './stringifyRowData';
|
||||
import css from './QueryBuilder.module.scss';
|
||||
|
||||
|
|
@ -47,7 +48,12 @@ type QueryBuilderProps = {
|
|||
columns: string[],
|
||||
operator?: Operator
|
||||
) => void;
|
||||
onRunGroupBy: (table: any, rowsData: RowsCallType, filter?: string) => void;
|
||||
onRunGroupBy: (
|
||||
table: any,
|
||||
rowsData: RowsCallType,
|
||||
sort: SortOption[],
|
||||
filter?: string
|
||||
) => void;
|
||||
onExternalLookup: (table: string, columns: number[]) => void;
|
||||
onClear: () => void;
|
||||
};
|
||||
|
|
@ -95,6 +101,7 @@ export const QueryBuilder: FC<QueryBuilderProps> = ({
|
|||
);
|
||||
const [groupByFilters, setGroupByFilters] = useState<any[]>([]);
|
||||
const [filter, setFilter] = useState<string>();
|
||||
const [sort, setSort] = useState<SortOption[]>([]);
|
||||
const colSizes = JSON.parse(
|
||||
localStorage.getItem('builderColSizes') || '[25, 75]'
|
||||
);
|
||||
|
|
@ -231,10 +238,25 @@ export const QueryBuilder: FC<QueryBuilderProps> = ({
|
|||
|
||||
const onRunClick = () => {
|
||||
if (operation === 'GroupBy') {
|
||||
const isInvalid = groupByCall.primary ? false : true;
|
||||
let isInvalid = false;
|
||||
if (!groupByCall.primary) {
|
||||
isInvalid = true;
|
||||
} else if (
|
||||
sort.length > 0 &&
|
||||
sort[0].sortValue.includes('sum') &&
|
||||
!sort[0].field
|
||||
) {
|
||||
isInvalid = true;
|
||||
} else if (
|
||||
sort.length > 1 &&
|
||||
sort[1].sortValue.includes('sum') &&
|
||||
!sort[1].field
|
||||
) {
|
||||
isInvalid = true;
|
||||
}
|
||||
setHasInvalid(isInvalid);
|
||||
if (!isInvalid) {
|
||||
onRunGroupBy(selectedTable, groupByCall, filter);
|
||||
onRunGroupBy(selectedTable, groupByCall, sort, filter);
|
||||
}
|
||||
} else {
|
||||
const { cleanRowCalls, isInvalid } = cleanupRows();
|
||||
|
|
@ -328,7 +350,7 @@ export const QueryBuilder: FC<QueryBuilderProps> = ({
|
|||
|
||||
if (!isInvalid) {
|
||||
if (operation === 'GroupBy') {
|
||||
onRunGroupBy(tableDetails, groupByCall, filter);
|
||||
onRunGroupBy(tableDetails, groupByCall, sort, filter);
|
||||
} else {
|
||||
onQuery(tableDetails, operation, rowCalls, columns, operator);
|
||||
}
|
||||
|
|
@ -659,6 +681,22 @@ export const QueryBuilder: FC<QueryBuilderProps> = ({
|
|||
for {selectedTable.name} with at least one field constraint.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={css.sortHeader}>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
Sort (optional)
|
||||
</Typography>
|
||||
<GroupBySort
|
||||
sort={sort}
|
||||
onUpdate={setSort}
|
||||
fields={selectedTable.fields
|
||||
.filter((field) => field.options.type === 'int')
|
||||
.map((field) => {
|
||||
return { label: field.name, value: field.name };
|
||||
})}
|
||||
showErrors={hasInvalid}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className={css.newGroup}>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { ResultType } from 'App/Query/QueryContainer';
|
|||
import { queryPQL } from 'services/grpcServices';
|
||||
import { grpc } from '@improbable-eng/grpc-web';
|
||||
import { RowResponse } from 'proto/pilosa_pb';
|
||||
import { SortOption } from './GroupBySort';
|
||||
import { stringifyRowData } from './stringifyRowData';
|
||||
import css from './QueryBuilderContainer.module.scss';
|
||||
|
||||
|
|
@ -160,6 +161,7 @@ export const QueryBuilderContainer = () => {
|
|||
const onRunGroupBy = (
|
||||
table: any,
|
||||
rowsData: RowsCallType,
|
||||
sort: SortOption[],
|
||||
filter?: string
|
||||
) => {
|
||||
streamingResults = {
|
||||
|
|
@ -174,11 +176,26 @@ export const QueryBuilderContainer = () => {
|
|||
};
|
||||
startTime = moment();
|
||||
setLoading(true);
|
||||
let sortString = '';
|
||||
let aggregateString = '';
|
||||
if (sort.length > 0) {
|
||||
sortString = sort[0].sortValue;
|
||||
if (sort[0].sortValue.includes('sum')) {
|
||||
aggregateString = `, aggregate=Sum(field=${sort[0].field})`;
|
||||
}
|
||||
if (sort.length > 1) {
|
||||
sortString = `${sortString}, ${sort[1].sortValue}`;
|
||||
if (sort[1].sortValue.includes('sum')) {
|
||||
aggregateString = `, aggregate=Sum(field=${sort[1].field})`;
|
||||
}
|
||||
}
|
||||
sortString = `, sort="${sortString}"`;
|
||||
}
|
||||
const filterString =
|
||||
filter && filter.length > 0 ? `, filter=${filter}` : '';
|
||||
const query = rowsData.secondary
|
||||
? `GroupBy(Rows(${rowsData.primary}), Rows(${rowsData.secondary})${filterString})`
|
||||
: `GroupBy(Rows(${rowsData.primary})${filterString})`;
|
||||
? `GroupBy(Rows(${rowsData.primary}), Rows(${rowsData.secondary})${filterString}${sortString}${aggregateString})`
|
||||
: `GroupBy(Rows(${rowsData.primary})${filterString}${sortString}${aggregateString})`;
|
||||
streamingResults.query = query;
|
||||
queryPQL(table.name, query, handleQueryMessages, handleQueryEnd);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue