Skip to content

Commit 8c542ee

Browse files
authored
Data-3395: Add GetLatestTabularData (#793)
1 parent 36f3f78 commit 8c542ee

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

src/viam/app/data_client.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
Filter,
3737
GetDatabaseConnectionRequest,
3838
GetDatabaseConnectionResponse,
39+
GetLatestTabularDataRequest,
40+
GetLatestTabularDataResponse,
3941
Order,
4042
RemoveBinaryDataFromDatasetByIDsRequest,
4143
RemoveBoundingBoxFromImageByIDRequest,
@@ -298,6 +300,40 @@ async def tabular_data_by_mql(self, organization_id: str, mql_binary: List[bytes
298300
response: TabularDataByMQLResponse = await self._data_client.TabularDataByMQL(request, metadata=self._metadata)
299301
return [bson.decode(bson_bytes) for bson_bytes in response.raw_data]
300302

303+
async def get_latest_tabular_data(self, part_id: str, resource_name: str, resource_subtype: str, method_name: str) -> Optional[Tuple[datetime, datetime, Dict[str, ValueTypes]]]:
304+
"""Gets the most recent tabular data captured from the specified data source, as long as it was synced within the last year.
305+
306+
::
307+
308+
time_captured, time_synced, payload = await data_client.get_latest_tabular_data(
309+
part_id="<PART-ID>",
310+
resource_name="<RESOURCE-NAME>",
311+
resource_subtype="<RESOURCE-SUBTYPE>",
312+
method_name="<METHOD-NAME>"
313+
)
314+
315+
316+
Args:
317+
part_id (str): The ID of the part that owns the data.
318+
resource_name (str): The name of the requested resource that captured the data.
319+
resource_subtype (str): The subtype of the requested resource that captured the data.
320+
method_name (str): The data capture method name.
321+
322+
Returns:
323+
Optional[Tuple[datetime, datetime, Dict[str, ValueTypes]]]: A return value of None means that data hasn't been synced yet for the data source
324+
or the most recently captured data was over a year ago, otherwise the returned tuple contains the following:
325+
datetime: The time captured,
326+
datetime: The time synced,
327+
Dict[str, ValueTypes]: The latest tabular data captured from the specified data source.
328+
For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
329+
"""
330+
331+
request = GetLatestTabularDataRequest(part_id=part_id, resource_name=resource_name, resource_subtype=resource_subtype, method_name=method_name)
332+
response: GetLatestTabularDataResponse = await self._data_client.GetLatestTabularData(request, metadata=self._metadata)
333+
if not response.payload:
334+
return None
335+
return response.time_captured.ToDatetime(), response.time_synced.ToDatetime(), struct_to_dict(response.payload)
336+
301337
async def binary_data_by_filter(
302338
self,
303339
filter: Optional[Filter] = None,

tests/mocks/services.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@
203203
DeleteTabularDataResponse,
204204
GetDatabaseConnectionRequest,
205205
GetDatabaseConnectionResponse,
206+
GetLatestTabularDataRequest,
207+
GetLatestTabularDataResponse,
206208
RemoveBinaryDataFromDatasetByIDsRequest,
207209
RemoveBinaryDataFromDatasetByIDsResponse,
208210
RemoveBoundingBoxFromImageByIDRequest,
@@ -1001,6 +1003,16 @@ async def TabularDataByMQL(self, stream: Stream[TabularDataByMQLRequest, Tabular
10011003
assert request is not None
10021004
await stream.send_message(TabularDataByMQLResponse(raw_data=[bson.encode(dict) for dict in self.tabular_query_response]))
10031005

1006+
async def GetLatestTabularData(self, stream: Stream[GetLatestTabularDataRequest, GetLatestTabularDataResponse]) -> None:
1007+
request = await stream.recv_message()
1008+
assert request is not None
1009+
self.part_id = request.part_id
1010+
self.resource_name = request.resource_name
1011+
self.resource_subtype = request.resource_subtype
1012+
self.method_name = request.method_name
1013+
timestamp = datetime_to_timestamp(datetime(2024, 12, 25))
1014+
data=dict_to_struct(self.tabular_response[0].data)
1015+
await stream.send_message(GetLatestTabularDataResponse(time_captured=timestamp, time_synced=timestamp, payload=data))
10041016

10051017
class MockDataset(DatasetServiceBase):
10061018
def __init__(self, create_response: str, datasets_response: Sequence[Dataset]):

tests/test_data_client.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,21 @@ async def test_tabular_data_by_mql(self, service: MockData):
164164
assert isinstance(response[0]["key1"], datetime)
165165
assert response == TABULAR_QUERY_RESPONSE
166166

167+
async def test_get_latest_tabular_data(self, service: MockData):
168+
async with ChannelFor([service]) as channel:
169+
client = DataClient(channel, DATA_SERVICE_METADATA)
170+
time = datetime(2024, 12, 25)
171+
response = await client.get_latest_tabular_data(PART_ID, COMPONENT_NAME, COMPONENT_TYPE, METHOD)
172+
assert response is not None
173+
time_captured, time_synced, payload = response
174+
assert service.part_id == PART_ID
175+
assert service.resource_name == COMPONENT_NAME
176+
assert service.resource_subtype == COMPONENT_TYPE
177+
assert service.method_name == METHOD
178+
assert payload == TABULAR_DATA
179+
assert time_captured == time
180+
assert time_synced == time
181+
167182
async def test_binary_data_by_filter(self, service: MockData):
168183
async with ChannelFor([service]) as channel:
169184
client = DataClient(channel, DATA_SERVICE_METADATA)

0 commit comments

Comments
 (0)