Skip to content

Commit

Permalink
Merge pull request #517 from rtdip/develop
Browse files Browse the repository at this point in the history
v0.8.0
  • Loading branch information
GBBBAS authored Oct 2, 2023
2 parents 4c20cc3 + 21de2d4 commit 8729332
Show file tree
Hide file tree
Showing 17 changed files with 755 additions and 5 deletions.
2 changes: 2 additions & 0 deletions docs/sdk/code-reference/query/latest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Raw Function
::: src.sdk.python.rtdip_sdk.queries.time_series.latest
6 changes: 6 additions & 0 deletions docs/sdk/queries/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ The RTDIP SDK enables users to perform complex queries, including aggregation on

[Raw](../code-reference/query/raw.md) facilitates performing raw extracts of time series data, typically filtered by a Tag Name or Device Name and an event time.

### Latest

[Latest](../code-reference/query/latest.md) queries provides the latest event values. The RTDIP SDK requires the following parameters to retrieve the latest event values:
- TagNames - A list of tag names

### Resample

[Resample](../code-reference/query/resample.md) enables changing the frequency of time series observations. This is achieved by providing the following parameters:
Expand Down Expand Up @@ -69,6 +74,7 @@ The RTDIP SDK enables users to perform complex queries, including aggregation on
### Metadata
[Metadata](../code-reference/query/metadata.md) queries provide contextual information for time series measurements and include information such as names, descriptions and units of measure.


!!! note "Note"
</b>RTDIP are continuously adding more to this list so check back regularly.<br />

Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ dependencies:
- pygments==2.16.1
- pymdown-extensions==10.1.0
- databricks-sql-connector==2.9.3
- databricks-sdk==0.6.0
- databricks-sdk==0.9.0
- semver==3.0.0
- xlrd==2.0.1
- pygithub==1.59.0
Expand Down
3 changes: 2 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,11 @@ nav:
- Queries:
- Query Builder: sdk/code-reference/query/query_builder.md
- Functions:
- Raw: sdk/code-reference/query/raw.md
- Latest: sdk/code-reference/query/latest.md
- Resample: sdk/code-reference/query/resample.md
- Interpolate: sdk/code-reference/query/interpolate.md
- Interpolation at Time: sdk/code-reference/query/interpolation-at-time.md
- Raw: sdk/code-reference/query/raw.md
- Time Weighted Average: sdk/code-reference/query/time-weighted-average.md
- Circular Average: sdk/code-reference/query/circular-average.md
- Circular Standard Deviation: sdk/code-reference/query/circular-standard-deviation.md
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

PIPELINE_PACKAGES = [
"dependency-injector==4.41.0",
"databricks-sdk==0.2.1",
"databricks-sdk==0.9.0",
"pydantic==1.10.12",
"azure-storage-file-datalake==12.12.0",
"boto3==1.28.2",
Expand Down
1 change: 1 addition & 0 deletions src/api/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from src.api.v1 import (
metadata,
raw,
latest,
resample,
interpolate,
interpolation_at_time,
Expand Down
126 changes: 126 additions & 0 deletions src/api/v1/latest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Copyright 2022 RTDIP
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import logging
import numpy as np
from pandas.io.json import build_table_schema
from fastapi import Query, HTTPException, Depends, Body
import nest_asyncio
from src.sdk.python.rtdip_sdk.queries import latest
from src.api.v1.models import (
BaseQueryParams,
BaseHeaders,
MetadataQueryParams,
TagsBodyParams,
LatestResponse,
LimitOffsetQueryParams,
HTTPError,
)
from src.api.auth.azuread import oauth2_scheme
from src.api.FastAPIApp import api_v1_router
from src.api.v1 import common

nest_asyncio.apply()


def latest_retrieval_get(
query_parameters, metadata_query_parameters, limit_offset_parameters, base_headers
):
try:
(connection, parameters) = common.common_api_setup_tasks(
query_parameters,
metadata_query_parameters=metadata_query_parameters,
limit_offset_query_parameters=limit_offset_parameters,
base_headers=base_headers,
)

data = latest.get(connection, parameters)
return LatestResponse(
schema=build_table_schema(data, index=False, primary_key=False),
data=data.replace({np.nan: None}).to_dict(orient="records"),
)
except Exception as e:
logging.error(str(e))
raise HTTPException(status_code=400, detail=str(e))


get_description = """
## Latest
Retrieval of latest event values for a given tag name or list of tag names.
"""


@api_v1_router.get(
path="/events/latest",
name="Latest GET",
description=get_description,
tags=["Events"],
dependencies=[Depends(oauth2_scheme)],
responses={200: {"model": LatestResponse}, 400: {"model": HTTPError}},
openapi_extra={
"externalDocs": {
"description": "RTDIP Latest Query Documentation",
"url": "https://www.rtdip.io/sdk/code-reference/query/latest/",
}
},
)
async def latest_get(
query_parameters: BaseQueryParams = Depends(),
metadata_query_parameters: MetadataQueryParams = Depends(),
limit_offset_parameters: LimitOffsetQueryParams = Depends(),
base_headers: BaseHeaders = Depends(),
):
return latest_retrieval_get(
query_parameters,
metadata_query_parameters,
limit_offset_parameters,
base_headers,
)


post_description = """
## Metadata
Retrieval of latest event values for a given tag name or list of tag names via a POST method to enable providing a list of tag names that can exceed url length restrictions via GET Query Parameters.
"""


@api_v1_router.post(
path="/events/latest",
name="Latest POST",
description=post_description,
tags=["Events"],
dependencies=[Depends(oauth2_scheme)],
responses={200: {"model": LatestResponse}, 400: {"model": HTTPError}},
openapi_extra={
"externalDocs": {
"description": "RTDIP Latest Query Documentation",
"url": "https://www.rtdip.io/sdk/code-reference/query/latest/",
}
},
)
async def latest_post(
query_parameters: BaseQueryParams = Depends(),
metadata_query_parameters: TagsBodyParams = Body(default=...),
limit_offset_parameters: LimitOffsetQueryParams = Depends(),
base_headers: BaseHeaders = Depends(),
):
return latest_retrieval_get(
query_parameters,
metadata_query_parameters,
limit_offset_parameters,
base_headers,
)
16 changes: 16 additions & 0 deletions src/api/v1/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ class Config:
extra = Extra.allow


class LatestRow(BaseModel):
TagName: str
EventTime: datetime
Status: str
Value: str
ValueType: str
GoodEventTime: datetime
GoodValue: str
GoodValueType: str


class RawRow(BaseModel):
EventTime: datetime
TagName: str
Expand All @@ -73,6 +84,11 @@ class MetadataResponse(BaseModel):
data: List[MetadataRow]


class LatestResponse(BaseModel):
field_schema: FieldSchema = Field(None, alias="schema")
data: List[LatestRow]


class RawResponse(BaseModel):
field_schema: FieldSchema = Field(None, alias="schema")
data: List[RawRow]
Expand Down
21 changes: 21 additions & 0 deletions src/sdk/python/rtdip_sdk/functions/latest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2022 RTDIP
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

logging.warning(
"Module rtdip_sdk.functions is deprecated and will be removed in v1.0.0. Please import rtdip_sdk.queries instead."
)

from ..queries.metadata import * # NOSONAR
1 change: 1 addition & 0 deletions src/sdk/python/rtdip_sdk/queries/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from .time_series import (
raw,
latest,
resample,
interpolate,
interpolation_at_time,
Expand Down
28 changes: 28 additions & 0 deletions src/sdk/python/rtdip_sdk/queries/query_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
time_weighted_average,
circular_average,
circular_standard_deviation,
latest,
)
from . import metadata
from pandas import DataFrame
Expand Down Expand Up @@ -352,6 +353,33 @@ def metadata(

return metadata.get(self.connection, metadata_parameters)

def latest(
self,
tagname_filter: [str],
limit: int = None,
offset: int = None,
) -> DataFrame:
"""
A query to retrieve latest event_values
Args:
tagname_filter (list str): List of tagnames to filter on the source
limit (optional int): The number of rows to be returned
offset (optional int): The number of rows to skip before returning rows
Returns:
DataFrame: A dataframe of events latest_values
"""
latest_parameters = {
"source": self.data_source,
"tag_names": tagname_filter,
"tagname_column": self.tagname_column,
"limit": limit,
"offset": offset,
}

return latest.get(self.connection, latest_parameters)

def circular_average(
self,
tagname_filter: [str],
Expand Down
39 changes: 39 additions & 0 deletions src/sdk/python/rtdip_sdk/queries/time_series/_query_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,42 @@ def _metadata_query(parameters_dict: dict) -> str:
return sql_template.render(metadata_parameters)


def _latest_query(parameters_dict: dict) -> str:
latest_query = (
"SELECT * FROM "
"{% if source is defined and source is not none %}"
"`{{ source|lower }}` "
"{% else %}"
"`{{ business_unit|lower }}`.`sensors`.`{{ asset|lower }}_{{ data_security_level|lower }}_events_latest` "
"{% endif %}"
"{% if tag_names is defined and tag_names|length > 0 %} "
"WHERE `{{ tagname_column }}` IN ('{{ tag_names | join('\\', \\'') }}') "
"{% endif %}"
"ORDER BY `{{ tagname_column }}` "
"{% if limit is defined and limit is not none %}"
"LIMIT {{ limit }} "
"{% endif %}"
"{% if offset is defined and offset is not none %}"
"OFFSET {{ offset }} "
"{% endif %}"
)

latest_parameters = {
"source": parameters_dict.get("source", None),
"business_unit": parameters_dict.get("business_unit"),
"region": parameters_dict.get("region"),
"asset": parameters_dict.get("asset"),
"data_security_level": parameters_dict.get("data_security_level"),
"tag_names": list(dict.fromkeys(parameters_dict["tag_names"])),
"limit": parameters_dict.get("limit", None),
"offset": parameters_dict.get("offset", None),
"tagname_column": parameters_dict.get("tagname_column", "TagName"),
}

sql_template = Template(latest_query)
return sql_template.render(latest_parameters)


def _time_weighted_average_query(parameters_dict: dict) -> str:
parameters_dict["start_datetime"] = datetime.strptime(
parameters_dict["start_date"], TIMESTAMP_FORMAT
Expand Down Expand Up @@ -577,6 +613,9 @@ def _query_builder(parameters_dict: dict, query_type: str) -> str:
if query_type == "metadata":
return _metadata_query(parameters_dict)

if query_type == "latest":
return _latest_query(parameters_dict)

parameters_dict = _parse_dates(parameters_dict)

if query_type == "interpolation_at_time":
Expand Down
Loading

0 comments on commit 8729332

Please sign in to comment.