Beispiel #1
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="rowParser">A delegate used for parsing a result row.</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>
        /// <exception cref="Exceptions.ApiException">The Aircloak Api returned a Http Error code.</exception>
        /// <exception cref="Exceptions.ResultException">The Aircloak Api result status is "Error".</exception>
        public async Task <QueryResult <TRow> > PollQueryUntilComplete <TRow>(
            Uri apiUrl,
            string queryId,
            string query,
            JsonRowParser <TRow> rowParser,
            TimeSpan pollFrequency,
            CancellationToken cancellationToken)
        {
            // Register the JsonArrayConverter so the TRow can be deserialized correctly
            var jsonDeserializeOptions = new JsonSerializerOptions
            {
                PropertyNamingPolicy = new SnakeCaseNamingPolicy(),
                Converters           = { new JsonArrayConverter <TRow>(rowParser) },
            };

            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 Exceptions.ResultException("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;
            }
Beispiel #2
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">The query statement as a string.</param>
        /// <param name="rowParser">A delegate used for parsing a result row.</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>
        /// <exception cref="Exceptions.ApiException">The Aircloak Api returned a Http Error code.</exception>
        /// <exception cref="Exceptions.QueryException">The Aircloak Api could not process the query.</exception>
        /// <exception cref="Exceptions.ResultException">The Aircloak Api result status is "Error".</exception>
        public async Task <QueryResult <TRow> > Query <TRow>(
            Uri apiUrl,
            string dataSource,
            string query,
            JsonRowParser <TRow> rowParser,
            TimeSpan pollFrequency,
            CancellationToken cancellationToken)
        {
            var queryResponse = await SubmitQuery(apiUrl, dataSource, query, cancellationToken);

            return(await PollQueryUntilComplete(apiUrl, queryResponse.QueryId, query, rowParser, pollFrequency, cancellationToken));
        }
Beispiel #3
0
        /// <summary>
        /// Executes the query.
        /// </summary>
        /// <param name="query">An object defining the query to be executed.</param>
        /// <param name="rowParser">A delegate used for parsing a result row.</param>
        /// <typeparam name="TRow">The type of the rows returned by the query.</typeparam>
        /// <returns>An object containing a collection with the rows returned by the query.</returns>
        public async Task <DResult <TRow> > Exec <TRow>(string query, JsonRowParser <TRow> rowParser)
        {
            await semaphore.WaitAsync(cancellationToken);

            try
            {
                return(await apiClient.Query(
                           apiUrl,
                           dataSourceName,
                           query,
                           rowParser,
                           pollFrequency,
                           cancellationToken));
            }
            finally
            {
                semaphore.Release();
            }
        }
Beispiel #4
0
 public JsonArrayConverter(JsonRowParser <TRow> rowParser)
 {
     this.rowParser = rowParser;
 }