diff --git a/src/SimplePatch.Tests/ConfigurationTests/Globals.cs b/src/SimplePatch.Tests/ConfigurationTests/Globals.cs index 83affe8..ecdbaf8 100644 --- a/src/SimplePatch.Tests/ConfigurationTests/Globals.cs +++ b/src/SimplePatch.Tests/ConfigurationTests/Globals.cs @@ -27,6 +27,19 @@ public void IgnoreLetterCase() Assert.AreEqual(23, John.Age); } + [TestMethod] + public void ConfigFromAssembly() + { + + var assembly = typeof(Person).Assembly; + DeltaConfig.InitFromAssembly(cfg => { + cfg.AddAssembly(assembly); + }); + CreateDelta("Age", 23).Patch(John); + Assert.AreEqual(23, John.Age); + + } + [TestMethod] public void MappingFunction() { diff --git a/src/SimplePatch.Tests/ConfigurationTests/Properties.cs b/src/SimplePatch.Tests/ConfigurationTests/Properties.cs index 008b6f1..1028e9e 100644 --- a/src/SimplePatch.Tests/ConfigurationTests/Properties.cs +++ b/src/SimplePatch.Tests/ConfigurationTests/Properties.cs @@ -32,6 +32,39 @@ public void Exclude() Assert.AreEqual(initialAge, John.Age); } + [TestMethod] + public void ExcludedByAttribute() + { + DeltaConfig.Init(cfg => + { + cfg + .AddEntity(); + }); + + var initialAge = John.AgeExcludeByAttibute; + + CreateDelta(x => x.AgeExcludeByAttibute, 23).Patch(John); + + Assert.AreEqual(initialAge, John.AgeExcludeByAttibute); + } + + [TestMethod] + public void ExcludedByMapping() + { + var assembly = typeof(Person).Assembly; + DeltaConfig.InitFromAssembly(cfg => + { + cfg + .AddAssembly(assembly); + }); + + var initialAge = John.AgeExcludeByAttibute; + + CreateDelta(x => x.AgeExcludeByMapping, 23).Patch(John); + + Assert.AreEqual(initialAge, John.AgeExcludeByAttibute); + } + [TestMethod] public void IgnoreNullValue() { diff --git a/src/SimplePatch.Tests/Person.cs b/src/SimplePatch.Tests/Person.cs index 182f114..d89c122 100644 --- a/src/SimplePatch.Tests/Person.cs +++ b/src/SimplePatch.Tests/Person.cs @@ -1,4 +1,5 @@ using System; +using SimplePatch.Attributes; namespace SimplePatch.Tests { @@ -7,6 +8,9 @@ internal class Person public string Name { get; set; } public string Surname { get; set; } public int Age { get; set; } + [Exclude] + public int AgeExcludeByAttibute { get; set; } + public int AgeExcludeByMapping { get; set; } public double Height { get; set; } public Guid Guid { get; set; } public DateTime BirthDate { get; set; } @@ -23,4 +27,13 @@ internal enum Cool { Awesome, NotReally } + + internal class PersonConfiguration : Mapping.IEntityTypeConfiguration + { + public void Configuration(DeltaConfig.EntityConfig entityConfig) + { + entityConfig.Property(x => x.AgeExcludeByMapping).Exclude(); + } + } + } diff --git a/src/SimplePatch.Tests/TestBase.cs b/src/SimplePatch.Tests/TestBase.cs index d1b76c3..f01eaa7 100644 --- a/src/SimplePatch.Tests/TestBase.cs +++ b/src/SimplePatch.Tests/TestBase.cs @@ -16,6 +16,7 @@ public void TestInit() Name = "John", Surname = "Doe", Age = 22, + AgeExcludeByAttibute = 22, Height = 1.7, BirthDate = new DateTime(1990, 2, 1, 20, 15, 10) }; diff --git a/src/SimplePatch/Attributes/ExcludeAttribute.cs b/src/SimplePatch/Attributes/ExcludeAttribute.cs new file mode 100644 index 0000000..0263299 --- /dev/null +++ b/src/SimplePatch/Attributes/ExcludeAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplePatch.Attributes +{ + public class ExcludeAttribute : Attribute + { + } +} diff --git a/src/SimplePatch/Delta.cs b/src/SimplePatch/Delta.cs index c42ace0..81321df 100644 --- a/src/SimplePatch/Delta.cs +++ b/src/SimplePatch/Delta.cs @@ -1,4 +1,5 @@ -using SimplePatch.Helpers; +using SimplePatch.Attributes; +using SimplePatch.Helpers; using SimplePatch.Mapping; using System; using System.Collections; @@ -194,7 +195,7 @@ private TEntity SetPropertiesValue(TEntity entity) foreach (var prop in entityProperties) { var propertyInfo = prop.PropertyInfo; - if (ContainsKey(propertyInfo.Name) && !prop.Excluded) + if (ContainsKey(propertyInfo.Name) && !prop.Excluded && !ExcludedByAttribute(propertyInfo)) { var truePropertyType = TypeHelper.GetTrueType(propertyInfo.PropertyType); var newPropertyValue = this[propertyInfo.Name]; @@ -340,6 +341,10 @@ public bool ContainsKey(string key) { return dict.ContainsKey(key); } + public bool ExcludedByAttribute(PropertyInfo propertyInfo) + { + return propertyInfo.GetCustomAttribute(typeof(ExcludeAttribute)) != null; + } public bool Remove(string key) { diff --git a/src/SimplePatch/DeltaConfig.cs b/src/SimplePatch/DeltaConfig.cs index b450d8f..cb0ae32 100644 --- a/src/SimplePatch/DeltaConfig.cs +++ b/src/SimplePatch/DeltaConfig.cs @@ -2,7 +2,9 @@ using SimplePatch.Mapping; using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; +using System.Reflection; namespace SimplePatch { @@ -20,6 +22,10 @@ public static void Init(Action config) config(new Config()); } + public static void InitFromAssembly(Action config) { + config(new ConfigFromAssembly()); + } + internal static void Clean() { IgnoreLetterCase = false; @@ -27,62 +33,63 @@ internal static void Clean() DeltaCache.Clear(); } - public sealed class Config + public sealed class EntityConfig where T : class, new() { - public sealed class EntityConfig where T : class, new() + public PropertyConfig Property(Expression> property) { - public PropertyConfig Property(Expression> property) - { - return new PropertyConfig(property); - } + return new PropertyConfig(property); } + } - public sealed class PropertyConfig where TEntity : class, new() - { - private readonly string propertyName; - private readonly DeltaCache.PropertyEditor deltaCachePropertyEditor; + public sealed class PropertyConfig where TEntity : class, new() + { + private readonly string propertyName; + private readonly DeltaCache.PropertyEditor deltaCachePropertyEditor; - public PropertyConfig(Expression> property) - { - propertyName = ExpressionHelper.GetPropertyName(property); - deltaCachePropertyEditor = new DeltaCache.PropertyEditor(propertyName); - } + public PropertyConfig(Expression> property) + { + propertyName = ExpressionHelper.GetPropertyName(property); + deltaCachePropertyEditor = new DeltaCache.PropertyEditor(propertyName); + } - /// - /// Adds a mapping function for the specified property of the specified entity. - /// - /// Type of the property - /// Expression which indicates the property - /// Mapping function used to evaluate the value to be assigned to the property - /// - public PropertyConfig AddMapping(MapDelegate mapFunction) - { - deltaCachePropertyEditor.AddMapping(mapFunction); - return this; - } + /// + /// Adds a mapping function for the specified property of the specified entity. + /// + /// Type of the property + /// Expression which indicates the property + /// Mapping function used to evaluate the value to be assigned to the property + /// + public PropertyConfig AddMapping(MapDelegate mapFunction) + { + deltaCachePropertyEditor.AddMapping(mapFunction); + return this; + } - /// - /// Ignore null value for the specified property - /// - /// - public PropertyConfig IgnoreNull() - { - deltaCachePropertyEditor.IgnoreNullValue(); - return this; - } + /// + /// Ignore null value for the specified property + /// + /// + public PropertyConfig IgnoreNull() + { + deltaCachePropertyEditor.IgnoreNullValue(); + return this; + } - /// - /// Marks the specified property as excluded when calling . - /// - /// - /// - /// - public PropertyConfig Exclude() - { - deltaCachePropertyEditor.Exclude(); - return this; - } + /// + /// Marks the specified property as excluded when calling . + /// + /// + /// + /// + public PropertyConfig Exclude() + { + deltaCachePropertyEditor.Exclude(); + return this; } + } + + public sealed class Config + { /// /// Allows to add settings for the specified property @@ -119,5 +126,37 @@ public Config AddMapping(MapDelegate mappingFunc) return this; } } + + public sealed class ConfigFromAssembly + { + private Config config; + public ConfigFromAssembly() { + this.config = new Config(); + } + public ConfigFromAssembly AddAssembly(Assembly assembly) { + + var types = assembly.GetTypes(); + foreach (var type in types) + { + var interfaces = type.GetInterfaces(); + var implementedInterface = interfaces.Where(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)).FirstOrDefault(); + if (implementedInterface != null) { + //add entity + var methodDef = typeof(Config).GetMethod("AddEntity"); + var method = methodDef.MakeGenericMethod(new Type[] { implementedInterface.GetGenericArguments()[0] }); + var entityConfig = method.Invoke(config, new object[] { }); + //run config from entity + var obj = Activator.CreateInstance(type); + var configurationMethodDef = type.GetMethod("Configuration"); + configurationMethodDef.Invoke(obj, new object[] { entityConfig }); + + } + } + return this; + } + } + + + } } diff --git a/src/SimplePatch/Mapping/IEntityTypeConfiguration.cs b/src/SimplePatch/Mapping/IEntityTypeConfiguration.cs new file mode 100644 index 0000000..9c6f657 --- /dev/null +++ b/src/SimplePatch/Mapping/IEntityTypeConfiguration.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplePatch.Mapping +{ + public interface IEntityTypeConfiguration where TEntity : class, new() + { + void Configuration(DeltaConfig.EntityConfig entityConfig); + } +} diff --git a/src/SimplePatch/SimplePatch.csproj b/src/SimplePatch/SimplePatch.csproj index 00439b8..c2a5b5c 100644 --- a/src/SimplePatch/SimplePatch.csproj +++ b/src/SimplePatch/SimplePatch.csproj @@ -30,4 +30,8 @@ + + + +