-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨feat: Auto filters & update objects (#7)
* ✨feat: Change tracking proxy factory Added support for creating change tracking proxies for intrafaces and classes. Proxy tracks changes on writable virtual properties (for classes) or all writable properties (for interfaces). Changes are availabe through the IChangeTrack interface on the object. * ✨feat: Automapping of filters & updates Introduced default auto mappers for entites which provide out-of-the box ability to use column based filtering and updateing. This reduces boilerplate code required to setup an entity. Extended filter and update properties are still supported and full control of the mapping is supported. BREAKING CHANGE: Removed IQueryFilter interface * version bump * Alpha version * Composite interface builder * Fix issue with missing properties * Version fixes & bump * Final version bump
- Loading branch information
1 parent
2520060
commit 6af5e1e
Showing
46 changed files
with
1,465 additions
and
313 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using Dapper; | ||
using Moq; | ||
using Moq.Dapper; | ||
using Simpleverse.Repository.Db; | ||
using Simpleverse.Repository.Db.SqlServer; | ||
using Simpleverse.Repository.Db.Test.SqlServer.Entity; | ||
using System; | ||
using System.Data; | ||
using System.Data.Common; | ||
using System.Linq; | ||
|
||
namespace Simpleverse.Repository.Db.Test | ||
{ | ||
public class DapperHelper | ||
{ | ||
private readonly Mock<DbConnection> _mockConnection; | ||
|
||
public DapperHelper() | ||
{ | ||
_mockConnection = new Mock<DbConnection>(); | ||
_mockConnection | ||
.SetupDapperAsync(c => c.QueryAsync<EntityModel>(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IDbTransaction>(), null, null)) | ||
.ReturnsAsync(Array.Empty<EntityModel>()); | ||
} | ||
|
||
public SqlRepository Instance() | ||
=> new SqlRepository(() => _mockConnection.Object); | ||
|
||
private IDbCommand LastDbCommandInvocation() | ||
{ | ||
var invocation = _mockConnection | ||
.Invocations | ||
.LastOrDefault(x => x.Method.Name == nameof(IDbConnection.CreateCommand)); | ||
|
||
if (invocation == null) | ||
return null; | ||
|
||
return (IDbCommand)invocation.ReturnValue; | ||
} | ||
|
||
public string Query() | ||
{ | ||
var command = LastDbCommandInvocation(); | ||
if (command == null) | ||
return string.Empty; | ||
|
||
return command.CommandText; | ||
} | ||
|
||
public IDataParameterCollection Parameters() | ||
{ | ||
var command = LastDbCommandInvocation(); | ||
if (command == null) | ||
return null; | ||
|
||
return command.Parameters; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
src/Simpleverse.Repository.Db.Test/SqlServer/Entity/Entity.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using Dapper.Contrib.Extensions; | ||
|
||
namespace Simpleverse.Repository.Db.Test.SqlServer.Entity | ||
{ | ||
public interface IEntityModel | ||
{ | ||
int Id { get; set; } | ||
string Name { get; set; } | ||
bool Active { get; set; } | ||
} | ||
|
||
public class Entity : Entity<EntityModel> | ||
{ | ||
public Entity(DbRepository repository) | ||
: base(repository, new Table<EntityModel>("I")) | ||
{ | ||
} | ||
} | ||
|
||
[Table("IEntity")] | ||
public class EntityModel : IEntityModel | ||
{ | ||
public virtual int Id { get; set; } | ||
public virtual string Name { get; set; } | ||
public virtual bool Active { get; set; } | ||
} | ||
|
||
public class EntityExtend : Entity<EntityModelExtended> | ||
{ | ||
public EntityExtend(DbRepository repository) | ||
: base(repository, new Table<EntityModelExtended>("I")) | ||
{ | ||
} | ||
} | ||
|
||
public interface IEntityModelExtended : IEntityModel | ||
{ | ||
string Description { get; set; } | ||
int DummyValue { get; set; } | ||
} | ||
|
||
public class EntityModelExtended : EntityModel, IEntityModelExtended | ||
{ | ||
public string NormalizedName => Name.ToUpper(); | ||
public virtual string Description { get; set; } | ||
public virtual int DummyValue { get; set; } | ||
} | ||
|
||
public class EntityCustom : Entity<EntityModelExtended> | ||
{ | ||
public EntityCustom(DbRepository repository) | ||
: base(repository, new Table<EntityModelExtended>("I")) | ||
{ | ||
} | ||
|
||
protected override void Filter(QueryBuilder<EntityModelExtended> builder, EntityModelExtended filter) | ||
{ | ||
base.Filter(builder, filter); | ||
IfChanged(filter, x => x.DummyValue, () => builder.Where(x => x.DummyValue, filter.DummyValue)); | ||
} | ||
} | ||
|
||
public class EntityInterfaceExtended : Entity<EntityModelExtended, IEntityModelExtended, DbQueryOptions> | ||
{ | ||
public EntityInterfaceExtended(DbRepository repository) | ||
: base(repository, new Table<EntityModelExtended>("I")) | ||
{ | ||
} | ||
} | ||
} |
197 changes: 197 additions & 0 deletions
197
src/Simpleverse.Repository.Db.Test/SqlServer/Entity/EntityProxyTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
using System.Threading.Tasks; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace Simpleverse.Repository.Db.Test.SqlServer.Entity | ||
{ | ||
[Collection("SqlServerCollection")] | ||
public class EntityProxyTest : TestFixture | ||
{ | ||
public EntityProxyTest(ITestOutputHelper output) | ||
: base(output) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public async Task ListAsyncWithParametersTest() | ||
{ | ||
// arange | ||
var repositoryHelper = new DapperHelper(); | ||
var entity = new Entity(repositoryHelper.Instance()); | ||
|
||
// act | ||
await entity.ListAsync( | ||
filter => | ||
{ | ||
filter.Name = "test"; | ||
filter.Active = false; | ||
} | ||
); | ||
|
||
// assert | ||
var query = repositoryHelper.Query(); | ||
Assert.Contains("[I].[Name] = @I_Name", query); | ||
Assert.Contains("[I].[Active] = @I_Active", query); | ||
} | ||
|
||
[Fact] | ||
public async Task UpdateAsyncWithParametersTest() | ||
{ | ||
// arange | ||
var repositoryHelper = new DapperHelper(); | ||
var entity = new Entity(repositoryHelper.Instance()); | ||
|
||
// act | ||
await entity.UpdateAsync( | ||
update => | ||
{ | ||
update.Name = "test"; | ||
}, | ||
filter => | ||
{ | ||
filter.Active = false; | ||
} | ||
); | ||
|
||
// assert | ||
var query = repositoryHelper.Query(); | ||
Assert.Contains("[I].[Name] = @Set_I_Name", query); | ||
Assert.Contains("[I].[Active] = @I_Active", query); | ||
} | ||
|
||
[Fact] | ||
public async Task ListAsyncWithExtendParametersTest() | ||
{ | ||
// arange | ||
var repositoryHelper = new DapperHelper(); | ||
var entity = new EntityExtend(repositoryHelper.Instance()); | ||
|
||
// act | ||
await entity.ListAsync( | ||
filter => | ||
{ | ||
filter.Name = "test"; | ||
filter.Active = false; | ||
filter.DummyValue = 1; | ||
} | ||
); | ||
|
||
// assert | ||
var query = repositoryHelper.Query(); | ||
Assert.Contains("[I].[Name] = @I_Name", query); | ||
Assert.Contains("[I].[Active] = @I_Active", query); | ||
Assert.Contains("[I].[DummyValue] = @I_DummyValue", query); | ||
} | ||
|
||
[Fact] | ||
public async Task UpdateAsyncWithExtendedParametersTest() | ||
{ | ||
// arange | ||
var repositoryHelper = new DapperHelper(); | ||
var entity = new EntityExtend(repositoryHelper.Instance()); | ||
|
||
// act | ||
await entity.UpdateAsync( | ||
update => | ||
{ | ||
update.Name = "test"; | ||
update.Description = "test"; | ||
}, | ||
filter => | ||
{ | ||
filter.DummyValue = 1; | ||
filter.Active = false; | ||
} | ||
); | ||
|
||
// assert | ||
var query = repositoryHelper.Query(); | ||
Assert.Contains("[I].[Name] = @Set_I_Name", query); | ||
Assert.Contains("[I].[Description] = @Set_I_Description", query); | ||
Assert.Contains("[I].[Active] = @I_Active", query); | ||
Assert.Contains("[I].[DummyValue] = @I_DummyValue", query); | ||
} | ||
|
||
[Fact] | ||
public async Task ListAsyncWithCustomParametersTest() | ||
{ | ||
// arange | ||
var repositoryHelper = new DapperHelper(); | ||
var entity = new EntityCustom(repositoryHelper.Instance()); | ||
|
||
// act | ||
await entity.ListAsync( | ||
filter => | ||
{ | ||
filter.Name = "test"; | ||
filter.Active = false; | ||
filter.DummyValue = 1; | ||
} | ||
); | ||
|
||
// assert | ||
var query = repositoryHelper.Query(); | ||
Assert.Contains("[I].[Name] = @I_Name", query); | ||
Assert.Contains("[I].[Active] = @I_Active", query); | ||
Assert.Contains("[I].[DummyValue] = @I_DummyValue", query); | ||
} | ||
|
||
[Fact] | ||
public async Task UpdateAsyncWithCustomParametersTest() | ||
{ | ||
// arange | ||
var repositoryHelper = new DapperHelper(); | ||
var entity = new EntityCustom(repositoryHelper.Instance()); | ||
|
||
// act | ||
await entity.UpdateAsync( | ||
update => | ||
{ | ||
update.Name = "test"; | ||
update.Description = "test"; | ||
}, | ||
filter => | ||
{ | ||
filter.DummyValue = 1; | ||
filter.Active = false; | ||
} | ||
); | ||
|
||
// assert | ||
var query = repositoryHelper.Query(); | ||
Assert.Contains("[I].[Name] = @Set_I_Name", query); | ||
Assert.Contains("[I].[Description] = @Set_I_Description", query); | ||
Assert.Contains("[I].[Active] = @I_Active", query); | ||
Assert.Contains("[I].[DummyValue] = @I_DummyValue", query); | ||
} | ||
|
||
[Fact] | ||
public async Task UpdateAsyncWithExtendedInterfaceParametersTest() | ||
{ | ||
// arange | ||
var repositoryHelper = new DapperHelper(); | ||
var entity = new EntityInterfaceExtended(repositoryHelper.Instance()); | ||
|
||
// act | ||
await entity.UpdateAsync( | ||
update => | ||
{ | ||
update.Name = "test"; | ||
update.Description = "test"; | ||
}, | ||
filter => | ||
{ | ||
filter.DummyValue = 1; | ||
filter.Active = false; | ||
} | ||
); | ||
|
||
// assert | ||
var query = repositoryHelper.Query(); | ||
Assert.Contains("[I].[Name] = @Set_I_Name", query); | ||
Assert.Contains("[I].[Description] = @Set_I_Description", query); | ||
Assert.Contains("[I].[Active] = @I_Active", query); | ||
Assert.Contains("[I].[DummyValue] = @I_DummyValue", query); | ||
} | ||
} | ||
} |
Oops, something went wrong.