/// <summary>
        /// Executes a query to Kusto for Fields Caps.
        /// </summary>
        /// <param name="indexName">Index name.</param>
        /// <returns>An object with the field caps.</returns>
        public async Task <FieldCapabilityResponse> GetFieldCapsAsync(string indexName)
        {
            var response = new FieldCapabilityResponse();

            try
            {
                Logger.LogDebug("Getting schema for table '{@indexName}'", indexName);
                var(databaseName, tableName) = KustoDatabaseTableNames.FromElasticIndexName(indexName, Kusto.DefaultDatabaseName);
                string kustoCommand = $".show {KustoQLOperators.Databases} {KustoQLOperators.Schema} | {KustoQLOperators.Where} TableName=='{tableName}' {KustoQLOperators.And} DatabaseName=='{databaseName}' {KustoQLOperators.And} ColumnName!='' | {KustoQLOperators.Project} ColumnName, ColumnType";

                using IDataReader kustoResults = await Kusto.ExecuteControlCommandAsync(kustoCommand, RequestContext);

                MapFieldCaps(kustoResults, response);

                if (response.Fields.Count > 0)
                {
                    return(response);
                }

                Logger.LogDebug("Getting schema for function '{@indexName}'", indexName);
                string functionQuery     = $"{tableName} | {KustoQLOperators.GetSchema} | project ColumnName, ColumnType=DataType";
                var    functionQueryData = new QueryData(functionQuery, tableName, null, null);
                var(timeTaken, reader) = await Kusto.ExecuteQueryAsync(functionQueryData, RequestContext);

                MapFieldCaps(reader, response);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Error while executing GetFieldCaps.");
                throw;
            }

            return(response);
        }
        /// <summary>
        /// Executes a query to Kusto for Index List.
        /// Searches for all tables and all functions that match the index name pattern.
        /// </summary>
        /// <param name="indexName">Index name pattern, e.g. "*", "orders*", "orders".</param>
        /// <returns>A list of Indexes matching the given name pattern.</returns>
        public async Task <IndexListResponseElement> GetIndexListAsync(string indexName)
        {
            var response = new IndexListResponseElement();

            try
            {
                Logger.LogDebug("Listing tables matching '{@indexName}'", indexName);
                var(databaseName, tableName) = KustoDatabaseTableNames.FromElasticIndexName(indexName, Kusto.DefaultDatabaseName);
                string readTablesCommand = $".show {KustoQLOperators.Databases} {KustoQLOperators.Schema} | {KustoQLOperators.Where} TableName != '' | {KustoQLOperators.Distinct} TableName, DatabaseName | {KustoQLOperators.Search} TableName: '{tableName}' | {KustoQLOperators.Search} DatabaseName: '{databaseName}' |  {KustoQLOperators.Project} strcat(DatabaseName, \"{KustoDatabaseTableNames.Separator}\", TableName)";

                using IDataReader kustoTables = await Kusto.ExecuteControlCommandAsync(readTablesCommand, RequestContext);

                if (kustoTables != null)
                {
                    MapIndexList(kustoTables, response);
                }

                Logger.LogDebug("Listing functions matching '{@indexName}'", indexName);
                var    defaultDb            = Kusto.DefaultDatabaseName;
                string readFunctionsCommand = $".show {KustoQLOperators.Functions} | {KustoQLOperators.Where} Parameters == '()' | {KustoQLOperators.Distinct} Name | {KustoQLOperators.Search} Name: '{tableName}' | {KustoQLOperators.Project} strcat(\"{defaultDb}\", \"{KustoDatabaseTableNames.Separator}\", Name)";

                using IDataReader kustoFunctions = await Kusto.ExecuteControlCommandAsync(readFunctionsCommand, RequestContext);

                if (kustoFunctions != null)
                {
                    MapIndexList(kustoFunctions, response);
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "Error while executing GetIndexList.");
                throw;
            }

            return(response);
        }
        /// <inheritdoc/>
        public void Visit(ElasticSearchDSL elasticSearchDSL)
        {
            Ensure.IsNotNull(elasticSearchDSL, nameof(elasticSearchDSL));

            // Preparing the schema with the index name to be used later
            schemaRetriever = schemaRetrieverFactory.Make(elasticSearchDSL.IndexName);

            // base query
            elasticSearchDSL.Query.Accept(this);

            var queryStringBuilder = new StringBuilder();

            var(databaseName, tableName) = KustoDatabaseTableNames.FromElasticIndexName(elasticSearchDSL.IndexName, defaultDatabaseName);

            // when an index-pattern doesn't have a default time filter the query element can be empty
            var translatedQueryExpression = !string.IsNullOrEmpty(elasticSearchDSL.Query.KustoQL) ? $"| {elasticSearchDSL.Query.KustoQL}" : string.Empty;

            // Aggregations
            if (elasticSearchDSL.Query.Bool != null)
            {
                queryStringBuilder.Append($"{KustoQLOperators.Let} _data = database(\"{databaseName}\").{tableName} {translatedQueryExpression};");

                // Aggregations
                if (elasticSearchDSL.Aggregations?.Count > 0)
                {
                    queryStringBuilder.Append('\n').Append($"(_data | {KustoQLOperators.Summarize} ");

                    foreach (var(_, aggregation) in elasticSearchDSL.Aggregations)
                    {
                        aggregation.Accept(this);
                        queryStringBuilder.Append($"{aggregation.KustoQL} ");
                    }

                    queryStringBuilder.Append("| as aggs);");
                }

                // hits (projections...)
                // The size is deserialized property
                // therefore we check 'Size >= 0' to protect the query.
                if (elasticSearchDSL.Size >= 0)
                {
                    queryStringBuilder.Append("\n(_data ");

                    if (elasticSearchDSL.Size > 0)
                    {
                        // we only need to sort if we're returning hits
                        var orderingList = new List <string>();

                        foreach (var sortClause in elasticSearchDSL.Sort)
                        {
                            sortClause.Accept(this);
                            if (!string.IsNullOrEmpty(sortClause.KustoQL))
                            {
                                orderingList.Add(sortClause.KustoQL);
                            }
                        }

                        if (orderingList.Count > 0)
                        {
                            queryStringBuilder.Append($"| {KustoQLOperators.OrderBy} {string.Join(", ", orderingList)} ");
                        }
                    }

                    queryStringBuilder.Append($"| {KustoQLOperators.Limit} {elasticSearchDSL.Size} | as hits)");
                }
            }
            else
            {
                // ViewSingleDocument query
                queryStringBuilder.Append($"database(\"{databaseName}\").{tableName} {translatedQueryExpression} | as hits;");
            }

            elasticSearchDSL.KustoQL = queryStringBuilder.ToString();
        }