Skip to content

Commit

Permalink
feat: Add query-tables method (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
mure committed Nov 28, 2022
1 parent 491892e commit 8b8afef
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 12 deletions.
3 changes: 2 additions & 1 deletion nisystemlink/clients/core/_uplink/_base_client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# mypy: disable-error-code = misc

import json
from typing import Dict, Optional, Type

from nisystemlink.clients import core
Expand Down Expand Up @@ -41,7 +42,7 @@ def _handle_http_status(response: Response) -> Optional[Response]:
@dumps.to_json(JsonModel)
def _deserialize_model(model_cls: Type[JsonModel], model_instance: JsonModel) -> Dict:
"""Turns a :class:`.JsonModel` instance into a dictionary for serialization."""
return model_instance.dict(by_alias=True, exclude_unset=True)
return json.loads(model_instance.json(by_alias=True, exclude_unset=True))


class BaseClient(Consumer):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from ._json_model import JsonModel


class PagedResult(JsonModel):
continuation_token: Optional[str]
class WithPaging(JsonModel):
continuation_token: Optional[str] = None
"""A token which allows the user to resume a query at the next item in the matching results.
When querying, a token will be returned if a query may be
Expand Down
15 changes: 14 additions & 1 deletion nisystemlink/clients/dataframe/_data_frame_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,26 @@ def create_table(self, table: models.CreateTableRequest) -> str:
"""Create a new table with the provided metadata and column definitions.
Args:
table: The request create the table.
table: The request to create the table.
Returns:
The ID of the newly created table.
"""
...

@json
@post(_BASE_PATH + "/query-tables", args=(Body,))
def query_tables(self, query: models.QueryTablesRequest) -> models.PagedTables:
"""Queries available tables on the SystemLink DataFrame service and returns their metadata.
Args:
query: The request to query tables.
Returns:
models.PagedTables: The list of tables with a continuation token.
"""
...

@get(_BASE_PATH + "/tables/{id}")
def get_table_metadata(self, id: str) -> models.TableMetadata:
"""Retrieves the metadata and column information for a single table identified by its ID.
Expand Down
1 change: 1 addition & 0 deletions nisystemlink/clients/dataframe/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from ._data_type import DataType
from ._order_by import OrderBy
from ._paged_tables import PagedTables
from ._query_tables_request import QueryTablesRequest
from ._table_metadata import TableMetadata

# flake8: noqa
4 changes: 2 additions & 2 deletions nisystemlink/clients/dataframe/models/_paged_tables.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import List

from nisystemlink.clients.core._uplink._paged_result import PagedResult
from nisystemlink.clients.core._uplink._with_paging import WithPaging

from ._table_metadata import TableMetadata


class PagedTables(PagedResult):
class PagedTables(WithPaging):
"""The response for a table query containing the matched tables."""

tables: List[TableMetadata]
Expand Down
78 changes: 78 additions & 0 deletions nisystemlink/clients/dataframe/models/_query_tables_request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from datetime import datetime
from typing import List, Optional, Union

from nisystemlink.clients.core._uplink._with_paging import WithPaging
from pydantic import StrictBool, StrictInt

from ._order_by import OrderBy


class QueryTablesRequest(WithPaging):
"""Request parameters for querying tables."""

filter: str
"""The table query filter in `Dynamic LINQ`_ format.
.. _Dynamic LINQ: https://github.com/ni/systemlink-OpenAPI-documents/wiki/Dynamic-Linq-Query-Language
Allowed properties in the filter are:
* ``createdAt``: DateTime the table was created
* ``createdWithin``: TimeSpan in which the table was created
* ``id``: String value uniquely identifying the table
* ``name``: String name for the table
* ``metadataModifiedAt``: DateTime the table's metadata was last modified
* ``metadataModifiedWithin``: TimeSpan in which the table's metadata was
last modified
* ``properties``: Dictionary with string keys and values representing table
metadata
* ``rowsModifiedAt``: DateTime rows were last appended to the table
* ``rowsModifiedWithin``: TimeSpan within rows were last appended to the
table
* ``rowCount``: Int32 number of rows in the table
* ``supportsAppend``: Boolean indicating whether or not the table supports
appending additional rows of data
* ``workspace``: String value ID of the workspace the table belongs to
* ``workspaceName``: String value name of the workspace the table belongs to
Allowed constants in the filter are:
* ``RelativeTime.CurrentDay``: TimeSpan representing the elapsed time
between now and the start of the current day
* ``RelativeTime.CurrentWeek``: TimeSpan representing the elapsed time
between now and the start of the current week
* ``RelativeTime.CurrentMonth``: TimeSpan representing the elapsed time
between now and the start of the current month
* ``RelativeTime.CurrentYear``: TimeSpan representing the elapsed time
between now and the start of the current year
"""

substitutions: Optional[List[Union[StrictInt, StrictBool, str, None]]] = None
"""Make substitutions in the query filter expression.
Substitutions for the query expression are indicated by non-negative
integers that are prefixed with the ``@`` symbol. Each substitution in the given
expression will be replaced by the element at the corresponding index
(zero-based) in this list. For example, ``@0`` in the filter expression will be
replaced with the element at the zeroth index of the substitutions list.
"""

reference_time: Optional[datetime] = None
"""The date and time to use as the reference point for `RelativeTime` filters,
including time zone information. Defaults to the time on the server in UTC."""

take: Optional[int] = None
"""Limits the returned list to the specified number of results."""

order_by: Optional[OrderBy] = None
"""The sort order of the returned list of tables."""

order_by_descending: Optional[bool] = None
"""Whether to sort descending instead of ascending.
The elements in the list are sorted ascending by default. If the
orderByDescending parameter is specified, the elements in the list are
sorted based on it's value. The orderByDescending value must be a boolean
string. The elements in the list are sorted ascending if false and
descending if true.
"""
36 changes: 30 additions & 6 deletions tests/integration/dataframe/test_dataframe.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from datetime import datetime, timezone
from typing import List

import pytest # type: ignore
Expand Down Expand Up @@ -111,24 +111,48 @@ def test__get_table_invalid_id__raises(self, client: DataFrameClient):
def test__list_tables__returns(
self, client: DataFrameClient, test_tables: List[str]
):
take = len(test_tables) - 1
first_page = client.list_tables(
take=take,
id=test_tables,
take=2,
id=test_tables[:3],
order_by="NAME",
order_by_descending=True,
)

assert len(first_page.tables) == take
assert len(first_page.tables) == 2
assert first_page.tables[0].id == test_tables[-1] # Asserts descending order
assert first_page.continuation_token is not None

second_page = client.list_tables(
id=test_tables,
id=test_tables[:3],
order_by="NAME",
order_by_descending=True,
continuation_token=first_page.continuation_token,
)

assert len(second_page.tables) == 1
assert second_page.continuation_token is None

def test__query_tables__returns(
self, client: DataFrameClient, test_tables: List[str]
):
query = models.QueryTablesRequest(
filter="""(id == @0 or id == @1 or id == @2)
and createdWithin <= RelativeTime.CurrentWeek
and supportsAppend == @3 and rowCount < @4""",
substitutions=[test_tables[0], test_tables[1], test_tables[2], True, 1],
reference_time=datetime.now(tz=timezone.utc),
take=2,
order_by="NAME",
order_by_descending=True,
)
first_page = client.query_tables(query)

assert len(first_page.tables) == 2
assert first_page.tables[0].id == test_tables[-1] # Asserts descending order
assert first_page.continuation_token is not None

query.continuation_token = first_page.continuation_token

second_page = client.query_tables(query)
assert len(second_page.tables) == 1
assert second_page.continuation_token is None

0 comments on commit 8b8afef

Please sign in to comment.