From 5072066eae5e336ad7976298195f07dd7870584a Mon Sep 17 00:00:00 2001 From: Jimmy Cheung <50635800+chejimmy@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:11:41 -0700 Subject: [PATCH] fix: removed unsupported time ordering from interpolated query; cache id of aggregates --- .../RelativeRangeCache.ts | 4 +- .../cacheIdUtils.test.ts | 13 ++-- src/RelativeRangeRequestCache/cacheIdUtils.ts | 2 + .../dataFrameUtils.test.ts | 1 - .../dataFrameUtils.ts | 16 +++-- src/RelativeRangeRequestCache/types.ts | 18 ++++- src/components/query/QualityAndOrderRow.tsx | 67 ++++++++++++------- src/components/query/QueryEditor.test.tsx | 2 - src/queryInfo.ts | 4 +- src/types.ts | 1 - 10 files changed, 80 insertions(+), 48 deletions(-) diff --git a/src/RelativeRangeRequestCache/RelativeRangeCache.ts b/src/RelativeRangeRequestCache/RelativeRangeCache.ts index 2bfdae90..975e5b50 100644 --- a/src/RelativeRangeRequestCache/RelativeRangeCache.ts +++ b/src/RelativeRangeRequestCache/RelativeRangeCache.ts @@ -2,7 +2,7 @@ import { DataFrame, DataQueryRequest, DataQueryResponse, LoadingState, TimeRange import { isTimeRangeCoveringStart } from 'timeRangeUtils'; import { SitewiseQuery } from 'types'; import { RequestCacheId, generateSiteWiseRequestCacheId } from './cacheIdUtils'; -import { CachedQueryInfo, TIME_SERIES_QUERY_TYPES } from './types'; +import { CachedQueryInfo, isTimeSeriesQueryType } from './types'; import { trimCachedQueryDataFramesAtStart, trimCachedQueryDataFramesEnding } from './dataFrameUtils'; import { getRefreshRequestRange, isCacheableTimeRange } from './timeRangeUtils'; @@ -174,7 +174,7 @@ export class RelativeRangeCache { return { ...request, range, - targets: targets.filter(({ queryType }) => TIME_SERIES_QUERY_TYPES.has(queryType)), + targets: targets.filter(({ queryType }) => isTimeSeriesQueryType(queryType)), }; } } diff --git a/src/RelativeRangeRequestCache/cacheIdUtils.test.ts b/src/RelativeRangeRequestCache/cacheIdUtils.test.ts index d8a2d33e..6b35b4ce 100644 --- a/src/RelativeRangeRequestCache/cacheIdUtils.test.ts +++ b/src/RelativeRangeRequestCache/cacheIdUtils.test.ts @@ -1,4 +1,4 @@ -import { QueryType, SiteWiseQuality, SiteWiseResolution, SiteWiseResponseFormat, SiteWiseTimeOrder } from 'types'; +import { AggregateType, QueryType, SiteWiseQuality, SiteWiseResolution, SiteWiseResponseFormat, SiteWiseTimeOrder } from 'types'; import { generateSiteWiseQueriesCacheId, generateSiteWiseRequestCacheId } from './cacheIdUtils'; import { dateTime } from '@grafana/data'; import { SitewiseQueriesUnion } from './types'; @@ -27,6 +27,7 @@ function createSiteWiseQuery(id: number): SitewiseQueriesUnion { hierarchyId: `mock-hierarchy-${id}`, modelId: `mock-model-${id}`, filter: 'ALL', + aggregates: [AggregateType.AVERAGE], }; } @@ -34,8 +35,8 @@ describe('generateSiteWiseQueriesCacheId()', () => { it('parses SiteWise Queries into cache Id', () => { const actualId = generateSiteWiseQueriesCacheId([createSiteWiseQuery(1), createSiteWiseQuery(2)]); const expectedId = JSON.stringify([ - '["PropertyValueHistory","us-west-2","table","mock-asset-id-1",["mock-asset-id-1"],"mock-property-id-1","mock-property-alias-1","ANY","AUTO",true,true,1000,"grafana-iot-sitewise-datasource","mock-datasource-uid","ASCENDING",true,"mock-hierarchy-1","mock-model-1","ALL"]', - '["PropertyValueHistory","us-west-2","table","mock-asset-id-2",["mock-asset-id-2"],"mock-property-id-2","mock-property-alias-2","ANY","AUTO",true,true,1000,"grafana-iot-sitewise-datasource","mock-datasource-uid","ASCENDING",true,"mock-hierarchy-2","mock-model-2","ALL"]' + '["PropertyValueHistory","us-west-2","table","mock-asset-id-1",["mock-asset-id-1"],"mock-property-id-1","mock-property-alias-1","ANY","AUTO",true,true,1000,"grafana-iot-sitewise-datasource","mock-datasource-uid","ASCENDING",true,"mock-hierarchy-1","mock-model-1","ALL",["AVERAGE"]]', + '["PropertyValueHistory","us-west-2","table","mock-asset-id-2",["mock-asset-id-2"],"mock-property-id-2","mock-property-alias-2","ANY","AUTO",true,true,1000,"grafana-iot-sitewise-datasource","mock-datasource-uid","ASCENDING",true,"mock-hierarchy-2","mock-model-2","ALL",["AVERAGE"]]' ]); expect(actualId).toEqual(expectedId); @@ -82,7 +83,7 @@ describe('generateSiteWiseQueriesCacheId()', () => { }; const actualId = generateSiteWiseQueriesCacheId([query]); const expectedId = JSON.stringify([ - '["ListAssets",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]', + '["ListAssets",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]', ]); expect(actualId).toEqual(expectedId); @@ -112,8 +113,8 @@ describe('generateSiteWiseRequestCacheId()', () => { const expectedId = JSON.stringify([ 'now-15m', JSON.stringify([ - '["PropertyValueHistory","us-west-2","table","mock-asset-id-1",["mock-asset-id-1"],"mock-property-id-1","mock-property-alias-1","ANY","AUTO",true,true,1000,"grafana-iot-sitewise-datasource","mock-datasource-uid","ASCENDING",true,"mock-hierarchy-1","mock-model-1","ALL"]', - '["PropertyValueHistory","us-west-2","table","mock-asset-id-2",["mock-asset-id-2"],"mock-property-id-2","mock-property-alias-2","ANY","AUTO",true,true,1000,"grafana-iot-sitewise-datasource","mock-datasource-uid","ASCENDING",true,"mock-hierarchy-2","mock-model-2","ALL"]' + '["PropertyValueHistory","us-west-2","table","mock-asset-id-1",["mock-asset-id-1"],"mock-property-id-1","mock-property-alias-1","ANY","AUTO",true,true,1000,"grafana-iot-sitewise-datasource","mock-datasource-uid","ASCENDING",true,"mock-hierarchy-1","mock-model-1","ALL",["AVERAGE"]]', + '["PropertyValueHistory","us-west-2","table","mock-asset-id-2",["mock-asset-id-2"],"mock-property-id-2","mock-property-alias-2","ANY","AUTO",true,true,1000,"grafana-iot-sitewise-datasource","mock-datasource-uid","ASCENDING",true,"mock-hierarchy-2","mock-model-2","ALL",["AVERAGE"]]' ]) ]); diff --git a/src/RelativeRangeRequestCache/cacheIdUtils.ts b/src/RelativeRangeRequestCache/cacheIdUtils.ts index c54636d0..b7aab375 100644 --- a/src/RelativeRangeRequestCache/cacheIdUtils.ts +++ b/src/RelativeRangeRequestCache/cacheIdUtils.ts @@ -40,6 +40,7 @@ function generateSiteWiseQueryCacheId(query: SitewiseQueriesUnion): QueryCacheId hierarchyId, modelId, filter, + aggregates, } = query; /* @@ -66,5 +67,6 @@ function generateSiteWiseQueryCacheId(query: SitewiseQueriesUnion): QueryCacheId hierarchyId, modelId, filter, + aggregates, ]); } diff --git a/src/RelativeRangeRequestCache/dataFrameUtils.test.ts b/src/RelativeRangeRequestCache/dataFrameUtils.test.ts index 048f7cab..19085dcb 100644 --- a/src/RelativeRangeRequestCache/dataFrameUtils.test.ts +++ b/src/RelativeRangeRequestCache/dataFrameUtils.test.ts @@ -153,7 +153,6 @@ describe('trimCachedQueryDataFrames', () => { it.each([ QueryType.PropertyAggregate, - QueryType.PropertyInterpolated, QueryType.PropertyValueHistory, ])('trims descending time series data of time-series type - "%s"', (queryType: QueryType) => { const cachedQueryInfo = { diff --git a/src/RelativeRangeRequestCache/dataFrameUtils.ts b/src/RelativeRangeRequestCache/dataFrameUtils.ts index 7cbb972e..f34eecb3 100644 --- a/src/RelativeRangeRequestCache/dataFrameUtils.ts +++ b/src/RelativeRangeRequestCache/dataFrameUtils.ts @@ -1,8 +1,12 @@ import { AbsoluteTimeRange, DataFrame } from '@grafana/data'; -import { CachedQueryInfo, TIME_SERIES_QUERY_TYPES } from './types'; +import { CachedQueryInfo, SitewiseQueriesUnion, isTimeOrderingQueryType, isTimeSeriesQueryType } from './types'; import { QueryType, SiteWiseTimeOrder } from 'types'; import { trimTimeSeriesDataFrame, trimTimeSeriesDataFrameReversedTime } from 'dataFrameUtils'; +function isRequestTimeDescending({queryType, timeOrdering}: SitewiseQueriesUnion) { + return isTimeOrderingQueryType(queryType) && timeOrdering === SiteWiseTimeOrder.DESCENDING; +} + /** * Trim cached query data frames based on the query type and time ordering for appending to the start of the data frame. * @@ -20,8 +24,10 @@ import { trimTimeSeriesDataFrame, trimTimeSeriesDataFrameReversedTime } from 'da export function trimCachedQueryDataFramesAtStart(cachedQueryInfos: CachedQueryInfo[], cacheRange: AbsoluteTimeRange): DataFrame[] { return cachedQueryInfos .map((cachedQueryInfo) => { - const { query: { queryType, timeOrdering }, dataFrame } = cachedQueryInfo; - if (timeOrdering === SiteWiseTimeOrder.DESCENDING) { + const { query, dataFrame } = cachedQueryInfo; + const { queryType } = query; + + if (isRequestTimeDescending(query)) { // Descending ordering data frame are added at the end of the request to respect the ordering // See related function - trimCachedQueryDataFramesEnding() return { @@ -40,7 +46,7 @@ export function trimCachedQueryDataFramesAtStart(cachedQueryInfos: CachedQueryIn }; } - if (TIME_SERIES_QUERY_TYPES.has(queryType)) { + if (isTimeSeriesQueryType(queryType)) { return trimTimeSeriesDataFrame({ dataFrame: cachedQueryInfo.dataFrame, timeRange: cacheRange, @@ -68,7 +74,7 @@ export function trimCachedQueryDataFramesAtStart(cachedQueryInfos: CachedQueryIn */ export function trimCachedQueryDataFramesEnding(cachedQueryInfos: CachedQueryInfo[], cacheRange: AbsoluteTimeRange): DataFrame[] { return cachedQueryInfos - .filter((cachedQueryInfo) => (cachedQueryInfo.query.timeOrdering === SiteWiseTimeOrder.DESCENDING)) + .filter(({query}) => (isRequestTimeDescending(query))) .map((cachedQueryInfo) => { return trimTimeSeriesDataFrameReversedTime({ dataFrame: cachedQueryInfo.dataFrame, diff --git a/src/RelativeRangeRequestCache/types.ts b/src/RelativeRangeRequestCache/types.ts index f4b134c9..c5dd54c8 100644 --- a/src/RelativeRangeRequestCache/types.ts +++ b/src/RelativeRangeRequestCache/types.ts @@ -1,13 +1,26 @@ import { DataFrame } from '@grafana/data'; -import { AssetPropertyValueHistoryQuery, ListAssetsQuery, ListAssociatedAssetsQuery, QueryType, SitewiseQuery } from 'types'; +import { AssetPropertyAggregatesQuery, AssetPropertyValueHistoryQuery, ListAssetsQuery, ListAssociatedAssetsQuery, QueryType, SitewiseQuery } from 'types'; -export const TIME_SERIES_QUERY_TYPES = new Set([ +const TIME_SERIES_QUERY_TYPES = new Set([ QueryType.PropertyAggregate, QueryType.PropertyInterpolated, QueryType.PropertyValue, QueryType.PropertyValueHistory, ]); +export function isTimeSeriesQueryType(queryType: QueryType) { + return TIME_SERIES_QUERY_TYPES.has(queryType); +} + +const TIME_ORDERING_QUERY_TYPES = new Set([ + QueryType.PropertyAggregate, + QueryType.PropertyValueHistory, +]); + +export function isTimeOrderingQueryType(queryType: QueryType) { + return TIME_ORDERING_QUERY_TYPES.has(queryType); +} + export interface CachedQueryInfo { query: Pick; dataFrame: DataFrame; @@ -15,6 +28,7 @@ export interface CachedQueryInfo { // Union of all SiteWise queries variants export type SitewiseQueriesUnion = SitewiseQuery + & Partial> & Partial> & Partial> & Partial> diff --git a/src/components/query/QualityAndOrderRow.tsx b/src/components/query/QualityAndOrderRow.tsx index 92a0243e..4ecf521f 100644 --- a/src/components/query/QualityAndOrderRow.tsx +++ b/src/components/query/QualityAndOrderRow.tsx @@ -9,6 +9,7 @@ import { SiteWiseResolution, isAssetPropertyInterpolatedQuery, SiteWiseResponseFormat, + QueryType, } from 'types'; import { InlineField, Select } from '@grafana/ui'; import { SitewiseQueryEditorProps } from './types'; @@ -62,11 +63,6 @@ export class QualityAndOrderRow extends PureComponent { onChange({ ...query, quality: sel.value }); }; - onOrderChange = (sel: SelectableValue) => { - const { onChange, query } = this.props; - onChange({ ...query, timeOrdering: sel.value }); - }; - onResponseFormatChange = (sel: SelectableValue) => { const { onChange, query } = this.props; onChange({ ...query, responseFormat: sel.value }); @@ -83,6 +79,44 @@ export class QualityAndOrderRow extends PureComponent { onChange({ ...query, maxPageAggregations: +event.currentTarget.value }); }; + timeOrderField = () => { + const { onChange, query } = this.props; + + // PropertyInterpolated has no time ordering support + if (query.queryType === QueryType.PropertyInterpolated) { + return null; + } + + const onOrderChange = (sel: SelectableValue) => { + onChange({ ...query, timeOrdering: sel.value }); + }; + + return this.props.newFormStylingEnabled ? ( + + v.value === query.timeOrdering) ?? ordering[0]} + onChange={onOrderChange} + isSearchable={true} + menuPlacement="bottom" + /> + + ); + }; + render() { const { query } = this.props; return this.props.newFormStylingEnabled ? ( @@ -98,17 +132,7 @@ export class QualityAndOrderRow extends PureComponent { menuPlacement="auto" /> - - { menuPlacement="bottom" /> - - { expect(screen.getByText('Asset')).toBeInTheDocument(); expect(screen.getByText('Property')).toBeInTheDocument(); expect(screen.getByText('Quality')).toBeInTheDocument(); - expect(screen.getByText('Time')).toBeInTheDocument(); expect(screen.getByText('Format')).toBeInTheDocument(); expect(screen.getByText('Resolution')).toBeInTheDocument(); }); @@ -125,7 +124,6 @@ describe('QueryEditor', () => { await waitFor(() => { expect(screen.getByText('Property Alias')).toBeInTheDocument(); expect(screen.getByText('Quality')).toBeInTheDocument(); - expect(screen.getByText('Time')).toBeInTheDocument(); expect(screen.getByText('Resolution')).toBeInTheDocument(); expect(screen.getByText('Format')).toBeInTheDocument(); }); diff --git a/src/queryInfo.ts b/src/queryInfo.ts index 357c4468..7ac5c9ab 100644 --- a/src/queryInfo.ts +++ b/src/queryInfo.ts @@ -38,9 +38,7 @@ export const siteWiseQueryTypes: QueryTypeInfo[] = [ label: 'Get interpolated property values', value: QueryType.PropertyInterpolated, description: `Gets interpolated values for an asset property.`, - defaultQuery: { - timeOrdering: 'ASCENDING', - } as AssetPropertyInterpolatedQuery, + defaultQuery: {} as AssetPropertyInterpolatedQuery, helpURL: 'https://docs.aws.amazon.com/iot-sitewise/latest/APIReference/API_GetInterpolatedAssetPropertyValues.html', }, { diff --git a/src/types.ts b/src/types.ts index c59f6fb2..b85baf6b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -187,7 +187,6 @@ export function isAssetPropertyAggregatesQuery(q?: SitewiseQuery): q is AssetPro */ export interface AssetPropertyInterpolatedQuery extends SitewiseQuery { queryType: QueryType.PropertyInterpolated; - timeOrdering?: SiteWiseTimeOrder; } export function isAssetPropertyInterpolatedQuery(q?: SitewiseQuery): q is AssetPropertyInterpolatedQuery {