Skip to content

Parameter #742

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 56 additions & 2 deletions QueryBuilder.Tests/DefineTest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using static SqlKata.Expressions;
using SqlKata.Compilers;
using SqlKata.Tests.Infrastructure;
Expand All @@ -15,15 +16,43 @@ public class DefineTest : TestSupport
public void Test_Define_Where()
{
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]);

}

[Fact]
public void Test_Define_Parameter_Where()
{
// note parameters need to start with @ or any other standard parameter indicator for
// the library running the query.
var query = new Query("Products")
.Define("@name", "Anto")
.DefineParameter("@param", "param")
.Where("ProductName", Variable("@name"))
.Where("ProductName", Variable("@param"))
.Where("ProductName", Variable("@param"));

var c = Compile(query);

Assert.Equal("SELECT * FROM [Products] WHERE [ProductName] = 'Anto' AND [ProductName] = 'param'" +
" AND [ProductName] = 'param'", c[EngineCodes.SqlServer]);

var s = Compilers.Compile(query)[EngineCodes.SqlServer];
Assert.Equal("SELECT * FROM [Products] WHERE [ProductName] = @p0 AND [ProductName] = @param" +
" AND [ProductName] = @param", s.Sql);
var expected = new Dictionary<string, object>()
{
{ "@param", "param" },
{ "@p0", "Anto" }
};
Assert.Equal(expected, s.NamedBindings);
}

[Fact]
public void Test_Define_SubQuery()
{
Expand All @@ -43,6 +72,31 @@ public void Test_Define_SubQuery()

}

[Fact]
public void Test_Define_Parameter_SubQuery()
{

var query = new Query("Products")
.DefineParameter("@a", 1)
.DefineParameter("@b","b")
.Where(q=> q.Where("a", "=", Variable("@a")))
.OrWhere(q =>
q.Where("a", "=", Variable("@a"))
.Where("b",">",Variable("@b"))
.Where("a",">",0));

var s = Compilers.Compile(query)[EngineCodes.SqlServer];
Assert.Equal("SELECT * FROM [Products] WHERE ([a] = @a) OR ([a] = @a AND [b] > @b AND [a] > @p3)", s.Sql);
Assert.Equal(3,s.NamedBindings.Count);
var expected = new Dictionary<string, object>()
{
{ "@a", 1 },
{ "@b", "b" },
{ "@p3", 0 }
};
Assert.Equal(expected, s.NamedBindings);
}


[Fact]
public void Test_Define_WhereEnds()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using System.Collections.Generic;
using System.Linq;
using MySql.Data.MySqlClient;
using SqlKata.Compilers;
using Xunit;
using SqlKata.Execution;
using MySql.Data.MySqlClient;
using System;
using System.Linq;
using Xunit;
using static SqlKata.Expressions;
using System.Collections.Generic;

namespace SqlKata.Tests
namespace SqlKata.Tests.MySql
{
public class MySqlExecutionTest
{
Expand Down Expand Up @@ -134,6 +133,37 @@ public void QueryWithVariable()
db.Drop("Cars");
}

[Fact]
public void QueryWithParameter()
{
var db = DB().Create("Cars", new[] {
"Id INT PRIMARY KEY AUTO_INCREMENT",
"Brand TEXT NOT NULL",
"Year INT NOT NULL",
"Color TEXT NULL",
});

for (int i = 0; i < 10; i++)
{
db.Query("Cars").Insert(new
{
Brand = "Brand " + i,
Year = "2020",
});
}


var count = db.Query("Cars")
.DefineParameter("Threshold", 5)
.Where("Id", "<", Variable("Threshold"))
.Where("Id", "<", Variable("Threshold"))
.Count<int>();

Assert.Equal(4, count);

db.Drop("Cars");
}

[Fact]
public void InlineTable()
{
Expand Down Expand Up @@ -213,12 +243,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},
Expand Down Expand Up @@ -251,10 +281,11 @@ public void BasicSelectFilter()

QueryFactory DB()
{
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 host = System.Environment.GetEnvironmentVariable("SQLKATA_MYSQL_HOST") ?? "localhost";
var user = System.Environment.GetEnvironmentVariable("SQLKATA_MYSQL_USER") ?? "root";
var password = System.Environment.GetEnvironmentVariable("SQLKATA_MYSQL_PASSWORD") ?? "my-secret-pw";
var dbName = System.Environment.GetEnvironmentVariable("SQLKATA_MYSQL_DB") ?? "test";
var cs = $"server={host};user={user};database={dbName};password={password}";

var connection = new MySqlConnection(cs);

Expand All @@ -266,4 +297,4 @@ QueryFactory DB()


}
}
}
13 changes: 13 additions & 0 deletions QueryBuilder.Tests/MySql/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Use root/my-secret-pw as user/password credentials
version: '3.1'

services:

db:
image: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: my-secret-pw
MYSQL_DATABASE: test
ports:
- "3306:3306"
36 changes: 28 additions & 8 deletions QueryBuilder/Compilers/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace SqlKata.Compilers
{
Expand Down Expand Up @@ -32,13 +33,13 @@ protected Compiler()
/// <summary>
/// Whether the compiler supports the `SELECT ... FILTER` syntax
/// </summary>
/// <value></value>
/// <value></value>
public virtual bool SupportsFilterClause { get; set; } = false;

/// <summary>
/// If true the compiler will remove the SELECT clause for the query used inside WHERE EXISTS
/// </summary>
/// <value></value>
/// <value></value>
public virtual bool OmitSelectInsideExists { get; set; } = true;

protected virtual string SingleRowDummyTableName { get => null; }
Expand All @@ -63,16 +64,35 @@ protected Compiler()

};

protected Dictionary<string, object> generateNamedBindings(object[] bindings)
protected (string Name,object Variable)[] generateNamedBindingsArray(object[] bindings)
{
return Helper.Flatten(bindings).Select((v, i) =>
{
if (v is NamedParameterVariable param)
{
return (param.Variable, param.Value);
}
return (parameterPrefix + i, v);
}).ToArray();
}

protected Dictionary<string, object> generateNamedBindings((string, object)[] bindings)
{
return Helper.Flatten(bindings).Select((v, i) => new { i, v })
.ToDictionary(x => parameterPrefix + x.i, x => x.v);
var dictionary = new Dictionary<string, object>();
foreach (var (name, variable) in bindings)
{
dictionary.TryAdd(name, variable);
}

return dictionary;
}


protected SqlResult PrepareResult(SqlResult ctx)
{
ctx.NamedBindings = generateNamedBindings(ctx.Bindings.ToArray());
ctx.Sql = Helper.ReplaceAll(ctx.RawSql, parameterPlaceholder, EscapeCharacter, i => parameterPrefix + i);
var bindings = generateNamedBindingsArray(ctx.Bindings.ToArray());
ctx.NamedBindings = generateNamedBindings(bindings);
ctx.Sql = Helper.ReplaceAll(ctx.RawSql, parameterPlaceholder, EscapeCharacter, i => bindings[i].Name);
return ctx;
}

Expand Down Expand Up @@ -295,7 +315,7 @@ protected virtual SqlResult CompileDeleteQuery(Query query)
}
else
{
// check if we have alias
// check if we have alias
if (fromClause is FromClause && !string.IsNullOrEmpty(fromClause.Alias))
{
ctx.RawSql = $"DELETE {Wrap(fromClause.Alias)} FROM {table} {joins}{where}";
Expand Down
7 changes: 7 additions & 0 deletions QueryBuilder/NamedParameterVariable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace SqlKata;

public class NamedParameterVariable(string variable, object value)
{
public object Value { get; set; } = value;
public string Variable { get; set; } = variable;
}
16 changes: 16 additions & 0 deletions QueryBuilder/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,22 @@ public Query Define(string variable, object value)
return this;
}

/// <summary>
/// Define a parameter to be used within the query
/// </summary>
/// <param name="parameter"></param>
/// <param name="value"></param>
/// <returns></returns>
public Query DefineParameter(string variable, object value)
{
Variables.Add(variable, new NamedParameterVariable(variable,value));

return this;
}




public object FindVariable(string variable)
{
var found = Variables.ContainsKey(variable);
Expand Down
4 changes: 4 additions & 0 deletions QueryBuilder/SqlResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public override string ToString()
}

var value = deepParameters[i];
if (value is NamedParameterVariable v)
{
return ChangeToSqlValue(v.Value);
}
return ChangeToSqlValue(value);
});

Expand Down