blob: 91248c55209b6c270ac928288f2eb86b2ae2fcce [file] [log] [blame]
/*
* 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 type { IconName } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import type { SqlExpression } from '@druid-toolkit/query';
import { C, F } from '@druid-toolkit/query';
import type { Filter } from 'react-table';
import { addOrUpdate, caseInsensitiveContains, filterMap } from '../utils';
export const DEFAULT_TABLE_CLASS_NAME = '-striped -highlight padded-header';
export const STANDARD_TABLE_PAGE_SIZE = 50;
export const STANDARD_TABLE_PAGE_SIZE_OPTIONS = [50, 100, 200];
export const SMALL_TABLE_PAGE_SIZE = 25;
export const SMALL_TABLE_PAGE_SIZE_OPTIONS = [25, 50, 100];
export type FilterMode = '~' | '=' | '!=' | '<=' | '>=';
export const FILTER_MODES: FilterMode[] = ['~', '=', '!=', '<=', '>='];
export const FILTER_MODES_NO_COMPARISON: FilterMode[] = ['~', '=', '!='];
export function filterModeToIcon(mode: FilterMode): IconName {
switch (mode) {
case '~':
return IconNames.SEARCH;
case '=':
return IconNames.EQUALS;
case '!=':
return IconNames.NOT_EQUAL_TO;
case '<=':
return IconNames.LESS_THAN_OR_EQUAL_TO;
case '>=':
return IconNames.GREATER_THAN_OR_EQUAL_TO;
default:
return IconNames.BLANK;
}
}
export function filterModeToTitle(mode: FilterMode): string {
switch (mode) {
case '~':
return 'Search';
case '=':
return 'Equals';
case '!=':
return 'Not equals';
case '<=':
return 'Less than or equal';
case '>=':
return 'Greater than or equal';
default:
return '?';
}
}
interface FilterModeAndNeedle {
mode: FilterMode;
needle: string;
}
export function addFilter(
filters: readonly Filter[],
id: string,
mode: FilterMode,
needle: string,
): Filter[] {
return addOrUpdateFilter(filters, { id, value: combineModeAndNeedle(mode, needle) });
}
export function parseFilterModeAndNeedle(
filter: Filter,
loose = false,
): FilterModeAndNeedle | undefined {
const m = String(filter.value).match(/^(~|=|!=|<=|>=)?(.*)$/);
if (!m) return;
if (!loose && !m[2]) return;
const mode = (m[1] as FilterMode) || '~';
return {
mode,
needle: m[2] || '',
};
}
export function combineModeAndNeedle(mode: FilterMode, needle: string): string {
return `${mode}${needle}`;
}
export function addOrUpdateFilter(filters: readonly Filter[], filter: Filter): Filter[] {
return addOrUpdate(filters, filter, f => f.id);
}
export function booleanCustomTableFilter(filter: Filter, value: unknown): boolean {
if (value == null) return false;
const modeAndNeedle = parseFilterModeAndNeedle(filter);
if (!modeAndNeedle) return true;
const { mode, needle } = modeAndNeedle;
switch (mode) {
case '=':
return String(value) === needle;
case '!=':
return String(value) !== needle;
case '<=':
return String(value) <= needle;
case '>=':
return String(value) >= needle;
default:
return caseInsensitiveContains(String(value), needle);
}
}
export function sqlQueryCustomTableFilter(filter: Filter): SqlExpression | undefined {
const modeAndNeedle = parseFilterModeAndNeedle(filter);
if (!modeAndNeedle) return;
const { mode, needle } = modeAndNeedle;
const column = C(filter.id);
switch (mode) {
case '=':
return column.equal(needle);
case '!=':
return column.unequal(needle);
case '<=':
return column.lessThanOrEqual(needle);
case '>=':
return column.greaterThanOrEqual(needle);
default:
return F('LOWER', column).like(`%${needle.toLowerCase()}%`);
}
}
export function tableFiltersToString(tableFilters: Filter[]): string {
return tableFilters
.map(({ id, value }) => `${id}${value.replace(/[&%]/g, encodeURIComponent)}`)
.join('&');
}
export function stringToTableFilters(str: string | undefined): Filter[] {
if (!str) return [];
// '~' | '=' | '!=' | '<=' | '>=';
return filterMap(str.split('&'), clause => {
const m = /^(\w+)((?:~|=|!=|<=|>=).*)$/.exec(clause.replace(/%2[56]/g, decodeURIComponent));
if (!m) return;
return { id: m[1], value: m[2] };
});
}