diff --git a/src/app/InfinityQuery.ts b/src/app/queryUtils.ts similarity index 97% rename from src/app/InfinityQuery.ts rename to src/app/queryUtils.ts index 64b3c074..1eb4a042 100644 --- a/src/app/InfinityQuery.ts +++ b/src/app/queryUtils.ts @@ -1,6 +1,6 @@ import { getTemplateSrv } from '@grafana/runtime'; import { ScopedVars } from '@grafana/data'; -import { InfinityQuery, InfinityQuerySources, InfinityQueryType, InfinityInstanceSettings } from './../types'; +import { InfinityQuery, InfinityQuerySources, InfinityQueryType, InfinityInstanceSettings } from '../types'; export const replaceVariables = (query: InfinityQuery, scopedVars: ScopedVars): InfinityQuery => { return { diff --git a/src/app/variablesQuery/Collection.spec.ts b/src/app/variablesQuery/Collection.spec.ts new file mode 100644 index 00000000..11dd3cef --- /dev/null +++ b/src/app/variablesQuery/Collection.spec.ts @@ -0,0 +1,47 @@ +import { SelectableValue } from '@grafana/data'; +import { CollectionVariable } from './Collection'; + +const data: Array<[string, string, Array>]> = [ + [ + 'it should return correct kv pairs and remove the variable keyword', + 'Collection(prod,pd,nonprod,np)', + [ + { value: 'pd', text: 'prod' }, + { value: 'np', text: 'nonprod' }, + ], + ], + [ + 'it should return correct kv pairs when even number of args passed', + 'prod,pd,nonprod,np', + [ + { value: 'pd', text: 'prod' }, + { value: 'np', text: 'nonprod' }, + ], + ], + [ + 'it should return correct kv pairs when value is missing', + 'prod,pd,nonprod,', + [ + { value: 'pd', text: 'prod' }, + { value: 'nonprod', text: 'nonprod' }, + ], + ], + [ + 'it should return correct kv pairs when odd number of args passed', + 'prod,pd,nonprod', + [ + { value: 'pd', text: 'prod' }, + { value: 'nonprod', text: 'nonprod' }, + ], + ], +]; +describe('Collection', () => { + it.each(data)('%s', (name, input, output) => { + let got = CollectionVariable(input); + expect(got.length).toBe(output.length); + output.forEach((o, index) => { + expect(got[index].value).toBe(o.value); + expect(got[index].text).toBe(o.text); + }); + }); +}); diff --git a/src/app/variablesQuery/Collection.ts b/src/app/variablesQuery/Collection.ts index 76a9b8e1..37e78f7e 100644 --- a/src/app/variablesQuery/Collection.ts +++ b/src/app/variablesQuery/Collection.ts @@ -1,11 +1,13 @@ import chunk from 'lodash/chunk'; import { SelectableValue } from '@grafana/data'; +import { replaceTokenFromVariable } from './utils'; export const CollectionVariable = (query: string): Array> => { + query = replaceTokenFromVariable(query, 'Collection'); let out = chunk(query.split(','), 2).map(value => { return { text: value[0], - value: value[1], + value: value[1] || value[0], }; }); return out; diff --git a/src/app/variablesQuery/CollectionLookup.spec.ts b/src/app/variablesQuery/CollectionLookup.spec.ts new file mode 100644 index 00000000..d26c89e9 --- /dev/null +++ b/src/app/variablesQuery/CollectionLookup.spec.ts @@ -0,0 +1,32 @@ +import { SelectableValue } from '@grafana/data'; +import { CollectionLookupVariable } from './CollectionLookup'; + +const data: Array<[string, string, Array>]> = [ + [ + 'it should return correct kv pairs and remove the variable keyword', + 'CollectionLookup(prod,pd,nonprod,np,nonprod)', + [{ value: 'np', text: 'np' }], + ], + [ + 'it should return correct kv pairs when even number of args passed', + 'prod,pd,nonprod,np,nonprod', + [{ value: 'np', text: 'np' }], + ], + [ + 'it should return correct kv pair when more than one arg matched', + 'prod,pd,nonprod,np,nonprod,foo,nonprod', + [{ value: 'np', text: 'np' }], + ], + ['it should return empty array when even number of args passed', 'prod,pd,nonprod,np', []], + ['it should return empty array when no args matched', 'prod,pd,nonprod,np,foo', []], +]; +describe('CollectionLookup', () => { + it.each(data)('%s', (name, input, output) => { + let got = CollectionLookupVariable(input); + expect(got.length).toBe(output.length); + output.forEach((o, index) => { + expect(got[index].value).toBe(o.value); + expect(got[index].text).toBe(o.text); + }); + }); +}); diff --git a/src/app/variablesQuery/CollectionLookup.ts b/src/app/variablesQuery/CollectionLookup.ts index 6c294e9c..387ef30d 100644 --- a/src/app/variablesQuery/CollectionLookup.ts +++ b/src/app/variablesQuery/CollectionLookup.ts @@ -1,8 +1,10 @@ import chunk from 'lodash/chunk'; import last from 'lodash/last'; import { SelectableValue } from '@grafana/data'; +import { replaceTokenFromVariable } from './utils'; export const CollectionLookupVariable = (query: string): Array> => { + query = replaceTokenFromVariable(query, 'CollectionLookup'); let querySplit = query.split(','); let chunkCollection = chunk(querySplit, 2); let out = chunkCollection diff --git a/src/app/variablesQuery/Join.spec.ts b/src/app/variablesQuery/Join.spec.ts new file mode 100644 index 00000000..e49f2af9 --- /dev/null +++ b/src/app/variablesQuery/Join.spec.ts @@ -0,0 +1,18 @@ +import { SelectableValue } from '@grafana/data'; +import { JoinVariable } from './Join'; + +const data: Array<[string, string, Array>]> = [ + ['it should return correct kv pairs and remove the variable keyword', 'Join(a,b,c)', [{ value: 'abc', text: 'abc' }]], + ['it should return correct kv pairs when no variable keyword passed', 'a,b,c', [{ value: 'abc', text: 'abc' }]], + ['it should return empty array when no args passed', '', []], +]; +describe('Join', () => { + it.each(data)('%s', (name, input, output) => { + let got = JoinVariable(input); + expect(got.length).toBe(output.length); + output.forEach((o, index) => { + expect(got[index].value).toBe(o.value); + expect(got[index].text).toBe(o.text); + }); + }); +}); diff --git a/src/app/variablesQuery/Join.ts b/src/app/variablesQuery/Join.ts index bfc4c187..ca68909c 100644 --- a/src/app/variablesQuery/Join.ts +++ b/src/app/variablesQuery/Join.ts @@ -1,11 +1,15 @@ import { SelectableValue } from '@grafana/data'; +import { replaceTokenFromVariable } from './utils'; export const JoinVariable = (query: string): Array> => { + query = replaceTokenFromVariable(query, 'Join'); let out = query.split(',').join(''); - return [ - { - value: out, - text: out, - }, - ]; + return out + ? [ + { + value: out, + text: out, + }, + ] + : []; }; diff --git a/src/app/variablesQuery/Random.spec.ts b/src/app/variablesQuery/Random.spec.ts new file mode 100644 index 00000000..862a4e0e --- /dev/null +++ b/src/app/variablesQuery/Random.spec.ts @@ -0,0 +1,33 @@ +import { SelectableValue } from '@grafana/data'; +import { RandomVariable } from './Random'; + +const data: Array<[string, string, Array>]> = [ + [ + 'it should return correct kv pairs and remove the variable keyword', + 'Random(a,b,c)', + [ + { value: 'a', text: 'a' }, + { value: 'b', text: 'b' }, + { value: 'c', text: 'c' }, + ], + ], + [ + 'it should return correct kv pairs and when no keyword passed', + 'a,b,c', + [ + { value: 'a', text: 'a' }, + { value: 'b', text: 'b' }, + { value: 'c', text: 'c' }, + ], + ], + ['it should return empty array when no args passed', '', []], +]; +describe('Random', () => { + it.each(data)('%s', (name, input, output) => { + let got = RandomVariable(input); + if (output.length > 0) { + expect(got.length).toBe(1); + expect(output).toContainEqual(got[0]); + } + }); +}); diff --git a/src/app/variablesQuery/Random.ts b/src/app/variablesQuery/Random.ts index 626f80f1..a2726975 100644 --- a/src/app/variablesQuery/Random.ts +++ b/src/app/variablesQuery/Random.ts @@ -1,7 +1,9 @@ import sample from 'lodash/sample'; import { SelectableValue } from '@grafana/data'; +import { replaceTokenFromVariable } from './utils'; export const RandomVariable = (query: string): Array> => { + query = replaceTokenFromVariable(query, 'Random'); let out = sample(query.split(',')); return [ { diff --git a/src/app/variablesQuery/VariableQuery.spec.ts b/src/app/variablesQuery/VariableQuery.spec.ts index 8e894e2f..4c63eff4 100644 --- a/src/app/variablesQuery/VariableQuery.spec.ts +++ b/src/app/variablesQuery/VariableQuery.spec.ts @@ -1,27 +1,5 @@ -import { replaceTokenFromVariable, migrateLegacyQuery } from './index'; -import { - InfinityQueryType, - VariableQuery, - VariableQueryType, - VariableTokenLegacy, - DefaultInfinityQuery, -} from './../../types'; - -const data: Array<[string, VariableTokenLegacy, string]> = [ - ['Collection(A,a,B,b)', 'Collection', 'A,a,B,b'], - ['CollectionLookup(A,a,B,b,A)', 'CollectionLookup', 'A,a,B,b,A'], - ['Random(A,a,B,b,A)', 'Random', 'A,a,B,b,A'], - ['Join(A,a,B,b,A)', 'Join', 'A,a,B,b,A'], - ['Something(A,a,B,b,A)', 'Join', 'Something(A,a,B,b,A)'], -]; - -data.forEach((item, index) => { - describe('replaceTokenFromVariable', () => { - it(`replaceTokenFromVariable ${index + 1} ${item[1]}`, () => { - expect(replaceTokenFromVariable(item[0], item[1])).toBe(item[2]); - }); - }); -}); +import { migrateLegacyQuery } from './index'; +import { InfinityQueryType, VariableQuery, VariableQueryType, DefaultInfinityQuery } from './../../types'; describe('migrateLegacyQuery', () => { it('Empty Query', () => { @@ -36,7 +14,7 @@ describe('migrateLegacyQuery', () => { expect(newQuery.queryType).toBe(VariableQueryType.Legacy); expect(newQuery.query).toBe(originalQuery); }); - it('Empty Inifinity Query', () => { + it('Empty Infinity Query', () => { let originalQuery: VariableQuery = { queryType: VariableQueryType.Infinity, query: '', @@ -46,7 +24,7 @@ describe('migrateLegacyQuery', () => { expect(newQuery.query).toBe(originalQuery.query); expect(newQuery.infinityQuery?.type).toBe(InfinityQueryType.CSV); }); - it('Inifinity Query', () => { + it('Infinity Query', () => { let originalQuery: VariableQuery = { queryType: VariableQueryType.Infinity, query: '', diff --git a/src/app/variablesQuery/index.ts b/src/app/variablesQuery/index.ts index b0c57907..55c67c09 100644 --- a/src/app/variablesQuery/index.ts +++ b/src/app/variablesQuery/index.ts @@ -2,10 +2,9 @@ import { flatten, defaultsDeep } from 'lodash'; import { SelectableValue } from '@grafana/data'; import { getTemplateSrv } from '@grafana/runtime'; import { InfinityProvider } from './../InfinityProvider'; -import { IsValidInfinityQuery, replaceVariables } from './../InfinityQuery'; +import { IsValidInfinityQuery, replaceVariables } from '../queryUtils'; import { InfinityQuery, - VariableTokenLegacy, InfinityInstanceSettings, VariableQuery, VariableQueryType, @@ -16,10 +15,6 @@ import { CollectionLookupVariable } from './CollectionLookup'; import { JoinVariable } from './Join'; import { RandomVariable } from './Random'; -export const replaceTokenFromVariable = (query: string, token: VariableTokenLegacy): string => { - return query.startsWith(`${token}(`) && query.endsWith(')') ? query.replace(`${token}(`, '').slice(0, -1) : query; -}; - const getTemplateVariablesFromResult = (res: any): Array> => { if (res.columns && res.columns.length > 0) { if (res.columns.length === 2) { @@ -108,17 +103,13 @@ export class LegacyVariableProvider implements VariableProvider { query(): Promise>> { return new Promise(resolve => { if (this.queryString.startsWith('Collection(') && this.queryString.endsWith(')')) { - let query = replaceTokenFromVariable(this.queryString, 'Collection'); - resolve(CollectionVariable(query)); + resolve(CollectionVariable(this.queryString)); } else if (this.queryString.startsWith('CollectionLookup(') && this.queryString.endsWith(')')) { - let query = replaceTokenFromVariable(this.queryString, 'CollectionLookup'); - resolve(CollectionLookupVariable(query)); + resolve(CollectionLookupVariable(this.queryString)); } else if (this.queryString.startsWith('Join(') && this.queryString.endsWith(')')) { - let query = replaceTokenFromVariable(this.queryString, 'Join'); - resolve(JoinVariable(query)); + resolve(JoinVariable(this.queryString)); } else if (this.queryString.startsWith('Random(') && this.queryString.endsWith(')')) { - let query = replaceTokenFromVariable(this.queryString, 'Random'); - resolve(RandomVariable(query)); + resolve(RandomVariable(this.queryString)); } else { resolve([]); } diff --git a/src/app/variablesQuery/utils.spec.ts b/src/app/variablesQuery/utils.spec.ts new file mode 100644 index 00000000..2fd522bc --- /dev/null +++ b/src/app/variablesQuery/utils.spec.ts @@ -0,0 +1,18 @@ +import { VariableTokenLegacy } from './../../types'; +import { replaceTokenFromVariable } from './utils'; + +const data: Array<[string, VariableTokenLegacy, string]> = [ + ['Collection(A,a,B,b)', 'Collection', 'A,a,B,b'], + ['CollectionLookup(A,a,B,b,A)', 'CollectionLookup', 'A,a,B,b,A'], + ['Random(A,a,B,b,A)', 'Random', 'A,a,B,b,A'], + ['Join(A,a,B,b,A)', 'Join', 'A,a,B,b,A'], + ['Something(A,a,B,b,A)', 'Join', 'Something(A,a,B,b,A)'], +]; + +data.forEach((item, index) => { + describe('replaceTokenFromVariable', () => { + it(`replaceTokenFromVariable ${index + 1} ${item[1]}`, () => { + expect(replaceTokenFromVariable(item[0], item[1])).toBe(item[2]); + }); + }); +}); diff --git a/src/app/variablesQuery/utils.ts b/src/app/variablesQuery/utils.ts new file mode 100644 index 00000000..5b103a0c --- /dev/null +++ b/src/app/variablesQuery/utils.ts @@ -0,0 +1,5 @@ +import { VariableTokenLegacy } from './../../types'; + +export const replaceTokenFromVariable = (query: string, token: VariableTokenLegacy): string => { + return query.startsWith(`${token}(`) && query.endsWith(')') ? query.replace(`${token}(`, '').slice(0, -1) : query; +}; diff --git a/src/datasource.ts b/src/datasource.ts index 18fdc7ab..eb80675b 100644 --- a/src/datasource.ts +++ b/src/datasource.ts @@ -4,7 +4,7 @@ import { DataQueryResponse, DataQueryRequest } from '@grafana/data'; import { DataSourceWithBackend } from '@grafana/runtime'; import { InfinityProvider } from './app/InfinityProvider'; import { SeriesProvider } from './app/SeriesProvider'; -import { replaceVariables } from './app/InfinityQuery'; +import { replaceVariables } from './app/queryUtils'; import { LegacyVariableProvider, InfinityVariableProvider, migrateLegacyQuery } from './app/variablesQuery'; import { InfinityQuery, diff --git a/src/editors/query.editor.tsx b/src/editors/query.editor.tsx index d374e541..81a3b757 100644 --- a/src/editors/query.editor.tsx +++ b/src/editors/query.editor.tsx @@ -3,7 +3,7 @@ import { defaultsDeep } from 'lodash'; import { QueryEditorProps } from '@grafana/data'; import { Datasource } from '../datasource'; import { InfinityQueryEditor } from './query/infinityQuery'; -import { getDefaultGlobalQueryID } from './../app/InfinityQuery'; +import { getDefaultGlobalQueryID } from '../app/queryUtils'; import { InfinityQuery, EditorMode, DefaultInfinityQuery } from '../types'; type EditorProps = QueryEditorProps;