Skip to content

Commit fbc1ce0

Browse files
RSDK-9503 accept bson queries in MQL function (#803)
1 parent f66b367 commit fbc1ce0

File tree

3 files changed

+42
-11
lines changed

3 files changed

+42
-11
lines changed

src/viam/app/data_client.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
StreamingDataCaptureUploadResponse,
8585
UploadMetadata,
8686
)
87-
from viam.utils import ValueTypes, create_filter, datetime_to_timestamp, struct_to_dict
87+
from viam.utils import ValueTypes, _alias_param, create_filter, datetime_to_timestamp, struct_to_dict
8888

8989
LOGGER = logging.getLogger(__name__)
9090

@@ -334,33 +334,36 @@ async def tabular_data_by_sql(self, organization_id: str, sql_query: str) -> Lis
334334
response: TabularDataBySQLResponse = await self._data_client.TabularDataBySQL(request, metadata=self._metadata)
335335
return [bson.decode(bson_bytes) for bson_bytes in response.raw_data]
336336

337-
async def tabular_data_by_mql(self, organization_id: str, mql_binary: List[bytes]) -> List[Dict[str, Union[ValueTypes, datetime]]]:
337+
@_alias_param("query", param_alias="mql_binary")
338+
async def tabular_data_by_mql(
339+
self, organization_id: str, query: Union[List[bytes], List[Dict[str, Any]]]
340+
) -> List[Dict[str, Union[ValueTypes, datetime]]]:
338341
"""Obtain unified tabular data and metadata, queried with MQL.
339342
340343
::
341344
342345
import bson
343346
344-
# using pymongo package (pip install pymongo)
345-
tabular_data = await data_client.tabular_data_by_mql(organization_id="<YOUR-ORG-ID>", mql_binary=[
346-
bson.encode({ '$match': { 'location_id': '<YOUR-LOCATION-ID>' } }),
347-
bson.encode({ "$limit": 5 })
347+
tabular_data = await data_client.tabular_data_by_mql(organization_id="<YOUR-ORG-ID>", mql_query=[
348+
{ '$match': { 'location_id': '<YOUR-LOCATION-ID>' } },
349+
{ "$limit": 5 }
348350
])
349351
350352
print(f"Tabular Data: {tabular_data}")
351353
352354
Args:
353355
organization_id (str): The ID of the organization that owns the data.
354356
You can obtain your organization ID from the Viam app's organization settings page.
355-
mql_binary (List[bytes]): The MQL query to run as a list of BSON queries. You can encode your bson queries using a library like
356-
`pymongo`.
357+
query (Union[List[bytes], List[Dict[str, Any]]]): The MQL query to run as a list of BSON queries.
358+
Note: Support for bytes will be removed in the future, so using a dictionary is preferred.
357359
358360
Returns:
359361
List[Dict[str, Union[ValueTypes, datetime]]]: An array of decoded BSON data objects.
360362
361363
For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
362364
"""
363-
request = TabularDataByMQLRequest(organization_id=organization_id, mql_binary=mql_binary)
365+
binary: List[bytes] = [bson.encode(query) for query in query] if isinstance(query[0], dict) else query # type: ignore
366+
request = TabularDataByMQLRequest(organization_id=organization_id, mql_binary=binary)
364367
response: TabularDataByMQLResponse = await self._data_client.TabularDataByMQL(request, metadata=self._metadata)
365368
return [bson.decode(bson_bytes) for bson_bytes in response.raw_data]
366369

src/viam/utils.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import sys
55
import threading
66
from datetime import datetime
7-
from typing import Any, Dict, List, Mapping, Optional, SupportsBytes, SupportsFloat, Type, TypeVar, Union
7+
from typing import Any, Callable, Dict, List, Mapping, Optional, SupportsBytes, SupportsFloat, Type, TypeVar, Union
88

99
from google.protobuf.json_format import MessageToDict, ParseDict
1010
from google.protobuf.message import Message
@@ -339,3 +339,28 @@ def create_filter(
339339
bbox_labels=bbox_labels,
340340
dataset_id=dataset_id if dataset_id else "",
341341
)
342+
343+
344+
def _alias_param(param_name: str, param_alias: str) -> Callable:
345+
"""
346+
Decorator for aliasing a param in a function. Intended for providing backwards compatibility on params with name changes.
347+
348+
Args:
349+
param_name: name of param in function to alias
350+
param_alias: alias that can be used for this param
351+
Returns:
352+
The input function, plus param alias.
353+
"""
354+
def decorator(func: Callable):
355+
@functools.wraps(func)
356+
def wrapper(*args, **kwargs):
357+
alias_param_value = kwargs.get(param_alias)
358+
if alias_param_value:
359+
# Only use alias value if param is not given.
360+
if not kwargs.get(param_name):
361+
kwargs[param_name] = alias_param_value
362+
del kwargs[param_alias]
363+
result = func(*args, **kwargs)
364+
return result
365+
return wrapper
366+
return decorator

tests/test_data_client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
)
7676
BBOXES = [BBOX]
7777
SQL_QUERY = "sql_query"
78-
MQL_BINARY = [b"mql_binary"]
78+
MQL_BINARY = [{"binary": "mql_binary"}]
7979
TABULAR_DATA = {"key": "value"}
8080
TABULAR_METADATA = CaptureMetadata(
8181
organization_id=ORG_ID,
@@ -180,6 +180,9 @@ async def test_tabular_data_by_mql(self, service: MockData):
180180
response = await client.tabular_data_by_mql(ORG_ID, MQL_BINARY)
181181
assert isinstance(response[0]["key1"], datetime)
182182
assert response == TABULAR_QUERY_RESPONSE
183+
response = await client.tabular_data_by_mql(ORG_ID, mql_binary=[b"mql_binary"])
184+
assert isinstance(response[0]["key1"], datetime)
185+
assert response == TABULAR_QUERY_RESPONSE
183186

184187
async def test_get_latest_tabular_data(self, service: MockData):
185188
async with ChannelFor([service]) as channel:

0 commit comments

Comments
 (0)