public static FieldAggregationsResult Process(string query, bool applyRules = true) { if (String.IsNullOrEmpty(query)) return new FieldAggregationsResult { IsValid = true }; var result = new FieldAggregationsResult { IsValid = true }; string[] aggregations = query.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string aggregation in aggregations) { string[] parts = aggregation.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 2 || parts.Length > 3) return new FieldAggregationsResult { Message = $"Invalid aggregation: {aggregation}"}; string type = parts[0]?.ToLower().Trim(); string field = parts[1]?.ToLower().Trim(); if (String.IsNullOrEmpty(type) || String.IsNullOrEmpty(field)) return new FieldAggregationsResult { Message = $"Invalid type: {type} or field: {field}" }; if (field.StartsWith("data.")) field = $"idx.{field.Substring(5)}-n"; else if (field.StartsWith("ref.")) field = $"idx.{field.Substring(4)}-r"; var fieldType = GetFieldAggregationTypet(type); if (fieldType == null) return new FieldAggregationsResult { Message = $"Invalid type: {type}" }; string defaultValueOrIncludeExclude = parts.Length > 2 && !String.IsNullOrWhiteSpace(parts[2]) ? parts[2]?.Trim() : null; if (fieldType == FieldAggregationType.Term) { var term = new TermFieldAggregation { Field = field }; if (defaultValueOrIncludeExclude != null) { if (defaultValueOrIncludeExclude.StartsWith("-")) term.ExcludePattern = defaultValueOrIncludeExclude.Substring(1).Trim(); else term.IncludePattern = defaultValueOrIncludeExclude; } result.Aggregations.Add(term); } else { result.Aggregations.Add(new FieldAggregation { Type = fieldType.Value, Field = field, DefaultValue = ParseDefaultValue(defaultValueOrIncludeExclude) }); } } if (result.Aggregations.Any(a => !_freeFields.Contains(a.Field))) result.UsesPremiumFeatures = true; return applyRules ? ApplyRules(result, aggregations) : result; }
protected bool Equals(TermFieldAggregation other) { return(base.Equals(other) && String.Equals(ExcludePattern, other.ExcludePattern) && String.Equals(IncludePattern, other.IncludePattern)); }
public static FieldAggregationsResult Process(string query, bool applyRules = true) { if (String.IsNullOrEmpty(query)) { return new FieldAggregationsResult { IsValid = true } } ; var result = new FieldAggregationsResult { IsValid = true }; string[] aggregations = query.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string aggregation in aggregations) { string[] parts = aggregation.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 2 || parts.Length > 3) { return new FieldAggregationsResult { Message = $"Invalid aggregation: {aggregation}" } } ; string type = parts[0]?.ToLower().Trim(); string field = parts[1]?.ToLower().Trim(); if (String.IsNullOrEmpty(type) || String.IsNullOrEmpty(field)) { return new FieldAggregationsResult { Message = $"Invalid type: {type} or field: {field}" } } ; if (field.StartsWith("data.")) { field = $"idx.{field.Substring(5)}-n"; } else if (field.StartsWith("ref.")) { field = $"idx.{field.Substring(4)}-r"; } var fieldType = GetFieldAggregationTypet(type); if (fieldType == null) { return new FieldAggregationsResult { Message = $"Invalid type: {type}" } } ; string defaultValueOrIncludeExclude = parts.Length > 2 && !String.IsNullOrWhiteSpace(parts[2]) ? parts[2]?.Trim() : null; if (fieldType == FieldAggregationType.Term) { var term = new TermFieldAggregation { Field = field }; if (defaultValueOrIncludeExclude != null) { if (defaultValueOrIncludeExclude.StartsWith("-")) { term.ExcludePattern = defaultValueOrIncludeExclude.Substring(1).Trim(); } else { term.IncludePattern = defaultValueOrIncludeExclude; } } result.Aggregations.Add(term); } else { result.Aggregations.Add(new FieldAggregation { Type = fieldType.Value, Field = field, DefaultValue = ParseDefaultValue(defaultValueOrIncludeExclude) }); } } if (result.Aggregations.Any(a => !_freeFields.Contains(a.Field))) { result.UsesPremiumFeatures = true; } return(applyRules ? ApplyRules(result, aggregations) : result); }
protected bool Equals(TermFieldAggregation other) { return base.Equals(other) && String.Equals(ExcludePattern, other.ExcludePattern) && String.Equals(IncludePattern, other.IncludePattern); }
public static FieldAggregationsResult Process(string query, bool applyRules = true) { if (String.IsNullOrEmpty(query)) { return new FieldAggregationsResult { IsValid = true } } ; var result = new FieldAggregationsResult { IsValid = true }; string[] aggregations = query.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string aggregation in aggregations) { string[] parts = aggregation.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 2 || parts.Length > 3) { return new FieldAggregationsResult { Message = $"Invalid aggregation: {aggregation}" } } ; string type = parts[0]?.ToLower().Trim(); string field = parts[1]?.ToLower().Trim(); if (String.IsNullOrEmpty(type) || String.IsNullOrEmpty(field)) { return new FieldAggregationsResult { Message = $"Invalid type: {type} or field: {field}" } } ; if (field.StartsWith("data.")) { field = $"idx.{field.Substring(5)}-n"; } else if (field.StartsWith("ref.")) { field = $"idx.{field.Substring(4)}-r"; } switch (type) { case "avg": result.Aggregations.Add(new FieldAggregation { Type = FieldAggregationType.Average, Field = field }); break; case "distinct": result.Aggregations.Add(new FieldAggregation { Type = FieldAggregationType.Distinct, Field = field }); break; case "sum": result.Aggregations.Add(new FieldAggregation { Type = FieldAggregationType.Sum, Field = field }); break; case "min": result.Aggregations.Add(new FieldAggregation { Type = FieldAggregationType.Min, Field = field }); break; case "max": result.Aggregations.Add(new FieldAggregation { Type = FieldAggregationType.Max, Field = field }); break; case "last": result.Aggregations.Add(new FieldAggregation { Type = FieldAggregationType.Last, Field = field }); break; case "term": var term = new TermFieldAggregation { Field = field }; if (parts.Length > 2 && !String.IsNullOrWhiteSpace(parts[2])) { if (parts[2].StartsWith("-")) { term.ExcludePattern = parts[2].Substring(1).Trim(); } else { term.IncludePattern = parts[2].Trim(); } } result.Aggregations.Add(term); break; default: return(new FieldAggregationsResult { Message = $"Invalid type: {type} for aggregation: {aggregation}" }); } } if (result.Aggregations.Any(a => !_freeFields.Contains(a.Field))) { result.UsesPremiumFeatures = true; } if (applyRules) { if (result.Aggregations.Count > 10) { return new FieldAggregationsResult { Message = "Aggregation count exceeded" } } ; // Duplicate aggregations if (result.Aggregations.Count != aggregations.Length) { return new FieldAggregationsResult { Message = "Duplicate aggregation detected" } } ; // Distinct queries are expensive. if (result.Aggregations.Count(a => a.Type == FieldAggregationType.Distinct) > 1) { return new FieldAggregationsResult { Message = "Distinct aggregation count exceeded" } } ; // Term queries are expensive. var terms = result.Aggregations.Where(a => a.Type == FieldAggregationType.Term).ToList(); if (terms.Count > 1 || terms.Any(a => !_allowedTermFields.Contains(a.Field))) { return new FieldAggregationsResult { Message = "Terms aggregation count exceeded" } } ; // Only allow fields that are numeric or have high commonality. if (result.Aggregations.Any(a => !_allowedFields.Contains(a.Field))) { return new FieldAggregationsResult { Message = "Dissallowed field detected" } } ; } return(result); } }