def load_chart_data_into_cache( job_metadata: Dict[str, Any], form_data: Dict[str, Any], ) -> None: # pylint: disable=import-outside-toplevel from superset.charts.data.commands.get_data_command import ChartDataCommand try: ensure_user_is_set(job_metadata.get("user_id")) set_form_data(form_data) query_context = _create_query_context_from_form(form_data) command = ChartDataCommand(query_context) result = command.run(cache=True) cache_key = result["cache_key"] result_url = f"/api/v1/chart/data/{cache_key}" async_query_manager.update_job( job_metadata, async_query_manager.STATUS_DONE, result_url=result_url, ) except SoftTimeLimitExceeded as ex: logger.warning( "A timeout occurred while loading chart data, error: %s", ex) raise ex except Exception as ex: # TODO: QueryContext should support SIP-40 style errors error = ex.message if hasattr(ex, "message") else str(ex) # type: ignore # pylint: disable=no-member errors = [{"message": error}] async_query_manager.update_job(job_metadata, async_query_manager.STATUS_ERROR, errors=errors) raise ex
def data_from_cache(self, cache_key: str) -> Response: """ Takes a query context cache key and returns payload data response for the given query. --- get: description: >- Takes a query context cache key and returns payload data response for the given query. parameters: - in: path schema: type: string name: cache_key responses: 200: description: Query result content: application/json: schema: $ref: "#/components/schemas/ChartDataResponseSchema" 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 404: $ref: '#/components/responses/404' 422: $ref: '#/components/responses/422' 500: $ref: '#/components/responses/500' """ try: cached_data = self._load_query_context_form_from_cache(cache_key) query_context = self._create_query_context_from_form(cached_data) command = ChartDataCommand(query_context) command.validate() except ChartDataCacheLoadError: return self.response_404() except ValidationError as error: return self.response_400(message=_( "Request is incorrect: %(error)s", error=error.messages)) return self._get_data_response(command, True)
def get_data(self, pk: int) -> Response: """ Takes a chart ID and uses the query context stored when the chart was saved to return payload data response. --- get: description: >- Takes a chart ID and uses the query context stored when the chart was saved to return payload data response. parameters: - in: path schema: type: integer name: pk description: The chart ID - in: query name: format description: The format in which the data should be returned schema: type: string - in: query name: type description: The type in which the data should be returned schema: type: string responses: 200: description: Query result content: application/json: schema: $ref: "#/components/schemas/ChartDataResponseSchema" 202: description: Async job details content: application/json: schema: $ref: "#/components/schemas/ChartDataAsyncResponseSchema" 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 500: $ref: '#/components/responses/500' """ chart = self.datamodel.get(pk, self._base_filters) if not chart: return self.response_404() try: json_body = json.loads(chart.query_context) except (TypeError, json.decoder.JSONDecodeError): json_body = None if json_body is None: return self.response_400(message=_( "Chart has no query context saved. Please save the chart again." )) # override saved query context json_body["result_format"] = request.args.get( "format", ChartDataResultFormat.JSON) json_body["result_type"] = request.args.get("type", ChartDataResultType.FULL) try: query_context = self._create_query_context_from_form(json_body) command = ChartDataCommand(query_context) command.validate() except QueryObjectValidationError as error: return self.response_400(message=error.message) except ValidationError as error: return self.response_400( message=_("Request is incorrect: %(error)s", error=error.normalized_messages())) # TODO: support CSV, SQL query and other non-JSON types if (is_feature_enabled("GLOBAL_ASYNC_QUERIES") and query_context.result_format == ChartDataResultFormat.JSON and query_context.result_type == ChartDataResultType.FULL): return self._run_async(json_body, command) try: form_data = json.loads(chart.params) except (TypeError, json.decoder.JSONDecodeError): form_data = {} return self._get_data_response(command=command, form_data=form_data, datasource=query_context.datasource)
def data(self) -> Response: """ Takes a query context constructed in the client and returns payload data response for the given query. --- post: description: >- Takes a query context constructed in the client and returns payload data response for the given query. requestBody: description: >- A query context consists of a datasource from which to fetch data and one or many query objects. required: true content: application/json: schema: $ref: "#/components/schemas/ChartDataQueryContextSchema" responses: 200: description: Query result content: application/json: schema: $ref: "#/components/schemas/ChartDataResponseSchema" 202: description: Async job details content: application/json: schema: $ref: "#/components/schemas/ChartDataAsyncResponseSchema" 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 500: $ref: '#/components/responses/500' """ json_body = None if request.is_json: json_body = request.json elif request.form.get("form_data"): # CSV export submits regular form data try: json_body = json.loads(request.form["form_data"]) except (TypeError, json.JSONDecodeError): pass if json_body is None: return self.response_400(message=_("Request is not JSON")) try: query_context = self._create_query_context_from_form(json_body) command = ChartDataCommand(query_context) command.validate() except QueryObjectValidationError as error: return self.response_400(message=error.message) except ValidationError as error: return self.response_400( message=_("Request is incorrect: %(error)s", error=error.normalized_messages())) # TODO: support CSV, SQL query and other non-JSON types if (is_feature_enabled("GLOBAL_ASYNC_QUERIES") and query_context.result_format == ChartDataResultFormat.JSON and query_context.result_type == ChartDataResultType.FULL): return self._run_async(json_body, command) form_data = json_body.get("form_data") return self._get_data_response(command, form_data=form_data, datasource=query_context.datasource)