Skip to content
Merged
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
34 changes: 34 additions & 0 deletions QueryBuilder.Tests/GeneralTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -401,5 +401,39 @@ public void Where_Nested()

Assert.Equal("SELECT * FROM [table] WHERE ([a] = 1 OR [a] = 2)", c[EngineCodes.SqlServer].ToString());
}

[Fact]
public void UnsafeLiteral_Insert()
{
var query = new Query("Table").AsInsert(new
{
Count = new UnsafeLiteral("Count + 1")
});

var engines = new[] {
EngineCodes.SqlServer,
};

var c = Compilers.Compile(engines, query);

Assert.Equal("INSERT INTO [Table] ([Count]) VALUES (Count + 1)", c[EngineCodes.SqlServer].ToString());
}

[Fact]
public void UnsafeLiteral_Update()
{
var query = new Query("Table").AsUpdate(new
{
Count = new UnsafeLiteral("Count + 1")
});

var engines = new[] {
EngineCodes.SqlServer,
};

var c = Compilers.Compile(engines, query);

Assert.Equal("UPDATE [Table] SET [Count] = Count + 1", c[EngineCodes.SqlServer].ToString());
}
}
}
32 changes: 32 additions & 0 deletions QueryBuilder.Tests/UpdateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,5 +283,37 @@ public void UpdateUsingExpandoObject()
"UPDATE [Table] SET [Name] = 'The User', [Age] = '2018-01-01'",
c[EngineCodes.SqlServer]);
}

[Fact]
public void IncrementUpdate()
{
var query = new Query("Table").AsIncrement("Total");
var c = Compile(query);
Assert.Equal("UPDATE [Table] SET [Total] = [Total] + 1", c[EngineCodes.SqlServer]);
}

[Fact]
public void IncrementUpdateWithValue()
{
var query = new Query("Table").AsIncrement("Total", 2);
var c = Compile(query);
Assert.Equal("UPDATE [Table] SET [Total] = [Total] + 2", c[EngineCodes.SqlServer]);
}

[Fact]
public void IncrementUpdateWithWheres()
{
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]);
}

[Fact]
public void DecrementUpdate()
{
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]);
}
}
}
19 changes: 19 additions & 0 deletions QueryBuilder/Clauses/IncrementClause.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace SqlKata
{
public class IncrementClause : InsertClause
{
public string Column { get; set; }
public int Value { get; set; } = 1;

public override AbstractClause Clone()
{
return new IncrementClause
{
Engine = Engine,
Component = Component,
Column = Column,
Value = Value
};
}
}
}
37 changes: 30 additions & 7 deletions QueryBuilder/Compilers/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,25 +285,48 @@ protected virtual SqlResult CompileUpdateQuery(Query query)
throw new InvalidOperationException("Invalid table expression");
}

var toUpdate = ctx.Query.GetOneComponent<InsertClause>("update", EngineCode);
// check for increment statements
var clause = ctx.Query.GetOneComponent("update", EngineCode);

string wheres;

if (clause != null && clause is IncrementClause increment)
{
var column = Wrap(increment.Column);
var value = Parameter(ctx, Math.Abs(increment.Value));
var sign = increment.Value >= 0 ? "+" : "-";

wheres = CompileWheres(ctx);

if (!string.IsNullOrEmpty(wheres))
{
wheres = " " + wheres;
}

ctx.RawSql = $"UPDATE {table} SET {column} = {column} {sign} {value}{wheres}";

return ctx;
}


var toUpdate = ctx.Query.GetOneComponent<InsertClause>("update", EngineCode);
var parts = new List<string>();

for (var i = 0; i < toUpdate.Columns.Count; i++)
{
parts.Add(Wrap(toUpdate.Columns[i]) + " = " + Parameter(ctx, toUpdate.Values[i]));
}

var where = CompileWheres(ctx);
var sets = string.Join(", ", parts);

if (!string.IsNullOrEmpty(where))
wheres = CompileWheres(ctx);

if (!string.IsNullOrEmpty(wheres))
{
where = " " + where;
wheres = " " + wheres;
}

var sets = string.Join(", ", parts);

ctx.RawSql = $"UPDATE {table} SET {sets}{where}";
ctx.RawSql = $"UPDATE {table} SET {sets}{wheres}";

return ctx;
}
Expand Down
17 changes: 17 additions & 0 deletions QueryBuilder/Query.Update.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,22 @@ public Query AsUpdate(IEnumerable<KeyValuePair<string, object>> values)

return this;
}

public Query AsIncrement(string column, int value = 1)
{
Method = "update";
AddOrReplaceComponent("update", new IncrementClause
{
Column = column,
Value = value
});

return this;
}

public Query AsDecrement(string column, int value = 1)
{
return AsIncrement(column, -value);
}
}
}
4 changes: 2 additions & 2 deletions SqlKata.Execution/Query.Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ public static int Insert(this Query query, IEnumerable<string> columns, IEnumera
return CreateQueryFactory(query).Execute(query.AsInsert(columns, valuesCollection), transaction, timeout);
}

public static async Task<int> InsertAsync(this Query query, IEnumerable<string> columns, IEnumerable<IEnumerable<object>> valuesCollection, IDbTransaction transaction = null, int? timeout = null)
public static async Task<int> InsertAsync(this Query query, IEnumerable<string> columns, IEnumerable<IEnumerable<object>> valuesCollection, IDbTransaction transaction = null, int? timeout = null, CancellationToken cancellationToken = default)
{
return await CreateQueryFactory(query).ExecuteAsync(query.AsInsert(columns, valuesCollection), transaction, timeout);
return await CreateQueryFactory(query).ExecuteAsync(query.AsInsert(columns, valuesCollection), transaction, timeout, cancellationToken);
}

public static int Insert(this Query query, IEnumerable<string> columns, Query fromQuery, IDbTransaction transaction = null, int? timeout = null)
Expand Down