blob: 89cb2b65b12ee293218aa04fdbc365e5acf29c2b [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 React from 'react';
import { ExternalLink, Field } from '../components';
import { getLink } from '../links';
import { deepGet, EMPTY_ARRAY, oneOf, typeIs } from '../utils';
import { IngestionSpec } from './ingestion-spec';
export interface DruidFilter {
readonly type: string;
readonly [k: string]: any;
}
export interface DimensionFiltersWithRest {
dimensionFilters: DruidFilter[];
restFilter?: DruidFilter;
}
export function splitFilter(filter: DruidFilter | null): DimensionFiltersWithRest {
const inputAndFilters: DruidFilter[] = filter
? filter.type === 'and' && Array.isArray(filter.fields)
? filter.fields
: filter.type !== 'true'
? [filter]
: EMPTY_ARRAY
: EMPTY_ARRAY;
const dimensionFilters: DruidFilter[] = inputAndFilters.filter(
f => typeof getFilterDimension(f) === 'string',
);
const restFilters: DruidFilter[] = inputAndFilters.filter(
f => typeof getFilterDimension(f) !== 'string',
);
return {
dimensionFilters,
restFilter: restFilters.length
? restFilters.length > 1
? { type: 'and', filters: restFilters }
: restFilters[0]
: undefined,
};
}
export function joinFilter(
dimensionFiltersWithRest: DimensionFiltersWithRest,
): DruidFilter | undefined {
const { dimensionFilters, restFilter } = dimensionFiltersWithRest;
let newFields = dimensionFilters || EMPTY_ARRAY;
if (restFilter && restFilter.type) newFields = newFields.concat([restFilter]);
if (!newFields.length) return;
if (newFields.length === 1) return newFields[0];
return { type: 'and', fields: newFields };
}
export function getFilterDimension(filter: DruidFilter): string | undefined {
if (typeof filter.dimension === 'string') return filter.dimension;
if (filter.type === 'not' && filter.field) return getFilterDimension(filter.field);
return;
}
export const KNOWN_FILTER_TYPES = ['selector', 'in', 'interval', 'regex', 'like', 'not'];
export const FILTER_FIELDS: Field<DruidFilter>[] = [
{
name: 'type',
type: 'string',
required: true,
suggestions: KNOWN_FILTER_TYPES,
},
{
name: 'dimension',
type: 'string',
defined: typeIs('selector', 'in', 'interval', 'regex', 'like'),
required: true,
},
{
name: 'value',
type: 'string',
defined: typeIs('selector'),
required: true,
},
{
name: 'values',
type: 'string-array',
defined: typeIs('in'),
required: true,
},
{
name: 'intervals',
type: 'string-array',
defined: typeIs('interval'),
required: true,
placeholder: 'ex: 2020-01-01/2020-06-01',
},
{
name: 'pattern',
type: 'string',
defined: typeIs('regex', 'like'),
required: true,
},
{
name: 'field.type',
label: 'Sub-filter type',
type: 'string',
suggestions: ['selector', 'in', 'interval', 'regex', 'like'],
defined: typeIs('not'),
required: true,
},
{
name: 'field.dimension',
label: 'Sub-filter dimension',
type: 'string',
defined: typeIs('not'),
},
{
name: 'field.value',
label: 'Sub-filter value',
type: 'string',
defined: df => df.type === 'not' && deepGet(df, 'field.type') === 'selector',
},
{
name: 'field.values',
label: 'Sub-filter values',
type: 'string-array',
defined: df => df.type === 'not' && deepGet(df, 'field.type') === 'in',
},
{
name: 'field.intervals',
label: 'Sub-filter intervals',
type: 'string-array',
defined: df => df.type === 'not' && deepGet(df, 'field.type') === 'interval',
placeholder: 'ex: 2020-01-01/2020-06-01',
},
{
name: 'field.pattern',
label: 'Sub-filter pattern',
type: 'string',
defined: df => df.type === 'not' && oneOf(deepGet(df, 'field.type'), 'regex', 'like'),
},
];
export const FILTERS_FIELDS: Field<IngestionSpec>[] = [
{
name: 'spec.dataSchema.transformSpec.filter',
type: 'json',
height: '350px',
placeholder: '{ "type": "true" }',
info: (
<>
<p>
A Druid{' '}
<ExternalLink href={`${getLink('DOCS')}/querying/filters.html`}>
JSON filter expression
</ExternalLink>{' '}
to apply to the data.
</p>
<p>
Note that only the value that match the filter will be included. If you want to remove
some data values you must negate the filter.
</p>
</>
),
},
];