diff --git a/QueryBuilder.Benchmarks/Infrastructure/TestCompiler.cs b/QueryBuilder.Benchmarks/Infrastructure/TestCompiler.cs new file mode 100644 index 00000000..171524ac --- /dev/null +++ b/QueryBuilder.Benchmarks/Infrastructure/TestCompiler.cs @@ -0,0 +1,9 @@ +using SqlKata.Compilers; + +namespace QueryBuilder.Benchmarks.Infrastructure; + +public class TestCompiler + : Compiler +{ + public override string EngineCode { get; } = "generic"; +} diff --git a/QueryBuilder.Benchmarks/Infrastructure/TestSupport.cs b/QueryBuilder.Benchmarks/Infrastructure/TestSupport.cs new file mode 100644 index 00000000..2e953a51 --- /dev/null +++ b/QueryBuilder.Benchmarks/Infrastructure/TestSupport.cs @@ -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 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 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)), + }; + } +} diff --git a/QueryBuilder.Benchmarks/Program.cs b/QueryBuilder.Benchmarks/Program.cs new file mode 100644 index 00000000..68481a35 --- /dev/null +++ b/QueryBuilder.Benchmarks/Program.cs @@ -0,0 +1,8 @@ +// See https://aka.ms/new-console-template for more information + +using BenchmarkDotNet.Running; +using QueryBuilder.Benchmarks; + +SelectsBenchmarkTests.TestAll(); + +BenchmarkRunner.Run(); diff --git a/QueryBuilder.Benchmarks/QueryBuilder.Benchmarks.csproj b/QueryBuilder.Benchmarks/QueryBuilder.Benchmarks.csproj new file mode 100644 index 00000000..2960e8f2 --- /dev/null +++ b/QueryBuilder.Benchmarks/QueryBuilder.Benchmarks.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + false + + + + + + + + + + + diff --git a/QueryBuilder.Benchmarks/SelectsBenchmark.cs b/QueryBuilder.Benchmarks/SelectsBenchmark.cs new file mode 100644 index 00000000..e81e7bef --- /dev/null +++ b/QueryBuilder.Benchmarks/SelectsBenchmark.cs @@ -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); + } + +} diff --git a/QueryBuilder.Benchmarks/SelectsBenchmarkTests.cs b/QueryBuilder.Benchmarks/SelectsBenchmarkTests.cs new file mode 100644 index 00000000..36aafac0 --- /dev/null +++ b/QueryBuilder.Benchmarks/SelectsBenchmarkTests.cs @@ -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(); +} diff --git a/QueryBuilder.Tests/AggregateTests.cs b/QueryBuilder.Tests/AggregateTests.cs index 68a69842..d299b96f 100644 --- a/QueryBuilder.Tests/AggregateTests.cs +++ b/QueryBuilder.Tests/AggregateTests.cs @@ -1,92 +1,175 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests { public class AggregateTests : TestSupport { - [Fact] - public void Count() + [Theory] + [InlineData(EngineCodes.Firebird, "SELECT COUNT(*) AS \"COUNT\" FROM \"A\"")] + [InlineData(EngineCodes.MySql, "SELECT COUNT(*) AS `count` FROM `A`")] + [InlineData(EngineCodes.Oracle, "SELECT COUNT(*) \"count\" FROM \"A\"")] + [InlineData(EngineCodes.PostgreSql, "SELECT COUNT(*) AS \"count\" FROM \"A\"")] + [InlineData(EngineCodes.Sqlite, "SELECT COUNT(*) AS \"count\" FROM \"A\"")] + [InlineData(EngineCodes.SqlServer, "SELECT COUNT(*) AS [count] FROM [A]")] + public void Count(string engine, string query) { - var query = new Query("A").AsCount(); + var q = new Query("A").AsCount(); - var c = Compile(query); + var result = CompileFor(engine, q); - Assert.Equal("SELECT COUNT(*) AS [count] FROM [A]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT COUNT(*) AS `count` FROM `A`", c[EngineCodes.MySql]); - Assert.Equal("SELECT COUNT(*) AS \"count\" FROM \"A\"", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT COUNT(*) AS \"COUNT\" FROM \"A\"", c[EngineCodes.Firebird]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void CountMultipleColumns() + [Theory] + [InlineData(EngineCodes.Firebird, + "SELECT COUNT(*) AS \"COUNT\" FROM (SELECT 1 FROM \"A\" WHERE \"COLUMNA\" IS NOT NULL AND \"COLUMNB\" IS NOT NULL) AS \"COUNTQUERY\"")] + [InlineData(EngineCodes.MySql, + "SELECT COUNT(*) AS `count` FROM (SELECT 1 FROM `A` WHERE `ColumnA` IS NOT NULL AND `ColumnB` IS NOT NULL) AS `countQuery`")] + [InlineData(EngineCodes.Oracle, + "SELECT COUNT(*) \"count\" FROM (SELECT 1 FROM \"A\" WHERE \"ColumnA\" IS NOT NULL AND \"ColumnB\" IS NOT NULL) \"countQuery\"")] + [InlineData(EngineCodes.PostgreSql, + "SELECT COUNT(*) AS \"count\" FROM (SELECT 1 FROM \"A\" WHERE \"ColumnA\" IS NOT NULL AND \"ColumnB\" IS NOT NULL) AS \"countQuery\"")] + [InlineData(EngineCodes.Sqlite, + "SELECT COUNT(*) AS \"count\" FROM (SELECT 1 FROM \"A\" WHERE \"ColumnA\" IS NOT NULL AND \"ColumnB\" IS NOT NULL) AS \"countQuery\"")] + [InlineData(EngineCodes.SqlServer, + "SELECT COUNT(*) AS [count] FROM (SELECT 1 FROM [A] WHERE [ColumnA] IS NOT NULL AND [ColumnB] IS NOT NULL) AS [countQuery]")] + public void CountMultipleColumns(string engine, string query) { - var query = new Query("A").AsCount(new[] { "ColumnA", "ColumnB" }); + var q = new Query("A").AsCount(["ColumnA", "ColumnB"]); - var c = Compile(query); + var result = CompileFor(engine, q); - Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT 1 FROM [A] WHERE [ColumnA] IS NOT NULL AND [ColumnB] IS NOT NULL) AS [countQuery]", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void DistinctCount() + [Theory] + [InlineData(EngineCodes.Firebird, + "SELECT COUNT(*) AS \"COUNT\" FROM (SELECT DISTINCT * FROM \"A\") AS \"COUNTQUERY\"")] + [InlineData(EngineCodes.MySql, "SELECT COUNT(*) AS `count` FROM (SELECT DISTINCT * FROM `A`) AS `countQuery`")] + [InlineData(EngineCodes.Oracle, "SELECT COUNT(*) \"count\" FROM (SELECT DISTINCT * FROM \"A\") \"countQuery\"")] + [InlineData(EngineCodes.PostgreSql, + "SELECT COUNT(*) AS \"count\" FROM (SELECT DISTINCT * FROM \"A\") AS \"countQuery\"")] + [InlineData(EngineCodes.Sqlite, + "SELECT COUNT(*) AS \"count\" FROM (SELECT DISTINCT * FROM \"A\") AS \"countQuery\"")] + [InlineData(EngineCodes.SqlServer, + "SELECT COUNT(*) AS [count] FROM (SELECT DISTINCT * FROM [A]) AS [countQuery]")] + public void DistinctCount(string engine, string query) { - var query = new Query("A").Distinct().AsCount(); + var q = new Query("A").Distinct().AsCount(); - var c = Compile(query); + var result = CompileFor(engine, q); - Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT DISTINCT * FROM [A]) AS [countQuery]", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void DistinctCountMultipleColumns() + [Theory] + [InlineData(EngineCodes.Firebird, + "SELECT COUNT(*) AS \"COUNT\" FROM (SELECT DISTINCT \"COLUMNA\", \"COLUMNB\" FROM \"A\") AS \"COUNTQUERY\"")] + [InlineData(EngineCodes.MySql, + "SELECT COUNT(*) AS `count` FROM (SELECT DISTINCT `ColumnA`, `ColumnB` FROM `A`) AS `countQuery`")] + [InlineData(EngineCodes.Oracle, + "SELECT COUNT(*) \"count\" FROM (SELECT DISTINCT \"ColumnA\", \"ColumnB\" FROM \"A\") \"countQuery\"")] + [InlineData(EngineCodes.PostgreSql, + "SELECT COUNT(*) AS \"count\" FROM (SELECT DISTINCT \"ColumnA\", \"ColumnB\" FROM \"A\") AS \"countQuery\"")] + [InlineData(EngineCodes.Sqlite, + "SELECT COUNT(*) AS \"count\" FROM (SELECT DISTINCT \"ColumnA\", \"ColumnB\" FROM \"A\") AS \"countQuery\"")] + [InlineData(EngineCodes.SqlServer, + "SELECT COUNT(*) AS [count] FROM (SELECT DISTINCT [ColumnA], [ColumnB] FROM [A]) AS [countQuery]")] + public void DistinctCountMultipleColumns(string engine, string query) { - var query = new Query("A").Distinct().AsCount(new[] { "ColumnA", "ColumnB" }); + var q = new Query("A").Distinct().AsCount(new[] { "ColumnA", "ColumnB" }); - var c = Compile(query); + var result = CompileFor(engine, q); - Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT DISTINCT [ColumnA], [ColumnB] FROM [A]) AS [countQuery]", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void Average() + [Theory] + [InlineData(EngineCodes.Firebird, + "SELECT AVG(\"TTL\") AS \"AVG\" FROM \"A\"")] + [InlineData(EngineCodes.MySql, + "SELECT AVG(`TTL`) AS `avg` FROM `A`")] + [InlineData(EngineCodes.Oracle, + "SELECT AVG(\"TTL\") \"avg\" FROM \"A\"")] + [InlineData(EngineCodes.PostgreSql, + "SELECT AVG(\"TTL\") AS \"avg\" FROM \"A\"")] + [InlineData(EngineCodes.Sqlite, + "SELECT AVG(\"TTL\") AS \"avg\" FROM \"A\"")] + [InlineData(EngineCodes.SqlServer, + "SELECT AVG([TTL]) AS [avg] FROM [A]")] + public void Average(string engine, string query) { - var query = new Query("A").AsAverage("TTL"); + var q = new Query("A").AsAverage("TTL"); - var c = Compile(query); + var result = CompileFor(engine, q); - Assert.Equal("SELECT AVG([TTL]) AS [avg] FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void Sum() + [Theory] + [InlineData(EngineCodes.Firebird, + "SELECT SUM(\"PACKETSDROPPED\") AS \"SUM\" FROM \"A\"")] + [InlineData(EngineCodes.MySql, + "SELECT SUM(`PacketsDropped`) AS `sum` FROM `A`")] + [InlineData(EngineCodes.Oracle, + "SELECT SUM(\"PacketsDropped\") \"sum\" FROM \"A\"")] + [InlineData(EngineCodes.PostgreSql, + "SELECT SUM(\"PacketsDropped\") AS \"sum\" FROM \"A\"")] + [InlineData(EngineCodes.Sqlite, + "SELECT SUM(\"PacketsDropped\") AS \"sum\" FROM \"A\"")] + [InlineData(EngineCodes.SqlServer, + "SELECT SUM([PacketsDropped]) AS [sum] FROM [A]")] + public void Sum(string engine, string query) { - var query = new Query("A").AsSum("PacketsDropped"); + var q = new Query("A").AsSum("PacketsDropped"); - var c = Compile(query); + var result = CompileFor(engine, q); - Assert.Equal("SELECT SUM([PacketsDropped]) AS [sum] FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void Max() + [Theory] + [InlineData(EngineCodes.Firebird, + "SELECT MAX(\"LATENCYMS\") AS \"MAX\" FROM \"A\"")] + [InlineData(EngineCodes.MySql, + "SELECT MAX(`LatencyMs`) AS `max` FROM `A`")] + [InlineData(EngineCodes.Oracle, + "SELECT MAX(\"LatencyMs\") \"max\" FROM \"A\"")] + [InlineData(EngineCodes.PostgreSql, + "SELECT MAX(\"LatencyMs\") AS \"max\" FROM \"A\"")] + [InlineData(EngineCodes.Sqlite, + "SELECT MAX(\"LatencyMs\") AS \"max\" FROM \"A\"")] + [InlineData(EngineCodes.SqlServer, + "SELECT MAX([LatencyMs]) AS [max] FROM [A]")] + public void Max(string engine, string query) { - var query = new Query("A").AsMax("LatencyMs"); + var q = new Query("A").AsMax("LatencyMs"); - var c = Compile(query); + var result = CompileFor(engine, q); - Assert.Equal("SELECT MAX([LatencyMs]) AS [max] FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void Min() + [Theory] + [InlineData(EngineCodes.Firebird, + "SELECT MIN(\"LATENCYMS\") AS \"MIN\" FROM \"A\"")] + [InlineData(EngineCodes.MySql, + "SELECT MIN(`LatencyMs`) AS `min` FROM `A`")] + [InlineData(EngineCodes.Oracle, + "SELECT MIN(\"LatencyMs\") \"min\" FROM \"A\"")] + [InlineData(EngineCodes.PostgreSql, + "SELECT MIN(\"LatencyMs\") AS \"min\" FROM \"A\"")] + [InlineData(EngineCodes.Sqlite, + "SELECT MIN(\"LatencyMs\") AS \"min\" FROM \"A\"")] + [InlineData(EngineCodes.SqlServer, + "SELECT MIN([LatencyMs]) AS [min] FROM [A]")] + public void Min(string engine, string query) { - var query = new Query("A").AsMin("LatencyMs"); + var q = new Query("A").AsMin("LatencyMs"); - var c = Compile(query); + var result = CompileFor(engine, q); - Assert.Equal("SELECT MIN([LatencyMs]) AS [min] FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } } } diff --git a/QueryBuilder.Tests/BindingsTests.cs b/QueryBuilder.Tests/BindingsTests.cs new file mode 100644 index 00000000..7a684920 --- /dev/null +++ b/QueryBuilder.Tests/BindingsTests.cs @@ -0,0 +1,199 @@ +using System.Text.RegularExpressions; +using SqlKata.Tests.Infrastructure; + +namespace SqlKata.Tests; + +public class BindingsTests : TestSupport +{ + private static readonly Regex _parameterExtractor = new(@"(@\w+\b)", RegexOptions.Compiled); + + [Fact] + public void BindingsAreAppliedFromWhere() + { + var q = new Query("Table") + .Where("Id", 1) + .Where("Name", "John"); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 1, + "John"); + } + + [Fact] + public void BindingsAreAppliedFromTake() + { + var q = new Query("Table") + .Take(10); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 10); + } + + [Fact] + public void BindingsAreAppliedFromSkip() + { + var q = new Query("Table") + .Skip(10); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 10L); + } + + [Fact] + public void BindingsAreAppliedFromTakeAndSkip() + { + var q = new Query("Table") + .Take(10) + .Skip(20); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 10, + 20L); + } + + [Fact] + public void BindingsAreAppliedFromOrderByRaw() + { + var q = new Query("Table") + .OrderByRaw("?, ?", 1, "John"); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 1, + "John"); + } + + [Fact] + public void BindingsAreAppliedFromHaving() + { + var q = new Query("Table") + .Having("Id", 1) + .Having("Name", "John"); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 1, + "John"); + } + + [Fact] + public void BindingsAreAppliedFromWith() + { + var q = new Query("Table") + .With("WithAlias", ["Id", "Name"], [[1, "First"], [2, "Second"]]); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 1, + "First", + 2, + "Second"); + } + + [Fact] + public void BindingsAreAppliedFromCombineRaw() + { + var q = new Query("Table") + .CombineRaw("UNION SELECT * FROM Table2 Id = ? AND Name = ?", 1, "John"); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 1, + "John"); + } + + [Fact] + public void BindingsAreAppliedFromHavingBetween() + { + var q = new Query("Table") + .HavingBetween("Id", 10, 20); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + 10, + 20); + } + + [Fact] + public void BindingsAreAppliedFromHavingContains() + { + // Contains is object but it works only with string. + var q = new Query("Table") + .HavingContains("Name", "John"); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + "%john%"); + } + + [Fact] + public void BindingsAreAppliedFromHavingEnds() + { + // Contains is object but it works only with string. + var q = new Query("Table") + .HavingEnds("Name", "John"); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + "%john"); + } + + [Fact] + public void BindingsAreAppliedFromHavingStarts() + { + var q = new Query("Table") + .HavingStarts("Name", "John"); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + "john%"); + } + + [Fact] + public void BindingsAreAppliedFromHavingLike() + { + var q = new Query("Table") + .HavingLike("Name", "John%Wick"); + + var result = CompileForGeneric(q); + + AssertBindingsAndNamedBindings(result, + "john%wick"); + } + + private static void AssertBindingsAndNamedBindings(SqlResult result, params object[] parameters) + { + Assert.Equal(parameters.Length, result.Bindings.Count); + foreach (var values in parameters.Zip(result.Bindings)) + { + Assert.Equal(values.First, values.Second); + } + + Assert.Equal(parameters.Length, result.NamedBindings.Count); + var parameterNames = _parameterExtractor + .Matches(result.Sql) + .Select(e => e.Value) + .ToArray(); + Assert.Equal(parameters.Length, parameterNames.Length); + foreach (var parameter in parameterNames.Zip(parameters)) + { + Assert.Equal(parameter.Second, result.NamedBindings[parameter.First]); + } + } +} diff --git a/QueryBuilder.Tests/DefineTest.cs b/QueryBuilder.Tests/DefineTest.cs index 0b5ff292..2dcead75 100644 --- a/QueryBuilder.Tests/DefineTest.cs +++ b/QueryBuilder.Tests/DefineTest.cs @@ -1,7 +1,5 @@ -using static SqlKata.Expressions; -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; +using static SqlKata.Expressions; namespace SqlKata.Tests { @@ -10,24 +8,25 @@ namespace SqlKata.Tests /// public class DefineTest : TestSupport { - - [Fact] - public void Test_Define_Where() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Products] WHERE [ProductName] = 'Anto'")] + public void Test_Define_Where(string engine, string sqlText) { var query = new Query("Products") - .Define("@name", "Anto") - .Where("ProductName", Variable("@name")); + .Define("@name", "Anto") + .Where("ProductName", Variable("@name")); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [Products] WHERE [ProductName] = 'Anto'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Test_Define_SubQuery() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "SELECT * FROM [Products] WHERE [unitprice] > (SELECT AVG([unitprice]) AS [avg] FROM [Products] WHERE [UnitsInStock] > 10) AND [UnitsOnOrder] > 5")] + public void Test_Define_SubQuery(string engine, string sqlText) { - var subquery = new Query("Products") .AsAverage("unitprice") .Define("@UnitsInSt", 10) @@ -37,232 +36,230 @@ public void Test_Define_SubQuery() .Where("unitprice", ">", subquery) .Where("UnitsOnOrder", ">", 5); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [Products] WHERE [unitprice] > (SELECT AVG([unitprice]) AS [avg] FROM [Products] WHERE [UnitsInStock] > 10) AND [UnitsOnOrder] > 5", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Test_Define_WhereEnds() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ProductId], [ProductName] FROM [Products] WHERE LOWER([ProductName]) like '%coffee'", + false)] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ProductId], [ProductName] FROM [Products] WHERE [ProductName] like '%Coffee'", + true)] + public void Test_Define_WhereEnds(string engine, string sqlText, bool caseSensitive) { - - var query1 = new Query("Products") - .Select("ProductId") - .Define("@product", "Coffee") - .WhereEnds("ProductName", Variable("@product")); - - - var query2 = new Query("Products") + var query = new Query("Products") .Select("ProductId", "ProductName") .Define("@product", "Coffee") - .WhereEnds("ProductName", Variable("@product"), true); + .WhereEnds("ProductName", Variable("@product"), caseSensitive); - var c1 = Compile(query1); - var c2 = Compile(query2); - - Assert.Equal("SELECT [ProductId] FROM [Products] WHERE LOWER([ProductName]) like '%coffee'", c1[EngineCodes.SqlServer]); - - Assert.Equal("SELECT [ProductId], [ProductName] FROM [Products] WHERE [ProductName] like '%Coffee'", c2[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void Test_Define_WhereStarts() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ProductId], [QuantityPerUnit] FROM [Products] WHERE LOWER([QuantityPerUnit]) like '12%'", + false)] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ProductId], [QuantityPerUnit] FROM [Products] WHERE [QuantityPerUnit] like '12%'", + true)] + public void Test_Define_WhereStarts(string engine, string sqlText, bool caseSensitive) { + var query = new Query("Products") + .Select("ProductId", "QuantityPerUnit") + .Define("@perUnit", "12") + .WhereStarts("QuantityPerUnit", Variable("@perUnit"), caseSensitive); + var result = CompileFor(engine, query); - var query1 = new Query("Products") - .Select("ProductId", "QuantityPerUnit") - .Define("@perUnit", "12") - .WhereStarts("QuantityPerUnit", Variable("@perUnit")); - - - var query2 = new Query("Products") - .Select("ProductId", "QuantityPerUnit") - .Define("@perUnit", "12") - .WhereStarts("QuantityPerUnit", Variable("@perUnit"), true); - - var c1 = Compile(query1); - var c2 = Compile(query2); - - Assert.Equal("SELECT [ProductId], [QuantityPerUnit] FROM [Products] WHERE LOWER([QuantityPerUnit]) like '12%'", c1[EngineCodes.SqlServer]); - Assert.Equal("SELECT [ProductId], [QuantityPerUnit] FROM [Products] WHERE [QuantityPerUnit] like '12%'", c2[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void Test_Define_WhereContains() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ProductId], [QuantityPerUnit] FROM [Products] WHERE LOWER([QuantityPerUnit]) like '%500%'", + false)] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ProductId], [QuantityPerUnit] FROM [Products] WHERE [QuantityPerUnit] like '%500%'", + true)] + public void Test_Define_WhereContains(string engine, string sqlText, bool caseSensitive) { - - var query1 = new Query("Products") - .Define("@perUnit", "500") - .Select("ProductId", "QuantityPerUnit") - .WhereContains("QuantityPerUnit", Variable("@perUnit")); - - - var query2 = new Query("Products") + var query = new Query("Products") .Define("@perUnit", "500") .Select("ProductId", "QuantityPerUnit") - .WhereContains("QuantityPerUnit", Variable("@perUnit"), true); - - var c1 = Compile(query1); - var c2 = Compile(query2); + .WhereContains("QuantityPerUnit", Variable("@perUnit"), caseSensitive); - Assert.Equal("SELECT [ProductId], [QuantityPerUnit] FROM [Products] WHERE LOWER([QuantityPerUnit]) like '%500%'", c1[EngineCodes.SqlServer]); - Assert.Equal("SELECT [ProductId], [QuantityPerUnit] FROM [Products] WHERE [QuantityPerUnit] like '%500%'", c2[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void Test_Define_WhereLike() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ProductId], [ProductName], [SupplierID] FROM [Products] WHERE LOWER([SupplierID]) like '20'", + false)] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ProductId], [ProductName], [SupplierID] FROM [Products] WHERE [SupplierID] like '20'", + true)] + public void Test_Define_WhereLike(string engine, string sqlText, bool caseSensitive) { - var query1 = new Query("Products") - .Select("ProductId", "ProductName", "SupplierID") - .Define("@id", "20") - .WhereLike("SupplierID", Variable("@id")); - - - var query2 = new Query("Products") + var query = new Query("Products") .Select("ProductId", "ProductName", "SupplierID") .Define("@id", "20") - .WhereLike("SupplierID", Variable("@id"), true); + .WhereLike("SupplierID", Variable("@id"), caseSensitive); - var c1 = Compile(query1); - var c2 = Compile(query2); + var result = CompileFor(engine, query); - Assert.Equal("SELECT [ProductId], [ProductName], [SupplierID] FROM [Products] WHERE LOWER([SupplierID]) like '20'", c1[EngineCodes.SqlServer]); - - Assert.Equal("SELECT [ProductId], [ProductName], [SupplierID] FROM [Products] WHERE [SupplierID] like '20'", c2[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void Test_Define_WhereInSubquery() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "SELECT [ShipperID], [CompanyName] FROM [Shippers] WHERE [ShipperID] IN (SELECT [ShipVia] FROM [Orders] WHERE [ShipVia] = 3)")] + public void Test_Define_WhereInSubquery(string engine, string sqlText) { - var subquery = new Query("Orders") - .Define("@shipId", 3) - .Select("ShipVia").Where("ShipVia", Variable("@shipId")); + .Define("@shipId", 3) + .Select("ShipVia").Where("ShipVia", Variable("@shipId")); - var query1 = new Query("Shippers") - .Select("ShipperID", "CompanyName") - .WhereIn("ShipperID", subquery); + var query = new Query("Shippers") + .Select("ShipperID", "CompanyName") + .WhereIn("ShipperID", subquery); - var c1 = Compile(query1); + var result = CompileFor(engine, query); - Assert.Equal("SELECT [ShipperID], [CompanyName] FROM [Shippers] WHERE [ShipperID] IN (SELECT [ShipVia] FROM [Orders] WHERE [ShipVia] = 3)", c1[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Test_Define_Having() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table] HAVING [Id] = 1")] + public void Test_Define_Having(string engine, string sqlText) { - var c = Compile(new Query("Table") + var query = new Query("Table") .Define("@foo", 1) - .Having("Id", "=", Variable("@foo"))); + .Having("Id", "=", Variable("@foo")); + + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM [Table] HAVING [Id] = 1", c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - /* - [Fact] - public void Test_Define_HavingRaw() + [Theory(Skip = "Not implemented")] + [InlineData(EngineCodes.SqlServer, + "SELECT [Employees].[LastName], COUNT(Orders.OrderID) AS NumberOfOrders FROM [Orders] \nINNER JOIN [Employees] ON [Employees].[EmployeeID] = [Orders].[EmployeeID] GROUP BY [LastName] HAVING COUNT(Orders.OrderID) > 80")] + public void Test_Define_HavingRaw(string engine, string sqlText) { - var query1 = new Query("Orders") - .Define("@count", 80) - .Select("Employees.LastName") - .SelectRaw("COUNT(Orders.OrderID) AS NumberOfOrders") - .Join("Employees", "Employees.EmployeeID", "Orders.EmployeeID") - .GroupBy("LastName") - .HavingRaw("COUNT(Orders.OrderID) > @count"); - - var c = Compile(query1); + var query = new Query("Orders") + .Define("@count", 80) + .Select("Employees.LastName") + .SelectRaw("COUNT(Orders.OrderID) AS NumberOfOrders") + .Join("Employees", "Employees.EmployeeID", "Orders.EmployeeID") + .GroupBy("LastName") + .HavingRaw("COUNT(Orders.OrderID) > @count"); - Assert.Equal("SELECT [Employees].[LastName], COUNT(Orders.OrderID) AS NumberOfOrders FROM [Orders] \nINNER JOIN [Employees] ON [Employees].[EmployeeID] = [Orders].[EmployeeID] GROUP BY [LastName] HAVING COUNT(Orders.OrderID) > 80", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - */ - [Fact] - public void Test_Define_HavingStarts() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT COUNT(CustomerID), [Country] FROM [Customers] GROUP BY [Country] HAVING LOWER([Country]) like 'u%'")] + public void Test_Define_HavingStarts(string engine, string sqlText) { - var query = new Query("Customers") - .Define("@label", "U") - .SelectRaw("COUNT(CustomerID)") - .Select("Country") - .GroupBy("Country") - .HavingStarts("Country", Variable("@label")); + .Define("@label", "U") + .SelectRaw("COUNT(CustomerID)") + .Select("Country") + .GroupBy("Country") + .HavingStarts("Country", Variable("@label")); - var c = Compile(query); - - Assert.Equal("SELECT COUNT(CustomerID), [Country] FROM [Customers] GROUP BY [Country] HAVING LOWER([Country]) like 'u%'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal( + sqlText, + result.ToString()); } - - - [Fact] - public void Test_Define_Having_Ends() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT COUNT(CustomerID), [Country] FROM [Customers] GROUP BY [Country] HAVING LOWER([Country]) like '%d'")] + public void Test_Define_Having_Ends(string engine, string sqlText) { var query = new Query("Customers") - .Define("@label", "d") - .SelectRaw("COUNT(CustomerID)") - .Select("Country") - .GroupBy("Country") - .HavingEnds("Country", Variable("@label")); + .Define("@label", "d") + .SelectRaw("COUNT(CustomerID)") + .Select("Country") + .GroupBy("Country") + .HavingEnds("Country", Variable("@label")); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal("SELECT COUNT(CustomerID), [Country] FROM [Customers] GROUP BY [Country] HAVING LOWER([Country]) like '%d'", c[EngineCodes.SqlServer]); + Assert.Equal( + sqlText, + result.ToString()); } - - [Fact] - public void Test_Define_Having_Contains() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT COUNT(CustomerID), [Country] FROM [Customers] GROUP BY [Country] HAVING LOWER([Country]) like '%d%'")] + public void Test_Define_Having_Contains(string engine, string sqlText) { - - var query = new Query("Customers") - .Define("@label", "d") - .SelectRaw("COUNT(CustomerID)") - .Select("Country") - .GroupBy("Country") - .HavingContains("Country", Variable("@label")); + .Define("@label", "d") + .SelectRaw("COUNT(CustomerID)") + .Select("Country") + .GroupBy("Country") + .HavingContains("Country", Variable("@label")); - var c = Compile(query); - - Assert.Equal("SELECT COUNT(CustomerID), [Country] FROM [Customers] GROUP BY [Country] HAVING LOWER([Country]) like '%d%'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void Test_Define_NestedCondition() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT COUNT(*) AS [count] FROM [Orders] WHERE ([ShipRegion] != NULL)")] + public void Test_Define_NestedCondition(string engine, string sqlText) { var query = new Query("Orders") - .Define("@shipReg", null) - .Define("@one", 1) - .Where(q => - q.Where("ShipRegion", "!=", Variable("@shipReg")) - // .WhereRaw("1 = @one") + .Define("@shipReg", null) + .Define("@one", 1) + .Where(q => + q.Where("ShipRegion", "!=", Variable("@shipReg")) + // .WhereRaw("1 = @one") ).AsCount(); - var c = Compile(query); - - Assert.Equal("SELECT COUNT(*) AS [count] FROM [Orders] WHERE ([ShipRegion] != NULL)", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Test_Define_WhereDate() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Orders] WHERE CAST([RequiredDate] AS DATE) = '1996-08-01'")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"Orders\" WHERE \"RequiredDate\"::date = '1996-08-01'")] + [InlineData(EngineCodes.Sqlite, + "SELECT * FROM \"Orders\" WHERE strftime('%Y-%m-%d', \"RequiredDate\") = cast('1996-08-01' as text)")] + [InlineData(EngineCodes.Firebird, + "SELECT * FROM \"ORDERS\" WHERE CAST(\"REQUIREDDATE\" as DATE) = '1996-08-01'")] + public void Test_Define_WhereDate(string engine, string sqlText) { var dateObj = new System.DateTime(year: 1996, month: 8, day: 1); @@ -270,158 +267,167 @@ public void Test_Define_WhereDate() .Define("@d", dateObj) .WhereDate("RequiredDate", Variable("@d")); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); + } - var query2 = new Query("Orders") + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Orders] WHERE DATEPART(YEAR, [RequiredDate]) = 1996")] + public void Test_Define_WhereDatePart(string engine, string sqlText) + { + var query = new Query("Orders") .Define("@d", 1996) .WhereDatePart("year", "RequiredDate", "=", Variable("@d")); - var query3 = new Query("Orders") - .Define("@d", "00:00:00") - .WhereTime("RequiredDate", "!=", Variable("@d")); - - var c = Compile(query); - var c2 = Compile(query2); - var c3 = Compile(query3); - - Assert.Equal("SELECT * FROM [Orders] WHERE CAST([RequiredDate] AS DATE) = '1996-08-01'", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM \"Orders\" WHERE \"RequiredDate\"::date = '1996-08-01'", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT * FROM \"Orders\" WHERE strftime('%Y-%m-%d', \"RequiredDate\") = cast('1996-08-01' as text)", c[EngineCodes.Sqlite]); - Assert.Equal("SELECT * FROM \"ORDERS\" WHERE CAST(\"REQUIREDDATE\" as DATE) = '1996-08-01'", c[EngineCodes.Firebird]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); + } + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Orders] WHERE CAST([RequiredDate] AS TIME) != '00:00:00'")] + public void Test_Define_WhereTime(string engine, string sqlText) + { + var query = new Query("Orders") + .Define("@d", "00:00:00") + .WhereTime("RequiredDate", "!=", Variable("@d")); - Assert.Equal("SELECT * FROM [Orders] WHERE DATEPART(YEAR, [RequiredDate]) = 1996", c2[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM [Orders] WHERE CAST([RequiredDate] AS TIME) != '00:00:00'", c3[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void Test_Define_WhereExists() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Customers] WHERE EXISTS (SELECT 1 FROM [Orders] WHERE [ShipPostalCode] = '8200')")] + public void Test_Define_WhereExists(string engine, string sqlText) { var query = new Query("Customers") .WhereExists(q => q.From("Orders") - .Define("@postal", "8200") - .Where("ShipPostalCode", Variable("@postal")) - ); - - var c = Compile(query); - Assert.Equal("SELECT * FROM [Customers] WHERE EXISTS (SELECT 1 FROM [Orders] WHERE [ShipPostalCode] = '8200')", c[EngineCodes.SqlServer]); - } + .Define("@postal", "8200") + .Where("ShipPostalCode", Variable("@postal")) + ); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); + } - [Fact] - public void Test_Define_With() + [Theory] + [InlineData(EngineCodes.SqlServer, + "WITH [prodCTE] AS (SELECT [Categories].[CategoryName], [Products].[UnitPrice] FROM [Products] \nINNER JOIN [Categories] ON [Categories].[CategoryID] = [Products].[CategoryID] WHERE [Products].[UnitPrice] > 10)\nSELECT * FROM [prodCTE]")] + public void Test_Define_With(string engine, string sqlText) { - var query = new Query("Products") - .Define("@unit", 10) - .Join("Categories", "Categories.CategoryID", "Products.CategoryID") - .Select("Categories.CategoryName", "Products.UnitPrice") - .Where("Products.UnitPrice", ">", Variable("@unit")); + .Define("@unit", 10) + .Join("Categories", "Categories.CategoryID", "Products.CategoryID") + .Select("Categories.CategoryName", "Products.UnitPrice") + .Where("Products.UnitPrice", ">", Variable("@unit")); var queryCTe = new Query("prodCTE") - .With("prodCTE", query); - - var c = Compile(queryCTe); + .With("prodCTE", query); + var result = CompileFor(engine, queryCTe); - Assert.Equal("WITH [prodCTE] AS (SELECT [Categories].[CategoryName], [Products].[UnitPrice] FROM [Products] \nINNER JOIN [Categories] ON [Categories].[CategoryID] = [Products].[CategoryID] WHERE [Products].[UnitPrice] > 10)\nSELECT * FROM [prodCTE]", c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - - - /* - [Fact] - public void Test_Define_WithRaw() + [Theory(Skip = "not implemented")] + [InlineData(EngineCodes.SqlServer, + "WITH [prodCTE] AS (SELECT c.CategoryName, p.UnitPrice FROM Products p INNER JOIN Categories c ON c.CategoryID = p.CategoryID WHERE p.UnitPrice > 10 AND 2 = 2)\nSELECT [CategoryName], [UnitPrice] FROM [prodCTE]")] + public void Test_Define_WithRaw(string engine, string sqlText) { - //WithRaw var query = new Query("prodCTE") .Define("@unit", 10) .Define("@foo", 2) .Select("CategoryName", "UnitPrice") - .WithRaw("prodCTE", "SELECT c.CategoryName, p.UnitPrice FROM Products p INNER JOIN Categories c ON c.CategoryID = p.CategoryID WHERE p.UnitPrice > @unit AND 2 = @foo"); - - var c = Compile(query); + .WithRaw("prodCTE", + "SELECT c.CategoryName, p.UnitPrice FROM Products p INNER JOIN Categories c ON c.CategoryID = p.CategoryID WHERE p.UnitPrice > @unit AND 2 = @foo"); - Assert.Equal("WITH [prodCTE] AS (SELECT c.CategoryName, p.UnitPrice FROM Products p INNER JOIN Categories c ON c.CategoryID = p.CategoryID WHERE p.UnitPrice > 10 AND 2 = 2)\nSELECT [CategoryName], [UnitPrice] FROM [prodCTE]", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - */ - // - [Fact] - public void Test_Define_Union() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT [City] FROM [Customers] WHERE NOT (LOWER([City]) like 'z') UNION SELECT [City] FROM [Suppliers] WHERE [City] = 'Beirut'")] + public void Test_Define_Union(string engine, string sqlText) { var q1 = new Query("Suppliers") - .Define("@foo", "Beirut") - .Select("City") - .Where("City", Variable("@foo")); + .Define("@foo", "Beirut") + .Select("City") + .Where("City", Variable("@foo")); var q2 = new Query("Customers") - .Define("@city", "Z") - .Select("City") - .Union(q1) - .WhereNotLike("City", Variable("@city")); + .Define("@city", "Z") + .Select("City") + .Union(q1) + .WhereNotLike("City", Variable("@city")); - var c = Compile(q2); - Assert.Equal("SELECT [City] FROM [Customers] WHERE NOT (LOWER([City]) like 'z') UNION SELECT [City] FROM [Suppliers] WHERE [City] = 'Beirut'", c[EngineCodes.SqlServer]); - } + var result = CompileFor(engine, q2); + Assert.Equal(sqlText, result.ToString()); + } - [Fact] - public void Test_Define_Except() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT [City] FROM [Customers] WHERE NOT (LOWER([City]) like 'z') EXCEPT SELECT [City] FROM [Suppliers] WHERE [City] = 'Beirut'")] + public void Test_Define_Except(string engine, string sqlText) { var q1 = new Query("Suppliers") - .Define("@foo", "Beirut") - .Select("City") - .Where("City", Variable("@foo")); + .Define("@foo", "Beirut") + .Select("City") + .Where("City", Variable("@foo")); var q2 = new Query("Customers") - .Define("@city", "Z") - .Select("City") - .Except(q1) - .WhereNotLike("City", Variable("@city")); + .Define("@city", "Z") + .Select("City") + .Except(q1) + .WhereNotLike("City", Variable("@city")); + + var result = CompileFor(engine, q2); - var c = Compile(q2); - Assert.Equal("SELECT [City] FROM [Customers] WHERE NOT (LOWER([City]) like 'z') EXCEPT SELECT [City] FROM [Suppliers] WHERE [City] = 'Beirut'", c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Test_Define_Intersect() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT [City] FROM [Customers] WHERE NOT (LOWER([City]) like 'z') INTERSECT SELECT [City] FROM [Suppliers] WHERE [City] = 'Beirut'")] + public void Test_Define_Intersect(string engine, string sqlText) { var q1 = new Query("Suppliers") - .Define("@foo", "Beirut") - .Select("City") - .Where("City", Variable("@foo")); + .Define("@foo", "Beirut") + .Select("City") + .Where("City", Variable("@foo")); var q2 = new Query("Customers") - .Define("@city", "Z") - .Select("City") - .Intersect(q1) - .WhereNotLike("City", Variable("@city")); + .Define("@city", "Z") + .Select("City") + .Intersect(q1) + .WhereNotLike("City", Variable("@city")); - var c = Compile(q2); - Assert.Equal("SELECT [City] FROM [Customers] WHERE NOT (LOWER([City]) like 'z') INTERSECT SELECT [City] FROM [Suppliers] WHERE [City] = 'Beirut'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, q2); + + Assert.Equal(sqlText, result.ToString()); } - /* - [Fact] - public void Test_Define_CombineRaw() + [Theory(Skip = "not implemented")] + [InlineData(EngineCodes.SqlServer, + "SELECT [City] FROM [Customers] UNION ALL SELECT City FROM Suppliers WHERE 1 = 1 AND 2 = 2")] + public void Test_Define_CombineRaw(string engine, string sqlText) { - var query = new Query("Customers") - .Define("@foo", 1) - .Define("@faa", 2) - .Select("City") - .CombineRaw("UNION ALL SELECT City FROM Suppliers WHERE 1 = @foo AND 2 = @faa"); + .Define("@foo", 1) + .Define("@faa", 2) + .Select("City") + .CombineRaw("UNION ALL SELECT City FROM Suppliers WHERE 1 = @foo AND 2 = @faa"); - var c = Compile(query); - Assert.Equal("SELECT [City] FROM [Customers] UNION ALL SELECT City FROM Suppliers WHERE 1 = 1 AND 2 = 2", c[EngineCodes.SqlServer]); - } - */ + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); + } } } diff --git a/QueryBuilder.Tests/DeleteTests.cs b/QueryBuilder.Tests/DeleteTests.cs index 14fd4043..9df932e8 100644 --- a/QueryBuilder.Tests/DeleteTests.cs +++ b/QueryBuilder.Tests/DeleteTests.cs @@ -1,49 +1,85 @@ -using SqlKata.Compilers; -using SqlKata.Extensions; using SqlKata.Tests.Infrastructure; -using System; -using System.Linq; -using Xunit; namespace SqlKata.Tests { public class DeleteTests : TestSupport { - [Fact] - public void BasicDelete() + [Theory] + [InlineData(EngineCodes.SqlServer, "DELETE FROM [Posts]")] + [InlineData(EngineCodes.Oracle, "DELETE FROM \"Posts\"")] + [InlineData(EngineCodes.PostgreSql, "DELETE FROM \"Posts\"")] + [InlineData(EngineCodes.MySql, "DELETE FROM `Posts`")] + [InlineData(EngineCodes.Firebird, "DELETE FROM \"POSTS\"")] + [InlineData(EngineCodes.Sqlite, "DELETE FROM \"Posts\"")] + public void BasicDelete(string engine, string query) { var q = new Query("Posts").AsDelete(); - var c = Compile(q); + var result = CompileFor(engine, q); - Assert.Equal("DELETE FROM [Posts]", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void DeleteWithJoin() + [Theory] + [InlineData(EngineCodes.SqlServer, + "DELETE [Posts] FROM [Posts] \n" + + "INNER JOIN [Authors] ON [Authors].[Id] = [Posts].[AuthorId] WHERE [Authors].[Id] = 5")] + [InlineData(EngineCodes.Oracle, + "DELETE \"Posts\" FROM \"Posts\" \n" + + "INNER JOIN \"Authors\" ON \"Authors\".\"Id\" = \"Posts\".\"AuthorId\" WHERE \"Authors\".\"Id\" = 5")] + [InlineData(EngineCodes.PostgreSql, + "DELETE \"Posts\" FROM \"Posts\" \n" + + "INNER JOIN \"Authors\" ON \"Authors\".\"Id\" = \"Posts\".\"AuthorId\" WHERE \"Authors\".\"Id\" = 5")] + [InlineData(EngineCodes.MySql, + "DELETE `Posts` FROM `Posts` \n" + + "INNER JOIN `Authors` ON `Authors`.`Id` = `Posts`.`AuthorId` WHERE `Authors`.`Id` = 5")] + [InlineData(EngineCodes.Firebird, + "DELETE \"POSTS\" FROM \"POSTS\" \n" + + "INNER JOIN \"AUTHORS\" ON \"AUTHORS\".\"ID\" = \"POSTS\".\"AUTHORID\" WHERE \"AUTHORS\".\"ID\" = 5")] + [InlineData(EngineCodes.Sqlite, + "DELETE \"Posts\" FROM \"Posts\" \n" + + "INNER JOIN \"Authors\" ON \"Authors\".\"Id\" = \"Posts\".\"AuthorId\" WHERE \"Authors\".\"Id\" = 5")] + public void DeleteWithJoin(string engine, string query) { var q = new Query("Posts") .Join("Authors", "Authors.Id", "Posts.AuthorId") .Where("Authors.Id", 5) .AsDelete(); - var c = Compile(q); + var result = CompileFor(engine, q); - Assert.Equal("DELETE [Posts] FROM [Posts] \nINNER JOIN [Authors] ON [Authors].[Id] = [Posts].[AuthorId] WHERE [Authors].[Id] = 5", c[EngineCodes.SqlServer]); - Assert.Equal("DELETE `Posts` FROM `Posts` \nINNER JOIN `Authors` ON `Authors`.`Id` = `Posts`.`AuthorId` WHERE `Authors`.`Id` = 5", c[EngineCodes.MySql]); + Assert.Equal(query, result.ToString()); } - [Fact] - public void DeleteWithJoinAndAlias() + [Theory] + [InlineData(EngineCodes.SqlServer, + "DELETE [P] FROM [Posts] AS [P] \n" + + "INNER JOIN [Authors] AS [A] ON [A].[Id] = [P].[AuthorId] WHERE [A].[Id] = 5")] + [InlineData(EngineCodes.Oracle, + "DELETE \"P\" FROM \"Posts\" \"P\" \n" + + "INNER JOIN \"Authors\" \"A\" ON \"A\".\"Id\" = \"P\".\"AuthorId\" WHERE \"A\".\"Id\" = 5")] + [InlineData(EngineCodes.PostgreSql, + "DELETE \"P\" FROM \"Posts\" AS \"P\" \n" + + "INNER JOIN \"Authors\" AS \"A\" ON \"A\".\"Id\" = \"P\".\"AuthorId\" WHERE \"A\".\"Id\" = 5")] + [InlineData(EngineCodes.MySql, + "DELETE `P` FROM `Posts` AS `P` \n" + + "INNER JOIN `Authors` AS `A` ON `A`.`Id` = `P`.`AuthorId` WHERE `A`.`Id` = 5")] + [InlineData(EngineCodes.Firebird, + "DELETE \"P\" FROM \"POSTS\" AS \"P\" \n" + + "INNER JOIN \"AUTHORS\" AS \"A\" ON \"A\".\"ID\" = \"P\".\"AUTHORID\" WHERE \"A\".\"ID\" = 5")] + [InlineData(EngineCodes.Sqlite, + "DELETE \"P\" FROM \"Posts\" AS \"P\" \n" + + "INNER JOIN \"Authors\" AS \"A\" ON \"A\".\"Id\" = \"P\".\"AuthorId\" WHERE \"A\".\"Id\" = 5")] + public void DeleteWithJoinAndAlias(string engine, string query) { var q = new Query("Posts as P") - .Join("Authors", "Authors.Id", "P.AuthorId") - .Where("Authors.Id", 5) + .Join("Authors as A", "A.Id", "P.AuthorId") + .Where("A.Id", 5) .AsDelete(); - var c = Compile(q); + var result = CompileFor(engine, q); - Assert.Equal("DELETE [P] FROM [Posts] AS [P] \nINNER JOIN [Authors] ON [Authors].[Id] = [P].[AuthorId] WHERE [Authors].[Id] = 5", c[EngineCodes.SqlServer]); + Assert.Equal(query, result.ToString()); } } } diff --git a/QueryBuilder.Tests/ExecutionTests.cs b/QueryBuilder.Tests/ExecutionTests.cs index 5d41e7fd..23a84bd5 100644 --- a/QueryBuilder.Tests/ExecutionTests.cs +++ b/QueryBuilder.Tests/ExecutionTests.cs @@ -1,13 +1,11 @@ -using System; using SqlKata.Execution; -using Xunit; namespace SqlKata.Tests { public class ExecutionTests { [Fact] - public void ShouldThrowException() + public void Get_WhenWasNotCalledOnXQuery_ShouldThrowException() { Assert.Throws(() => { @@ -23,8 +21,8 @@ public void TimeoutShouldBeCarriedToNewCreatedFactory() var newFactory = QueryExtensions.CreateQueryFactory(db.Query()); Assert.Equal(db.QueryTimeout, newFactory.QueryTimeout); } - - [Fact(Skip = "timeout over cloned xQuery is not supported yet")] + + [Fact] public void TimeoutShouldBeCarriedToNewCreatedFactoryAfterClone() { var db = new QueryFactory(); diff --git a/QueryBuilder.Tests/Firebird/FirebirdLimitTests.cs b/QueryBuilder.Tests/Firebird/FirebirdLimitTests.cs index b449bae8..e0593efa 100644 --- a/QueryBuilder.Tests/Firebird/FirebirdLimitTests.cs +++ b/QueryBuilder.Tests/Firebird/FirebirdLimitTests.cs @@ -1,55 +1,57 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.Firebird { public class FirebirdLimitTests : TestSupport { - private readonly FirebirdCompiler compiler; + private readonly Compiler compiler; public FirebirdLimitTests() { - compiler = Compilers.Get(EngineCodes.Firebird); + compiler = CreateCompiler(EngineCodes.Firebird); } [Fact] public void NoLimitNorOffset() { var query = new Query("Table"); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + var result = compiler.Compile(query); + + Assert.Equal("SELECT * FROM \"TABLE\"", result.ToString()); } [Fact] public void LimitOnly() { var query = new Query("Table").Limit(10); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + var result = compiler.Compile(query); + + Assert.Equal("SELECT FIRST 10 * FROM \"TABLE\"", result.ToString()); } [Fact] public void OffsetOnly() { var query = new Query("Table").Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + var result = compiler.Compile(query); + + Assert.Equal("SELECT SKIP 20 * FROM \"TABLE\"", result.ToString()); } [Fact] public void LimitAndOffset() { var query = new Query("Table").Limit(5).Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Equal("ROWS ? TO ?", compiler.CompileLimit(ctx)); - Assert.Equal(21L, ctx.Bindings[0]); - Assert.Equal(25L, ctx.Bindings[1]); - Assert.Equal(2, ctx.Bindings.Count); + var result = compiler.Compile(query); + + Assert.Equal("SELECT * FROM \"TABLE\" ROWS ? TO ?", result.RawSql); + Assert.Equal(2, result.Bindings.Count); + Assert.Equal(21L, result.Bindings[0]); + Assert.Equal(25L, result.Bindings[1]); } } } diff --git a/QueryBuilder.Tests/GeneralTests.cs b/QueryBuilder.Tests/GeneralTests.cs index 63fb3d3f..8f0c7c56 100644 --- a/QueryBuilder.Tests/GeneralTests.cs +++ b/QueryBuilder.Tests/GeneralTests.cs @@ -1,28 +1,34 @@ -using SqlKata.Compilers; using SqlKata.Extensions; using SqlKata.Tests.Infrastructure; -using System; -using System.Linq; -using Xunit; +using SqlKata.Tests.Infrastructure.TestCompilers; namespace SqlKata.Tests { public class GeneralTests : TestSupport { - [Fact] - public void ColumnsEscaping() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [mycol[isthis]]] FROM [users]")] + public void ColumnsEscaping(string engine, string sqlText) { - var q = new Query().From("users") + var query = new Query().From("users") .Select("mycol[isthis]"); - var c = Compile(q); + var result = CompileFor(engine, query); - Assert.Equal("SELECT [mycol[isthis]]] FROM [users]", c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void InnerScopeEngineWithinCTE() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "WITH [series] AS (SELECT * FROM [table] WHERE sqlsrv = 1)\nSELECT * FROM [series]")] + [InlineData( + EngineCodes.PostgreSql, + "WITH \"series\" AS (SELECT * FROM \"table\" WHERE postgres = true)\nSELECT * FROM \"series\"")] + [InlineData( + EngineCodes.Firebird, + "WITH \"SERIES\" AS (SELECT * FROM \"TABLE\" WHERE firebird = 1)\nSELECT * FROM \"SERIES\"")] + public void InnerScopeEngineWithinCTE(string engine, string sqlText) { var series = new Query("table") .ForPostgreSql(q => q.WhereRaw("postgres = true")) @@ -30,18 +36,22 @@ public void InnerScopeEngineWithinCTE() .ForFirebird(q => q.WhereRaw("firebird = 1")); var query = new Query("series").With("series", series); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal("WITH [series] AS (SELECT * FROM [table] WHERE sqlsrv = 1)\nSELECT * FROM [series]", c[EngineCodes.SqlServer]); - - Assert.Equal("WITH \"series\" AS (SELECT * FROM \"table\" WHERE postgres = true)\nSELECT * FROM \"series\"", - c[EngineCodes.PostgreSql]); - Assert.Equal("WITH \"SERIES\" AS (SELECT * FROM \"TABLE\" WHERE firebird = 1)\nSELECT * FROM \"SERIES\"", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InnerScopeEngineWithinSubQuery() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "SELECT * FROM (SELECT * FROM [table] WHERE sqlsrv = 1) AS [series]")] + [InlineData( + EngineCodes.PostgreSql, + "SELECT * FROM (SELECT * FROM \"table\" WHERE postgres = true) AS \"series\"")] + [InlineData( + EngineCodes.Firebird, + "SELECT * FROM (SELECT * FROM \"TABLE\" WHERE firebird = 1) AS \"SERIES\"")] + public void InnerScopeEngineWithinSubQuery(string engine, string sqlText) { var series = new Query("table") .ForPostgreSql(q => q.WhereRaw("postgres = true")) @@ -49,12 +59,9 @@ public void InnerScopeEngineWithinSubQuery() .ForFirebird(q => q.WhereRaw("firebird = 1")); var query = new Query("series").From(series.As("series")); - var c = Compile(query); - - Assert.Equal("SELECT * FROM (SELECT * FROM [table] WHERE sqlsrv = 1) AS [series]", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM (SELECT * FROM \"table\" WHERE postgres = true) AS \"series\"", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT * FROM (SELECT * FROM \"TABLE\" WHERE firebird = 1) AS \"SERIES\"", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -99,8 +106,14 @@ public void Custom_compiler_with_empty_identifier_overrides_should_remove_identi Assert.Equal("Table", wrappedValue); } - [Fact] - public void Should_Equal_AfterMultipleCompile() + [Theory] + [InlineData(EngineCodes.Firebird)] + [InlineData(EngineCodes.MySql)] + [InlineData(EngineCodes.Oracle)] + [InlineData(EngineCodes.PostgreSql)] + [InlineData(EngineCodes.Sqlite)] + [InlineData(EngineCodes.SqlServer)] + public void Should_Equal_AfterMultipleCompile(string engine) { var query = new Query() .Select("Id", "Name") @@ -109,43 +122,35 @@ public void Should_Equal_AfterMultipleCompile() .Limit(20) .Offset(1); - var first = Compile(query); - Assert.Equal( - "SELECT * FROM (SELECT [Id], [Name], ROW_NUMBER() OVER (ORDER BY [Name]) AS [row_num] FROM [Table]) AS [results_wrapper] WHERE [row_num] BETWEEN 2 AND 21", - first[EngineCodes.SqlServer]); - Assert.Equal("SELECT `Id`, `Name` FROM `Table` ORDER BY `Name` LIMIT 20 OFFSET 1", first[EngineCodes.MySql]); - Assert.Equal("SELECT \"Id\", \"Name\" FROM \"Table\" ORDER BY \"Name\" LIMIT 20 OFFSET 1", first[EngineCodes.PostgreSql]); - Assert.Equal("SELECT \"ID\", \"NAME\" FROM \"TABLE\" ORDER BY \"NAME\" ROWS 2 TO 21", first[EngineCodes.Firebird]); + var first = CompileFor(engine, query); + var second = CompileFor(engine, query); - var second = Compile(query); - - Assert.Equal(first[EngineCodes.SqlServer], second[EngineCodes.SqlServer]); - Assert.Equal(first[EngineCodes.MySql], second[EngineCodes.MySql]); - Assert.Equal(first[EngineCodes.PostgreSql], second[EngineCodes.PostgreSql]); - Assert.Equal(first[EngineCodes.Firebird], second[EngineCodes.Firebird]); + Assert.Equal(first.ToString(), second.ToString()); } - [Fact] - public void Raw_WrapIdentifiers() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [Id], [Name], [Age] FROM [Users]")] + [InlineData(EngineCodes.MySql, "SELECT `Id`, `Name`, `Age` FROM `Users`")] + [InlineData(EngineCodes.PostgreSql, "SELECT \"Id\", \"Name\", \"Age\" FROM \"Users\"")] + [InlineData(EngineCodes.Firebird, "SELECT \"Id\", \"Name\", \"Age\" FROM \"USERS\"")] + public void Raw_WrapIdentifiers(string engine, string sqlText) { var query = new Query("Users").SelectRaw("[Id], [Name], {Age}"); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal("SELECT [Id], [Name], [Age] FROM [Users]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT `Id`, `Name`, `Age` FROM `Users`", c[EngineCodes.MySql]); - Assert.Equal("SELECT \"Id\", \"Name\", \"Age\" FROM \"Users\"", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT \"Id\", \"Name\", \"Age\" FROM \"USERS\"", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Raw_WrapIdentifiers_Escaped() + [Theory] + [InlineData(EngineCodes.PostgreSql, "SELECT '{1,2,3}'::int[] FROM \"Users\"")] + public void Raw_WrapIdentifiers_Escaped(string engine, string sqlText) { var query = new Query("Users").SelectRaw("'\\{1,2,3\\}'::int\\[\\]"); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal("SELECT '{1,2,3}'::int[] FROM \"Users\"", c[EngineCodes.PostgreSql]); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -153,7 +158,6 @@ public void WrapWithSpace() { var compiler = new SqlServerCompiler(); - Assert.Equal("[My Table] AS [Table]", compiler.Wrap("My Table as Table")); } @@ -162,7 +166,6 @@ public void WrapWithDotes() { var compiler = new SqlServerCompiler(); - Assert.Equal("[My Schema].[My Table] AS [Table]", compiler.Wrap("My Schema.My Table as Table")); } @@ -171,53 +174,55 @@ public void WrapWithMultipleSpaces() { var compiler = new SqlServerCompiler(); - Assert.Equal("[My Table One] AS [Table One]", compiler.Wrap("My Table One as Table One")); } - [Fact] - public void CompilerSpecificFrom() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [mssql]")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"pgsql\"")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `mysql`")] + public void CompilerSpecificFrom(string engine, string sqlText) { var query = new Query() .ForSqlServer(q => q.From("mssql")) .ForPostgreSql(q => q.From("pgsql")) .ForMySql(q => q.From("mysql")); - var engines = new[] { EngineCodes.SqlServer, EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); - Assert.Equal("SELECT * FROM [mssql]", c[EngineCodes.SqlServer].RawSql); - Assert.Equal("SELECT * FROM \"pgsql\"", c[EngineCodes.PostgreSql].RawSql); - Assert.Equal("SELECT * FROM `mysql`", c[EngineCodes.MySql].RawSql); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void CompilerSpecificFromRaw() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [mssql]")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"pgsql\"")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `mysql`")] + public void CompilerSpecificFromRaw(string engine, string sqlText) { var query = new Query() .ForSqlServer(q => q.FromRaw("[mssql]")) .ForPostgreSql(q => q.FromRaw("[pgsql]")) .ForMySql(q => q.FromRaw("[mysql]")); - var engines = new[] { EngineCodes.SqlServer, EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); - Assert.Equal("SELECT * FROM [mssql]", c[EngineCodes.SqlServer].RawSql); - Assert.Equal("SELECT * FROM \"pgsql\"", c[EngineCodes.PostgreSql].RawSql); - Assert.Equal("SELECT * FROM `mysql`", c[EngineCodes.MySql].RawSql); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void CompilerSpecificFromMixed() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [mssql]")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"pgsql\"")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `mysql`")] + public void CompilerSpecificFromMixed(string engine, string sqlText) { var query = new Query() .ForSqlServer(q => q.From("mssql")) .ForPostgreSql(q => q.FromRaw("[pgsql]")) .ForMySql(q => q.From("mysql")); - var engines = new[] { EngineCodes.SqlServer, EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); - Assert.Equal("SELECT * FROM [mssql]", c[EngineCodes.SqlServer].RawSql); - Assert.Equal("SELECT * FROM \"pgsql\"", c[EngineCodes.PostgreSql].RawSql); - Assert.Equal("SELECT * FROM `mysql`", c[EngineCodes.MySql].RawSql); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -226,13 +231,15 @@ public void OneFromPerEngine() var query = new Query("generic") .ForSqlServer(q => q.From("dnu")) .ForSqlServer(q => q.From("mssql")); - var engines = new[] { EngineCodes.SqlServer, EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); + + var c = CompileFor(EngineCodes.SqlServer, query); + var c2 = CompileFor(EngineCodes.PostgreSql, query); + var c3 = CompileFor(EngineCodes.MySql, query); Assert.Equal(2, query.Clauses.OfType().Count()); - Assert.Equal("SELECT * FROM [mssql]", c[EngineCodes.SqlServer].RawSql); - Assert.Equal("SELECT * FROM \"generic\"", c[EngineCodes.PostgreSql].RawSql); - Assert.Equal("SELECT * FROM `generic`", c[EngineCodes.MySql].RawSql); + Assert.Equal("SELECT * FROM [mssql]", c.RawSql); + Assert.Equal("SELECT * FROM \"generic\"", c2.RawSql); + Assert.Equal("SELECT * FROM `generic`", c3.RawSql); } [Theory] @@ -245,8 +252,8 @@ public void AddOrReplace_Works(string table, string engine) var query = new Query(); if (table != null) query.From(table); - query.AddOrReplaceComponent("from", new FromClause() { Table = "updated", Engine = engine }); - var froms = query.Clauses.OfType(); + query.AddOrReplaceComponent("from", new FromClause { Table = "updated", Engine = engine }); + var froms = query.Clauses.OfType().ToList(); Assert.Single(froms); Assert.Equal("updated", froms.Single().Table); @@ -276,6 +283,7 @@ public void AddOrReplace_Throws_MoreThanOne() .Where("c", "d"); Action act = () => query.AddOrReplaceComponent("where", new BasicCondition()); + Assert.Throws(act); } @@ -287,24 +295,25 @@ public void OneLimitPerEngine() .ForSqlServer(q => q.Limit(10)); var limits = query.GetComponents("limit", EngineCodes.SqlServer); + Assert.Single(limits); Assert.Equal(10, limits.Single().Limit); } - [Fact] - public void CompilerSpecificLimit() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT TOP (5) * FROM [mytable]")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"mytable\" LIMIT 10")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `mytable`")] + public void CompilerSpecificLimit(string engine, string sqlText) { var query = new Query("mytable") .ForSqlServer(q => q.Limit(5)) .ForPostgreSql(q => q.Limit(10)); - var engines = new[] { EngineCodes.SqlServer, EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); + var result = CompileFor(engine, query); Assert.Equal(2, query.GetComponents("limit").Count); - Assert.Equal("SELECT TOP (5) * FROM [mytable]", c[EngineCodes.SqlServer].ToString()); - Assert.Equal("SELECT * FROM \"mytable\" LIMIT 10", c[EngineCodes.PostgreSql].ToString()); - Assert.Equal("SELECT * FROM `mytable`", c[EngineCodes.MySql].ToString()); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -319,50 +328,50 @@ public void OneOffsetPerEngine() Assert.Equal(10, limits.Single().Offset); } - [Fact] - public void CompilerSpecificOffset() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [mytable]")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"mytable\" OFFSET 10")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `mytable` LIMIT 18446744073709551615 OFFSET 5")] + public void CompilerSpecificOffset(string engine, string sqlText) { var query = new Query("mytable") .ForMySql(q => q.Offset(5)) .ForPostgreSql(q => q.Offset(10)); - var engines = new[] { EngineCodes.SqlServer, EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); + var result = CompileFor(engine, query); Assert.Equal(2, query.GetComponents("offset").Count); - Assert.Equal("SELECT * FROM `mytable` LIMIT 18446744073709551615 OFFSET 5", c[EngineCodes.MySql].ToString()); - Assert.Equal("SELECT * FROM \"mytable\" OFFSET 10", c[EngineCodes.PostgreSql].ToString()); - Assert.Equal("SELECT * FROM [mytable]", c[EngineCodes.SqlServer].ToString()); + Assert.Equal(sqlText, result.ToString()); } [Fact] - public void Limit_Takes_Generic_If_Needed() + public void Offset_Takes_Generic_If_Needed() { var query = new Query("mytable") .Limit(5) .Offset(10) .ForPostgreSql(q => q.Offset(20)); - var engines = new[] { EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); + var c = CompileFor(EngineCodes.MySql, query); + var c2 = CompileFor(EngineCodes.PostgreSql, query); - Assert.Equal("SELECT * FROM `mytable` LIMIT 5 OFFSET 10", c[EngineCodes.MySql].ToString()); - Assert.Equal("SELECT * FROM \"mytable\" LIMIT 5 OFFSET 20", c[EngineCodes.PostgreSql].ToString()); + Assert.Equal("SELECT * FROM `mytable` LIMIT 5 OFFSET 10", c.ToString()); + Assert.Equal("SELECT * FROM \"mytable\" LIMIT 5 OFFSET 20", c2.ToString()); } [Fact] - public void Offset_Takes_Generic_If_Needed() + public void Limit_Takes_Generic_If_Needed() { var query = new Query("mytable") .Limit(5) .Offset(10) .ForPostgreSql(q => q.Limit(20)); - var engines = new[] { EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); + var c = CompileFor(EngineCodes.MySql, query); + var c2 = CompileFor(EngineCodes.PostgreSql, query); - Assert.Equal("SELECT * FROM `mytable` LIMIT 5 OFFSET 10", c[EngineCodes.MySql].ToString()); - Assert.Equal("SELECT * FROM \"mytable\" LIMIT 20 OFFSET 10", c[EngineCodes.PostgreSql].ToString()); + Assert.Equal("SELECT * FROM `mytable` LIMIT 5 OFFSET 10", c.ToString()); + Assert.Equal("SELECT * FROM \"mytable\" LIMIT 20 OFFSET 10", c2.ToString()); } [Fact] @@ -374,11 +383,11 @@ public void Can_Change_Generic_Limit_After_SpecificOffset() .ForPostgreSql(q => q.Offset(20)) .Limit(7); - var engines = new[] { EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); + var c = CompileFor(EngineCodes.MySql, query); + var c2 = CompileFor(EngineCodes.PostgreSql, query); - Assert.Equal("SELECT * FROM `mytable` LIMIT 7 OFFSET 10", c[EngineCodes.MySql].ToString()); - Assert.Equal("SELECT * FROM \"mytable\" LIMIT 7 OFFSET 20", c[EngineCodes.PostgreSql].ToString()); + Assert.Equal("SELECT * FROM `mytable` LIMIT 7 OFFSET 10", c.ToString()); + Assert.Equal("SELECT * FROM \"mytable\" LIMIT 7 OFFSET 20", c2.ToString()); } [Fact] @@ -390,26 +399,25 @@ public void Can_Change_Generic_Offset_After_SpecificLimit() .ForPostgreSql(q => q.Limit(20)) .Offset(7); - var engines = new[] { EngineCodes.MySql, EngineCodes.PostgreSql }; - var c = Compilers.Compile(engines, query); + var c = CompileFor(EngineCodes.MySql, query); + var c2 = CompileFor(EngineCodes.PostgreSql, query); - Assert.Equal("SELECT * FROM `mytable` LIMIT 5 OFFSET 7", c[EngineCodes.MySql].ToString()); - Assert.Equal("SELECT * FROM \"mytable\" LIMIT 20 OFFSET 7", c[EngineCodes.PostgreSql].ToString()); + Assert.Equal("SELECT * FROM `mytable` LIMIT 5 OFFSET 7", c.ToString()); + Assert.Equal("SELECT * FROM \"mytable\" LIMIT 20 OFFSET 7", c2.ToString()); } - [Fact] - public void Where_Nested() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "SELECT * FROM [table] WHERE ([a] = 1 OR [a] = 2)")] + public void Where_Nested(string engine, string sqlText) { var query = new Query("table") - .Where(q => q.Where("a", 1).OrWhere("a", 2)); + .Where(q => q.Where("a", 1).OrWhere("a", 2)); - var engines = new[] { - EngineCodes.SqlServer, - }; + var result = CompileFor(engine, query); - var c = Compilers.Compile(engines, query); - - Assert.Equal("SELECT * FROM [table] WHERE ([a] = 1 OR [a] = 2)", c[EngineCodes.SqlServer].ToString()); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -417,9 +425,10 @@ public void AdHoc_Throws_WhenNoColumnsProvided() => Assert.Throws(() => new Query("rows").With("rows", new string[0], - new object[][] { - new object[] {}, - new object[] {}, + new object[][] + { + new object[] { }, + new object[] { }, })); [Fact] @@ -427,7 +436,8 @@ public void AdHoc_Throws_WhenNoValueRowsProvided() => Assert.Throws(() => new Query("rows").With("rows", new[] { "a", "b", "c" }, - new object[][] { + new object[][] + { })); [Fact] @@ -435,7 +445,8 @@ public void AdHoc_Throws_WhenColumnsOutnumberFieldValues() => Assert.Throws(() => new Query("rows").With("rows", new[] { "a", "b", "c", "d" }, - new object[][] { + new object[][] + { new object[] { 1, 2, 3 }, new object[] { 4, 5, 6 }, })); @@ -445,48 +456,77 @@ public void AdHoc_Throws_WhenFieldValuesOutNumberColumns() => Assert.Throws(() => new Query("rows").With("rows", new[] { "a", "b" }, - new object[][] { + new object[][] + { new object[] { 1, 2, 3 }, new object[] { 4, 5, 6 }, })); - [Fact] - public void AdHoc_SingletonRow() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "WITH [rows] AS (SELECT [a] FROM (VALUES (1)) AS tbl ([a]))\nSELECT * FROM [rows]")] + [InlineData( + EngineCodes.PostgreSql, + "WITH \"rows\" AS (SELECT 1 AS \"a\")\nSELECT * FROM \"rows\"")] + [InlineData( + EngineCodes.MySql, + "WITH `rows` AS (SELECT 1 AS `a`)\nSELECT * FROM `rows`")] + [InlineData( + EngineCodes.Sqlite, + "WITH \"rows\" AS (SELECT 1 AS \"a\")\nSELECT * FROM \"rows\"")] + [InlineData( + EngineCodes.Firebird, + "WITH \"ROWS\" AS (SELECT 1 AS \"A\" FROM RDB$DATABASE)\nSELECT * FROM \"ROWS\"")] + [InlineData( + EngineCodes.Oracle, + "WITH \"rows\" AS (SELECT 1 AS \"a\" FROM DUAL)\nSELECT * FROM \"rows\"")] + public void AdHoc_SingletonRow(string engine, string sqlText) { var query = new Query("rows").With("rows", new[] { "a" }, - new object[][] { + new object[][] + { new object[] { 1 }, }); - var c = Compilers.Compile(query); + var result = CompileFor(engine, query); - Assert.Equal("WITH [rows] AS (SELECT [a] FROM (VALUES (1)) AS tbl ([a]))\nSELECT * FROM [rows]", c[EngineCodes.SqlServer].ToString()); - Assert.Equal("WITH \"rows\" AS (SELECT 1 AS \"a\")\nSELECT * FROM \"rows\"", c[EngineCodes.PostgreSql].ToString()); - Assert.Equal("WITH `rows` AS (SELECT 1 AS `a`)\nSELECT * FROM `rows`", c[EngineCodes.MySql].ToString()); - Assert.Equal("WITH \"rows\" AS (SELECT 1 AS \"a\")\nSELECT * FROM \"rows\"", c[EngineCodes.Sqlite].ToString()); - Assert.Equal("WITH \"ROWS\" AS (SELECT 1 AS \"A\" FROM RDB$DATABASE)\nSELECT * FROM \"ROWS\"", c[EngineCodes.Firebird].ToString()); - Assert.Equal("WITH \"rows\" AS (SELECT 1 AS \"a\" FROM DUAL)\nSELECT * FROM \"rows\"", c[EngineCodes.Oracle].ToString()); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void AdHoc_TwoRows() + [Theory] + [InlineData( + EngineCodes.SqlServer, + "WITH [rows] AS (SELECT [a], [b], [c] FROM (VALUES (1, 2, 3), (4, 5, 6)) AS tbl ([a], [b], [c]))\nSELECT * FROM [rows]")] + [InlineData( + EngineCodes.PostgreSql, + "WITH \"rows\" AS (SELECT 1 AS \"a\", 2 AS \"b\", 3 AS \"c\" UNION ALL SELECT 4 AS \"a\", 5 AS \"b\", 6 AS \"c\")\nSELECT * FROM \"rows\"")] + [InlineData( + EngineCodes.MySql, + "WITH `rows` AS (SELECT 1 AS `a`, 2 AS `b`, 3 AS `c` UNION ALL SELECT 4 AS `a`, 5 AS `b`, 6 AS `c`)\nSELECT * FROM `rows`")] + [InlineData( + EngineCodes.Sqlite, + "WITH \"rows\" AS (SELECT 1 AS \"a\", 2 AS \"b\", 3 AS \"c\" UNION ALL SELECT 4 AS \"a\", 5 AS \"b\", 6 AS \"c\")\nSELECT * FROM \"rows\"")] + [InlineData( + EngineCodes.Firebird, + "WITH \"ROWS\" AS (SELECT 1 AS \"A\", 2 AS \"B\", 3 AS \"C\" FROM RDB$DATABASE UNION ALL SELECT 4 AS \"A\", 5 AS \"B\", 6 AS \"C\" FROM RDB$DATABASE)\nSELECT * FROM \"ROWS\"")] + [InlineData( + EngineCodes.Oracle, + "WITH \"rows\" AS (SELECT 1 AS \"a\", 2 AS \"b\", 3 AS \"c\" FROM DUAL UNION ALL SELECT 4 AS \"a\", 5 AS \"b\", 6 AS \"c\" FROM DUAL)\nSELECT * FROM \"rows\"")] + public void AdHoc_TwoRows(string engine, string sqlText) { var query = new Query("rows").With("rows", new[] { "a", "b", "c" }, - new object[][] { + new object[][] + { new object[] { 1, 2, 3 }, new object[] { 4, 5, 6 }, }); - var c = Compilers.Compile(query); + var c = CompileFor(engine, query); - Assert.Equal("WITH [rows] AS (SELECT [a], [b], [c] FROM (VALUES (1, 2, 3), (4, 5, 6)) AS tbl ([a], [b], [c]))\nSELECT * FROM [rows]", c[EngineCodes.SqlServer].ToString()); - Assert.Equal("WITH \"rows\" AS (SELECT 1 AS \"a\", 2 AS \"b\", 3 AS \"c\" UNION ALL SELECT 4 AS \"a\", 5 AS \"b\", 6 AS \"c\")\nSELECT * FROM \"rows\"", c[EngineCodes.PostgreSql].ToString()); - Assert.Equal("WITH `rows` AS (SELECT 1 AS `a`, 2 AS `b`, 3 AS `c` UNION ALL SELECT 4 AS `a`, 5 AS `b`, 6 AS `c`)\nSELECT * FROM `rows`", c[EngineCodes.MySql].ToString()); - Assert.Equal("WITH \"rows\" AS (SELECT 1 AS \"a\", 2 AS \"b\", 3 AS \"c\" UNION ALL SELECT 4 AS \"a\", 5 AS \"b\", 6 AS \"c\")\nSELECT * FROM \"rows\"", c[EngineCodes.Sqlite].ToString()); - Assert.Equal("WITH \"ROWS\" AS (SELECT 1 AS \"A\", 2 AS \"B\", 3 AS \"C\" FROM RDB$DATABASE UNION ALL SELECT 4 AS \"A\", 5 AS \"B\", 6 AS \"C\" FROM RDB$DATABASE)\nSELECT * FROM \"ROWS\"", c[EngineCodes.Firebird].ToString()); - Assert.Equal("WITH \"rows\" AS (SELECT 1 AS \"a\", 2 AS \"b\", 3 AS \"c\" FROM DUAL UNION ALL SELECT 4 AS \"a\", 5 AS \"b\", 6 AS \"c\" FROM DUAL)\nSELECT * FROM \"rows\"", c[EngineCodes.Oracle].ToString()); + Assert.Equal(sqlText, c.ToString()); } [Fact] @@ -496,20 +536,22 @@ public void AdHoc_ProperBindingsPlacement() .With("othercte", q => q.From("othertable").Where("othertable.status", "A")) .Where("rows.foo", "bar") .With("rows", - new[] { "a", "b", "c" }, - new object[][] { - new object[] { 1, 2, 3 }, - new object[] { 4, 5, 6 }, - }) + new[] { "a", "b", "c" }, + new object[][] + { + new object[] { 1, 2, 3 }, + new object[] { 4, 5, 6 }, + }) .Where("rows.baz", "buzz"); - var c = Compilers.Compile(query); + var c = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal(string.Join("\n", new[] { + Assert.Equal(string.Join("\n", new[] + { "WITH [othercte] AS (SELECT * FROM [othertable] WHERE [othertable].[status] = 'A'),", "[rows] AS (SELECT [a], [b], [c] FROM (VALUES (1, 2, 3), (4, 5, 6)) AS tbl ([a], [b], [c]))", "SELECT * FROM [rows] WHERE [rows].[foo] = 'bar' AND [rows].[baz] = 'buzz'", - }), c[EngineCodes.SqlServer].ToString()); + }), c.ToString()); } [Fact] @@ -520,13 +562,9 @@ public void UnsafeLiteral_Insert() Count = new UnsafeLiteral("Count + 1") }); - var engines = new[] { - EngineCodes.SqlServer, - }; + var c = CompileFor(EngineCodes.SqlServer, query); - var c = Compilers.Compile(engines, query); - - Assert.Equal("INSERT INTO [Table] ([Count]) VALUES (Count + 1)", c[EngineCodes.SqlServer].ToString()); + Assert.Equal("INSERT INTO [Table] ([Count]) VALUES (Count + 1)", c.ToString()); } [Fact] @@ -537,69 +575,57 @@ public void UnsafeLiteral_Update() Count = new UnsafeLiteral("Count + 1") }); - var engines = new[] { - EngineCodes.SqlServer, - }; - - var c = Compilers.Compile(engines, query); + var c = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal("UPDATE [Table] SET [Count] = Count + 1", c[EngineCodes.SqlServer].ToString()); + Assert.Equal("UPDATE [Table] SET [Count] = Count + 1", c.ToString()); } - [Fact] - public void Passing_Boolean_To_Where_Should_Call_WhereTrue_Or_WhereFalse() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table] WHERE [Col] = cast(1 as bit)")] + public void Passing_Boolean_To_Where_Should_Call_WhereTrue_Or_WhereFalse(string engine, string sqlText) { var query = new Query("Table").Where("Col", true); - var engines = new[] { - EngineCodes.SqlServer, - }; + var result = CompileFor(engine, query); - var c = Compilers.Compile(engines, query); - - Assert.Equal("SELECT * FROM [Table] WHERE [Col] = cast(1 as bit)", c[EngineCodes.SqlServer].ToString()); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Passing_Boolean_False_To_Where_Should_Call_WhereTrue_Or_WhereFalse() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table] WHERE [Col] = cast(0 as bit)")] + public void Passing_Boolean_False_To_Where_Should_Call_WhereTrue_Or_WhereFalse(string engine, string sqlText) { var query = new Query("Table").Where("Col", false); - var engines = new[] { - EngineCodes.SqlServer, - }; - - var c = Compilers.Compile(engines, query); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM [Table] WHERE [Col] = cast(0 as bit)", c[EngineCodes.SqlServer].ToString()); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Passing_Negative_Boolean_To_Where_Should_Call_WhereTrue_Or_WhereFalse() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table] WHERE [Col] != cast(1 as bit)")] + public void Passing_Negative_Boolean_To_Where_Should_Call_WhereTrue_Or_WhereFalse( + string engine, + string sqlText) { var query = new Query("Table").Where("Col", "!=", true); - var engines = new[] { - EngineCodes.SqlServer, - }; + var result = CompileFor(engine, query); - var c = Compilers.Compile(engines, query); - - Assert.Equal("SELECT * FROM [Table] WHERE [Col] != cast(1 as bit)", c[EngineCodes.SqlServer].ToString()); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Passing_Negative_Boolean_False_To_Where_Should_Call_WhereTrue_Or_WhereFalse() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table] WHERE [Col] != cast(0 as bit)")] + public void Passing_Negative_Boolean_False_To_Where_Should_Call_WhereTrue_Or_WhereFalse( + string engine, + string sqlText) { var query = new Query("Table").Where("Col", "!=", false); - var engines = new[] { - EngineCodes.SqlServer, - }; - - var c = Compilers.Compile(engines, query); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM [Table] WHERE [Col] != cast(0 as bit)", c[EngineCodes.SqlServer].ToString()); + Assert.Equal(sqlText, result.ToString()); } } } diff --git a/QueryBuilder.Tests/GlobalUsings.cs b/QueryBuilder.Tests/GlobalUsings.cs new file mode 100644 index 00000000..63d30c4a --- /dev/null +++ b/QueryBuilder.Tests/GlobalUsings.cs @@ -0,0 +1,2 @@ +global using SqlKata.Compilers; +global using Xunit; diff --git a/QueryBuilder.Tests/HelperTests.cs b/QueryBuilder.Tests/HelperTests.cs index ab80e2c5..f7ce375c 100644 --- a/QueryBuilder.Tests/HelperTests.cs +++ b/QueryBuilder.Tests/HelperTests.cs @@ -1,6 +1,4 @@ using System.Collections; -using System.Linq; -using Xunit; namespace SqlKata.Tests { diff --git a/QueryBuilder.Tests/QueryFactoryExtension.cs b/QueryBuilder.Tests/Infrastructure/QueryFactoryExtension.cs similarity index 91% rename from QueryBuilder.Tests/QueryFactoryExtension.cs rename to QueryBuilder.Tests/Infrastructure/QueryFactoryExtension.cs index 9f87bfce..35b206ab 100644 --- a/QueryBuilder.Tests/QueryFactoryExtension.cs +++ b/QueryBuilder.Tests/Infrastructure/QueryFactoryExtension.cs @@ -1,7 +1,7 @@ - -using System.Collections.Generic; using SqlKata.Execution; +namespace SqlKata.Tests.Infrastructure; + static class QueryFactoryExtensions { public static QueryFactory Create(this QueryFactory db, string table, IEnumerable cols) @@ -16,4 +16,4 @@ public static QueryFactory Drop(this QueryFactory db, string table) db.Statement($"DROP TABLE IF EXISTS `{table}`;"); return db; } -} \ No newline at end of file +} diff --git a/QueryBuilder.Tests/Infrastructure/TestCompiler.cs b/QueryBuilder.Tests/Infrastructure/TestCompiler.cs deleted file mode 100644 index aded9fd1..00000000 --- a/QueryBuilder.Tests/Infrastructure/TestCompiler.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Reflection; -using SqlKata.Compilers; - -namespace SqlKata.Tests.Infrastructure -{ - /// - /// A test class to expose private methods - /// - class TestCompiler : Compiler - { - public override string EngineCode { get; } = "test"; - - public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) - { - return FindCompilerMethodInfo(clauseType, methodName); - } - } - - class TestSqlServerCompiler : SqlServerCompiler - { - public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) - { - return FindCompilerMethodInfo(clauseType, methodName); - } - } - - class TestMySqlCompiler : MySqlCompiler - { - public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) - { - return FindCompilerMethodInfo(clauseType, methodName); - } - } - - class TestPostgresCompiler : PostgresCompiler - { - public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) - { - return FindCompilerMethodInfo(clauseType, methodName); - } - } - - class TestFirebirdCompiler : FirebirdCompiler - { - public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) - { - return FindCompilerMethodInfo(clauseType, methodName); - } - } - - class TestEmptyIdentifiersCompiler : TestCompiler - { - protected override string OpeningIdentifier { get; set; } = ""; - protected override string ClosingIdentifier { get; set; } = ""; - } -} - diff --git a/QueryBuilder.Tests/Infrastructure/TestCompilers/TestCompiler.cs b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestCompiler.cs new file mode 100644 index 00000000..83033a08 --- /dev/null +++ b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestCompiler.cs @@ -0,0 +1,18 @@ +using System.Reflection; + +namespace SqlKata.Tests.Infrastructure.TestCompilers +{ + /// + /// A test class to expose private methods + /// + class TestCompiler : Compiler + { + public override string EngineCode { get; } = "generic"; + + public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) + { + return FindCompilerMethodInfo(clauseType, methodName); + } + } +} + diff --git a/QueryBuilder.Tests/Infrastructure/TestCompilers/TestEmptyIdentifiersCompiler.cs b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestEmptyIdentifiersCompiler.cs new file mode 100644 index 00000000..c18dd7b2 --- /dev/null +++ b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestEmptyIdentifiersCompiler.cs @@ -0,0 +1,7 @@ +namespace SqlKata.Tests.Infrastructure.TestCompilers; + +class TestEmptyIdentifiersCompiler : TestCompiler +{ + protected override string OpeningIdentifier { get; set; } = ""; + protected override string ClosingIdentifier { get; set; } = ""; +} diff --git a/QueryBuilder.Tests/Infrastructure/TestCompilers/TestFirebirdCompiler.cs b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestFirebirdCompiler.cs new file mode 100644 index 00000000..4be3e0ae --- /dev/null +++ b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestFirebirdCompiler.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +namespace SqlKata.Tests.Infrastructure.TestCompilers; + +class TestFirebirdCompiler : FirebirdCompiler +{ + public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) + { + return FindCompilerMethodInfo(clauseType, methodName); + } +} diff --git a/QueryBuilder.Tests/Infrastructure/TestCompilers/TestMySqlCompiler.cs b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestMySqlCompiler.cs new file mode 100644 index 00000000..6b51eabc --- /dev/null +++ b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestMySqlCompiler.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +namespace SqlKata.Tests.Infrastructure.TestCompilers; + +class TestMySqlCompiler : MySqlCompiler +{ + public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) + { + return FindCompilerMethodInfo(clauseType, methodName); + } +} diff --git a/QueryBuilder.Tests/Infrastructure/TestCompilers/TestPostgresCompiler.cs b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestPostgresCompiler.cs new file mode 100644 index 00000000..555c2ba7 --- /dev/null +++ b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestPostgresCompiler.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +namespace SqlKata.Tests.Infrastructure.TestCompilers; + +class TestPostgresCompiler : PostgresCompiler +{ + public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) + { + return FindCompilerMethodInfo(clauseType, methodName); + } +} diff --git a/QueryBuilder.Tests/Infrastructure/TestCompilers/TestSqlServerCompiler.cs b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestSqlServerCompiler.cs new file mode 100644 index 00000000..554c4642 --- /dev/null +++ b/QueryBuilder.Tests/Infrastructure/TestCompilers/TestSqlServerCompiler.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +namespace SqlKata.Tests.Infrastructure.TestCompilers; + +class TestSqlServerCompiler : SqlServerCompiler +{ + public virtual MethodInfo Call_FindCompilerMethodInfo(Type clauseType, string methodName) + { + return FindCompilerMethodInfo(clauseType, methodName); + } +} diff --git a/QueryBuilder.Tests/Infrastructure/TestCompilersContainer.cs b/QueryBuilder.Tests/Infrastructure/TestCompilersContainer.cs deleted file mode 100644 index 2312a192..00000000 --- a/QueryBuilder.Tests/Infrastructure/TestCompilersContainer.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using SqlKata.Compilers; - -namespace SqlKata.Tests.Infrastructure -{ - public class TestCompilersContainer - { - private static class Messages - { - public const string ERR_INVALID_ENGINECODE = "Engine code '{0}' is not valid"; - public const string ERR_INVALID_ENGINECODES = "Invalid engine codes supplied '{0}'"; - } - - protected readonly IDictionary Compilers = new Dictionary - { - [EngineCodes.Firebird] = new FirebirdCompiler(), - [EngineCodes.MySql] = new MySqlCompiler(), - [EngineCodes.Oracle] = new OracleCompiler(), - [EngineCodes.PostgreSql] = new PostgresCompiler(), - [EngineCodes.Sqlite] = new SqliteCompiler(), - [EngineCodes.SqlServer] = new SqlServerCompiler() - { - UseLegacyPagination = true - } - }; - - public IEnumerable KnownEngineCodes - { - get { return Compilers.Select(s => s.Key); } - } - - /// - /// Returns a instance for the given engine code - /// - /// - /// - public Compiler Get(string engineCode) - { - if (!Compilers.ContainsKey(engineCode)) - { - throw new InvalidOperationException(string.Format(Messages.ERR_INVALID_ENGINECODE, engineCode)); - } - - return Compilers[engineCode]; - } - - /// - /// Convenience method - /// - /// Does not validate generic type against engine code before cast - /// - /// - /// - public TCompiler Get(string engineCode) where TCompiler : Compiler - { - return (TCompiler)Get(engineCode); - } - - /// - /// Compiles the against the given engine code - /// - /// - /// - /// - public SqlResult CompileFor(string engineCode, Query query) - { - var compiler = Get(engineCode); - return compiler.Compile(query); - } - - /// - /// Compiles the against the given engine codes - /// - /// - /// - /// - public TestSqlResultContainer Compile(IEnumerable engineCodes, Query query) - { - var codes = engineCodes.ToList(); - - var results = Compilers - .Where(w => codes.Contains(w.Key)) - .ToDictionary(k => k.Key, v => v.Value.Compile(query.Clone())); - - if (results.Count != codes.Count) - { - var missingCodes = codes.Where(w => Compilers.All(a => a.Key != w)); - var templateArg = string.Join(", ", missingCodes); - throw new InvalidOperationException(string.Format(Messages.ERR_INVALID_ENGINECODES, templateArg)); - } - - return new TestSqlResultContainer(results); - } - - /// - /// Compiles the against all s - /// - /// - /// - public TestSqlResultContainer Compile(Query query) - { - var resultKeyValues = Compilers - .ToDictionary(k => k.Key, v => v.Value.Compile(query.Clone())); - return new TestSqlResultContainer(resultKeyValues); - } - } -} diff --git a/QueryBuilder.Tests/Infrastructure/TestSqlResultContainer.cs b/QueryBuilder.Tests/Infrastructure/TestSqlResultContainer.cs deleted file mode 100644 index 16a5eeff..00000000 --- a/QueryBuilder.Tests/Infrastructure/TestSqlResultContainer.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; - -namespace SqlKata.Tests.Infrastructure -{ - public class TestSqlResultContainer : ReadOnlyDictionary - { - public TestSqlResultContainer(IDictionary dictionary) : base(dictionary) - { - - } - } -} diff --git a/QueryBuilder.Tests/Infrastructure/TestSupport.cs b/QueryBuilder.Tests/Infrastructure/TestSupport.cs index 78d912cc..d351da73 100644 --- a/QueryBuilder.Tests/Infrastructure/TestSupport.cs +++ b/QueryBuilder.Tests/Infrastructure/TestSupport.cs @@ -1,20 +1,53 @@ -using System.Collections.Generic; -using System.Linq; +using SqlKata.Tests.Infrastructure.TestCompilers; namespace SqlKata.Tests.Infrastructure { public abstract class TestSupport { - protected readonly TestCompilersContainer Compilers = new TestCompilersContainer(); + protected SqlResult CompileForGeneric(Query query, Func configuration = null) + { + return CompileFor(EngineCodes.Generic, query, configuration); + } + + protected SqlResult CompileFor(string engine, Query query, Func configuration = null) + { + var compiler = CreateCompiler(engine); + if (configuration != null) + { + compiler = configuration(compiler); + } + + return compiler.Compile(query); + } + + protected SqlResult CompileFor(string engine, Query query, Action configuration) + { + return CompileFor(engine, query, compiler => + { + configuration(compiler); + return compiler; + }); + } - /// - /// For legacy test support - /// - /// - /// - protected IReadOnlyDictionary Compile(Query query) + protected Compiler CreateCompiler(string engine, bool? useLegacyPagination = null) { - return Compilers.Compile(query).ToDictionary(s => s.Key, v => v.Value.ToString()); + return engine switch + { + EngineCodes.Firebird => new FirebirdCompiler(), + EngineCodes.MySql => new MySqlCompiler(), + EngineCodes.Oracle => new OracleCompiler + { + UseLegacyPagination = useLegacyPagination ?? false + }, + EngineCodes.PostgreSql => new PostgresCompiler(), + EngineCodes.Sqlite => new SqliteCompiler(), + EngineCodes.SqlServer => new SqlServerCompiler + { + UseLegacyPagination = useLegacyPagination ?? true + }, + EngineCodes.Generic => new TestCompiler(), + _ => throw new ArgumentException($"Unsupported engine type: {engine}", nameof(engine)), + }; } } } diff --git a/QueryBuilder.Tests/InfrastructureTests.cs b/QueryBuilder.Tests/InfrastructureTests.cs deleted file mode 100644 index 5bb7f2df..00000000 --- a/QueryBuilder.Tests/InfrastructureTests.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Linq; -using SqlKata.Compilers; -using SqlKata.Tests.Infrastructure; -using Xunit; - -namespace SqlKata.Tests -{ - public class InfrastructureTests : TestSupport - { - [Fact] - public void CanGetCompiler() - { - var compiler = Compilers.Get(EngineCodes.SqlServer); - - Assert.NotNull(compiler); - Assert.IsType(compiler); - } - - [Fact] - public void CanCompile() - { - var results = Compilers.Compile(new Query("Table")); - - Assert.NotNull(results); - Assert.Equal(Compilers.KnownEngineCodes.Count(), results.Count); - } - - [Fact] - public void CanCompileSelectively() - { - var desiredEngines = new[] { EngineCodes.SqlServer, EngineCodes.MySql }; - var results = Compilers.Compile(desiredEngines, new Query("Table")); - - Assert.Equal(desiredEngines.Length, results.Count); - Assert.Contains(results, a => a.Key == EngineCodes.SqlServer); - Assert.Contains(results, a => a.Key == EngineCodes.MySql); - } - - - [Fact] - public void ShouldThrowIfInvalidEngineCode() - { - Assert.Throws(() => Compilers.CompileFor("XYZ", new Query())); - } - - [Fact] - public void ShouldThrowIfAnyEngineCodesAreInvalid() - { - var codes = new[] { EngineCodes.SqlServer, "123", EngineCodes.MySql, "abc" }; - Assert.Throws(() => Compilers.Compile(codes, new Query())); - } - } -} diff --git a/QueryBuilder.Tests/InsertTests.cs b/QueryBuilder.Tests/InsertTests.cs index 926e18b2..ae0428b7 100644 --- a/QueryBuilder.Tests/InsertTests.cs +++ b/QueryBuilder.Tests/InsertTests.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Dynamic; -using System.Linq; -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests { @@ -29,8 +24,10 @@ public Account(string name, string currency = null, string created_at = null, st public string color { get; set; } } - [Fact] - public void InsertObject() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')")] + public void InsertObject(string engine, string sqlText) { var query = new Query("Table") .AsInsert( @@ -40,19 +37,16 @@ public void InsertObject() Age = new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc), }); - var c = Compile(query); - - Assert.Equal( - "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InsertFromSubQueryWithCte() + [Theory] + [InlineData(EngineCodes.SqlServer, "WITH [old_cards] AS (SELECT * FROM [all_cars] WHERE [year] < 2000)\nINSERT INTO [expensive_cars] ([name], [model], [year]) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [old_cars] WHERE [price] > 100) AS [results_wrapper] WHERE [row_num] BETWEEN 11 AND 20")] + [InlineData(EngineCodes.MySql, "WITH `old_cards` AS (SELECT * FROM `all_cars` WHERE `year` < 2000)\nINSERT INTO `expensive_cars` (`name`, `model`, `year`) SELECT * FROM `old_cars` WHERE `price` > 100 LIMIT 10 OFFSET 10")] + [InlineData(EngineCodes.PostgreSql, "WITH \"old_cards\" AS (SELECT * FROM \"all_cars\" WHERE \"year\" < 2000)\nINSERT INTO \"expensive_cars\" (\"name\", \"model\", \"year\") SELECT * FROM \"old_cars\" WHERE \"price\" > 100 LIMIT 10 OFFSET 10")] + public void InsertFromSubQueryWithCte(string engine, string sqlText) { var query = new Query("expensive_cars") .With("old_cards", new Query("all_cars").Where("year", "<", 2000)) @@ -60,23 +54,15 @@ public void InsertFromSubQueryWithCte() new[] { "name", "model", "year" }, new Query("old_cars").Where("price", ">", 100).ForPage(2, 10)); - var c = Compile(query); - - Assert.Equal( - "WITH [old_cards] AS (SELECT * FROM [all_cars] WHERE [year] < 2000)\nINSERT INTO [expensive_cars] ([name], [model], [year]) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [old_cars] WHERE [price] > 100) AS [results_wrapper] WHERE [row_num] BETWEEN 11 AND 20", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "WITH `old_cards` AS (SELECT * FROM `all_cars` WHERE `year` < 2000)\nINSERT INTO `expensive_cars` (`name`, `model`, `year`) SELECT * FROM `old_cars` WHERE `price` > 100 LIMIT 10 OFFSET 10", - c[EngineCodes.MySql]); - - Assert.Equal( - "WITH \"old_cards\" AS (SELECT * FROM \"all_cars\" WHERE \"year\" < 2000)\nINSERT INTO \"expensive_cars\" (\"name\", \"model\", \"year\") SELECT * FROM \"old_cars\" WHERE \"price\" > 100 LIMIT 10 OFFSET 10", - c[EngineCodes.PostgreSql]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InsertMultiRecords() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [expensive_cars] ([name], [brand], [year]) VALUES ('Chiron', 'Bugatti', NULL), ('Huayra', 'Pagani', 2012), ('Reventon roadster', 'Lamborghini', 2009)")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"EXPENSIVE_CARS\" (\"NAME\", \"BRAND\", \"YEAR\") SELECT 'Chiron', 'Bugatti', NULL FROM RDB$DATABASE UNION ALL SELECT 'Huayra', 'Pagani', 2012 FROM RDB$DATABASE UNION ALL SELECT 'Reventon roadster', 'Lamborghini', 2009 FROM RDB$DATABASE")] + public void InsertMultiRecords(string engine, string sqlText) { var query = new Query("expensive_cars") .AsInsert( @@ -88,54 +74,39 @@ public void InsertMultiRecords() new object[] { "Reventon roadster", "Lamborghini", 2009 } }); - var c = Compile(query); - - Assert.Equal( - "INSERT INTO [expensive_cars] ([name], [brand], [year]) VALUES ('Chiron', 'Bugatti', NULL), ('Huayra', 'Pagani', 2012), ('Reventon roadster', 'Lamborghini', 2009)", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO \"EXPENSIVE_CARS\" (\"NAME\", \"BRAND\", \"YEAR\") SELECT 'Chiron', 'Bugatti', NULL FROM RDB$DATABASE UNION ALL SELECT 'Huayra', 'Pagani', 2012 FROM RDB$DATABASE UNION ALL SELECT 'Reventon roadster', 'Lamborghini', 2009 FROM RDB$DATABASE", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InsertWithNullValues() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [Books] ([Id], [Author], [ISBN], [Date]) VALUES (1, 'Author 1', '123456', NULL)")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"BOOKS\" (\"ID\", \"AUTHOR\", \"ISBN\", \"DATE\") VALUES (1, 'Author 1', '123456', NULL)")] + public void InsertWithNullValues(string engine, string sqlText) { var query = new Query("Books") .AsInsert( new[] { "Id", "Author", "ISBN", "Date" }, new object[] { 1, "Author 1", "123456", null }); - var c = Compile(query); - - Assert.Equal("INSERT INTO [Books] ([Id], [Author], [ISBN], [Date]) VALUES (1, 'Author 1', '123456', NULL)", - c[EngineCodes.SqlServer]); - + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO \"BOOKS\" (\"ID\", \"AUTHOR\", \"ISBN\", \"DATE\") VALUES (1, 'Author 1', '123456', NULL)", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InsertWithEmptyString() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [Books] ([Id], [Author], [ISBN], [Description]) VALUES (1, 'Author 1', '123456', '')")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"BOOKS\" (\"ID\", \"AUTHOR\", \"ISBN\", \"DESCRIPTION\") VALUES (1, 'Author 1', '123456', '')")] + public void InsertWithEmptyString(string engine, string sqlText) { var query = new Query("Books") .AsInsert( new[] { "Id", "Author", "ISBN", "Description" }, new object[] { 1, "Author 1", "123456", "" }); - var c = Compile(query); - - Assert.Equal( - "INSERT INTO [Books] ([Id], [Author], [ISBN], [Description]) VALUES (1, 'Author 1', '123456', '')", - c[EngineCodes.SqlServer]); - + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO \"BOOKS\" (\"ID\", \"AUTHOR\", \"ISBN\", \"DESCRIPTION\") VALUES (1, 'Author 1', '123456', '')", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -151,34 +122,31 @@ public void InsertWithByteArray() fauxImagebytes }); - var c = Compilers.Compile(query); - Assert.All(c.Values, a => Assert.Equal(2, a.NamedBindings.Count)); + var result = CompileFor(EngineCodes.SqlServer, query); - var exemplar = c[EngineCodes.SqlServer]; - - Assert.Equal("INSERT INTO [Books] ([Id], [CoverImageBytes]) VALUES (?, ?)", exemplar.RawSql); - Assert.Equal("INSERT INTO [Books] ([Id], [CoverImageBytes]) VALUES (@p0, @p1)", exemplar.Sql); + Assert.Equal(2, result.NamedBindings.Count); + Assert.Equal("INSERT INTO [Books] ([Id], [CoverImageBytes]) VALUES (?, ?)", result.RawSql); + Assert.Equal("INSERT INTO [Books] ([Id], [CoverImageBytes]) VALUES (@p0, @p1)", result.Sql); + Assert.Equal(1, result.NamedBindings["@p0"]); + Assert.Equal(fauxImagebytes, result.NamedBindings["@p1"]); } - [Fact] - public void InsertWithIgnoreAndColumnProperties() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [Account] ([name], [currency_id]) VALUES ('popular', 'US')")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"ACCOUNT\" (\"NAME\", \"CURRENCY_ID\") VALUES ('popular', 'US')")] + public void InsertWithIgnoreAndColumnProperties(string engine, string sqlText) { var account = new Account(name: $"popular", color: $"blue", currency: "US"); var query = new Query("Account").AsInsert(account); - var c = Compile(query); - - Assert.Equal( - "INSERT INTO [Account] ([name], [currency_id]) VALUES ('popular', 'US')", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO \"ACCOUNT\" (\"NAME\", \"CURRENCY_ID\") VALUES ('popular', 'US')", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InsertFromRaw() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO Table.With.Dots ([Name], [Age]) VALUES ('The User', '2018-01-01')")] + public void InsertFromRaw(string engine, string sqlText) { var query = new Query() .FromRaw("Table.With.Dots") @@ -189,11 +157,9 @@ public void InsertFromRaw() Age = new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc), }); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO Table.With.Dots ([Name], [Age]) VALUES ('The User', '2018-01-01')", - c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -210,12 +176,14 @@ public void InsertFromQueryShouldFail() Assert.Throws(() => { - Compile(query); + CompileFor(EngineCodes.Generic, query); }); } - [Fact] - public void InsertKeyValuePairs() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')")] + public void InsertKeyValuePairs(string engine, string sqlText) { var dictionaryUser = new Dictionary { @@ -227,19 +195,15 @@ public void InsertKeyValuePairs() var query = new Query("Table") .AsInsert(dictionaryUser); - var c = Compile(query); - - Assert.Equal( - "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InsertDictionary() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')")] + public void InsertDictionary(string engine, string sqlText) { var dictionaryUser = new Dictionary { { "Name", "The User" }, @@ -249,19 +213,15 @@ public void InsertDictionary() var query = new Query("Table") .AsInsert(dictionaryUser); - var c = Compile(query); - - Assert.Equal( - "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InsertReadOnlyDictionary() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')")] + public void InsertReadOnlyDictionary(string engine, string sqlText) { var dictionaryUser = new ReadOnlyDictionary( new Dictionary @@ -273,19 +233,15 @@ public void InsertReadOnlyDictionary() var query = new Query("Table") .AsInsert(dictionaryUser); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')", - c[EngineCodes.SqlServer]); - - Assert.Equal( - "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void InsertExpandoObject() + [Theory] + [InlineData(EngineCodes.SqlServer, "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')")] + [InlineData(EngineCodes.Firebird, "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')")] + public void InsertExpandoObject(string engine, string sqlText) { dynamic expandoUser = new ExpandoObject(); expandoUser.Name = "The User"; @@ -294,15 +250,9 @@ public void InsertExpandoObject() var query = new Query("Table") .AsInsert(expandoUser); - var c = Compile(query); - - Assert.Equal( - "INSERT INTO [Table] ([Name], [Age]) VALUES ('The User', '2018-01-01')", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "INSERT INTO \"TABLE\" (\"NAME\", \"AGE\") VALUES ('The User', '2018-01-01')", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } } } diff --git a/QueryBuilder.Tests/MySqlExecutionTest.cs b/QueryBuilder.Tests/MySql/MySqlExecutionTest.cs similarity index 92% rename from QueryBuilder.Tests/MySqlExecutionTest.cs rename to QueryBuilder.Tests/MySql/MySqlExecutionTest.cs index 07df93c8..e614e4f7 100644 --- a/QueryBuilder.Tests/MySqlExecutionTest.cs +++ b/QueryBuilder.Tests/MySql/MySqlExecutionTest.cs @@ -1,13 +1,9 @@ -using SqlKata.Compilers; -using Xunit; -using SqlKata.Execution; +using Microsoft.Extensions.Configuration; using MySql.Data.MySqlClient; -using System; -using System.Linq; -using static SqlKata.Expressions; -using System.Collections.Generic; +using SqlKata.Execution; +using SqlKata.Tests.Infrastructure; -namespace SqlKata.Tests +namespace SqlKata.Tests.MySql { public class MySqlExecutionTest { @@ -213,12 +209,12 @@ public void BasicSelectFilter() // 2020 {"2020-01-01", 10}, {"2020-05-01", 20}, - + // 2021 {"2021-01-01", 40}, {"2021-02-01", 10}, {"2021-04-01", -10}, - + // 2022 {"2022-01-01", 80}, {"2022-02-01", -30}, @@ -249,14 +245,19 @@ public void BasicSelectFilter() db.Drop("Transaction"); } - QueryFactory DB() + private static string GetConnectionString() { - var host = System.Environment.GetEnvironmentVariable("SQLKATA_MYSQL_HOST"); - var user = System.Environment.GetEnvironmentVariable("SQLKATA_MYSQL_USER"); - var dbName = System.Environment.GetEnvironmentVariable("SQLKATA_MYSQL_DB"); - var cs = $"server={host};user={user};database={dbName}"; + var config = new ConfigurationBuilder() + .AddUserSecrets(typeof(MySqlExecutionTest).Assembly) + .Build(); + return config.GetConnectionString("MySqlExecutionTest"); + } + + private static Lazy ConnectionString { get; } = new(GetConnectionString); - var connection = new MySqlConnection(cs); + QueryFactory DB() + { + var connection = new MySqlConnection(ConnectionString.Value); var db = new QueryFactory(connection, new MySqlCompiler()); @@ -266,4 +267,4 @@ QueryFactory DB() } -} \ No newline at end of file +} diff --git a/QueryBuilder.Tests/MySql/MySqlLimitTests.cs b/QueryBuilder.Tests/MySql/MySqlLimitTests.cs index 3e22c19a..6925355c 100644 --- a/QueryBuilder.Tests/MySql/MySqlLimitTests.cs +++ b/QueryBuilder.Tests/MySql/MySqlLimitTests.cs @@ -1,34 +1,32 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.MySql { public class MySqlLimitTests : TestSupport { - private readonly MySqlCompiler compiler; + private readonly Compiler compiler; public MySqlLimitTests() { - compiler = Compilers.Get(EngineCodes.MySql); + compiler = CreateCompiler(EngineCodes.MySql); } [Fact] public void WithNoLimitNorOffset() { var query = new Query("Table"); - var ctx = new SqlResult("?", "\\") {Query = query}; + var ctx = compiler.Compile(query); - Assert.Null(compiler.CompileLimit(ctx)); + Assert.Equal("SELECT * FROM `Table`", ctx.RawSql); } [Fact] public void WithNoOffset() { var query = new Query("Table").Limit(10); - var ctx = new SqlResult("?", "\\") {Query = query}; + var ctx = compiler.Compile(query); - Assert.Equal("LIMIT ?", compiler.CompileLimit(ctx)); + Assert.Equal("SELECT * FROM `Table` LIMIT ?", ctx.RawSql); Assert.Equal(10, ctx.Bindings[0]); } @@ -36,9 +34,9 @@ public void WithNoOffset() public void WithNoLimit() { var query = new Query("Table").Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; + var ctx = compiler.Compile(query); - Assert.Equal("LIMIT 18446744073709551615 OFFSET ?", compiler.CompileLimit(ctx)); + Assert.Equal("SELECT * FROM `Table` LIMIT 18446744073709551615 OFFSET ?", ctx.RawSql); Assert.Equal(20L, ctx.Bindings[0]); Assert.Single(ctx.Bindings); } @@ -47,9 +45,9 @@ public void WithNoLimit() public void WithLimitAndOffset() { var query = new Query("Table").Limit(5).Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; + var ctx = compiler.Compile(query); - Assert.Equal("LIMIT ? OFFSET ?", compiler.CompileLimit(ctx)); + Assert.Equal("SELECT * FROM `Table` LIMIT ? OFFSET ?", ctx.RawSql); Assert.Equal(5, ctx.Bindings[0]); Assert.Equal(20L, ctx.Bindings[1]); Assert.Equal(2, ctx.Bindings.Count); diff --git a/QueryBuilder.Tests/OperatorWhitelistTests.cs b/QueryBuilder.Tests/OperatorWhitelistTests.cs index 55c3aafc..7c8e6867 100644 --- a/QueryBuilder.Tests/OperatorWhitelistTests.cs +++ b/QueryBuilder.Tests/OperatorWhitelistTests.cs @@ -1,34 +1,34 @@ -using System; -using SqlKata.Compilers; -using Xunit; +using SqlKata.Tests.Infrastructure; +using SqlKata.Tests.Infrastructure.TestCompilers; namespace SqlKata.Tests { - public class OperatorWhitelistTests + public class OperatorWhitelistTests : TestSupport { - - public OperatorWhitelistTests() + public static TheoryData AllowedOperators = new() { - - } + "=", "<", ">", "<=", ">=", "<>", "!=", "<=>", + "like", "not like", + "ilike", "not ilike", + "like binary", "not like binary", + "rlike", "not rlike", + "regexp", "not regexp", + "similar to", "not similar to" + }; [Theory] [InlineData("!!")] [InlineData("~!")] [InlineData("*=")] + [InlineData("")] public void DenyInvalidOperatorsInWhere(string op) { - var compiler = new SqlServerCompiler(); + var compiler = new TestCompiler(); Assert.Throws(() => { - compiler.Compile(new Query("Table").Where("Id", op, 1)); - compiler.Compile(new Query("Table").OrWhere("Id", op, 1)); - compiler.Compile(new Query("Table").WhereNot("Id", op, 1)); - compiler.Compile(new Query("Table").OrWhereNot("Id", op, 1)); - - compiler.Compile(new Query("Table").WhereColumns("Col1", op, "Col2")); - compiler.Compile(new Query("Table").OrWhereColumns("Col1", op, "Col2")); + var query = new Query("Table").Where("Id", op, 1); + compiler.Compile(query); }); } @@ -36,51 +36,37 @@ public void DenyInvalidOperatorsInWhere(string op) [InlineData("!!")] [InlineData("~!")] [InlineData("*=")] + [InlineData("")] public void DenyInvalidOperatorsInHaving(string op) { - var compiler = new SqlServerCompiler(); + var compiler = new TestCompiler(); Assert.Throws(() => { - compiler.Compile(new Query("Table").Having("Id", op, 1)); - compiler.Compile(new Query("Table").OrHaving("Id", op, 1)); - compiler.Compile(new Query("Table").HavingNot("Id", op, 1)); - compiler.Compile(new Query("Table").OrHavingNot("Id", op, 1)); - - compiler.Compile(new Query("Table").HavingColumns("Col1", op, "Col2")); - compiler.Compile(new Query("Table").OrHavingColumns("Col1", op, "Col2")); + var query = new Query("Table").Having("Id", op, 1); + compiler.Compile(query); }); } - [Theory] - [InlineData("=")] - [InlineData("!=")] - [InlineData("ilike")] + [MemberData(nameof(AllowedOperators))] public void AllowValidOperatorsInWhere(string op) { - new Query("Table").Where("Id", op, 1); - new Query("Table").OrWhere("Id", op, 1); - new Query("Table").WhereNot("Id", op, 1); - new Query("Table").OrWhereNot("Id", op, 1); + var query = new Query("Table").Where("Id", op, 1); + + var result = CompileFor(EngineCodes.Generic, query); - new Query("Table").WhereColumns("Col1", op, "Col2"); - new Query("Table").OrWhereColumns("Col1", op, "Col2"); + Assert.Equal($"""SELECT * FROM "Table" WHERE "Id" {op} 1""", result.ToString()); } [Theory] - [InlineData("=")] - [InlineData("!=")] - [InlineData("ilike")] + [MemberData(nameof(AllowedOperators))] public void AllowValidOperatorsInHaving(string op) { - new Query("Table").Having("Id", op, 1); - new Query("Table").OrHaving("Id", op, 1); - new Query("Table").HavingNot("Id", op, 1); - new Query("Table").OrHavingNot("Id", op, 1); + var query = new Query("Table").Having("Id", op, 1); + var result = CompileFor(EngineCodes.Generic, query); - new Query("Table").HavingColumns("Col1", op, "Col2"); - new Query("Table").OrHavingColumns("Col1", op, "Col2"); + Assert.Equal($"""SELECT * FROM "Table" HAVING "Id" {op} 1""", result.ToString()); } [Theory] @@ -93,46 +79,38 @@ public void AllowValidOperatorsInHaving(string op) [InlineData("!~*")] public void ShouldNotThrowAfterWhiteListing(string op) { - var compiler = new SqlServerCompiler().Whitelist(op); + var query = new Query("Table").Where("Id", op, 1); - var query = new Query("Table"); + var result = CompileFor( + EngineCodes.Generic, + query, + compiler => compiler.Whitelist(op)); - compiler.Compile(query.Clone().Where("Id", op, 1)); - compiler.Compile(query.Clone().OrWhere("Id", op, 1)); - compiler.Compile(query.Clone().WhereNot("Id", op, 1)); - compiler.Compile(query.Clone().OrWhereNot("Id", op, 1)); + Assert.Equal($"""SELECT * FROM "Table" WHERE "Id" {op} 1""", result.ToString()); - compiler.Compile(query.Clone().WhereColumns("Col1", op, "Col2")); - compiler.Compile(query.Clone().OrWhereColumns("Col1", op, "Col2")); - - compiler.Compile(query.Clone().Having("Id", op, 1)); - compiler.Compile(query.Clone().OrHaving("Id", op, 1)); - compiler.Compile(query.Clone().HavingNot("Id", op, 1)); - compiler.Compile(query.Clone().OrHavingNot("Id", op, 1)); - - compiler.Compile(query.Clone().HavingColumns("Col1", op, "Col2")); - compiler.Compile(query.Clone().OrHavingColumns("Col1", op, "Col2")); } [Fact] public void ShouldAllowWhiteListedOperatorsInNestedWhere() { - var compiler = new SqlServerCompiler().Whitelist("!!"); - var query = new Query("Table") .Where(q => q.Where("A", "!!", "value")); - compiler.Compile(query); + var result = CompileFor(EngineCodes.Generic, query, compiler => compiler.Whitelist("!!")); + + Assert.Equal("""SELECT * FROM "Table" WHERE ("A" !! 'value')""", result.ToString()); } [Fact] public void ShouldNotConsiderWhereRawCondition() { - var compiler = new SqlServerCompiler(); - var query = new Query("Table") .WhereRaw("Col !! value"); + var result = CompileFor(EngineCodes.Generic, query); + + Assert.Equal("""SELECT * FROM "Table" WHERE Col !! value""", result.ToString()); + } } diff --git a/QueryBuilder.Tests/Oracle/OracleDateConditionTests.cs b/QueryBuilder.Tests/Oracle/OracleDateConditionTests.cs index 57a5605e..c91d72fa 100644 --- a/QueryBuilder.Tests/Oracle/OracleDateConditionTests.cs +++ b/QueryBuilder.Tests/Oracle/OracleDateConditionTests.cs @@ -1,6 +1,4 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.Oracle { @@ -9,11 +7,11 @@ public class OracleDateConditionTests : TestSupport private const string TableName = "Table"; private const string SqlPlaceholder = "GENERATED_SQL"; - private readonly OracleCompiler compiler; + private readonly Compiler compiler; public OracleDateConditionTests() { - compiler = Compilers.Get(EngineCodes.Oracle); + compiler = CreateCompiler(EngineCodes.Oracle); } [Fact] diff --git a/QueryBuilder.Tests/Oracle/OracleInsertManyTests.cs b/QueryBuilder.Tests/Oracle/OracleInsertManyTests.cs index f25cf2ba..2c366503 100644 --- a/QueryBuilder.Tests/Oracle/OracleInsertManyTests.cs +++ b/QueryBuilder.Tests/Oracle/OracleInsertManyTests.cs @@ -1,17 +1,15 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.Oracle { public class OracleInsertManyTests : TestSupport { private const string TableName = "Table"; - private readonly OracleCompiler compiler; + private readonly Compiler compiler; public OracleInsertManyTests() { - compiler = Compilers.Get(EngineCodes.Oracle); + compiler = CreateCompiler(EngineCodes.Oracle); } [Fact] diff --git a/QueryBuilder.Tests/Oracle/OracleLegacyLimitTests.cs b/QueryBuilder.Tests/Oracle/OracleLegacyLimitTests.cs index 47a233dd..d19af76e 100644 --- a/QueryBuilder.Tests/Oracle/OracleLegacyLimitTests.cs +++ b/QueryBuilder.Tests/Oracle/OracleLegacyLimitTests.cs @@ -1,6 +1,4 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.Oracle { @@ -8,12 +6,11 @@ public class OracleLegacyLimitTests : TestSupport { private const string TableName = "Table"; private const string SqlPlaceholder = "GENERATED_SQL"; - private readonly OracleCompiler compiler; + private readonly Compiler compiler; public OracleLegacyLimitTests() { - compiler = Compilers.Get(EngineCodes.Oracle); - compiler.UseLegacyPagination = true; + compiler = CreateCompiler(EngineCodes.Oracle, useLegacyPagination: true); } [Fact] @@ -21,13 +18,12 @@ public void WithNoLimitNorOffset() { // Arrange: var query = new Query(TableName); - var ctx = new SqlResult("?", "\\") { Query = query, RawSql = SqlPlaceholder }; // Act: - compiler.ApplyLegacyLimit(ctx); + var ctx = compiler.Compile(query); // Assert: - Assert.Equal(SqlPlaceholder, ctx.RawSql); + Assert.Equal("SELECT * FROM \"Table\"", ctx.RawSql); } [Fact] @@ -35,13 +31,12 @@ public void WithNoOffset() { // Arrange: var query = new Query(TableName).Limit(10); - var ctx = new SqlResult("?", "\\") { Query = query, RawSql = SqlPlaceholder }; // Act: - compiler.ApplyLegacyLimit(ctx); + var ctx = compiler.Compile(query); // Assert: - Assert.Matches($"SELECT \\* FROM \\({SqlPlaceholder}\\) WHERE ROWNUM <= ?", ctx.RawSql); + Assert.Equal("SELECT * FROM (SELECT * FROM \"Table\") WHERE ROWNUM <= ?", ctx.RawSql); Assert.Equal(10, ctx.Bindings[0]); Assert.Single(ctx.Bindings); } @@ -51,13 +46,12 @@ public void WithNoLimit() { // Arrange: var query = new Query(TableName).Offset(20); - var ctx = new SqlResult("?", "\\") { Query = query, RawSql = SqlPlaceholder }; // Act: - compiler.ApplyLegacyLimit(ctx); + var ctx = compiler.Compile(query); // Assert: - Assert.Equal("SELECT * FROM (SELECT \"results_wrapper\".*, ROWNUM \"row_num\" FROM (GENERATED_SQL) \"results_wrapper\") WHERE \"row_num\" > ?", ctx.RawSql); + Assert.Equal("SELECT * FROM (SELECT \"results_wrapper\".*, ROWNUM \"row_num\" FROM (SELECT * FROM \"Table\") \"results_wrapper\") WHERE \"row_num\" > ?", ctx.RawSql); Assert.Equal(20L, ctx.Bindings[0]); Assert.Single(ctx.Bindings); } @@ -67,13 +61,12 @@ public void WithLimitAndOffset() { // Arrange: var query = new Query(TableName).Limit(5).Offset(20); - var ctx = new SqlResult("?", "\\") { Query = query, RawSql = SqlPlaceholder }; // Act: - compiler.ApplyLegacyLimit(ctx); + var ctx = compiler.Compile(query); // Assert: - Assert.Equal("SELECT * FROM (SELECT \"results_wrapper\".*, ROWNUM \"row_num\" FROM (GENERATED_SQL) \"results_wrapper\" WHERE ROWNUM <= ?) WHERE \"row_num\" > ?", ctx.RawSql); + Assert.Equal("SELECT * FROM (SELECT \"results_wrapper\".*, ROWNUM \"row_num\" FROM (SELECT * FROM \"Table\") \"results_wrapper\" WHERE ROWNUM <= ?) WHERE \"row_num\" > ?", ctx.RawSql); Assert.Equal(25L, ctx.Bindings[0]); Assert.Equal(20L, ctx.Bindings[1]); Assert.Equal(2, ctx.Bindings.Count); diff --git a/QueryBuilder.Tests/Oracle/OracleLimitTests.cs b/QueryBuilder.Tests/Oracle/OracleLimitTests.cs index 9701705c..8354f39f 100644 --- a/QueryBuilder.Tests/Oracle/OracleLimitTests.cs +++ b/QueryBuilder.Tests/Oracle/OracleLimitTests.cs @@ -1,6 +1,4 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.Oracle { @@ -9,11 +7,11 @@ public class OracleLimitTests : TestSupport private const string TableName = "Table"; private const string SqlPlaceholder = "GENERATED_SQL"; - private readonly OracleCompiler compiler; + private readonly Compiler compiler; public OracleLimitTests() { - compiler = Compilers.Get(EngineCodes.Oracle); + compiler = CreateCompiler(EngineCodes.Oracle); } [Fact] @@ -21,10 +19,12 @@ public void NoLimitNorOffset() { // Arrange: var query = new Query(TableName); - var ctx = new SqlResult("?", "\\") { Query = query, RawSql = SqlPlaceholder }; - // Act & Assert: - Assert.Null(compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\"", ctx.RawSql); } [Fact] @@ -32,10 +32,12 @@ public void LimitOnly() { // Arrange: var query = new Query(TableName).Limit(10); - var ctx = new SqlResult("?", "\\") { Query = query, RawSql = SqlPlaceholder }; - // Act & Assert: - Assert.EndsWith("OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\" ORDER BY (SELECT 0 FROM DUAL) OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", ctx.RawSql); Assert.Equal(2, ctx.Bindings.Count); Assert.Equal(0L, ctx.Bindings[0]); Assert.Equal(10, ctx.Bindings[1]); @@ -46,11 +48,12 @@ public void OffsetOnly() { // Arrange: var query = new Query(TableName).Offset(20); - var ctx = new SqlResult("?", "\\") { Query = query, RawSql = SqlPlaceholder }; - // Act & Assert: - Assert.EndsWith("OFFSET ? ROWS", compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + // Assert: + Assert.Equal("SELECT * FROM \"Table\" ORDER BY (SELECT 0 FROM DUAL) OFFSET ? ROWS", ctx.RawSql); Assert.Single(ctx.Bindings); Assert.Equal(20L, ctx.Bindings[0]); } @@ -60,16 +63,15 @@ public void LimitAndOffset() { // Arrange: var query = new Query(TableName).Limit(5).Offset(20); - var ctx = new SqlResult("?", "\\") { Query = query, RawSql = SqlPlaceholder }; - - // Act & Assert: - Assert.EndsWith("OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", compiler.CompileLimit(ctx)); - Assert.Equal(2, ctx.Bindings.Count); - Assert.Equal(20L, ctx.Bindings[0]); - Assert.Equal(5, ctx.Bindings[1]); + // Act + var result = compiler.Compile(query); - compiler.CompileLimit(ctx); + // Assert: + Assert.Equal("SELECT * FROM \"Table\" ORDER BY (SELECT 0 FROM DUAL) OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", result.RawSql); + Assert.Equal(2, result.Bindings.Count); + Assert.Equal(20L, result.Bindings[0]); + Assert.Equal(5, result.Bindings[1]); } } } diff --git a/QueryBuilder.Tests/ParameterTypeTests.cs b/QueryBuilder.Tests/ParameterTypeTests.cs index 095a6e53..39263e1e 100644 --- a/QueryBuilder.Tests/ParameterTypeTests.cs +++ b/QueryBuilder.Tests/ParameterTypeTests.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using SqlKata.Compilers; -using Xunit; using System.Collections; using SqlKata.Tests.Infrastructure; @@ -22,9 +17,9 @@ public class ParameterTypeGenerator : IEnumerable private readonly List _data = new List { new object[] {"1", 1}, - new object[] {Convert.ToSingle("10.5", CultureInfo.InvariantCulture).ToString(), 10.5}, + new object[] {"10.5", 10.5}, new object[] {"-2", -2}, - new object[] {Convert.ToSingle("-2.8", CultureInfo.InvariantCulture).ToString(), -2.8}, + new object[] {"-2.8", -2.8}, new object[] {"cast(1 as bit)", true}, new object[] {"cast(0 as bit)", false}, new object[] {"'2018-10-28 19:22:00'", new DateTime(2018, 10, 28, 19, 22, 0)}, @@ -44,9 +39,9 @@ public void CorrectParameterTypeOutput(string rendered, object input) { var query = new Query("Table").Where("Col", input); - var c = Compile(query); + var c = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal($"SELECT * FROM [Table] WHERE [Col] = {rendered}", c[EngineCodes.SqlServer]); + Assert.Equal($"SELECT * FROM [Table] WHERE [Col] = {rendered}", c.ToString()); } } } diff --git a/QueryBuilder.Tests/PostgreSql/PostgreSqlLimitTests.cs b/QueryBuilder.Tests/PostgreSql/PostgreSqlLimitTests.cs index 169fb99d..34e8076e 100644 --- a/QueryBuilder.Tests/PostgreSql/PostgreSqlLimitTests.cs +++ b/QueryBuilder.Tests/PostgreSql/PostgreSqlLimitTests.cs @@ -1,34 +1,38 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.PostgreSql { public class PostgreSqlLimitTests : TestSupport { - private readonly PostgresCompiler compiler; + private readonly Compiler compiler; public PostgreSqlLimitTests() { - compiler = Compilers.Get(EngineCodes.PostgreSql); + compiler = CreateCompiler(EngineCodes.PostgreSql); } [Fact] public void WithNoLimitNorOffset() { var query = new Query("Table"); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\"", ctx.RawSql); } [Fact] public void WithNoOffset() { var query = new Query("Table").Limit(10); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Equal("LIMIT ?", compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\" LIMIT ?", ctx.RawSql); Assert.Equal(10, ctx.Bindings[0]); } @@ -36,9 +40,12 @@ public void WithNoOffset() public void WithNoLimit() { var query = new Query("Table").Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Equal("OFFSET ?", compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\" OFFSET ?", ctx.RawSql); Assert.Equal(20L, ctx.Bindings[0]); Assert.Single(ctx.Bindings); } @@ -47,9 +54,12 @@ public void WithNoLimit() public void WithLimitAndOffset() { var query = new Query("Table").Limit(5).Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Equal("LIMIT ? OFFSET ?", compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\" LIMIT ? OFFSET ?", ctx.RawSql); Assert.Equal(5, ctx.Bindings[0]); Assert.Equal(20L, ctx.Bindings[1]); Assert.Equal(2, ctx.Bindings.Count); diff --git a/QueryBuilder.Tests/QueryBuilder.Tests.csproj b/QueryBuilder.Tests/QueryBuilder.Tests.csproj index 92829215..3616518a 100755 --- a/QueryBuilder.Tests/QueryBuilder.Tests.csproj +++ b/QueryBuilder.Tests/QueryBuilder.Tests.csproj @@ -1,14 +1,18 @@ - net6.0 Library false + true SqlKata.Tests + net8.0 + c675ce13-c233-4a60-9fcc-dadf8f5238ca + + - + @@ -16,4 +20,4 @@ - \ No newline at end of file + diff --git a/QueryBuilder.Tests/SelectTests.cs b/QueryBuilder.Tests/SelectTests.cs index 647187b9..5c896233 100644 --- a/QueryBuilder.Tests/SelectTests.cs +++ b/QueryBuilder.Tests/SelectTests.cs @@ -1,220 +1,239 @@ -using SqlKata.Compilers; using SqlKata.Extensions; using SqlKata.Tests.Infrastructure; -using System; -using System.Collections.Generic; -using Xunit; namespace SqlKata.Tests { public class SelectTests : TestSupport { - [Fact] - public void BasicSelect() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [id], [name] FROM [users]")] + [InlineData(EngineCodes.MySql, "SELECT `id`, `name` FROM `users`")] + [InlineData(EngineCodes.PostgreSql, "SELECT \"id\", \"name\" FROM \"users\"")] + [InlineData(EngineCodes.Firebird, "SELECT \"ID\", \"NAME\" FROM \"USERS\"")] + [InlineData(EngineCodes.Oracle, "SELECT \"id\", \"name\" FROM \"users\"")] + public void BasicSelect(string engine, string sqlText) { - var q = new Query().From("users").Select("id", "name"); - var c = Compile(q); + var query = new Query().From("users").Select("id", "name"); - Assert.Equal("SELECT [id], [name] FROM [users]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT `id`, `name` FROM `users`", c[EngineCodes.MySql]); - Assert.Equal("SELECT \"id\", \"name\" FROM \"users\"", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT \"ID\", \"NAME\" FROM \"USERS\"", c[EngineCodes.Firebird]); - Assert.Equal("SELECT \"id\", \"name\" FROM \"users\"", c[EngineCodes.Oracle]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void BasicSelectEnumerable() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [id], [name] FROM [users]")] + [InlineData(EngineCodes.MySql, "SELECT `id`, `name` FROM `users`")] + [InlineData(EngineCodes.PostgreSql, "SELECT \"id\", \"name\" FROM \"users\"")] + [InlineData(EngineCodes.Firebird, "SELECT \"ID\", \"NAME\" FROM \"USERS\"")] + [InlineData(EngineCodes.Oracle, "SELECT \"id\", \"name\" FROM \"users\"")] + public void BasicSelectEnumerable(string engine, string sqlText) { - var q = new Query().From("users").Select(new List() { "id", "name" }); - var c = Compile(q); + var query = new Query().From("users").Select(new List() { "id", "name" }); + + var result = CompileFor(engine, query); - Assert.Equal("SELECT [id], [name] FROM [users]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT `id`, `name` FROM `users`", c[EngineCodes.MySql]); - Assert.Equal("SELECT \"id\", \"name\" FROM \"users\"", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT \"ID\", \"NAME\" FROM \"USERS\"", c[EngineCodes.Firebird]); - Assert.Equal("SELECT \"id\", \"name\" FROM \"users\"", c[EngineCodes.Oracle]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void BasicSelectWhereBindingIsEmptyOrNull() - { - var q = new Query() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [id], [name] FROM [users] WHERE [author] = '' OR [author] IS NULL")] + [InlineData(EngineCodes.MySql, "SELECT `id`, `name` FROM `users` WHERE `author` = '' OR `author` IS NULL")] + [InlineData(EngineCodes.PostgreSql, + "SELECT \"id\", \"name\" FROM \"users\" WHERE \"author\" = '' OR \"author\" IS NULL")] + [InlineData(EngineCodes.Firebird, + "SELECT \"ID\", \"NAME\" FROM \"USERS\" WHERE \"AUTHOR\" = '' OR \"AUTHOR\" IS NULL")] + [InlineData(EngineCodes.Oracle, + "SELECT \"id\", \"name\" FROM \"users\" WHERE \"author\" = '' OR \"author\" IS NULL")] + public void BasicSelectWhereBindingIsEmptyOrNull(string engine, string sqlText) + { + var query = new Query() .From("users") .Select("id", "name") .Where("author", "") .OrWhere("author", null); - var c = Compile(q); + var result = CompileFor(engine, query); - Assert.Equal("SELECT [id], [name] FROM [users] WHERE [author] = '' OR [author] IS NULL", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT `id`, `name` FROM `users` WHERE `author` = '' OR `author` IS NULL", c[EngineCodes.MySql]); - Assert.Equal("SELECT \"id\", \"name\" FROM \"users\" WHERE \"author\" = '' OR \"author\" IS NULL", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT \"ID\", \"NAME\" FROM \"USERS\" WHERE \"AUTHOR\" = '' OR \"AUTHOR\" IS NULL", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void BasicSelectWithAlias() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [id], [name] FROM [users] AS [u]")] + [InlineData(EngineCodes.MySql, "SELECT `id`, `name` FROM `users` AS `u`")] + [InlineData(EngineCodes.PostgreSql, "SELECT \"id\", \"name\" FROM \"users\" AS \"u\"")] + [InlineData(EngineCodes.Firebird, "SELECT \"ID\", \"NAME\" FROM \"USERS\" AS \"U\"")] + [InlineData(EngineCodes.Oracle, "SELECT \"id\", \"name\" FROM \"users\" \"u\"")] + public void BasicSelectWithAlias(string engine, string sqlText) { - var q = new Query().From("users as u").Select("id", "name"); - var c = Compile(q); + var query = new Query().From("users as u").Select("id", "name"); + + var result = CompileFor(engine, query); - Assert.Equal("SELECT [id], [name] FROM [users] AS [u]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT `id`, `name` FROM `users` AS `u`", c[EngineCodes.MySql]); - Assert.Equal("SELECT \"id\", \"name\" FROM \"users\" AS \"u\"", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT \"ID\", \"NAME\" FROM \"USERS\" AS \"U\"", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void ExpandedSelect() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [users].[id], [users].[name], [users].[age] FROM [users]")] + [InlineData(EngineCodes.MySql, "SELECT `users`.`id`, `users`.`name`, `users`.`age` FROM `users`")] + public void ExpandedSelect(string engine, string sqlText) { - var q = new Query().From("users").Select("users.{id,name, age}"); - var c = Compile(q); + var query = new Query().From("users").Select("users.{id,name, age}"); + + var result = CompileFor(engine, query); - Assert.Equal("SELECT [users].[id], [users].[name], [users].[age] FROM [users]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT `users`.`id`, `users`.`name`, `users`.`age` FROM `users`", c[EngineCodes.MySql]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void ExpandedSelectMultiline() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [users].[id], [users].[name] AS [Name], [users].[age] FROM [users]")] + [InlineData(EngineCodes.MySql, "SELECT `users`.`id`, `users`.`name` AS `Name`, `users`.`age` FROM `users`")] + public void ExpandedSelectMultiline(string engine, string sqlText) { - var q = new Query().From("users").Select(@"users.{ + var query = new Query().From("users").Select(@"users.{ id, name as Name, age }"); - var c = Compile(q); - Assert.Equal("SELECT [users].[id], [users].[name] AS [Name], [users].[age] FROM [users]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT `users`.`id`, `users`.`name` AS `Name`, `users`.`age` FROM `users`", c[EngineCodes.MySql]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } [Fact] public void ExpandedSelectWithSchema() { - var q = new Query().From("users").Select("dbo.users.{id,name, age}"); - var c = Compile(q); + var query = new Query().From("users").Select("dbo.users.{id,name, age}"); + var result = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal("SELECT [dbo].[users].[id], [dbo].[users].[name], [dbo].[users].[age] FROM [users]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT [dbo].[users].[id], [dbo].[users].[name], [dbo].[users].[age] FROM [users]", + result.ToString()); } [Fact] public void ExpandedSelectMultilineWithSchema() { - var q = new Query().From("users").Select(@"dbo.users.{ + var query = new Query().From("users").Select(@"dbo.users.{ id, name as Name, age }"); - var c = Compile(q); + var result = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal("SELECT [dbo].[users].[id], [dbo].[users].[name] AS [Name], [dbo].[users].[age] FROM [users]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT [dbo].[users].[id], [dbo].[users].[name] AS [Name], [dbo].[users].[age] FROM [users]", + result.ToString()); } - [Fact] - public void NestedEmptyWhereAtFirstCondition() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [table] WHERE [id] = 1")] + [InlineData(EngineCodes.Firebird, "SELECT * FROM \"TABLE\" WHERE \"ID\" = 1")] + public void NestedEmptyWhereAtFirstCondition(string engine, string sqlText) { var query = new Query("table") - .Where(q => new Query()) + .Where(_ => new Query()) .Where("id", 1); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [table] WHERE [id] = 1", c[EngineCodes.SqlServer]); - + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM \"TABLE\" WHERE \"ID\" = 1", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void WhereTrue() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table] WHERE [IsActive] = cast(1 as bit)")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `Table` WHERE `IsActive` = true")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"Table\" WHERE \"IsActive\" = true")] + [InlineData(EngineCodes.Firebird, "SELECT * FROM \"TABLE\" WHERE \"ISACTIVE\" = 1")] + public void WhereTrue(string engine, string sqlText) { var query = new Query("Table").WhereTrue("IsActive"); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM [Table] WHERE [IsActive] = cast(1 as bit)", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM `Table` WHERE `IsActive` = true", c[EngineCodes.MySql]); - Assert.Equal("SELECT * FROM \"Table\" WHERE \"IsActive\" = true", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT * FROM \"TABLE\" WHERE \"ISACTIVE\" = 1", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void WhereFalse() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table] WHERE [IsActive] = cast(0 as bit)")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `Table` WHERE `IsActive` = false")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"Table\" WHERE \"IsActive\" = false")] + [InlineData(EngineCodes.Firebird, "SELECT * FROM \"TABLE\" WHERE \"ISACTIVE\" = 0")] + public void WhereFalse(string engine, string sqlText) { var query = new Query("Table").WhereFalse("IsActive"); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM [Table] WHERE [IsActive] = cast(0 as bit)", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM `Table` WHERE `IsActive` = false", c[EngineCodes.MySql]); - Assert.Equal("SELECT * FROM \"Table\" WHERE \"IsActive\" = false", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT * FROM \"TABLE\" WHERE \"ISACTIVE\" = 0", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void OrWhereFalse() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table] WHERE [MyCol] = 'abc' OR [IsActive] = cast(0 as bit)")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"Table\" WHERE \"MyCol\" = 'abc' OR \"IsActive\" = false")] + public void OrWhereFalse(string engine, string sqlText) { var query = new Query("Table").Where("MyCol", "abc").OrWhereFalse("IsActive"); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [Table] WHERE [MyCol] = 'abc' OR [IsActive] = cast(0 as bit)", c[EngineCodes.SqlServer]); - - Assert.Equal("SELECT * FROM \"Table\" WHERE \"MyCol\" = 'abc' OR \"IsActive\" = false", c[EngineCodes.PostgreSql]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void OrWhereTrue() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table] WHERE [MyCol] = 'abc' OR [IsActive] = cast(1 as bit)")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"Table\" WHERE \"MyCol\" = 'abc' OR \"IsActive\" = true")] + public void OrWhereTrue(string engine, string sqlText) { var query = new Query("Table").Where("MyCol", "abc").OrWhereTrue("IsActive"); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [Table] WHERE [MyCol] = 'abc' OR [IsActive] = cast(1 as bit)", c[EngineCodes.SqlServer]); - - Assert.Equal("SELECT * FROM \"Table\" WHERE \"MyCol\" = 'abc' OR \"IsActive\" = true", c[EngineCodes.PostgreSql]); + var result = CompileFor(engine, query); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void OrWhereNull() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table] WHERE [MyCol] = 'abc' OR [IsActive] IS NULL")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"Table\" WHERE \"MyCol\" = 'abc' OR \"IsActive\" IS NULL")] + public void OrWhereNull(string engine, string sqlText) { var query = new Query("Table").Where("MyCol", "abc").OrWhereNull("IsActive"); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [Table] WHERE [MyCol] = 'abc' OR [IsActive] IS NULL", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM \"Table\" WHERE \"MyCol\" = 'abc' OR \"IsActive\" IS NULL", c[EngineCodes.PostgreSql]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void WhereSub() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table] WHERE (SELECT COUNT(*) AS [count] FROM [Table2] WHERE [Table2].[Column] = [Table].[MyCol]) = 1")] + [InlineData(EngineCodes.PostgreSql, + "SELECT * FROM \"Table\" WHERE (SELECT COUNT(*) AS \"count\" FROM \"Table2\" WHERE \"Table2\".\"Column\" = \"Table\".\"MyCol\") = 1")] + public void WhereSub(string engine, string sqlText) { var subQuery = new Query("Table2").WhereColumns("Table2.Column", "=", "Table.MyCol").AsCount(); var query = new Query("Table").WhereSub(subQuery, 1); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [Table] WHERE (SELECT COUNT(*) AS [count] FROM [Table2] WHERE [Table2].[Column] = [Table].[MyCol]) = 1", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM \"Table\" WHERE (SELECT COUNT(*) AS \"count\" FROM \"Table2\" WHERE \"Table2\".\"Column\" = \"Table\".\"MyCol\") = 1", c[EngineCodes.PostgreSql]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void OrWhereSub() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table] WHERE [MyCol] IS NULL OR (SELECT COUNT(*) AS [count] FROM [Table2] WHERE [Table2].[Column] = [Table].[MyCol]) < 1")] + [InlineData(EngineCodes.PostgreSql, + "SELECT * FROM \"Table\" WHERE \"MyCol\" IS NULL OR (SELECT COUNT(*) AS \"count\" FROM \"Table2\" WHERE \"Table2\".\"Column\" = \"Table\".\"MyCol\") < 1")] + public void OrWhereSub(string engine, string sqlText) { var subQuery = new Query("Table2").WhereColumns("Table2.Column", "=", "Table.MyCol").AsCount(); var query = new Query("Table").WhereNull("MyCol").OrWhereSub(subQuery, "<", 1); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [Table] WHERE [MyCol] IS NULL OR (SELECT COUNT(*) AS [count] FROM [Table2] WHERE [Table2].[Column] = [Table].[MyCol]) < 1", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM \"Table\" WHERE \"MyCol\" IS NULL OR (SELECT COUNT(*) AS \"count\" FROM \"Table2\" WHERE \"Table2\".\"Column\" = \"Table\".\"MyCol\") < 1", c[EngineCodes.PostgreSql]); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -222,9 +241,9 @@ public void PassingArrayAsParameter() { var query = new Query("Table").WhereRaw("[Id] in (?)", new object[] { new object[] { 1, 2, 3 } }); - var c = Compile(query); + var result = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal("SELECT * FROM [Table] WHERE [Id] in (1,2,3)", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT * FROM [Table] WHERE [Id] in (1,2,3)", result.ToString()); } [Fact] @@ -232,131 +251,137 @@ public void UsingJsonArray() { var query = new Query("Table").WhereRaw("[Json]->'address'->>'country' in (?)", new[] { 1, 2, 3, 4 }); - var c = Compile(query); + var result = CompileFor(EngineCodes.PostgreSql, query); - Assert.Equal("SELECT * FROM \"Table\" WHERE \"Json\"->'address'->>'country' in (1,2,3,4)", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT * FROM \"Table\" WHERE \"Json\"->'address'->>'country' in (1,2,3,4)", + result.ToString()); } - [Fact] - public void Union() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Phones] UNION SELECT * FROM [Laptops]")] + [InlineData(EngineCodes.Sqlite, "SELECT * FROM \"Phones\" UNION SELECT * FROM \"Laptops\"")] + [InlineData(EngineCodes.Firebird, "SELECT * FROM \"PHONES\" UNION SELECT * FROM \"LAPTOPS\"")] + public void Union(string engine, string sqlText) { var laptops = new Query("Laptops"); var mobiles = new Query("Phones").Union(laptops); - var c = Compile(mobiles); + var result = CompileFor(engine, mobiles); - Assert.Equal("SELECT * FROM [Phones] UNION SELECT * FROM [Laptops]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM \"Phones\" UNION SELECT * FROM \"Laptops\"", c[EngineCodes.Sqlite]); - Assert.Equal("SELECT * FROM \"PHONES\" UNION SELECT * FROM \"LAPTOPS\"", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void UnionWithBindings() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Phones] UNION SELECT * FROM [Laptops] WHERE [Type] = 'A'")] + [InlineData(EngineCodes.Sqlite, + "SELECT * FROM \"Phones\" UNION SELECT * FROM \"Laptops\" WHERE \"Type\" = 'A'")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `Phones` UNION SELECT * FROM `Laptops` WHERE `Type` = 'A'")] + [InlineData(EngineCodes.Firebird, + "SELECT * FROM \"PHONES\" UNION SELECT * FROM \"LAPTOPS\" WHERE \"TYPE\" = 'A'")] + public void UnionWithBindings(string engine, string sqlText) { var laptops = new Query("Laptops").Where("Type", "A"); var mobiles = new Query("Phones").Union(laptops); - var c = Compile(mobiles); + var result = CompileFor(engine, mobiles); - Assert.Equal("SELECT * FROM [Phones] UNION SELECT * FROM [Laptops] WHERE [Type] = 'A'", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM \"Phones\" UNION SELECT * FROM \"Laptops\" WHERE \"Type\" = 'A'", c[EngineCodes.Sqlite]); - Assert.Equal("SELECT * FROM `Phones` UNION SELECT * FROM `Laptops` WHERE `Type` = 'A'", c[EngineCodes.MySql]); - Assert.Equal("SELECT * FROM \"PHONES\" UNION SELECT * FROM \"LAPTOPS\" WHERE \"TYPE\" = 'A'", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void RawUnionWithBindings() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Phones] UNION SELECT * FROM [Laptops] WHERE [Type] = 'A'")] + [InlineData(EngineCodes.Sqlite, + "SELECT * FROM \"Phones\" UNION SELECT * FROM \"Laptops\" WHERE \"Type\" = 'A'")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `Phones` UNION SELECT * FROM `Laptops` WHERE `Type` = 'A'")] + [InlineData(EngineCodes.Firebird, + "SELECT * FROM \"PHONES\" UNION SELECT * FROM \"Laptops\" WHERE \"Type\" = 'A'")] // Is this good? + public void RawUnionWithBindings(string engine, string sqlText) { var mobiles = new Query("Phones").UnionRaw("UNION SELECT * FROM [Laptops] WHERE [Type] = ?", "A"); - var c = Compile(mobiles); + var result = CompileFor(engine, mobiles); - Assert.Equal("SELECT * FROM [Phones] UNION SELECT * FROM [Laptops] WHERE [Type] = 'A'", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM `Phones` UNION SELECT * FROM `Laptops` WHERE `Type` = 'A'", c[EngineCodes.MySql]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void MultipleUnion() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Phones] UNION SELECT * FROM [Laptops] UNION SELECT * FROM [Tablets]")] + [InlineData(EngineCodes.Firebird, + "SELECT * FROM \"PHONES\" UNION SELECT * FROM \"LAPTOPS\" UNION SELECT * FROM \"TABLETS\"")] + public void MultipleUnion(string engine, string sqlText) { var laptops = new Query("Laptops"); var tablets = new Query("Tablets"); var mobiles = new Query("Phones").Union(laptops).Union(tablets); - var c = Compile(mobiles); - - Assert.Equal("SELECT * FROM [Phones] UNION SELECT * FROM [Laptops] UNION SELECT * FROM [Tablets]", - c[EngineCodes.SqlServer]); - + var result = CompileFor(engine, mobiles); - Assert.Equal("SELECT * FROM \"PHONES\" UNION SELECT * FROM \"LAPTOPS\" UNION SELECT * FROM \"TABLETS\"", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void MultipleUnionWithBindings() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Phones] WHERE [Price] < 3000 UNION SELECT * FROM [Laptops] WHERE [Price] > 1000 UNION SELECT * FROM [Tablets] WHERE [Price] > 2000")] + [InlineData(EngineCodes.Firebird, + "SELECT * FROM \"PHONES\" WHERE \"PRICE\" < 3000 UNION SELECT * FROM \"LAPTOPS\" WHERE \"PRICE\" > 1000 UNION SELECT * FROM \"TABLETS\" WHERE \"PRICE\" > 2000")] + public void MultipleUnionWithBindings(string engine, string sqlText) { var laptops = new Query("Laptops").Where("Price", ">", 1000); var tablets = new Query("Tablets").Where("Price", ">", 2000); var mobiles = new Query("Phones").Where("Price", "<", 3000).Union(laptops).Union(tablets); - var c = Compile(mobiles); + var result = CompileFor(engine, mobiles); - Assert.Equal( - "SELECT * FROM [Phones] WHERE [Price] < 3000 UNION SELECT * FROM [Laptops] WHERE [Price] > 1000 UNION SELECT * FROM [Tablets] WHERE [Price] > 2000", - c[EngineCodes.SqlServer]); - - - Assert.Equal( - "SELECT * FROM \"PHONES\" WHERE \"PRICE\" < 3000 UNION SELECT * FROM \"LAPTOPS\" WHERE \"PRICE\" > 1000 UNION SELECT * FROM \"TABLETS\" WHERE \"PRICE\" > 2000", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void MultipleUnionWithBindingsAndPagination() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Phones] WHERE [Price] < 3000 UNION SELECT * FROM [Laptops] WHERE [Price] > 1000 UNION ALL SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [Tablets] WHERE [Price] > 2000) AS [results_wrapper] WHERE [row_num] BETWEEN 16 AND 30")] + [InlineData(EngineCodes.Firebird, + "SELECT * FROM \"PHONES\" WHERE \"PRICE\" < 3000 UNION SELECT * FROM \"LAPTOPS\" WHERE \"PRICE\" > 1000 UNION ALL SELECT * FROM \"TABLETS\" WHERE \"PRICE\" > 2000 ROWS 16 TO 30")] + public void MultipleUnionWithBindingsAndPagination(string engine, string sqlText) { var laptops = new Query("Laptops").Where("Price", ">", 1000); var tablets = new Query("Tablets").Where("Price", ">", 2000).ForPage(2); var mobiles = new Query("Phones").Where("Price", "<", 3000).Union(laptops).UnionAll(tablets); + var result = CompileFor(engine, mobiles); - var c = Compile(mobiles); - - Assert.Equal( - "SELECT * FROM [Phones] WHERE [Price] < 3000 UNION SELECT * FROM [Laptops] WHERE [Price] > 1000 UNION ALL SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [Tablets] WHERE [Price] > 2000) AS [results_wrapper] WHERE [row_num] BETWEEN 16 AND 30", - c[EngineCodes.SqlServer]); - - - Assert.Equal( - "SELECT * FROM \"PHONES\" WHERE \"PRICE\" < 3000 UNION SELECT * FROM \"LAPTOPS\" WHERE \"PRICE\" > 1000 UNION ALL SELECT * FROM \"TABLETS\" WHERE \"PRICE\" > 2000 ROWS 16 TO 30", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UnionWithCallbacks() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Phones] WHERE [Price] < 3000 UNION SELECT * FROM [Laptops] UNION ALL SELECT * FROM [Tablets]")] + [InlineData(EngineCodes.Firebird, + "SELECT * FROM \"PHONES\" WHERE \"PRICE\" < 3000 UNION SELECT * FROM \"LAPTOPS\" UNION ALL SELECT * FROM \"TABLETS\"")] + public void UnionWithCallbacks(string engine, string sqlText) { var mobiles = new Query("Phones") .Where("Price", "<", 3000) .Union(q => q.From("Laptops")) .UnionAll(q => q.From("Tablets")); - var c = Compile(mobiles); + var result = CompileFor(engine, mobiles); - Assert.Equal( - "SELECT * FROM [Phones] WHERE [Price] < 3000 UNION SELECT * FROM [Laptops] UNION ALL SELECT * FROM [Tablets]", - c[EngineCodes.SqlServer]); - - - Assert.Equal( - "SELECT * FROM \"PHONES\" WHERE \"PRICE\" < 3000 UNION SELECT * FROM \"LAPTOPS\" UNION ALL SELECT * FROM \"TABLETS\"", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UnionWithDifferentEngine() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Phones] WHERE [Price] < 300 EXCEPT SELECT * FROM [Phones] WHERE NOT ([Os] = 'iOS') UNION ALL SELECT * FROM [Tablets] WHERE [Price] < 100")] + [InlineData(EngineCodes.MySql, + "SELECT * FROM `Phones` WHERE `Price` < 300 INTERSECT ALL SELECT * FROM `Watches` WHERE `Os` = 'Android' UNION ALL SELECT * FROM `Tablets` WHERE `Price` < 100")] + [InlineData(EngineCodes.PostgreSql, + "SELECT * FROM \"Phones\" WHERE \"Price\" < 300 UNION SELECT * FROM \"Laptops\" WHERE \"Price\" < 800 UNION ALL SELECT * FROM \"Tablets\" WHERE \"Price\" < 100")] + [InlineData(EngineCodes.Firebird, + "SELECT * FROM \"PHONES\" WHERE \"PRICE\" < 300 UNION SELECT * FROM \"LAPTOPS\" WHERE \"PRICE\" < 800 UNION ALL SELECT * FROM \"TABLETS\" WHERE \"PRICE\" < 100")] + public void UnionWithDifferentEngine(string engine, string sqlText) { var mobiles = new Query("Phones") .Where("Price", "<", 300) @@ -366,23 +391,9 @@ public void UnionWithDifferentEngine() .ForFirebird(scope => scope.Union(q => q.From("Laptops").Where("Price", "<", 800))) .UnionAll(q => q.From("Tablets").Where("Price", "<", 100)); - var c = Compile(mobiles); + var result = CompileFor(engine, mobiles); - Assert.Equal( - "SELECT * FROM [Phones] WHERE [Price] < 300 EXCEPT SELECT * FROM [Phones] WHERE NOT ([Os] = 'iOS') UNION ALL SELECT * FROM [Tablets] WHERE [Price] < 100", - c[EngineCodes.SqlServer]); - - Assert.Equal( - "SELECT * FROM `Phones` WHERE `Price` < 300 INTERSECT ALL SELECT * FROM `Watches` WHERE `Os` = 'Android' UNION ALL SELECT * FROM `Tablets` WHERE `Price` < 100", - c[EngineCodes.MySql]); - - Assert.Equal( - "SELECT * FROM \"Phones\" WHERE \"Price\" < 300 UNION SELECT * FROM \"Laptops\" WHERE \"Price\" < 800 UNION ALL SELECT * FROM \"Tablets\" WHERE \"Price\" < 100", - c[EngineCodes.PostgreSql]); - - Assert.Equal( - "SELECT * FROM \"PHONES\" WHERE \"PRICE\" < 300 UNION SELECT * FROM \"LAPTOPS\" WHERE \"PRICE\" < 800 UNION ALL SELECT * FROM \"TABLETS\" WHERE \"PRICE\" < 100", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -390,43 +401,43 @@ public void CombineRaw() { var query = new Query("Mobiles").CombineRaw("UNION ALL SELECT * FROM Devices"); - var c = Compile(query); + var result = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal("SELECT * FROM [Mobiles] UNION ALL SELECT * FROM Devices", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT * FROM [Mobiles] UNION ALL SELECT * FROM Devices", result.ToString()); } - [Fact] - public void CombineRawWithPlaceholders() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Mobiles] UNION ALL SELECT * FROM [Devices]")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `Mobiles` UNION ALL SELECT * FROM `Devices`")] + [InlineData(EngineCodes.Firebird, "SELECT * FROM \"MOBILES\" UNION ALL SELECT * FROM \"Devices\"")] + public void CombineRawWithPlaceholders(string engine, string sqlText) { var query = new Query("Mobiles").CombineRaw("UNION ALL SELECT * FROM {Devices}"); - var c = Compile(query); - - Assert.Equal("SELECT * FROM [Mobiles] UNION ALL SELECT * FROM [Devices]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM `Mobiles` UNION ALL SELECT * FROM `Devices`", c[EngineCodes.MySql]); + var result = CompileFor(engine, query); - Assert.Equal("SELECT * FROM \"MOBILES\" UNION ALL SELECT * FROM \"Devices\"", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } [Fact] public void NestedEmptyWhere() { // Empty nested where should be ignored - var query = new Query("A").Where(q => new Query().Where(q2 => new Query().Where(q3 => new Query()))); + var query = new Query("A").Where(_ => new Query().Where(_ => new Query().Where(_ => new Query()))); - var c = Compile(query); + var result = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal("SELECT * FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT * FROM [A]", result.ToString()); } [Fact] public void NestedQuery() { - var query = new Query("A").Where(q => new Query("B")); + var query = new Query("A").Where(_ => new Query("B")); - var c = Compile(query); + var result = CompileFor(EngineCodes.SqlServer, query); - Assert.Equal("SELECT * FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT * FROM [A]", result.ToString()); } [Fact] @@ -435,12 +446,12 @@ public void NestedQueryAfterNestedJoin() // in this test, i am testing the compiler dynamic caching functionality var query = new Query("users") .Join("countries", j => j.On("countries.id", "users.country_id")) - .Where(q => new Query()); + .Where(_ => new Query()); - var c = Compile(query); + var result = CompileFor(EngineCodes.SqlServer, query); Assert.Equal("SELECT * FROM [users] \nINNER JOIN [countries] ON ([countries].[id] = [users].[country_id])", - c[EngineCodes.SqlServer]); + result.ToString()); } [Fact] @@ -455,15 +466,23 @@ public void MultipleCte() .With("B", q2) .With("C", q3); - var c = Compile(query); + var result = CompileFor(EngineCodes.SqlServer, query); Assert.Equal( "WITH [A] AS (SELECT * FROM [A]),\n[B] AS (SELECT * FROM [B]),\n[C] AS (SELECT * FROM [C])\nSELECT * FROM [A]", - c[EngineCodes.SqlServer]); + result.ToString()); } - [Fact] - public void CteAndBindings() + [Theory] + [InlineData(EngineCodes.SqlServer, + "WITH [range] AS (SELECT [Number] FROM [Sequence] WHERE [Number] < 78)\nSELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [Races] WHERE [Id] > 55 AND [Value] BETWEEN 18 AND 24) AS [results_wrapper] WHERE [row_num] BETWEEN 21 AND 45")] + [InlineData(EngineCodes.MySql, + "WITH `range` AS (SELECT `Id` FROM `seqtbl` WHERE `Id` < 33)\nSELECT * FROM `Races` WHERE `RaceAuthor` IN (SELECT `Name` FROM `Users` WHERE `Status` = 'Available') AND `Id` > 55 AND `Value` BETWEEN 18 AND 24")] + [InlineData(EngineCodes.PostgreSql, + "WITH \"range\" AS (SELECT \"d\" FROM generate_series(1, 33) as d)\nSELECT * FROM \"Races\" WHERE \"Name\" = '3778' AND \"Id\" > 55 AND \"Value\" BETWEEN 18 AND 24")] + [InlineData(EngineCodes.Firebird, + "WITH \"RANGE\" AS (SELECT \"D\" FROM generate_series(1, 33) as d)\nSELECT * FROM \"RACES\" WHERE \"NAME\" = '3778' AND \"ID\" > 55 AND \"VALUE\" BETWEEN 18 AND 24")] + public void CteAndBindings(string engine, string sqlText) { var query = new Query("Races") .For("mysql", s => @@ -491,28 +510,22 @@ public void CteAndBindings() .Where("Id", ">", 55) .WhereBetween("Value", 18, 24); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "WITH [range] AS (SELECT [Number] FROM [Sequence] WHERE [Number] < 78)\nSELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [Races] WHERE [Id] > 55 AND [Value] BETWEEN 18 AND 24) AS [results_wrapper] WHERE [row_num] BETWEEN 21 AND 45", - c[EngineCodes.SqlServer]); - - Assert.Equal( - "WITH `range` AS (SELECT `Id` FROM `seqtbl` WHERE `Id` < 33)\nSELECT * FROM `Races` WHERE `RaceAuthor` IN (SELECT `Name` FROM `Users` WHERE `Status` = 'Available') AND `Id` > 55 AND `Value` BETWEEN 18 AND 24", - c[EngineCodes.MySql]); - - Assert.Equal( - "WITH \"range\" AS (SELECT \"d\" FROM generate_series(1, 33) as d)\nSELECT * FROM \"Races\" WHERE \"Name\" = '3778' AND \"Id\" > 55 AND \"Value\" BETWEEN 18 AND 24", - c[EngineCodes.PostgreSql]); - - Assert.Equal( - "WITH \"RANGE\" AS (SELECT \"D\" FROM generate_series(1, 33) as d)\nSELECT * FROM \"RACES\" WHERE \"NAME\" = '3778' AND \"ID\" > 55 AND \"VALUE\" BETWEEN 18 AND 24", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } // test for issue #50 - [Fact] - public void CascadedCteAndBindings() + [Theory] + [InlineData(EngineCodes.SqlServer, + "WITH [cte1] AS (SELECT [Column1], [Column2] FROM [Table1] WHERE [Column2] = 1),\n[cte2] AS (SELECT [Column3], [Column4] FROM [Table2] \nINNER JOIN [cte1] ON ([Column1] = [Column3]) WHERE [Column4] = 2)\nSELECT * FROM [cte2] WHERE [Column3] = 5")] + [InlineData(EngineCodes.MySql, + "WITH `cte1` AS (SELECT `Column1`, `Column2` FROM `Table1` WHERE `Column2` = 1),\n`cte2` AS (SELECT `Column3`, `Column4` FROM `Table2` \nINNER JOIN `cte1` ON (`Column1` = `Column3`) WHERE `Column4` = 2)\nSELECT * FROM `cte2` WHERE `Column3` = 5")] + [InlineData(EngineCodes.PostgreSql, + "WITH \"cte1\" AS (SELECT \"Column1\", \"Column2\" FROM \"Table1\" WHERE \"Column2\" = 1),\n\"cte2\" AS (SELECT \"Column3\", \"Column4\" FROM \"Table2\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3\") WHERE \"Column4\" = 2)\nSELECT * FROM \"cte2\" WHERE \"Column3\" = 5")] + [InlineData(EngineCodes.Firebird, + "WITH \"CTE1\" AS (SELECT \"COLUMN1\", \"COLUMN2\" FROM \"TABLE1\" WHERE \"COLUMN2\" = 1),\n\"CTE2\" AS (SELECT \"COLUMN3\", \"COLUMN4\" FROM \"TABLE2\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3\") WHERE \"COLUMN4\" = 2)\nSELECT * FROM \"CTE2\" WHERE \"COLUMN3\" = 5")] + public void CascadedCteAndBindings(string engine, string sqlText) { var cte1 = new Query("Table1"); cte1.Select("Column1", "Column2"); @@ -530,20 +543,22 @@ public void CascadedCteAndBindings() mainQuery.From("cte2"); mainQuery.Where("Column3", 5); - var c = Compile(mainQuery); - - Assert.Equal("WITH [cte1] AS (SELECT [Column1], [Column2] FROM [Table1] WHERE [Column2] = 1),\n[cte2] AS (SELECT [Column3], [Column4] FROM [Table2] \nINNER JOIN [cte1] ON ([Column1] = [Column3]) WHERE [Column4] = 2)\nSELECT * FROM [cte2] WHERE [Column3] = 5", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, mainQuery); - Assert.Equal("WITH `cte1` AS (SELECT `Column1`, `Column2` FROM `Table1` WHERE `Column2` = 1),\n`cte2` AS (SELECT `Column3`, `Column4` FROM `Table2` \nINNER JOIN `cte1` ON (`Column1` = `Column3`) WHERE `Column4` = 2)\nSELECT * FROM `cte2` WHERE `Column3` = 5", c[EngineCodes.MySql]); - - Assert.Equal("WITH \"cte1\" AS (SELECT \"Column1\", \"Column2\" FROM \"Table1\" WHERE \"Column2\" = 1),\n\"cte2\" AS (SELECT \"Column3\", \"Column4\" FROM \"Table2\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3\") WHERE \"Column4\" = 2)\nSELECT * FROM \"cte2\" WHERE \"Column3\" = 5", c[EngineCodes.PostgreSql]); - - Assert.Equal("WITH \"CTE1\" AS (SELECT \"COLUMN1\", \"COLUMN2\" FROM \"TABLE1\" WHERE \"COLUMN2\" = 1),\n\"CTE2\" AS (SELECT \"COLUMN3\", \"COLUMN4\" FROM \"TABLE2\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3\") WHERE \"COLUMN4\" = 2)\nSELECT * FROM \"CTE2\" WHERE \"COLUMN3\" = 5", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } // test for issue #50 - [Fact] - public void CascadedAndMultiReferencedCteAndBindings() + [Theory] + [InlineData(EngineCodes.SqlServer, + "WITH [cte1] AS (SELECT [Column1], [Column2] FROM [Table1] WHERE [Column2] = 1),\n[cte2] AS (SELECT [Column3], [Column4] FROM [Table2] \nINNER JOIN [cte1] ON ([Column1] = [Column3]) WHERE [Column4] = 2),\n[cte3] AS (SELECT [Column3_3], [Column3_4] FROM [Table3] \nINNER JOIN [cte1] ON ([Column1] = [Column3_3]) WHERE [Column3_4] = 33)\nSELECT * FROM [cte2] WHERE [Column3] = 5")] + [InlineData(EngineCodes.MySql, + "WITH `cte1` AS (SELECT `Column1`, `Column2` FROM `Table1` WHERE `Column2` = 1),\n`cte2` AS (SELECT `Column3`, `Column4` FROM `Table2` \nINNER JOIN `cte1` ON (`Column1` = `Column3`) WHERE `Column4` = 2),\n`cte3` AS (SELECT `Column3_3`, `Column3_4` FROM `Table3` \nINNER JOIN `cte1` ON (`Column1` = `Column3_3`) WHERE `Column3_4` = 33)\nSELECT * FROM `cte2` WHERE `Column3` = 5")] + [InlineData(EngineCodes.PostgreSql, + "WITH \"cte1\" AS (SELECT \"Column1\", \"Column2\" FROM \"Table1\" WHERE \"Column2\" = 1),\n\"cte2\" AS (SELECT \"Column3\", \"Column4\" FROM \"Table2\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3\") WHERE \"Column4\" = 2),\n\"cte3\" AS (SELECT \"Column3_3\", \"Column3_4\" FROM \"Table3\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3_3\") WHERE \"Column3_4\" = 33)\nSELECT * FROM \"cte2\" WHERE \"Column3\" = 5")] + [InlineData(EngineCodes.Firebird, + "WITH \"CTE1\" AS (SELECT \"COLUMN1\", \"COLUMN2\" FROM \"TABLE1\" WHERE \"COLUMN2\" = 1),\n\"CTE2\" AS (SELECT \"COLUMN3\", \"COLUMN4\" FROM \"TABLE2\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3\") WHERE \"COLUMN4\" = 2),\n\"CTE3\" AS (SELECT \"COLUMN3_3\", \"COLUMN3_4\" FROM \"TABLE3\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3_3\") WHERE \"COLUMN3_4\" = 33)\nSELECT * FROM \"CTE2\" WHERE \"COLUMN3\" = 5")] + public void CascadedAndMultiReferencedCteAndBindings(string engine, string sqlText) { var cte1 = new Query("Table1"); cte1.Select("Column1", "Column2"); @@ -568,20 +583,22 @@ public void CascadedAndMultiReferencedCteAndBindings() mainQuery.From("cte2"); mainQuery.Where("Column3", 5); - var c = Compile(mainQuery); - - Assert.Equal("WITH [cte1] AS (SELECT [Column1], [Column2] FROM [Table1] WHERE [Column2] = 1),\n[cte2] AS (SELECT [Column3], [Column4] FROM [Table2] \nINNER JOIN [cte1] ON ([Column1] = [Column3]) WHERE [Column4] = 2),\n[cte3] AS (SELECT [Column3_3], [Column3_4] FROM [Table3] \nINNER JOIN [cte1] ON ([Column1] = [Column3_3]) WHERE [Column3_4] = 33)\nSELECT * FROM [cte2] WHERE [Column3] = 5", c[EngineCodes.SqlServer]); - - Assert.Equal("WITH `cte1` AS (SELECT `Column1`, `Column2` FROM `Table1` WHERE `Column2` = 1),\n`cte2` AS (SELECT `Column3`, `Column4` FROM `Table2` \nINNER JOIN `cte1` ON (`Column1` = `Column3`) WHERE `Column4` = 2),\n`cte3` AS (SELECT `Column3_3`, `Column3_4` FROM `Table3` \nINNER JOIN `cte1` ON (`Column1` = `Column3_3`) WHERE `Column3_4` = 33)\nSELECT * FROM `cte2` WHERE `Column3` = 5", c[EngineCodes.MySql]); - - Assert.Equal("WITH \"cte1\" AS (SELECT \"Column1\", \"Column2\" FROM \"Table1\" WHERE \"Column2\" = 1),\n\"cte2\" AS (SELECT \"Column3\", \"Column4\" FROM \"Table2\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3\") WHERE \"Column4\" = 2),\n\"cte3\" AS (SELECT \"Column3_3\", \"Column3_4\" FROM \"Table3\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3_3\") WHERE \"Column3_4\" = 33)\nSELECT * FROM \"cte2\" WHERE \"Column3\" = 5", c[EngineCodes.PostgreSql]); + var result = CompileFor(engine, mainQuery); - Assert.Equal("WITH \"CTE1\" AS (SELECT \"COLUMN1\", \"COLUMN2\" FROM \"TABLE1\" WHERE \"COLUMN2\" = 1),\n\"CTE2\" AS (SELECT \"COLUMN3\", \"COLUMN4\" FROM \"TABLE2\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3\") WHERE \"COLUMN4\" = 2),\n\"CTE3\" AS (SELECT \"COLUMN3_3\", \"COLUMN3_4\" FROM \"TABLE3\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3_3\") WHERE \"COLUMN3_4\" = 33)\nSELECT * FROM \"CTE2\" WHERE \"COLUMN3\" = 5", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } // test for issue #50 - [Fact] - public void MultipleCtesAndBindings() + [Theory] + [InlineData(EngineCodes.SqlServer, + "WITH [cte1] AS (SELECT [Column1], [Column2] FROM [Table1] WHERE [Column2] = 1),\n[cte2] AS (SELECT [Column3], [Column4] FROM [Table2] \nINNER JOIN [cte1] ON ([Column1] = [Column3]) WHERE [Column4] = 2),\n[cte3] AS (SELECT [Column3_3], [Column3_4] FROM [Table3] \nINNER JOIN [cte1] ON ([Column1] = [Column3_3]) WHERE [Column3_4] = 33)\nSELECT * FROM [cte3] WHERE [Column3_4] = 5")] + [InlineData(EngineCodes.MySql, + "WITH `cte1` AS (SELECT `Column1`, `Column2` FROM `Table1` WHERE `Column2` = 1),\n`cte2` AS (SELECT `Column3`, `Column4` FROM `Table2` \nINNER JOIN `cte1` ON (`Column1` = `Column3`) WHERE `Column4` = 2),\n`cte3` AS (SELECT `Column3_3`, `Column3_4` FROM `Table3` \nINNER JOIN `cte1` ON (`Column1` = `Column3_3`) WHERE `Column3_4` = 33)\nSELECT * FROM `cte3` WHERE `Column3_4` = 5")] + [InlineData(EngineCodes.PostgreSql, + "WITH \"cte1\" AS (SELECT \"Column1\", \"Column2\" FROM \"Table1\" WHERE \"Column2\" = 1),\n\"cte2\" AS (SELECT \"Column3\", \"Column4\" FROM \"Table2\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3\") WHERE \"Column4\" = 2),\n\"cte3\" AS (SELECT \"Column3_3\", \"Column3_4\" FROM \"Table3\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3_3\") WHERE \"Column3_4\" = 33)\nSELECT * FROM \"cte3\" WHERE \"Column3_4\" = 5")] + [InlineData(EngineCodes.Firebird, + "WITH \"CTE1\" AS (SELECT \"COLUMN1\", \"COLUMN2\" FROM \"TABLE1\" WHERE \"COLUMN2\" = 1),\n\"CTE2\" AS (SELECT \"COLUMN3\", \"COLUMN4\" FROM \"TABLE2\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3\") WHERE \"COLUMN4\" = 2),\n\"CTE3\" AS (SELECT \"COLUMN3_3\", \"COLUMN3_4\" FROM \"TABLE3\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3_3\") WHERE \"COLUMN3_4\" = 33)\nSELECT * FROM \"CTE3\" WHERE \"COLUMN3_4\" = 5")] + public void MultipleCtesAndBindings(string engine, string sqlText) { var cte1 = new Query("Table1"); cte1.Select("Column1", "Column2"); @@ -605,98 +622,110 @@ public void MultipleCtesAndBindings() mainQuery.From("cte3"); mainQuery.Where("Column3_4", 5); - var c = Compile(mainQuery); + var result = CompileFor(engine, mainQuery); - Assert.Equal("WITH [cte1] AS (SELECT [Column1], [Column2] FROM [Table1] WHERE [Column2] = 1),\n[cte2] AS (SELECT [Column3], [Column4] FROM [Table2] \nINNER JOIN [cte1] ON ([Column1] = [Column3]) WHERE [Column4] = 2),\n[cte3] AS (SELECT [Column3_3], [Column3_4] FROM [Table3] \nINNER JOIN [cte1] ON ([Column1] = [Column3_3]) WHERE [Column3_4] = 33)\nSELECT * FROM [cte3] WHERE [Column3_4] = 5", c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); + } - Assert.Equal("WITH `cte1` AS (SELECT `Column1`, `Column2` FROM `Table1` WHERE `Column2` = 1),\n`cte2` AS (SELECT `Column3`, `Column4` FROM `Table2` \nINNER JOIN `cte1` ON (`Column1` = `Column3`) WHERE `Column4` = 2),\n`cte3` AS (SELECT `Column3_3`, `Column3_4` FROM `Table3` \nINNER JOIN `cte1` ON (`Column1` = `Column3_3`) WHERE `Column3_4` = 33)\nSELECT * FROM `cte3` WHERE `Column3_4` = 5", c[EngineCodes.MySql]); + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT TOP (10) [id], [name] FROM [users]")] + [InlineData(EngineCodes.MySql, "SELECT `id`, `name` FROM `users` LIMIT 10")] + [InlineData(EngineCodes.PostgreSql, "SELECT \"id\", \"name\" FROM \"users\" LIMIT 10")] + [InlineData(EngineCodes.Firebird, "SELECT FIRST 10 \"ID\", \"NAME\" FROM \"USERS\"")] + public void Limit(string engine, string sqlText) + { + var query = new Query().From("users").Select("id", "name").Limit(10); - Assert.Equal("WITH \"cte1\" AS (SELECT \"Column1\", \"Column2\" FROM \"Table1\" WHERE \"Column2\" = 1),\n\"cte2\" AS (SELECT \"Column3\", \"Column4\" FROM \"Table2\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3\") WHERE \"Column4\" = 2),\n\"cte3\" AS (SELECT \"Column3_3\", \"Column3_4\" FROM \"Table3\" \nINNER JOIN \"cte1\" ON (\"Column1\" = \"Column3_3\") WHERE \"Column3_4\" = 33)\nSELECT * FROM \"cte3\" WHERE \"Column3_4\" = 5", c[EngineCodes.PostgreSql]); + var result = CompileFor(engine, query); - Assert.Equal("WITH \"CTE1\" AS (SELECT \"COLUMN1\", \"COLUMN2\" FROM \"TABLE1\" WHERE \"COLUMN2\" = 1),\n\"CTE2\" AS (SELECT \"COLUMN3\", \"COLUMN4\" FROM \"TABLE2\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3\") WHERE \"COLUMN4\" = 2),\n\"CTE3\" AS (SELECT \"COLUMN3_3\", \"COLUMN3_4\" FROM \"TABLE3\" \nINNER JOIN \"CTE1\" ON (\"COLUMN1\" = \"COLUMN3_3\") WHERE \"COLUMN3_4\" = 33)\nSELECT * FROM \"CTE3\" WHERE \"COLUMN3_4\" = 5", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - - [Fact] - public void Limit() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [users]) AS [results_wrapper] WHERE [row_num] >= 11")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `users` LIMIT 18446744073709551615 OFFSET 10")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"users\" OFFSET 10")] + [InlineData(EngineCodes.Firebird, "SELECT SKIP 10 * FROM \"USERS\"")] + public void Offset(string engine, string sqlText) { - var q = new Query().From("users").Select("id", "name").Limit(10); - var c = Compile(q); + var query = new Query().From("users").Offset(10); + + var result = CompileFor(engine, query); - // Assert.Equal(c[EngineCodes.SqlServer], "SELECT * FROM (SELECT [id], [name],ROW_NUMBER() OVER (SELECT 0) AS [row_num] FROM [users]) AS [temp_table] WHERE [row_num] >= 10"); - Assert.Equal("SELECT TOP (10) [id], [name] FROM [users]", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT `id`, `name` FROM `users` LIMIT 10", c[EngineCodes.MySql]); - Assert.Equal("SELECT \"id\", \"name\" FROM \"users\" LIMIT 10", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT FIRST 10 \"ID\", \"NAME\" FROM \"USERS\"", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void Offset() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [users]) AS [results_wrapper] WHERE [row_num] BETWEEN 11 AND 15")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `users` LIMIT 5 OFFSET 10")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"users\" LIMIT 5 OFFSET 10")] + [InlineData(EngineCodes.Firebird, "SELECT * FROM \"USERS\" ROWS 11 TO 15")] + public void LimitOffset(string engine, string sqlText) { - var q = new Query().From("users").Offset(10); - var c = Compile(q); + var query = new Query().From("users").Offset(10).Limit(5); - Assert.Equal( - "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [users]) AS [results_wrapper] WHERE [row_num] >= 11", - c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM `users` LIMIT 18446744073709551615 OFFSET 10", c[EngineCodes.MySql]); - Assert.Equal("SELECT * FROM \"users\" OFFSET 10", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT SKIP 10 * FROM \"USERS\"", c[EngineCodes.Firebird]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void LimitOffset() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [users] \nINNER JOIN [countries] ON [countries].[id] = [users].[country_id]")] + [InlineData(EngineCodes.MySql, + "SELECT * FROM `users` \nINNER JOIN `countries` ON `countries`.`id` = `users`.`country_id`")] + public void BasicJoin(string engine, string sqlText) { - var q = new Query().From("users").Offset(10).Limit(5); + var query = new Query().From("users").Join("countries", "countries.id", "users.country_id"); - var c = Compile(q); + var result = CompileFor(engine, query); - Assert.Equal( - "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [users]) AS [results_wrapper] WHERE [row_num] BETWEEN 11 AND 15", - c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM `users` LIMIT 5 OFFSET 10", c[EngineCodes.MySql]); - Assert.Equal("SELECT * FROM \"users\" LIMIT 5 OFFSET 10", c[EngineCodes.PostgreSql]); - Assert.Equal("SELECT * FROM \"USERS\" ROWS 11 TO 15", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void BasicJoin() + public static TheoryData JoinTypesData() { - var q = new Query().From("users").Join("countries", "countries.id", "users.country_id"); + var data = new TheoryData(); + AddEngines("inner join", "INNER JOIN", data); + AddEngines("left join", "LEFT JOIN", data); + AddEngines("right join", "RIGHT JOIN", data); + AddEngines("cross join", "CROSS JOIN", data); - var c = Compile(q); + return data; - Assert.Equal("SELECT * FROM [users] \nINNER JOIN [countries] ON [countries].[id] = [users].[country_id]", - c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM `users` \nINNER JOIN `countries` ON `countries`.`id` = `users`.`country_id`", - c[EngineCodes.MySql]); + void AddEngines(string given, string output, TheoryData data) + { + data.Add( + given, + EngineCodes.SqlServer, + $"SELECT * FROM [users] \n{output} [countries] ON [countries].[id] = [users].[country_id]"); + data.Add( + given, + EngineCodes.MySql, + $"SELECT * FROM `users` \n{output} `countries` ON `countries`.`id` = `users`.`country_id`"); + data.Add( + given, + EngineCodes.PostgreSql, + $"SELECT * FROM \"users\" \n{output} \"countries\" ON \"countries\".\"id\" = \"users\".\"country_id\""); + data.Add( + given, + EngineCodes.Firebird, + $"SELECT * FROM \"USERS\" \n{output} \"COUNTRIES\" ON \"COUNTRIES\".\"ID\" = \"USERS\".\"COUNTRY_ID\""); + } } [Theory] - [InlineData("inner join", "INNER JOIN")] - [InlineData("left join", "LEFT JOIN")] - [InlineData("right join", "RIGHT JOIN")] - [InlineData("cross join", "CROSS JOIN")] - public void JoinTypes(string given, string output) + [MemberData(nameof(JoinTypesData))] + public void JoinTypes(string given, string engine, string sqlText) { var q = new Query().From("users") .Join("countries", "countries.id", "users.country_id", "=", given); - var c = Compile(q); - - Assert.Equal($"SELECT * FROM [users] \n{output} [countries] ON [countries].[id] = [users].[country_id]", - c[EngineCodes.SqlServer]); - - Assert.Equal($"SELECT * FROM `users` \n{output} `countries` ON `countries`.`id` = `users`.`country_id`", - c[EngineCodes.MySql]); - - Assert.Equal( - $"SELECT * FROM \"users\" \n{output} \"countries\" ON \"countries\".\"id\" = \"users\".\"country_id\"", - c[EngineCodes.PostgreSql]); + var result = CompileFor(engine, q); - Assert.Equal( - $"SELECT * FROM \"USERS\" \n{output} \"COUNTRIES\" ON \"COUNTRIES\".\"ID\" = \"USERS\".\"COUNTRY_ID\"", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -704,132 +733,164 @@ public void OrWhereRawEscaped() { var query = new Query("Table").WhereRaw("[MyCol] = ANY(?::int\\[\\])", "{1,2,3}"); - var c = Compile(query); + var result = CompileFor(EngineCodes.PostgreSql, query); - Assert.Equal("SELECT * FROM \"Table\" WHERE \"MyCol\" = ANY('{1,2,3}'::int[])", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT * FROM \"Table\" WHERE \"MyCol\" = ANY('{1,2,3}'::int[])", result.ToString()); } - [Fact] - public void Having() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table1] HAVING [Column1] > 1")] + public void Having(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .Having("Column1", ">", 1); - var c = Compile(q); - Assert.Equal("SELECT * FROM [Table1] HAVING [Column1] > 1", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void MultipleHaving() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table1] HAVING [Column1] > 1 AND [Column2] = 1")] + public void MultipleHaving(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .Having("Column1", ">", 1) .Having("Column2", "=", 1); - var c = Compile(q); - Assert.Equal("SELECT * FROM [Table1] HAVING [Column1] > 1 AND [Column2] = 1", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void MultipleOrHaving() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table1] HAVING [Column1] > 1 OR [Column2] = 1")] + public void MultipleOrHaving(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .Having("Column1", ">", 1) .OrHaving("Column2", "=", 1); - var c = Compile(q); - Assert.Equal("SELECT * FROM [Table1] HAVING [Column1] > 1 OR [Column2] = 1", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void ShouldUseILikeOnPostgresWhenNonCaseSensitive() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table1] WHERE LOWER([Column1]) like '%upper word%'")] + [InlineData(EngineCodes.PostgreSql, "SELECT * FROM \"Table1\" WHERE \"Column1\" ilike '%Upper Word%'")] + public void ShouldUseILikeOnPostgresWhenNonCaseSensitive(string engine, string sqlText) { - var q = new Query("Table1") - .WhereLike("Column1", "%Upper Word%", false); - var c = Compile(q); + var query = new Query("Table1") + .WhereLike("Column1", "%Upper Word%", caseSensitive: false); - Assert.Equal(@"SELECT * FROM [Table1] WHERE LOWER([Column1]) like '%upper word%'", c[EngineCodes.SqlServer]); - Assert.Equal("SELECT * FROM \"Table1\" WHERE \"Column1\" ilike '%Upper Word%'", c[EngineCodes.PostgreSql]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void EscapedWhereLike() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table1] WHERE LOWER([Column1]) like 'teststring\\%' ESCAPE '\\'")] + public void EscapedWhereLike(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .WhereLike("Column1", @"TestString\%", false, @"\"); - var c = Compile(q); - Assert.Equal(@"SELECT * FROM [Table1] WHERE LOWER([Column1]) like 'teststring\%' ESCAPE '\'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void EscapedWhereStarts() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table1] WHERE LOWER([Column1]) like 'teststring\\%%' ESCAPE '\\'")] + public void EscapedWhereStarts(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .WhereStarts("Column1", @"TestString\%", false, @"\"); - var c = Compile(q); - Assert.Equal(@"SELECT * FROM [Table1] WHERE LOWER([Column1]) like 'teststring\%%' ESCAPE '\'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void EscapedWhereEnds() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table1] WHERE LOWER([Column1]) like '%teststring\\%' ESCAPE '\\'")] + public void EscapedWhereEnds(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .WhereEnds("Column1", @"TestString\%", false, @"\"); - var c = Compile(q); - Assert.Equal(@"SELECT * FROM [Table1] WHERE LOWER([Column1]) like '%teststring\%' ESCAPE '\'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void EscapedWhereContains() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table1] WHERE LOWER([Column1]) like '%teststring\\%%' ESCAPE '\\'")] + public void EscapedWhereContains(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .WhereContains("Column1", @"TestString\%", false, @"\"); - var c = Compile(q); - Assert.Equal(@"SELECT * FROM [Table1] WHERE LOWER([Column1]) like '%teststring\%%' ESCAPE '\'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void EscapedHavingLike() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table1] HAVING LOWER([Column1]) like 'teststring\\%' ESCAPE '\\'")] + public void EscapedHavingLike(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .HavingLike("Column1", @"TestString\%", false, @"\"); - var c = Compile(q); - Assert.Equal(@"SELECT * FROM [Table1] HAVING LOWER([Column1]) like 'teststring\%' ESCAPE '\'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void EscapedHavingStarts() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table1] HAVING LOWER([Column1]) like 'teststring\\%%' ESCAPE '\\'")] + public void EscapedHavingStarts(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .HavingStarts("Column1", @"TestString\%", false, @"\"); - var c = Compile(q); - Assert.Equal(@"SELECT * FROM [Table1] HAVING LOWER([Column1]) like 'teststring\%%' ESCAPE '\'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void EscapedHavingEnds() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table1] HAVING LOWER([Column1]) like '%teststring\\%' ESCAPE '\\'")] + public void EscapedHavingEnds(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .HavingEnds("Column1", @"TestString\%", false, @"\"); - var c = Compile(q); - Assert.Equal(@"SELECT * FROM [Table1] HAVING LOWER([Column1]) like '%teststring\%' ESCAPE '\'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void EscapedHavingContains() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Table1] HAVING LOWER([Column1]) like '%teststring\\%%' ESCAPE '\\'")] + public void EscapedHavingContains(string engine, string sqlText) { - var q = new Query("Table1") + var query = new Query("Table1") .HavingContains("Column1", @"TestString\%", false, @"\"); - var c = Compile(q); - Assert.Equal(@"SELECT * FROM [Table1] HAVING LOWER([Column1]) like '%teststring\%%' ESCAPE '\'", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } [Fact] @@ -837,7 +898,7 @@ public void EscapeClauseThrowsForMultipleCharacters() { Assert.ThrowsAny(() => { - var q = new Query("Table1") + _ = new Query("Table1") .HavingContains("Column1", @"TestString\%", false, @"\aa"); }); } @@ -848,115 +909,137 @@ public void BasicSelectRaw_WithNoTable() { var q = new Query().SelectRaw("somefunction() as c1"); - var c = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT somefunction() as c1", c.ToString()); + var result = CompileFor(EngineCodes.SqlServer, q); + + Assert.Equal("SELECT somefunction() as c1", result.ToString()); } - [Fact] - public void BasicSelect_WithNoTable() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [c1]")] + public void BasicSelect_WithNoTable(string engine, string sqlText) { - var q = new Query().Select("c1"); - var c = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT [c1]", c.ToString()); + var query = new Query().Select("c1"); + + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void BasicSelect_WithNoTableAndWhereClause() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [c1] WHERE [p] = 1")] + public void BasicSelect_WithNoTableAndWhereClause(string engine, string sqlText) { - var q = new Query().Select("c1").Where("p", 1); - var c = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT [c1] WHERE [p] = 1", c.ToString()); + var query = new Query().Select("c1").Where("p", 1); + + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void BasicSelect_WithNoTableWhereRawClause() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [c1] WHERE 1 = 1")] + public void BasicSelect_WithNoTableWhereRawClause(string engine, string sqlText) { - var q = new Query().Select("c1").WhereRaw("1 = 1"); - var c = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT [c1] WHERE 1 = 1", c.ToString()); + var query = new Query().Select("c1").WhereRaw("1 = 1"); + + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void BasicSelectAggregate() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [Title], SUM([ViewCount]) FROM [Posts]")] + public void BasicSelectAggregate(string engine, string sqlText) { - var q = new Query("Posts").Select("Title") + var query = new Query("Posts").Select("Title") .SelectAggregate("sum", "ViewCount"); - var sqlServer = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT [Title], SUM([ViewCount]) FROM [Posts]", sqlServer.ToString()); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void SelectAggregateShouldIgnoreEmptyFilter() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [Title], SUM([ViewCount]) FROM [Posts]")] + public void SelectAggregateShouldIgnoreEmptyFilter(string engine, string sqlText) { - var q = new Query("Posts").Select("Title") + var query = new Query("Posts").Select("Title") .SelectAggregate("sum", "ViewCount", q => q); - var sqlServer = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT [Title], SUM([ViewCount]) FROM [Posts]", sqlServer.ToString()); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void SelectAggregateShouldIgnoreEmptyQueryFilter() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [Title], SUM([ViewCount]) FROM [Posts]")] + public void SelectAggregateShouldIgnoreEmptyQueryFilter(string engine, string sqlText) { - var q = new Query("Posts").Select("Title") + var query = new Query("Posts").Select("Title") .SelectAggregate("sum", "ViewCount", new Query()); - var sqlServer = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT [Title], SUM([ViewCount]) FROM [Posts]", sqlServer.ToString()); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void BasicSelectAggregateWithAlias() + [Theory] + [InlineData(EngineCodes.SqlServer, "SELECT [Title], SUM([ViewCount]) AS [TotalViews] FROM [Posts]")] + public void BasicSelectAggregateWithAlias(string engine, string sqlText) { - var q = new Query("Posts").Select("Title") + var query = new Query("Posts").Select("Title") .SelectAggregate("sum", "ViewCount as TotalViews"); - var sqlServer = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT [Title], SUM([ViewCount]) AS [TotalViews] FROM [Posts]", sqlServer.ToString()); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void SelectWithFilter() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT [Title], SUM(CASE WHEN [Published_Month] = 'Jan' THEN [ViewCount] END) AS [Published_Jan], SUM(CASE WHEN [Published_Month] = 'Feb' THEN [ViewCount] END) AS [Published_Feb] FROM [Posts]")] + [InlineData(EngineCodes.PostgreSql, + "SELECT \"Title\", SUM(\"ViewCount\") FILTER (WHERE \"Published_Month\" = 'Jan') AS \"Published_Jan\", SUM(\"ViewCount\") FILTER (WHERE \"Published_Month\" = 'Feb') AS \"Published_Feb\" FROM \"Posts\"")] + public void SelectWithFilter(string engine, string sqlText) { - var q = new Query("Posts").Select("Title") + var query = new Query("Posts").Select("Title") .SelectAggregate("sum", "ViewCount as Published_Jan", q => q.Where("Published_Month", "Jan")) .SelectAggregate("sum", "ViewCount as Published_Feb", q => q.Where("Published_Month", "Feb")); - var pgSql = Compilers.CompileFor(EngineCodes.PostgreSql, q); - Assert.Equal("SELECT \"Title\", SUM(\"ViewCount\") FILTER (WHERE \"Published_Month\" = 'Jan') AS \"Published_Jan\", SUM(\"ViewCount\") FILTER (WHERE \"Published_Month\" = 'Feb') AS \"Published_Feb\" FROM \"Posts\"", pgSql.ToString()); + var result = CompileFor(engine, query); - var sqlServer = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT [Title], SUM(CASE WHEN [Published_Month] = 'Jan' THEN [ViewCount] END) AS [Published_Jan], SUM(CASE WHEN [Published_Month] = 'Feb' THEN [ViewCount] END) AS [Published_Feb] FROM [Posts]", sqlServer.ToString()); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void SelectWithExists() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Posts] WHERE EXISTS (SELECT 1 FROM [Comments] WHERE [Comments].[PostId] = [Posts].[Id])")] + public void SelectWithExists(string engine, string sqlText) { - var q = new Query("Posts").WhereExists( + var query = new Query("Posts").WhereExists( new Query("Comments").WhereColumns("Comments.PostId", "=", "Posts.Id") ); - var sqlServer = Compilers.CompileFor(EngineCodes.SqlServer, q); - Assert.Equal("SELECT * FROM [Posts] WHERE EXISTS (SELECT 1 FROM [Comments] WHERE [Comments].[PostId] = [Posts].[Id])", sqlServer.ToString()); + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void SelectWithExists_OmitSelectIsFalse() + [Theory] + [InlineData(EngineCodes.SqlServer, + "SELECT * FROM [Posts] WHERE EXISTS (SELECT [Id] FROM [Comments] WHERE [Comments].[PostId] = [Posts].[Id])")] + public void SelectWithExists_OmitSelectIsFalse(string engine, string sqlText) { var q = new Query("Posts").WhereExists( new Query("Comments").Select("Id").WhereColumns("Comments.PostId", "=", "Posts.Id") ); - - var compiler = new SqlServerCompiler + var result = CompileFor(engine, q, compiler => { - OmitSelectInsideExists = false, - }; + compiler.OmitSelectInsideExists = false; + }); - var sqlServer = compiler.Compile(q).ToString(); - Assert.Equal("SELECT * FROM [Posts] WHERE EXISTS (SELECT [Id] FROM [Comments] WHERE [Comments].[PostId] = [Posts].[Id])", sqlServer.ToString()); + Assert.Equal(sqlText, result.ToString()); } - } } diff --git a/QueryBuilder.Tests/SqlServer/NestedSelectTests.cs b/QueryBuilder.Tests/SqlServer/NestedSelectTests.cs index 4c591ba2..0bad0a20 100644 --- a/QueryBuilder.Tests/SqlServer/NestedSelectTests.cs +++ b/QueryBuilder.Tests/SqlServer/NestedSelectTests.cs @@ -1,16 +1,14 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.SqlServer { public class NestedSelectTests : TestSupport { - private readonly SqlServerCompiler compiler; + private readonly Compiler compiler; public NestedSelectTests() { - compiler = Compilers.Get(EngineCodes.SqlServer); + compiler = CreateCompiler(EngineCodes.SqlServer); } [Fact] diff --git a/QueryBuilder.Tests/SqlServer/SqlServerLegacyLimitTests.cs b/QueryBuilder.Tests/SqlServer/SqlServerLegacyLimitTests.cs index 1cc58060..62a1acae 100644 --- a/QueryBuilder.Tests/SqlServer/SqlServerLegacyLimitTests.cs +++ b/QueryBuilder.Tests/SqlServer/SqlServerLegacyLimitTests.cs @@ -1,53 +1,67 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.SqlServer { public class SqlServerLegacyLimitTests : TestSupport { - private readonly SqlServerCompiler compiler; + private readonly Compiler compiler; public SqlServerLegacyLimitTests() { - compiler = Compilers.Get(EngineCodes.SqlServer); - compiler.UseLegacyPagination = true; + compiler = CreateCompiler(EngineCodes.SqlServer, useLegacyPagination: true); } [Fact] public void NoLimitNorOffset() { var query = new Query("Table"); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM [Table]", ctx.RawSql); } [Fact] public void LimitOnly() { var query = new Query("Table").Limit(10); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT TOP (?) * FROM [Table]", ctx.RawSql); } [Fact] public void OffsetOnly() { var query = new Query("Table").Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [Table]) AS [results_wrapper] WHERE [row_num] >= ?", ctx.RawSql); + Assert.Single(ctx.Bindings); + Assert.Equal(21L, ctx.Bindings[0]); } [Fact] public void LimitAndOffset() { var query = new Query("Table").Limit(5).Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [Table]) AS [results_wrapper] WHERE [row_num] BETWEEN ? AND ?", ctx.RawSql); + Assert.Collection(ctx.Bindings, + e => Assert.Equal(21L, e), + e => Assert.Equal(25L, e)); } [Fact] @@ -55,7 +69,9 @@ public void ShouldEmulateOrderByIfNoOrderByProvided() { var query = new Query("Table").Limit(5).Offset(20); - Assert.Contains("ORDER BY (SELECT 0)", compiler.Compile(query).ToString()); + var ctx = compiler.Compile(query); + + Assert.Contains("ORDER BY (SELECT 0)", ctx.ToString()); } [Fact] @@ -63,7 +79,9 @@ public void ShouldKeepTheOrdersAsIsIfNoPaginationProvided() { var query = new Query("Table").OrderBy("Id"); - Assert.Contains("ORDER BY [Id]", compiler.Compile(query).ToString()); + var ctx = compiler.Compile(query); + + Assert.Contains("ORDER BY [Id]", ctx.ToString()); } [Fact] @@ -71,8 +89,10 @@ public void ShouldKeepTheOrdersAsIsIfPaginationProvided() { var query = new Query("Table").Offset(10).Limit(20).OrderBy("Id"); - Assert.Contains("ORDER BY [Id]", compiler.Compile(query).ToString()); - Assert.DoesNotContain("(SELECT 0)", compiler.Compile(query).ToString()); + var sqlResult = compiler.Compile(query); + + Assert.Contains("ORDER BY [Id]", sqlResult.ToString()); + Assert.DoesNotContain("(SELECT 0)", sqlResult.ToString()); } } } diff --git a/QueryBuilder.Tests/SqlServer/SqlServerLimitTests.cs b/QueryBuilder.Tests/SqlServer/SqlServerLimitTests.cs index e6fa416b..ac80b10d 100644 --- a/QueryBuilder.Tests/SqlServer/SqlServerLimitTests.cs +++ b/QueryBuilder.Tests/SqlServer/SqlServerLimitTests.cs @@ -1,60 +1,59 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.SqlServer { public class SqlServerLimitTests : TestSupport { - private readonly SqlServerCompiler compiler; + private readonly Compiler compiler; public SqlServerLimitTests() { - compiler = Compilers.Get(EngineCodes.SqlServer); - compiler.UseLegacyPagination = false; + compiler = CreateCompiler(EngineCodes.SqlServer, useLegacyPagination: false); } [Fact] public void NoLimitNorOffset() { var query = new Query("Table"); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.Null(compiler.CompileLimit(ctx)); + var result = compiler.Compile(query); + + Assert.Equal("SELECT * FROM [Table]", result.ToString()); } [Fact] public void LimitOnly() { var query = new Query("Table").Limit(10); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.EndsWith("OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", compiler.CompileLimit(ctx)); - Assert.Equal(2, ctx.Bindings.Count); - Assert.Equal(0L, ctx.Bindings[0]); - Assert.Equal(10, ctx.Bindings[1]); + var result = compiler.Compile(query); + + Assert.Equal("SELECT * FROM [Table] ORDER BY (SELECT 0) OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", result.RawSql); + Assert.Equal(2, result.Bindings.Count); + Assert.Equal(0L, result.Bindings[0]); + Assert.Equal(10, result.Bindings[1]); } [Fact] public void OffsetOnly() { var query = new Query("Table").Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.EndsWith("OFFSET ? ROWS", compiler.CompileLimit(ctx)); + var result = compiler.Compile(query); - Assert.Single(ctx.Bindings); - Assert.Equal(20L, ctx.Bindings[0]); + Assert.Equal("SELECT * FROM [Table] ORDER BY (SELECT 0) OFFSET ? ROWS", result.RawSql); + Assert.Single(result.Bindings); + Assert.Equal(20L, result.Bindings[0]); } [Fact] public void LimitAndOffset() { var query = new Query("Table").Limit(5).Offset(20); - var ctx = new SqlResult("?", "\\") {Query = query}; - Assert.EndsWith("OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", compiler.CompileLimit(ctx)); + var ctx = compiler.Compile(query); + Assert.Equal("SELECT * FROM [Table] ORDER BY (SELECT 0) OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", ctx.RawSql); Assert.Equal(2, ctx.Bindings.Count); Assert.Equal(20L, ctx.Bindings[0]); Assert.Equal(5, ctx.Bindings[1]); @@ -65,7 +64,9 @@ public void ShouldEmulateOrderByIfNoOrderByProvided() { var query = new Query("Table").Limit(5).Offset(20); - Assert.Contains("ORDER BY (SELECT 0)", compiler.Compile(query).ToString()); + var sqlResult = compiler.Compile(query); + + Assert.Contains("ORDER BY (SELECT 0)", sqlResult.ToString()); } [Fact] @@ -73,7 +74,9 @@ public void ShouldKeepTheOrdersAsIsIfNoPaginationProvided() { var query = new Query("Table").OrderBy("Id"); - Assert.Contains("ORDER BY [Id]", compiler.Compile(query).ToString()); + var sqlResult = compiler.Compile(query); + + Assert.Contains("ORDER BY [Id]", sqlResult.ToString()); } [Fact] @@ -81,8 +84,10 @@ public void ShouldKeepTheOrdersAsIsIfPaginationProvided() { var query = new Query("Table").Offset(10).Limit(20).OrderBy("Id"); - Assert.Contains("ORDER BY [Id]", compiler.Compile(query).ToString()); - Assert.DoesNotContain("(SELECT 0)", compiler.Compile(query).ToString()); + var sqlResult = compiler.Compile(query); + + Assert.Contains("ORDER BY [Id]", sqlResult.ToString()); + Assert.DoesNotContain("(SELECT 0)", sqlResult.ToString()); } } } diff --git a/QueryBuilder.Tests/SqlServer/SqlServerTests.cs b/QueryBuilder.Tests/SqlServer/SqlServerTests.cs index 5ab15634..db1736de 100644 --- a/QueryBuilder.Tests/SqlServer/SqlServerTests.cs +++ b/QueryBuilder.Tests/SqlServer/SqlServerTests.cs @@ -1,16 +1,14 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.SqlServer { public class SqlServerTests : TestSupport { - private readonly SqlServerCompiler compiler; + private readonly Compiler compiler; public SqlServerTests() { - compiler = Compilers.Get(EngineCodes.SqlServer); + compiler = CreateCompiler(EngineCodes.SqlServer); } @@ -18,7 +16,9 @@ public SqlServerTests() public void SqlServerTop() { var query = new Query("table").Limit(1); + var result = compiler.Compile(query); + Assert.Equal("SELECT TOP (@p0) * FROM [table]", result.Sql); } @@ -27,7 +27,9 @@ public void SqlServerTop() public void SqlServerSelectWithParameterPlaceHolder() { var query = new Query("table").Select("Column\\?"); + var result = compiler.Compile(query); + Assert.Equal("SELECT [Column\\?] FROM [table]", result.Sql); } @@ -35,31 +37,36 @@ public void SqlServerSelectWithParameterPlaceHolder() public void SqlServerTopWithDistinct() { var query = new Query("table").Limit(1).Distinct(); + var result = compiler.Compile(query); + Assert.Equal("SELECT DISTINCT TOP (@p0) * FROM [table]", result.Sql); } - [Theory()] + [Theory] [InlineData(-100)] [InlineData(0)] public void OffsetSqlServer_Should_Be_Ignored_If_Zero_Or_Negative(int offset) { - var q = new Query().From("users").Offset(offset); - var c = Compilers.CompileFor(EngineCodes.SqlServer, q); + var query = new Query().From("users").Offset(offset); - Assert.Equal("SELECT * FROM [users]", c.ToString()); + var result = compiler.Compile(query); + + Assert.Equal("SELECT * FROM [users]", result.ToString()); } [Fact] public void SqlServerSelectWithParameterPlaceHolderEscaped() { var query = new Query("table").Select("Column\\?"); + var result = compiler.Compile(query); + Assert.Equal("SELECT [Column?] FROM [table]", result.ToString()); } - [Theory()] + [Theory] [InlineData(1)] [InlineData(2)] [InlineData(3)] @@ -68,8 +75,10 @@ public void SqlServerSelectWithParameterPlaceHolderEscaped() [InlineData(1000000)] public void OffsetSqlServer_Should_Be_Incremented_By_One(int offset) { - var q = new Query().From("users").Offset(offset); - var c = Compilers.CompileFor(EngineCodes.SqlServer, q); + var query = new Query().From("users").Offset(offset); + + var c = compiler.Compile(query); + Assert.Equal( "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [users]) AS [results_wrapper] WHERE [row_num] >= " + (offset + 1), c.ToString()); diff --git a/QueryBuilder.Tests/SQLiteExecutionTest.cs b/QueryBuilder.Tests/Sqlite/SQLiteExecutionTest.cs similarity index 96% rename from QueryBuilder.Tests/SQLiteExecutionTest.cs rename to QueryBuilder.Tests/Sqlite/SQLiteExecutionTest.cs index 8c4d43f5..3fdd6b37 100644 --- a/QueryBuilder.Tests/SQLiteExecutionTest.cs +++ b/QueryBuilder.Tests/Sqlite/SQLiteExecutionTest.cs @@ -1,14 +1,8 @@ -using SqlKata.Compilers; -using Xunit; -using SqlKata.Execution; -using MySql.Data.MySqlClient; -using System; -using System.Linq; -using static SqlKata.Expressions; -using System.Collections.Generic; using Microsoft.Data.Sqlite; +using SqlKata.Execution; +using SqlKata.Tests.Infrastructure; -namespace SqlKata.Tests +namespace SqlKata.Tests.Sqlite { public class SqliteExecutionTest { @@ -222,12 +216,12 @@ public void BasicSelectFilter() // 2020 {"2020-01-01", 10}, {"2020-05-01", 20}, - + // 2021 {"2021-01-01", 40}, {"2021-02-01", 10}, {"2021-04-01", -10}, - + // 2022 {"2022-01-01", 80}, {"2022-02-01", -30}, @@ -272,4 +266,4 @@ QueryFactory DB() } -} \ No newline at end of file +} diff --git a/QueryBuilder.Tests/Sqlite/SqliteLimitTests.cs b/QueryBuilder.Tests/Sqlite/SqliteLimitTests.cs index 837a6654..cf0fb1f2 100644 --- a/QueryBuilder.Tests/Sqlite/SqliteLimitTests.cs +++ b/QueryBuilder.Tests/Sqlite/SqliteLimitTests.cs @@ -1,34 +1,38 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests.Sqlite { public class SqliteLimitTests : TestSupport { - private readonly SqliteCompiler compiler; + private readonly Compiler compiler; public SqliteLimitTests() { - compiler = Compilers.Get(EngineCodes.Sqlite); + compiler = CreateCompiler(EngineCodes.Sqlite); } [Fact] public void WithNoLimitNorOffset() { var query = new Query("Table"); - var ctx = new SqlResult("?", "\\") { Query = query }; - Assert.Null(compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\"", ctx.RawSql); } [Fact] public void WithNoOffset() { var query = new Query("Table").Limit(10); - var ctx = new SqlResult("?", "\\") { Query = query }; - Assert.Equal("LIMIT ?", compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\" LIMIT ?", ctx.RawSql); Assert.Equal(10, ctx.Bindings[0]); } @@ -36,9 +40,12 @@ public void WithNoOffset() public void WithNoLimit() { var query = new Query("Table").Offset(20); - var ctx = new SqlResult("?", "\\") { Query = query }; - Assert.Equal("LIMIT -1 OFFSET ?", compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\" LIMIT -1 OFFSET ?", ctx.RawSql); Assert.Equal(20L, ctx.Bindings[0]); Assert.Single(ctx.Bindings); } @@ -47,9 +54,12 @@ public void WithNoLimit() public void WithLimitAndOffset() { var query = new Query("Table").Limit(5).Offset(20); - var ctx = new SqlResult("?", "\\") { Query = query }; - Assert.Equal("LIMIT ? OFFSET ?", compiler.CompileLimit(ctx)); + // Act + var ctx = compiler.Compile(query); + + // Assert: + Assert.Equal("SELECT * FROM \"Table\" LIMIT ? OFFSET ?", ctx.RawSql); Assert.Equal(5, ctx.Bindings[0]); Assert.Equal(20L, ctx.Bindings[1]); Assert.Equal(2, ctx.Bindings.Count); diff --git a/QueryBuilder.Tests/UpdateTests.cs b/QueryBuilder.Tests/UpdateTests.cs index bf3dd7d9..5e189682 100644 --- a/QueryBuilder.Tests/UpdateTests.cs +++ b/QueryBuilder.Tests/UpdateTests.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Dynamic; -using System.Linq; -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests { @@ -55,8 +49,10 @@ public OrderProductComposite(string orderid, string productid, int quantity) public string Foo { get; set; } } - [Fact] - public void UpdateObject() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'")] + [InlineData(EngineCodes.Firebird, "UPDATE \"TABLE\" SET \"NAME\" = 'The User', \"AGE\" = '2018-01-01'")] + public void UpdateObject(string engine, string sqlText) { var query = new Query("Table").AsUpdate(new { @@ -64,122 +60,107 @@ public void UpdateObject() Age = new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc), }); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'", - c[EngineCodes.SqlServer]); - - Assert.Equal( - "UPDATE \"TABLE\" SET \"NAME\" = 'The User', \"AGE\" = '2018-01-01'", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UpdateWithNullValues() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Books] SET [Author] = 'Author 1', [Date] = NULL, [Version] = NULL WHERE [Id] = 1")] + [InlineData(EngineCodes.Firebird, "UPDATE \"BOOKS\" SET \"AUTHOR\" = 'Author 1', \"DATE\" = NULL, \"VERSION\" = NULL WHERE \"ID\" = 1")] + public void UpdateWithNullValues(string engine, string sqlText) { var query = new Query("Books").Where("Id", 1).AsUpdate( new[] { "Author", "Date", "Version" }, new object[] { "Author 1", null, null } ); - var c = Compile(query); - - Assert.Equal( - "UPDATE [Books] SET [Author] = 'Author 1', [Date] = NULL, [Version] = NULL WHERE [Id] = 1", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "UPDATE \"BOOKS\" SET \"AUTHOR\" = 'Author 1', \"DATE\" = NULL, \"VERSION\" = NULL WHERE \"ID\" = 1", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UpdateWithEmptyString() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Books] SET [Author] = 'Author 1', [Description] = '' WHERE [Id] = 1")] + [InlineData(EngineCodes.Firebird, "UPDATE \"BOOKS\" SET \"AUTHOR\" = 'Author 1', \"DESCRIPTION\" = '' WHERE \"ID\" = 1")] + public void UpdateWithEmptyString(string engine, string sqlText) { var query = new Query("Books").Where("Id", 1).AsUpdate( new[] { "Author", "Description" }, new object[] { "Author 1", "" } ); - var c = Compile(query); - - Assert.Equal("UPDATE [Books] SET [Author] = 'Author 1', [Description] = '' WHERE [Id] = 1", c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal("UPDATE \"BOOKS\" SET \"AUTHOR\" = 'Author 1', \"DESCRIPTION\" = '' WHERE \"ID\" = 1", c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UpdateWithCte() + [Theory] + [InlineData(EngineCodes.SqlServer, + "WITH [OldBooks] AS (SELECT * FROM [Books] WHERE [Date] < '2024-05-24')\nUPDATE [Books] SET [Price] = '150' WHERE [Price] > 100")] + public void UpdateWithCte(string engine, string sqlText) { - var now = DateTime.UtcNow.ToString("yyyy-MM-dd"); - var query = new Query("Books") - .With("OldBooks", q => q.From("Books").Where("Date", "<", now)) + .With("OldBooks", q => q.From("Books").Where("Date", "<", "2024-05-24")) .Where("Price", ">", 100) .AsUpdate(new Dictionary { {"Price", "150"} }); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - $"WITH [OldBooks] AS (SELECT * FROM [Books] WHERE [Date] < '{now}')\nUPDATE [Books] SET [Price] = '150' WHERE [Price] > 100", - c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UpdateWithIgnoreAndColumnProperties() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Book] SET [Name] = 'SqlKataBook', [Author] = 'Kata', [Price] = 100")] + [InlineData(EngineCodes.Firebird, "UPDATE \"BOOK\" SET \"NAME\" = 'SqlKataBook', \"AUTHOR\" = 'Kata', \"PRICE\" = 100")] + public void UpdateWithIgnoreAndColumnProperties(string engine, string sqlText) { var book = new Book(name: $"SqlKataBook", author: "Kata", color: $"red", price: 100m); var query = new Query("Book").AsUpdate(book); - var c = Compile(query); - - Assert.Equal( - "UPDATE [Book] SET [Name] = 'SqlKataBook', [Author] = 'Kata', [Price] = 100", - c[EngineCodes.SqlServer]); + var result = CompileFor(engine, query); - Assert.Equal( - "UPDATE \"BOOK\" SET \"NAME\" = 'SqlKataBook', \"AUTHOR\" = 'Kata', \"PRICE\" = 100", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UpdateWithKeyAttribute() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [OrderProductComposite] SET [OrdId] = 'ORD01', [ProductId] = 'PROD02', [Quantity] = 20, [Faa] = 'baz' WHERE [OrdId] = 'ORD01' AND [ProductId] = 'PROD02'")] + [InlineData(EngineCodes.Firebird, "UPDATE \"ORDERPRODUCTCOMPOSITE\" SET \"ORDID\" = 'ORD01', \"PRODUCTID\" = 'PROD02', \"QUANTITY\" = 20, \"FAA\" = 'baz' WHERE \"ORDID\" = 'ORD01' AND \"PRODUCTID\" = 'PROD02'")] + public void UpdateWithKeyAttribute(string engine, string sqlText) { var order = new OrderProductComposite("ORD01", "PROD02", 20); var query = new Query("OrderProductComposite").AsUpdate(order); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "UPDATE [OrderProductComposite] SET [OrdId] = 'ORD01', [ProductId] = 'PROD02', [Quantity] = 20, [Faa] = 'baz' WHERE [OrdId] = 'ORD01' AND [ProductId] = 'PROD02'", - c[EngineCodes.SqlServer]); - - Assert.Equal( - "UPDATE \"ORDERPRODUCTCOMPOSITE\" SET \"ORDID\" = 'ORD01', \"PRODUCTID\" = 'PROD02', \"QUANTITY\" = 20, \"FAA\" = 'baz' WHERE \"ORDID\" = 'ORD01' AND \"PRODUCTID\" = 'PROD02'", - c[EngineCodes.Firebird]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UpdateFromRaw() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE Table.With.Dots SET [Name] = 'The User'")] + public void UpdateFromRaw(string engine, string sqlText) { var query = new Query().FromRaw("Table.With.Dots").AsUpdate(new { Name = "The User", }); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "UPDATE Table.With.Dots SET [Name] = 'The User'", - c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UpdateFromQueryShouldFail() + [Theory] + [InlineData(EngineCodes.Firebird)] + [InlineData(EngineCodes.MySql)] + [InlineData(EngineCodes.Oracle)] + [InlineData(EngineCodes.PostgreSql)] + [InlineData(EngineCodes.Sqlite)] + [InlineData(EngineCodes.SqlServer)] + public void UpdateFromQueryShouldFail(string engine) { var query = new Query().From(new Query("InnerTable")).AsUpdate(new { @@ -188,12 +169,13 @@ public void UpdateFromQueryShouldFail() Assert.Throws(() => { - Compile(query); + _ = CompileFor(engine, query); }); } - [Fact] - public void update_should_compile_literal_without_parameters_holders() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [MyTable] SET [Name] = ?, [Address] = @address")] + public void update_should_compile_literal_without_parameters_holders(string engine, string sqlText) { var query = new Query("MyTable").AsUpdate(new { @@ -201,16 +183,16 @@ public void update_should_compile_literal_without_parameters_holders() Address = new UnsafeLiteral("@address") }); - var compiler = new SqlServerCompiler(); - var result = compiler.Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "UPDATE [MyTable] SET [Name] = ?, [Address] = @address", - result.RawSql); + Assert.Equal(sqlText, result.RawSql); + Assert.Single(result.NamedBindings); + Assert.Equal("The User", result.NamedBindings.First().Value); } - [Fact] - public void UpdateUsingKeyValuePairs() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'")] + public void UpdateUsingKeyValuePairs(string engine, string sqlText) { var dictionaryUser = new Dictionary { @@ -222,53 +204,14 @@ public void UpdateUsingKeyValuePairs() var query = new Query("Table") .AsUpdate(dictionaryUser); - var c = Compile(query); - - Assert.Equal( - "UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'", - c[EngineCodes.SqlServer]); - } - - [Fact] - public void UpdateUsingDictionary() - { - var dictionaryUser = new Dictionary { - { "Name", "The User" }, - { "Age", new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc) }, - }; - - var query = new Query("Table") - .AsUpdate(dictionaryUser); - - var c = Compile(query); - - Assert.Equal( - "UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'", - c[EngineCodes.SqlServer]); - } - - [Fact] - public void UpdateUsingReadOnlyDictionary() - { - var dictionaryUser = new ReadOnlyDictionary( - new Dictionary - { - { "Name", "The User" }, - { "Age", new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc) }, - }); - - var query = new Query("Table") - .AsUpdate(dictionaryUser); - - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'", - c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void UpdateUsingExpandoObject() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'")] + public void UpdateUsingExpandoObject(string engine, string sqlText) { dynamic expandoUser = new ExpandoObject(); expandoUser.Name = "The User"; @@ -277,43 +220,53 @@ public void UpdateUsingExpandoObject() var query = new Query("Table") .AsUpdate(expandoUser); - var c = Compile(query); + var result = CompileFor(engine, query); - Assert.Equal( - "UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'", - c[EngineCodes.SqlServer]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void IncrementUpdate() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Table] SET [Total] = [Total] + 1")] + public void IncrementUpdate(string engine, string sqlText) { var query = new Query("Table").AsIncrement("Total"); - var c = Compile(query); - Assert.Equal("UPDATE [Table] SET [Total] = [Total] + 1", c[EngineCodes.SqlServer]); + + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void IncrementUpdateWithValue() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Table] SET [Total] = [Total] + 2")] + public void IncrementUpdateWithValue(string engine, string sqlText) { var query = new Query("Table").AsIncrement("Total", 2); - var c = Compile(query); - Assert.Equal("UPDATE [Table] SET [Total] = [Total] + 2", c[EngineCodes.SqlServer]); + + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void IncrementUpdateWithWheres() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Table] SET [Total] = [Total] + 2 WHERE [Name] = 'A'")] + public void IncrementUpdateWithWheres(string engine, string sqlText) { var query = new Query("Table").Where("Name", "A").AsIncrement("Total", 2); - var c = Compile(query); - Assert.Equal("UPDATE [Table] SET [Total] = [Total] + 2 WHERE [Name] = 'A'", c[EngineCodes.SqlServer]); + + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void DecrementUpdate() + [Theory] + [InlineData(EngineCodes.SqlServer, "UPDATE [Table] SET [Total] = [Total] - 2 WHERE [Name] = 'A'")] + public void DecrementUpdate(string engine, string sqlText) { var query = new Query("Table").Where("Name", "A").AsDecrement("Total", 2); - var c = Compile(query); - Assert.Equal("UPDATE [Table] SET [Total] = [Total] - 2 WHERE [Name] = 'A'", c[EngineCodes.SqlServer]); + + var result = CompileFor(engine, query); + + Assert.Equal(sqlText, result.ToString()); } } } diff --git a/QueryBuilder.Tests/WhereTests.cs b/QueryBuilder.Tests/WhereTests.cs index 0c1254b2..613be6d7 100644 --- a/QueryBuilder.Tests/WhereTests.cs +++ b/QueryBuilder.Tests/WhereTests.cs @@ -1,33 +1,52 @@ -using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; -using Xunit; namespace SqlKata.Tests { public class WhereTests : TestSupport { - [Fact] - public void GroupedWhereFilters() + [Theory] + [InlineData(EngineCodes.PostgreSql, + """SELECT * FROM "Table1" WHERE ("Column1" = 10 OR "Column2" = 20) AND "Column3" = 30""")] + public void GroupedWhereFilters(string engine, string sqlText) { var q = new Query("Table1") .Where(q => q.Or().Where("Column1", 10).Or().Where("Column2", 20)) .Where("Column3", 30); - var c = Compile(q); + var result = CompileFor(engine, q); - Assert.Equal(@"SELECT * FROM ""Table1"" WHERE (""Column1"" = 10 OR ""Column2"" = 20) AND ""Column3"" = 30", c[EngineCodes.PostgreSql]); + Assert.Equal(sqlText, result.ToString()); } - [Fact] - public void GroupedHavingFilters() + [Theory] + [InlineData(EngineCodes.PostgreSql, + """SELECT * FROM "Table1" HAVING (SUM("Column1") = 10 OR SUM("Column2") = 20) AND SUM("Column3") = 30""")] + public void GroupedHavingFilters(string engine, string sqlText) { var q = new Query("Table1") .Having(q => q.Or().HavingRaw("SUM([Column1]) = ?", 10).Or().HavingRaw("SUM([Column2]) = ?", 20)) .HavingRaw("SUM([Column3]) = ?", 30); - var c = Compile(q); + var result = CompileFor(engine, q); - Assert.Equal(@"SELECT * FROM ""Table1"" HAVING (SUM(""Column1"") = 10 OR SUM(""Column2"") = 20) AND SUM(""Column3"") = 30", c[EngineCodes.PostgreSql]); + Assert.Equal(sqlText, result.ToString()); + } + + [Theory] + [InlineData(EngineCodes.Firebird, """SELECT * FROM "TABLE1" WHERE "FIELD1" = Field2""")] + [InlineData(EngineCodes.MySql, "SELECT * FROM `Table1` WHERE `Field1` = Field2")] + [InlineData(EngineCodes.Oracle, """SELECT * FROM "Table1" WHERE "Field1" = Field2""")] + [InlineData(EngineCodes.PostgreSql, """SELECT * FROM "Table1" WHERE "Field1" = Field2""")] + [InlineData(EngineCodes.Sqlite, """SELECT * FROM "Table1" WHERE "Field1" = Field2""")] + [InlineData(EngineCodes.SqlServer, "SELECT * FROM [Table1] WHERE [Field1] = Field2")] + public void UnsafeLiteralConditions(string engine, string sqlText) + { + var q = new Query("Table1") + .Where("Field1", new UnsafeLiteral("Field2")); + + var result = CompileFor(engine, q); + + Assert.Equal(sqlText, result.ToString()); } } } diff --git a/sqlkata.sln b/sqlkata.sln index 957e67a0..4b9382a1 100644 --- a/sqlkata.sln +++ b/sqlkata.sln @@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QueryBuilder.Benchmarks", "QueryBuilder.Benchmarks\QueryBuilder.Benchmarks.csproj", "{4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -74,6 +76,18 @@ Global {5DEA7DBC-5B8A-44A9-A070-55E95881A4CF}.Release|x64.Build.0 = Release|Any CPU {5DEA7DBC-5B8A-44A9-A070-55E95881A4CF}.Release|x86.ActiveCfg = Release|Any CPU {5DEA7DBC-5B8A-44A9-A070-55E95881A4CF}.Release|x86.Build.0 = Release|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Debug|x64.ActiveCfg = Debug|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Debug|x64.Build.0 = Debug|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Debug|x86.ActiveCfg = Debug|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Debug|x86.Build.0 = Debug|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Release|Any CPU.Build.0 = Release|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Release|x64.ActiveCfg = Release|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Release|x64.Build.0 = Release|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Release|x86.ActiveCfg = Release|Any CPU + {4C4BB0A9-0FD3-455D-B4C4-2BB43C5C7388}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE