コード例 #1
0
 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}");
 }
コード例 #2
0
 /// <inheritdoc />
 public async Task <DResult <TRow> > Exec <TRow>(DQuery <TRow> query)
 {
     return(await apiClient.Query(
                apiUrl,
                dataSourceName,
                query,
                pollFrequency,
                cancellationToken));
 }
コード例 #3
0
        /// <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));
        }
コード例 #4
0
        public async Task <IEnumerable <TRow> > QueryRows <TRow>(DQuery <TRow> query)
        {
            var queryResult = await Context.Exec(query);

            return(queryResult.Rows);
        }
コード例 #5
0
 public JsonArrayConverter(DQuery <TRow> query)
 {
     this.query = query;
 }
コード例 #6
0
 public Task <DResult <TRow> > Exec <TRow>(DQuery <TRow> query) =>
 Connection.Exec(query.BuildQueryStatement(Table, Columns.ToArray()), query.ParseRow);
コード例 #7
0
        public async Task <IEnumerable <TRow> > QueryRows <TRow>(DQuery <TRow> query)
        {
            var queryResult = await Inner.Scope.GetInstance <DConnection>().Exec(query);

            return(queryResult.Rows);
        }
コード例 #8
0
        /// <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;
            }