Skip to content

Test Improvements & Benchmarks for SqlKata Compiler #738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9519fc7
Basic Fixes and Add user secrets for db connection.
faddiv Nov 29, 2024
4e748e1
Testing improvement: Eliminate direct testing of CompileLimit
faddiv Nov 29, 2024
7d23e22
Improved Delete tests
faddiv Nov 30, 2024
d3355a1
Improved ExecutionTests
faddiv Nov 30, 2024
e9df38e
Refactor DefineTest
faddiv Nov 30, 2024
3631797
Improved GeneralTests part 1
faddiv Nov 30, 2024
0ba9bf3
Improved GeneralTests part 2
faddiv Dec 1, 2024
8a7996e
Imporved InsertTests part 1
faddiv Dec 1, 2024
8e97da4
Imporved InsertTests part 2
faddiv Dec 4, 2024
8b9d26d
Move MySql and SqlLite execution tests into subdir.
faddiv Dec 4, 2024
67ab7ad
Move QueryFactoryExtensions into infra
faddiv Dec 4, 2024
047ec4d
Imporved SelectTests part 1
faddiv Dec 4, 2024
d009e75
Imporved SelectTests part 2
faddiv Dec 8, 2024
1b3d430
Imporved SelectTests part 3
faddiv Dec 22, 2024
1496dbd
Improved UpdateTests
faddiv Dec 22, 2024
132e8b9
Improved WhereTests
faddiv Dec 22, 2024
1de8e2d
Organize code.
faddiv Dec 22, 2024
21bf41f
Improve WhiteListing coverage.
faddiv Dec 22, 2024
6f70580
Improve AggregateTests
faddiv Dec 22, 2024
b9553b6
UnsafeLiteral in conditions
faddiv Dec 22, 2024
b9e3ed7
Binding tests
faddiv Dec 23, 2024
3c26169
Eliminate old TestCompilersContainer
faddiv Dec 24, 2024
7d69200
Add Select benchmark.
faddiv Dec 24, 2024
fdbe84d
Add different benchmarks and tests
faddiv Dec 25, 2024
441a619
Global usings
faddiv Dec 25, 2024
817c514
Remove direct Limit test from Firebird
faddiv Dec 25, 2024
39c9719
Remove direct Limit test from Oracle and SqlServer
faddiv Dec 25, 2024
b0672d2
Merge branch 'master' into faddiv/main
faddiv Feb 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions QueryBuilder.Benchmarks/Infrastructure/TestCompiler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using SqlKata.Compilers;

namespace QueryBuilder.Benchmarks.Infrastructure;

public class TestCompiler
: Compiler
{
public override string EngineCode { get; } = "generic";
}
49 changes: 49 additions & 0 deletions QueryBuilder.Benchmarks/Infrastructure/TestSupport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using SqlKata;
using SqlKata.Compilers;

namespace QueryBuilder.Benchmarks.Infrastructure;

public class TestSupport
{

public static SqlResult CompileFor(string engine, Query query, Func<Compiler, Compiler> configuration = null)
{
var compiler = CreateCompiler(engine);
if (configuration != null)
{
compiler = configuration(compiler);
}

return compiler.Compile(query);
}

public static SqlResult CompileFor(string engine, Query query, Action<Compiler> configuration)
{
return CompileFor(engine, query, compiler =>
{
configuration(compiler);
return compiler;
});
}

public static Compiler CreateCompiler(string engine)
{
return engine switch
{
EngineCodes.Firebird => new FirebirdCompiler(),
EngineCodes.MySql => new MySqlCompiler(),
EngineCodes.Oracle => new OracleCompiler
{
UseLegacyPagination = false
},
EngineCodes.PostgreSql => new PostgresCompiler(),
EngineCodes.Sqlite => new SqliteCompiler(),
EngineCodes.SqlServer => new SqlServerCompiler
{
UseLegacyPagination = false
},
EngineCodes.Generic => new TestCompiler(),
_ => throw new ArgumentException($"Unsupported engine type: {engine}", nameof(engine)),
};
}
}
8 changes: 8 additions & 0 deletions QueryBuilder.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// See https://aka.ms/new-console-template for more information

using BenchmarkDotNet.Running;
using QueryBuilder.Benchmarks;

SelectsBenchmarkTests.TestAll();

BenchmarkRunner.Run<SelectsBenchmark>();
19 changes: 19 additions & 0 deletions QueryBuilder.Benchmarks/QueryBuilder.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\QueryBuilder\QueryBuilder.csproj" />
</ItemGroup>

</Project>
82 changes: 82 additions & 0 deletions QueryBuilder.Benchmarks/SelectsBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using BenchmarkDotNet.Attributes;
using QueryBuilder.Benchmarks.Infrastructure;
using SqlKata;
using SqlKata.Compilers;

namespace QueryBuilder.Benchmarks;

[MemoryDiagnoser]
public class SelectsBenchmark
{
private Query selectSimple;
private Query selectGroupBy;
private Query selectWith;

public Compiler compiler;

[Params(
EngineCodes.SqlServer)]
public string EngineCode { get; set; }

[GlobalSetup]
public void Setup()
{
selectSimple = new Query("Products")
.Select("ProductID", "ProductName", "SupplierID", "CategoryID", "UnitPrice", "UnitsInStock", "UnitsOnOrder",
"ReorderLevel", "Discontinued")
.WhereIn("CategoryID", [1, 2, 3])
.Where("SupplierID", 5)
.Where("UnitPrice", ">=", 10)
.Where("UnitPrice", "<=", 100)
.Take(10)
.Skip(20)
.OrderBy("UnitPrice", "ProductName");


selectGroupBy = new Query("Products")
.Select("SupplierID", "CategoryID")
.SelectAvg("UnitPrice")
.SelectMin("UnitPrice")
.SelectMax("UnitPrice")
.Where("CategoryID", 123)
.GroupBy("SupplierID", "CategoryID")
.HavingRaw("MIN(UnitPrice) >= ?", 10)
.Take(10)
.Skip(20)
.OrderBy("SupplierID", "CategoryID");

var activePosts = new Query("Comments")
.Select("PostId")
.SelectRaw("count(1) as Count")
.GroupBy("PostId")
.HavingRaw("count(1) > 100");

selectWith = new Query("Posts")
.With("ActivePosts", activePosts)
.Join("ActivePosts", "ActivePosts.PostId", "Posts.Id")
.Select("Posts.*", "ActivePosts.Count");

compiler = TestSupport.CreateCompiler(EngineCode);
}

[Benchmark]
public SqlResult SelectSimple()
{
return compiler.Compile(selectSimple);
}

[Benchmark]
public SqlResult SelectGroupBy()
{
return compiler.Compile(selectGroupBy);
}

[Benchmark]
public SqlResult SelectWith()
{
return compiler.Compile(selectWith);
}

}
95 changes: 95 additions & 0 deletions QueryBuilder.Benchmarks/SelectsBenchmarkTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using SqlKata;
using SqlKata.Compilers;

namespace QueryBuilder.Benchmarks;

public static partial class SelectsBenchmarkTests
{
public static void TestAll()
{
TestSelectSimple();
TestSelectGroupBy();
TestSelectWith();
}

public static void TestSelectSimple()
{
var benchmark = CreateBenchmark();

var result = benchmark.SelectSimple();

// language=SQL
ValidateResult(
"""
SELECT [ProductID], [ProductName], [SupplierID], [CategoryID], [UnitPrice],
[UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]
FROM [Products]
WHERE [CategoryID] IN (1, 2, 3)
AND [SupplierID] = 5
AND [UnitPrice] >= 10
AND [UnitPrice] <= 100
ORDER BY [UnitPrice], [ProductName]
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
""", result);
}

public static void TestSelectGroupBy()
{
var benchmark = CreateBenchmark();

var result = benchmark.SelectGroupBy();

// language=SQL
ValidateResult(
"""
SELECT [SupplierID], [CategoryID],
AVG([UnitPrice]), MIN([UnitPrice]), MAX([UnitPrice])
FROM [Products]
WHERE [CategoryID] = 123
GROUP BY [SupplierID], [CategoryID]
HAVING MIN(UnitPrice) >= 10
ORDER BY [SupplierID], [CategoryID]
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
""", result);
}

public static void TestSelectWith()
{
var benchmark = CreateBenchmark();

var result = benchmark.SelectWith();

// language=SQL
ValidateResult(
"""
WITH [ActivePosts] AS (SELECT [PostId], count(1) as Count FROM [Comments] GROUP BY [PostId] HAVING count(1) > 100)
SELECT [Posts].*, [ActivePosts].[Count]
FROM [Posts]
INNER JOIN [ActivePosts] ON [ActivePosts].[PostId] = [Posts].[Id]
""", result);
}

private static SelectsBenchmark CreateBenchmark()
{
var benchmark = new SelectsBenchmark
{
EngineCode = EngineCodes.SqlServer
};
benchmark.Setup();
return benchmark;
}

private static void ValidateResult(string expected, SqlResult result)
{
var actual = result.ToString();
if (WhiteSpaces().Replace(actual, " ") != WhiteSpaces().Replace(expected, " "))
{
throw new ValidationException($"Invalid result: {actual}");
}
}

[GeneratedRegex(@"\s+")]
private static partial Regex WhiteSpaces();
}
Loading