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
10 changes: 5 additions & 5 deletions QMap.SqlBuilder.Tests/SqlBuilderParseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void FullSqlInsertBuildWitoutSyntaxErrosInAllParsers()
.Create<TypesTestEntity>();

var sql = queryBuilder
.BuildInsert(connectionFake, out var _, entity, (p) => p.Name == "Id");
.BuildInsert(connectionFake, out var _, entity, (p) => p.Id);

_parsers.ToList().ForEach(p =>
{
Expand Down Expand Up @@ -151,7 +151,7 @@ public void BuildDeleteNoThrowsErrors()
StatementsBuilders queryBuilder = new StatementsBuilders(new SqlDialectBase());

var sql = queryBuilder
.Delete<TypesTestEntity>()
.Delete<TypesTestEntity>(out var _)
.From(typeof(TypesTestEntity))
.Build();
}
Expand All @@ -165,7 +165,7 @@ public void BuildDeleteThrowInvalidOperationException()
StatementsBuilders queryBuilder = new StatementsBuilders(new SqlDialectBase());

var sql = queryBuilder
.Delete<TypesTestEntity>()
.Delete<TypesTestEntity>(out var _)
.Build();
});
}
Expand All @@ -177,7 +177,7 @@ public void DeleteSqlBuidWitoutSyntaxErrosInAllParsers()
StatementsBuilders queryBuilder = new(new TSqlDialect());

var sql = queryBuilder
.Delete<TypesTestEntity>()
.Delete<TypesTestEntity>(out var _)
.From(typeof(TypesTestEntity))
.Build();

Expand All @@ -196,7 +196,7 @@ public void DeleteFullSqlBuidWitoutSyntaxErrosInAllParsers()
StatementsBuilders queryBuilder = new(new SqlDialectBase());

var sql = queryBuilder
.Delete<TypesTestEntity>()
.Delete<TypesTestEntity>(out var _)
.From(typeof(TypesTestEntity))
.Where<TypesTestEntity>((TypesTestEntity t) => t.Id < 0, out var parameters)
.Build();
Expand Down
5 changes: 3 additions & 2 deletions QMap.SqlBuilder/Abstractions/IInsertBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Reflection;
using System.Linq.Expressions;
using System.Reflection;

namespace QMap.SqlBuilder.Abstractions
{
public interface IInsertBuilder : IQueryBuilder
{
IInsertBuilder BuildInsert<T>(T entity);
public IInsertBuilder BuildInsertExcept<T>(T entity, Func<PropertyInfo, bool> exceptPropsFilter);
public IInsertBuilder BuildInsertExcept<T, TProperty>(T entity, Expression<Func<T, TProperty>> exceptPropsFilter);
}
}
12 changes: 8 additions & 4 deletions QMap.SqlBuilder/QueryBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,25 @@ public static IUpdateBuilder Update<T, V>(this IQueryBuilder queryBuilder, IQMap
return builder;
}

public static IDeleteBuilder Delete<T>(this IQueryBuilder queryBuilder)
public static IDeleteBuilder Delete<T>(this IQueryBuilder queryBuilder, out Dictionary<string, object> parameters)
{
return new DeleteBuilder(queryBuilder.SqlDialect)
var builder = new DeleteBuilder(queryBuilder.SqlDialect)
.BuildDelete<T>();

parameters = builder.Parameters;

return builder;
}

public static string Build(this IQueryBuilder queryBuilder)
{
return queryBuilder.Build();
}

public static string BuildInsert<T>(this IQueryBuilder queryBuilder, IQMapConnection connection, out Dictionary<string, object> parameters, T entity, Func<PropertyInfo, bool> exceptProperty)
public static string BuildInsert<T, TProperty>(this IQueryBuilder queryBuilder, IQMapConnection connection, out Dictionary<string, object> parameters, T entity, Expression<Func<T, TProperty>> exceptProp)
{
var builder = new InsertBuilder(queryBuilder.SqlDialect)
.BuildInsertExcept(entity, exceptProperty);
.BuildInsertExcept(entity, exceptProp);

parameters = builder.Parameters;

Expand Down
35 changes: 22 additions & 13 deletions QMap.SqlBuilder/StatementsBuilders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
{
}

public string Sql

Check warning on line 59 in QMap.SqlBuilder/StatementsBuilders.cs

View workflow job for this annotation

GitHub Actions / build

'SelectBuilder.Sql' hides inherited member 'StatementsBuilders.Sql'. Use the new keyword if hiding was intended.
{
get => _sql;

Expand All @@ -78,7 +78,7 @@
return this;
}

public string Build()

Check warning on line 81 in QMap.SqlBuilder/StatementsBuilders.cs

View workflow job for this annotation

GitHub Actions / build

'SelectBuilder.Build()' hides inherited member 'StatementsBuilders.Build()'. Use the new keyword if hiding was intended.
{
throw new InvalidOperationException();
}
Expand Down Expand Up @@ -109,14 +109,16 @@

public IFromBuilder BuildFrom(ISelectBuilder quryBuilder, Type entity, params Type[] entities)
{
this.Sql += $"{quryBuilder.Sql}" + $" from {entity.Name} " + _aliases.GetOrAdd(entity.Name, (ak) => NameToAlias(entity.Name));
this.Sql += FormattableStringFactory
.Create("{0} from {1} {2}", quryBuilder.Sql, entity.Name, _aliases.GetOrAdd(entity.Name, (ak) => NameToAlias(entity.Name)));

return this;
}

public IFromBuilder BuildFrom(IDeleteBuilder quryBuilder, Type entity, params Type[] entities)
{
this.Sql += $"{quryBuilder.Sql}" + $" from {entity.Name} ";
this.Sql += FormattableStringFactory
.Create("{0} from {1}", quryBuilder.Sql, entity.Name);

return this;
}
Expand Down Expand Up @@ -203,6 +205,7 @@

public class InsertBuilder : StatementsBuilders, IInsertBuilder
{
private IEnumerable<PropertyInfo> _properties;
public InsertBuilder(ISqlDialect sqlDialect) : base(sqlDialect)
{
}
Expand All @@ -226,11 +229,19 @@
return this;
}

public IInsertBuilder BuildInsertExcept<T>(T entity, Func<PropertyInfo, bool> exceptPropsFilter)
public IInsertBuilder BuildInsertExcept<T, TProperty>(T entity, Expression<Func<T, TProperty>> exceptProp)
{
var columns = BuildColumns<T>(exceptPropsFilter);
MemberInfo? excludedMember = null;

if(exceptProp.Body is MemberExpression member)
{
excludedMember = member.Member;
}

var columns = BuildColumns<T>(excludedMember);
var values = BuildValues(entity, columns);


Sql = $"insert into {typeof(T).Name} " +
$"({columns.Aggregate((c1, c2) => $"{c1},{c2}")})"
+ "values"
Expand All @@ -239,35 +250,35 @@
return this;
}

private IEnumerable<string> BuildColumns<T>(Func<PropertyInfo, bool>? exceptPropsFilter = null)
private IEnumerable<string> BuildColumns<T>(MemberInfo? exceptProp = null)
{
var properties = typeof(T)
_properties = typeof(T)
.GetProperties(BindingFlags.Public
| BindingFlags.GetProperty
| BindingFlags.SetProperty
| BindingFlags.Instance)
.AsEnumerable();

if (exceptPropsFilter != null)
if (exceptProp != null)
{
properties = properties.Where(p => !exceptPropsFilter.Invoke(p));
_properties = _properties.Where(p => p.Name != exceptProp.Name);
}

return properties
return _properties
.Select(p => p.Name);
}

private IEnumerable<string> BuildValues<T>(T entity, IEnumerable<string> columns)
{
var properties = typeof(T)
_properties = typeof(T)
.GetProperties(BindingFlags.Public
| BindingFlags.GetProperty
| BindingFlags.SetProperty
| BindingFlags.Instance)
.AsEnumerable();

#nullable disable
return properties
return _properties
.Where(p => columns.Contains(p.Name))
.Select(p =>
{
Expand Down Expand Up @@ -311,8 +322,6 @@
{
}

public Dictionary<string, object> Parameters => throw new NotImplementedException();

private Type _entity = null;

public string Build()
Expand Down
32 changes: 30 additions & 2 deletions QMap.Tests/QMapConnectionExtensionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,7 @@ public void InsertWithoutPropertyExecutesWithoutErrors()

connection.Open();

connection.Insert(entity, p => p.Name == "Id");

connection.Insert(entity, p => p.Id);
connection.Close();

context.Database.EnsureDeleted();
Expand Down Expand Up @@ -496,5 +495,34 @@ public void Update_Should_Not_Pass_Drop_Statemant_When_Injection_In_Where()
context.TypesTestEntity.Count();
});
}

[Fact]
public void Delete_Should_Not_Pass_Drop_Statemant_When_Injection_In_Where()
{
var builder = new StatementsBuilders(new SqlDialectBase());

_connectionFactories.ForEach(c =>
{

var context = c.GetDbContext<TestContext>();

context.Database.EnsureCreated();

using var connection = c.Create();

connection.Open();

var entity = new Fixture()
.Build<TypesTestEntity>()
.Without(t => t.Id)
.Create();

context.TypesTestEntity.Add(entity);
context.SaveChanges();
connection.Delete<TypesTestEntity>((TypesTestEntity t) => t.StringField != "\'DROP TABLE TypesTestEntity;--");

context.TypesTestEntity.Count();
});
}
}
}
35 changes: 32 additions & 3 deletions QMap/QMapConnectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Data;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace QMap
{
Expand Down Expand Up @@ -34,6 +35,30 @@ public static class QMapConnectionExtension
return queryMapper.Map<T>(command.ExecuteReader());
}

/// <summary>
/// Execute query and map to <typeparamref name="T"/>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="connection">Connection</param>
/// <param name="sql">Qery text</param>
/// <param name="customMapper">Custom mapper if required, else uses base implementation"/></param>
/// <returns></returns>
public static IEnumerable<T> Query<T>(this IQMapConnection connection, string sql, object[] parameters, IEntityMapper? customMapper = null) where T : class, new()
{
var mapper = _mappersCache.GetOrAdd(typeof(T),
(customMapper is null ? new EntityMapper() : customMapper));

var queryMapper = new QueryMapperBase(mapper);

var parametrizedString = FormattableStringFactory.Create(sql, parameters);

var command = connection.CreateCommand();

command.CommandText = parametrizedString.ToString();

return queryMapper.Map<T>(command.ExecuteReader());
}

public static IEnumerable<T> Where<T>(this IQMapConnection connection, LambdaExpression predicate, IEntityMapper? customMapper = null) where T : class, new()
{
var mapper = _mappersCache.GetOrAdd(typeof(T),
Expand All @@ -55,7 +80,7 @@ public static class QMapConnectionExtension
return queryMapper.Map<T>(command.ExecuteReader());
}

public static void Insert<T>(this IQMapConnection connection, T entity, Func<PropertyInfo, bool> exceptProperty)
public static void Insert<T, TProperty>(this IQMapConnection connection, T entity, Expression<Func<T, TProperty>> exceptProperty)
{
var command = connection.CreateCommand();
var sql = new StatementsBuilders(connection.Dialect)
Expand Down Expand Up @@ -103,13 +128,17 @@ public static void Insert<T>(this IQMapConnection connection, T entity)
{
var command = connection.CreateCommand();
var sql = new StatementsBuilders(connection.Dialect)
.Delete<T>()
.Delete<T>(out var parameters)
.From(typeof(T))
.Where<T>(predicate, out var parameters)
.Where<T>(predicate, out var parameters1)
.Build();

var allParameters = parameters.AsEnumerable().Concat(parameters1).ToDictionary((p) => p.Key, (p) => p.Value);

command.CommandText = sql;

connection.Dialect.BuildParameters(command, allParameters);

command.ExecuteNonQuery();
}
}
Expand Down
Loading