/// <inheritdoc />
        public async Task <Census> GetCensusAsync(
            IEnumerable <string> aggregationFields,
            DatasetQueryFile datasetQueryFile,
            Dictionary <string, AggregateQuery> aggregateQueries,
            string parameterName,
            string parameterValue,
            BuildCensusResultsCallback buildCensusResultsCallback,
            CancellationToken cancellationToken)
        {
            Census toReturn = null;

            if (datasetQueryFile == null)
            {
                throw new ArgumentNullException(nameof(datasetQueryFile));
            }

            if (buildCensusResultsCallback == null)
            {
                throw new ArgumentNullException(
                          nameof(buildCensusResultsCallback));
            }

            QueryConfiguration queryConfiguration =
                datasetQueryFile.QueryConfiguration;

            string connectionString = this.GetConnectionString(
                queryConfiguration);

            string query = datasetQueryFile.Query;

            toReturn = await this.ExecuteQueryAsync(
                aggregationFields,
                aggregateQueries,
                connectionString,
                query,
                parameterName,
                parameterValue,
                buildCensusResultsCallback,
                cancellationToken)
                       .ConfigureAwait(false);

            return(toReturn);
        }
        /// <inheritdoc />
        public async Task <DatasetQueryFile> GetDatabaseQueryFileAsync(
            string datasetQueryFileId,
            CancellationToken cancellationToken)
        {
            DatasetQueryFile toReturn = null;

            CloudBlobDirectory cloudBlobDirectory =
                await this.GetDatasetQueryFileDirectory(datasetQueryFileId)
                .ConfigureAwait(false);

            if (cloudBlobDirectory == null)
            {
                throw new DatasetQueryFileNotFoundException(
                          datasetQueryFileId);
            }

            // List all the files in the directory.
            IEnumerable <IListBlobItem> listBlobItems =
                await cloudBlobDirectory.Container
                .ListBlobsAsync(cloudBlobDirectory.Prefix)
                .ConfigureAwait(false);

            IEnumerable <CloudBlockBlob> cloudBlockBlobs =
                listBlobItems
                .Where(x => x is CloudBlockBlob)
                .Cast <CloudBlockBlob>();

            CloudBlockBlob queryFile = cloudBlockBlobs.SingleOrDefault(
                x => x.Name.EndsWith(
                    this.datasetQueryFileQueryFilename,
                    StringComparison.InvariantCulture));

            if (queryFile == null)
            {
                throw new IncompleteDatasetQueryFileException(
                          this.datasetQueryFileQueryFilename);
            }

            string query =
                await this.GetFileContentsAsString(
                    queryFile,
                    cancellationToken)
                .ConfigureAwait(false);

            CloudBlockBlob configFile = cloudBlockBlobs.SingleOrDefault(
                x => x.Name.EndsWith(
                    this.datasetQueryFileConfigFilename,
                    StringComparison.InvariantCulture));

            if (configFile == null)
            {
                throw new IncompleteDatasetQueryFileException(
                          this.datasetQueryFileConfigFilename);
            }

            string configurationStr = await this.GetFileContentsAsString(
                configFile,
                cancellationToken)
                                      .ConfigureAwait(false);

            QueryConfiguration queryConfiguration =
                JsonConvert.DeserializeObject <QueryConfiguration>(configurationStr);

            toReturn = new DatasetQueryFile()
            {
                Query = query,
                QueryConfiguration = queryConfiguration,
            };

            return(toReturn);
        }
        /// <inheritdoc />
        public async Task <GetCensusResponse> GetCensusAsync(
            GetCensusRequest getCensusRequest,
            CancellationToken cancellationToken)
        {
            GetCensusResponse toReturn = null;

            if (getCensusRequest == null)
            {
                throw new ArgumentNullException(nameof(getCensusRequest));
            }

            CensusIdentifier censusIdentifier =
                getCensusRequest.CensusIdentifier;

            string datasetQueryFileId = censusIdentifier.DatasetQueryFileId;

            this.loggerWrapper.Debug(
                $"Pulling back {nameof(DatasetQueryFile)} with id " +
                $"\"{datasetQueryFileId}\"...");

            DatasetQueryFile datasetQueryFile =
                await this.datasetQueryFilesStorageAdapter.GetDatabaseQueryFileAsync(
                    censusIdentifier.DatasetQueryFileId,
                    cancellationToken)
                .ConfigureAwait(false);

            this.loggerWrapper.Info(
                $"Got {nameof(DatasetQueryFile)} for id " +
                $"\"{datasetQueryFileId}\": {datasetQueryFile}.");

            Dictionary <string, AggregateQuery> aggregateQueries =
                getCensusRequest.AggregateQueries;

            Census census = null;

            if (aggregateQueries != null)
            {
                census = await this.GetCensusAggregates(
                    getCensusRequest,
                    datasetQueryFile,
                    cancellationToken)
                         .ConfigureAwait(false);
            }
            else
            {
                census = new Census();
            }

            census.Name = $"Census results from " +
                          $"{datasetQueryFile.QueryConfiguration.DatabaseName}";

            this.loggerWrapper.Info(
                $"Fetched {nameof(Census)}: {census} using " +
                $"{datasetQueryFile} and supplied aggregate queries.");

            toReturn = new GetCensusResponse()
            {
                Census = census,
            };

            return(toReturn);
        }
        private async Task <Census> GetCensusAggregates(
            GetCensusRequest getCensusRequest,
            DatasetQueryFile datasetQueryFile,
            CancellationToken cancellationToken)
        {
            Census toReturn = null;

            CensusIdentifier censusIdentifier =
                getCensusRequest.CensusIdentifier;

            // Get an entire list of aggregation fields that we can use.
            Dictionary <string, Type> aggregationFieldsAndTypes = null;

            if (this.aggregationFieldsCache.AggregationFieldsAndTypes == null)
            {
                this.loggerWrapper.Debug(
                    "Fetching available aggregation mappings from the " +
                    "Translator API...");

                GetEnumerationMappingsResponse getEnumerationMappingsResponse =
                    await this.translationApiAdapter.GetEnumerationMappingsAsync(
                        this.aggregationFieldsEnumerationName,
                        this.aggregationFieldsAdapterName,
                        cancellationToken)
                    .ConfigureAwait(false);

                aggregationFieldsAndTypes =
                    ConvertMappingsResponseToFieldsAndTypes(
                        getEnumerationMappingsResponse);

                this.loggerWrapper.Info(
                    $"Aggregation fields and types obtained - " +
                    $"{aggregationFieldsAndTypes.Count} in total.");

                this.aggregationFieldsCache.AggregationFieldsAndTypes =
                    aggregationFieldsAndTypes;
            }

            aggregationFieldsAndTypes =
                this.aggregationFieldsCache.AggregationFieldsAndTypes;

            IEnumerable <string> aggregationFields =
                aggregationFieldsAndTypes.Keys.ToList();

            string parameterName  = censusIdentifier.ParameterName;
            string parameterValue = censusIdentifier.ParameterValue;

            Dictionary <string, AggregateQuery> aggregateQueries =
                getCensusRequest.AggregateQueries;

            AssertFieldsAreSupported(aggregationFields, aggregateQueries);

            this.loggerWrapper.Debug(
                $"Fetching {nameof(Census)} using {datasetQueryFile} and " +
                $"supplied aggregate queries...");

            toReturn = await this.censusAdapter.GetCensusAsync(
                aggregationFields,
                datasetQueryFile,
                aggregateQueries,
                parameterName,
                parameterValue,
                this.BuildCensusResults,
                cancellationToken)
                       .ConfigureAwait(false);

            return(toReturn);
        }