feat: add support for range filters

This commit is contained in:
Wieland Schöbl
2020-11-30 16:21:04 +01:00
committed by Rainer Killinger
parent 785813c3fb
commit dcf7906f79
5 changed files with 466 additions and 136 deletions

View File

@@ -283,6 +283,53 @@ export interface ESTermFilter {
};
}
export interface ESGenericRange<T> {
/**
* Greater than field
*/
gt?: T;
/**
* Greater or equal than field
*/
gte?: T;
/**
* Less than field
*/
lt?: T;
/**
* Less or equal than field
*/
lte?: T;
}
interface ESGenericRangeFilter<G, T extends ESGenericRange<G>> {
/**
* Range filter definition
*/
range: {
[fieldName: string]: T;
};
}
export interface ESDateRange extends ESGenericRange<string> {
/**
* Optional date format override
*/
format?: string;
/**
* Optional timezone specifier
*/
time_zone?: string;
}
export type ESNumericRangeFilter = ESGenericRangeFilter<number, ESGenericRange<number>>;
export type ESDateRangeFilter = ESGenericRangeFilter<string, ESDateRange>;
export type ESRangeFilter = ESNumericRangeFilter | ESDateRangeFilter;
/**
* Checks if the parameter is of type ESTermsFilter
* @param agg the value to check
@@ -435,9 +482,9 @@ export interface ESFunctionScoreQueryFunction {
}
/**
* An elasticsearch ducet sort
* An elasticsearch generic sort
*/
export interface ESDucetSort {
export interface ESGenericSort {
[field: string]: string;
}

View File

@@ -26,13 +26,19 @@ import {
SCThingsField,
SCThingType,
} from '@openstapps/core';
import {ElasticsearchConfig, ScriptSort} from './common';
import {
ElasticsearchConfig,
ESDateRange,
ESDateRangeFilter, ESGenericRange, ESNumericRangeFilter,
ESRangeFilter,
ScriptSort,
} from './common';
import {
ESBooleanFilter,
ESBooleanFilterArguments,
ESDucetSort,
ESFunctionScoreQuery,
ESFunctionScoreQueryFunction,
ESGenericSort,
ESGeoDistanceFilter,
ESGeoDistanceFilterArguments,
ESGeoDistanceSort,
@@ -89,7 +95,8 @@ export function buildBooleanFilter(booleanFilter: SCSearchBooleanFilter): ESBool
* Converts Array of Filters to elasticsearch query-syntax
* @param filter A search filter for the retrieval of the data
*/
export function buildFilter(filter: SCSearchFilter): ESTermFilter | ESGeoDistanceFilter | ESBooleanFilter<unknown> {
export function buildFilter(filter: SCSearchFilter):
ESTermFilter | ESGeoDistanceFilter | ESBooleanFilter<unknown> | ESRangeFilter {
switch (filter.type) {
case 'value':
@@ -109,8 +116,7 @@ export function buildFilter(filter: SCSearchFilter): ESTermFilter | ESGeoDistanc
};
} = {};
startRangeFilter[filter.arguments.fromField] = {
lte: typeof filter.arguments.time !== 'undefined'
? filter.arguments.time : 'now',
lte: filter.arguments.time ?? 'now',
};
const endRangeFilter: {
@@ -122,8 +128,7 @@ export function buildFilter(filter: SCSearchFilter): ESTermFilter | ESGeoDistanc
};
} = {};
endRangeFilter[filter.arguments.toField] = {
gte: typeof filter.arguments.time !== 'undefined'
? filter.arguments.time : 'now',
gte: filter.arguments.time ?? 'now',
};
return {
@@ -176,6 +181,42 @@ export function buildFilter(filter: SCSearchFilter): ESTermFilter | ESGeoDistanc
return {
bool: buildBooleanFilter(filter),
};
case 'numeric range':
const numericRangeObject: ESGenericRange<number> = {};
if (filter.arguments.bounds.lowerBound?.mode === 'exclusive') {
numericRangeObject.gt = filter.arguments.bounds.lowerBound.limit;
} else if (filter.arguments.bounds.lowerBound?.mode === 'inclusive') {
numericRangeObject.gte = filter.arguments.bounds.lowerBound.limit;
}
if (filter.arguments.bounds.upperBound?.mode === 'exclusive') {
numericRangeObject.lt = filter.arguments.bounds.upperBound.limit;
} else if (filter.arguments.bounds.upperBound?.mode === 'inclusive') {
numericRangeObject.lte = filter.arguments.bounds.upperBound.limit;
}
const numericRangeFilter: ESNumericRangeFilter = {range: {}};
numericRangeFilter.range[filter.arguments.field] = numericRangeObject;
return numericRangeFilter;
case 'date range':
const dateRangeObject: ESDateRange = {};
if (filter.arguments.bounds.lowerBound?.mode === 'exclusive') {
dateRangeObject.lt = filter.arguments.bounds.lowerBound.limit;
} else if (filter.arguments.bounds.lowerBound?.mode === 'inclusive') {
dateRangeObject.lte = filter.arguments.bounds.lowerBound.limit;
}
if (filter.arguments.bounds.upperBound?.mode === 'exclusive') {
dateRangeObject.gt = filter.arguments.bounds.upperBound.limit;
} else if (filter.arguments.bounds.upperBound?.mode === 'inclusive') {
dateRangeObject.gte = filter.arguments.bounds.upperBound.limit;
}
dateRangeObject.format = filter.arguments.format;
dateRangeObject.time_zone = filter.arguments.timeZone;
const dateRangeFilter: ESDateRangeFilter = {range: {}};
dateRangeFilter.range[filter.arguments.field] = dateRangeObject;
return dateRangeFilter;
}
}
@@ -403,14 +444,19 @@ export function buildQuery(
*/
export function buildSort(
sorts: SCSearchSort[],
): Array<ESDucetSort | ESGeoDistanceSort | ScriptSort> {
): Array<ESGenericSort | ESGeoDistanceSort | ScriptSort> {
return sorts.map((sort) => {
switch (sort.type) {
case 'ducet':
const ducetSort: ESDucetSort = {};
ducetSort[`${sort.arguments.field}.sort`] = sort.order;
case 'generic':
const esGenericSort: ESGenericSort = {};
esGenericSort[sort.arguments.field] = sort.order;
return ducetSort;
return esGenericSort;
case 'ducet':
const esDucetSort: ESGenericSort = {};
esDucetSort[`${sort.arguments.field}.sort`] = sort.order;
return esDucetSort;
case 'distance':
const args: ESGeoDistanceSortArguments = {
mode: 'avg',