Skip to content

Commit

Permalink
Merge pull request #346 from phnx47/feat/nullable-status
Browse files Browse the repository at this point in the history
feat: allow 'bool?' for status attribute
  • Loading branch information
phnx47 authored Dec 21, 2023
2 parents 5593e8d + 3f1c976 commit ac88557
Show file tree
Hide file tree
Showing 18 changed files with 133 additions and 109 deletions.
2 changes: 1 addition & 1 deletion src/MicroOrm.Dapper.Repositories.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<Description>CRUD for Dapper</Description>
<Copyright>2015 © Serge K</Copyright>
<Authors>Serge K and Contributors</Authors>
<TargetFrameworks>net461;netstandard2.0;net5.0</TargetFrameworks>
<TargetFrameworks>net461;netstandard2.0;net5.0;net7.0</TargetFrameworks>
<LangVersion>11.0</LangVersion>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down
29 changes: 19 additions & 10 deletions src/SqlGenerator/SqlGenerator.AppendJoin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,29 @@ private void AppendJoinQuery(JoinAttributeBase attrJoin, StringBuilder joinBuild
var colAttr = deleteAttr.GetCustomAttribute<ColumnAttribute>();
var colName = colAttr == null ? deleteAttr.Name : colAttr.Name;
object deleteValue = Provider == SqlProvider.PostgreSQL ? "true" : 1;
if (deleteAttr.PropertyType.IsEnum)
if(deleteAttr.PropertyType == typeof(bool?))
{
var deleteOption = deleteAttr.PropertyType.GetFields().FirstOrDefault(f => f.GetCustomAttribute<DeletedAttribute>() != null);

if (deleteOption != null)
customFilter = attrJoin.TableAlias == string.Empty
? $"AND {attrJoin.TableName}.{colName} IS NULL "
: $"AND {attrJoin.TableAlias}.{colName} IS NULL ";
}
else
{
if (deleteAttr.PropertyType.IsEnum)
{
var enumValue = Enum.Parse(deleteAttr.PropertyType, deleteOption.Name);
deleteValue = Convert.ChangeType(enumValue, Enum.GetUnderlyingType(deleteAttr.PropertyType));
var deleteOption = deleteAttr.PropertyType.GetFields().FirstOrDefault(f => f.GetCustomAttribute<DeletedAttribute>() != null);

if (deleteOption != null)
{
var enumValue = Enum.Parse(deleteAttr.PropertyType, deleteOption.Name);
deleteValue = Convert.ChangeType(enumValue, Enum.GetUnderlyingType(deleteAttr.PropertyType));
}
}
}

customFilter = attrJoin.TableAlias == string.Empty
? $"AND {attrJoin.TableName}.{colName} != {deleteValue} "
: $"AND {attrJoin.TableAlias}.{colName} != {deleteValue} ";
customFilter = attrJoin.TableAlias == string.Empty
? $"AND {attrJoin.TableName}.{colName} != {deleteValue} "
: $"AND {attrJoin.TableAlias}.{colName} != {deleteValue} ";
}
}

joinBuilder.Append(attrJoin.TableAlias == string.Empty
Expand Down
17 changes: 15 additions & 2 deletions src/SqlGenerator/SqlGenerator.AppendWherePredicateQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,27 @@ private void AppendWherePredicateQuery(SqlQuery sqlQuery, Expression<Func<TEntit
dictionaryParams.AddRange(conditions);

if (LogicalDelete && queryType == QueryType.Select)
sqlQuery.SqlBuilder.AppendFormat("({3}) AND {0}.{1} != {2} ", TableName, StatusPropertyName, LogicalDeleteValue, sqlBuilder);
{
if (LogicalDeleteValueNullable)
sqlQuery.SqlBuilder.AppendFormat("({2}) AND {0}.{1} IS NULL ", TableName, StatusPropertyName, sqlBuilder);
else
sqlQuery.SqlBuilder.AppendFormat("({3}) AND {0}.{1} != {2} ", TableName, StatusPropertyName, LogicalDeleteValue, sqlBuilder);
}
else
{
sqlQuery.SqlBuilder.AppendFormat("{0} ", sqlBuilder);
}
}
else
{
if (LogicalDelete && queryType == QueryType.Select)
sqlQuery.SqlBuilder.AppendFormat("WHERE {0}.{1} != {2} ", TableName, StatusPropertyName, LogicalDeleteValue);
{
if (LogicalDeleteValueNullable)
sqlQuery.SqlBuilder.AppendFormat("WHERE {0}.{1} IS NULL ", TableName, StatusPropertyName);
else
sqlQuery.SqlBuilder.AppendFormat("WHERE {0}.{1} != {2} ", TableName, StatusPropertyName, LogicalDeleteValue);
}

}

if (LogicalDelete && HasUpdatedAt && queryType == QueryType.Delete)
Expand Down
29 changes: 18 additions & 11 deletions src/SqlGenerator/SqlGenerator.GetSelect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

namespace MicroOrm.Dapper.Repositories.SqlGenerator;


public partial class SqlGenerator<TEntity>
where TEntity : class
{
Expand Down Expand Up @@ -57,8 +56,7 @@ private SqlQuery GetSelect(Expression<Func<TEntity, bool>>? predicate, bool firs
if (Provider == SqlProvider.Oracle)
sqlQuery.SqlBuilder.Append("FETCH FIRST 1 ROW ONLY");
else if (Provider != SqlProvider.MSSQL)
sqlQuery.SqlBuilder
.Append("LIMIT 1");
sqlQuery.SqlBuilder.Append("LIMIT 1");
}

return sqlQuery;
Expand Down Expand Up @@ -293,21 +291,30 @@ public virtual SqlQuery GetSelectById(object id, FilterData? filterData, params
.Append(" ");

if (LogicalDelete)
{
sqlQuery.SqlBuilder
.Append("AND ")
.Append(TableName)
.Append(".")
.Append(StatusPropertyName)
.Append(" != ")
.Append(LogicalDeleteValue)
.Append(" ");
.Append(StatusPropertyName);

if (LogicalDeleteValueNullable)
{
sqlQuery.SqlBuilder
.Append(" IS NULL ");
}
else
{
sqlQuery.SqlBuilder
.Append(" != ")
.Append(LogicalDeleteValue)
.Append(" ");
}
}

if (includes.Length == 0 && Provider != SqlProvider.MSSQL)
{
if (Provider == SqlProvider.Oracle)
sqlQuery.SqlBuilder.Append("FETCH FIRST 1 ROWS ONLY");
else
sqlQuery.SqlBuilder.Append("LIMIT 1");
sqlQuery.SqlBuilder.Append(Provider == SqlProvider.Oracle ? "FETCH FIRST 1 ROWS ONLY" : "LIMIT 1");
}

sqlQuery.SetParam(param);
Expand Down
12 changes: 8 additions & 4 deletions src/SqlGenerator/SqlGenerator.InitLogicalDeleted.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ private void InitLogicalDeleted()
if (deleteAttr == null)
continue;

if (JoinsLogicalDelete == null)
JoinsLogicalDelete = new Dictionary<string, PropertyInfo>();

JoinsLogicalDelete ??= new Dictionary<string, PropertyInfo>();
JoinsLogicalDelete.Add(joinAttr.TableName, deleteAttr);
}

Expand All @@ -41,7 +39,13 @@ private void InitLogicalDeleted()
if (statusProperty.PropertyInfo.PropertyType == typeof(bool))
{
LogicalDelete = true;
LogicalDeleteValue = Provider == SqlProvider.PostgreSQL ? "true" : 1; // true
LogicalDeleteValue = Provider == SqlProvider.PostgreSQL ? "true" : 1;
}
else if (statusProperty.PropertyInfo.PropertyType == typeof(bool?))
{
LogicalDelete = true;
LogicalDeleteValue = Provider == SqlProvider.PostgreSQL ? "true" : 1;
LogicalDeleteValueNullable = true;
}
else if (statusProperty.PropertyInfo.PropertyType.IsEnum)
{
Expand Down
2 changes: 2 additions & 0 deletions src/SqlGenerator/SqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ public SqlGenerator(SqlProvider provider)

public object? LogicalDeleteValue { get; protected set; }

public bool LogicalDeleteValueNullable { get; protected set; }

/// <summary>
/// In Oracle parameter should be build with : instead of @.
/// </summary>
Expand Down
18 changes: 9 additions & 9 deletions tests/Repositories.Base/BaseRepositoriesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void Count()
{
var count = Db.Users.Count();
var countHandQuery = Db.Connection
.ExecuteScalar<int>("SELECT COUNT(*) FROM Users WHERE Users.Deleted != " + Db.Users.SqlGenerator.LogicalDeleteValue);
.ExecuteScalar<int>("SELECT COUNT(*) FROM Users WHERE Users.Deleted IS NULL");
Assert.Equal(countHandQuery, count);
}

Expand Down Expand Up @@ -78,15 +78,15 @@ public void CountWithDistinctAndWhere()
public void Find()
{
var user = Db.Users.Find(x => x.Id == 2);
Assert.False(user.Deleted);
Assert.Null(user.Deleted);
Assert.Equal("TestName1", user.Name);
}

[Fact]
public void FindById()
{
var user = Db.Users.FindById(2);
Assert.False(user.Deleted);
Assert.Null(user.Deleted);
Assert.Equal("TestName1", user.Name);
}

Expand All @@ -100,15 +100,15 @@ public void FindById_MultiKeys()
public async void FindByIdAsync()
{
var user = await Db.Users.FindByIdAsync(2);
Assert.False(user.Deleted);
Assert.Null(user.Deleted);
Assert.Equal("TestName1", user.Name);
}

[Fact]
public async void FindByIdAsync_WithJoins_NotNull()
{
var user = await Db.Users.FindByIdAsync<Car, Phone, Address>(1, x => x.Cars, x => x.Phone, x => x.Addresses);
Assert.False(user.Deleted);
Assert.Null(user.Deleted);
Assert.Equal("TestName0", user.Name);

Assert.NotNull(user.Phone);
Expand Down Expand Up @@ -150,7 +150,7 @@ public async void FindAllAsync_NullPredicate_CheckCount()
protected void FindJoin_CollectionnRecord()
{
var user = Db.Users.Find<Car>(q => q.Id == 1, q => q.Cars);
Assert.False(user.Deleted);
Assert.Null(user.Deleted);
Assert.Equal("TestName0", user.Name);

Assert.True(user.Cars.Count == 2);
Expand All @@ -160,7 +160,7 @@ protected void FindJoin_CollectionnRecord()
public async void FindJoinAsync_CollectionnRecord()
{
var user = await Db.Users.FindAsync<Car>(q => q.Id == 1, q => q.Cars);
Assert.False(user.Deleted);
Assert.Null(user.Deleted);
Assert.Equal("TestName0", user.Name);

Assert.True(user.Cars.Count == 2);
Expand Down Expand Up @@ -297,7 +297,7 @@ public async Task FindAsync()
const string name = "TestName3";
{
var user = await Db.Users.FindAsync(x => x.Id == id);
Assert.False(user.Deleted);
Assert.Null(user.Deleted);
Assert.Equal(name, user.Name);
}
{
Expand Down Expand Up @@ -429,7 +429,7 @@ public async Task LogicalDeletedBoolAsync()
const int id = 10;

var user = await Db.Users.FindAsync(x => x.Id == id);
Assert.False(user.Deleted);
Assert.Null(user.Deleted);

var deleted = await Db.Users.DeleteAsync(user);
Assert.True(deleted);
Expand Down
2 changes: 1 addition & 1 deletion tests/Repositories.MSSQL.Tests/DatabaseFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ void CreateSchema(string dbSchema)
CreateSchema("DAB");

Db.Connection.Execute(
@"CREATE TABLE Users (Id int IDENTITY(1,1) not null, Name varchar(256) not null, AddressId int not null, PhoneId int not null, OfficePhoneId int not null, Deleted bit not null, UpdatedAt datetime2, PRIMARY KEY (Id))");
@"CREATE TABLE Users (Id int IDENTITY(1,1) not null, Name varchar(256) not null, AddressId int not null, PhoneId int not null, OfficePhoneId int not null, Deleted bit, UpdatedAt datetime2, PRIMARY KEY (Id))");
Db.Connection.Execute(
@"CREATE TABLE Cars (Id int IDENTITY(1,1) not null, Name varchar(256) not null, UserId int not null, Status int not null, Data binary(16) null, PRIMARY KEY (Id))");

Expand Down
4 changes: 2 additions & 2 deletions tests/Repositories.MySql.Tests/DatabaseFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private void InitDb()

Db.Connection.Execute("CREATE TABLE IF NOT EXISTS `Users` " +
"(`Id` int not null auto_increment, `Name` varchar(256) not null, `AddressId` int not null, `PhoneId` int not null, " +
"`OfficePhoneId` int not null, `Deleted` boolean not null, `UpdatedAt` datetime, PRIMARY KEY (`Id`));");
"`OfficePhoneId` int not null, `Deleted` boolean, `UpdatedAt` datetime, PRIMARY KEY (`Id`));");

Db.Connection.Execute("CREATE TABLE IF NOT EXISTS `Cars` " +
"(`Id` int not null auto_increment, `Name` varchar(256) not null, " +
Expand All @@ -65,6 +65,6 @@ private void InitDb()
private void DropDatabase()
{
Db.Connection.Execute($"DROP DATABASE IF EXISTS {_dbName}");
Db.Connection.Execute($"DROP DATABASE IF EXISTS DAB");
Db.Connection.Execute("DROP DATABASE IF EXISTS DAB");
}
}
2 changes: 1 addition & 1 deletion tests/Repositories.Oracle.Tests/DatabaseFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ NAME VARCHAR(256) NOT NULL,
ADDRESSID NUMBER NOT NULL,
PHONEID NUMBER NOT NULL,
OFFICEPHONEID NUMBER NOT NULL,
DELETED NUMBER NOT NULL,
DELETED NUMBER,
UPDATEDAT DATE,
PRIMARY KEY (ID))");

Expand Down
2 changes: 1 addition & 1 deletion tests/Repositories.PostgreSQL.Tests/DatabaseFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void CreateSchema(string dbSchema)
CreateSchema("DAB");

Db.Connection.Execute(
@"CREATE TABLE Users (Id SERIAL not null, Name varchar(256) not null, AddressId int not null, PhoneId int not null, OfficePhoneId int not null, Deleted bool not null, UpdatedAt timestamp, PRIMARY KEY (Id))");
@"CREATE TABLE Users (Id SERIAL not null, Name varchar(256) not null, AddressId int not null, PhoneId int not null, OfficePhoneId int not null, Deleted bool, UpdatedAt timestamp, PRIMARY KEY (Id))");
Db.Connection.Execute(
@"CREATE TABLE Cars (Id SERIAL not null, Name varchar(256) not null, UserId int not null, Status int not null, Data bytea null, PRIMARY KEY (Id))");

Expand Down
2 changes: 1 addition & 1 deletion tests/Repositories.SQLite.Tests/DatabaseFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private void InitDb()

Db.Connection.Execute("CREATE TABLE `Users` " +
"(`Id` integer not null primary key autoincrement, `Name` varchar(256) not null, `AddressId` integer not null, `PhoneId` integer not null, " +
"`OfficePhoneId` integer not null, `Deleted` boolean not null, `UpdatedAt` datetime);");
"`OfficePhoneId` integer not null, `Deleted` boolean, `UpdatedAt` datetime);");

Db.Connection.Execute("CREATE TABLE `Cars` " +
"(`Id` integer not null primary key autoincrement, `Name` varchar(256) not null, " +
Expand Down
Loading

0 comments on commit ac88557

Please sign in to comment.