Skip to content

Commit

Permalink
fix(tag): convert strings to numbers for tag current value (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
mure authored Sep 18, 2023
1 parent eab6a44 commit f0d2685
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
61 changes: 45 additions & 16 deletions src/datasources/tag/TagDataSource.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('queries', () => {

expect(result.data).toEqual([
{
fields: [{ name: 'my.tag', values: ['3.14'] }],
fields: [{ name: 'my.tag', values: [3.14] }],
refId: 'A',
},
]);
Expand All @@ -64,27 +64,27 @@ describe('queries', () => {

const result = await ds.query({ ...defaultQueryOptions, targets: [{ path: 'my.tag' } as TagQuery] });

expect(result.data[0]).toHaveProperty('fields', [{ name: 'my.tag', values: ['3.14'] }]);
expect(result.data[0]).toHaveProperty('fields', [{ name: 'my.tag', values: [3.14] }]);
});

test('uses displayName property', async () => {
backendSrv.fetch.mockReturnValue(createQueryTagsResponse({ tag: { properties: { displayName: 'My cool tag' } } }));
backendSrv.fetch.mockReturnValue(createQueryTagsResponse({ properties: { displayName: 'My cool tag' } }));

const result = await ds.query(buildQuery({ path: 'my.tag' }));

expect(result.data[0].fields[0]).toHaveProperty('name', 'My cool tag');
});

test('handles null tag properties', async () => {
backendSrv.fetch.mockReturnValue(createQueryTagsResponse({ tag: { properties: null } }));
backendSrv.fetch.mockReturnValue(createQueryTagsResponse({ properties: null }));

const result = await ds.query(buildQuery({ path: 'my.tag' }));

expect(result.data[0]).toHaveProperty('fields', [{ name: 'my.tag', values: ['3.14'] }]);
expect(result.data[0]).toHaveProperty('fields', [{ name: 'my.tag', values: [3.14] }]);
});

test('handles tag with no current value', async () => {
backendSrv.fetch.mockReturnValue(createQueryTagsResponse({ current: null }));
backendSrv.fetch.mockReturnValue(createQueryTagsResponse({}, null));

const result = await ds.query(buildQuery({ path: 'my.tag' }));

Expand All @@ -94,25 +94,48 @@ describe('queries', () => {
test('multiple targets - skips invalid queries', async () => {
backendSrv.fetch
.calledWith(requestMatching({ data: { filter: 'path = "my.tag1"' } }))
.mockReturnValue(createQueryTagsResponse({ tag: { path: 'my.tag1' } }));
.mockReturnValue(createQueryTagsResponse({ path: 'my.tag1' }));
backendSrv.fetch
.calledWith(requestMatching({ data: { filter: 'path = "my.tag2"' } }))
.mockReturnValue(createQueryTagsResponse({ tag: { path: 'my.tag2' }, current: { value: { value: 'foo' } } }));
.mockReturnValue(createQueryTagsResponse({ path: 'my.tag2' }, { value: { value: '41.3' } }));

const result = await ds.query(buildQuery({ path: 'my.tag1' }, { path: '' }, { path: 'my.tag2' }));

expect(result.data).toEqual([
{
fields: [{ name: 'my.tag1', values: ['3.14'] }],
fields: [{ name: 'my.tag1', values: [3.14] }],
refId: 'A',
},
{
fields: [{ name: 'my.tag2', values: ['foo'] }],
fields: [{ name: 'my.tag2', values: [41.3] }],
refId: 'C',
},
]);
});

test('current value for all data types', async () => {
backendSrv.fetch
.mockReturnValueOnce(createQueryTagsResponse({ datatype: 'INT', path: 'tag1' }, { value: { value: '3' } }))
.mockReturnValueOnce(createQueryTagsResponse({ datatype: 'DOUBLE', path: 'tag2' }, { value: { value: '3.3' } }))
.mockReturnValueOnce(createQueryTagsResponse({ datatype: 'STRING', path: 'tag3' }, { value: { value: 'foo' } }))
.mockReturnValueOnce(createQueryTagsResponse({ datatype: 'BOOLEAN', path: 'tag4' }, { value: { value: 'True' } }))
.mockReturnValueOnce(
createQueryTagsResponse({ datatype: 'U_INT64', path: 'tag5' }, { value: { value: '2147483648' } })
);

const result = await ds.query(
buildQuery({ path: 'tag1' }, { path: 'tag2' }, { path: 'tag3' }, { path: 'tag4' }, { path: 'tag5' })
);

expect(result.data.map(frames => frames.fields[0])).toEqual([
{ name: 'tag1', values: [3] },
{ name: 'tag2', values: [3.3] },
{ name: 'tag3', values: ['foo'] },
{ name: 'tag4', values: ['True'] },
{ name: 'tag5', values: [2147483648] },
]);
});

test('throw when no tags matched', async () => {
backendSrv.fetch.mockReturnValue(createFetchResponse({ tagsWithValues: [] }));

Expand Down Expand Up @@ -211,7 +234,7 @@ describe('queries', () => {
});

test('filters by workspace if provided', async () => {
backendSrv.fetch.mockReturnValueOnce(createQueryTagsResponse({ tag: { workspace_id: '2' } }));
backendSrv.fetch.mockReturnValueOnce(createQueryTagsResponse({ workspace_id: '2' }));
backendSrv.fetch.mockReturnValueOnce(createTagHistoryResponse('my.tag', 'DOUBLE', []));

await ds.query(buildQuery({ type: TagQueryType.History, path: 'my.tag', workspace: '2' }));
Expand Down Expand Up @@ -243,13 +266,19 @@ describe('queries', () => {
});
});

function createQueryTagsResponse(tag?: DeepPartial<TagWithValue>) {
function createQueryTagsResponse(
tag?: DeepPartial<TagWithValue['tag']>,
current?: DeepPartial<TagWithValue['current']>
) {
return createFetchResponse({
tagsWithValues: [
_.defaultsDeep(tag, {
current: { value: { value: '3.14' } },
tag: { path: 'my.tag', properties: {}, workspace_id: '1' },
}),
_.defaultsDeep(
{ tag, current },
{
current: { value: { value: '3.14' } },
tag: { datatype: 'DOUBLE', path: 'my.tag', properties: {}, workspace_id: '1' },
}
),
],
});
}
Expand Down
8 changes: 4 additions & 4 deletions src/datasources/tag/TagDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class TagDataSource extends DataSourceBase<TagQuery> {
if (query.type === TagQueryType.Current) {
return {
refId: query.refId,
fields: [{ name, values: [current?.value.value] }],
fields: [{ name, values: [this.convertTagValue(tag.datatype, current?.value.value)] }],
};
}

Expand Down Expand Up @@ -75,12 +75,12 @@ export class TagDataSource extends DataSourceBase<TagQuery> {
const { type, values } = response.results[path];
return {
datetimes: values.map(v => dateTime(v.timestamp).valueOf()),
values: values.map(v => this.convertTagValue(v.value, type)),
values: values.map(v => this.convertTagValue(type, v.value)),
};
}

private convertTagValue(value: string, type: string) {
return type === 'DOUBLE' || type === 'INT' || type === 'U_INT64' ? Number(value) : value;
private convertTagValue(type: string, value?: string) {
return value && ['DOUBLE', 'INT', 'U_INT64'].includes(type) ? Number(value) : value;
}

shouldRunQuery(query: TagQuery): boolean {
Expand Down
1 change: 1 addition & 0 deletions src/datasources/tag/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface TagQuery extends DataQuery {
export interface TagWithValue {
current: { value: { value: string } } | null;
tag: {
datatype: string;
path: string;
properties: { displayName?: string } | null;
workspace_id: string;
Expand Down

0 comments on commit f0d2685

Please sign in to comment.