static string GetQueryResultDetails(DQuery <TRow> query, QueryResult <TRow> queryResult) { return($"DataSource: {queryResult.Query.DataSource.Name}.\n" + $"Error: {queryResult.Query.Error}\n" + $"Query Id: {queryResult.Query.Id}\n" + $"Query Statement: {query.QueryStatement}"); }
/// <inheritdoc /> public async Task <DResult <TRow> > Exec <TRow>(DQuery <TRow> query) { return(await apiClient.Query( apiUrl, dataSourceName, query, pollFrequency, cancellationToken)); }
/// <summary> /// Posts a query to the Aircloak server, retrieves the query ID, and then polls for the result. /// </summary> /// <param name="apiUrl">The Url of the Aircloak api.</param> /// <param name="dataSource">The data source to run the query against.</param> /// <param name="query">An instance of the <see cref="DQuery{TRow}"/> interface.</param> /// <param name="pollFrequency">How often to poll the api endpoint. </param> /// <param name="cancellationToken">A <see cref="CancellationToken" /> object that can be used to cancel the operation.</param> /// <returns>A <see cref="QueryResult{TRow}"/> instance containing the success status and query Id.</returns> /// <typeparam name="TRow">The type that the query row will be deserialized to.</typeparam> public async Task <QueryResult <TRow> > Query <TRow>( Uri apiUrl, string dataSource, DQuery <TRow> query, TimeSpan pollFrequency, CancellationToken cancellationToken) { var queryResponse = await SubmitQuery(apiUrl, dataSource, query.QueryStatement, cancellationToken); return(await PollQueryUntilComplete(apiUrl, queryResponse.QueryId, query, pollFrequency, cancellationToken)); }
public async Task <IEnumerable <TRow> > QueryRows <TRow>(DQuery <TRow> query) { var queryResult = await Context.Exec(query); return(queryResult.Rows); }
public JsonArrayConverter(DQuery <TRow> query) { this.query = query; }
public Task <DResult <TRow> > Exec <TRow>(DQuery <TRow> query) => Connection.Exec(query.BuildQueryStatement(Table, Columns.ToArray()), query.ParseRow);
public async Task <IEnumerable <TRow> > QueryRows <TRow>(DQuery <TRow> query) { var queryResult = await Inner.Scope.GetInstance <DConnection>().Exec(query); return(queryResult.Rows); }
/// <summary> /// Calls <c>PollQueryResult</c> in a loop until the query completes. Can be canceled. /// </summary> /// <remarks> /// Canceling via the <c>CancellationToken</c> cancels the returned <c>Task</c> and /// automatically cancels the query execution by calling <c>/api/queries/{query_id}/cancel</c>. /// </remarks> /// <param name="apiUrl">The Url of the Aircloak api.</param> /// <param name="queryId">The query Id obtained via a previous call to the /api/query endpoint.</param> /// <param name="query">An instance of the <see cref="DQuery{TRow}"/> interface.</param> /// <param name="pollFrequency">How often to poll the api endpoint. </param> /// <param name="cancellationToken">A <c>CancellationToken</c> that cancels the returned <c>Task</c>.</param> /// <typeparam name="TRow">The type to use to deserialise each row returned in the query results.</typeparam> /// <returns>A QueryResult instance. If the query has finished executing, contains the query results, with each /// row seralised to type <c>TRow</c>.</returns> public async Task <QueryResult <TRow> > PollQueryUntilComplete <TRow>( Uri apiUrl, string queryId, DQuery <TRow> query, TimeSpan pollFrequency, CancellationToken cancellationToken) { // Register the JsonArrayConverter so the TRow can be deserialized correctly var jsonDeserializeOptions = new JsonSerializerOptions { PropertyNamingPolicy = new SnakeCaseNamingPolicy(), Converters = { new JsonArrayConverter <DQuery <TRow>, TRow>(query), new DValueTypeEnumConverter(), }, }; var queryCompleted = false; var speed = 16; try { while (true) { cancellationToken.ThrowIfCancellationRequested(); var endPoint = new Uri(apiUrl, $"queries/{queryId}"); using var httpResponse = await ApiGetRequest(endPoint, cancellationToken); var queryResult = await ParseJson <QueryResult <TRow> >(httpResponse, jsonDeserializeOptions, cancellationToken); if (queryResult.Query.Completed) { queryCompleted = true; switch (queryResult.Query.QueryState) { case "completed": return(queryResult); case "error": throw new Exception("Aircloak API query error.\n" + GetQueryResultDetails(query, queryResult)); case "cancelled": throw new OperationCanceledException("Aircloak API query canceled.\n" + GetQueryResultDetails(query, queryResult)); } } await Task.Delay(pollFrequency / speed, cancellationToken); speed = Math.Max(speed / 2, 1); } } catch (Exception) { if (!queryCompleted) { await CancelQuery(apiUrl, queryId); } throw; }