Skip to content

Commit

Permalink
Service: TimestreamQuery (#8019)
Browse files Browse the repository at this point in the history
  • Loading branch information
bblommers authored Aug 22, 2024
1 parent 56abecb commit aef5b8e
Show file tree
Hide file tree
Showing 14 changed files with 633 additions and 1 deletion.
22 changes: 21 additions & 1 deletion IMPLEMENTATION_COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8481,6 +8481,27 @@
- [ ] update_adapter
</details>

## timestream-query
<details>
<summary>40% implemented</summary>

- [ ] cancel_query
- [X] create_scheduled_query
- [X] delete_scheduled_query
- [ ] describe_account_settings
- [X] describe_endpoints
- [X] describe_scheduled_query
- [ ] execute_scheduled_query
- [ ] list_scheduled_queries
- [ ] list_tags_for_resource
- [ ] prepare_query
- [X] query
- [ ] tag_resource
- [ ] untag_resource
- [ ] update_account_settings
- [X] update_scheduled_query
</details>

## timestream-write
<details>
<summary>78% implemented</summary>
Expand Down Expand Up @@ -9010,7 +9031,6 @@
- synthetics
- taxsettings
- timestream-influxdb
- timestream-query
- tnb
- translate
- trustedadvisor
Expand Down
80 changes: 80 additions & 0 deletions docs/docs/services/timestream-query.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
.. _implementedservice_timestream-query:

.. |start-h3| raw:: html

<h3>

.. |end-h3| raw:: html

</h3>

================
timestream-query
================

.. autoclass:: moto.timestreamquery.models.TimestreamQueryBackend

|start-h3| Implemented features for this service |end-h3|

- [ ] cancel_query
- [X] create_scheduled_query
- [X] delete_scheduled_query
- [ ] describe_account_settings
- [X] describe_endpoints
- [X] describe_scheduled_query
- [ ] execute_scheduled_query
- [ ] list_scheduled_queries
- [ ] list_tags_for_resource
- [ ] prepare_query
- [X] query

Moto does not have a builtin time-series Database, so calling this endpoint will return zero results by default.

You can use a dedicated API to configuring a queue of expected results.

An example invocation looks like this:

.. sourcecode:: python

first_result = {
'QueryId': 'some_id',
'Rows': [...],
'ColumnInfo': [...],
'QueryStatus': ...
}
result_for_unknown_query_string = {
'QueryId': 'unknown',
'Rows': [...],
'ColumnInfo': [...],
'QueryStatus': ...
}
expected_results = {
"account_id": "123456789012", # This is the default - can be omitted
"region": "us-east-1", # This is the default - can be omitted
"results": {
# Use the exact querystring, and a list of results for it
# For example
"SELECT data FROM mytable": [first_result, ...],
# Use None if the exact querystring is unknown/irrelevant
None: [result_for_unknown_query_string, ...],
}
}
requests.post(
"http://motoapi.amazonaws.com/moto-api/static/timestream/query-results",
json=expected_results,
)

When calling `query(QueryString='SELECT data FROM mytable')`, the `first_result` will be returned.
Call the query again for the second result, and so on.

If you don't know the exact query strings, use the `None`-key. In the above example, when calling `SELECT something FROM unknown`, there are no results for that specific query, so `result_for_unknown_query_string` will be returned.

Results for unknown queries are cached, so calling `SELECT something FROM unknown` will return the same result.



- [ ] tag_resource
- [ ] untag_resource
- [ ] update_account_settings
- [X] update_scheduled_query

4 changes: 4 additions & 0 deletions moto/backend_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@
("support", re.compile("https?://support\\.(.+)\\.amazonaws\\.com")),
("swf", re.compile("https?://swf\\.(.+)\\.amazonaws\\.com")),
("textract", re.compile("https?://textract\\.(.+)\\.amazonaws\\.com")),
(
"timestreamquery",
re.compile("https?://query.timestream\\.(.+)\\.amazonaws\\.com"),
),
(
"timestreamwrite",
re.compile("https?://ingest\\.timestream\\.(.+)\\.amazonaws\\.com"),
Expand Down
6 changes: 6 additions & 0 deletions moto/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
from moto.support.models import SupportBackend
from moto.swf.models import SWFBackend
from moto.textract.models import TextractBackend
from moto.timestreamquery.models import TimestreamQueryBackend
from moto.timestreamwrite.models import TimestreamWriteBackend
from moto.transcribe.models import TranscribeBackend
from moto.transfer.models import TransferBackend
Expand Down Expand Up @@ -318,6 +319,7 @@ def get_service_from_url(url: str) -> Optional[str]:
"Literal['support']",
"Literal['swf']",
"Literal['textract']",
"Literal['timestream-query']",
"Literal['timestream-write']",
"Literal['transcribe']",
"Literal['transfer']",
Expand Down Expand Up @@ -710,6 +712,10 @@ def get_backend(name: "Literal['swf']") -> "BackendDict[SWFBackend]": ...
@overload
def get_backend(name: "Literal['textract']") -> "BackendDict[TextractBackend]": ...
@overload
def get_backend(
name: "Literal['timestream-query']",
) -> "BackendDict[TimestreamQueryBackend]": ...
@overload
def get_backend(
name: "Literal['timestream-write']",
) -> "BackendDict[TimestreamWriteBackend]": ...
Expand Down
17 changes: 17 additions & 0 deletions moto/moto_api/_internal/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,23 @@ def set_inspector2_findings_result(
backend = inspector2_backends[account_id][region]
backend.findings_queue.append(results)

def set_timestream_result(
self,
query: Optional[str],
query_results: List[Dict[str, Any]],
account_id: str,
region: str,
) -> None:
from moto.timestreamquery.models import (
TimestreamQueryBackend,
timestreamquery_backends,
)

backend: TimestreamQueryBackend = timestreamquery_backends[account_id][region]
if query not in backend.query_result_queue:
backend.query_result_queue[query] = []
backend.query_result_queue[query].extend(query_results)

def get_proxy_passthrough(self) -> Tuple[Set[str], Set[str]]:
return self.proxy_urls_to_passthrough, self.proxy_hosts_to_passthrough

Expand Down
22 changes: 22 additions & 0 deletions moto/moto_api/_internal/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,28 @@ def set_inspector2_findings_result(
)
return 201, {}, ""

def set_timestream_result(
self,
request: Any,
full_url: str, # pylint: disable=unused-argument
headers: Any,
) -> TYPE_RESPONSE:
from .models import moto_api_backend

body = self._get_body(headers, request)
account_id = body.get("account_id", DEFAULT_ACCOUNT_ID)
region = body.get("region", "us-east-1")
results = body.get("results", {})

for query in results:
moto_api_backend.set_timestream_result(
query=None if query == "null" else query,
query_results=results[query],
account_id=account_id,
region=region,
)
return 201, {}, ""

def set_proxy_passthrough(
self,
request: Any,
Expand Down
1 change: 1 addition & 0 deletions moto/moto_api/_internal/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"{0}/moto-api/static/lambda-simple/response": response_instance.set_lambda_simple_result,
"{0}/moto-api/static/resilience-hub-assessments/response": response_instance.set_resilience_result,
"{0}/moto-api/static/sagemaker/endpoint-results": response_instance.set_sagemaker_result,
"{0}/moto-api/static/timestream/query-results": response_instance.set_timestream_result,
"{0}/moto-api/static/rds-data/statement-results": response_instance.set_rds_data_result,
"{0}/moto-api/state-manager/get-transition": response_instance.get_transition,
"{0}/moto-api/state-manager/set-transition": response_instance.set_transition,
Expand Down
3 changes: 3 additions & 0 deletions moto/timestreamquery/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .models import timestreamquery_backends # noqa: F401

# Responses are handled by TimestreamWrite
11 changes: 11 additions & 0 deletions moto/timestreamquery/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Exceptions raised by the timestreamquery service."""

from moto.core.exceptions import JsonRESTError


class ResourceNotFound(JsonRESTError):
def __init__(self, arn: str):
super().__init__(
error_type="ResourceNotFoundException",
message=f"The resource with arn {arn} does not exist.",
)
Loading

0 comments on commit aef5b8e

Please sign in to comment.