diff --git a/.all-contributorsrc b/.all-contributorsrc
index 8909956d..8e875c59 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -120,6 +120,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "techgarage-ir",
+ "name": "Tech Garage",
+ "avatar_url": "https://avatars.githubusercontent.com/u/126519308?v=4",
+ "profile": "https://techgarage.ir/",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 10
diff --git a/.github/workflows/DotNET-build.yml b/.github/workflows/DotNET-build.yml
index 8819d367..41953c96 100644
--- a/.github/workflows/DotNET-build.yml
+++ b/.github/workflows/DotNET-build.yml
@@ -36,11 +36,11 @@ jobs:
with:
distribution: 'temurin'
java-version: '17'
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 'Cache: .nuke/temp, ~/.nuget/packages'
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
.nuke/temp
diff --git a/.github/workflows/JS-build.yml b/.github/workflows/JS-build.yml
index f9f8b72f..36e0f6f0 100644
--- a/.github/workflows/JS-build.yml
+++ b/.github/workflows/JS-build.yml
@@ -36,11 +36,11 @@ jobs:
with:
distribution: 'temurin'
java-version: '17'
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 'Cache: .nuke/temp, ~/.nuget/packages'
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
.nuke/temp
diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml
index 0919c0a5..3da37125 100644
--- a/.github/workflows/Release.yml
+++ b/.github/workflows/Release.yml
@@ -48,11 +48,11 @@ jobs:
with:
distribution: 'temurin'
java-version: '17'
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 'Cache: .nuke/temp, ~/.nuget/packages'
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
.nuke/temp
diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json
index 12486dce..7a201556 100644
--- a/.nuke/build.schema.json
+++ b/.nuke/build.schema.json
@@ -1,68 +1,119 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
- "$ref": "#/definitions/build",
- "title": "Build Schema",
+ "properties": {
+ "Configuration": {
+ "type": "string",
+ "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
+ "enum": [
+ "Debug",
+ "Release"
+ ]
+ },
+ "ElasticProvider": {
+ "type": "string"
+ },
+ "MongoProvider": {
+ "type": "string"
+ },
+ "MsSqlProvider": {
+ "type": "string"
+ },
+ "MySqlProvider": {
+ "type": "string"
+ },
+ "NugetApiKey": {
+ "type": "string",
+ "default": "Secrets must be entered via 'nuke :secrets [profile]'"
+ },
+ "PostgresProvider": {
+ "type": "string"
+ },
+ "Solution": {
+ "type": "string",
+ "description": "Path to a solution file that is automatically loaded"
+ },
+ "SonarToken": {
+ "type": "string",
+ "default": "Secrets must be entered via 'nuke :secrets [profile]'"
+ },
+ "SonarTokenUi": {
+ "type": "string",
+ "default": "Secrets must be entered via 'nuke :secrets [profile]'"
+ },
+ "Ui": {
+ "type": "string"
+ }
+ },
"definitions": {
- "build": {
- "type": "object",
+ "Host": {
+ "type": "string",
+ "enum": [
+ "AppVeyor",
+ "AzurePipelines",
+ "Bamboo",
+ "Bitbucket",
+ "Bitrise",
+ "GitHubActions",
+ "GitLab",
+ "Jenkins",
+ "Rider",
+ "SpaceAutomation",
+ "TeamCity",
+ "Terminal",
+ "TravisCI",
+ "VisualStudio",
+ "VSCode"
+ ]
+ },
+ "ExecutableTarget": {
+ "type": "string",
+ "enum": [
+ "Backend_Clean",
+ "Backend_Compile",
+ "Backend_Report_Ci",
+ "Backend_Restore",
+ "Backend_SonarScan_End",
+ "Backend_SonarScan_Start",
+ "Backend_Test",
+ "Backend_Test_Ci",
+ "Clean",
+ "Frontend_Build",
+ "Frontend_Clean",
+ "Frontend_Restore",
+ "Frontend_Tests",
+ "Frontend_Tests_Ci",
+ "Pack",
+ "Publish"
+ ]
+ },
+ "Verbosity": {
+ "type": "string",
+ "description": "",
+ "enum": [
+ "Verbose",
+ "Normal",
+ "Minimal",
+ "Quiet"
+ ]
+ },
+ "NukeBuild": {
"properties": {
- "Configuration": {
- "type": "string",
- "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
- "enum": [
- "Debug",
- "Release"
- ]
- },
"Continue": {
"type": "boolean",
"description": "Indicates to continue a previously failed build attempt"
},
- "ElasticProvider": {
- "type": "string"
- },
"Help": {
"type": "boolean",
"description": "Shows the help text for this build assembly"
},
"Host": {
- "type": "string",
"description": "Host for execution. Default is 'automatic'",
- "enum": [
- "AppVeyor",
- "AzurePipelines",
- "Bamboo",
- "Bitbucket",
- "Bitrise",
- "GitHubActions",
- "GitLab",
- "Jenkins",
- "Rider",
- "SpaceAutomation",
- "TeamCity",
- "Terminal",
- "TravisCI",
- "VisualStudio",
- "VSCode"
- ]
- },
- "MongoProvider": {
- "type": "string"
- },
- "MsSqlProvider": {
- "type": "string"
- },
- "MySqlProvider": {
- "type": "string"
+ "$ref": "#/definitions/Host"
},
"NoLogo": {
"type": "boolean",
"description": "Disables displaying the NUKE logo"
},
- "NugetApiKey": {
- "type": "string",
- "default": "Secrets must be entered via 'nuke :secrets [profile]'"
- },
"Partition": {
"type": "string",
"description": "Partition to use on CI"
@@ -71,9 +122,6 @@
"type": "boolean",
"description": "Shows the execution plan (HTML)"
},
- "PostgresProvider": {
- "type": "string"
- },
"Profile": {
"type": "array",
"description": "Defines the profiles to load",
@@ -89,78 +137,22 @@
"type": "array",
"description": "List of targets to be skipped. Empty list skips all dependencies",
"items": {
- "type": "string",
- "enum": [
- "Backend_Clean",
- "Backend_Compile",
- "Backend_Report_Ci",
- "Backend_Restore",
- "Backend_SonarScan_End",
- "Backend_SonarScan_Start",
- "Backend_Test",
- "Backend_Test_Ci",
- "Clean",
- "Frontend_Build",
- "Frontend_Clean",
- "Frontend_Restore",
- "Frontend_Tests",
- "Frontend_Tests_Ci",
- "Pack",
- "Publish"
- ]
+ "$ref": "#/definitions/ExecutableTarget"
}
},
- "Solution": {
- "type": "string",
- "description": "Path to a solution file that is automatically loaded"
- },
- "SonarToken": {
- "type": "string",
- "default": "Secrets must be entered via 'nuke :secrets [profile]'"
- },
- "SonarTokenUi": {
- "type": "string",
- "default": "Secrets must be entered via 'nuke :secrets [profile]'"
- },
"Target": {
"type": "array",
"description": "List of targets to be invoked. Default is '{default_target}'",
"items": {
- "type": "string",
- "enum": [
- "Backend_Clean",
- "Backend_Compile",
- "Backend_Report_Ci",
- "Backend_Restore",
- "Backend_SonarScan_End",
- "Backend_SonarScan_Start",
- "Backend_Test",
- "Backend_Test_Ci",
- "Clean",
- "Frontend_Build",
- "Frontend_Clean",
- "Frontend_Restore",
- "Frontend_Tests",
- "Frontend_Tests_Ci",
- "Pack",
- "Publish"
- ]
+ "$ref": "#/definitions/ExecutableTarget"
}
},
- "Ui": {
- "type": "string"
- },
"Verbosity": {
- "type": "string",
"description": "Logging verbosity during build execution. Default is 'Normal'",
- "enum": [
- "Minimal",
- "Normal",
- "Quiet",
- "Verbose"
- ]
+ "$ref": "#/definitions/Verbosity"
}
}
}
- }
+ },
+ "$ref": "#/definitions/NukeBuild"
}
diff --git a/Directory.Build.props b/Directory.Build.props
index bf94e62c..43a15681 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -23,7 +23,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/README.md b/README.md
index fdf1eff1..8d643448 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,12 @@
A simple Serilog log viewer for the following sinks:
- Serilog.Sinks.**MSSqlServer** ([Nuget](https://github.com/serilog/serilog-sinks-mssqlserver))
-- Serilog.Sinks.**MySql** ([Nuget](https://github.com/TeleSoftas/serilog-sinks-mariadb)) and Serilog.Sinks.**MariaDB** [Nuget](https://github.com/TeleSoftas/serilog-sinks-mariadb)
+- Serilog.Sinks.**MySql** ([Nuget](https://github.com/saleem-mirza/serilog-sinks-mysql)) and Serilog.Sinks.**MariaDB** [Nuget](https://github.com/TeleSoftas/serilog-sinks-mariadb)
- Serilog.Sinks.**Postgresql** ([Nuget](https://github.com/b00ted/serilog-sinks-postgresql)) and Serilog.Sinks.**Postgresql.Alternative** ([Nuget](https://github.com/serilog-contrib/Serilog.Sinks.Postgresql.Alternative))
- Serilog.Sinks.**MongoDB** ([Nuget](https://github.com/serilog/serilog-sinks-mongodb))
- Serilog.Sinks.**ElasticSearch** ([Nuget](https://github.com/serilog/serilog-sinks-elasticsearch))
- Serilog.Sinks.**RavenDB** ([Nuget](https://github.com/ravendb/serilog-sinks-ravendb))
+- Serilog.Sinks.**SQLite** ([Nuget](https://github.com/saleem-mirza/serilog-sinks-sqlite/))
@@ -43,6 +44,7 @@ Install one or more of the available providers, based upon your sink(s):
| **Serilog.UI.MongoDbProvider** [[NuGet](https://www.nuget.org/packages/Serilog.UI.MongoDbProvider)] | `dotnet add package Serilog.UI.MongoDbProvider` | `Install-Package Serilog.UI.MongoDbProvider` |
| **Serilog.UI.ElasticSearchProvider** [[NuGet](https://www.nuget.org/packages/Serilog.UI.ElasticSearchProvider)] | `dotnet add package Serilog.UI.ElasticSearchProvider` | `Install-Package Serilog.UI.ElasticSearchProvider` |
| **Serilog.UI.RavenDbProvider** [[NuGet](https://www.nuget.org/packages/Serilog.UI.RavenDbProvider)] | `dotnet add package Serilog.UI.RavenDbProvider` | `Install-Package Serilog.UI.RavenDbProvider` |
+| **Serilog.UI.SQLiteProvider** [[NuGet](https://www.nuget.org/packages/Serilog.UI.SQLiteProvider)] | `dotnet add package Serilog.UI.SQLiteProvider` | `Install-Package Serilog.UI.SQLiteProvider` |
### DI registration
@@ -120,6 +122,7 @@ See [LICENSE](https://github.com/serilog-contrib/serilog-ui/blob/master/LICENSE)
 Uthman 💻 |
 jorgevp 💻 |
+  Tech Garage 💻 |
diff --git a/README_Nuget.md b/README_Nuget.md
index a3f29621..cae30e94 100644
--- a/README_Nuget.md
+++ b/README_Nuget.md
@@ -3,11 +3,12 @@
A simple Serilog log viewer for the following sinks:
- Serilog.Sinks.**MSSqlServer** ([Nuget](https://github.com/serilog/serilog-sinks-mssqlserver))
-- Serilog.Sinks.**MySql** ([Nuget](https://github.com/TeleSoftas/serilog-sinks-mariadb)) and Serilog.Sinks.**MariaDB** [Nuget](https://github.com/TeleSoftas/serilog-sinks-mariadb)
+- Serilog.Sinks.**MySql** ([Nuget](https://github.com/saleem-mirza/serilog-sinks-mysql)) and Serilog.Sinks.**MariaDB** [Nuget](https://github.com/TeleSoftas/serilog-sinks-mariadb)
- Serilog.Sinks.**Postgresql** ([Nuget](https://github.com/b00ted/serilog-sinks-postgresql)) and Serilog.Sinks.**Postgresql.Alternative** ([Nuget](https://github.com/serilog-contrib/Serilog.Sinks.Postgresql.Alternative))
- Serilog.Sinks.**MongoDB** ([Nuget](https://github.com/serilog/serilog-sinks-mongodb))
- Serilog.Sinks.**ElasticSearch** ([Nuget](https://github.com/serilog/serilog-sinks-elasticsearch))
- Serilog.Sinks.**RavenDB** ([Nuget](https://github.com/ravendb/serilog-sinks-ravendb))
+- Serilog.Sinks.**SQLite** ([Nuget](https://github.com/saleem-mirza/serilog-sinks-sqlite/))
# Read the [Wiki](https://github.com/serilog-contrib/serilog-ui/wiki)
@@ -35,6 +36,7 @@ Install one or more of the available providers, based upon your sink(s):
| **Serilog.UI.MongoDbProvider** [[NuGet](https://www.nuget.org/packages/Serilog.UI.MongoDbProvider)] | `dotnet add package Serilog.UI.MongoDbProvider` | `Install-Package Serilog.UI.MongoDbProvider` |
| **Serilog.UI.ElasticSearchProvider** [[NuGet](https://www.nuget.org/packages/Serilog.UI.ElasticSearchProvider)] | `dotnet add package Serilog.UI.ElasticSearchProvider` | `Install-Package Serilog.UI.ElasticSearchProvider` |
| **Serilog.UI.RavenDbProvider** [[NuGet](https://www.nuget.org/packages/Serilog.UI.RavenDbProvider)] | `dotnet add package Serilog.UI.RavenDbProvider` | `Install-Package Serilog.UI.RavenDbProvider` |
+| **Serilog.UI.SQLiteProvider** [[NuGet](https://www.nuget.org/packages/Serilog.UI.SQLiteProvider)] | `dotnet add package Serilog.UI.SQLiteProvider` | `Install-Package Serilog.UI.SQLiteProvider` |
### DI registration
diff --git a/Serilog.Ui.sln b/Serilog.Ui.sln
index 6fa13f8a..8fd5e62c 100644
--- a/Serilog.Ui.sln
+++ b/Serilog.Ui.sln
@@ -61,6 +61,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Ui.RavenDbProvider"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Ui.RavenDbProvider.Tests", "tests\Serilog.Ui.RavenDbProvider.Tests\Serilog.Ui.RavenDbProvider.Tests.csproj", "{B785845B-D858-4562-B224-67468B4FEE41}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Ui.SqliteDataProvider", "src\Serilog.Ui.SqliteDataProvider\Serilog.Ui.SqliteDataProvider.csproj", "{A23F4275-DB47-40C9-96CE-1116E20F5EB7}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Ui.SqliteProvider.Tests", "tests\Serilog.Ui.SqliteProvider.Tests\Serilog.Ui.SqliteProvider.Tests.csproj", "{C9CBABEA-622C-4E11-9D68-816F685E8E0D}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApp", "samples\WebApp\WebApp.csproj", "{8F9A0E5E-8C1D-4FF8-8865-1B362CF51765}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi", "samples\WebApi\WebApi.csproj", "{A2701899-102D-4926-B054-FD76F59A0791}"
@@ -137,6 +141,14 @@ Global
{B785845B-D858-4562-B224-67468B4FEE41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B785845B-D858-4562-B224-67468B4FEE41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B785845B-D858-4562-B224-67468B4FEE41}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A23F4275-DB47-40C9-96CE-1116E20F5EB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A23F4275-DB47-40C9-96CE-1116E20F5EB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A23F4275-DB47-40C9-96CE-1116E20F5EB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A23F4275-DB47-40C9-96CE-1116E20F5EB7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C9CBABEA-622C-4E11-9D68-816F685E8E0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C9CBABEA-622C-4E11-9D68-816F685E8E0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C9CBABEA-622C-4E11-9D68-816F685E8E0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C9CBABEA-622C-4E11-9D68-816F685E8E0D}.Release|Any CPU.Build.0 = Release|Any CPU
{8F9A0E5E-8C1D-4FF8-8865-1B362CF51765}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F9A0E5E-8C1D-4FF8-8865-1B362CF51765}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F9A0E5E-8C1D-4FF8-8865-1B362CF51765}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -168,6 +180,8 @@ Global
{DCB452AD-2E0E-4D6A-B46D-72D0AF247381} = {83E91BE7-19B3-4AE0-992C-9DFF30FC409E}
{8973E5F5-FD9B-41B1-B2D6-8B281754C443} = {ACA69857-2E3E-468C-B0B0-A86852E3492D}
{B785845B-D858-4562-B224-67468B4FEE41} = {75F9223B-15F2-4465-B01D-2A5A49FCD000}
+ {A23F4275-DB47-40C9-96CE-1116E20F5EB7} = {ACA69857-2E3E-468C-B0B0-A86852E3492D}
+ {C9CBABEA-622C-4E11-9D68-816F685E8E0D} = {75F9223B-15F2-4465-B01D-2A5A49FCD000}
{8F9A0E5E-8C1D-4FF8-8865-1B362CF51765} = {157CA77C-513A-409F-8045-E68739AAC8C8}
{A2701899-102D-4926-B054-FD76F59A0791} = {157CA77C-513A-409F-8045-E68739AAC8C8}
EndGlobalSection
diff --git a/Serilog.Ui.sln.DotSettings b/Serilog.Ui.sln.DotSettings
index 4d35b8be..e62a5d60 100644
--- a/Serilog.Ui.sln.DotSettings
+++ b/Serilog.Ui.sln.DotSettings
@@ -1,2 +1,3 @@
- True
\ No newline at end of file
+ True
+ True
\ No newline at end of file
diff --git a/build/_build.csproj b/build/_build.csproj
index 65b26c59..0027e160 100644
--- a/build/_build.csproj
+++ b/build/_build.csproj
@@ -25,8 +25,8 @@
-
-
+
+
diff --git a/samples/WebApi/WebApi.csproj b/samples/WebApi/WebApi.csproj
index 0ee86da5..574a2a7a 100644
--- a/samples/WebApi/WebApi.csproj
+++ b/samples/WebApi/WebApi.csproj
@@ -14,7 +14,7 @@
-
+
@@ -22,9 +22,9 @@
diff --git a/samples/WebApp/WebApp.csproj b/samples/WebApp/WebApp.csproj
index ed8b0fa2..4771bc46 100644
--- a/samples/WebApp/WebApp.csproj
+++ b/samples/WebApp/WebApp.csproj
@@ -18,7 +18,7 @@
-
+
@@ -38,8 +38,8 @@
diff --git a/src/Serilog.Ui.Core/QueryBuilder/Sql/SinkColumnNames.cs b/src/Serilog.Ui.Core/QueryBuilder/Sql/SinkColumnNames.cs
new file mode 100644
index 00000000..786c1d1a
--- /dev/null
+++ b/src/Serilog.Ui.Core/QueryBuilder/Sql/SinkColumnNames.cs
@@ -0,0 +1,37 @@
+namespace Serilog.Ui.Core.QueryBuilder.Sql;
+
+///
+/// Represents the column names used in the SQL-based sink for logging.
+///
+public abstract class SinkColumnNames
+{
+ ///
+ /// Gets or sets the message of the log entry.
+ ///
+ public string Message { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the message template of the log entry.
+ ///
+ public string MessageTemplate { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the level of the log entry.
+ ///
+ public string Level { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the timestamp of the log entry.
+ ///
+ public string Timestamp { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the exception of the log entry.
+ ///
+ public string Exception { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the serialized log event like properties.
+ ///
+ public string LogEventSerialized { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.Core/QueryBuilder/Sql/SqlQueryBuilder.cs b/src/Serilog.Ui.Core/QueryBuilder/Sql/SqlQueryBuilder.cs
new file mode 100644
index 00000000..b9b112b3
--- /dev/null
+++ b/src/Serilog.Ui.Core/QueryBuilder/Sql/SqlQueryBuilder.cs
@@ -0,0 +1,67 @@
+using Serilog.Ui.Core.Attributes;
+using Serilog.Ui.Core.Models;
+using System.Reflection;
+using static Serilog.Ui.Core.Models.SearchOptions;
+
+namespace Serilog.Ui.Core.QueryBuilder.Sql;
+
+///
+/// Abstract class that provides methods to build SQL queries for fetching and counting logs.
+///
+public abstract class SqlQueryBuilder where TModel : LogModel
+{
+ ///
+ /// Builds a SQL query to fetch logs from the specified table.
+ ///
+ /// The column names used in the sink for logging.
+ /// The schema of the table.
+ /// The name of the table.
+ /// The query parameters for fetching logs.
+ /// A SQL query string to fetch logs.
+ public abstract string BuildFetchLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query);
+
+ ///
+ /// Builds a SQL query to count logs in the specified table.
+ ///
+ /// The column names used in the sink for logging.
+ /// The schema of the table.
+ /// The name of the table.
+ /// The query parameters for counting logs.
+ /// A SQL query string to count logs.
+ public abstract string BuildCountLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query);
+
+ ///
+ /// Generates a SQL sort clause based on the specified sort property and direction.
+ ///
+ /// The column names used in the sink for logging.
+ /// The property to sort on.
+ /// The direction to sort by.
+ /// A SQL sort clause string.
+ protected abstract string GenerateSortClause(SinkColumnNames columns, SortProperty sortOn, SortDirection sortBy);
+
+ ///
+ /// Generates a SQL sort clause based on the specified sort property and direction.
+ ///
+ /// The column names used in the sink for logging.
+ /// The property to sort on.
+ /// A SQL sort clause string.
+ protected static string GetSortColumnName(SinkColumnNames columns, SortProperty sortOn) => sortOn switch
+ {
+ SortProperty.Timestamp => columns.Timestamp,
+ SortProperty.Level => columns.Level,
+ SortProperty.Message => columns.Message,
+ _ => columns.Timestamp
+ };
+
+ ///
+ /// Determines whether to add the exception column to the WHERE clause based on the presence of the RemovedColumnAttribute.
+ ///
+ /// True if the exception column should be added to the WHERE clause; otherwise, false.
+ protected static bool AddExceptionToWhereClause()
+ {
+ PropertyInfo? exceptionProperty = typeof(TModel).GetProperty("Exception");
+ RemovedColumnAttribute? att = exceptionProperty?.GetCustomAttribute();
+
+ return att is null;
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.Core/Serilog.Ui.Core.csproj b/src/Serilog.Ui.Core/Serilog.Ui.Core.csproj
index cf49d99e..4cb6fb32 100644
--- a/src/Serilog.Ui.Core/Serilog.Ui.Core.csproj
+++ b/src/Serilog.Ui.Core/Serilog.Ui.Core.csproj
@@ -3,12 +3,12 @@
netstandard2.0
True
latest
- 3.0.0
+ 3.1.0
-
+
-
+
\ No newline at end of file
diff --git a/src/Serilog.Ui.ElasticSearchProvider/Serilog.Ui.ElasticSearchProvider.csproj b/src/Serilog.Ui.ElasticSearchProvider/Serilog.Ui.ElasticSearchProvider.csproj
index a5be13be..bfd5db6e 100644
--- a/src/Serilog.Ui.ElasticSearchProvider/Serilog.Ui.ElasticSearchProvider.csproj
+++ b/src/Serilog.Ui.ElasticSearchProvider/Serilog.Ui.ElasticSearchProvider.csproj
@@ -5,7 +5,7 @@
netstandard2.0
latest
- 3.0.0
+ 3.1.0
Ricardo Demauro - rmauro.dev
ElasticSearch data provider for Serilog UI.
diff --git a/src/Serilog.Ui.MongoDbProvider/Serilog.Ui.MongoDbProvider.csproj b/src/Serilog.Ui.MongoDbProvider/Serilog.Ui.MongoDbProvider.csproj
index 988835d3..8b3898a1 100644
--- a/src/Serilog.Ui.MongoDbProvider/Serilog.Ui.MongoDbProvider.csproj
+++ b/src/Serilog.Ui.MongoDbProvider/Serilog.Ui.MongoDbProvider.csproj
@@ -4,7 +4,7 @@
Serilog.UI.MongoDbProvider
netstandard2.0
latest
- 3.0.0
+ 3.1.0
Christian Haase
MongoDB data provider for Serilog UI.
diff --git a/src/Serilog.Ui.MsSqlServerProvider/Extensions/SerilogUiOptionBuilderExtensions.cs b/src/Serilog.Ui.MsSqlServerProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
index a1d67b01..30f36029 100644
--- a/src/Serilog.Ui.MsSqlServerProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
+++ b/src/Serilog.Ui.MsSqlServerProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
@@ -1,64 +1,64 @@
-using System;
-using Dapper;
+using Dapper;
using Microsoft.Extensions.DependencyInjection;
using Serilog.Ui.Core;
using Serilog.Ui.Core.Interfaces;
using Serilog.Ui.Core.Models.Options;
+using System;
-namespace Serilog.Ui.MsSqlServerProvider.Extensions
-{
- ///
- /// SQL Server data provider specific extension methods for .
- ///
- public static class SerilogUiOptionBuilderExtensions
- {
- /// Configures the SerilogUi to connect to a SQL Server database.
- /// The options builder.
- /// The Ms Sql options action.
- ///
- /// Delegate to customize the DateTime parsing.
- /// It throws if the return DateTime isn't UTC kind.
- ///
- public static ISerilogUiOptionsBuilder UseSqlServer(
- this ISerilogUiOptionsBuilder optionsBuilder,
- Action setupOptions,
- Func? dateTimeCustomParsing = null
- ) => optionsBuilder.UseSqlServer(setupOptions, dateTimeCustomParsing);
-
- /// Configures the SerilogUi to connect to a SQL Server database.
- /// The log model, containing any additional columns. It must inherit .
- /// The options builder.
- /// The Ms Sql options action.
- ///
- /// Delegate to customize the DateTime parsing.
- /// It throws if the return DateTime isn't UTC kind.
- ///
- public static ISerilogUiOptionsBuilder UseSqlServer(
- this ISerilogUiOptionsBuilder optionsBuilder,
- Action setupOptions,
- Func? dateTimeCustomParsing = null
- ) where T : SqlServerLogModel
- {
- var dbOptions = new RelationalDbOptions("dbo");
- setupOptions(dbOptions);
- dbOptions.Validate();
-
- var providerName = dbOptions.GetProviderName(SqlServerDataProvider.MsSqlProviderName);
+namespace Serilog.Ui.MsSqlServerProvider.Extensions;
- optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
- SqlMapper.AddTypeHandler(new DapperDateTimeHandler(dateTimeCustomParsing));
+///
+/// SQL Server data provider specific extension methods for .
+///
+public static class SerilogUiOptionBuilderExtensions
+{
+ /// Configures the SerilogUi to connect to a SQL Server database.
+ /// The options builder.
+ /// The Ms Sql options action.
+ ///
+ /// Delegate to customize the DateTime parsing.
+ /// It throws if the return DateTime isn't UTC kind.
+ ///
+ public static ISerilogUiOptionsBuilder UseSqlServer(
+ this ISerilogUiOptionsBuilder optionsBuilder,
+ Action setupOptions,
+ Func? dateTimeCustomParsing = null
+ ) => optionsBuilder.UseSqlServer(setupOptions, dateTimeCustomParsing);
- var customModel = typeof(T) != typeof(SqlServerLogModel);
- if (customModel)
- {
- optionsBuilder.RegisterColumnsInfo(providerName);
- optionsBuilder.Services.AddScoped(_ => new SqlServerDataProvider(dbOptions));
+ /// Configures the SerilogUi to connect to a SQL Server database.
+ /// The log model, containing any additional columns. It must inherit .
+ /// The options builder.
+ /// The Ms Sql options action.
+ ///
+ /// Delegate to customize the DateTime parsing.
+ /// It throws if the return DateTime isn't UTC kind.
+ ///
+ public static ISerilogUiOptionsBuilder UseSqlServer(
+ this ISerilogUiOptionsBuilder optionsBuilder,
+ Action setupOptions,
+ Func? dateTimeCustomParsing = null
+ ) where T : SqlServerLogModel
+ {
+ SqlServerDbOptions dbOptions = new("dbo");
+ setupOptions(dbOptions);
+ dbOptions.Validate();
- return optionsBuilder;
- }
+ string providerName = dbOptions.GetProviderName(SqlServerDataProvider.MsSqlProviderName);
+ optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
+ SqlMapper.AddTypeHandler(new DapperDateTimeHandler(dateTimeCustomParsing));
- optionsBuilder.Services.AddScoped(_ => new SqlServerDataProvider(dbOptions));
- return optionsBuilder;
+ bool customModel = typeof(T) != typeof(SqlServerLogModel);
+ if (customModel)
+ {
+ optionsBuilder.RegisterColumnsInfo(providerName);
+ optionsBuilder.Services.AddScoped(_ => new SqlServerDataProvider(dbOptions, new SqlServerQueryBuilder()));
}
+ else
+ {
+ optionsBuilder.Services.AddScoped(_ =>
+ new SqlServerDataProvider(dbOptions, new SqlServerQueryBuilder()));
+ }
+
+ return optionsBuilder;
}
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MsSqlServerProvider/Extensions/SqlServerDbOptions.cs b/src/Serilog.Ui.MsSqlServerProvider/Extensions/SqlServerDbOptions.cs
new file mode 100644
index 00000000..2e221ec4
--- /dev/null
+++ b/src/Serilog.Ui.MsSqlServerProvider/Extensions/SqlServerDbOptions.cs
@@ -0,0 +1,10 @@
+using Serilog.Ui.Core.Models.Options;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+using Serilog.Ui.MsSqlServerProvider.Models;
+
+namespace Serilog.Ui.MsSqlServerProvider.Extensions;
+
+public class SqlServerDbOptions(string defaultSchemaName) : RelationalDbOptions(defaultSchemaName)
+{
+ public SinkColumnNames ColumnNames { get; } = new SqlServerSinkColumnNames();
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MsSqlServerProvider/SqlServerLogModel.cs b/src/Serilog.Ui.MsSqlServerProvider/Models/SqlServerLogModel.cs
similarity index 100%
rename from src/Serilog.Ui.MsSqlServerProvider/SqlServerLogModel.cs
rename to src/Serilog.Ui.MsSqlServerProvider/Models/SqlServerLogModel.cs
diff --git a/src/Serilog.Ui.MsSqlServerProvider/Models/SqlServerSinkColumnNames.cs b/src/Serilog.Ui.MsSqlServerProvider/Models/SqlServerSinkColumnNames.cs
new file mode 100644
index 00000000..3806f527
--- /dev/null
+++ b/src/Serilog.Ui.MsSqlServerProvider/Models/SqlServerSinkColumnNames.cs
@@ -0,0 +1,16 @@
+using Serilog.Ui.Core.QueryBuilder.Sql;
+
+namespace Serilog.Ui.MsSqlServerProvider.Models;
+
+internal class SqlServerSinkColumnNames : SinkColumnNames
+{
+ public SqlServerSinkColumnNames()
+ {
+ Exception = "Exception";
+ Level = "Level";
+ LogEventSerialized = "Properties";
+ Message = "Message";
+ MessageTemplate = "";
+ Timestamp = "TimeStamp";
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MsSqlServerProvider/Serilog.Ui.MsSqlServerProvider.csproj b/src/Serilog.Ui.MsSqlServerProvider/Serilog.Ui.MsSqlServerProvider.csproj
index ff8363bd..c01d0388 100644
--- a/src/Serilog.Ui.MsSqlServerProvider/Serilog.Ui.MsSqlServerProvider.csproj
+++ b/src/Serilog.Ui.MsSqlServerProvider/Serilog.Ui.MsSqlServerProvider.csproj
@@ -5,7 +5,7 @@
netstandard2.0
latest
- 3.0.0
+ 3.1.0
Microsoft SQL Server data provider for Serilog UI.
serilog serilog-ui serilog.sinks.mssqlserver mssqlserver
@@ -18,5 +18,6 @@
+
\ No newline at end of file
diff --git a/src/Serilog.Ui.MsSqlServerProvider/SqlServerDataProvider.cs b/src/Serilog.Ui.MsSqlServerProvider/SqlServerDataProvider.cs
index 15100abe..93b57651 100644
--- a/src/Serilog.Ui.MsSqlServerProvider/SqlServerDataProvider.cs
+++ b/src/Serilog.Ui.MsSqlServerProvider/SqlServerDataProvider.cs
@@ -1,168 +1,76 @@
-using System.Collections.Generic;
+using Dapper;
+using Microsoft.Data.SqlClient;
+using Serilog.Ui.Core;
+using Serilog.Ui.Core.Models;
+using Serilog.Ui.MsSqlServerProvider.Extensions;
+using System.Collections.Generic;
using System.Data;
using System.Linq;
-using System.Reflection;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Ardalis.GuardClauses;
-using Dapper;
-using Microsoft.Data.SqlClient;
-using Serilog.Ui.Core;
-using Serilog.Ui.Core.Attributes;
-using Serilog.Ui.Core.Models;
-using Serilog.Ui.Core.Models.Options;
-using static Serilog.Ui.Core.Models.SearchOptions;
-
-namespace Serilog.Ui.MsSqlServerProvider
-{
- public class SqlServerDataProvider(RelationalDbOptions options) : SqlServerDataProvider(options)
- {
- protected override string SearchCriteriaWhereQuery() => "OR [Exception] LIKE @Search";
-
- protected override string SelectQuery()
- {
- const string level = $"[{ColumnLevelName}]";
- const string message = $"[{ColumnMessageName}]";
- const string timestamp = $"[{ColumnTimestampName}]";
-
- return $"SELECT [Id], {message}, {level}, {timestamp}, [Exception], [Properties] ";
- }
- }
-
- public class SqlServerDataProvider(RelationalDbOptions options) : IDataProvider
- where T : SqlServerLogModel
- {
- internal const string MsSqlProviderName = "MsSQL";
-
- private protected const string ColumnTimestampName = "TimeStamp";
-
- private protected const string ColumnLevelName = "Level";
-
- private protected const string ColumnMessageName = "Message";
-
- private readonly RelationalDbOptions _options = Guard.Against.Null(options);
-
- public string Name => _options.GetProviderName(MsSqlProviderName);
-
- protected virtual string SelectQuery() => "SELECT * ";
- public async Task<(IEnumerable, int)> FetchDataAsync(FetchLogsQuery queryParams, CancellationToken cancellationToken = default)
- {
- // since sink stores dates in local time, we query by local time
- queryParams.ToLocalDates();
+namespace Serilog.Ui.MsSqlServerProvider;
- var logsTask = GetLogsAsync(queryParams);
- var logCountTask = CountLogsAsync(queryParams);
+///
+public class SqlServerDataProvider(SqlServerDbOptions options, SqlServerQueryBuilder queryBuilder)
+ : SqlServerDataProvider(options, queryBuilder);
- await Task.WhenAll(logsTask, logCountTask);
-
- return (await logsTask, await logCountTask);
- }
-
- private async Task> GetLogsAsync(FetchLogsQuery queryParams)
- {
- var queryBuilder = new StringBuilder();
-
- queryBuilder.Append(SelectQuery());
- queryBuilder.Append($"FROM [{_options.Schema}].[{_options.TableName}] ");
-
- GenerateWhereClause(queryBuilder, queryParams);
-
- GenerateSortClause(queryBuilder, queryParams.SortOn, queryParams.SortBy);
-
- queryBuilder.Append("OFFSET @Offset ROWS FETCH NEXT @Count ROWS ONLY");
-
- var rowNoStart = queryParams.Page * queryParams.Count;
-
- using IDbConnection connection = new SqlConnection(_options.ConnectionString);
- var logs = await connection.QueryAsync(queryBuilder.ToString(),
- new
- {
- Offset = rowNoStart,
- queryParams.Count,
- queryParams.Level,
- Search = queryParams.SearchCriteria != null ? $"%{queryParams.SearchCriteria}%" : null,
- queryParams.StartDate,
- queryParams.EndDate
- });
-
- return logs.Select((item, i) => item.SetRowNo(rowNoStart, i)).ToList();
- }
-
- private async Task CountLogsAsync(FetchLogsQuery queryParams)
- {
- var queryBuilder = new StringBuilder();
- queryBuilder.Append($"SELECT COUNT(Id) FROM [{_options.Schema}].[{_options.TableName}]");
+///
+public class SqlServerDataProvider(SqlServerDbOptions options, SqlServerQueryBuilder queryBuilder) : IDataProvider
+ where T : SqlServerLogModel
+{
+ internal const string MsSqlProviderName = "MsSQL";
- GenerateWhereClause(queryBuilder, queryParams);
+ ///
+ public string Name => options.GetProviderName(MsSqlProviderName);
- using IDbConnection connection = new SqlConnection(_options.ConnectionString);
- return await connection.ExecuteScalarAsync(queryBuilder.ToString(),
- new
- {
- queryParams.Level,
- Search = queryParams.SearchCriteria != null ? "%" + queryParams.SearchCriteria + "%" : null,
- queryParams.StartDate,
- queryParams.EndDate
- });
- }
+ public async Task<(IEnumerable, int)> FetchDataAsync(FetchLogsQuery queryParams, CancellationToken cancellationToken = default)
+ {
+ // since sink stores dates in local time, we query by local time
+ queryParams.ToLocalDates();
- ///
- /// If Exception property is flagged with ,
- /// it removes the Where query part on the Exception field.
- ///
- ///
- protected virtual string SearchCriteriaWhereQuery()
- {
- var exceptionProperty = typeof(T).GetProperty(nameof(SqlServerLogModel.Exception));
- var att = exceptionProperty?.GetCustomAttribute();
- return att is null ? "OR [Exception] LIKE @Search" : string.Empty;
- }
+ var logsTask = GetLogsAsync(queryParams);
+ var logCountTask = CountLogsAsync(queryParams);
- private void GenerateWhereClause(StringBuilder queryBuilder, FetchLogsQuery queryParams)
- {
- var conditionStart = "WHERE";
+ await Task.WhenAll(logsTask, logCountTask);
- if (!string.IsNullOrWhiteSpace(queryParams.Level))
- {
- queryBuilder.Append($"{conditionStart} [{ColumnLevelName}] = @Level ");
- conditionStart = "AND";
- }
+ return (await logsTask, await logCountTask);
+ }
- if (!string.IsNullOrWhiteSpace(queryParams.SearchCriteria))
- {
- queryBuilder.Append($"{conditionStart} [{ColumnMessageName}] LIKE @Search {SearchCriteriaWhereQuery()} ");
- conditionStart = "AND";
- }
+ private async Task> GetLogsAsync(FetchLogsQuery queryParams)
+ {
+ string query = queryBuilder.BuildFetchLogsQuery(options.ColumnNames, options.Schema, options.TableName, queryParams);
+ int rowNoStart = queryParams.Page * queryParams.Count;
- if (queryParams.StartDate != null)
- {
- queryBuilder.Append($"{conditionStart} [{ColumnTimestampName}] >= @StartDate ");
- conditionStart = "AND";
- }
+ using IDbConnection connection = new SqlConnection(options.ConnectionString);
- if (queryParams.EndDate != null)
+ IEnumerable logs = await connection.QueryAsync(query,
+ new
{
- queryBuilder.Append($"{conditionStart} [{ColumnTimestampName}] <= @EndDate ");
- }
- }
+ Offset = rowNoStart,
+ queryParams.Count,
+ queryParams.Level,
+ Search = queryParams.SearchCriteria != null ? $"%{queryParams.SearchCriteria}%" : null,
+ queryParams.StartDate,
+ queryParams.EndDate
+ });
+
+ return logs.Select((item, i) => item.SetRowNo(rowNoStart, i)).ToList();
+ }
- private static void GenerateSortClause(StringBuilder queryBuilder, SortProperty sortOn, SortDirection sortBy)
- {
- var sortOnCol = GetColumnName(sortOn);
- var sortByCol = sortBy.ToString().ToUpper();
+ private async Task CountLogsAsync(FetchLogsQuery queryParams)
+ {
+ string query = queryBuilder.BuildCountLogsQuery(options.ColumnNames, options.Schema, options.TableName, queryParams);
- queryBuilder.Append($"ORDER BY [{sortOnCol}] {sortByCol} ");
- }
+ using IDbConnection connection = new SqlConnection(options.ConnectionString);
- private static string GetColumnName(SortProperty sortOn)
- => sortOn switch
+ return await connection.ExecuteScalarAsync(query,
+ new
{
- SortProperty.Level => ColumnLevelName,
- SortProperty.Message => ColumnMessageName,
- SortProperty.Timestamp => ColumnTimestampName,
- _ => ColumnTimestampName
- };
+ queryParams.Level,
+ Search = queryParams.SearchCriteria != null ? "%" + queryParams.SearchCriteria + "%" : null,
+ queryParams.StartDate,
+ queryParams.EndDate
+ });
}
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MsSqlServerProvider/SqlServerQueryBuilder.cs b/src/Serilog.Ui.MsSqlServerProvider/SqlServerQueryBuilder.cs
new file mode 100644
index 00000000..1bf038d5
--- /dev/null
+++ b/src/Serilog.Ui.MsSqlServerProvider/SqlServerQueryBuilder.cs
@@ -0,0 +1,126 @@
+using Serilog.Ui.Core.Models;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+using System;
+using System.Text;
+
+namespace Serilog.Ui.MsSqlServerProvider;
+
+///
+/// Provides methods to build SQL queries specifically for SQL Server to fetch and count logs.
+///
+/// The type of the log model.
+public class SqlServerQueryBuilder : SqlQueryBuilder where TModel : LogModel
+{
+ ///
+ public override string BuildFetchLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query)
+ {
+ StringBuilder queryStr = new();
+
+ GenerateSelectClause(queryStr, columns, schema, tableName);
+
+ GenerateWhereClause(queryStr, columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate);
+
+ queryStr.Append($"{GenerateSortClause(columns, query.SortOn, query.SortBy)} OFFSET @Offset ROWS FETCH NEXT @Count ROWS ONLY");
+
+ return queryStr.ToString();
+ }
+
+ ///
+ /// Builds a SQL query to count logs in the specified table.
+ ///
+ /// The column names used in the sink for logging.
+ /// The schema of the table.
+ /// The name of the table.
+ /// The query parameters for counting logs.
+ /// A SQL query string to count logs.
+ public override string BuildCountLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query)
+ {
+ StringBuilder queryStr = new();
+
+ queryStr.Append("SELECT COUNT([Id]) ")
+ .Append($"FROM [{schema}].[{tableName}] ");
+
+ GenerateWhereClause(queryStr, columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate);
+
+ return queryStr.ToString();
+ }
+
+ protected override string GenerateSortClause(SinkColumnNames columns, SearchOptions.SortProperty sortOn, SearchOptions.SortDirection sortBy)
+ => $"ORDER BY [{GetSortColumnName(columns, sortOn)}] {sortBy.ToString().ToUpper()}";
+
+ ///
+ /// Generates the SELECT clause for the SQL query.
+ ///
+ /// The StringBuilder to append the SELECT clause to.
+ /// The column names used in the sink for logging.
+ /// The schema of the table.
+ /// The name of the table.
+ private static void GenerateSelectClause(StringBuilder queryBuilder, SinkColumnNames columns, string schema, string tableName)
+ {
+ if (typeof(TModel) != typeof(SqlServerLogModel))
+ {
+ queryBuilder.Append("SELECT * ");
+ }
+ else
+ {
+ queryBuilder.Append("SELECT [Id], ")
+ .Append($"[{columns.Message}], ")
+ .Append($"[{columns.Level}], ")
+ .Append($"[{columns.Timestamp}], ")
+ .Append($"[{columns.Exception}], ")
+ .Append($"[{columns.LogEventSerialized}] ");
+ }
+
+ queryBuilder.Append($"FROM [{schema}].[{tableName}] ");
+ }
+
+ ///
+ /// Generates the WHERE clause for the SQL query.
+ ///
+ /// The StringBuilder to append the WHERE clause to.
+ /// The column names used in the sink for logging.
+ /// The log level to filter by.
+ /// The search criteria to filter by.
+ /// The start date to filter by.
+ /// The end date to filter by.
+ private static void GenerateWhereClause(
+ StringBuilder queryBuilder,
+ SinkColumnNames columns,
+ string? level,
+ string? searchCriteria,
+ DateTime? startDate,
+ DateTime? endDate)
+ {
+ StringBuilder conditions2 = new();
+
+ if (!string.IsNullOrWhiteSpace(level))
+ {
+ conditions2.Append($"AND [{columns.Level}] = @Level ");
+ }
+
+ if (!string.IsNullOrWhiteSpace(searchCriteria))
+ {
+ conditions2.Append($"AND ([{columns.Message}] LIKE @Search ");
+ conditions2.Append(AddExceptionToWhereClause() ? $"OR [{columns.Exception}] LIKE @Search) " : ") ");
+ }
+
+ if (startDate.HasValue)
+ {
+ conditions2.Append($"AND [{columns.Timestamp}] >= @StartDate ");
+ }
+
+ if (endDate.HasValue)
+ {
+ conditions2.Append($"AND [{columns.Timestamp}] <= @EndDate ");
+ }
+
+ if (conditions2.Length <= 0)
+ {
+ return;
+ }
+
+ queryBuilder
+ .Append("WHERE 1 = 1 ")
+ .Append(conditions2);
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/Extensions/MariaDbOptions.cs b/src/Serilog.Ui.MySqlProvider/Extensions/MariaDbOptions.cs
new file mode 100644
index 00000000..1f3be6c0
--- /dev/null
+++ b/src/Serilog.Ui.MySqlProvider/Extensions/MariaDbOptions.cs
@@ -0,0 +1,11 @@
+using Serilog.Ui.MySqlProvider.Models;
+
+namespace Serilog.Ui.MySqlProvider.Extensions;
+
+public class MariaDbOptions : MySqlDbOptions
+{
+ public MariaDbOptions(string defaultSchemaName) : base(defaultSchemaName)
+ {
+ ColumnNames = new MariaDbSinkColumnNames();
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/Extensions/MySqlDbOptions.cs b/src/Serilog.Ui.MySqlProvider/Extensions/MySqlDbOptions.cs
new file mode 100644
index 00000000..f1e07950
--- /dev/null
+++ b/src/Serilog.Ui.MySqlProvider/Extensions/MySqlDbOptions.cs
@@ -0,0 +1,10 @@
+using Serilog.Ui.Core.Models.Options;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+using Serilog.Ui.MySqlProvider.Models;
+
+namespace Serilog.Ui.MySqlProvider.Extensions;
+
+public class MySqlDbOptions(string defaultSchemaName) : RelationalDbOptions(defaultSchemaName)
+{
+ internal SinkColumnNames ColumnNames { get; set; } = new MySqlSinkColumnNames();
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/Extensions/SerilogUiOptionBuilderExtensions.cs b/src/Serilog.Ui.MySqlProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
index 16673cc5..1348591f 100644
--- a/src/Serilog.Ui.MySqlProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
+++ b/src/Serilog.Ui.MySqlProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
@@ -1,84 +1,77 @@
-using System;
-using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection;
using Serilog.Ui.Core;
using Serilog.Ui.Core.Interfaces;
using Serilog.Ui.Core.Models.Options;
+using System;
-namespace Serilog.Ui.MySqlProvider.Extensions
+namespace Serilog.Ui.MySqlProvider.Extensions;
+
+///
+/// MySQL data provider specific extension methods for .
+///
+public static class SerilogUiOptionBuilderExtensions
{
///
- /// MySQL data provider specific extension methods for .
+ /// Configures the SerilogUi to connect to a MySQL/MariaDb database expecting
+ /// Serilog.Sinks.MySQL. defaults.
+ /// Provider expects sink to store timestamp in utc.
///
- public static class SerilogUiOptionBuilderExtensions
+ /// The options builder.
+ /// The MySql options action.
+ public static ISerilogUiOptionsBuilder UseMySqlServer(this ISerilogUiOptionsBuilder optionsBuilder, Action setupOptions)
{
- ///
- /// Configures the SerilogUi to connect to a MySQL/MariaDb database expecting
- /// Serilog.Sinks.MySQL. defaults.
- /// Provider expects sink to store timestamp in utc.
- ///
- /// The options builder.
- /// The MySql options action.
- public static ISerilogUiOptionsBuilder UseMySqlServer(
- this ISerilogUiOptionsBuilder optionsBuilder,
- Action setupOptions
- )
- {
- var dbOptions = new RelationalDbOptions("dbo");
- setupOptions(dbOptions);
- dbOptions.Validate();
-
- var providerName = dbOptions.GetProviderName(MySqlDataProvider.MySqlProviderName);
-
- optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
+ MySqlDbOptions dbOptions = new("dbo");
+ setupOptions(dbOptions);
+ dbOptions.Validate();
- optionsBuilder.Services.AddScoped(_ => new MySqlDataProvider(dbOptions));
+ string providerName = dbOptions.GetProviderName(MySqlDataProvider.MySqlProviderName);
- return optionsBuilder;
- }
+ optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
+ optionsBuilder.Services.AddScoped(_ => new MySqlDataProvider(dbOptions, new MySqlQueryBuilder()));
- ///
- /// Configures the SerilogUi to connect to a MySQL/MariaDb database expecting
- /// Serilog.Sinks.MariaDB. defaults.
- /// Provider expects sink to store timestamp in utc.
- ///
- /// The options builder.
- /// The MySql options action.
- public static ISerilogUiOptionsBuilder UseMariaDbServer(
- this ISerilogUiOptionsBuilder optionsBuilder,
- Action setupOptions
- ) => optionsBuilder.UseMariaDbServer(setupOptions);
+ return optionsBuilder;
+ }
- ///
- /// Configures the SerilogUi to connect to a MySQL/MariaDb database expecting
- /// Serilog.Sinks.MariaDB. defaults.
- /// Provider expects sink to store timestamp in utc.
- ///
- /// The log model, containing any additional columns. It must inherit .
- /// The options builder.
- /// The MySql options action.
- public static ISerilogUiOptionsBuilder UseMariaDbServer(
- this ISerilogUiOptionsBuilder optionsBuilder,
- Action setupOptions
- ) where T : MySqlLogModel
- {
- var dbOptions = new RelationalDbOptions("dbo");
- setupOptions(dbOptions);
- dbOptions.Validate();
+ ///
+ /// Configures the SerilogUi to connect to a MySQL/MariaDb database expecting
+ /// Serilog.Sinks.MariaDB. defaults.
+ /// Provider expects sink to store timestamp in utc.
+ ///
+ /// The options builder.
+ /// The MySql options action.
+ public static ISerilogUiOptionsBuilder UseMariaDbServer(this ISerilogUiOptionsBuilder optionsBuilder, Action setupOptions)
+ => optionsBuilder.UseMariaDbServer(setupOptions);
- var providerName = dbOptions.GetProviderName(MariaDbDataProvider.ProviderName);
+ ///
+ /// Configures the SerilogUi to connect to a MySQL/MariaDb database expecting
+ /// Serilog.Sinks.MariaDB. defaults.
+ /// Provider expects sink to store timestamp in utc.
+ ///
+ /// The log model, containing any additional columns. It must inherit .
+ /// The options builder.
+ /// The MySql options action.
+ public static ISerilogUiOptionsBuilder UseMariaDbServer(this ISerilogUiOptionsBuilder optionsBuilder, Action setupOptions)
+ where T : MySqlLogModel
+ {
+ MariaDbOptions dbOptions = new("dbo");
+ setupOptions(dbOptions);
+ dbOptions.Validate();
- optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
+ string providerName = dbOptions.GetProviderName(MariaDbDataProvider.ProviderName);
- var customModel = typeof(T) != typeof(MySqlLogModel);
- if (customModel)
- {
- optionsBuilder.RegisterColumnsInfo(providerName);
- optionsBuilder.Services.AddScoped(_ => new MariaDbDataProvider(dbOptions));
- return optionsBuilder;
- }
+ optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
- optionsBuilder.Services.AddScoped(_ => new MariaDbDataProvider(dbOptions));
- return optionsBuilder;
+ bool customModel = typeof(T) != typeof(MySqlLogModel);
+ if (customModel)
+ {
+ optionsBuilder.RegisterColumnsInfo(providerName);
+ optionsBuilder.Services.AddScoped(_ => new MariaDbDataProvider(dbOptions, new MySqlQueryBuilder()));
+ }
+ else
+ {
+ optionsBuilder.Services.AddScoped(_ => new MariaDbDataProvider(dbOptions, new MySqlQueryBuilder()));
}
+
+ return optionsBuilder;
}
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/MariaDbDataProvider.cs b/src/Serilog.Ui.MySqlProvider/MariaDbDataProvider.cs
index 92bb825f..37fe6af3 100644
--- a/src/Serilog.Ui.MySqlProvider/MariaDbDataProvider.cs
+++ b/src/Serilog.Ui.MySqlProvider/MariaDbDataProvider.cs
@@ -1,23 +1,16 @@
-using Serilog.Ui.Core.Models.Options;
+using Serilog.Ui.MySqlProvider.Extensions;
using Serilog.Ui.MySqlProvider.Shared;
namespace Serilog.Ui.MySqlProvider;
-public class MariaDbDataProvider(RelationalDbOptions options) : MariaDbDataProvider(options)
-{
- protected override string SelectQuery
- => $"SELECT Id, {ColumnMessageName}, {ColumnLevelName} AS 'Level', {ColumnTimestampName}, Exception, Properties ";
-
- protected override string SearchCriteriaWhereQuery() => "OR Exception LIKE @Search";
-}
+public class MariaDbDataProvider(MariaDbOptions options, MySqlQueryBuilder queryBuilder)
+ : MariaDbDataProvider(options, queryBuilder);
-public class MariaDbDataProvider(RelationalDbOptions options) : DataProvider(options)
+public class MariaDbDataProvider(MariaDbOptions options, MySqlQueryBuilder queryBuilder) : DataProvider(options, queryBuilder)
where T : MySqlLogModel
{
internal const string ProviderName = "MariaDb";
- protected override string ColumnLevelName => "LogLevel";
-
- public override string Name => Options.GetProviderName(ProviderName);
+ public override string Name => options.GetProviderName(ProviderName);
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/Models/MariaDbSinkColumnNames.cs b/src/Serilog.Ui.MySqlProvider/Models/MariaDbSinkColumnNames.cs
new file mode 100644
index 00000000..723a6f0a
--- /dev/null
+++ b/src/Serilog.Ui.MySqlProvider/Models/MariaDbSinkColumnNames.cs
@@ -0,0 +1,16 @@
+using Serilog.Ui.Core.QueryBuilder.Sql;
+
+namespace Serilog.Ui.MySqlProvider.Models;
+
+internal class MariaDbSinkColumnNames : SinkColumnNames
+{
+ public MariaDbSinkColumnNames()
+ {
+ Exception = "Exception";
+ Level = "LogLevel";
+ LogEventSerialized = "Properties";
+ Message = "Message";
+ MessageTemplate = "";
+ Timestamp = "TimeStamp";
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/Models/MySqlLogModel.cs b/src/Serilog.Ui.MySqlProvider/Models/MySqlLogModel.cs
new file mode 100644
index 00000000..a79802d6
--- /dev/null
+++ b/src/Serilog.Ui.MySqlProvider/Models/MySqlLogModel.cs
@@ -0,0 +1,27 @@
+using System;
+using Serilog.Ui.Core.Attributes;
+using Serilog.Ui.Core.Models;
+
+namespace Serilog.Ui.MySqlProvider;
+
+///
+/// MySql/MariaDb Log Model.
+/// , , ,
+/// columns can't be overridden and removed from the model, due to query requirements.
+/// To remove a field, apply on it.
+/// To add a field, register the property with the correct datatype on the child class and the sink.
+///
+public class MySqlLogModel : LogModel
+{
+ public override sealed int RowNo => base.RowNo;
+
+ public override sealed string? Level { get; set; }
+
+ public string LogLevel { get; set; } = string.Empty;
+
+ public override sealed string? Message { get; set; } = string.Empty;
+
+ public override sealed DateTime Timestamp { get; set; }
+
+ public override string PropertyType => "json";
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/Models/MySqlSinkColumnNames.cs b/src/Serilog.Ui.MySqlProvider/Models/MySqlSinkColumnNames.cs
new file mode 100644
index 00000000..67c6888a
--- /dev/null
+++ b/src/Serilog.Ui.MySqlProvider/Models/MySqlSinkColumnNames.cs
@@ -0,0 +1,16 @@
+using Serilog.Ui.Core.QueryBuilder.Sql;
+
+namespace Serilog.Ui.MySqlProvider.Models;
+
+internal class MySqlSinkColumnNames : SinkColumnNames
+{
+ public MySqlSinkColumnNames()
+ {
+ Exception = "Exception";
+ Level = "Level";
+ LogEventSerialized = "Properties";
+ Message = "Message";
+ MessageTemplate = "";
+ Timestamp = "TimeStamp";
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/MySqlDataProvider.cs b/src/Serilog.Ui.MySqlProvider/MySqlDataProvider.cs
index 6bdd363e..b11e8dcb 100644
--- a/src/Serilog.Ui.MySqlProvider/MySqlDataProvider.cs
+++ b/src/Serilog.Ui.MySqlProvider/MySqlDataProvider.cs
@@ -1,15 +1,14 @@
-using Serilog.Ui.Core.Models.Options;
+using Serilog.Ui.MySqlProvider.Extensions;
using Serilog.Ui.MySqlProvider.Shared;
namespace Serilog.Ui.MySqlProvider;
-public class MySqlDataProvider(RelationalDbOptions options) : DataProvider(options)
+public class MySqlDataProvider(MySqlDbOptions options, MySqlQueryBuilder queryBuilder)
+ : DataProvider(options, queryBuilder)
{
- protected override string SelectQuery
- => $"SELECT Id, {ColumnMessageName}, {ColumnLevelName}, {ColumnTimestampName}, Exception, Properties ";
-
- protected override string SearchCriteriaWhereQuery() => "OR Exception LIKE @Search";
+ private readonly MySqlDbOptions _options = options;
internal const string MySqlProviderName = "MySQL";
- public override string Name => Options.GetProviderName(MySqlProviderName);
+
+ public override string Name => _options.GetProviderName(MySqlProviderName);
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/MySqlLogModel.cs b/src/Serilog.Ui.MySqlProvider/MySqlLogModel.cs
deleted file mode 100644
index e1358aaa..00000000
--- a/src/Serilog.Ui.MySqlProvider/MySqlLogModel.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using Serilog.Ui.Core.Attributes;
-using Serilog.Ui.Core.Models;
-
-namespace Serilog.Ui.MySqlProvider
-{
- ///
- /// MySql/MariaDb Log Model.
- /// , , ,
- /// columns can't be overridden and removed from the model, due to query requirements.
- /// To remove a field, apply on it.
- /// To add a field, register the property with the correct datatype on the child class and the sink.
- ///
- public class MySqlLogModel : LogModel
- {
- public sealed override int RowNo => base.RowNo;
-
- public sealed override string? Level { get; set; }
-
- public string LogLevel { get; set; } = string.Empty;
-
- public sealed override string? Message { get; set; } = string.Empty;
-
- public sealed override DateTime Timestamp { get; set; }
-
- public override string PropertyType => "json";
- }
-}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/MySqlQueryBuilder.cs b/src/Serilog.Ui.MySqlProvider/MySqlQueryBuilder.cs
new file mode 100644
index 00000000..b52150f1
--- /dev/null
+++ b/src/Serilog.Ui.MySqlProvider/MySqlQueryBuilder.cs
@@ -0,0 +1,125 @@
+using Serilog.Ui.Core.Models;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+using System;
+using System.Text;
+
+namespace Serilog.Ui.MySqlProvider;
+
+///
+/// Provides methods to build SQL queries specifically for MySQL and MariaDB to fetch and count logs.
+///
+/// The type of the log model.
+public class MySqlQueryBuilder : SqlQueryBuilder where TModel : LogModel
+{
+ ///
+ public override string BuildFetchLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query)
+ {
+ StringBuilder queryStr = new();
+
+ GenerateSelectClause(queryStr, columns, tableName);
+
+ GenerateWhereClause(queryStr, columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate);
+
+ queryStr.Append($"{GenerateSortClause(columns, query.SortOn, query.SortBy)} LIMIT @Offset, @Count");
+
+ return queryStr.ToString();
+ }
+
+ ///
+ /// Builds a SQL query to count logs in the specified table.
+ ///
+ /// The column names used in the sink for logging.
+ /// The schema of the table.
+ /// The name of the table.
+ /// The query parameters for counting logs.
+ /// A SQL query string to count logs.
+ public override string BuildCountLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query)
+ {
+ StringBuilder queryStr = new();
+
+ queryStr.Append("SELECT COUNT(Id) ")
+ .Append($"FROM {tableName} ");
+
+ GenerateWhereClause(queryStr, columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate);
+
+ return queryStr.ToString();
+ }
+
+ protected override string GenerateSortClause(SinkColumnNames columns, SearchOptions.SortProperty sortOn, SearchOptions.SortDirection sortBy)
+ => $"ORDER BY {GetSortColumnName(columns, sortOn)} {sortBy.ToString().ToUpper()}";
+
+ ///
+ /// Generates the SELECT clause for the SQL query.
+ ///
+ /// The StringBuilder to append the SELECT clause to.
+ /// The column names used in the sink for logging.
+ /// The name of the table.
+ private static void GenerateSelectClause(StringBuilder queryBuilder, SinkColumnNames columns, string tableName)
+ {
+ if (typeof(TModel) != typeof(MySqlLogModel))
+ {
+ queryBuilder.Append("SELECT * ");
+ }
+ else
+ {
+ queryBuilder.Append("SELECT Id, ")
+ .Append($"{columns.Message}, ")
+ .Append($"{columns.Level}, ")
+ .Append($"{columns.Timestamp}, ")
+ .Append($"{columns.Exception}, ")
+ .Append($"{columns.LogEventSerialized} ");
+ }
+
+ queryBuilder.Append($"FROM {tableName} ");
+ }
+
+ ///
+ /// Generates the WHERE clause for the SQL query.
+ ///
+ /// The StringBuilder to append the WHERE clause to.
+ /// The column names used in the sink for logging.
+ /// The log level to filter by.
+ /// The search criteria to filter by.
+ /// The start date to filter by.
+ /// The end date to filter by.
+ private static void GenerateWhereClause(
+ StringBuilder queryBuilder,
+ SinkColumnNames columns,
+ string? level,
+ string? searchCriteria,
+ DateTime? startDate,
+ DateTime? endDate)
+ {
+ StringBuilder conditions2 = new();
+
+ if (!string.IsNullOrWhiteSpace(level))
+ {
+ conditions2.Append($"AND {columns.Level} = @Level ");
+ }
+
+ if (!string.IsNullOrWhiteSpace(searchCriteria))
+ {
+ conditions2.Append($"AND ({columns.Message} LIKE @Search ");
+ conditions2.Append(AddExceptionToWhereClause() ? $"OR {columns.Exception} LIKE @Search) " : ") ");
+ }
+
+ if (startDate.HasValue)
+ {
+ conditions2.Append($"AND {columns.Timestamp} >= @StartDate ");
+ }
+
+ if (endDate.HasValue)
+ {
+ conditions2.Append($"AND {columns.Timestamp} <= @EndDate ");
+ }
+
+ if (conditions2.Length <= 0)
+ {
+ return;
+ }
+
+ queryBuilder
+ .Append("WHERE TRUE ")
+ .Append(conditions2);
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/Serilog.Ui.MySqlProvider.csproj b/src/Serilog.Ui.MySqlProvider/Serilog.Ui.MySqlProvider.csproj
index 209595e7..85f3e8ac 100644
--- a/src/Serilog.Ui.MySqlProvider/Serilog.Ui.MySqlProvider.csproj
+++ b/src/Serilog.Ui.MySqlProvider/Serilog.Ui.MySqlProvider.csproj
@@ -4,7 +4,7 @@
Serilog.UI.MySqlProvider
netstandard2.0
latest
- 3.0.0
+ 3.1.0
MySQL and MariaDB data provider for Serilog UI.
serilog serilog-ui serilog.sinks.mysql serilog.sinks.mariadb
@@ -17,5 +17,6 @@
+
\ No newline at end of file
diff --git a/src/Serilog.Ui.MySqlProvider/Shared/DataProvider.cs b/src/Serilog.Ui.MySqlProvider/Shared/DataProvider.cs
index 5a603b03..24c8ccb8 100644
--- a/src/Serilog.Ui.MySqlProvider/Shared/DataProvider.cs
+++ b/src/Serilog.Ui.MySqlProvider/Shared/DataProvider.cs
@@ -1,29 +1,20 @@
-using System;
+using Dapper;
+using MySqlConnector;
+using Serilog.Ui.Core;
+using Serilog.Ui.Core.Models;
+using Serilog.Ui.MySqlProvider.Extensions;
+using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Dapper;
-using MySqlConnector;
-using Serilog.Ui.Core;
-using Serilog.Ui.Core.Attributes;
-using Serilog.Ui.Core.Models;
-using Serilog.Ui.Core.Models.Options;
namespace Serilog.Ui.MySqlProvider.Shared;
-public abstract class DataProvider(RelationalDbOptions options) : IDataProvider
+public abstract class DataProvider(MySqlDbOptions options, MySqlQueryBuilder queryBuilder) : IDataProvider
where T : MySqlLogModel
{
- protected virtual string ColumnTimestampName => "TimeStamp";
-
- protected virtual string ColumnLevelName => "Level";
-
- protected virtual string ColumnMessageName => "Message";
-
- protected readonly RelationalDbOptions Options = options ?? throw new ArgumentNullException(nameof(options));
+ public abstract string Name { get; }
public async Task<(IEnumerable, int)> FetchDataAsync(FetchLogsQuery queryParams, CancellationToken cancellationToken = default)
{
@@ -31,30 +22,19 @@ public abstract class DataProvider(RelationalDbOptions options) : IDataProvid
var logsTask = GetLogsAsync(queryParams);
var logCountTask = CountLogsAsync(queryParams);
-
- await Task.WhenAll(logsTask, logCountTask);
+ await Task.WhenAll(logsTask);
return (await logsTask, await logCountTask);
}
- public abstract string Name { get; }
-
- protected virtual string SelectQuery => "SELECT * ";
-
private async Task> GetLogsAsync(FetchLogsQuery queryParams)
{
- var queryBuilder = new StringBuilder();
- queryBuilder.Append(SelectQuery).Append($"FROM `{Options.TableName}` ");
-
- GenerateWhereClause(queryBuilder, queryParams);
- var sortClause = GenerateSortClause(queryParams.SortOn, queryParams.SortBy);
+ string query = queryBuilder.BuildFetchLogsQuery(options.ColumnNames, options.Schema, options.TableName, queryParams);
+ int rowNoStart = queryParams.Page * queryParams.Count;
- queryBuilder.Append($"ORDER BY {sortClause} LIMIT @Offset, @Count");
+ using MySqlConnection connection = new(options.ConnectionString);
- var rowNoStart = queryParams.Page * queryParams.Count;
-
- using var connection = new MySqlConnection(Options.ConnectionString);
- var param = new
+ IEnumerable logs = await connection.QueryAsync(query, new
{
Offset = rowNoStart,
queryParams.Count,
@@ -62,18 +42,15 @@ private async Task> GetLogsAsync(FetchLogsQuery queryParam
Search = queryParams.SearchCriteria != null ? $"%{queryParams.SearchCriteria}%" : null,
queryParams.StartDate,
queryParams.EndDate
- };
-
- var logs = await connection.QueryAsync(queryBuilder.ToString(), param);
+ });
return logs
.Select((item, i) =>
{
item.SetRowNo(rowNoStart, i);
item.Level ??= item.LogLevel;
- // both sinks save UTC but MariaDb is queried as Unspecified, MySql is queried as Local
- var ts = DateTime.SpecifyKind(item.Timestamp,
- item.Timestamp.Kind == DateTimeKind.Unspecified ? DateTimeKind.Utc : item.Timestamp.Kind);
+ // both sinks save UTC but MariaDb is queried as Unspecified, MySql is queried as Local
+ var ts = DateTime.SpecifyKind(item.Timestamp, item.Timestamp.Kind == DateTimeKind.Unspecified ? DateTimeKind.Utc : item.Timestamp.Kind);
item.Timestamp = ts.ToUniversalTime();
return item;
})
@@ -82,13 +59,11 @@ private async Task> GetLogsAsync(FetchLogsQuery queryParam
private async Task CountLogsAsync(FetchLogsQuery queryParams)
{
- var queryBuilder = new StringBuilder();
- queryBuilder.Append($"SELECT COUNT(Id) FROM `{Options.TableName}` ");
+ string query = queryBuilder.BuildCountLogsQuery(options.ColumnNames, options.Schema, options.TableName, queryParams);
- GenerateWhereClause(queryBuilder, queryParams);
+ using MySqlConnection connection = new(options.ConnectionString);
- using var connection = new MySqlConnection(Options.ConnectionString);
- return await connection.ExecuteScalarAsync(queryBuilder.ToString(),
+ return await connection.ExecuteScalarAsync(query,
new
{
queryParams.Level,
@@ -97,50 +72,4 @@ private async Task CountLogsAsync(FetchLogsQuery queryParams)
queryParams.EndDate
});
}
-
- ///
- /// If Exception property is flagged with ,
- /// it removes the Where query part on the Exception field.
- ///
- ///
- protected virtual string SearchCriteriaWhereQuery()
- {
- var exceptionProperty = typeof(T).GetProperty(nameof(MySqlLogModel.Exception));
- var att = exceptionProperty?.GetCustomAttribute();
- return att is null ? "OR Exception LIKE @Search" : string.Empty;
- }
-
- private void GenerateWhereClause(StringBuilder queryBuilder, FetchLogsQuery queryParams)
- {
- var conditionStart = "WHERE";
-
- if (!string.IsNullOrWhiteSpace(queryParams.Level))
- {
- queryBuilder.Append($"WHERE {ColumnLevelName} = @Level ");
- conditionStart = "AND";
- }
-
- if (!string.IsNullOrWhiteSpace(queryParams.SearchCriteria))
- {
- queryBuilder.Append($"{conditionStart} ({ColumnMessageName} LIKE @Search {SearchCriteriaWhereQuery()}) ");
- conditionStart = "AND";
- }
-
- if (queryParams.StartDate != null)
- {
- queryBuilder.Append($"{conditionStart} {ColumnTimestampName} >= @StartDate ");
- conditionStart = "AND";
- }
-
- if (queryParams.EndDate != null)
- {
- queryBuilder.Append($"{conditionStart} {ColumnTimestampName} <= @EndDate ");
- }
- }
-
- private string GenerateSortClause(SearchOptions.SortProperty sortOn, SearchOptions.SortDirection sortBy)
- {
- var sortProperty = sortOn == SearchOptions.SortProperty.Level ? ColumnLevelName : sortOn.ToString();
- return $"{sortProperty} {sortBy.ToString().ToUpper()}";
- }
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.PostgreSqlProvider/Extensions/PostgreSqlDbOptions.cs b/src/Serilog.Ui.PostgreSqlProvider/Extensions/PostgreSqlDbOptions.cs
index 06cea7c4..0ff48ee9 100644
--- a/src/Serilog.Ui.PostgreSqlProvider/Extensions/PostgreSqlDbOptions.cs
+++ b/src/Serilog.Ui.PostgreSqlProvider/Extensions/PostgreSqlDbOptions.cs
@@ -1,4 +1,5 @@
using Serilog.Ui.Core.Models.Options;
+using Serilog.Ui.Core.QueryBuilder.Sql;
using Serilog.Ui.PostgreSqlProvider.Models;
namespace Serilog.Ui.PostgreSqlProvider.Extensions;
@@ -9,10 +10,9 @@ public class PostgreSqlDbOptions : RelationalDbOptions
///
public PostgreSqlDbOptions(string defaultSchemaName) : base(defaultSchemaName)
{
+ ColumnNames = new PostgreSqlAlternativeSinkColumnNames();
}
- internal SinkColumnNames ColumnNames = new PostgreSqlAlternativeSinkColumnNames();
-
///
/// It gets or sets SinkType.
/// The sink that used to store logs in the PostgreSQL database. This data provider supports
@@ -31,6 +31,9 @@ public PostgreSqlDbOptions WithSinkType(PostgreSqlSinkType sinkType)
ColumnNames = sinkType == PostgreSqlSinkType.SerilogSinksPostgreSQLAlternative
? new PostgreSqlAlternativeSinkColumnNames()
: new PostgreSqlSinkColumnNames();
+
return this;
}
+
+ internal SinkColumnNames ColumnNames { get; set; }
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.PostgreSqlProvider/Extensions/SerilogUiOptionBuilderExtensions.cs b/src/Serilog.Ui.PostgreSqlProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
index 9f217bcb..8ba23502 100644
--- a/src/Serilog.Ui.PostgreSqlProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
+++ b/src/Serilog.Ui.PostgreSqlProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
@@ -1,56 +1,51 @@
-using System;
-using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection;
using Serilog.Ui.Core;
using Serilog.Ui.Core.Interfaces;
using Serilog.Ui.PostgreSqlProvider.Models;
+using System;
-namespace Serilog.Ui.PostgreSqlProvider.Extensions
+namespace Serilog.Ui.PostgreSqlProvider.Extensions;
+
+///
+/// PostgreSQL data provider specific extension methods for .
+///
+public static class SerilogUiOptionBuilderExtensions
{
///
- /// PostgreSQL data provider specific extension methods for .
+ /// Configures the SerilogUi to connect to a PostgreSQL database.
///
- public static class SerilogUiOptionBuilderExtensions
- {
- ///
- /// Configures the SerilogUi to connect to a PostgreSQL database.
- ///
- /// The Serilog UI option builder.
- /// The Postgres Sql options action.
- public static ISerilogUiOptionsBuilder UseNpgSql(
- this ISerilogUiOptionsBuilder optionsBuilder,
- Action setupOptions
- ) => optionsBuilder.UseNpgSql(setupOptions);
-
- ///
- /// Configures the SerilogUi to connect to a PostgreSQL database.
- ///
- /// The log model, containing any additional columns. It must inherit .
- /// The Serilog UI option builder.
- /// The Postgres Sql options action.
- public static ISerilogUiOptionsBuilder UseNpgSql(
- this ISerilogUiOptionsBuilder optionsBuilder,
- Action setupOptions
- ) where T : PostgresLogModel
- {
- var dbOptions = new PostgreSqlDbOptions("public");
- setupOptions(dbOptions);
- dbOptions.Validate();
+ /// The Serilog UI option builder.
+ /// The Postgres Sql options action.
+ public static ISerilogUiOptionsBuilder UseNpgSql(this ISerilogUiOptionsBuilder optionsBuilder, Action setupOptions)
+ => optionsBuilder.UseNpgSql(setupOptions);
- var providerName = dbOptions.GetProviderName(PostgresDataProvider.ProviderName);
-
- optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
-
- var customModel = typeof(T) != typeof(PostgresLogModel);
- if (customModel)
- {
- optionsBuilder.RegisterColumnsInfo(providerName);
- optionsBuilder.Services.AddScoped(_ => new PostgresDataProvider(dbOptions));
+ ///
+ /// Configures the SerilogUi to connect to a PostgreSQL database.
+ ///
+ /// The log model, containing any additional columns. It must inherit .
+ /// The Serilog UI option builder.
+ /// The Postgres Sql options action.
+ public static ISerilogUiOptionsBuilder UseNpgSql(this ISerilogUiOptionsBuilder optionsBuilder, Action setupOptions)
+ where T : PostgresLogModel
+ {
+ PostgreSqlDbOptions dbOptions = new("public");
+ setupOptions(dbOptions);
+ dbOptions.Validate();
- return optionsBuilder;
- }
+ string providerName = dbOptions.GetProviderName(PostgresDataProvider.ProviderName);
+ optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
- optionsBuilder.Services.AddScoped(_ => new PostgresDataProvider(dbOptions));
- return optionsBuilder;
+ bool customModel = typeof(T) != typeof(PostgresLogModel);
+ if (customModel)
+ {
+ optionsBuilder.RegisterColumnsInfo(providerName);
+ optionsBuilder.Services.AddScoped(_ => new PostgresDataProvider(dbOptions, new PostgresQueryBuilder()));
}
+ else
+ {
+ optionsBuilder.Services.AddScoped(_ => new PostgresDataProvider(dbOptions, new PostgresQueryBuilder()));
+ }
+
+ return optionsBuilder;
}
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreLogModel.cs b/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreLogModel.cs
index d0149d7f..546204d3 100644
--- a/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreLogModel.cs
+++ b/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreLogModel.cs
@@ -17,23 +17,23 @@ public class PostgresLogModel : LogModel
private string _level = string.Empty;
///
- public sealed override int RowNo => base.RowNo;
+ public override sealed int RowNo => base.RowNo;
///
- public sealed override string? Message { get; set; }
+ public override sealed string? Message { get; set; }
///
- public sealed override DateTime Timestamp { get; set; }
+ public override sealed DateTime Timestamp { get; set; }
///
- public sealed override string? Level
+ public override sealed string? Level
{
get => _level;
set => _level = LogLevelConverter.GetLevelName(value);
}
///
- /// It get or sets LogEventSerialized.
+ /// It gets or sets LogEventSerialized.
///
[JsonIgnore]
public string LogEvent { get; set; } = string.Empty;
diff --git a/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreSqlAlternativeSinkColumnNames.cs b/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreSqlAlternativeSinkColumnNames.cs
index 8f72b6e4..b1ecae3c 100644
--- a/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreSqlAlternativeSinkColumnNames.cs
+++ b/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreSqlAlternativeSinkColumnNames.cs
@@ -1,4 +1,6 @@
-namespace Serilog.Ui.PostgreSqlProvider.Models;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+
+namespace Serilog.Ui.PostgreSqlProvider.Models;
internal class PostgreSqlAlternativeSinkColumnNames : SinkColumnNames
{
@@ -7,8 +9,8 @@ public PostgreSqlAlternativeSinkColumnNames()
Exception = "Exception";
Level = "Level";
LogEventSerialized = "LogEvent";
+ Message = "Message";
MessageTemplate = "MessageTemplate";
- RenderedMessage = "Message";
Timestamp = "Timestamp";
}
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreSqlSinkColumnNames.cs b/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreSqlSinkColumnNames.cs
index a2d56427..01153b9d 100644
--- a/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreSqlSinkColumnNames.cs
+++ b/src/Serilog.Ui.PostgreSqlProvider/Models/PostgreSqlSinkColumnNames.cs
@@ -1,14 +1,16 @@
-namespace Serilog.Ui.PostgreSqlProvider.Models;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+
+namespace Serilog.Ui.PostgreSqlProvider.Models;
internal class PostgreSqlSinkColumnNames : SinkColumnNames
{
public PostgreSqlSinkColumnNames()
{
- RenderedMessage = "message";
- MessageTemplate = "message_template";
- Level = "level";
- Timestamp = "timestamp";
Exception = "exception";
+ Level = "level";
LogEventSerialized = "log_event";
+ Message = "message";
+ MessageTemplate = "message_template";
+ Timestamp = "timestamp";
}
}
\ No newline at end of file
diff --git a/src/Serilog.Ui.PostgreSqlProvider/Models/SinkColumnNames.cs b/src/Serilog.Ui.PostgreSqlProvider/Models/SinkColumnNames.cs
deleted file mode 100644
index 296c5d29..00000000
--- a/src/Serilog.Ui.PostgreSqlProvider/Models/SinkColumnNames.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace Serilog.Ui.PostgreSqlProvider.Models;
-
-internal abstract class SinkColumnNames
-{
- public string RenderedMessage { get; set; } = string.Empty;
-
- public string MessageTemplate { get; set; } = string.Empty;
-
- public string Level { get; set; } = string.Empty;
-
- public string Timestamp { get; set; } = string.Empty;
-
- public string Exception { get; set; } = string.Empty;
-
- public string LogEventSerialized { get; set; } = string.Empty;
-}
\ No newline at end of file
diff --git a/src/Serilog.Ui.PostgreSqlProvider/PostgreDataProvider.cs b/src/Serilog.Ui.PostgreSqlProvider/PostgresDataProvider.cs
similarity index 67%
rename from src/Serilog.Ui.PostgreSqlProvider/PostgreDataProvider.cs
rename to src/Serilog.Ui.PostgreSqlProvider/PostgresDataProvider.cs
index fc76c115..3a2d44be 100644
--- a/src/Serilog.Ui.PostgreSqlProvider/PostgreDataProvider.cs
+++ b/src/Serilog.Ui.PostgreSqlProvider/PostgresDataProvider.cs
@@ -1,38 +1,36 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Dapper;
+using Dapper;
using Npgsql;
using Serilog.Ui.Core;
using Serilog.Ui.Core.Models;
using Serilog.Ui.PostgreSqlProvider.Extensions;
using Serilog.Ui.PostgreSqlProvider.Models;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
namespace Serilog.Ui.PostgreSqlProvider;
///
-public class PostgresDataProvider(PostgreSqlDbOptions options) : PostgresDataProvider(options);
+public class PostgresDataProvider(PostgreSqlDbOptions options, PostgresQueryBuilder queryBuilder)
+ : PostgresDataProvider(options, queryBuilder);
///
-public class PostgresDataProvider(PostgreSqlDbOptions options) : IDataProvider
+public class PostgresDataProvider(PostgreSqlDbOptions options, PostgresQueryBuilder queryBuilder) : IDataProvider
where T : PostgresLogModel
{
internal const string ProviderName = "NPGSQL";
- private readonly PostgreSqlDbOptions _options = options ?? throw new ArgumentNullException(nameof(options));
-
///
- public string Name => _options.GetProviderName(ProviderName);
+ public string Name => options.GetProviderName(ProviderName);
///
public async Task<(IEnumerable, int)> FetchDataAsync(FetchLogsQuery queryParams, CancellationToken cancellationToken = default)
{
queryParams.ToUtcDates();
- var logsTask = GetLogsAsync(queryParams);
- var logCountTask = CountLogsAsync(queryParams);
+ Task> logsTask = GetLogsAsync(queryParams);
+ Task logCountTask = CountLogsAsync(queryParams);
await Task.WhenAll(logsTask, logCountTask);
return (await logsTask, await logCountTask);
@@ -40,12 +38,12 @@ public class PostgresDataProvider(PostgreSqlDbOptions options) : IDataProvide
private async Task> GetLogsAsync(FetchLogsQuery queryParams)
{
- var query = options.ColumnNames.BuildFetchLogsQuery(_options.Schema, _options.TableName, queryParams);
- var rowNoStart = queryParams.Page * queryParams.Count;
+ string query = queryBuilder.BuildFetchLogsQuery(options.ColumnNames, options.Schema, options.TableName, queryParams);
+ int rowNoStart = queryParams.Page * queryParams.Count;
- await using var connection = new NpgsqlConnection(_options.ConnectionString);
+ await using NpgsqlConnection connection = new(options.ConnectionString);
- var logs = await connection.QueryAsync(query,
+ IEnumerable logs = await connection.QueryAsync(query,
new
{
Offset = rowNoStart,
@@ -68,9 +66,9 @@ private async Task> GetLogsAsync(FetchLogsQuery queryParam
private async Task CountLogsAsync(FetchLogsQuery queryParams)
{
- var query = options.ColumnNames.BuildCountLogsQuery(_options.Schema, _options.TableName, queryParams);
+ string query = queryBuilder.BuildCountLogsQuery(options.ColumnNames, options.Schema, options.TableName, queryParams);
- await using var connection = new NpgsqlConnection(_options.ConnectionString);
+ await using NpgsqlConnection connection = new(options.ConnectionString);
return await connection.ExecuteScalarAsync(query,
new
diff --git a/src/Serilog.Ui.PostgreSqlProvider/PostgresQueryBuilder.cs b/src/Serilog.Ui.PostgreSqlProvider/PostgresQueryBuilder.cs
new file mode 100644
index 00000000..675fe49a
--- /dev/null
+++ b/src/Serilog.Ui.PostgreSqlProvider/PostgresQueryBuilder.cs
@@ -0,0 +1,122 @@
+using Serilog.Ui.Core.Models;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+using Serilog.Ui.PostgreSqlProvider.Models;
+using System;
+using System.Text;
+using static Serilog.Ui.Core.Models.SearchOptions;
+
+namespace Serilog.Ui.PostgreSqlProvider;
+
+///
+/// Provides methods to build SQL queries specifically for PostgreSQL to fetch and count logs.
+///
+/// The type of the log model.
+public class PostgresQueryBuilder : SqlQueryBuilder where TModel : LogModel
+{
+ ///
+ public override string BuildFetchLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query)
+ {
+ StringBuilder queryStr = new();
+
+ GenerateSelectClause(queryStr, columns, schema, tableName);
+
+ GenerateWhereClause(queryStr, columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate);
+
+ queryStr.Append($"{GenerateSortClause(columns, query.SortOn, query.SortBy)} LIMIT @Count OFFSET @Offset");
+
+ return queryStr.ToString();
+ }
+
+ ///
+ public override string BuildCountLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query)
+ {
+ StringBuilder queryStr = new();
+
+ queryStr.Append($"SELECT COUNT(\"{columns.Message}\") ")
+ .Append($"FROM \"{schema}\".\"{tableName}\"");
+
+ GenerateWhereClause(queryStr, columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate);
+
+ return queryStr.ToString();
+ }
+
+ ///
+ protected override string GenerateSortClause(SinkColumnNames columns, SortProperty sortOn, SortDirection sortBy)
+ => $"ORDER BY \"{GetSortColumnName(columns, sortOn)}\" {sortBy.ToString().ToUpper()}";
+
+ ///
+ /// Generates the SELECT clause for the SQL query.
+ ///
+ /// The StringBuilder to append the SELECT clause to.
+ /// The column names used in the sink for logging.
+ /// The schema of the table.
+ /// The name of the table.
+ private static void GenerateSelectClause(StringBuilder queryBuilder, SinkColumnNames columns, string schema, string tableName)
+ {
+ if (typeof(TModel) != typeof(PostgresLogModel))
+ {
+ queryBuilder.Append("SELECT *");
+ }
+ else
+ {
+ queryBuilder.Append($"SELECT \"{columns.Message}\", ")
+ .Append($"\"{columns.MessageTemplate}\", ")
+ .Append($"\"{columns.Level}\", ")
+ .Append($"\"{columns.Timestamp}\", ")
+ .Append($"\"{columns.Exception}\", ")
+ .Append($"\"{columns.LogEventSerialized}\" AS \"Properties\"");
+ }
+
+ queryBuilder.Append($" FROM \"{schema}\".\"{tableName}\" ");
+ }
+
+ ///
+ /// Generates the WHERE clause for the SQL query.
+ ///
+ /// The StringBuilder to append the WHERE clause to.
+ /// The column names used in the sink for logging.
+ /// The log level to filter by.
+ /// The search criteria to filter by.
+ /// The start date to filter by.
+ /// The end date to filter by.
+ private static void GenerateWhereClause(
+ StringBuilder queryBuilder,
+ SinkColumnNames columns,
+ string? level,
+ string? searchCriteria,
+ DateTime? startDate,
+ DateTime? endDate)
+ {
+ StringBuilder conditions = new();
+
+ if (!string.IsNullOrWhiteSpace(level))
+ {
+ conditions.Append($"AND \"{columns.Level}\" = @Level ");
+ }
+
+ if (!string.IsNullOrWhiteSpace(searchCriteria))
+ {
+ conditions.Append($"AND (\"{columns.Message}\" LIKE @Search ");
+ conditions.Append(AddExceptionToWhereClause() ? $"OR \"{columns.Exception}\" LIKE @Search) " : ") ");
+ }
+
+ if (startDate.HasValue)
+ {
+ conditions.Append($"AND \"{columns.Timestamp}\" >= @StartDate ");
+ }
+
+ if (endDate.HasValue)
+ {
+ conditions.Append($"AND \"{columns.Timestamp}\" <= @EndDate ");
+ }
+
+ if (conditions.Length <= 0)
+ {
+ return;
+ }
+
+ queryBuilder
+ .Append("WHERE TRUE ")
+ .Append(conditions);
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.PostgreSqlProvider/QueryBuilder.cs b/src/Serilog.Ui.PostgreSqlProvider/QueryBuilder.cs
deleted file mode 100644
index 49d8171a..00000000
--- a/src/Serilog.Ui.PostgreSqlProvider/QueryBuilder.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Text;
-using Serilog.Ui.Core.Attributes;
-using Serilog.Ui.Core.Models;
-using Serilog.Ui.PostgreSqlProvider.Models;
-using static Serilog.Ui.Core.Models.SearchOptions;
-
-namespace Serilog.Ui.PostgreSqlProvider;
-
-internal static class QueryBuilder
-{
- internal static string BuildFetchLogsQuery(this SinkColumnNames _columns, string schema, string tableName, FetchLogsQuery query)
- where T : PostgresLogModel
- {
- var sortClause = _columns.GenerateSortClause(query.SortOn, query.SortBy);
-
- return new StringBuilder()
- .GenerateSelectClause(_columns)
- .Append($" FROM \"{schema}\".\"{tableName}\"")
- .GenerateWhereClause(_columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate)
- .Append($" ORDER BY {sortClause} LIMIT @Count OFFSET @Offset")
- .ToString();
- }
-
- internal static string BuildCountLogsQuery(this SinkColumnNames _columns, string schema, string tableName, FetchLogsQuery query)
- where T : PostgresLogModel
- {
- return new StringBuilder()
- .Append($"SELECT COUNT(\"{_columns.RenderedMessage}\") ")
- .Append($"FROM \"{schema}\".\"{tableName}\"")
- .GenerateWhereClause(_columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate)
- .ToString();
- }
-
- private static StringBuilder GenerateSelectClause(this StringBuilder queryBuilder, SinkColumnNames _columns)
- where T : PostgresLogModel
- {
- if (typeof(T) != typeof(PostgresLogModel))
- {
- return queryBuilder.Append("SELECT *");
- }
-
- return queryBuilder.Append($"SELECT \"{_columns.RenderedMessage}\", ")
- .Append($"\"{_columns.MessageTemplate}\", ")
- .Append($"\"{_columns.Level}\", ")
- .Append($"\"{_columns.Timestamp}\", ")
- .Append($"\"{_columns.Exception}\", ")
- .Append($"\"{_columns.LogEventSerialized}\" AS \"Properties\"");
- }
-
- private static StringBuilder GenerateWhereClause(this StringBuilder queryBuilder,
- SinkColumnNames _columns,
- string? level,
- string? searchCriteria,
- DateTime? startDate,
- DateTime? endDate)
- where T : PostgresLogModel
- {
- var conditions = new List();
-
- if (!string.IsNullOrWhiteSpace(level))
- {
- conditions.Add($"\"{_columns.Level}\" = @Level");
- }
-
- if (!string.IsNullOrWhiteSpace(searchCriteria))
- {
- var exceptionCondition = AddExceptionToWhereClause() ? $"OR \"{_columns.Exception}\" LIKE @Search" : string.Empty;
- conditions.Add($"(\"{_columns.RenderedMessage}\" LIKE @Search {exceptionCondition})");
- }
-
- if (startDate.HasValue)
- {
- conditions.Add($"\"{_columns.Timestamp}\" >= @StartDate");
- }
-
- if (endDate.HasValue)
- {
- conditions.Add($"\"{_columns.Timestamp}\" <= @EndDate");
- }
-
- if (conditions.Count <= 0) return queryBuilder;
-
- return queryBuilder
- .Append(" WHERE TRUE AND ")
- .Append(string.Join(" AND ", conditions));
- }
-
- private static bool AddExceptionToWhereClause()
- where T : PostgresLogModel
- {
- var exceptionProperty = typeof(T).GetProperty(nameof(PostgresLogModel.Exception));
- var att = exceptionProperty?.GetCustomAttribute();
- return att is null;
- }
-
- private static string GenerateSortClause(this SinkColumnNames _columns, SortProperty sortOn, SortDirection sortBy)
- {
- var sortPropertyName = sortOn switch
- {
- SortProperty.Timestamp => _columns.Timestamp,
- SortProperty.Level => _columns.Level,
- SortProperty.Message => _columns.RenderedMessage,
- _ => _columns.Timestamp,
- };
-
- return $"\"{sortPropertyName}\" {sortBy.ToString().ToUpper()}";
- }
-}
\ No newline at end of file
diff --git a/src/Serilog.Ui.PostgreSqlProvider/Serilog.Ui.PostgreSqlProvider.csproj b/src/Serilog.Ui.PostgreSqlProvider/Serilog.Ui.PostgreSqlProvider.csproj
index 9aaffd0f..47a97a7a 100644
--- a/src/Serilog.Ui.PostgreSqlProvider/Serilog.Ui.PostgreSqlProvider.csproj
+++ b/src/Serilog.Ui.PostgreSqlProvider/Serilog.Ui.PostgreSqlProvider.csproj
@@ -4,10 +4,8 @@
Serilog.UI.PostgreSqlProvider
netstandard2.0
latest
- 3.0.0
-
+ 3.1.0
True
-
PostgreSQL data provider for Serilog UI.
serilog serilog-ui serilog.sinks.postgresql postgresql
diff --git a/src/Serilog.Ui.RavenDbProvider/Serilog.Ui.RavenDbProvider.csproj b/src/Serilog.Ui.RavenDbProvider/Serilog.Ui.RavenDbProvider.csproj
index 9d938aab..a055f756 100644
--- a/src/Serilog.Ui.RavenDbProvider/Serilog.Ui.RavenDbProvider.csproj
+++ b/src/Serilog.Ui.RavenDbProvider/Serilog.Ui.RavenDbProvider.csproj
@@ -4,7 +4,7 @@
Serilog.Ui.RavenDbProvider
netstandard2.0
latest
- 2.0.0
+ 2.1.0
enable
enable
diff --git a/src/Serilog.Ui.SqliteDataProvider/Extensions/SerilogUiOptionBuilderExtensions.cs b/src/Serilog.Ui.SqliteDataProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
new file mode 100644
index 00000000..906d551a
--- /dev/null
+++ b/src/Serilog.Ui.SqliteDataProvider/Extensions/SerilogUiOptionBuilderExtensions.cs
@@ -0,0 +1,31 @@
+using Microsoft.Extensions.DependencyInjection;
+using Serilog.Ui.Core;
+using Serilog.Ui.Core.Interfaces;
+using Serilog.Ui.Core.Models.Options;
+using System;
+
+namespace Serilog.Ui.SqliteDataProvider.Extensions;
+
+///
+/// SQLite data provider specific extension methods for .
+///
+public static class SerilogUiOptionBuilderExtensions
+{
+ /// Configures the SerilogUi to connect to a SQLite database.
+ /// The options builder.
+ /// The SQLite options action.
+ public static ISerilogUiOptionsBuilder UseSqliteServer(
+ this ISerilogUiOptionsBuilder optionsBuilder,
+ Action setupOptions)
+ {
+ var dbOptions = new SqliteDbOptions();
+ setupOptions(dbOptions);
+ dbOptions.Validate();
+
+ string providerName = dbOptions.GetProviderName(SqliteDataProvider.SqliteProviderName);
+ optionsBuilder.RegisterExceptionAsStringForProviderKey(providerName);
+ optionsBuilder.Services.AddScoped(_ => new SqliteDataProvider(dbOptions, new SqliteQueryBuilder()));
+
+ return optionsBuilder;
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.SqliteDataProvider/Extensions/SqliteDbOptions.cs b/src/Serilog.Ui.SqliteDataProvider/Extensions/SqliteDbOptions.cs
new file mode 100644
index 00000000..449a55b2
--- /dev/null
+++ b/src/Serilog.Ui.SqliteDataProvider/Extensions/SqliteDbOptions.cs
@@ -0,0 +1,10 @@
+using Serilog.Ui.Core.Models.Options;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+using Serilog.Ui.SqliteDataProvider.Models;
+
+namespace Serilog.Ui.SqliteDataProvider.Extensions;
+
+public class SqliteDbOptions() : RelationalDbOptions("ununsed")
+{
+ public SinkColumnNames ColumnNames { get; } = new SqliteSinkColumnNames();
+}
diff --git a/src/Serilog.Ui.SqliteDataProvider/Models/SqliteSinkColumnNames.cs b/src/Serilog.Ui.SqliteDataProvider/Models/SqliteSinkColumnNames.cs
new file mode 100644
index 00000000..a86e515e
--- /dev/null
+++ b/src/Serilog.Ui.SqliteDataProvider/Models/SqliteSinkColumnNames.cs
@@ -0,0 +1,16 @@
+using Serilog.Ui.Core.QueryBuilder.Sql;
+
+namespace Serilog.Ui.SqliteDataProvider.Models;
+
+internal class SqliteSinkColumnNames : SinkColumnNames
+{
+ public SqliteSinkColumnNames()
+ {
+ Exception = "Exception";
+ Level = "Level";
+ LogEventSerialized = "Properties";
+ Message = "RenderedMessage";
+ MessageTemplate = "";
+ Timestamp = "Timestamp";
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.SqliteDataProvider/Serilog.Ui.SqliteDataProvider.csproj b/src/Serilog.Ui.SqliteDataProvider/Serilog.Ui.SqliteDataProvider.csproj
new file mode 100644
index 00000000..9b25cc3e
--- /dev/null
+++ b/src/Serilog.Ui.SqliteDataProvider/Serilog.Ui.SqliteDataProvider.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Serilog.UI.SqliteProvider
+ netstandard2.0
+ latest
+ 1.0.0
+
+ Tech Garage (team)
+ SQLite data provider for Serilog UI.
+ serilog serilog-ui serilog.sinks.sqlite sqlite
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Serilog.Ui.SqliteDataProvider/SqliteDataProvider.cs b/src/Serilog.Ui.SqliteDataProvider/SqliteDataProvider.cs
new file mode 100644
index 00000000..c9bc3584
--- /dev/null
+++ b/src/Serilog.Ui.SqliteDataProvider/SqliteDataProvider.cs
@@ -0,0 +1,82 @@
+using Ardalis.GuardClauses;
+using Dapper;
+using Microsoft.Data.Sqlite;
+using Serilog.Ui.Core;
+using Serilog.Ui.Core.Models;
+using Serilog.Ui.SqliteDataProvider.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Serilog.Ui.SqliteDataProvider;
+
+public class SqliteDataProvider(SqliteDbOptions options, SqliteQueryBuilder queryBuilder) : IDataProvider
+{
+ internal const string SqliteProviderName = "SQLite";
+ private readonly SqliteDbOptions _options = Guard.Against.Null(options);
+
+ public async Task<(IEnumerable, int)> FetchDataAsync(FetchLogsQuery queryParams, CancellationToken cancellationToken = default)
+ {
+ queryParams.ToUtcDates(); // assuming data is saved in UTC, due to UTC predictability
+
+ var logsTask = GetLogsAsync(queryParams);
+ var logCountTask = CountLogsAsync(queryParams);
+
+ await Task.WhenAll(logsTask, logCountTask);
+
+ return (await logsTask, await logCountTask);
+ }
+
+ public string Name => _options.GetProviderName(SqliteProviderName);
+
+ private async Task> GetLogsAsync(FetchLogsQuery queryParams)
+ {
+ var query = queryBuilder.BuildFetchLogsQuery(_options.ColumnNames, _options.Schema, _options.TableName, queryParams);
+
+ var rowNoStart = queryParams.Page * queryParams.Count;
+
+ using var connection = new SqliteConnection(_options.ConnectionString);
+ var queryParameters = new
+ {
+ Offset = rowNoStart,
+ queryParams.Count,
+ queryParams.Level,
+ Search = queryParams.SearchCriteria != null ? $"%{queryParams.SearchCriteria}%" : null,
+ StartDate = StringifyDate(queryParams.StartDate),
+ EndDate = StringifyDate(queryParams.EndDate)
+ };
+ var logs = await connection.QueryAsync(query.ToString(), queryParameters);
+
+ return logs.Select((item, i) =>
+ {
+ item.PropertyType = "json";
+
+ var ts = DateTime.SpecifyKind(item.Timestamp, item.Timestamp.Kind == DateTimeKind.Unspecified ? DateTimeKind.Utc : item.Timestamp.Kind);
+ item.Timestamp = ts.ToUniversalTime();
+
+ item.SetRowNo(rowNoStart, i);
+ return item;
+ }).ToList();
+ }
+
+ private Task CountLogsAsync(FetchLogsQuery queryParams)
+ {
+ var query = queryBuilder.BuildCountLogsQuery(_options.ColumnNames, _options.Schema, _options.TableName, queryParams);
+
+ using var connection = new SqliteConnection(_options.ConnectionString);
+
+ return connection.QueryFirstOrDefaultAsync(
+ query.ToString(),
+ new
+ {
+ queryParams.Level,
+ Search = queryParams.SearchCriteria != null ? $"%{queryParams.SearchCriteria}%" : null,
+ StartDate = StringifyDate(queryParams.StartDate),
+ EndDate = StringifyDate(queryParams.EndDate)
+ });
+ }
+
+ private static string StringifyDate(DateTime? date) => date.HasValue ? date.Value.ToString("s") + ".999" : "null";
+}
diff --git a/src/Serilog.Ui.SqliteDataProvider/SqliteQueryBuilder.cs b/src/Serilog.Ui.SqliteDataProvider/SqliteQueryBuilder.cs
new file mode 100644
index 00000000..54f7bf2c
--- /dev/null
+++ b/src/Serilog.Ui.SqliteDataProvider/SqliteQueryBuilder.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Text;
+using Serilog.Ui.Core.Models;
+using Serilog.Ui.Core.QueryBuilder.Sql;
+
+namespace Serilog.Ui.SqliteDataProvider;
+
+///
+/// Provides methods to build SQL queries specifically for Sqlite to fetch and count logs.
+///
+/// The type of the log model.
+public class SqliteQueryBuilder : SqlQueryBuilder
+{
+ ///
+ public override string BuildFetchLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query)
+ {
+ StringBuilder queryStr = new();
+
+ GenerateSelectClause(queryStr, columns, schema, tableName);
+
+ GenerateWhereClause(queryStr, columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate);
+
+ queryStr.Append($"{GenerateSortClause(columns, query.SortOn, query.SortBy)} LIMIT @Offset, @Count");
+
+ return queryStr.ToString();
+ }
+
+ ///
+ public override string BuildCountLogsQuery(SinkColumnNames columns, string schema, string tableName, FetchLogsQuery query)
+ {
+ StringBuilder queryStr = new();
+
+ queryStr.Append($"SELECT COUNT(Id) FROM {tableName} ");
+
+ GenerateWhereClause(queryStr, columns, query.Level, query.SearchCriteria, query.StartDate, query.EndDate);
+
+ return queryStr.ToString();
+ }
+
+ protected override string GenerateSortClause(SinkColumnNames columns, SearchOptions.SortProperty sortOn, SearchOptions.SortDirection sortBy)
+ => $"ORDER BY {GetSortColumnName(columns, sortOn)} {sortBy.ToString().ToUpper()}";
+
+ ///
+ private static void GenerateSelectClause(StringBuilder queryBuilder, SinkColumnNames columns, string schema, string tableName)
+ {
+ queryBuilder.Append($"SELECT Id, {columns.Message} AS Message, {columns.Level}, {columns.Timestamp}, {columns.Exception}, {columns.LogEventSerialized} ");
+ queryBuilder.Append($"FROM {tableName} ");
+ }
+
+ ///
+ private static void GenerateWhereClause(
+ StringBuilder queryBuilder,
+ SinkColumnNames columns,
+ string? level,
+ string? searchCriteria,
+ DateTime? startDate,
+ DateTime? endDate)
+ {
+ var conditionStart = "WHERE";
+
+ if (!string.IsNullOrWhiteSpace(level))
+ {
+ queryBuilder.Append($"{conditionStart} {columns.Level} = @Level ");
+ conditionStart = "AND";
+ }
+
+ if (!string.IsNullOrWhiteSpace(searchCriteria))
+ {
+ queryBuilder.Append($"{conditionStart} ({columns.Message} LIKE @Search OR {columns.Exception} LIKE @Search) ");
+ conditionStart = "AND";
+ }
+
+ if (startDate != null)
+ {
+ queryBuilder.Append($"{conditionStart} {columns.Timestamp} >= @StartDate ");
+ conditionStart = "AND";
+ }
+
+ if (endDate != null)
+ {
+ queryBuilder.Append($"{conditionStart} {columns.Timestamp} <= @EndDate ");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Serilog.Ui.Web/Extensions/ServiceCollectionExtensions.cs b/src/Serilog.Ui.Web/Extensions/ServiceCollectionExtensions.cs
index 03b6546b..a5b07e5a 100644
--- a/src/Serilog.Ui.Web/Extensions/ServiceCollectionExtensions.cs
+++ b/src/Serilog.Ui.Web/Extensions/ServiceCollectionExtensions.cs
@@ -40,12 +40,17 @@ public static IServiceCollection AddSerilogUi(this IServiceCollection services,
services.AddScoped();
services.AddSingleton();
- services.AddScoped();
- services.Decorate();
-
- services.AddScoped();
- services.Decorate();
-
+ services.AddScoped();
+ services.AddScoped(sp => new SerilogUiEndpointsDecorator(
+ sp.GetRequiredService(),
+ sp.GetRequiredService()));
+
+ services.AddScoped();
+ services.AddScoped(sp => new SerilogUiAppRoutesDecorator(
+ sp.GetRequiredService(),
+ sp.GetRequiredService(),
+ sp.GetRequiredService()));
+
services.AddScoped();
return services;
diff --git a/src/Serilog.Ui.Web/Serilog.Ui.Web.csproj b/src/Serilog.Ui.Web/Serilog.Ui.Web.csproj
index a8905db6..02173b62 100644
--- a/src/Serilog.Ui.Web/Serilog.Ui.Web.csproj
+++ b/src/Serilog.Ui.Web/Serilog.Ui.Web.csproj
@@ -4,18 +4,11 @@
Serilog.UI
net6.0;net7.0;net8.0
latest
- 3.0.2
+ 3.1.0
-
-
-
-
-
-
-
diff --git a/src/Serilog.Ui.Web/package.json b/src/Serilog.Ui.Web/package.json
index 6ae1c9f5..d4d52386 100644
--- a/src/Serilog.Ui.Web/package.json
+++ b/src/Serilog.Ui.Web/package.json
@@ -1,5 +1,5 @@
{
- "version": "3.0.2",
+ "version": "3.1.0",
"name": "serilog-ui",
"private": true,
"type": "module",
@@ -15,14 +15,14 @@
},
"dependencies": {
"@fontsource/mononoki": "^5.1.0",
- "@mantine/core": "^7.12.2",
- "@mantine/dates": "^7.12.2",
- "@mantine/hooks": "^7.12.2",
- "@mantine/notifications": "^7.12.2",
- "@tabler/icons-react": "^3.17.0",
- "@tanstack/react-query": "^5.56.2",
+ "@mantine/core": "^7.13.2",
+ "@mantine/dates": "^7.13.2",
+ "@mantine/hooks": "^7.13.2",
+ "@mantine/notifications": "^7.13.2",
+ "@tabler/icons-react": "^3.19.0",
+ "@tanstack/react-query": "^5.59.8",
"dayjs": "^1.11.13",
- "jose": "^5.9.2",
+ "jose": "^5.9.3",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.53.0",
@@ -30,26 +30,26 @@
"xml-formatter": "^3.6.3"
},
"devDependencies": {
- "@faker-js/faker": "^9.0.1",
+ "@faker-js/faker": "^9.0.3",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
- "@types/node": "^22.5.5",
- "@types/react": "^18.3.8",
+ "@types/node": "^22.7.5",
+ "@types/react": "^18.3.11",
"@types/react-dom": "^18.3.0",
- "@vitejs/plugin-react-swc": "^3.7.0",
- "@vitest/coverage-istanbul": "^2.1.1",
- "@vitest/ui": "^2.1.1",
+ "@vitejs/plugin-react-swc": "^3.7.1",
+ "@vitest/coverage-istanbul": "^2.1.2",
+ "@vitest/ui": "^2.1.2",
"@welldone-software/why-did-you-render": "^8.0.3",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
- "eslint-plugin-html": "^8.1.1",
- "eslint-plugin-import": "^2.30.0",
+ "eslint-plugin-html": "^8.1.2",
+ "eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-promise": "^7.1.0",
- "eslint-plugin-react": "^7.36.1",
+ "eslint-plugin-react": "^7.37.1",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-testing-library": "^6.3.0",
"eslint-plugin-vitest": "^0.5.4",
@@ -61,15 +61,15 @@
"postcss-simple-vars": "^7.0.1",
"prettier": "^3.3.3",
"prettier-plugin-organize-imports": "^4.1.0",
- "shiki": "^1.18.0",
+ "shiki": "^1.22.0",
"testing-library-selector": "^0.3.1",
- "typescript": "^5.6.2",
- "typescript-eslint": "^8.6.0",
- "vite": "^5.4.7",
+ "typescript": "^5.6.3",
+ "typescript-eslint": "^8.8.1",
+ "vite": "^5.4.8",
"vite-plugin-checker": "^0.8.0",
"vite-plugin-mkcert": "^1.17.6",
"vite-tsconfig-paths": "^5.0.1",
- "vitest": "^2.1.1",
+ "vitest": "^2.1.2",
"vitest-sonar-reporter": "^2.0.0"
},
"engines": {
diff --git a/src/Serilog.Ui.Web/yarn.lock b/src/Serilog.Ui.Web/yarn.lock
index 91870f78..61de84d5 100644
--- a/src/Serilog.Ui.Web/yarn.lock
+++ b/src/Serilog.Ui.Web/yarn.lock
@@ -376,10 +376,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f"
integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
-"@faker-js/faker@^9.0.1":
- version "9.0.1"
- resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.0.1.tgz#5e201ffc4524d00a200c648d2be55be6e25b3c3e"
- integrity sha512-4mDeYIgM3By7X6t5E6eYwLAa+2h4DeZDF7thhzIg6XB76jeEvMwadYAMCFJL/R4AnEBcAUO9+gL0vhy3s+qvZA==
+"@faker-js/faker@^9.0.3":
+ version "9.0.3"
+ resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.0.3.tgz#be817db896b07d1716bc65d9aad1ba587b499826"
+ integrity sha512-lWrrK4QNlFSU+13PL9jMbMKLJYXDFu3tQfayBsMXX7KL/GiQeqfB1CzHkqD5UHBUtPAuPo6XwGbMFNdVMZObRA==
"@floating-ui/core@^1.0.0":
version "1.6.2"
@@ -532,10 +532,10 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
-"@mantine/core@^7.12.2":
- version "7.12.2"
- resolved "https://registry.yarnpkg.com/@mantine/core/-/core-7.12.2.tgz#d8fb7969a62dd5367331b141e053c4b2989c677a"
- integrity sha512-FrMHOKq4s3CiPIxqZ9xnVX7H4PEGNmbtHMvWO/0YlfPgoV0Er/N/DNJOFW1ys4WSnidPTayYeB41riyxxGOpRQ==
+"@mantine/core@^7.13.2":
+ version "7.13.2"
+ resolved "https://registry.yarnpkg.com/@mantine/core/-/core-7.13.2.tgz#8fb8ee2857a40f237ffed370a6ad768fbb1b3be2"
+ integrity sha512-nD8oKIal+KdthqF074+ZG21035QBEAKso2zK9D6zWxRTLVCjLCNSc5JSXrXLrdBTnvPQGY26yunX4+MEPlmrHg==
dependencies:
"@floating-ui/react" "^0.26.9"
clsx "^2.1.1"
@@ -544,30 +544,30 @@
react-textarea-autosize "8.5.3"
type-fest "^4.12.0"
-"@mantine/dates@^7.12.2":
- version "7.12.2"
- resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-7.12.2.tgz#32fd7341283450487de884b6f996647431690938"
- integrity sha512-qsDDl9qF80QLG1n6JiysyELAhbNLbV3qmXRAIU3GJLLxtZfyD9ntOUg0B64EpNl3Py4btXNo4yniFdu1JSUgwg==
+"@mantine/dates@^7.13.2":
+ version "7.13.2"
+ resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-7.13.2.tgz#b6e2a83f507efe25b211f1d8765dd9af7a827c7d"
+ integrity sha512-FSLGTM5s47mmHnIudRxrMXjE1EO56Qp01nATa9OwqVgVYVxxJ5xvS1ys5yxSGSE1jQk+3kyYQXHyLFcqbFhIVA==
dependencies:
clsx "^2.1.1"
-"@mantine/hooks@^7.12.2":
- version "7.12.2"
- resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-7.12.2.tgz#f8e6a8345bb0892d8d1f5d1dc544a568572b79f4"
- integrity sha512-dVMw8jpM0hAzc8e7/GNvzkk9N0RN/m+PKycETB3H6lJGuXJJSRR4wzzgQKpEhHwPccktDpvb4rkukKDq2jA8Fg==
+"@mantine/hooks@^7.13.2":
+ version "7.13.2"
+ resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-7.13.2.tgz#ec6a17faee4c8f3c0fe06f7b66c0e4a12c9b1ad1"
+ integrity sha512-NKfGl2sKZw6zF//AfAFJrVDftjg7DKCn0h8rwJBIZCKi9axhwlV0Mvlqe2dep8QuM7O/uLLJSymSKIv1gaxIJg==
-"@mantine/notifications@^7.12.2":
- version "7.12.2"
- resolved "https://registry.yarnpkg.com/@mantine/notifications/-/notifications-7.12.2.tgz#531a6a3f23adc579b0a8f322ccf42b1789327698"
- integrity sha512-gTvLHkoAZ42v5bZxibP9A50djp5ndEwumVhHSa7mxQ8oSS23tt3It/6hOqH7M+9kHY0a8s+viMiflUzTByA9qg==
+"@mantine/notifications@^7.13.2":
+ version "7.13.2"
+ resolved "https://registry.yarnpkg.com/@mantine/notifications/-/notifications-7.13.2.tgz#0be074470b0a91a6dc7a6834e67c301d7ebea903"
+ integrity sha512-14vFJtR0wjO8Won96UMLxIGmKetR0ocBxcghtuGh6+wnXt6r/ezfQKsdGkkNj6w91I+0Nl9jspcxEekE5q2tBQ==
dependencies:
- "@mantine/store" "7.12.2"
+ "@mantine/store" "7.13.2"
react-transition-group "4.4.5"
-"@mantine/store@7.12.2":
- version "7.12.2"
- resolved "https://registry.yarnpkg.com/@mantine/store/-/store-7.12.2.tgz#da576a63d860d44525bd18c9dd3977b6d2840011"
- integrity sha512-NqL31sO/KcAETEWP/CiXrQOQNoE4168vZsxyXacQHGBueVMJa64WIDQtKLHrCnFRMws3vsXF02/OO4bH4XGcMQ==
+"@mantine/store@7.13.2":
+ version "7.13.2"
+ resolved "https://registry.yarnpkg.com/@mantine/store/-/store-7.13.2.tgz#aba23573bff42eda28716f422275929afde086c9"
+ integrity sha512-JcBGOqRynYiRWzw1rYdmViB/lfeYSec2EXVdSt4eJv+RPICsjjuqrIc3sNzfqJEGxcN4hGSlaeBriSh05K+vNQ==
"@mswjs/interceptors@^0.35.8":
version "0.35.8"
@@ -735,237 +735,237 @@
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.19.2.tgz#0c896535473291cb41f152c180bedd5680a3b273"
integrity sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==
-"@rollup/rollup-android-arm-eabi@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz#155c7d82c1b36c3ad84d9adf9b3cd520cba81a0f"
- integrity sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==
-
-"@rollup/rollup-android-arm64@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz#b94b6fa002bd94a9cbd8f9e47e23b25e5bd113ba"
- integrity sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==
-
-"@rollup/rollup-darwin-arm64@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz#0934126cf9cbeadfe0eb7471ab5d1517e8cd8dcc"
- integrity sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==
-
-"@rollup/rollup-darwin-x64@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz#0ce8e1e0f349778938c7c90e4bdc730640e0a13e"
- integrity sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==
-
-"@rollup/rollup-linux-arm-gnueabihf@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz#5669d34775ad5d71e4f29ade99d0ff4df523afb6"
- integrity sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==
-
-"@rollup/rollup-linux-arm-musleabihf@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz#f6d1a0e1da4061370cb2f4244fbdd727c806dd88"
- integrity sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==
-
-"@rollup/rollup-linux-arm64-gnu@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz#ed96a05e99743dee4d23cc4913fc6e01a0089c88"
- integrity sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==
-
-"@rollup/rollup-linux-arm64-musl@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz#057ea26eaa7e537a06ded617d23d57eab3cecb58"
- integrity sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==
-
-"@rollup/rollup-linux-powerpc64le-gnu@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz#6e6e1f9404c9bf3fbd7d51cd11cd288a9a2843aa"
- integrity sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==
-
-"@rollup/rollup-linux-riscv64-gnu@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz#eef1536a53f6e6658a2a778130e6b1a4a41cb439"
- integrity sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==
-
-"@rollup/rollup-linux-s390x-gnu@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz#2b28fb89ca084efaf8086f435025d96b4a966957"
- integrity sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==
-
-"@rollup/rollup-linux-x64-gnu@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz#5226cde6c6b495b04a3392c1d2c572844e42f06b"
- integrity sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==
-
-"@rollup/rollup-linux-x64-musl@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz#2c2412982e6c2a00a2ecac6d548ebb02f0aa6ca4"
- integrity sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==
-
-"@rollup/rollup-win32-arm64-msvc@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz#fbb6ef5379199e2ec0103ef32877b0985c773a55"
- integrity sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==
-
-"@rollup/rollup-win32-ia32-msvc@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz#d50e2082e147e24d87fe34abbf6246525ec3845a"
- integrity sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==
-
-"@rollup/rollup-win32-x64-msvc@4.21.3":
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz#4115233aa1bd5a2060214f96d8511f6247093212"
- integrity sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==
+"@rollup/rollup-android-arm-eabi@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5"
+ integrity sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==
+
+"@rollup/rollup-android-arm64@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz#654ca1049189132ff602bfcf8df14c18da1f15fb"
+ integrity sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==
+
+"@rollup/rollup-darwin-arm64@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz#6d241d099d1518ef0c2205d96b3fa52e0fe1954b"
+ integrity sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==
+
+"@rollup/rollup-darwin-x64@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz#42bd19d292a57ee11734c980c4650de26b457791"
+ integrity sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz#f23555ee3d8fe941c5c5fd458cd22b65eb1c2232"
+ integrity sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==
+
+"@rollup/rollup-linux-arm-musleabihf@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz#f3bbd1ae2420f5539d40ac1fde2b38da67779baa"
+ integrity sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==
+
+"@rollup/rollup-linux-arm64-gnu@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz#7abe900120113e08a1f90afb84c7c28774054d15"
+ integrity sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==
+
+"@rollup/rollup-linux-arm64-musl@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz#9e655285c8175cd44f57d6a1e8e5dedfbba1d820"
+ integrity sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==
+
+"@rollup/rollup-linux-powerpc64le-gnu@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz#9a79ae6c9e9d8fe83d49e2712ecf4302db5bef5e"
+ integrity sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==
+
+"@rollup/rollup-linux-riscv64-gnu@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz#67ac70eca4ace8e2942fabca95164e8874ab8128"
+ integrity sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==
+
+"@rollup/rollup-linux-s390x-gnu@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz#9f883a7440f51a22ed7f99e1d070bd84ea5005fc"
+ integrity sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==
+
+"@rollup/rollup-linux-x64-gnu@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz#70116ae6c577fe367f58559e2cffb5641a1dd9d0"
+ integrity sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==
+
+"@rollup/rollup-linux-x64-musl@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz#f473f88219feb07b0b98b53a7923be716d1d182f"
+ integrity sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==
+
+"@rollup/rollup-win32-arm64-msvc@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz#4349482d17f5d1c58604d1c8900540d676f420e0"
+ integrity sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==
+
+"@rollup/rollup-win32-ia32-msvc@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz#a6fc39a15db618040ec3c2a24c1e26cb5f4d7422"
+ integrity sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==
+
+"@rollup/rollup-win32-x64-msvc@4.22.4":
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202"
+ integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==
"@rtsao/scc@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==
-"@shikijs/core@1.18.0":
- version "1.18.0"
- resolved "https://registry.yarnpkg.com/@shikijs/core/-/core-1.18.0.tgz#30dde8e53026dada606c4cf7f32d80a3f33d437c"
- integrity sha512-VK4BNVCd2leY62Nm2JjyxtRLkyrZT/tv104O81eyaCjHq4Adceq2uJVFJJAIof6lT1mBwZrEo2qT/T+grv3MQQ==
+"@shikijs/core@1.22.0":
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/@shikijs/core/-/core-1.22.0.tgz#74e5d4485e5f7afa85109e322b42e400686f92bb"
+ integrity sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==
dependencies:
- "@shikijs/engine-javascript" "1.18.0"
- "@shikijs/engine-oniguruma" "1.18.0"
- "@shikijs/types" "1.18.0"
- "@shikijs/vscode-textmate" "^9.2.2"
+ "@shikijs/engine-javascript" "1.22.0"
+ "@shikijs/engine-oniguruma" "1.22.0"
+ "@shikijs/types" "1.22.0"
+ "@shikijs/vscode-textmate" "^9.3.0"
"@types/hast" "^3.0.4"
hast-util-to-html "^9.0.3"
-"@shikijs/engine-javascript@1.18.0":
- version "1.18.0"
- resolved "https://registry.yarnpkg.com/@shikijs/engine-javascript/-/engine-javascript-1.18.0.tgz#9888011c5d869a687b42e3e56c7243f15a73524b"
- integrity sha512-qoP/aO/ATNwYAUw1YMdaip/YVEstMZEgrwhePm83Ll9OeQPuxDZd48szZR8oSQNQBT8m8UlWxZv8EA3lFuyI5A==
+"@shikijs/engine-javascript@1.22.0":
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/@shikijs/engine-javascript/-/engine-javascript-1.22.0.tgz#2e5db29f0421755492f5279f8224ef7a7f907a29"
+ integrity sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==
dependencies:
- "@shikijs/types" "1.18.0"
- "@shikijs/vscode-textmate" "^9.2.2"
+ "@shikijs/types" "1.22.0"
+ "@shikijs/vscode-textmate" "^9.3.0"
oniguruma-to-js "0.4.3"
-"@shikijs/engine-oniguruma@1.18.0":
- version "1.18.0"
- resolved "https://registry.yarnpkg.com/@shikijs/engine-oniguruma/-/engine-oniguruma-1.18.0.tgz#7e57fd19b62b18cf2de382da684d042ee934f65d"
- integrity sha512-B9u0ZKI/cud+TcmF8Chyh+R4V5qQVvyDOqXC2l2a4x73PBSBc6sZ0JRAX3eqyJswqir6ktwApUUGBYePdKnMJg==
+"@shikijs/engine-oniguruma@1.22.0":
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.0.tgz#74c661fac4cd1f08f2c09b5d6e2fd2a6720d0401"
+ integrity sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==
dependencies:
- "@shikijs/types" "1.18.0"
- "@shikijs/vscode-textmate" "^9.2.2"
+ "@shikijs/types" "1.22.0"
+ "@shikijs/vscode-textmate" "^9.3.0"
-"@shikijs/types@1.18.0":
- version "1.18.0"
- resolved "https://registry.yarnpkg.com/@shikijs/types/-/types-1.18.0.tgz#4c2d62d17f78cbfc051a15480ab4dfb0f06196c9"
- integrity sha512-O9N36UEaGGrxv1yUrN2nye7gDLG5Uq0/c1LyfmxsvzNPqlHzWo9DI0A4+fhW2y3bGKuQu/fwS7EPdKJJCowcVA==
+"@shikijs/types@1.22.0":
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/@shikijs/types/-/types-1.22.0.tgz#d2a572381395c9308b472c8199b8e0289753b9ad"
+ integrity sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==
dependencies:
- "@shikijs/vscode-textmate" "^9.2.2"
+ "@shikijs/vscode-textmate" "^9.3.0"
"@types/hast" "^3.0.4"
-"@shikijs/vscode-textmate@^9.2.2":
- version "9.2.2"
- resolved "https://registry.yarnpkg.com/@shikijs/vscode-textmate/-/vscode-textmate-9.2.2.tgz#24571f50625c7cd075f9efe0def8b9d2c0930ada"
- integrity sha512-TMp15K+GGYrWlZM8+Lnj9EaHEFmOen0WJBrfa17hF7taDOYthuPPV0GWzfd/9iMij0akS/8Yw2ikquH7uVi/fg==
-
-"@swc/core-darwin-arm64@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.7.tgz#2b5cdbd34e4162e50de6147dd1a5cb12d23b08e8"
- integrity sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==
-
-"@swc/core-darwin-x64@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.5.7.tgz#6aa7e3c01ab8e5e41597f8a24ff24c4e50936a46"
- integrity sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==
-
-"@swc/core-linux-arm-gnueabihf@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.7.tgz#160108633b9e1d1ad05f815bedc7e9eb5d59fc2a"
- integrity sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==
-
-"@swc/core-linux-arm64-gnu@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.7.tgz#cbfa512683c73227ad25552f3b3e722b0e7fbd1d"
- integrity sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==
-
-"@swc/core-linux-arm64-musl@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.7.tgz#80239cb58fe57f3c86b44617fe784530ec55ee2b"
- integrity sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==
-
-"@swc/core-linux-x64-gnu@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.7.tgz#a699c1632de60b6a63b7fdb7abcb4fef317e57ca"
- integrity sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==
-
-"@swc/core-linux-x64-musl@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.7.tgz#8e4c203d6bc41e7f85d7d34d0fdf4ef751fa626c"
- integrity sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==
-
-"@swc/core-win32-arm64-msvc@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.7.tgz#31e3d42b8c0aa79f0ea1a980c0dd1a999d378ed7"
- integrity sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==
-
-"@swc/core-win32-ia32-msvc@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.7.tgz#a235285f9f62850aefcf9abb03420f2c54f63638"
- integrity sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==
-
-"@swc/core-win32-x64-msvc@1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz#f84641393b5223450d00d97bfff877b8b69d7c9b"
- integrity sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==
-
-"@swc/core@^1.5.7":
- version "1.5.7"
- resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.5.7.tgz#e1db7b9887d5f34eb4a3256a738d0c5f1b018c33"
- integrity sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==
- dependencies:
- "@swc/counter" "^0.1.2"
- "@swc/types" "0.1.7"
+"@shikijs/vscode-textmate@^9.3.0":
+ version "9.3.0"
+ resolved "https://registry.yarnpkg.com/@shikijs/vscode-textmate/-/vscode-textmate-9.3.0.tgz#b2f1776e488c1d6c2b6cd129bab62f71bbc9c7ab"
+ integrity sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==
+
+"@swc/core-darwin-arm64@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz#5f4096c00e71771ca1b18c824f0c92a052c70760"
+ integrity sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw==
+
+"@swc/core-darwin-x64@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz#867b7a4f094e6b64201090ca5fcbf3da7d0f3e22"
+ integrity sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ==
+
+"@swc/core-linux-arm-gnueabihf@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz#35bb43894def296d92aaa2cc9372d48042f37777"
+ integrity sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q==
+
+"@swc/core-linux-arm64-gnu@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz#8e2321cc4ec84cbfed8f8e16ff1ed7b854450443"
+ integrity sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q==
+
+"@swc/core-linux-arm64-musl@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz#b1c16e4b23ffa9ff19973eda6ffee35d2a7de7b0"
+ integrity sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==
+
+"@swc/core-linux-x64-gnu@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz#388e2cc13a010cd28787aead2cecf31eb491836d"
+ integrity sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==
+
+"@swc/core-linux-x64-musl@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz#51e0ff30981f26d7a5b97a7a7b5b291bad050d1a"
+ integrity sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==
+
+"@swc/core-win32-arm64-msvc@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz#a7fdcc4074c34ee6a026506b594d00323383c11f"
+ integrity sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA==
+
+"@swc/core-win32-ia32-msvc@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz#ae7be6dde798eebee2000b8fd84e01a439b5bd6a"
+ integrity sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ==
+
+"@swc/core-win32-x64-msvc@1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz#310d607004d7319085a4dec20c0c38c3405cc05b"
+ integrity sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w==
+
+"@swc/core@^1.7.26":
+ version "1.7.26"
+ resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.26.tgz#beda9b82063fcec7b56c958804a4d175aecf9a9d"
+ integrity sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+ "@swc/types" "^0.1.12"
optionalDependencies:
- "@swc/core-darwin-arm64" "1.5.7"
- "@swc/core-darwin-x64" "1.5.7"
- "@swc/core-linux-arm-gnueabihf" "1.5.7"
- "@swc/core-linux-arm64-gnu" "1.5.7"
- "@swc/core-linux-arm64-musl" "1.5.7"
- "@swc/core-linux-x64-gnu" "1.5.7"
- "@swc/core-linux-x64-musl" "1.5.7"
- "@swc/core-win32-arm64-msvc" "1.5.7"
- "@swc/core-win32-ia32-msvc" "1.5.7"
- "@swc/core-win32-x64-msvc" "1.5.7"
-
-"@swc/counter@^0.1.2", "@swc/counter@^0.1.3":
+ "@swc/core-darwin-arm64" "1.7.26"
+ "@swc/core-darwin-x64" "1.7.26"
+ "@swc/core-linux-arm-gnueabihf" "1.7.26"
+ "@swc/core-linux-arm64-gnu" "1.7.26"
+ "@swc/core-linux-arm64-musl" "1.7.26"
+ "@swc/core-linux-x64-gnu" "1.7.26"
+ "@swc/core-linux-x64-musl" "1.7.26"
+ "@swc/core-win32-arm64-msvc" "1.7.26"
+ "@swc/core-win32-ia32-msvc" "1.7.26"
+ "@swc/core-win32-x64-msvc" "1.7.26"
+
+"@swc/counter@^0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
-"@swc/types@0.1.7":
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.7.tgz#ea5d658cf460abff51507ca8d26e2d391bafb15e"
- integrity sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==
+"@swc/types@^0.1.12":
+ version "0.1.12"
+ resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.12.tgz#7f632c06ab4092ce0ebd046ed77ff7557442282f"
+ integrity sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==
dependencies:
"@swc/counter" "^0.1.3"
-"@tabler/icons-react@^3.17.0":
- version "3.17.0"
- resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-3.17.0.tgz#badafce6618f6b8104262538e3f55d34d09c2e29"
- integrity sha512-Ndm9Htv7KpIU1PYYrzs5EMhyA3aZGcgaxUp9Q1XOxcRZ+I0X+Ub2WS5f4bkRyDdL1s0++k2T9XRgmg2pG113sw==
+"@tabler/icons-react@^3.19.0":
+ version "3.19.0"
+ resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-3.19.0.tgz#9b5a421bf69875677fde52e7de73b4e6b5571e57"
+ integrity sha512-AqEWGI0tQWgqo6ZjMO5yJ9sYT8oXLuAM/up0hN9iENS6IdtNZryKrkNSiMgpwweNTpl8wFFG/dAZ959S91A/uQ==
dependencies:
- "@tabler/icons" "3.17.0"
+ "@tabler/icons" "3.19.0"
-"@tabler/icons@3.17.0":
- version "3.17.0"
- resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.17.0.tgz#329ca3e4cb533c5a6a61467fe5d6de14a0813020"
- integrity sha512-sCSfAQ0w93KSnSL7tS08n73CdIKpuHP8foeLMWgDKiZaCs8ZE//N3ytazCk651ZtruTtByI3b+ZDj7nRf+hHvA==
+"@tabler/icons@3.19.0":
+ version "3.19.0"
+ resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.19.0.tgz#5998b0557ef34572e003f2d75ac95e7c04f88c81"
+ integrity sha512-A4WEWqpdbTfnpFEtwXqwAe9qf9sp1yRPvzppqAuwcoF0q5YInqB+JkJtSFToCyBpPVeLxJUxxkapLvt2qQgnag==
-"@tanstack/query-core@5.56.2":
- version "5.56.2"
- resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.56.2.tgz#2def2fb0290cd2836bbb08afb0c175595bb8109b"
- integrity sha512-gor0RI3/R5rVV3gXfddh1MM+hgl0Z4G7tj6Xxpq6p2I03NGPaJ8dITY9Gz05zYYb/EJq9vPas/T4wn9EaDPd4Q==
+"@tanstack/query-core@5.59.6":
+ version "5.59.6"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.59.6.tgz#96bf2cc00f2bbd111def52134f10d50e6c1235dd"
+ integrity sha512-g58YTHe4ClRrjJ50GY9fas/0zARJVozY0Hs+hcSBOmwZaeKY+to0/LX8wKnnH/EJiLYcC1sHmE11CAS3ncfZBg==
-"@tanstack/react-query@^5.56.2":
- version "5.56.2"
- resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.56.2.tgz#3a0241b9d010910905382f5e99160997b8795f91"
- integrity sha512-SR0GzHVo6yzhN72pnRhkEFRAHMsUo5ZPzAxfTMvUxFIDVS6W9LYUp6nXW3fcHVdg0ZJl8opSH85jqahvm6DSVg==
+"@tanstack/react-query@^5.59.8":
+ version "5.59.8"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.59.8.tgz#ae00d67235be9fb6ce79779faa84228e69676041"
+ integrity sha512-jkvObpbjBL6P/PHFIjvNGG19XyhI8sjP6/Mw7CbmgT6SAps/5fZY5pxDicRwAt1YGCiEQvwrJQ6IdbZ8j5CVfw==
dependencies:
- "@tanstack/query-core" "5.56.2"
+ "@tanstack/query-core" "5.59.6"
"@testing-library/dom@^10.4.0":
version "10.4.0"
@@ -1059,10 +1059,10 @@
dependencies:
undici-types "~5.26.4"
-"@types/node@^22.5.5":
- version "22.5.5"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44"
- integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==
+"@types/node@^22.7.5":
+ version "22.7.5"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b"
+ integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==
dependencies:
undici-types "~6.19.2"
@@ -1086,10 +1086,10 @@
"@types/prop-types" "*"
csstype "^3.0.2"
-"@types/react@^18.3.8":
- version "18.3.8"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.8.tgz#1672ab19993f8aca7c7dc844c07d5d9e467d5a79"
- integrity sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==
+"@types/react@^18.3.11":
+ version "18.3.11"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.11.tgz#9d530601ff843ee0d7030d4227ea4360236bd537"
+ integrity sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==
dependencies:
"@types/prop-types" "*"
csstype "^3.0.2"
@@ -1124,30 +1124,30 @@
resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd"
integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==
-"@typescript-eslint/eslint-plugin@8.6.0":
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz#20049754ff9f6d3a09bf240297f029ce04290999"
- integrity sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==
+"@typescript-eslint/eslint-plugin@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371"
+ integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==
dependencies:
"@eslint-community/regexpp" "^4.10.0"
- "@typescript-eslint/scope-manager" "8.6.0"
- "@typescript-eslint/type-utils" "8.6.0"
- "@typescript-eslint/utils" "8.6.0"
- "@typescript-eslint/visitor-keys" "8.6.0"
+ "@typescript-eslint/scope-manager" "8.8.1"
+ "@typescript-eslint/type-utils" "8.8.1"
+ "@typescript-eslint/utils" "8.8.1"
+ "@typescript-eslint/visitor-keys" "8.8.1"
graphemer "^1.4.0"
ignore "^5.3.1"
natural-compare "^1.4.0"
ts-api-utils "^1.3.0"
-"@typescript-eslint/parser@8.6.0":
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.6.0.tgz#02e092b9dc8b4e319172af620d0d39b337d948f6"
- integrity sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==
+"@typescript-eslint/parser@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8"
+ integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==
dependencies:
- "@typescript-eslint/scope-manager" "8.6.0"
- "@typescript-eslint/types" "8.6.0"
- "@typescript-eslint/typescript-estree" "8.6.0"
- "@typescript-eslint/visitor-keys" "8.6.0"
+ "@typescript-eslint/scope-manager" "8.8.1"
+ "@typescript-eslint/types" "8.8.1"
+ "@typescript-eslint/typescript-estree" "8.8.1"
+ "@typescript-eslint/visitor-keys" "8.8.1"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.62.0":
@@ -1166,21 +1166,21 @@
"@typescript-eslint/types" "7.10.0"
"@typescript-eslint/visitor-keys" "7.10.0"
-"@typescript-eslint/scope-manager@8.6.0":
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz#28cc2fc26a84b75addf45091a2c6283e29e2c982"
- integrity sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==
+"@typescript-eslint/scope-manager@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff"
+ integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==
dependencies:
- "@typescript-eslint/types" "8.6.0"
- "@typescript-eslint/visitor-keys" "8.6.0"
+ "@typescript-eslint/types" "8.8.1"
+ "@typescript-eslint/visitor-keys" "8.8.1"
-"@typescript-eslint/type-utils@8.6.0":
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz#d4347e637478bef88cee1db691fcfa20ade9b8a0"
- integrity sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==
+"@typescript-eslint/type-utils@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e"
+ integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==
dependencies:
- "@typescript-eslint/typescript-estree" "8.6.0"
- "@typescript-eslint/utils" "8.6.0"
+ "@typescript-eslint/typescript-estree" "8.8.1"
+ "@typescript-eslint/utils" "8.8.1"
debug "^4.3.4"
ts-api-utils "^1.3.0"
@@ -1194,10 +1194,10 @@
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.10.0.tgz#da92309c97932a3a033762fd5faa8b067de84e3b"
integrity sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==
-"@typescript-eslint/types@8.6.0":
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.6.0.tgz#cdc3a16f83f2f0663d6723e9fd032331cdd9f51c"
- integrity sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==
+"@typescript-eslint/types@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1"
+ integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==
"@typescript-eslint/typescript-estree@5.62.0":
version "5.62.0"
@@ -1226,13 +1226,13 @@
semver "^7.6.0"
ts-api-utils "^1.3.0"
-"@typescript-eslint/typescript-estree@8.6.0":
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz#f945506de42871f04868371cb5bf21e8f7266e01"
- integrity sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==
+"@typescript-eslint/typescript-estree@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec"
+ integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==
dependencies:
- "@typescript-eslint/types" "8.6.0"
- "@typescript-eslint/visitor-keys" "8.6.0"
+ "@typescript-eslint/types" "8.8.1"
+ "@typescript-eslint/visitor-keys" "8.8.1"
debug "^4.3.4"
fast-glob "^3.3.2"
is-glob "^4.0.3"
@@ -1240,15 +1240,15 @@
semver "^7.6.0"
ts-api-utils "^1.3.0"
-"@typescript-eslint/utils@8.6.0":
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.6.0.tgz#175fe893f32804bed1e72b3364ea6bbe1044181c"
- integrity sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==
+"@typescript-eslint/utils@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d"
+ integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==
dependencies:
"@eslint-community/eslint-utils" "^4.4.0"
- "@typescript-eslint/scope-manager" "8.6.0"
- "@typescript-eslint/types" "8.6.0"
- "@typescript-eslint/typescript-estree" "8.6.0"
+ "@typescript-eslint/scope-manager" "8.8.1"
+ "@typescript-eslint/types" "8.8.1"
+ "@typescript-eslint/typescript-estree" "8.8.1"
"@typescript-eslint/utils@^5.58.0":
version "5.62.0"
@@ -1290,12 +1290,12 @@
"@typescript-eslint/types" "7.10.0"
eslint-visitor-keys "^3.4.3"
-"@typescript-eslint/visitor-keys@8.6.0":
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz#5432af4a1753f376f35ab5b891fc9db237aaf76f"
- integrity sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==
+"@typescript-eslint/visitor-keys@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5"
+ integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==
dependencies:
- "@typescript-eslint/types" "8.6.0"
+ "@typescript-eslint/types" "8.8.1"
eslint-visitor-keys "^3.4.3"
"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0":
@@ -1303,17 +1303,17 @@
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
-"@vitejs/plugin-react-swc@^3.7.0":
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.7.0.tgz#e456c0a6d7f562268e1d231af9ac46b86ef47d88"
- integrity sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA==
+"@vitejs/plugin-react-swc@^3.7.1":
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.7.1.tgz#bc5af48ef35c525d623fa14177c912cbaa86a846"
+ integrity sha512-vgWOY0i1EROUK0Ctg1hwhtC3SdcDjZcdit4Ups4aPkDcB1jYhmo+RMYWY87cmXMhvtD5uf8lV89j2w16vkdSVg==
dependencies:
- "@swc/core" "^1.5.7"
+ "@swc/core" "^1.7.26"
-"@vitest/coverage-istanbul@^2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/coverage-istanbul/-/coverage-istanbul-2.1.1.tgz#11950fea0bff2628f3c278e2dac338e4af69c521"
- integrity sha512-ZQM8uLinwmhmLp49fxLxIM46nC7NisCbaiydcQoV1hLvQfFL92Gg3tInRvowZyV78G0IknjN10JzH7oqPlPjZw==
+"@vitest/coverage-istanbul@^2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/coverage-istanbul/-/coverage-istanbul-2.1.2.tgz#9c0beddef5a146b7cbf39781cfd6f6dde6e3b3c8"
+ integrity sha512-dg7ex3GKrTIenAV0oEp78JucTVFsPMzjl1gYWun22O7SBDxcHFC/REZjWLhMTHRHY8ihm4uBCvmu+CvEu5/Adg==
dependencies:
"@istanbuljs/schema" "^0.1.3"
debug "^4.3.6"
@@ -1326,53 +1326,53 @@
test-exclude "^7.0.1"
tinyrainbow "^1.2.0"
-"@vitest/expect@2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.1.1.tgz#907137a86246c5328929d796d741c4e95d1ee19d"
- integrity sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==
+"@vitest/expect@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.1.2.tgz#e92fa284b8472548f72cacfe896020c64af6bf78"
+ integrity sha512-FEgtlN8mIUSEAAnlvn7mP8vzaWhEaAEvhSXCqrsijM7K6QqjB11qoRZYEd4AKSCDz8p0/+yH5LzhZ47qt+EyPg==
dependencies:
- "@vitest/spy" "2.1.1"
- "@vitest/utils" "2.1.1"
+ "@vitest/spy" "2.1.2"
+ "@vitest/utils" "2.1.2"
chai "^5.1.1"
tinyrainbow "^1.2.0"
-"@vitest/mocker@2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-2.1.1.tgz#3e37c80ac267318d4aa03c5073a017d148dc8e67"
- integrity sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==
+"@vitest/mocker@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-2.1.2.tgz#08853a9d8d12afba284aebdf9b5ea26ddae5f20a"
+ integrity sha512-ExElkCGMS13JAJy+812fw1aCv2QO/LBK6CyO4WOPAzLTmve50gydOlWhgdBJPx2ztbADUq3JVI0C5U+bShaeEA==
dependencies:
"@vitest/spy" "^2.1.0-beta.1"
estree-walker "^3.0.3"
magic-string "^0.30.11"
-"@vitest/pretty-format@2.1.1", "@vitest/pretty-format@^2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.1.tgz#fea25dd4e88c3c1329fbccd1d16b1d607eb40067"
- integrity sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==
+"@vitest/pretty-format@2.1.2", "@vitest/pretty-format@^2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.2.tgz#42882ea18c4cd40428e34f74bbac706a82465193"
+ integrity sha512-FIoglbHrSUlOJPDGIrh2bjX1sNars5HbxlcsFKCtKzu4+5lpsRhOCVcuzp0fEhAGHkPZRIXVNzPcpSlkoZ3LuA==
dependencies:
tinyrainbow "^1.2.0"
-"@vitest/runner@2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.1.1.tgz#f3b1fbc3c109fc44e2cceecc881344453f275559"
- integrity sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==
+"@vitest/runner@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.1.2.tgz#14da1f5eac43fbd9a37d7cd72de102e8f785d727"
+ integrity sha512-UCsPtvluHO3u7jdoONGjOSil+uON5SSvU9buQh3lP7GgUXHp78guN1wRmZDX4wGK6J10f9NUtP6pO+SFquoMlw==
dependencies:
- "@vitest/utils" "2.1.1"
+ "@vitest/utils" "2.1.2"
pathe "^1.1.2"
-"@vitest/snapshot@2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.1.1.tgz#38ef23104e90231fea5540754a19d8468afbba66"
- integrity sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==
+"@vitest/snapshot@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.1.2.tgz#e20bd794b33fdcd4bfe69138baac7bb890c4d51f"
+ integrity sha512-xtAeNsZ++aRIYIUsek7VHzry/9AcxeULlegBvsdLncLmNCR6tR8SRjn8BbDP4naxtccvzTqZ+L1ltZlRCfBZFA==
dependencies:
- "@vitest/pretty-format" "2.1.1"
+ "@vitest/pretty-format" "2.1.2"
magic-string "^0.30.11"
pathe "^1.1.2"
-"@vitest/spy@2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.1.1.tgz#20891f7421a994256ea0d739ed72f05532c78488"
- integrity sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==
+"@vitest/spy@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.1.2.tgz#bccdeca597c8fc3777302889e8c98cec9264df44"
+ integrity sha512-GSUi5zoy+abNRJwmFhBDC0yRuVUn8WMlQscvnbbXdKLXX9dE59YbfwXxuJ/mth6eeqIzofU8BB5XDo/Ns/qK2A==
dependencies:
tinyspy "^3.0.0"
@@ -1383,12 +1383,12 @@
dependencies:
tinyspy "^3.0.0"
-"@vitest/ui@^2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-2.1.1.tgz#3d2b3c4e2f8f30c3615e731e0c63510799546b94"
- integrity sha512-IIxo2LkQDA+1TZdPLYPclzsXukBWd5dX2CKpGqH8CCt8Wh0ZuDn4+vuQ9qlppEju6/igDGzjWF/zyorfsf+nHg==
+"@vitest/ui@^2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-2.1.2.tgz#039d2a264ea517cb2f5b8a6a5d806c6a7c73f9a2"
+ integrity sha512-92gcNzkDnmxOxyHzQrQYRsoV9Q0Aay0r4QMLnV+B+lbqlUWa8nDg9ivyLV5mMVTtGirHsYUGGh/zbIA55gBZqA==
dependencies:
- "@vitest/utils" "2.1.1"
+ "@vitest/utils" "2.1.2"
fflate "^0.8.2"
flatted "^3.3.1"
pathe "^1.1.2"
@@ -1396,12 +1396,12 @@
tinyglobby "^0.2.6"
tinyrainbow "^1.2.0"
-"@vitest/utils@2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.1.tgz#284d016449ecb4f8704d198d049fde8360cc136e"
- integrity sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==
+"@vitest/utils@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.2.tgz#222ac35ba02493173e40581256eb7a62520fcdba"
+ integrity sha512-zMO2KdYy6mx56btx9JvAqAZ6EyS3g49krMPPrgOp1yxGZiA93HumGk+bZ5jIZtOg5/VBYl5eBmGRQHqq4FG6uQ==
dependencies:
- "@vitest/pretty-format" "2.1.1"
+ "@vitest/pretty-format" "2.1.2"
loupe "^3.1.1"
tinyrainbow "^1.2.0"
@@ -2308,24 +2308,24 @@ eslint-import-resolver-node@^0.3.9:
is-core-module "^2.13.0"
resolve "^1.22.4"
-eslint-module-utils@^2.9.0:
- version "2.11.0"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz#b99b211ca4318243f09661fae088f373ad5243c4"
- integrity sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==
+eslint-module-utils@^2.12.0:
+ version "2.12.0"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b"
+ integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==
dependencies:
debug "^3.2.7"
-eslint-plugin-html@^8.1.1:
- version "8.1.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-8.1.1.tgz#504444f39e3ccb64502ac68dc6c534567aa56492"
- integrity sha512-6qmlJsc40D2m3Dn9oEH+0PAOkJhxVu0f5sVItqpCE0YWgYnyP4xCjBc3UWTHaJcY9ARkWOLIIuXLq0ndRnQOHw==
+eslint-plugin-html@^8.1.2:
+ version "8.1.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-8.1.2.tgz#3a7a092d1e19e7e494014ed0747c5873856d7e1c"
+ integrity sha512-pbRchDV2SmqbCi/Ev/q3aAikzG9BcFe0IjjqjtMn8eTLq71ZUggyJB6CDmuwGAXmYZHrXI12XTfCqvgcnPRqGw==
dependencies:
htmlparser2 "^9.1.0"
-eslint-plugin-import@^2.30.0:
- version "2.30.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz#21ceea0fc462657195989dd780e50c92fe95f449"
- integrity sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==
+eslint-plugin-import@^2.31.0:
+ version "2.31.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7"
+ integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==
dependencies:
"@rtsao/scc" "^1.1.0"
array-includes "^3.1.8"
@@ -2335,7 +2335,7 @@ eslint-plugin-import@^2.30.0:
debug "^3.2.7"
doctrine "^2.1.0"
eslint-import-resolver-node "^0.3.9"
- eslint-module-utils "^2.9.0"
+ eslint-module-utils "^2.12.0"
hasown "^2.0.2"
is-core-module "^2.15.1"
is-glob "^4.0.3"
@@ -2344,6 +2344,7 @@ eslint-plugin-import@^2.30.0:
object.groupby "^1.0.3"
object.values "^1.2.0"
semver "^6.3.1"
+ string.prototype.trimend "^1.0.8"
tsconfig-paths "^3.15.0"
eslint-plugin-jsx-a11y@^6.10.0:
@@ -2386,10 +2387,10 @@ eslint-plugin-react-hooks@^4.6.2:
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596"
integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==
-eslint-plugin-react@^7.36.1:
- version "7.36.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz#f1dabbb11f3d4ebe8b0cf4e54aff4aee81144ee5"
- integrity sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==
+eslint-plugin-react@^7.37.1:
+ version "7.37.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz#56493d7d69174d0d828bc83afeffe96903fdadbd"
+ integrity sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==
dependencies:
array-includes "^3.1.8"
array.prototype.findlast "^1.2.5"
@@ -3258,10 +3259,10 @@ jackspeak@^3.1.2:
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
-jose@^5.9.2:
- version "5.9.2"
- resolved "https://registry.yarnpkg.com/jose/-/jose-5.9.2.tgz#22a22da06edb8fb9e583aa24bafc1e8457b4db92"
- integrity sha512-ILI2xx/I57b20sd7rHZvgiiQrmp2mcotwsAH+5ajbpFQbrYVQdNHYlQhoA5cFb78CgtBOxtC05TeA+mcgkuCqQ==
+jose@^5.9.3:
+ version "5.9.3"
+ resolved "https://registry.yarnpkg.com/jose/-/jose-5.9.3.tgz#6eba1ee3f70b42891f0e1883fe0084a46dbbe02c"
+ integrity sha512-egLIoYSpcd+QUF+UHgobt5YzI2Pkw/H39ou9suW687MY6PmCwPmkNV/4TNjn1p2tX5xO3j0d0sq5hiYE24bSlg==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
@@ -4126,28 +4127,28 @@ rimraf@^3.0.2:
glob "^7.1.3"
rollup@^4.20.0:
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.3.tgz#c64ba119e6aeb913798a6f7eef2780a0df5a0821"
- integrity sha512-7sqRtBNnEbcBtMeRVc6VRsJMmpI+JU1z9VTvW8D4gXIYQFz0aLcsE6rRkyghZkLfEgUZgVvOG7A5CVz/VW5GIA==
+ version "4.22.4"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.22.4.tgz#4135a6446671cd2a2453e1ad42a45d5973ec3a0f"
+ integrity sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==
dependencies:
"@types/estree" "1.0.5"
optionalDependencies:
- "@rollup/rollup-android-arm-eabi" "4.21.3"
- "@rollup/rollup-android-arm64" "4.21.3"
- "@rollup/rollup-darwin-arm64" "4.21.3"
- "@rollup/rollup-darwin-x64" "4.21.3"
- "@rollup/rollup-linux-arm-gnueabihf" "4.21.3"
- "@rollup/rollup-linux-arm-musleabihf" "4.21.3"
- "@rollup/rollup-linux-arm64-gnu" "4.21.3"
- "@rollup/rollup-linux-arm64-musl" "4.21.3"
- "@rollup/rollup-linux-powerpc64le-gnu" "4.21.3"
- "@rollup/rollup-linux-riscv64-gnu" "4.21.3"
- "@rollup/rollup-linux-s390x-gnu" "4.21.3"
- "@rollup/rollup-linux-x64-gnu" "4.21.3"
- "@rollup/rollup-linux-x64-musl" "4.21.3"
- "@rollup/rollup-win32-arm64-msvc" "4.21.3"
- "@rollup/rollup-win32-ia32-msvc" "4.21.3"
- "@rollup/rollup-win32-x64-msvc" "4.21.3"
+ "@rollup/rollup-android-arm-eabi" "4.22.4"
+ "@rollup/rollup-android-arm64" "4.22.4"
+ "@rollup/rollup-darwin-arm64" "4.22.4"
+ "@rollup/rollup-darwin-x64" "4.22.4"
+ "@rollup/rollup-linux-arm-gnueabihf" "4.22.4"
+ "@rollup/rollup-linux-arm-musleabihf" "4.22.4"
+ "@rollup/rollup-linux-arm64-gnu" "4.22.4"
+ "@rollup/rollup-linux-arm64-musl" "4.22.4"
+ "@rollup/rollup-linux-powerpc64le-gnu" "4.22.4"
+ "@rollup/rollup-linux-riscv64-gnu" "4.22.4"
+ "@rollup/rollup-linux-s390x-gnu" "4.22.4"
+ "@rollup/rollup-linux-x64-gnu" "4.22.4"
+ "@rollup/rollup-linux-x64-musl" "4.22.4"
+ "@rollup/rollup-win32-arm64-msvc" "4.22.4"
+ "@rollup/rollup-win32-ia32-msvc" "4.22.4"
+ "@rollup/rollup-win32-x64-msvc" "4.22.4"
fsevents "~2.3.2"
run-parallel@^1.1.9:
@@ -4227,16 +4228,16 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-shiki@^1.18.0:
- version "1.18.0"
- resolved "https://registry.yarnpkg.com/shiki/-/shiki-1.18.0.tgz#4f9ca2f442b3612849017ab1dcac47c35ee52276"
- integrity sha512-8jo7tOXr96h9PBQmOHVrltnETn1honZZY76YA79MHheGQg55jBvbm9dtU+MI5pjC5NJCFuA6rvVTLVeSW5cE4A==
+shiki@^1.22.0:
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/shiki/-/shiki-1.22.0.tgz#45d1dfff0e03a598af70e2ec8592f14ef07827b4"
+ integrity sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==
dependencies:
- "@shikijs/core" "1.18.0"
- "@shikijs/engine-javascript" "1.18.0"
- "@shikijs/engine-oniguruma" "1.18.0"
- "@shikijs/types" "1.18.0"
- "@shikijs/vscode-textmate" "^9.2.2"
+ "@shikijs/core" "1.22.0"
+ "@shikijs/engine-javascript" "1.22.0"
+ "@shikijs/engine-oniguruma" "1.22.0"
+ "@shikijs/types" "1.22.0"
+ "@shikijs/vscode-textmate" "^9.3.0"
"@types/hast" "^3.0.4"
side-channel@^1.0.4, side-channel@^1.0.6:
@@ -4679,19 +4680,19 @@ typed-array-length@^1.0.6:
is-typed-array "^1.1.13"
possible-typed-array-names "^1.0.0"
-typescript-eslint@^8.6.0:
- version "8.6.0"
- resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.6.0.tgz#5f0b5e23b34385ef146e447616c1a0d6bd14bedb"
- integrity sha512-eEhhlxCEpCd4helh3AO1hk0UP2MvbRi9CtIAJTVPQjuSXOOO2jsEacNi4UdcJzZJbeuVg1gMhtZ8UYb+NFYPrA==
+typescript-eslint@^8.8.1:
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.8.1.tgz#b375c877b2184d883b6228170bc66f0fca847c9a"
+ integrity sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==
dependencies:
- "@typescript-eslint/eslint-plugin" "8.6.0"
- "@typescript-eslint/parser" "8.6.0"
- "@typescript-eslint/utils" "8.6.0"
+ "@typescript-eslint/eslint-plugin" "8.8.1"
+ "@typescript-eslint/parser" "8.8.1"
+ "@typescript-eslint/utils" "8.8.1"
-typescript@^5.6.2:
- version "5.6.2"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0"
- integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==
+typescript@^5.6.3:
+ version "5.6.3"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b"
+ integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==
unbox-primitive@^1.0.2:
version "1.0.2"
@@ -4842,10 +4843,10 @@ vfile@^6.0.0:
"@types/unist" "^3.0.0"
vfile-message "^4.0.0"
-vite-node@2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.1.1.tgz#7d46f623c04dfed6df34e7127711508a3386fa1c"
- integrity sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==
+vite-node@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.1.2.tgz#f5491a2b399959c9e2f3c4b70cb0cbaecf9be6d2"
+ integrity sha512-HPcGNN5g/7I2OtPjLqgOtCRu/qhVvBxTUD3qzitmL0SrG1cWFzxzhMDWussxSbrRYWqnKf8P2jiNhPMSN+ymsQ==
dependencies:
cac "^6.7.14"
debug "^4.3.6"
@@ -4902,10 +4903,10 @@ vite@^5.0.0:
optionalDependencies:
fsevents "~2.3.3"
-vite@^5.4.7:
- version "5.4.7"
- resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.7.tgz#d226f57c08b61379e955f3836253ed3efb2dcf00"
- integrity sha512-5l2zxqMEPVENgvzTuBpHer2awaetimj2BGkhBPdnwKbPNOlHsODU+oiazEZzLK7KhAnOrO+XGYJYn4ZlUhDtDQ==
+vite@^5.4.8:
+ version "5.4.8"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8"
+ integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==
dependencies:
esbuild "^0.21.3"
postcss "^8.4.43"
@@ -4918,18 +4919,18 @@ vitest-sonar-reporter@^2.0.0:
resolved "https://registry.yarnpkg.com/vitest-sonar-reporter/-/vitest-sonar-reporter-2.0.0.tgz#6372e5faba2b2834eac0b2cd1283263d38d0e718"
integrity sha512-LorC3NnmrBrryx4+l3BEsNQjD0Y7wfmrD1y/+tHDuZUuVj7w8nOxRXCBSppDfmgfpToOhwchh0JcL4IGMKUKDA==
-vitest@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.1.1.tgz#24a6f6f5d894509f10685b82de008c507faacbb1"
- integrity sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==
- dependencies:
- "@vitest/expect" "2.1.1"
- "@vitest/mocker" "2.1.1"
- "@vitest/pretty-format" "^2.1.1"
- "@vitest/runner" "2.1.1"
- "@vitest/snapshot" "2.1.1"
- "@vitest/spy" "2.1.1"
- "@vitest/utils" "2.1.1"
+vitest@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.1.2.tgz#f285fdde876749fddc0cb4d9748ae224443c1694"
+ integrity sha512-veNjLizOMkRrJ6xxb+pvxN6/QAWg95mzcRjtmkepXdN87FNfxAss9RKe2far/G9cQpipfgP2taqg0KiWsquj8A==
+ dependencies:
+ "@vitest/expect" "2.1.2"
+ "@vitest/mocker" "2.1.2"
+ "@vitest/pretty-format" "^2.1.2"
+ "@vitest/runner" "2.1.2"
+ "@vitest/snapshot" "2.1.2"
+ "@vitest/spy" "2.1.2"
+ "@vitest/utils" "2.1.2"
chai "^5.1.1"
debug "^4.3.6"
magic-string "^0.30.11"
@@ -4940,7 +4941,7 @@ vitest@^2.1.1:
tinypool "^1.0.0"
tinyrainbow "^1.2.0"
vite "^5.0.0"
- vite-node "2.1.1"
+ vite-node "2.1.2"
why-is-node-running "^2.3.0"
vscode-jsonrpc@6.0.0:
diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props
index fd31157a..555a684f 100644
--- a/tests/Directory.Build.props
+++ b/tests/Directory.Build.props
@@ -18,8 +18,8 @@
runtime; build; native; contentfiles; analyzers
-
-
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/tests/Serilog.Ui.Common.Tests/Serilog.Ui.Common.Tests.csproj b/tests/Serilog.Ui.Common.Tests/Serilog.Ui.Common.Tests.csproj
index 41d9b3f3..625cd480 100644
--- a/tests/Serilog.Ui.Common.Tests/Serilog.Ui.Common.Tests.csproj
+++ b/tests/Serilog.Ui.Common.Tests/Serilog.Ui.Common.Tests.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/tests/Serilog.Ui.ElasticSearchProvider.Tests/Serilog.Ui.ElasticSearchProvider.Tests.csproj b/tests/Serilog.Ui.ElasticSearchProvider.Tests/Serilog.Ui.ElasticSearchProvider.Tests.csproj
index 9bd4ca9b..f773c9e1 100644
--- a/tests/Serilog.Ui.ElasticSearchProvider.Tests/Serilog.Ui.ElasticSearchProvider.Tests.csproj
+++ b/tests/Serilog.Ui.ElasticSearchProvider.Tests/Serilog.Ui.ElasticSearchProvider.Tests.csproj
@@ -8,8 +8,8 @@
-
-
+
+
diff --git a/tests/Serilog.Ui.MongoDbProvider.Tests/Serilog.Ui.MongoDbProvider.Tests.csproj b/tests/Serilog.Ui.MongoDbProvider.Tests/Serilog.Ui.MongoDbProvider.Tests.csproj
index 6b181e90..0564f22b 100644
--- a/tests/Serilog.Ui.MongoDbProvider.Tests/Serilog.Ui.MongoDbProvider.Tests.csproj
+++ b/tests/Serilog.Ui.MongoDbProvider.Tests/Serilog.Ui.MongoDbProvider.Tests.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/tests/Serilog.Ui.MsSqlServerProvider.Tests/DataProvider/DataProviderBaseTest.cs b/tests/Serilog.Ui.MsSqlServerProvider.Tests/DataProvider/DataProviderBaseTest.cs
index 34ab68d9..6278d88b 100644
--- a/tests/Serilog.Ui.MsSqlServerProvider.Tests/DataProvider/DataProviderBaseTest.cs
+++ b/tests/Serilog.Ui.MsSqlServerProvider.Tests/DataProvider/DataProviderBaseTest.cs
@@ -7,42 +7,39 @@
using Serilog.Ui.Common.Tests.TestSuites;
using Serilog.Ui.Core.Extensions;
using Serilog.Ui.Core.Models;
-using Serilog.Ui.Core.Models.Options;
using Serilog.Ui.MsSqlServerProvider;
+using Serilog.Ui.MsSqlServerProvider.Extensions;
using Xunit;
-namespace MsSql.Tests.DataProvider
+namespace MsSql.Tests.DataProvider;
+
+[Trait("Unit-Base", "MsSql")]
+public class DataProviderBaseTest : IUnitBaseTests
{
- [Trait("Unit-Base", "MsSql")]
- public class DataProviderBaseTest : IUnitBaseTests
+ [Fact(Skip = "Not required")]
+ public void It_throws_when_any_dependency_is_null()
+ => throw new NotImplementedException();
+
+ [Fact]
+ public async Task It_logs_and_throws_when_db_read_breaks_down()
{
- [Fact]
- public void It_throws_when_any_dependency_is_null()
- {
- var suts = new List
- {
- () => { _ = new SqlServerDataProvider(null!); },
- () => { _ = new SqlServerDataProvider(null!); },
- };
+ // Arrange
+ SqlServerDataProvider sut = new(
+ new SqlServerDbOptions("dbo").WithConnectionString("connString").WithTable("logs"),
+ new SqlServerQueryBuilder());
- suts.ForEach(sut => sut.Should().ThrowExactly());
- }
+ SqlServerDataProvider sutWithCols = new(
+ new SqlServerDbOptions("dbo").WithConnectionString("connString").WithTable("logs"),
+ new SqlServerQueryBuilder());
- [Fact]
- public async Task It_logs_and_throws_when_db_read_breaks_down()
- {
- // Arrange
- var sut = new SqlServerDataProvider(new RelationalDbOptions("dbo").WithConnectionString("connString").WithTable("logs"));
- var sutWithAdditionalCols =
- new SqlServerDataProvider(new RelationalDbOptions("dbo").WithConnectionString("connString").WithTable("logs"));
- var query = new Dictionary { ["page"] = "1", ["count"] = "10", };
+ Dictionary query = new() { ["page"] = "1", ["count"] = "10" };
- // Act
- var assert = () => sut.FetchDataAsync(FetchLogsQuery.ParseQuery(query));
- var assertWithAdditionalCols = () => sutWithAdditionalCols.FetchDataAsync(FetchLogsQuery.ParseQuery(query));
+ // Act
+ var assert = () => sut.FetchDataAsync(FetchLogsQuery.ParseQuery(query));
+ var assertWithCols = () => sutWithCols.FetchDataAsync(FetchLogsQuery.ParseQuery(query));
- await assert.Should().ThrowExactlyAsync();
- await assertWithAdditionalCols.Should().ThrowExactlyAsync();
- }
+ // Assert
+ await assert.Should().ThrowExactlyAsync();
+ await assertWithCols.Should().ThrowExactlyAsync();
}
}
\ No newline at end of file
diff --git a/tests/Serilog.Ui.MsSqlServerProvider.Tests/DataProvider/QueryBuilderTests.cs b/tests/Serilog.Ui.MsSqlServerProvider.Tests/DataProvider/QueryBuilderTests.cs
new file mode 100644
index 00000000..1c3ce788
--- /dev/null
+++ b/tests/Serilog.Ui.MsSqlServerProvider.Tests/DataProvider/QueryBuilderTests.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using FluentAssertions;
+using Microsoft.Extensions.Primitives;
+using MsSql.Tests.Util;
+using Serilog.Ui.Core.Models;
+using Serilog.Ui.MsSqlServerProvider;
+using Serilog.Ui.MsSqlServerProvider.Models;
+using Xunit;
+
+namespace MsSql.Tests.DataProvider;
+
+[Trait("Unit-QueryBuilder", "MsSql")]
+public class QueryBuilderTests
+{
+ [Theory]
+ [ClassData(typeof(QueryBuilderTestData))]
+ public void BuildFetchLogsQuery_ForSink_ReturnsCorrectQuery(
+ string schema,
+ string tableName,
+ string level,
+ string searchCriteria,
+ DateTime? startDate,
+ DateTime? endDate,
+ string expectedQuery)
+ {
+ // Arrange
+ Dictionary queryLogs = new()
+ {
+ ["level"] = level,
+ ["search"] = searchCriteria,
+ ["startDate"] = startDate?.ToString("O"),
+ ["endDate"] = endDate?.ToString("O")
+ };
+
+ SqlServerSinkColumnNames sinkColumns = new();
+ SqlServerQueryBuilder sut = new();
+
+ // Act
+ string query = sut.BuildFetchLogsQuery(sinkColumns, schema, tableName, FetchLogsQuery.ParseQuery(queryLogs));
+
+ // Assert
+ query.Should().Be(expectedQuery);
+ }
+
+ [Fact]
+ public void BuildFetchLogsQuery_not_includes_Exception_if_custom_log_model()
+ {
+ // Arrange
+ Dictionary queryLogs = new()
+ {
+ ["level"] = "level",
+ ["search"] = "criteria"
+ };
+
+ SqlServerSinkColumnNames sinkColumns = new();
+ SqlServerQueryBuilder sut = new();
+
+ // Act
+ string query = sut.BuildFetchLogsQuery(sinkColumns, "test", "logs", FetchLogsQuery.ParseQuery(queryLogs));
+
+ // Assert
+ query.ToLowerInvariant().Should().StartWith("select");
+ query.ToLowerInvariant().Should().NotContain("exception");
+ }
+
+ public class QueryBuilderTestData : IEnumerable