Skip to content

Commit 623a3cf

Browse files
committed
Add base.test.ts to tests luceneEscape/formatQuery functions
1 parent 65f7717 commit 623a3cf

File tree

2 files changed

+180
-8
lines changed

2 files changed

+180
-8
lines changed

src/datasource/base.test.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import { formatQuery, luceneEscape } from './base';
2+
3+
describe('BaseQuickwitDataSource', () => {
4+
describe('luceneEscape', () => {
5+
it('should not escape numeric values', () => {
6+
expect(luceneEscape('123')).toBe('123');
7+
expect(luceneEscape('123.45')).toBe('123.45');
8+
});
9+
10+
it('should escape special Lucene characters', () => {
11+
expect(luceneEscape('test+value')).toBe('test\\+value');
12+
expect(luceneEscape('test-value')).toBe('test\\-value');
13+
expect(luceneEscape('test:value')).toBe('test\\:value');
14+
expect(luceneEscape('test"value"')).toBe('test\\"value\\"');
15+
});
16+
17+
it('should handle empty strings', () => {
18+
expect(luceneEscape('')).toBe('');
19+
});
20+
21+
it('should handle strings with multiple special characters', () => {
22+
expect(luceneEscape('field:value AND other:test')).toBe('field\\:value\\ AND\\ other\\:test');
23+
});
24+
});
25+
26+
describe('formatQuery', () => {
27+
28+
describe('String values', () => {
29+
it('should return escaped string for simple string values', () => {
30+
const result = formatQuery('simple_value', { id: 'test_var' });
31+
expect(result).toBe('simple_value');
32+
});
33+
34+
it('should escape special characters in string values', () => {
35+
const result = formatQuery('value+with-special:chars', { id: 'test_var' });
36+
expect(result).toBe('value\\+with\\-special\\:chars');
37+
});
38+
39+
it('should not escape numeric strings', () => {
40+
const result = formatQuery('123', { id: 'test_var' });
41+
expect(result).toBe('123');
42+
});
43+
});
44+
45+
describe('Array values with valid field configuration', () => {
46+
const validVariable = {
47+
id: 'test_var',
48+
query: '{"field": "status"}'
49+
};
50+
51+
it('should format array values with field-specific OR syntax', () => {
52+
const result = formatQuery(['error', 'warning'], validVariable);
53+
expect(result).toBe('"error" OR status:"warning"');
54+
});
55+
56+
it('should handle single-item arrays', () => {
57+
const result = formatQuery(['error'], validVariable);
58+
expect(result).toBe('"error"');
59+
});
60+
61+
it('should escape special characters in array values', () => {
62+
const result = formatQuery(['error+critical', 'warning:high'], validVariable);
63+
expect(result).toBe('"error\\+critical" OR status:"warning\\:high"');
64+
});
65+
});
66+
67+
describe('Array values without field configuration', () => {
68+
it('should use IN syntax when variable.query is undefined', () => {
69+
const variable = { id: 'test_var' };
70+
const result = formatQuery(['error', 'warning'], variable);
71+
expect(result).toBe('IN ["error" "warning"]');
72+
});
73+
74+
it('should use IN syntax when variable.query is null', () => {
75+
const variable = { id: 'test_var', query: null };
76+
const result = formatQuery(['error', 'warning'], variable);
77+
expect(result).toBe('IN ["error" "warning"]');
78+
});
79+
80+
it('should use IN syntax when variable.query contains invalid JSON', () => {
81+
const variable = { id: 'test_var', query: 'not valid json' };
82+
const result = formatQuery(['error', 'warning'], variable);
83+
expect(result).toBe('IN ["error" "warning"]');
84+
});
85+
86+
it('should use IN syntax when variable.query is valid JSON but missing field', () => {
87+
const variable = { id: 'test_var', query: '{"other": "value"}' };
88+
const result = formatQuery(['error', 'warning'], variable);
89+
expect(result).toBe('IN ["error" "warning"]');
90+
});
91+
92+
it('should use IN syntax when field is not a string', () => {
93+
const variable = { id: 'test_var', query: '{"field": 123}' };
94+
const result = formatQuery(['error', 'warning'], variable);
95+
expect(result).toBe('IN ["error" "warning"]');
96+
});
97+
});
98+
99+
describe('Empty arrays', () => {
100+
it('should return __empty__ for empty arrays', () => {
101+
const variable = { id: 'test_var', query: '{"field": "status"}' };
102+
const result = formatQuery([], variable);
103+
expect(result).toBe('__empty__');
104+
});
105+
106+
it('should return __empty__ for empty arrays even without field config', () => {
107+
const variable = { id: 'test_var' };
108+
const result = formatQuery([], variable);
109+
expect(result).toBe('__empty__');
110+
});
111+
});
112+
113+
describe('Error handling and robustness', () => {
114+
it('should not throw when variable.query is undefined', () => {
115+
expect(() => {
116+
formatQuery(['test'], { id: 'test_var' });
117+
}).not.toThrow();
118+
});
119+
120+
it('should not throw when variable.query is malformed JSON', () => {
121+
expect(() => {
122+
formatQuery(['test'], { id: 'test_var', query: '{invalid json}' });
123+
}).not.toThrow();
124+
});
125+
126+
it('should not throw when variable.query is empty string', () => {
127+
expect(() => {
128+
formatQuery(['test'], { id: 'test_var', query: '' });
129+
}).not.toThrow();
130+
});
131+
132+
it('should handle non-string, non-array values', () => {
133+
const result = formatQuery(123 as any, { id: 'test_var' });
134+
expect(result).toBe('123');
135+
});
136+
137+
it('should handle boolean values', () => {
138+
const result = formatQuery(true as any, { id: 'test_var' });
139+
expect(result).toBe('true');
140+
});
141+
});
142+
143+
describe('Real-world scenarios', () => {
144+
it('should handle variables from template variable queries', () => {
145+
// Simulates a properly configured template variable
146+
const templateVariable = {
147+
id: 'log_level',
148+
query: '{"field": "level"}'
149+
};
150+
const result = formatQuery(['ERROR', 'WARN', 'INFO'], templateVariable);
151+
expect(result).toBe('"ERROR" OR level:"WARN" OR level:"INFO"');
152+
});
153+
154+
it('should handle variables without query configuration (legacy/simple variables)', () => {
155+
// Simulates a simple template variable without field configuration
156+
const simpleVariable = {
157+
id: 'service_names'
158+
};
159+
const result = formatQuery(['web-service', 'api-service'], simpleVariable);
160+
expect(result).toBe('IN ["web\\-service" "api\\-service"]');
161+
});
162+
163+
it('should handle variables with corrupted configuration', () => {
164+
// Simulates a variable with corrupted/invalid configuration
165+
const corruptedVariable = {
166+
id: 'corrupted_var',
167+
query: '{"field": undefined}' // Invalid JSON that might come from UI bugs
168+
};
169+
const result = formatQuery(['value1', 'value2'], corruptedVariable);
170+
expect(result).toBe('IN ["value1" "value2"]');
171+
});
172+
});
173+
});
174+
});

src/datasource/base.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ export class BaseQuickwitDataSource
359359
return finalQuery;
360360
}
361361
}
362-
function formatQuery(value: string | string[], variable: any): string {
362+
export function formatQuery(value: string | string[], variable: any): string {
363363
if (typeof value === 'string') {
364364
return luceneEscape(value);
365365
}
@@ -368,12 +368,10 @@ function formatQuery(value: string | string[], variable: any): string {
368368
return '__empty__';
369369
}
370370
let fieldName;
371-
if (variable.query) {
372-
try {
373-
fieldName = JSON.parse(variable.query).field;
374-
} catch (error) {
375-
console.warn('Could not parse variable.query', variable.query);
376-
}
371+
try {
372+
fieldName = variable.query ? JSON.parse(variable.query).field : undefined;
373+
} catch (e) {
374+
fieldName = undefined;
377375
}
378376
const quotedValues = value.map((val) => '"' + luceneEscape(val) + '"');
379377
// Quickwit query language does not support fieldName:(value1 OR value2 OR....)
@@ -395,7 +393,7 @@ function formatQuery(value: string | string[], variable: any): string {
395393
}
396394
}
397395

398-
function luceneEscape(value: string) {
396+
export function luceneEscape(value: string) {
399397
if (isNaN(+value) === false) {
400398
return value;
401399
}

0 commit comments

Comments
 (0)