Skip to content

Commit bcd86cf

Browse files
committed
Fix interpolation of template variable with array of values.
1 parent 6ab4f14 commit bcd86cf

File tree

1 file changed

+44
-9
lines changed

1 file changed

+44
-9
lines changed

src/datasource.ts

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ export class QuickwitDataSource
147147

148148
async importFromAbstractQueries(abstractQueries: AbstractQuery[]): Promise<ElasticsearchQuery[]> {
149149
// FIXME: this function does not seem to be used.
150-
console.log("importFromAbstractQueries");
151150
return abstractQueries.map((abstractQuery) => this.languageProvider.importFromAbstractQuery(abstractQuery));
152151
}
153152

@@ -432,24 +431,23 @@ export class QuickwitDataSource
432431
const range = options?.range;
433432
const parsedQuery = JSON.parse(query);
434433
if (query) {
435-
if (parsedQuery.find === 'fields') {
436-
parsedQuery.type = this.interpolateLuceneQuery(parsedQuery.type);
437-
return lastValueFrom(this.getFields(parsedQuery.type, range));
438-
}
439-
434+
// Interpolation of variables with a list of values for which we don't
435+
// know the field name is not supported yet.
436+
// if (parsedQuery.find === 'fields') {
437+
// parsedQuery.type = this.interpolateLuceneQuery(parsedQuery.type);
438+
// return lastValueFrom(this.getFields(parsedQuery.type, range));
439+
// }
440440
if (parsedQuery.find === 'terms') {
441441
parsedQuery.field = this.interpolateLuceneQuery(parsedQuery.field);
442442
parsedQuery.query = this.interpolateLuceneQuery(parsedQuery.query);
443-
console.log(parsedQuery);
444443
return lastValueFrom(this.getTerms(parsedQuery, range));
445444
}
446445
}
447-
448446
return Promise.resolve([]);
449447
}
450448

451449
interpolateLuceneQuery(queryString: string, scopedVars?: ScopedVars) {
452-
return this.templateSrv.replace(queryString, scopedVars, 'lucene');
450+
return this.templateSrv.replace(queryString, scopedVars, formatQuery);
453451
}
454452

455453
interpolateVariablesInQueries(queries: ElasticsearchQuery[], scopedVars: ScopedVars | {}): ElasticsearchQuery[] {
@@ -695,3 +693,40 @@ function getLogLevelFromKey(dataframe: DataFrame): LogLevel {
695693
}
696694
return LogLevel.unknown;
697695
}
696+
697+
function formatQuery(value: string | string[], variable: any): string {
698+
if (typeof value === 'string') {
699+
return luceneEscape(value);
700+
}
701+
if (Array.isArray(value)) {
702+
if (value.length === 0) {
703+
return '__empty__';
704+
}
705+
const fieldName = JSON.parse(variable.query).field;
706+
const quotedValues = value.map((val) => '"' + luceneEscape(val) + '"');
707+
// Quickwit query language does not support fieldName:(value1 OR value2 OR....)
708+
// like lucene does.
709+
// When we know the fieldName, we can directly generate a query
710+
// fieldName:value1 OR fieldName:value2 OR ...
711+
// But when we don't know the fieldName, the simplest is to generate a query
712+
// with the IN operator. Unfortunately, IN operator does not work on JSON field.
713+
// TODO: fix that by using doing a regex on queryString to find the fieldName.
714+
// Note that variable.id gives the name of the template variable to interpolate,
715+
// so if we have `fieldName:${variable.id}` in the queryString, we can isolate
716+
// the fieldName.
717+
if (typeof fieldName !== 'string') {
718+
return 'IN [' + quotedValues.join(' ') + ']';
719+
}
720+
return quotedValues.join(' OR ' + fieldName + ':');
721+
} else {
722+
return luceneEscape(`${value}`);
723+
}
724+
}
725+
726+
function luceneEscape(value: string) {
727+
if (isNaN(+value) === false) {
728+
return value;
729+
}
730+
731+
return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, '\\$1');
732+
}

0 commit comments

Comments
 (0)