< Summary

Information
Class: Elsa.Diagnostics.StructuredLogs.Persistence.Relational.Services.QueryDefinition
Assembly: Elsa.Diagnostics.StructuredLogs.Persistence.Relational
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Services/RelationalStructuredLogSqlBuilder.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 138
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Sql()100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Services/RelationalStructuredLogSqlBuilder.cs

#LineLine coverage
 1using Elsa.Diagnostics.StructuredLogs.Models;
 2using Elsa.Diagnostics.StructuredLogs.Options;
 3using Elsa.Diagnostics.StructuredLogs.Persistence.Relational.Contracts;
 4using Microsoft.Extensions.Options;
 5
 6namespace Elsa.Diagnostics.StructuredLogs.Persistence.Relational.Services;
 7
 8public class RelationalStructuredLogSqlBuilder(IRelationalStructuredLogDialect dialect, IOptions<StructuredLogsOptions> 
 9{
 10    private readonly string _table = dialect.QuoteIdentifier("StructuredLogEvents");
 11
 12    public string BuildInsert()
 13    {
 14        var columns = Columns;
 15        var columnList = string.Join(", ", columns.Select(dialect.QuoteIdentifier));
 16        var parameterList = string.Join(", ", columns.Select(x => $"{dialect.ParameterPrefix}{x}"));
 17        return $"INSERT INTO {_table} ({columnList}) VALUES ({parameterList})";
 18    }
 19
 20    public QueryDefinition BuildQuery(StructuredLogFilter filter)
 21    {
 22        var parameters = new Dictionary<string, object?>();
 23        var predicates = BuildFilterPredicates(filter, parameters);
 24        var where = predicates.Count == 0 ? "" : $" WHERE {string.Join(" AND ", predicates)}";
 25        var limit = options.Value.ClampRecentLogQueryTake(filter.Take);
 26        var sql = $"SELECT {string.Join(", ", Columns.Select(dialect.QuoteIdentifier))} FROM {_table}{where} ORDER BY {d
 27        sql = dialect.ApplyLimit(sql, limit);
 28        return new(sql, parameters);
 29    }
 30
 31    public string BuildListSources()
 32    {
 33        var sourceId = dialect.QuoteIdentifier("SourceId");
 34        var receivedAt = dialect.QuoteIdentifier("ReceivedAt");
 35        return $"SELECT {sourceId}, MAX({receivedAt}) AS {dialect.QuoteIdentifier("LastSeen")} FROM {_table} GROUP BY {s
 36    }
 37
 38    public QueryDefinition BuildDeleteOlderThan(string cutoff)
 39    {
 40        return new($"DELETE FROM {_table} WHERE {dialect.QuoteIdentifier("ReceivedAt")} < {dialect.ParameterPrefix}Cutof
 41    }
 42
 43    public QueryDefinition BuildDeleteRowsBeyondMax(int maxRows)
 44    {
 45        var id = dialect.QuoteIdentifier("Id");
 46        var receivedAt = dialect.QuoteIdentifier("ReceivedAt");
 47        var sequence = dialect.QuoteIdentifier("Sequence");
 48        var selectSql = $"SELECT {id} FROM {_table} ORDER BY {receivedAt} DESC, {sequence} DESC, {id} DESC";
 49        var sql = $"DELETE FROM {_table} WHERE {id} IN ({dialect.ApplyOffset(selectSql, maxRows)})";
 50        return new(sql, new Dictionary<string, object?>());
 51    }
 52
 53    private List<string> BuildFilterPredicates(StructuredLogFilter filter, IDictionary<string, object?> parameters)
 54    {
 55        var predicates = new List<string>();
 56
 57        if (filter.MinimumLevel is { } minimumLevel)
 58            AddPredicate(predicates, parameters, "Level", ">=", (int)minimumLevel);
 59
 60        if (filter.Levels is { Count: > 0 })
 61        {
 62            var names = filter.Levels.Select((level, index) =>
 63            {
 64                var name = $"Level{index}";
 65                parameters[name] = (int)level;
 66                return $"{dialect.ParameterPrefix}{name}";
 67            });
 68            predicates.Add($"{dialect.QuoteIdentifier("Level")} IN ({string.Join(", ", names)})");
 69        }
 70
 71        if (!string.IsNullOrWhiteSpace(filter.CategoryPrefix))
 72            AddPredicate(predicates, parameters, "Category", "LIKE", $"{filter.CategoryPrefix}%");
 73
 74        if (!string.IsNullOrWhiteSpace(filter.Text))
 75        {
 76            parameters["Text"] = $"%{filter.Text}%";
 77            var textParameter = $"{dialect.ParameterPrefix}Text";
 78            predicates.Add($"({dialect.QuoteIdentifier("Message")} LIKE {textParameter} OR {dialect.QuoteIdentifier("Mes
 79        }
 80
 81        AddStringPredicate(predicates, parameters, "TenantId", filter.TenantId);
 82        AddStringPredicate(predicates, parameters, "WorkflowDefinitionId", filter.WorkflowDefinitionId);
 83        AddStringPredicate(predicates, parameters, "WorkflowInstanceId", filter.WorkflowInstanceId);
 84        AddStringPredicate(predicates, parameters, "TraceId", filter.TraceId);
 85        AddStringPredicate(predicates, parameters, "SpanId", filter.SpanId);
 86        AddStringPredicate(predicates, parameters, "CorrelationId", filter.CorrelationId);
 87        AddStringPredicate(predicates, parameters, "SourceId", filter.SourceId);
 88
 89        if (filter.From is { } from)
 90            AddPredicate(predicates, parameters, "Timestamp", ">=", RelationalStructuredLogMapper.FormatTimestamp(from),
 91
 92        if (filter.To is { } to)
 93            AddPredicate(predicates, parameters, "Timestamp", "<=", RelationalStructuredLogMapper.FormatTimestamp(to), "
 94
 95        return predicates;
 96    }
 97
 98    private void AddStringPredicate(ICollection<string> predicates, IDictionary<string, object?> parameters, string colu
 99    {
 100        if (string.IsNullOrWhiteSpace(value))
 101            return;
 102
 103        AddPredicate(predicates, parameters, column, "=", value);
 104    }
 105
 106    private void AddPredicate(ICollection<string> predicates, IDictionary<string, object?> parameters, string column, st
 107    {
 108        var name = parameterName ?? column;
 109        predicates.Add($"{dialect.QuoteIdentifier(column)} {op} {dialect.ParameterPrefix}{name}");
 110        parameters[name] = value;
 111    }
 112
 113    private static readonly string[] Columns =
 114    [
 115        "Id",
 116        "Sequence",
 117        "Timestamp",
 118        "ReceivedAt",
 119        "Level",
 120        "Category",
 121        "EventId",
 122        "EventName",
 123        "Message",
 124        "MessageTemplate",
 125        "ExceptionJson",
 126        "ScopesJson",
 127        "PropertiesJson",
 128        "TraceId",
 129        "SpanId",
 130        "CorrelationId",
 131        "TenantId",
 132        "WorkflowDefinitionId",
 133        "WorkflowInstanceId",
 134        "SourceId"
 135    ];
 136}
 137
 59138public record QueryDefinition(string Sql, IReadOnlyDictionary<string, object?> Parameters);

Methods/Properties

get_Sql()