diff --git a/src/DapperQueryBuilder.StrongName/DapperQueryBuilder.StrongName.csproj b/src/DapperQueryBuilder.StrongName/DapperQueryBuilder.StrongName.csproj
index fd032ac..78af237 100644
--- a/src/DapperQueryBuilder.StrongName/DapperQueryBuilder.StrongName.csproj
+++ b/src/DapperQueryBuilder.StrongName/DapperQueryBuilder.StrongName.csproj
@@ -1,55 +1,59 @@
-
- net461;netstandard2.0;net5.0
- Rick Drizin
- MIT
- https://github.com/Drizin/DapperQueryBuilder/
- Dapper Query Builder using Fluent API and String Interpolation
- Rick Drizin
- Rick Drizin
- 1.2.9
- false
- DapperQueryBuilder (Strong Named)
- DapperQueryBuilder.StrongName
- DapperQueryBuilder.StrongName.xml
- dapper;query-builder;query builder;dapperquerybuilder;dapper-query-builder;dapper-interpolation;dapper-interpolated-string
- true
- true
-
- NuGetReadMe.md
- DapperQueryBuilder.StrongName
-
+
+ netstandard2.0;net462;net472;net5.0;net6.0;net7.0
+ Rick Drizin
+ MIT
+ https://github.com/Drizin/DapperQueryBuilder/
+ Dapper Query Builder using Fluent API and String Interpolation
+ Rick Drizin
+ Rick Drizin
+ 2.0.0-beta1
+ false
+ DapperQueryBuilder (Strong Named)
+ DapperQueryBuilder.StrongName
+ DapperQueryBuilder.StrongName.xml
+ dapper;query-builder;query builder;dapperquerybuilder;dapper-query-builder;dapper-interpolation;dapper-interpolated-string
+ true
+ true
+
+ NuGetReadMe.md
+ DapperQueryBuilder.StrongName
+ enable
+ 8.0
+
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
-
-
-
- True
- ..\debug.snk
-
-
-
-
- True
- ..\release.snk
-
-
-
+
+
+
+ True
+ ..\debug.snk
+
+
+
+
+ True
+ ..\release.snk
+
+
+
-
-
-
-
+
+
+
+
diff --git a/src/DapperQueryBuilder.StrongName/DapperQueryBuilder.StrongName.nuspec b/src/DapperQueryBuilder.StrongName/DapperQueryBuilder.StrongName.nuspec
index 97808c8..59823ca 100644
--- a/src/DapperQueryBuilder.StrongName/DapperQueryBuilder.StrongName.nuspec
+++ b/src/DapperQueryBuilder.StrongName/DapperQueryBuilder.StrongName.nuspec
@@ -13,8 +13,4 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/DapperQueryBuilder.Tests/CommandBuilderTests.cs b/src/DapperQueryBuilder.Tests/CommandBuilderTests.cs
index f73526c..8e6b368 100644
--- a/src/DapperQueryBuilder.Tests/CommandBuilderTests.cs
+++ b/src/DapperQueryBuilder.Tests/CommandBuilderTests.cs
@@ -1,4 +1,4 @@
-using Dapper;
+using InterpolatedSql;
using NUnit.Framework;
using System;
using System.Collections;
@@ -19,7 +19,7 @@ public class CommandBuilderTests
public CommandBuilderTests() { } // nunit requires parameterless constructor
public CommandBuilderTests(bool reuseIdenticalParameters)
{
- DapperQueryBuilderOptions.ReuseIdenticalParameters = reuseIdenticalParameters;
+ InterpolatedSqlBuilder.DefaultOptions.ReuseIdenticalParameters = reuseIdenticalParameters;
}
#region Setup
@@ -49,12 +49,13 @@ public void TestBareCommand()
int subCategoryId = 12;
var query = cn
- .QueryBuilder($@"
+ .QueryBuilder($$"""
SELECT * FROM [Production].[Product]
WHERE
- [Name] LIKE {productName}
- AND [ProductSubcategoryID] = {subCategoryId}
- ORDER BY [ProductId]");
+ [Name] LIKE {{productName}}
+ AND [ProductSubcategoryID] = {{subCategoryId}}
+ ORDER BY [ProductId]
+ """);
Assert.AreEqual(@"
SELECT * FROM [Production].[Product]
@@ -74,12 +75,13 @@ public void TestNameof()
int subCategoryId = 12;
var query = cn
- .QueryBuilder($@"
+ .QueryBuilder($$"""
SELECT * FROM [Production].[Product]
WHERE
- [{nameof(Product.Name):raw}] LIKE {productName}
- AND [ProductSubcategoryID] = {subCategoryId}
- ORDER BY [ProductId]");
+ [{{nameof(Product.Name):raw}}] LIKE {{productName}}
+ AND [ProductSubcategoryID] = {{subCategoryId}}
+ ORDER BY [ProductId]
+ """);
Assert.AreEqual(@"
SELECT * FROM [Production].[Product]
@@ -171,7 +173,9 @@ public void TestStoredProcedureOutput()
.AddParameter("Input1", dbType: DbType.Int32);
//.AddParameter("Output1", dbType: DbType.Int32, direction: ParameterDirection.Output);
//var getter = ParameterInfos.GetSetter((MyPoco p) => p.MyValue);
- cmd.Parameters.Add(ParameterInfo.CreateOutputParameter("Output1", poco, p => p.MyValue, ParameterInfo.OutputParameterDirection.Output, size: 4));
+ var outputParm = new DbTypeParameterInfo("Output1", size: 4);
+ outputParm.ConfigureOutputParameter(poco, p => p.MyValue, SqlParameterInfo.OutputParameterDirection.Output);
+ cmd.AddParameter(outputParm); //TODO: AddOutputParameter? move ConfigureOutputParameter inside it. // previously this was cmd.Parameters.Add, but not Parameters is get-only
int affected = cmd.Execute(commandType: CommandType.StoredProcedure);
string outputValue = cmd.Parameters.Get("Output1"); // why is this being returned as string? just because I didn't provide type above?
@@ -304,10 +308,11 @@ public void TestOperatorOverload()
public void TestAutospacing2()
{
string search = "%mountain%";
- var cmd = cn.CommandBuilder($@"
+ var cmd = cn.CommandBuilder($$"""
SELECT * FROM [Production].[Product]
- WHERE [Name] LIKE {search}
- AND 1=2");
+ WHERE [Name] LIKE {{search}}
+ AND 1=2
+ """);
Assert.AreEqual(
"SELECT * FROM [Production].[Product]" + Environment.NewLine +
"WHERE [Name] LIKE @p0" + Environment.NewLine +
@@ -319,10 +324,11 @@ public void TestAutospacing3()
{
string productNumber = "EC-M092";
int productId = 328;
- var cmd = cn.CommandBuilder($@"
+ var cmd = cn.CommandBuilder($$"""
UPDATE [Production].[Product]
- SET [ProductNumber]={productNumber}
- WHERE [ProductId]={productId}");
+ SET [ProductNumber]={{productNumber}}
+ WHERE [ProductId]={{productId}}
+ """);
string expected =
"UPDATE [Production].[Product]" + Environment.NewLine +
@@ -393,7 +399,7 @@ public void TestRepeatedParameters()
query.Append($"OR [ProductCategoryID]={subCategoryId}");
query.Append($"OR [ProductCategoryID]={categoryId})");
- if (DapperQueryBuilderOptions.ReuseIdenticalParameters)
+ if (InterpolatedSqlBuilder.DefaultOptions.ReuseIdenticalParameters)
{
Assert.AreEqual(@"SELECT * FROM [table1] WHERE ([Name]=@p0 or [Author]=@p0"
+ " or [Creator]=@p0)"
@@ -425,7 +431,7 @@ public void TestRepeatedParameters()
[Test]
public void TestRepeatedParameters2()
{
- if (!DapperQueryBuilderOptions.ReuseIdenticalParameters)
+ if (!InterpolatedSqlBuilder.DefaultOptions.ReuseIdenticalParameters)
return;
int? fileId = null;
@@ -525,7 +531,7 @@ public void TestRepeatedParameters4()
qb.Append($"{"A"}"); // @p21 should reuse @p0
qb.Append($"{"B"}"); // @p22 should reuse @p1
- if (DapperQueryBuilderOptions.ReuseIdenticalParameters)
+ if (InterpolatedSqlBuilder.DefaultOptions.ReuseIdenticalParameters)
Assert.AreEqual("@p0,@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p10,@p11,@p12,@p13,@p14,@p14,@p15,@p16,@p17,@p18,@p19,@p20,@p0 @p1", qb.Sql);
else
Assert.AreEqual("@p0,@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p10,@p11,@p12,@p13,@p14,@p15,@p16,@p17,@p18,@p19,@p20,@p21,@p22 @p23", qb.Sql);
@@ -562,7 +568,7 @@ public void TestRepeatedParameters5()
qb.Append($"{"A"}"); // @p20 should reuse @p0
qb.Append($"{"B"}"); // @p21 should reuse @p1
- if (DapperQueryBuilderOptions.ReuseIdenticalParameters)
+ if (InterpolatedSqlBuilder.DefaultOptions.ReuseIdenticalParameters)
Assert.AreEqual("@p0 @p1 @p2 @p3 @p4 @p5 @p6 @p7 @p8 @p9 @p10 @p11 @p12 @p13 @p14 @p15 @p16 @p17 @p18 @p19 @p0 @p1", qb.Sql);
else
Assert.AreEqual("@p0 @p1 @p2 @p3 @p4 @p5 @p6 @p7 @p8 @p9 @p10 @p11 @p12 @p13 @p14 @p15 @p16 @p17 @p18 @p19 @p20 @p21", qb.Sql);
@@ -585,7 +591,7 @@ public void TestMultipleStatements()
cmd.Append($"DELETE FROM Orders WHERE OrderId = {orderId}; ");
cmd.Append($"INSERT INTO Logs (Action, UserId, Description) VALUES ({action}, {orderId}, {description}); ");
- if (DapperQueryBuilderOptions.ReuseIdenticalParameters)
+ if (InterpolatedSqlBuilder.DefaultOptions.ReuseIdenticalParameters)
{
Assert.AreEqual(cmd.Parameters.Count, 3);
Assert.AreEqual(cmd.Parameters.Get("p0"), orderId);
@@ -691,7 +697,7 @@ declare @v23 nvarchar(10)={v}
var s = query.Sql;
var p = query.Parameters;
- if (DapperQueryBuilderOptions.ReuseIdenticalParameters)
+ if (InterpolatedSqlBuilder.DefaultOptions.ReuseIdenticalParameters)
{
Assert.AreEqual(@"
declare @v1 nvarchar(10)=@p0
@@ -719,7 +725,7 @@ declare @v21 nvarchar(10)=@p0
declare @v22 nvarchar(10)=@p0
declare @v23 nvarchar(10)=@p0
select 'ok'
-".TrimStart(), query.Sql);
+", query.Sql);
Assert.AreEqual(query.Parameters.Get("p0"), v);
Assert.AreEqual(query.Parameters.Get>("parray1"), numList);
@@ -752,7 +758,7 @@ declare @v21 nvarchar(10)=@p21
declare @v22 nvarchar(10)=@p22
declare @v23 nvarchar(10)=@p23
select 'ok'
-".TrimStart(), query.Sql);
+", query.Sql);
Assert.AreEqual(query.Parameters.Get("p0"), v);
Assert.AreEqual(query.Parameters.Get("p1"), v);
@@ -784,7 +790,6 @@ @BusinessEntityID [int]
EXEC [dbo].[uspGetEmployeeManagers] @BusinessEntityID = @BusinessEntityID
END").Execute();
-
var q = cn.CommandBuilder($"[dbo].[uspGetEmployeeManagers_Twice]")
.AddParameter("BusinessEntityID", 280);
diff --git a/src/DapperQueryBuilder.Tests/DapperQueryBuilder.Tests.csproj b/src/DapperQueryBuilder.Tests/DapperQueryBuilder.Tests.csproj
index 4c838d7..ae82d8a 100644
--- a/src/DapperQueryBuilder.Tests/DapperQueryBuilder.Tests.csproj
+++ b/src/DapperQueryBuilder.Tests/DapperQueryBuilder.Tests.csproj
@@ -13,6 +13,7 @@
MIT
https://github.com/Drizin/DapperQueryBuilder/
+ 11.0
diff --git a/src/DapperQueryBuilder.Tests/FluentQueryBuilderTests.cs b/src/DapperQueryBuilder.Tests/FluentQueryBuilderTests.cs
index 4e899ad..79062bf 100644
--- a/src/DapperQueryBuilder.Tests/FluentQueryBuilderTests.cs
+++ b/src/DapperQueryBuilder.Tests/FluentQueryBuilderTests.cs
@@ -1,3 +1,4 @@
+using InterpolatedSql;
using NUnit.Framework;
using System;
using System.Collections.Generic;
@@ -22,8 +23,7 @@ public void Setup()
string expected = @"SELECT ProductId, Name, ListPrice, Weight
FROM [Production].[Product]
WHERE [ListPrice] <= @p0 AND [Weight] <= @p1 AND [Name] LIKE @p2
-ORDER BY ProductId
-";
+ORDER BY ProductId";
public class Product
{
@@ -112,8 +112,7 @@ FROM [Production].[Product] p
LEFT JOIN [Production].[ProductCategory] cat on sc.[ProductCategoryID]=cat.[ProductCategoryID]
WHERE p.[ListPrice] BETWEEN @p0 and @p1 AND cat.[Name] IS NOT NULL
GROUP BY cat.[Name], sc.[Name]
-HAVING COUNT(*)>@p2
-";
+HAVING COUNT(*)>@p2";
Assert.AreEqual(expected, q.Sql);
@@ -134,8 +133,7 @@ public void TestAndOr()
string expected = @"SELECT ProductId, Name, ListPrice, Weight
FROM [Production].[Product]
WHERE [ListPrice] <= @p0 AND ([Weight] <= @p1 OR [Name] LIKE @p2)
-ORDER BY ProductId
-";
+ORDER BY ProductId";
var q = cn.FluentQueryBuilder()
.Select($"ProductId")
@@ -174,8 +172,7 @@ public void TestAndOr2()
string expected = @"SELECT ProductId, Name, ListPrice, Weight
FROM [Production].[Product]
-WHERE ([ListPrice] >= @p0 AND [ListPrice] <= @p1) AND ([Weight] <= @p2 OR [Name] LIKE @p3)
-";
+WHERE ([ListPrice] >= @p0 AND [ListPrice] <= @p1) AND ([Weight] <= @p2 OR [Name] LIKE @p3)";
var q = cn.FluentQueryBuilder()
.Select($"ProductId, Name, ListPrice, Weight")
@@ -226,6 +223,12 @@ public void TestDetachedFilters()
string where = filters.BuildFilters(parms);
Assert.AreEqual(@"WHERE ([ListPrice] >= @p0 AND [ListPrice] <= @p1) AND ([Weight] <= @p2 OR [Name] LIKE @p3)", where);
+
+ Assert.AreEqual(4, parms.ParameterNames.Count());
+ Assert.AreEqual(minPrice, parms.Get("p0"));
+ Assert.AreEqual(maxPrice, parms.Get("p1"));
+ Assert.AreEqual(maxWeight, parms.Get("p2"));
+ Assert.AreEqual(search, parms.Get("p3"));
}
[Test]
@@ -262,8 +265,7 @@ FROM [Production].[Product] p
WHERE p.[ListPrice] BETWEEN @p0 and @p1 AND cat.[Name] IS NOT NULL
GROUP BY cat.[Name]
HAVING COUNT(*)>@p2
-ORDER BY cat.[Name]
-";
+ORDER BY cat.[Name]";
Assert.AreEqual(expected, q.Sql);
@@ -291,8 +293,7 @@ FROM [Production].[Product] p
LEFT JOIN [Production].[ProductSubcategory] sc ON p.[ProductSubcategoryID]=sc.[ProductSubcategoryID]
LEFT JOIN [Production].[ProductCategory] cat on sc.[ProductCategoryID]=cat.[ProductCategoryID]
GROUP BY cat.[Name]
-HAVING COUNT(*)>@p0
-";
+HAVING COUNT(*)>@p0";
Assert.AreEqual(expected, q.Sql);
@@ -332,11 +333,9 @@ public void FluentQueryBuilderInsideCommandBuilder()
string expected =
@"SELECT * FROM [Sales].[SalesOrderDetail] WHERE [ProductId] IN (SELECT ProductId
FROM [Production].[Product]
-WHERE [ListPrice] <= @p0 AND [Weight] <= @p1 AND [Name] LIKE @p2
-) AND [SalesOrderId] IN (SELECT SalesOrderID
+WHERE [ListPrice] <= @p0 AND [Weight] <= @p1 AND [Name] LIKE @p2) AND [SalesOrderId] IN (SELECT SalesOrderID
FROM [Sales].[SalesOrderHeader]
-WHERE [CustomerId] = @p3 AND [Status] IN @parray4
-)";
+WHERE [CustomerId] = @p3 AND [Status] IN @parray4)";
Assert.AreEqual(expected, finalQuery.Sql);
Assert.That(finalQuery.Parameters.ParameterNames.Contains("p0"));
diff --git a/src/DapperQueryBuilder.Tests/PostgreSQLTests.cs b/src/DapperQueryBuilder.Tests/PostgreSQLTests.cs
index f454c8b..dcbc732 100644
--- a/src/DapperQueryBuilder.Tests/PostgreSQLTests.cs
+++ b/src/DapperQueryBuilder.Tests/PostgreSQLTests.cs
@@ -1,11 +1,8 @@
-using Npgsql;
+using InterpolatedSql;
+using Npgsql;
using NUnit.Framework;
-using System;
-using System.Collections.Generic;
using System.Data;
-using System.Data.OleDb;
using System.Linq;
-using System.Text;
namespace DapperQueryBuilder.Tests
{
@@ -23,8 +20,8 @@ public void Setup()
public void TearDown()
{
// reverting back for next unit tests
- DapperQueryBuilderOptions.DatabaseParameterSymbol = "@";
- DapperQueryBuilderOptions.AutoGeneratedParameterName = "p";
+ InterpolatedSqlBuilder.DefaultOptions.DatabaseParameterSymbol = "@";
+ InterpolatedSqlBuilder.DefaultOptions.AutoGeneratedParameterPrefix = "p";
}
#endregion
@@ -56,8 +53,8 @@ public void TestParameters()
public void TestAutoGeneratedParameterPrefix()
{
// Npgsql does NOT require this, but it may be required in some databases/drivers which do not accept "at-parameters" (@p0, @p1, etc).
- DapperQueryBuilderOptions.DatabaseParameterSymbol = ":";
- DapperQueryBuilderOptions.AutoGeneratedParameterName = "parm";
+ InterpolatedSqlBuilder.DefaultOptions.DatabaseParameterSymbol = ":";
+ InterpolatedSqlBuilder.DefaultOptions.AutoGeneratedParameterPrefix = "parm";
string search = "%Dinosaur%";
var cmd = cn.QueryBuilder($"SELECT * FROM film WHERE title like {search}");
diff --git a/src/DapperQueryBuilder.Tests/QueryBuilderTests.cs b/src/DapperQueryBuilder.Tests/QueryBuilderTests.cs
index fc5c852..f37ecf5 100644
--- a/src/DapperQueryBuilder.Tests/QueryBuilderTests.cs
+++ b/src/DapperQueryBuilder.Tests/QueryBuilderTests.cs
@@ -1,6 +1,6 @@
+using InterpolatedSql;
using NUnit.Framework;
using System;
-using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
@@ -107,6 +107,12 @@ public void TestDetachedFilters()
string where = filters.BuildFilters(parms);
Assert.AreEqual(@"WHERE ([ListPrice] >= @p0 AND [ListPrice] <= @p1) AND ([Weight] <= @p2 OR [Name] LIKE @p3)", where);
+
+ Assert.AreEqual(4, parms.ParameterNames.Count());
+ Assert.AreEqual(minPrice, parms.Get("p0"));
+ Assert.AreEqual(maxPrice, parms.Get("p1"));
+ Assert.AreEqual(maxWeight, parms.Get("p2"));
+ Assert.AreEqual(search, parms.Get("p3"));
}
[Test]
diff --git a/src/DapperQueryBuilder/CommandBuilder.cs b/src/DapperQueryBuilder/CommandBuilder.cs
deleted file mode 100644
index c155e9e..0000000
--- a/src/DapperQueryBuilder/CommandBuilder.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-using Dapper;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-
-namespace DapperQueryBuilder
-{
- ///
- /// CommandBuilder wraps an underlying SQL statement and the associated parameters.
- /// Allows to easily add new clauses to underlying statement and also add new parameters.
- ///
- [DebuggerDisplay("{Sql} ({_parametersStr,nq})")]
- public class CommandBuilder : ICompleteCommand
- {
- #region Members
- private readonly IDbConnection _cnn;
- private readonly ParameterInfos _parameters;
- private string _parametersStr;
-
- private readonly StringBuilder _command;
-
- ///
- public IDbConnection Connection { get { return _cnn; } }
-
- #endregion
-
- #region statics/constants
-
- ///
- /// Identify all types of line-breaks
- ///
- protected static readonly Regex _lineBreaksRegex = new Regex(@"(\r\n|\n|\r)", RegexOptions.Compiled);
-
- #endregion
-
- #region ctors
- ///
- /// New CommandBuilder.
- ///
- ///
- public CommandBuilder(IDbConnection cnn)
- {
- _cnn = cnn;
- _command = new StringBuilder();
- _parameters = new ParameterInfos();
- }
-
- ///
- /// New CommandBuilder based on an initial command.
- /// Parameters embedded using string-interpolation will be automatically converted into Dapper parameters.
- ///
- ///
- /// SQL command
- public CommandBuilder(IDbConnection cnn, FormattableString command) : this(cnn)
- {
- var parsedStatement = new InterpolatedStatementParser(command);
- parsedStatement.MergeParameters(this.Parameters);
- string sql = AdjustMultilineString(parsedStatement.Sql);
- _command.Append(sql);
- }
- #endregion
-
- #region Parameters Adding/Merging
- ///
- /// Adds single parameter to current Command Builder.
- ///
- public CommandBuilder AddParameter(string parameterName, object parameterValue = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null, byte? precision = null, byte? scale = null)
- {
- _parameters.Add(new ParameterInfo(parameterName, parameterValue, dbType, direction, size, precision, scale));
- _parametersStr = string.Join(", ", _parameters.ParameterNames.ToList().Select(n => DapperQueryBuilderOptions.DatabaseParameterSymbol + n + "='" + Convert.ToString(Parameters.Get(n)) + "'"));
- return this;
- }
-
-
- ///
- /// Adds all public properties of an object (like a POCO) as parameters of the current Command Builder.
- /// This is like Dapper templates: useful when you're passing an object with multiple properties and you'll reference those properties in the SQL statement.
- /// This method does not check for name clashes against previously added parameters.
- ///
- public void AddObjectProperties(object obj)
- {
- Dictionary props =
- obj.GetType()
- .GetProperties(BindingFlags.Public | BindingFlags.Instance)
- .ToDictionary(prop => prop.Name, prop => prop);
-
- foreach (var prop in props)
- {
- _parameters.Add(new ParameterInfo(prop.Key, prop.Value.GetValue(obj, new object[] { })));
- }
- _parametersStr = string.Join(", ", _parameters.ParameterNames.ToList().Select(n => DapperQueryBuilderOptions.DatabaseParameterSymbol + n + "='" + Convert.ToString(Parameters.Get(n)) + "'"));
- }
- #endregion
-
-
-
- ///
- /// Appends a statement to the current command.
- /// Parameters embedded using string-interpolation will be automatically converted into Dapper parameters.
- ///
- /// SQL command
- public CommandBuilder Append(FormattableString statement)
- {
- var parsedStatement = new InterpolatedStatementParser(statement);
- parsedStatement.MergeParameters(this.Parameters);
- string sql = AdjustMultilineString(parsedStatement.Sql);
- if (!string.IsNullOrWhiteSpace(sql))
- {
- // we assume that a single word will always be appended in a single statement (why would anyone split a single sql word in 2 appends?!),
- // so if there is no whitespace (or line break) between last text and new text, we add a space betwen them
- string currentLine = _command.ToString().Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None).LastOrDefault();
- if (currentLine != null && currentLine.Length > 0 && !char.IsWhiteSpace(currentLine.Last()) && currentLine.Last()!=',' && !char.IsWhiteSpace(sql[0]))
- _command.Append(" ");
- }
- _command.Append(sql);
- return this;
- }
-
- ///
- /// Appends a statement to the current command.
- /// Parameters embedded using string-interpolation will be automatically converted into Dapper parameters.
- ///
- public static CommandBuilder operator + (CommandBuilder cmd, FormattableString fs)
- {
- return cmd.Append(fs);
- }
-
- ///
- /// Replaces a text by a replacement text
- ///
- public CommandBuilder Replace(string oldValue, FormattableString newValue)
- {
- var parsedStatement = new InterpolatedStatementParser(newValue);
- parsedStatement.MergeParameters(this.Parameters);
- string sql = AdjustMultilineString(parsedStatement.Sql);
- _command.Replace(oldValue, sql);
- return this;
- }
-
-
-
-
-
-
- #region Multi-line blocks can be conveniently used with any indentation, and we will correctly adjust the indentation of those blocks (TrimLeftPadding and TrimFirstEmptyLine)
- ///
- /// Given a text block (multiple lines), this removes the left padding of the block, by calculating the minimum number of spaces which happens in EVERY line.
- /// Then, other methods writes the lines one by one, which in case will respect the current indent of the writer.
- ///
- protected string AdjustMultilineString(string block)
- {
- // copied from https://github.com/Drizin/CodegenCS/
-
- if (string.IsNullOrEmpty(block))
- return null;
- string[] parts = _lineBreaksRegex.Split(block);
- if (parts.Length <= 1) // no linebreaks at all
- return block;
- var nonEmptyLines = parts.Where(line => line.TrimEnd().Length > 0).ToList();
- if (nonEmptyLines.Count <= 1) // if there's not at least 2 non-empty lines, assume that we don't need to adjust anything
- return block;
-
- Match m = _lineBreaksRegex.Match(block);
- if (m != null && m.Success && m.Index == 0)
- {
- block = block.Substring(m.Length); // remove first empty line
- parts = _lineBreaksRegex.Split(block);
- nonEmptyLines = parts.Where(line => line.TrimEnd().Length > 0).ToList();
- }
-
-
- int minNumberOfSpaces = nonEmptyLines.Select(nonEmptyLine => nonEmptyLine.Length - nonEmptyLine.TrimStart().Length).Min();
-
- StringBuilder sb = new StringBuilder();
-
- var matches = _lineBreaksRegex.Matches(block);
- int lastPos = 0;
- for (int i = 0; i < matches.Count; i++)
- {
- string line = block.Substring(lastPos, matches[i].Index - lastPos);
- string lineBreak = block.Substring(matches[i].Index, matches[i].Length);
- lastPos = matches[i].Index + matches[i].Length;
-
- sb.Append(line.Substring(Math.Min(line.Length, minNumberOfSpaces)));
- sb.Append(lineBreak);
- }
- string lastLine = block.Substring(lastPos);
- sb.Append(lastLine.Substring(Math.Min(lastLine.Length, minNumberOfSpaces)));
-
- return sb.ToString();
- }
- #endregion
-
-
- ///
- /// Appends a statement to the current command, but before statement adds a linebreak.
- /// Parameters embedded using string-interpolation will be automatically converted into Dapper parameters.
- ///
- /// SQL command
- public CommandBuilder AppendLine(FormattableString statement)
- {
- // instead of appending line AFTER the statement it makes sense to add BEFORE, just to ISOLATE the new line from previous one
- // there's no point in having linebreaks at the end of a query
- _command.AppendLine();
-
- this.Append(statement);
- return this;
- }
-
-
- ///
- /// SQL of Command
- ///
- public virtual string Sql => _command.ToString(); // base CommandBuilder will just have a single variable for the statement;
-
- ///
- /// Parameters of Command
- ///
- public virtual ParameterInfos Parameters => _parameters;
-
- }
-}
diff --git a/src/DapperQueryBuilder/Dapper-QueryBuilder.nuspec b/src/DapperQueryBuilder/Dapper-QueryBuilder.nuspec
index 04055c1..206d97e 100644
--- a/src/DapperQueryBuilder/Dapper-QueryBuilder.nuspec
+++ b/src/DapperQueryBuilder/Dapper-QueryBuilder.nuspec
@@ -13,8 +13,4 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/DapperQueryBuilder/DapperQueryBuilder.csproj b/src/DapperQueryBuilder/DapperQueryBuilder.csproj
index 355db0c..de50458 100644
--- a/src/DapperQueryBuilder/DapperQueryBuilder.csproj
+++ b/src/DapperQueryBuilder/DapperQueryBuilder.csproj
@@ -1,46 +1,50 @@
-
- net461;netstandard2.0;net5.0
- Rick Drizin
- MIT
- https://github.com/Drizin/DapperQueryBuilder/
- Dapper Query Builder using Fluent API and String Interpolation
- Rick Drizin
- Rick Drizin
- 1.2.9
- false
- DapperQueryBuilder
- Dapper-QueryBuilder
- DapperQueryBuilder.xml
- dapper;query-builder;query builder;dapperquerybuilder;dapper-query-builder;dapper-interpolation;dapper-interpolated-string
- true
- true
-
- NuGetReadMe.md
- DapperQueryBuilder
-
+
+ netstandard2.0;net462;net472;net5.0;net6.0;net7.0
+ Rick Drizin
+ MIT
+ https://github.com/Drizin/DapperQueryBuilder/
+ Dapper Query Builder using Fluent API and String Interpolation
+ Rick Drizin
+ Rick Drizin
+ 2.0.0-beta1
+ false
+ DapperQueryBuilder
+ Dapper-QueryBuilder
+ DapperQueryBuilder.xml
+ dapper;query-builder;query builder;dapperquerybuilder;dapper-query-builder;dapper-interpolation;dapper-interpolated-string
+ true
+ true
+
+ NuGetReadMe.md
+ DapperQueryBuilder
+ enable
+ 8.0
+
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/DapperQueryBuilder/DapperQueryBuilderOptions.cs b/src/DapperQueryBuilder/DapperQueryBuilderOptions.cs
index b183eb3..614c6ca 100644
--- a/src/DapperQueryBuilder/DapperQueryBuilderOptions.cs
+++ b/src/DapperQueryBuilder/DapperQueryBuilderOptions.cs
@@ -1,39 +1,16 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+using InterpolatedSql;
namespace DapperQueryBuilder
{
///
- /// Global options for DapperQueryBuilder
+ /// Global Options
///
public class DapperQueryBuilderOptions
{
///
- /// In the rendered SQL statement the parameters by default are named like @p0, @p1, etc.
- /// You can change the name p0/p1/etc to any other prfix.
- /// Example: if you set to "arg" you'll get @arg0, @arg1, etc.
+ /// Responsible for parsing SqlParameters (see )
+ /// into a list of SqlParameterInfo that
///
- public static string AutoGeneratedParameterName { get; set; } = "p";
-
- ///
- /// String that is appended to the parameter name for enumerable types to avoid name conflicts.
- ///
- public static string ParameterArrayNameSuffix { get; set; } = "array";
-
- ///
- /// In the rendered SQL statement the parameters by default are named like @p0, @p1, etc.
- /// If your database does not accept @ symbol you can change for any other symbol.
- /// For Oracle you should use ":"
- ///
- public static string DatabaseParameterSymbol { get; set; } = "@";
-
-
- ///
- /// If enabled (default is disabled) each added parameter will check if identical parameter (same type and value)
- /// was already added, and if so will reuse the existing parameter.
- ///
- public static bool ReuseIdenticalParameters { get; set; } = false;
-
+ public static SqlParameterMapper InterpolatedSqlParameterParser = new SqlParameterMapper();
}
}
diff --git a/src/DapperQueryBuilder/Filter.cs b/src/DapperQueryBuilder/Filter.cs
deleted file mode 100644
index e6ef974..0000000
--- a/src/DapperQueryBuilder/Filter.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using Dapper;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-
-namespace DapperQueryBuilder
-{
- ///
- /// Filter statement defined in a single statement
- /// It can include multiple conditions (if defined in a single statement during constructor),
- /// but usually this is used as one condition (one column, one comparison operator, and one parameter).
- ///
- [DebuggerDisplay("{Sql} ({_parametersStr,nq})")]
- public class Filter : IFilter
- {
- #region Members
- ///
- /// Formatted SQL statement using parameters (@p0, @p1, etc)
- ///
- public string Sql { get; set; }
-
- ///
- /// Dictionary of Dapper parameters
- ///
- public ParameterInfos Parameters { get; set; }
-
- private string _parametersStr;
- #endregion
-
- #region ctor
- ///
- /// New Filter statement.
- /// Example: $"[CategoryId] = {categoryId}"
- /// Example: $"[Name] LIKE {productName}"
- ///
- public Filter(FormattableString filter)
- {
- var parsedStatement = new InterpolatedStatementParser(filter);
- Sql = parsedStatement.Sql;
- Parameters = parsedStatement.Parameters;
- _parametersStr = string.Join(", ", Parameters.ParameterNames.ToList().Select(n => DapperQueryBuilderOptions.DatabaseParameterSymbol + n + "='" + Convert.ToString(Parameters.Get(n)) + "'"));
- }
- #endregion
-
- #region IFilter
- ///
- public void WriteFilter(StringBuilder sb)
- {
- sb.Append(Sql);
- }
-
- ///
- public void MergeParameters(ParameterInfos target)
- {
- string newSql = target.MergeParameters(Parameters, Sql);
- if (newSql != null)
- {
- Sql = newSql;
- //_parametersStr = string.Join(", ", Parameters.ParameterNames.ToList().Select(n => "@" + n + "='" + Convert.ToString(Parameters.Get(n)) + "'"));
- _parametersStr = string.Join(", ", Parameters.ParameterNames.ToList().Select(n => "'" + Convert.ToString(Parameters.Get(n)) + "'"));
- // filter parameters in Sql were renamed and won't match the previous passed filters - discard original parameters to avoid reusing wrong values
- Parameters = null;
- }
- }
- #endregion
- }
-}
diff --git a/src/DapperQueryBuilder/FilterExtensions.cs b/src/DapperQueryBuilder/FilterExtensions.cs
new file mode 100644
index 0000000..0de9e81
--- /dev/null
+++ b/src/DapperQueryBuilder/FilterExtensions.cs
@@ -0,0 +1,27 @@
+using Dapper;
+using InterpolatedSql;
+
+namespace DapperQueryBuilder
+{
+ public static class FilterExtensions
+ {
+ ///
+ /// If you're using Filters in standalone structure (without QueryBuilder),
+ /// you can just "build" the filters over a ParameterInfos and get the string for the filters (with leading WHERE)
+ ///
+ public static string BuildFilters(this Filters filters, DynamicParameters target)
+ {
+ ParametersDictionary parameters = new ParametersDictionary();
+ foreach (var parameter in parameters.Values)
+ SqlParameterMapper.Default.AddToDynamicParameters(target, parameter);
+
+ InterpolatedSqlBuilder command = new InterpolatedSqlBuilder();
+ filters.WriteTo(command);
+ if (!command.IsEmpty)
+ command.InsertLiteral(0, "WHERE ");
+ foreach(var parameter in ParametersDictionary.LoadFrom(command))
+ SqlParameterMapper.Default.AddToDynamicParameters(target, parameter.Value);
+ return command.Sql;
+ }
+ }
+}
diff --git a/src/DapperQueryBuilder/Filters.cs b/src/DapperQueryBuilder/Filters.cs
deleted file mode 100644
index 3c84c01..0000000
--- a/src/DapperQueryBuilder/Filters.cs
+++ /dev/null
@@ -1,134 +0,0 @@
-using Dapper;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-
-namespace DapperQueryBuilder
-{
- ///
- /// Multiple Filter statements which are grouped together. Can be grouped with ANDs or ORs.
- ///
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
- public class Filters : List, IFilter
- {
- #region Members
- ///
- /// By default Filter Groups are combined with AND operator. But you can use OR.
- ///
- public FiltersType Type { get; set; } = FiltersType.AND;
-
- ///
- /// How a list of Filters are combined (AND operator or OR operator)
- ///
- public enum FiltersType
- {
- ///
- /// AND
- ///
- AND,
-
- ///
- /// OR
- ///
- OR
- }
- #endregion
-
- #region ctor
-
- ///
- /// Create a new group of filters.
- ///
- public Filters(FiltersType type, IEnumerable filters)
- {
- Type = type;
- this.AddRange(filters);
- }
-
- ///
- /// Create a new group of filters which are combined with AND operator.
- ///
- public Filters(IEnumerable filters): this(FiltersType.AND, filters)
- {
- }
-
- ///
- /// Create a new group of filters from formattable strings
- ///
- public Filters(FiltersType type, params FormattableString[] filters):
- this(type, filters.Select(fiString => new Filter(fiString)))
- {
- }
-
- ///
- /// Create a new group of filters from formattable strings which are combined with AND operator.
- ///
- public Filters(params FormattableString[] filters) : this(FiltersType.AND, filters)
- {
- }
- #endregion
-
- #region IFilter
- ///
- public void WriteFilter(StringBuilder sb)
- {
- //if (this.Count() > 1)
- // sb.Append("(");
- for (int i = 0; i < this.Count(); i++)
- {
- if (i > 0 && Type == FiltersType.AND)
- sb.Append(" AND ");
- else if (i > 0 && Type == FiltersType.OR)
- sb.Append(" OR ");
- IFilter filter = this[i];
- if (filter is Filters && ((Filters)filter).Count() > 1) // only put brackets in groups after the first level
- {
- sb.Append("(");
- filter.WriteFilter(sb);
- sb.Append(")");
- }
- else
- filter.WriteFilter(sb);
- }
- //if (this.Count() > 1)
- // sb.Append(")");
- }
-
- ///
- public void MergeParameters(ParameterInfos target)
- {
- foreach(IFilter filter in this)
- {
- filter.MergeParameters(target);
- }
- }
-
- ///
- /// If you're using Filters in standalone structure (without QueryBuilder),
- /// you can just "build" the filters over a ParameterInfos and get the string for the filters (with leading WHERE)
- ///
- ///
- ///
- public string BuildFilters(DynamicParameters target)
- {
- ParameterInfos parameters = new ParameterInfos();
- foreach (IFilter filter in this)
- {
- filter.MergeParameters(parameters);
- }
- foreach (var parameter in parameters.Values)
- target.Add(parameter.Name, parameter.Value, parameter.DbType, parameter.ParameterDirection, parameter.Size);
- StringBuilder sb = new StringBuilder();
- WriteFilter(sb);
- if (sb.Length > 0)
- return "WHERE " + sb.ToString();
- return "";
- }
-
- private string DebuggerDisplay { get { StringBuilder sb = new StringBuilder(); sb.Append($"({this.Count()} filters): "); WriteFilter(sb); return sb.ToString(); } }
- #endregion
-
- }
-}
diff --git a/src/DapperQueryBuilder/FluentQueryBuilder/FluentQueryBuilder.cs b/src/DapperQueryBuilder/FluentQueryBuilder/FluentQueryBuilder.cs
index 9ad7484..2a84e1b 100644
--- a/src/DapperQueryBuilder/FluentQueryBuilder/FluentQueryBuilder.cs
+++ b/src/DapperQueryBuilder/FluentQueryBuilder/FluentQueryBuilder.cs
@@ -1,9 +1,7 @@
-using Dapper;
+using InterpolatedSql;
using System;
-using System.Collections.Generic;
using System.Data;
using System.Linq;
-using System.Text;
using System.Text.RegularExpressions;
namespace DapperQueryBuilder
@@ -11,16 +9,13 @@ namespace DapperQueryBuilder
///
/// FluentQueryBuilder allows to build queries using a Fluent-API interface
///
- public class FluentQueryBuilder : IEmptyQueryBuilder, ISelectBuilder, ISelectDistinctBuilder, IFromBuilder, IWhereBuilder, IGroupByBuilder, IGroupByHavingBuilder, IOrderByBuilder, ICompleteCommand
+ public class FluentQueryBuilder : QueryBuilder, IEmptyQueryBuilder, ISelectBuilder, ISelectDistinctBuilder, IFromBuilder, IWhereBuilder, IGroupByBuilder, IGroupByHavingBuilder, IOrderByBuilder, ICompleteCommand
{
#region Members
- private readonly QueryBuilder _queryBuilder;
- private readonly List _selectColumns = new List();
- private readonly List _fromTables = new List();
- private readonly List _orderBy = new List();
- private readonly List _groupBy = new List();
- private readonly List _having = new List();
+ private readonly InterpolatedSqlBuilder _orderBy = new InterpolatedSqlBuilder();
+ private readonly InterpolatedSqlBuilder _groupBy = new InterpolatedSqlBuilder();
+ private readonly InterpolatedSqlBuilder _having = new InterpolatedSqlBuilder();
private int? _rowCount = null;
private int? _offset = null;
private bool _isSelectDistinct = false;
@@ -32,21 +27,16 @@ public class FluentQueryBuilder : IEmptyQueryBuilder, ISelectBuilder, ISelectDis
/// Should be constructed using .Select(), .From(), .Where(), etc.
///
///
- public FluentQueryBuilder(IDbConnection cnn)
- {
- _queryBuilder = new QueryBuilder(cnn);
- }
+ public FluentQueryBuilder(IDbConnection cnn) : base(cnn) { }
#endregion
- #region Fluent API methods
+#region Fluent API methods
///
/// Adds one column to the select clauses
///
- public ISelectBuilder Select(FormattableString column)
+ public new ISelectBuilder Select(FormattableString column)
{
- var parsedStatement = new InterpolatedStatementParser(column);
- parsedStatement.MergeParameters(this.Parameters);
- _selectColumns.Add(parsedStatement.Sql);
+ base.Select(column);
return this;
}
@@ -67,9 +57,7 @@ public ISelectBuilder Select(params FormattableString[] moreColumns)
public ISelectDistinctBuilder SelectDistinct(FormattableString select)
{
_isSelectDistinct = true;
- var parsedStatement = new InterpolatedStatementParser(select);
- parsedStatement.MergeParameters(this.Parameters);
- _selectColumns.Add(parsedStatement.Sql);
+ base.Select(select);
return this;
}
@@ -90,14 +78,13 @@ public ISelectDistinctBuilder SelectDistinct(params FormattableString[] moreColu
/// You can add an alias after table name.
/// You can also add INNER JOIN, LEFT JOIN, etc (with the matching conditions).
///
- public IFromBuilder From(FormattableString from)
+ public new IFromBuilder From(FormattableString from)
{
- var parsedStatement = new InterpolatedStatementParser(from);
- parsedStatement.MergeParameters(this.Parameters);
- string sql = parsedStatement.Sql;
- if (!_fromTables.Any() && !Regex.IsMatch(sql, "\\b FROM \\b", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace))
- sql = "FROM " + sql;
- _fromTables.Add(sql);
+ var target = new InterpolatedSqlBuilder();
+ base.Options.Parser.ParseAppend(from, target);
+ if (_froms.IsEmpty && !Regex.IsMatch(target.Sql, "\\b FROM \\b", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace))
+ target.InsertLiteral(0, "FROM ");
+ base.From((FormattableString)target);
return this;
}
//TODO: create options with InnerJoin, LeftJoin, RightJoin, FullJoin, CrossJoin? Create overloads with table alias?
@@ -108,9 +95,9 @@ public IFromBuilder From(FormattableString from)
///
public IOrderByBuilder OrderBy(FormattableString orderBy)
{
- var parsedStatement = new InterpolatedStatementParser(orderBy);
- parsedStatement.MergeParameters(this.Parameters);
- _orderBy.Add(parsedStatement.Sql);
+ if (!_orderBy.IsEmpty)
+ _orderBy.AppendLiteral(", ");
+ _orderBy.Append(orderBy);
return this;
}
@@ -119,9 +106,9 @@ public IOrderByBuilder OrderBy(FormattableString orderBy)
///
public IGroupByBuilder GroupBy(FormattableString groupBy)
{
- var parsedStatement = new InterpolatedStatementParser(groupBy);
- parsedStatement.MergeParameters(this.Parameters);
- _groupBy.Add(parsedStatement.Sql);
+ if (!_groupBy.IsEmpty)
+ _groupBy.AppendLiteral(", ");
+ _groupBy.Append(groupBy);
return this;
}
@@ -130,9 +117,9 @@ public IGroupByBuilder GroupBy(FormattableString groupBy)
///
public IGroupByHavingBuilder Having(FormattableString having)
{
- var parsedStatement = new InterpolatedStatementParser(having);
- parsedStatement.MergeParameters(this.Parameters);
- _having.Add(parsedStatement.Sql);
+ if (!_having.IsEmpty)
+ _having.AppendLiteral(", ");
+ _having.Append(having);
return this;
}
@@ -146,24 +133,24 @@ public ICompleteCommand Limit(int offset, int rowCount)
return this;
}
- #endregion
+#endregion
- #region Where overrides
+#region Where overrides
///
/// Adds a new condition to where clauses.
///
- public IWhereBuilder Where(Filter filter)
+ public new IWhereBuilder Where(Filter filter)
{
- _queryBuilder.Where(filter);
+ base.Where(filter);
return this;
}
///
/// Adds a new condition to where clauses.
///
- public IWhereBuilder Where(Filters filters)
+ public new IWhereBuilder Where(Filters filters)
{
- _queryBuilder.Where(filters);
+ base.Where(filters);
return this;
}
@@ -172,64 +159,68 @@ public IWhereBuilder Where(Filters filters)
/// Adds a new condition to where clauses.
/// Parameters embedded using string-interpolation will be automatically converted into Dapper parameters.
///
- public IWhereBuilder Where(FormattableString filter)
+ public new IWhereBuilder Where(FormattableString filter)
{
- _queryBuilder.Where(filter);
+ base.Where(filter);
return this;
}
- #endregion
+#endregion
+#region ICompleteCommand
- #region ICompleteCommand
+#region Sql
- #region Sql
///
- ///
+ /// Gets the combined command
///
- public string Sql
+ public override InterpolatedSqlBuilder CombinedQuery
{
get
{
- //TODO: bool AutoLineBreaks - if false don't use AppendLine()
- StringBuilder finalSql = new StringBuilder();
+ if (_cachedCombinedQuery != null)
+ return _cachedCombinedQuery;
- // If Query Template is provided, we assume it contains both SELECT and FROMs
- if (_selectColumns.Any())
- finalSql.AppendLine($"SELECT {(_isSelectDistinct ? "DISTINCT " : "")}{string.Join(", ", _selectColumns)}");
+ _cachedCombinedQuery = new InterpolatedSqlBuilder(Options);
+
+ _cachedCombinedQuery.AppendLiteral("SELECT ").AppendLiteral(_isSelectDistinct ? "DISTINCT " : "");
+ if (_selects.IsEmpty)
+ _cachedCombinedQuery.AppendLiteral("*");
else
- finalSql.AppendLine($"SELECT {(_isSelectDistinct ? "DISTINCT " : "")}*");
+ _cachedCombinedQuery.Append(_selects);
+
+
+
+ if (!_froms.IsEmpty)
+ {
+ _froms.TrimEnd();
+ _cachedCombinedQuery.AppendLine(_froms); //TODO: inner join and left/outer join shortcuts?
+ // TODO: AppendLine adds linebreak BEFORE the value - is that a little counterintuitive?
+ }
- if (_fromTables.Any())
- finalSql.AppendLine($"{string.Join(Environment.NewLine, _fromTables)}"); //TODO: inner join and left/outer join shortcuts?
- string filters = _queryBuilder.GetFilters();
- if (filters != null)
- finalSql.AppendLine("WHERE " + filters);
+ if (_filters.Any())
+ {
+ var filters = GetFilters()!;
- if (_groupBy.Any())
- finalSql.AppendLine($"GROUP BY {string.Join(", ", _groupBy)}");
- if (_having.Any())
- finalSql.AppendLine($"HAVING {string.Join(" AND ", _having)}");
- if (_orderBy.Any())
- finalSql.AppendLine($"ORDER BY {string.Join(", ", _orderBy)}");
+ _cachedCombinedQuery.AppendLine().AppendLiteral("WHERE ").Append(filters);
+ }
+
+ if (!_groupBy.IsEmpty)
+ _cachedCombinedQuery.AppendLine().AppendLiteral("GROUP BY").Append(_groupBy);
+ if (!_having.IsEmpty)
+ _cachedCombinedQuery.AppendLine().AppendLiteral("HAVING ").Append(_having);
+ if (!_orderBy.IsEmpty)
+ _cachedCombinedQuery.AppendLine().AppendLiteral("ORDER BY ").Append(_orderBy);
if (_rowCount != null)
- finalSql.AppendLine($"OFFSET {_offset ?? 0} ROWS FETCH NEXT {_rowCount} ROWS ONLY"); // TODO: PostgreSQL? "LIMIT row_count OFFSET offset"
+ _cachedCombinedQuery.AppendLine().AppendLiteral("OFFSET ").AppendLiteral((_offset ?? 0).ToString())
+ .AppendLiteral($"ROWS FETCH NEXT {_rowCount} ROWS ONLY"); // TODO: PostgreSQL? "LIMIT row_count OFFSET offset"
- return finalSql.ToString();
+ return _cachedCombinedQuery;
}
}
- #endregion
-
- ///
- /// Parameters of Query
- ///
- public ParameterInfos Parameters => _queryBuilder.Parameters;
+#endregion
- ///
- /// Underlying connection
- ///
- public IDbConnection Connection => _queryBuilder.Connection;
- #endregion
+#endregion
}
-}
+}
\ No newline at end of file
diff --git a/src/DapperQueryBuilder/FluentQueryBuilder/IFromBuilder.cs b/src/DapperQueryBuilder/FluentQueryBuilder/IFromBuilder.cs
index 942787d..3d8a9ca 100644
--- a/src/DapperQueryBuilder/FluentQueryBuilder/IFromBuilder.cs
+++ b/src/DapperQueryBuilder/FluentQueryBuilder/IFromBuilder.cs
@@ -1,6 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+using InterpolatedSql;
+using System;
namespace DapperQueryBuilder
{
diff --git a/src/DapperQueryBuilder/FluentQueryBuilder/ISelectDistinctBuilder.cs b/src/DapperQueryBuilder/FluentQueryBuilder/ISelectDistinctBuilder.cs
index b19091f..7a6575b 100644
--- a/src/DapperQueryBuilder/FluentQueryBuilder/ISelectDistinctBuilder.cs
+++ b/src/DapperQueryBuilder/FluentQueryBuilder/ISelectDistinctBuilder.cs
@@ -1,6 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Text;
+using InterpolatedSql;
namespace DapperQueryBuilder
{
diff --git a/src/DapperQueryBuilder/FluentQueryBuilder/IWhereBuilder.cs b/src/DapperQueryBuilder/FluentQueryBuilder/IWhereBuilder.cs
index 11f2328..a3d9e59 100644
--- a/src/DapperQueryBuilder/FluentQueryBuilder/IWhereBuilder.cs
+++ b/src/DapperQueryBuilder/FluentQueryBuilder/IWhereBuilder.cs
@@ -1,4 +1,5 @@
-using System;
+using InterpolatedSql;
+using System;
using System.Collections.Generic;
using System.Text;
diff --git a/src/DapperQueryBuilder/ICommand.cs b/src/DapperQueryBuilder/ICommand.cs
index 596d287..1603626 100644
--- a/src/DapperQueryBuilder/ICommand.cs
+++ b/src/DapperQueryBuilder/ICommand.cs
@@ -1,8 +1,5 @@
-using Dapper;
-using System;
-using System.Collections.Generic;
+using System;
using System.Data;
-using System.Text;
namespace DapperQueryBuilder
{
@@ -19,11 +16,13 @@ public interface ICommand
///
/// Parameters of Command
///
- ParameterInfos Parameters { get; }
+ ParametersDictionary DapperParameters { get; }
+
+ [Obsolete("Use DapperParameters")] ParametersDictionary Parameters { get; }
///
/// Underlying connection
///
- IDbConnection Connection { get; }
+ IDbConnection DbConnection { get; }
}
}
diff --git a/src/DapperQueryBuilder/ICompleteCommand.cs b/src/DapperQueryBuilder/ICompleteCommand.cs
index ec49fd5..b5934b1 100644
--- a/src/DapperQueryBuilder/ICompleteCommand.cs
+++ b/src/DapperQueryBuilder/ICompleteCommand.cs
@@ -1,15 +1,11 @@
-using Dapper;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Text;
+using InterpolatedSql;
namespace DapperQueryBuilder
{
///
/// Any command (Contains Connection, SQL, and Parameters) which is complete for execution.
///
- public interface ICompleteCommand : ICommand
+ public interface ICompleteCommand : ICommand, IInterpolatedSql
{
}
}
diff --git a/src/DapperQueryBuilder/ICompleteCommandExtensions.cs b/src/DapperQueryBuilder/ICompleteCommandExtensions.cs
index 01b9ea8..15f240d 100644
--- a/src/DapperQueryBuilder/ICompleteCommandExtensions.cs
+++ b/src/DapperQueryBuilder/ICompleteCommandExtensions.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
-using System.Text;
using System.Threading.Tasks;
using Dapper;
@@ -19,7 +18,7 @@ public static class ICompleteCommandExtensions
///
public static int Execute(this ICompleteCommand command, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
- return command.Connection.Execute(sql: command.Sql, param: command.Parameters, transaction: transaction, commandTimeout: commandTimeout, commandType: commandType);
+ return command.DbConnection.Execute(sql: command.Sql, param: ParametersDictionary.LoadFrom(command), transaction: transaction, commandTimeout: commandTimeout, commandType: commandType);
}
///
@@ -27,7 +26,7 @@ public static int Execute(this ICompleteCommand command, IDbTransaction transact
///
public static Task ExecuteAsync(this ICompleteCommand command, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
- return command.Connection.ExecuteAsync(sql: command.Sql, param: command.Parameters, transaction: transaction, commandTimeout: commandTimeout, commandType: commandType);
+ return command.DbConnection.ExecuteAsync(sql: command.Sql, param: ParametersDictionary.LoadFrom(command), transaction: transaction, commandTimeout: commandTimeout, commandType: commandType);
}
#endregion
@@ -38,7 +37,7 @@ public static Task ExecuteAsync(this ICompleteCommand command, IDbTransacti
///
public static object ExecuteScalar(this ICompleteCommand command, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
- return command.Connection.ExecuteScalar(sql: command.Sql, param: command.Parameters, transaction: transaction, commandTimeout: commandTimeout, commandType: commandType);
+ return command.DbConnection.ExecuteScalar(sql: command.Sql, param: ParametersDictionary.LoadFrom(command), transaction: transaction, commandTimeout: commandTimeout, commandType: commandType);
}
///
@@ -46,7 +45,7 @@ public static object ExecuteScalar(this ICompleteCommand command, IDbTransaction
///
public static Task ExecuteScalarAsync(this ICompleteCommand command, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
- return command.Connection.ExecuteScalarAsync(sql: command.Sql, param: command.Parameters, transaction: transaction, commandTimeout: commandTimeout, commandType: commandType);
+ return command.DbConnection.ExecuteScalarAsync(sql: command.Sql, param: ParametersDictionary.LoadFrom(command), transaction: transaction, commandTimeout: commandTimeout, commandType: commandType);
}
///
@@ -54,7 +53,7 @@ public static Task ExecuteScalarAsync(this ICompleteCommand command, IDbTr
///
public static Task