diff --git a/lib/src/app/data.dart b/lib/src/app/data.dart index f7b10484618..81dce31c74a 100644 --- a/lib/src/app/data.dart +++ b/lib/src/app/data.dart @@ -533,6 +533,36 @@ class DataClient { final response = await _datasetClient.listDatasetsByIDs(request); return response.datasets; } + + /// Gets the most recent tabular data captured from the specified data source, + /// as long as it was synced within the last year. + /// + /// For more information, see [Data Client API](https://docs.viam.com/appendix/apis/data-client/). + Future<(DateTime, DateTime, Map)?> getLatestTabularData( + String partId, + String resourceName, + String resourceSubtype, + String methodName, + ) async { + final request = GetLatestTabularDataRequest() + ..partId = partId + ..resourceName = resourceName + ..resourceSubtype = resourceSubtype + ..methodName = methodName; + + final response = await _dataClient.getLatestTabularData(request); + + if (!response.hasPayload() || !response.hasTimeCaptured() || !response.hasTimeSynced()) { + return null; + } + + return ( + response.timeCaptured.toDateTime(), + response.timeSynced.toDateTime(), + response.payload.toStruct().toMap(), + ); + } + } /// {@category Viam SDK} diff --git a/test/unit_test/app/data_client_test.dart b/test/unit_test/app/data_client_test.dart index fbe5ba0a1bf..65488cf598b 100644 --- a/test/unit_test/app/data_client_test.dart +++ b/test/unit_test/app/data_client_test.dart @@ -411,6 +411,47 @@ void main() { }); }); }); + + test('getLatestTabularData', () async { + final timeCaptured = DateTime(2023, 1, 1); + final timeSynced = DateTime(2023, 1, 2); + final payload = Struct()..fields.addAll({ + 'key': Value()..stringValue = 'value' + }); + + when(dataServiceClient.getLatestTabularData(any)).thenAnswer((_) => MockResponseFuture.value( + GetLatestTabularDataResponse() + ..timeCaptured = Timestamp.fromDateTime(timeCaptured) + ..timeSynced = Timestamp.fromDateTime(timeSynced) + ..payload = payload + )); + + final response = await dataClient.getLatestTabularData( + 'part-id', + 'resource-name', + 'resource-subtype', + 'method-name' + ); + + expect(response?.$1, equals(timeCaptured)); + expect(response?.$2, equals(timeSynced)); + expect(response?.$3, equals({'key': 'value'})); + + verify(dataServiceClient.getLatestTabularData(any)).called(1); + + // Test null response + when(dataServiceClient.getLatestTabularData(any)).thenAnswer((_) => + MockResponseFuture.value(GetLatestTabularDataResponse())); + + final nullResponse = await dataClient.getLatestTabularData( + 'part-id', + 'resource-name', + 'resource-subtype', + 'method-name' + ); + + expect(nullResponse, isNull); + }); group('Filter Utils Tests', () { test('setDateTimeCaptureInterval', () {