From 201e4fbea43e828454b9f1fcd5b187dfc16dc618 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 3 Jun 2026 08:53:36 +1000 Subject: [PATCH 1/7] 2026.1 alerts updates --- .../Model/Alerting/AlertActivityPart.cs | 4 +- src/Seq.Api/Model/Alerting/AlertEntity.cs | 14 ++++++- .../Model/Alerting/AlertOccurrencePart.cs | 2 +- .../Model/Alerting/NotificationChannelPart.cs | 2 +- .../AppInstanceOutputMetricsPart.cs | 7 ++++ src/Seq.Api/Model/Shared/JoinKind.cs | 31 +++++++++++++++ src/Seq.Api/Model/Shared/JoinPart.cs | 38 ++++++++++++++++++ .../ResourceGroups/MetricsResourceGroup.cs | 39 ++++++++++++++++--- 8 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 src/Seq.Api/Model/Shared/JoinKind.cs create mode 100644 src/Seq.Api/Model/Shared/JoinPart.cs diff --git a/src/Seq.Api/Model/Alerting/AlertActivityPart.cs b/src/Seq.Api/Model/Alerting/AlertActivityPart.cs index 97f25f5..340e9f1 100644 --- a/src/Seq.Api/Model/Alerting/AlertActivityPart.cs +++ b/src/Seq.Api/Model/Alerting/AlertActivityPart.cs @@ -38,14 +38,14 @@ public class AlertActivityPart /// /// The most recent occurrences of the alert that triggered notifications. /// - public List RecentOccurrences { get; set; } = new List(); + public List RecentOccurrences { get; set; } = new(); /// /// Minimal metrics for the most recent occurrences of the alert that triggered notifications. /// The metrics in this list are a superset of . /// public List RecentOccurrenceRanges { get; set; } = - new List(); + new(); /// /// The number of times this alert has been triggered since its creation. diff --git a/src/Seq.Api/Model/Alerting/AlertEntity.cs b/src/Seq.Api/Model/Alerting/AlertEntity.cs index ad8bab1..d39927d 100644 --- a/src/Seq.Api/Model/Alerting/AlertEntity.cs +++ b/src/Seq.Api/Model/Alerting/AlertEntity.cs @@ -51,11 +51,21 @@ public class AlertEntity : Entity /// public bool IsDisabled { get; set; } + /// + /// The source of the data for the query. + /// + public DataSource DataSource { get; set; } = DataSource.Stream; + + /// + /// Lateral joins applied to the data source. + /// + public List Joins { get; set; } = []; + /// /// An optional limiting the data source that triggers the alert. /// public SignalExpressionPart SignalExpression { get; set; } - + /// /// An optional where clause limiting the data source that triggers the alert. /// @@ -75,7 +85,7 @@ public class AlertEntity : Entity /// /// The individual measurements that will be tested by the alert condition. /// - public List Select { get; set; } = new List(); + public List Select { get; set; } = []; /// /// The alert condition. This is a having clause over the grouped results diff --git a/src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs b/src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs index 8104e3d..fd04f7a 100644 --- a/src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs +++ b/src/Seq.Api/Model/Alerting/AlertOccurrencePart.cs @@ -28,6 +28,6 @@ public class AlertOccurrencePart /// /// The NotificationChannelParts that were alerted. /// - public List Notifications { get; set; } = new List(); + public List Notifications { get; set; } = new(); } } \ No newline at end of file diff --git a/src/Seq.Api/Model/Alerting/NotificationChannelPart.cs b/src/Seq.Api/Model/Alerting/NotificationChannelPart.cs index 37988dc..bd901a9 100644 --- a/src/Seq.Api/Model/Alerting/NotificationChannelPart.cs +++ b/src/Seq.Api/Model/Alerting/NotificationChannelPart.cs @@ -58,6 +58,6 @@ public class NotificationChannelPart /// by the alert. /// public Dictionary NotificationAppSettingOverrides { get; set; } = - new Dictionary(); + new(); } } diff --git a/src/Seq.Api/Model/AppInstances/AppInstanceOutputMetricsPart.cs b/src/Seq.Api/Model/AppInstances/AppInstanceOutputMetricsPart.cs index d0f36bb..4e1c114 100644 --- a/src/Seq.Api/Model/AppInstances/AppInstanceOutputMetricsPart.cs +++ b/src/Seq.Api/Model/AppInstances/AppInstanceOutputMetricsPart.cs @@ -11,5 +11,12 @@ public class AppInstanceOutputMetricsPart /// it being processed by the app. /// public int DispatchedEventsPerMinute { get; set; } + + /// + /// The number of events per minute that failed to reach the app from Seq. Includes streamed events (if enabled), + /// manual invocations, and alert notifications. This value doesn't track events the app may have internally + /// failed to process. + /// + public int FailedEventsPerMinute { get; set; } } } diff --git a/src/Seq.Api/Model/Shared/JoinKind.cs b/src/Seq.Api/Model/Shared/JoinKind.cs new file mode 100644 index 0000000..59328d5 --- /dev/null +++ b/src/Seq.Api/Model/Shared/JoinKind.cs @@ -0,0 +1,31 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Seq.Api.Model.Shared; + +/// +/// A type of relational join. +/// +public enum JoinKind +{ + /// + /// The unknown join kind. + /// + Unknown, + + /// + /// A join type that joins each row to the output of a table function evaluated in the context of the row. + /// + Lateral +} \ No newline at end of file diff --git a/src/Seq.Api/Model/Shared/JoinPart.cs b/src/Seq.Api/Model/Shared/JoinPart.cs new file mode 100644 index 0000000..51a439c --- /dev/null +++ b/src/Seq.Api/Model/Shared/JoinPart.cs @@ -0,0 +1,38 @@ +// Copyright © Datalust and contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Seq.Api.Model.Shared; + +#nullable enable + +/// +/// The lateral cross join part of a from clause. +/// +public class JoinPart +{ + /// + /// The type of relational join. + /// + public JoinKind Kind { get; set; } + + /// + /// The set function call used in the lateral join. + /// + public string? SetFunctionCall { get; set; } + + /// + /// The alias of the set function call. + /// + public string? Alias { get; set; } +} \ No newline at end of file diff --git a/src/Seq.Api/ResourceGroups/MetricsResourceGroup.cs b/src/Seq.Api/ResourceGroups/MetricsResourceGroup.cs index 182c7c0..29c5df5 100644 --- a/src/Seq.Api/ResourceGroups/MetricsResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/MetricsResourceGroup.cs @@ -37,8 +37,8 @@ internal MetricsResourceGroup(ILoadResourceGroup connection) /// A strict Seq filter expression to match (text expressions must be in double quotes). To /// convert a "fuzzy" filter into a strict one the way the Seq UI does, use . /// The number of definitions to retrieve. If not specified will default to 30. - /// The earliest timestamp from which to include events in the query result. - /// The exclusive latest timestamp to which events are included in the query result. The default is the current time. + /// The earliest timestamp from which to include definitions in the query result. + /// The exclusive latest timestamp to which definitions are included in the query result. The default is the current time. /// The query timeout; if not specified, the query will run until completion. /// Values for any free variables that appear in . /// Enable detailed (server-side) query tracing. @@ -61,13 +61,13 @@ public async Task SearchAsync( } /// - /// Retrieve information about the labels available for filtering samples matching a set of search criteria. + /// Retrieve information about the dimensions available for filtering samples matching a set of search criteria. /// - /// The number of definitions to retrieve. If not specified will default to 30. + /// The number of dimensions to retrieve. If not specified will default to 30. /// Optionally, the name of a metric to limit dimension search to. By default, dimensions /// for all metrics are returned. - /// The earliest timestamp from which to include events in the query result. - /// The exclusive latest timestamp to which events are included in the query result. The default is the current time. + /// The earliest timestamp from which to include dimensions in the query result. + /// The exclusive latest timestamp to which dimensions are included in the query result. The default is the current time. /// The query timeout; if not specified, the query will run until completion. /// Enable detailed (server-side) query tracing. /// Token through which the operation can be cancelled. @@ -88,6 +88,33 @@ public async Task> ListDimensionsAsync( return await GroupPostAsync>("Dimensions", body, parameters, cancellationToken).ConfigureAwait(false); } + /// + /// Retrieve the top values associated with the metric dimension . + /// + /// The dimension's accessor. This is generally a simple property path (cluster.node.name) but can + /// use explict root namespaces and indexer notation (@Resource.cluster['node name']) if necessary. + /// The number of values to retrieve. If not specified will default to 30. + /// The earliest timestamp from which to include values in the query result. + /// The exclusive latest timestamp to which values are included in the query result. The default is the current time. + /// The query timeout; if not specified, the query will run until completion. + /// Enable detailed (server-side) query tracing. + /// Token through which the operation can be cancelled. + /// A structured result set. + public async Task> ListDimensionValuesAsync( + string accessor, + int count = 30, + DateTime? rangeStartUtc = null, + DateTime? rangeEndUtc = null, + TimeSpan? timeout = null, + bool trace = false, + CancellationToken cancellationToken = default) + { + var parameters = MakeParameters(null, null, count, rangeStartUtc, rangeEndUtc, timeout, trace); + parameters.Add(nameof(accessor), accessor); + var body = new EvaluationContextPart(); + return await GroupPostAsync>("DimensionValues", body, parameters, cancellationToken).ConfigureAwait(false); + } + static Dictionary MakeParameters(List groups, string filter, int count, DateTime? rangeStartUtc, DateTime? rangeEndUtc, TimeSpan? timeout, bool trace) { var parameters = new Dictionary From dbe447d15195badf05f2145733b426fbd173c8c5 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 3 Jun 2026 09:46:59 +1000 Subject: [PATCH 2/7] Aggregation preference updates --- .../Metrics/MetricAggregationPreference.cs | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/Seq.Api/Model/Metrics/MetricAggregationPreference.cs b/src/Seq.Api/Model/Metrics/MetricAggregationPreference.cs index a9e0985..e077c02 100644 --- a/src/Seq.Api/Model/Metrics/MetricAggregationPreference.cs +++ b/src/Seq.Api/Model/Metrics/MetricAggregationPreference.cs @@ -6,27 +6,37 @@ namespace Seq.Api.Model.Metrics; public enum MetricAggregationPreference { /// - /// The count() aggregate function. + /// The total count of observed values. /// - Count, - + Total, + /// - /// The sum() aggregate function. + /// The sum of all observed values. /// Sum, /// - /// The min() aggregate function. + /// The counts of values falling in each histogram bucket. + /// + BucketSum, + + /// + /// The smallest observed value. /// Min, /// - /// The mean() aggregate function. + /// The center observed value. /// Mean, /// - /// The max() aggregate function. + /// The largest observed value. + /// + Max, + + /// + /// The set of values greater than a percentage of all other observed values. /// - Max + Percentiles } \ No newline at end of file From af6910d3916ae175d40688bd001267cdb95ff58a Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 3 Jun 2026 10:42:13 +1000 Subject: [PATCH 3/7] Add Data.TryQueryAsync() to better support syntax error reporting --- src/Seq.Api/Client/SeqApiClient.cs | 23 +++++++++++-- .../ResourceGroups/ApiResourceGroup.cs | 7 ++++ .../ResourceGroups/DataResourceGroup.cs | 34 ++++++++++++++++++- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/Seq.Api/Client/SeqApiClient.cs b/src/Seq.Api/Client/SeqApiClient.cs index d25ae82..8ea024c 100644 --- a/src/Seq.Api/Client/SeqApiClient.cs +++ b/src/Seq.Api/Client/SeqApiClient.cs @@ -191,6 +191,14 @@ public async Task PostAsync(ILinked entity, strin return _serializer.Deserialize(new JsonTextReader(new StreamReader(stream))); } + // Throws on 5xx errors; callers are expected to derive 4xx error information from the response stream. + internal async Task TryPostAsync(ILinked entity, string link, TEntity content, IDictionary parameters = null, CancellationToken cancellationToken = default) + { + var linkUri = ResolveLink(entity, link, parameters); + var request = new HttpRequestMessage(HttpMethod.Post, linkUri) { Content = MakeJsonContent(content) }; + var stream = await HttpTrySendAsync(request, cancellationToken).ConfigureAwait(false); + return _serializer.Deserialize(new JsonTextReader(new StreamReader(stream))); + } /// /// Issue a POST request accepting a serialized and returning a string by following from . /// @@ -452,8 +460,19 @@ async Task HttpGetStringAsync(string url, CancellationToken cancellation #endif ).ConfigureAwait(false); } - + + // Throws on 5xx errors; callers are expected to derive 4xx error information from the response stream. + async Task HttpTrySendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) + { + return await HttpSendAsyncCore(request, throwOn4xx: false, cancellationToken); + } + async Task HttpSendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) + { + return await HttpSendAsyncCore(request, throwOn4xx: true, cancellationToken); + } + + async Task HttpSendAsyncCore(HttpRequestMessage request, bool throwOn4xx, CancellationToken cancellationToken) { var response = await HttpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); var stream = await response.Content.ReadAsStreamAsync( @@ -462,7 +481,7 @@ async Task HttpSendAsync(HttpRequestMessage request, CancellationToken c #endif ).ConfigureAwait(false); - if (response.IsSuccessStatusCode) + if (response.IsSuccessStatusCode || (!throwOn4xx && (int)response.StatusCode >= 400 && (int)response.StatusCode < 500)) { return stream; } diff --git a/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs b/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs index 4347f64..6ecf7c9 100644 --- a/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs @@ -159,6 +159,13 @@ protected async Task GroupPostAsync(string link, var group = await LoadGroupAsync(cancellationToken).ConfigureAwait(false); return await Client.PostAsync(group, link, content, parameters, cancellationToken).ConfigureAwait(false); } + + // Throws on 5xx errors; callers are expected to derive 4xx error information from the response stream. + internal async Task GroupTryPostAsync(string link, TEntity content, IDictionary parameters = null, CancellationToken cancellationToken = default) + { + var group = await LoadGroupAsync(cancellationToken).ConfigureAwait(false); + return await Client.TryPostAsync(group, link, content, parameters, cancellationToken).ConfigureAwait(false); + } /// /// Update an entity. diff --git a/src/Seq.Api/ResourceGroups/DataResourceGroup.cs b/src/Seq.Api/ResourceGroups/DataResourceGroup.cs index df10b64..5a9d0e3 100644 --- a/src/Seq.Api/ResourceGroups/DataResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/DataResourceGroup.cs @@ -33,7 +33,8 @@ internal DataResourceGroup(ILoadResourceGroup connection) } /// - /// Execute an SQL query and retrieve the result set as a structured . + /// Execute an SQL query and retrieve the result set as a structured . For non-throwing + /// syntax error reporting, see . /// /// The query to execute. /// The earliest timestamp from which to include events in the query result. @@ -61,6 +62,37 @@ public async Task QueryAsync( return await GroupPostAsync("Query", body, parameters, cancellationToken).ConfigureAwait(false); } + /// + /// Execute an SQL query and retrieve the result set as a structured . This method + /// differs from by returning a result object with error information instead of throwing + /// when the query syntax is invalid. + /// + /// The query to execute. + /// The earliest timestamp from which to include events in the query result. + /// The exclusive latest timestamp to which events are included in the query result. The default is the current time. + /// A signal expression over which the query will be executed. + /// A constructed signal that may not appear on the server, for example, a that has been + /// created but not saved, a signal from another server, or the modified representation of an entity already persisted. + /// The query timeout; if not specified, the query will run until completion. + /// Values for any free variables that appear in . + /// Enable detailed (server-side) query tracing. + /// Token through which the operation can be cancelled. + /// A structured result set or syntax/execution error information. + public async Task TryQueryAsync( + string query, + DateTime? rangeStartUtc = null, + DateTime? rangeEndUtc = null, + SignalExpressionPart signal = null, + SignalEntity unsavedSignal = null, + TimeSpan? timeout = null, + Dictionary variables = null, + bool trace = false, + CancellationToken cancellationToken = default) + { + MakeParameters(query, rangeStartUtc, rangeEndUtc, signal, unsavedSignal, timeout, variables, trace, out var body, out var parameters); + return await GroupTryPostAsync("Query", body, parameters, cancellationToken).ConfigureAwait(false); + } + /// /// Execute an SQL query and retrieve the result set as a structured . /// From 0c90247c30acf14343dec49a66d10907383fad20 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 3 Jun 2026 10:44:18 +1000 Subject: [PATCH 4/7] Tighten Try* to 400s --- src/Seq.Api/Client/SeqApiClient.cs | 12 ++++++------ src/Seq.Api/ResourceGroups/ApiResourceGroup.cs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Seq.Api/Client/SeqApiClient.cs b/src/Seq.Api/Client/SeqApiClient.cs index 8ea024c..80488e3 100644 --- a/src/Seq.Api/Client/SeqApiClient.cs +++ b/src/Seq.Api/Client/SeqApiClient.cs @@ -191,7 +191,7 @@ public async Task PostAsync(ILinked entity, strin return _serializer.Deserialize(new JsonTextReader(new StreamReader(stream))); } - // Throws on 5xx errors; callers are expected to derive 4xx error information from the response stream. + // Throws on 5xx errors; callers are expected to derive 400 error information from the response stream. internal async Task TryPostAsync(ILinked entity, string link, TEntity content, IDictionary parameters = null, CancellationToken cancellationToken = default) { var linkUri = ResolveLink(entity, link, parameters); @@ -461,18 +461,18 @@ async Task HttpGetStringAsync(string url, CancellationToken cancellation ).ConfigureAwait(false); } - // Throws on 5xx errors; callers are expected to derive 4xx error information from the response stream. + // Throws on 5xx errors; callers are expected to derive 400 error information from the response stream. async Task HttpTrySendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) { - return await HttpSendAsyncCore(request, throwOn4xx: false, cancellationToken); + return await HttpSendAsyncCore(request, throwOn400: false, cancellationToken); } async Task HttpSendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) { - return await HttpSendAsyncCore(request, throwOn4xx: true, cancellationToken); + return await HttpSendAsyncCore(request, throwOn400: true, cancellationToken); } - async Task HttpSendAsyncCore(HttpRequestMessage request, bool throwOn4xx, CancellationToken cancellationToken) + async Task HttpSendAsyncCore(HttpRequestMessage request, bool throwOn400, CancellationToken cancellationToken) { var response = await HttpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); var stream = await response.Content.ReadAsStreamAsync( @@ -481,7 +481,7 @@ async Task HttpSendAsyncCore(HttpRequestMessage request, bool throwOn4xx #endif ).ConfigureAwait(false); - if (response.IsSuccessStatusCode || (!throwOn4xx && (int)response.StatusCode >= 400 && (int)response.StatusCode < 500)) + if (response.IsSuccessStatusCode || (!throwOn400 && response.StatusCode == HttpStatusCode.BadRequest)) { return stream; } diff --git a/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs b/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs index 6ecf7c9..f853503 100644 --- a/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs @@ -160,7 +160,7 @@ protected async Task GroupPostAsync(string link, return await Client.PostAsync(group, link, content, parameters, cancellationToken).ConfigureAwait(false); } - // Throws on 5xx errors; callers are expected to derive 4xx error information from the response stream. + // Throws on 5xx errors; callers are expected to derive 400 error information from the response stream. internal async Task GroupTryPostAsync(string link, TEntity content, IDictionary parameters = null, CancellationToken cancellationToken = default) { var group = await LoadGroupAsync(cancellationToken).ConfigureAwait(false); From 419bb7a3109e2b0c3e8fb678af648882e4939303 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 3 Jun 2026 11:03:52 +1000 Subject: [PATCH 5/7] Drop null response columns on query results --- src/Seq.Api/Model/Data/QueryResultPart.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Seq.Api/Model/Data/QueryResultPart.cs b/src/Seq.Api/Model/Data/QueryResultPart.cs index cbd14ea..0cbffa4 100644 --- a/src/Seq.Api/Model/Data/QueryResultPart.cs +++ b/src/Seq.Api/Model/Data/QueryResultPart.cs @@ -32,6 +32,7 @@ public class QueryResultPart /// /// The columns within the result set (at various levels of the hierarchy). /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string[] Columns { get; set; } /// @@ -43,6 +44,7 @@ public class QueryResultPart /// /// Metadata for the time grouping column. /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public ColumnMetadataPart TimeColumnMetadata { get; set; } /// From 24c75e837079d93f0cff1f66c0c071a061970281 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 3 Jun 2026 11:04:38 +1000 Subject: [PATCH 6/7] Fix doc --- src/Seq.Api/Client/SeqApiClient.cs | 2 +- src/Seq.Api/ResourceGroups/ApiResourceGroup.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Seq.Api/Client/SeqApiClient.cs b/src/Seq.Api/Client/SeqApiClient.cs index 80488e3..14f2c70 100644 --- a/src/Seq.Api/Client/SeqApiClient.cs +++ b/src/Seq.Api/Client/SeqApiClient.cs @@ -191,7 +191,7 @@ public async Task PostAsync(ILinked entity, strin return _serializer.Deserialize(new JsonTextReader(new StreamReader(stream))); } - // Throws on 5xx errors; callers are expected to derive 400 error information from the response stream. + // Callers are expected to derive 400 error information from the response stream. All other result status codes throw. internal async Task TryPostAsync(ILinked entity, string link, TEntity content, IDictionary parameters = null, CancellationToken cancellationToken = default) { var linkUri = ResolveLink(entity, link, parameters); diff --git a/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs b/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs index f853503..48da13d 100644 --- a/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/ApiResourceGroup.cs @@ -160,7 +160,7 @@ protected async Task GroupPostAsync(string link, return await Client.PostAsync(group, link, content, parameters, cancellationToken).ConfigureAwait(false); } - // Throws on 5xx errors; callers are expected to derive 400 error information from the response stream. + // Callers are expected to derive 400 error information from the response stream. All other result status codes throw. internal async Task GroupTryPostAsync(string link, TEntity content, IDictionary parameters = null, CancellationToken cancellationToken = default) { var group = await LoadGroupAsync(cancellationToken).ConfigureAwait(false); From 81e4205d85271039f6a0218d1e73144ca7dbf03e Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 3 Jun 2026 12:21:32 +1000 Subject: [PATCH 7/7] Remove 'SQL' from query terminology where possible. This is a source/binary breaking change, but maintains API compatibility --- .../QueryEntity.cs} | 12 ++++---- .../Model/Workspaces/WorkspaceContentPart.cs | 4 +-- ...sourceGroup.cs => QueriesResourceGroup.cs} | 28 +++++++++---------- src/Seq.Api/SeqConnection.cs | 4 +-- 4 files changed, 24 insertions(+), 24 deletions(-) rename src/Seq.Api/Model/{SqlQueries/SqlQueryEntity.cs => Queries/QueryEntity.cs} (87%) rename src/Seq.Api/ResourceGroups/{SqlQueriesResourceGroup.cs => QueriesResourceGroup.cs} (71%) diff --git a/src/Seq.Api/Model/SqlQueries/SqlQueryEntity.cs b/src/Seq.Api/Model/Queries/QueryEntity.cs similarity index 87% rename from src/Seq.Api/Model/SqlQueries/SqlQueryEntity.cs rename to src/Seq.Api/Model/Queries/QueryEntity.cs index 49b3b15..9630fc8 100644 --- a/src/Seq.Api/Model/SqlQueries/SqlQueryEntity.cs +++ b/src/Seq.Api/Model/Queries/QueryEntity.cs @@ -14,19 +14,19 @@ using Seq.Api.Model.Security; -namespace Seq.Api.Model.SqlQueries +namespace Seq.Api.Model.Queries { /// - /// A saved SQL-style query. + /// A saved query. /// - public class SqlQueryEntity : Entity + public class QueryEntity : Entity { /// - /// Construct a . + /// Construct a . /// - public SqlQueryEntity() + public QueryEntity() { - Title = "New SQL Query"; + Title = "New Query"; Sql = ""; } diff --git a/src/Seq.Api/Model/Workspaces/WorkspaceContentPart.cs b/src/Seq.Api/Model/Workspaces/WorkspaceContentPart.cs index b6924fd..ab4940a 100644 --- a/src/Seq.Api/Model/Workspaces/WorkspaceContentPart.cs +++ b/src/Seq.Api/Model/Workspaces/WorkspaceContentPart.cs @@ -16,7 +16,7 @@ using Seq.Api.Model.Dashboarding; using Seq.Api.Model.Metrics; using Seq.Api.Model.Signals; -using Seq.Api.Model.SqlQueries; +using Seq.Api.Model.Queries; namespace Seq.Api.Model.Workspaces { @@ -31,7 +31,7 @@ public class WorkspaceContentPart public List SignalIds { get; set; } = []; /// - /// A list of ids to include in the workspace. + /// A list of ids to include in the workspace. /// public List QueryIds { get; set; } = []; diff --git a/src/Seq.Api/ResourceGroups/SqlQueriesResourceGroup.cs b/src/Seq.Api/ResourceGroups/QueriesResourceGroup.cs similarity index 71% rename from src/Seq.Api/ResourceGroups/SqlQueriesResourceGroup.cs rename to src/Seq.Api/ResourceGroups/QueriesResourceGroup.cs index 83414ed..671fab2 100644 --- a/src/Seq.Api/ResourceGroups/SqlQueriesResourceGroup.cs +++ b/src/Seq.Api/ResourceGroups/QueriesResourceGroup.cs @@ -17,17 +17,17 @@ using System.Threading; using System.Threading.Tasks; using Seq.Api.Model; -using Seq.Api.Model.SqlQueries; +using Seq.Api.Model.Queries; using Seq.Api.Model.Users; namespace Seq.Api.ResourceGroups { /// - /// Perform operations on saved SQL queries. + /// Perform operations on saved queries. /// - public class SqlQueriesResourceGroup : ApiResourceGroup + public class QueriesResourceGroup : ApiResourceGroup { - internal SqlQueriesResourceGroup(ILoadResourceGroup connection) + internal QueriesResourceGroup(ILoadResourceGroup connection) : base("SqlQueries", connection) { } @@ -38,10 +38,10 @@ internal SqlQueriesResourceGroup(ILoadResourceGroup connection) /// The id of the query. /// A allowing the operation to be canceled. /// The query. - public async Task FindAsync(string id, CancellationToken cancellationToken = default) + public async Task FindAsync(string id, CancellationToken cancellationToken = default) { if (id == null) throw new ArgumentNullException(nameof(id)); - return await GroupGetAsync("Item", new Dictionary { { "id", id } }, cancellationToken).ConfigureAwait(false); + return await GroupGetAsync("Item", new Dictionary { { "id", id } }, cancellationToken).ConfigureAwait(false); } /// @@ -52,10 +52,10 @@ public async Task FindAsync(string id, CancellationToken cancell /// If true, shared queries will be included in the result. /// allowing the operation to be canceled. /// A list containing matching queries. - public async Task> ListAsync(string ownerId = null, bool shared = false, CancellationToken cancellationToken = default) + public async Task> ListAsync(string ownerId = null, bool shared = false, CancellationToken cancellationToken = default) { var parameters = new Dictionary { { "ownerId", ownerId }, { "shared", shared } }; - return await GroupListAsync("Items", parameters, cancellationToken: cancellationToken).ConfigureAwait(false); + return await GroupListAsync("Items", parameters, cancellationToken: cancellationToken).ConfigureAwait(false); } /// @@ -63,9 +63,9 @@ public async Task> ListAsync(string ownerId = null, bool sh /// /// allowing the operation to be canceled. /// The unsaved query. - public async Task TemplateAsync(CancellationToken cancellationToken = default) + public async Task TemplateAsync(CancellationToken cancellationToken = default) { - return await GroupGetAsync("Template", cancellationToken: cancellationToken).ConfigureAwait(false); + return await GroupGetAsync("Template", cancellationToken: cancellationToken).ConfigureAwait(false); } /// @@ -74,9 +74,9 @@ public async Task TemplateAsync(CancellationToken cancellationTo /// The query to add. /// A allowing the operation to be canceled. /// The query, with server-allocated properties such as initialized. - public async Task AddAsync(SqlQueryEntity entity, CancellationToken cancellationToken = default) + public async Task AddAsync(QueryEntity entity, CancellationToken cancellationToken = default) { - return await GroupCreateAsync(entity, cancellationToken: cancellationToken).ConfigureAwait(false); + return await GroupCreateAsync(entity, cancellationToken: cancellationToken).ConfigureAwait(false); } /// @@ -85,7 +85,7 @@ public async Task AddAsync(SqlQueryEntity entity, CancellationTo /// The query to remove. /// A allowing the operation to be canceled. /// A task indicating completion. - public async Task RemoveAsync(SqlQueryEntity entity, CancellationToken cancellationToken = default) + public async Task RemoveAsync(QueryEntity entity, CancellationToken cancellationToken = default) { await Client.DeleteAsync(entity, "Self", entity, cancellationToken: cancellationToken).ConfigureAwait(false); } @@ -96,7 +96,7 @@ public async Task RemoveAsync(SqlQueryEntity entity, CancellationToken cancellat /// The query to update. /// A allowing the operation to be canceled. /// A task indicating completion. - public async Task UpdateAsync(SqlQueryEntity entity, CancellationToken cancellationToken = default) + public async Task UpdateAsync(QueryEntity entity, CancellationToken cancellationToken = default) { await Client.PutAsync(entity, "Self", entity, cancellationToken: cancellationToken).ConfigureAwait(false); } diff --git a/src/Seq.Api/SeqConnection.cs b/src/Seq.Api/SeqConnection.cs index 29f90e2..5ac056d 100644 --- a/src/Seq.Api/SeqConnection.cs +++ b/src/Seq.Api/SeqConnection.cs @@ -180,9 +180,9 @@ public void Dispose() public SignalsResourceGroup Signals => new(this); /// - /// Perform operations on saved SQL queries. + /// Perform operations on saved queries. /// - public SqlQueriesResourceGroup SqlQueries => new(this); + public QueriesResourceGroup Queries => new(this); /// /// Perform operations on known available Seq versions.