async def get_query(query_id): request.socket.send_json({"action": "get_sql", "query_id": query_id}) message = await request.socket.recv_json() current_app.logger.debug(f"Got message: {message}") if message["status"] == "done": results_streamer = stream_with_context(generate_json)(message["sql"], query_id) mimetype = "application/json" current_app.logger.debug("Returning.") return ( results_streamer, 200, { "Transfer-Encoding": "chunked", "Content-Disposition": f"attachment;filename={query_id}.json", "Content-type": mimetype, }, ) elif message["status"] == "running": return jsonify({}), 202 elif message["status"] == "error": return jsonify({"status": "Error", "msg": message["error"]}), 403 else: return jsonify({}), 404
async def get_query_result(query_id): await current_user.can_get_results_by_query_id(query_id=query_id) msg = { "request_id": request.request_id, "action": "get_sql_for_query_result", "params": { "query_id": query_id }, } request.socket.send_json(msg) reply = await request.socket.recv_json() current_app.flowapi_logger.debug(f"Received reply: {reply}", request_id=request.request_id) if reply["status"] == "error": # TODO: check that this path is fully tested! query_state = reply["payload"]["query_state"] if query_state in ("executing", "queued"): return jsonify({}), 202 elif query_state == "errored": return ( jsonify({ "status": "Error", "msg": reply["msg"] }), 403, ) # TODO: should this really be 403? elif query_state in ("awol", "known"): return (jsonify({"status": "Error", "msg": reply["msg"]}), 404) else: return ( jsonify({ "status": "Error", "msg": f"Unexpected query state: {query_state}" }), 500, ) else: sql = reply["payload"]["sql"] results_streamer = stream_with_context(stream_result_as_json)( sql, additional_elements={ "query_id": query_id }) mimetype = "application/json" current_app.flowapi_logger.debug( f"Returning result of query {query_id}.", request_id=request.request_id) return ( results_streamer, 200, { "Transfer-Encoding": "chunked", "Content-Disposition": f"attachment;filename={query_id}.json", "Content-type": mimetype, }, )
async def get_geography(aggregation_unit): current_user.can_get_geography(aggregation_unit=aggregation_unit) msg = { "request_id": request.request_id, "action": "get_geography", "params": { "aggregation_unit": aggregation_unit }, } request.socket.send_json(msg) # Get the reply. reply = await request.socket.recv_json() current_app.flowapi_logger.debug(f"Got message: {reply}", request_id=request.request_id) if reply["status"] == "error": return jsonify({ "status": "Error", "msg": "Internal server error" }), 500 try: query_state = reply["payload"]["query_state"] if query_state == "completed": results_streamer = stream_with_context(stream_result_as_json)( reply["payload"]["sql"], result_name="features", additional_elements={ "type": "FeatureCollection" }, ) mimetype = "application/geo+json" current_app.flowapi_logger.debug( f"Returning {aggregation_unit} geography data.", request_id=request.request_id, ) return ( results_streamer, 200, { "Transfer-Encoding": "chunked", "Content-Disposition": f"attachment;filename={aggregation_unit}.geojson", "Content-type": mimetype, }, ) # TODO: Reinstate correct status codes for geographies # # elif query_state == "error": # return jsonify({"status": "Error", "msg": reply["msg"]}), 403 # elif query_state == "awol": # return (jsonify({"status": "Error", "msg": reply["msg"]}), 404) except KeyError: # TODO: This should never happen! return (jsonify({"status": "Error", "msg": f"No query state."}), 500)
async def get_query(query_id): request.socket.send_json({ "request_id": request.request_id, "action": "get_sql", "query_id": query_id }) message = await request.socket.recv_json() current_app.logger.debug(f"Got message: {message}") try: status = message["status"] except KeyError: return ( jsonify({ "status": "Error", "msg": "Server responded without status" }), 500, ) if message["status"] == "done": results_streamer = stream_with_context(stream_result_as_json)( message["sql"], additional_elements={ "query_id": query_id }) mimetype = "application/json" current_app.logger.debug(f"Returning result of query {query_id}.") return ( results_streamer, 200, { "Transfer-Encoding": "chunked", "Content-Disposition": f"attachment;filename={query_id}.json", "Content-type": mimetype, }, ) elif message["status"] == "running": return jsonify({}), 202 elif message["status"] == "error": return jsonify({"status": "Error", "msg": message["error"]}), 403 elif status == "awol": return (jsonify({"status": "Error", "msg": message["error"]}), 404) else: return jsonify({ "status": "Error", "msg": f"Unexpected status: {status}" }), 500
async def get_geography(aggregation_unit): request.socket.send_json( { "request_id": request.request_id, "action": "get_geography", "params": {"aggregation_unit": aggregation_unit}, } ) # Get the reply. message = await request.socket.recv_json() current_app.logger.debug(f"Got message: {message}") try: status = message["status"] except KeyError: return ( jsonify({"status": "Error", "msg": "Server responded without status"}), 500, ) if status == "done": results_streamer = stream_with_context(stream_result_as_json)( message["sql"], result_name="features", additional_elements={"type": "FeatureCollection"}, ) mimetype = "application/geo+json" current_app.logger.debug(f"Returning {aggregation_unit} geography data.") return ( results_streamer, 200, { "Transfer-Encoding": "chunked", "Content-Disposition": f"attachment;filename={aggregation_unit}.geojson", "Content-type": mimetype, }, ) elif status == "error": return jsonify({"status": "Error", "msg": message["error"]}), 403 elif status == "awol": return (jsonify({"status": "Error", "msg": message["error"]}), 404) else: return ( jsonify({"status": "Error", "msg": f"Unexpected status: {status}"}), 500, )
async def get_geography(aggregation_unit): """ Get geojson --- get: parameters: - in: path name: aggregation_unit required: true schema: type: string responses: '200': content: application/geo+json: schema: type: object description: Downloading. '401': description: Unauthorized. '403': content: application/json: schema: type: object description: Token does not grant run access to this spatial aggregation unit. '500': description: Server error. summary: Get geojson for an aggregation unit """ current_user.can_get_geography(aggregation_unit=aggregation_unit) msg = { "request_id": request.request_id, "action": "get_geography", "params": { "aggregation_unit": aggregation_unit }, } request.socket.send_json(msg) # Get the reply. reply = await request.socket.recv_json() current_app.flowapi_logger.debug(f"Got message: {reply}", request_id=request.request_id) if reply["status"] == "error": try: msg = reply["msg"] except KeyError: msg = "Internal server error" return {"status": "Error", "msg": msg}, 500 try: query_state = reply["payload"]["query_state"] if query_state == "completed": results_streamer = stream_with_context(stream_result_as_json)( reply["payload"]["sql"], result_name="features", additional_elements={ "type": "FeatureCollection" }, ) mimetype = "application/geo+json" current_app.flowapi_logger.debug( f"Returning {aggregation_unit} geography data.", request_id=request.request_id, ) return ( results_streamer, 200, { "Transfer-Encoding": "chunked", "Content-Disposition": f"attachment;filename={aggregation_unit}.geojson", "Content-type": mimetype, }, ) # TODO: Reinstate correct status codes for geographies # # elif query_state == "error": # return {"status": "Error", "msg": reply["msg"]}, 403 # elif query_state == "awol": # return ({"status": "Error", "msg": reply["msg"]}, 404) except KeyError: # TODO: This should never happen! return ({"status": "Error", "msg": f"No query state."}, 500)
async def get_query_result(query_id, filetype="json"): """ Get the output of a completed query. --- get: parameters: - in: path name: query_id required: true schema: type: string - in: path name: filetype required: false default: json schema: type: string enum: - json - geojson - csv responses: '200': content: application/json: schema: type: object application/geo+json: schema: type: object text/csv: schema: type: string description: Results returning. '202': content: application/json: schema: type: object description: Request accepted. '401': description: Unauthorized. '403': content: application/json: schema: type: object description: Token does not grant results access to this query or spatial aggregation unit. '404': description: Unknown ID '500': description: Server error. summary: Get the output of query """ await current_user.can_get_results_by_query_id(query_id=query_id) msg = { "request_id": request.request_id, "action": "get_geo_sql_for_query_result" if filetype == "geojson" else "get_sql_for_query_result", "params": { "query_id": query_id }, } request.socket.send_json(msg) reply = await request.socket.recv_json() current_app.flowapi_logger.debug(f"Received reply: {reply}", request_id=request.request_id) if reply["status"] == "error": try: # TODO: check that this path is fully tested! query_state = reply["payload"]["query_state"] if query_state in ("executing", "queued"): return {}, 202 elif query_state == "errored": return ( { "status": "Error", "msg": reply["msg"] }, 403, ) # TODO: should this really be 403? elif query_state in ("awol", "known"): return {"status": "Error", "msg": reply["msg"]}, 404 else: return ( { "status": "Error", "msg": f"Unexpected query state: {query_state}", }, 500, ) except KeyError: return {"status": "error", "msg": reply["msg"]}, 500 else: sql = reply["payload"]["sql"] if filetype == "json": results_streamer = stream_with_context(stream_result_as_json)( sql, additional_elements={ "query_id": query_id }) mimetype = "application/json" elif filetype == "csv": results_streamer = stream_with_context(stream_result_as_csv)(sql) mimetype = "text/csv" elif filetype == "geojson": current_user.can_get_geography( aggregation_unit=reply["payload"]["aggregation_unit"]) results_streamer = stream_with_context(stream_result_as_json)( sql, result_name="features", additional_elements={ "type": "FeatureCollection" }, ) mimetype = "application/geo+json" else: return {"status": "error", "msg": "Invalid file format"}, 400 current_app.flowapi_logger.debug( f"Returning result of query {query_id}.", request_id=request.request_id) return ( results_streamer, 200, { "Transfer-Encoding": "chunked", "Content-Disposition": f"attachment;filename={query_id}.{filetype}", "Content-type": mimetype, }, )
async def get_query_result(query_id): """ Get the output of a completed query. --- get: parameters: - in: path name: query_id required: true schema: type: string responses: '200': content: application/json: schema: type: object description: Results returning. '202': content: application/json: schema: type: object description: Request accepted. '401': description: Unauthorized. '403': content: application/json: schema: type: object description: Token does not grant results access to this query or spatial aggregation unit. '404': description: Unknown ID '500': description: Server error. summary: Get the output of query """ await current_user.can_get_results_by_query_id(query_id=query_id) msg = { "request_id": request.request_id, "action": "get_sql_for_query_result", "params": { "query_id": query_id }, } request.socket.send_json(msg) reply = await request.socket.recv_json() current_app.flowapi_logger.debug(f"Received reply: {reply}", request_id=request.request_id) if reply["status"] == "error": # TODO: check that this path is fully tested! query_state = reply["payload"]["query_state"] if query_state in ("executing", "queued"): return jsonify({}), 202 elif query_state == "errored": return ( jsonify({ "status": "Error", "msg": reply["msg"] }), 403, ) # TODO: should this really be 403? elif query_state in ("awol", "known"): return (jsonify({"status": "Error", "msg": reply["msg"]}), 404) else: return ( jsonify({ "status": "Error", "msg": f"Unexpected query state: {query_state}" }), 500, ) else: sql = reply["payload"]["sql"] results_streamer = stream_with_context(stream_result_as_json)( sql, additional_elements={ "query_id": query_id }) mimetype = "application/json" current_app.flowapi_logger.debug( f"Returning result of query {query_id}.", request_id=request.request_id) return ( results_streamer, 200, { "Transfer-Encoding": "chunked", "Content-Disposition": f"attachment;filename={query_id}.json", "Content-type": mimetype, }, )