From b46378adb46687d4ca28232734a96e404d58dd5b Mon Sep 17 00:00:00 2001 From: zadykian Date: Fri, 27 Oct 2023 14:55:52 +0400 Subject: [PATCH 1/7] DynamicRuntimeMacro.GetPropValue - added nested keys support for IDictionary --- .../sdmap/Macros/Implements/RuntimeMacros.cs | 44 +++- .../test/sdmap.test/GetPropertyValueTests.cs | 246 ++++++++++++++++++ 2 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 sdmap/test/sdmap.test/GetPropertyValueTests.cs diff --git a/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs b/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs index c953d86..6a61bfb 100644 --- a/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs +++ b/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs @@ -471,15 +471,47 @@ public static QueryPropertyInfo GetProp(object self, object syntax) public static object GetPropValue(object self, string prop) { - if (self is IDictionary dicSelf) + if (string.IsNullOrWhiteSpace(prop)) { - return dicSelf[prop]; + return default; } - else + + return prop + .Split('.') + .Aggregate(self, GetByKey); + + static object GetByKey(object target, string key) + => target switch + { + _ when string.IsNullOrWhiteSpace(key) + => default, + + IDictionary dictionary + => dictionary.Contains(key) + ? dictionary[key] + : default, + + not null + => GetByMemberInfo(target, key), + + _ => default + }; + + static object GetByMemberInfo(object target, string memberName) { - var props = prop.Split('.'); - return props.Aggregate(self, (s, p) => - s?.GetType().GetTypeInfo().GetProperty(p)?.GetValue(s)); + var type = target.GetType(); + + if (type.GetProperty(memberName) is { } property) + { + return property.GetValue(target); + } + + if (type.GetField(memberName) is { } field) + { + return field.GetValue(field); + } + + return default; } } diff --git a/sdmap/test/sdmap.test/GetPropertyValueTests.cs b/sdmap/test/sdmap.test/GetPropertyValueTests.cs new file mode 100644 index 0000000..093c0a2 --- /dev/null +++ b/sdmap/test/sdmap.test/GetPropertyValueTests.cs @@ -0,0 +1,246 @@ +using System.Collections.Generic; +using sdmap.Macros.Implements; +using Xunit; + +// ReSharper disable UnusedAutoPropertyAccessor.Local + +namespace sdmap.test; + +public class GetPropertyValueTests +{ + [Fact] + public void NullObject_ReturnsNull() + { + var result = DynamicRuntimeMacros.GetPropValue(self: null, "Prop"); + Assert.Null(result); + } + + [Theory] + [InlineData(data: null)] + [InlineData("")] + [InlineData(" ")] + public void NullOrEmptyProp_ReturnsNull(string prop) + { + var obj = new ComplexClass { Prop = "Test" }; + var result = DynamicRuntimeMacros.GetPropValue(obj, prop); + Assert.Null(result); + } + + [Fact] + public void ValidProp_ReturnsValue() + { + var obj = new ComplexClass { Prop = "Test" }; + var result = DynamicRuntimeMacros.GetPropValue(obj, "Prop"); + Assert.Equal("Test", result); + } + + [Fact] + public void ValidField_ReturnsValue() + { + var obj = new ComplexClass { Field = "Test" }; + var result = DynamicRuntimeMacros.GetPropValue(obj, "Field"); + Assert.Equal("Test", result); + } + + [Fact] + public void NestedProp_ReturnsValue() + { + var obj = new ComplexClass + { + Prop = new ComplexClass + { + Prop = "NestedTest" + } + }; + var result = DynamicRuntimeMacros.GetPropValue( + obj, + "Prop.Prop" + ); + Assert.Equal("NestedTest", result); + } + + [Fact] + public void NestedPropAndField_ReturnsValue() + { + var obj = new ComplexClass + { + Prop = new ComplexClass + { + Field = "NestedTest" + } + }; + var result = DynamicRuntimeMacros.GetPropValue( + obj, + "Prop.Field" + ); + Assert.Equal("NestedTest", result); + } + + [Fact] + public void NonExistentProp_ReturnsNull() + { + var obj = new ComplexClass { Prop = "Test" }; + var result = DynamicRuntimeMacros.GetPropValue( + obj, + "NonExistent" + ); + Assert.Null(result); + } + + [Fact] + public void Dictionary_ReturnsValue() + { + var dictionary = new Dictionary + { + ["Key"] = "Value" + }; + var result = DynamicRuntimeMacros.GetPropValue(dictionary, "Key"); + Assert.Equal("Value", result); + } + + [Fact] + public void DictionaryNonExistentKey_ReturnsNull() + { + var dictionary = new Dictionary + { + ["Key"] = "Value" + }; + var result = DynamicRuntimeMacros.GetPropValue( + dictionary, + "NonExistentKey" + ); + Assert.Null(result); + } + + [Fact] + public void DictionaryWithNestedDictionary_ReturnsValue() + { + var nestedDictionary = new Dictionary { ["NestedKey"] = "NestedValue" }; + var dictionary = new Dictionary + { + ["Key"] = nestedDictionary + }; + var result = DynamicRuntimeMacros.GetPropValue( + dictionary, + "Key.NestedKey" + ); + Assert.Equal("NestedValue", result); + } + + [Fact] + public void ObjectWithNestedDictionary_ReturnsValue() + { + var obj = new ComplexClass + { + InnerDictionary = new() + { + ["DictionaryKey"] = "DictionaryValue" + } + }; + + var result = DynamicRuntimeMacros.GetPropValue( + obj, + "InnerDictionary.DictionaryKey" + ); + Assert.Equal("DictionaryValue", result); + } + + [Fact] + public void ObjectWithNestedDictionary_NonExistentKey_ReturnsNull() + { + var obj = new ComplexClass + { + InnerDictionary = new() + { + ["DictionaryKey"] = "DictionaryValue" + } + }; + + var result = DynamicRuntimeMacros.GetPropValue( + obj, + "InnerDictionary.NonExistentKey" + ); + Assert.Null(result); + } + + [Fact] + public void DictionaryWithNestedObject_ReturnsValue() + { + var nestedObj = new ComplexClass { Prop = "NestedObjectValue" }; + var dictionary = new Dictionary + { + ["ObjectKey"] = nestedObj + }; + + var result = DynamicRuntimeMacros.GetPropValue( + dictionary, + "ObjectKey.Prop" + ); + Assert.Equal("NestedObjectValue", result); + } + + [Fact] + public void + DictionaryWithNestedObject_NonExistentProperty_ReturnsNull() + { + var nestedObj = new ComplexClass { Prop = "NestedObjectValue" }; + var dictionary = new Dictionary + { + ["ObjectKey"] = nestedObj + }; + + var result = DynamicRuntimeMacros.GetPropValue( + dictionary, + "ObjectKey.NonExistentProp" + ); + Assert.Null(result); + } + + [Fact] + public void ObjectWithNestedDictionaryAndObject_ReturnsValue() + { + var nestedObj = new ComplexClass { Prop = "NestedObjectValue" }; + var obj = new ComplexClass + { + InnerDictionary = new() + { + ["NestedObjectKey"] = nestedObj + } + }; + + var result = DynamicRuntimeMacros.GetPropValue( + obj, + "InnerDictionary.NestedObjectKey.Prop" + ); + Assert.Equal("NestedObjectValue", result); + } + + [Fact] + public void DictionaryWithNestedObjectAndDictionary_ReturnsValue() + { + var nestedDictionary = new Dictionary + { + ["NestedDictionaryKey"] = "NestedDictionaryValue" + }; + var nestedObj = new ComplexClass { Prop = nestedDictionary }; + var dictionary = new Dictionary + { + ["NestedObjectKey"] = nestedObj + }; + + var result = DynamicRuntimeMacros.GetPropValue( + dictionary, + "NestedObjectKey.Prop.NestedDictionaryKey" + ); + Assert.Equal("NestedDictionaryValue", result); + } + + private sealed class ComplexClass + { + public Dictionary InnerDictionary { get; set; } + + public object Prop { get; set; } + + public object Field { get; set; } + } +} \ No newline at end of file From e625a91ada7b0fefe94148918833d001ed16e2ee Mon Sep 17 00:00:00 2001 From: zadykian Date: Fri, 27 Oct 2023 16:59:44 +0400 Subject: [PATCH 2/7] version 0.16.6 --- sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj | 6 +++--- sdmap/src/sdmap.ext/sdmap.ext.csproj | 6 +++--- sdmap/src/sdmap/sdmap.csproj | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj b/sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj index 2b0d125..96f42c0 100644 --- a/sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj +++ b/sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj @@ -14,13 +14,13 @@ https://github.com/sdcb/sdmap/blob/master/ReleaseNotes.md false false false - 0.16.5 + 0.16.6 Dapper extensions for sdmap. https://github.com/sdcb/sdmap sdcb MIT - 0.16.5 - 0.16.5 + 0.16.6 + 0.16.6 LICENSE true true diff --git a/sdmap/src/sdmap.ext/sdmap.ext.csproj b/sdmap/src/sdmap.ext/sdmap.ext.csproj index d6b0843..cf37935 100644 --- a/sdmap/src/sdmap.ext/sdmap.ext.csproj +++ b/sdmap/src/sdmap.ext/sdmap.ext.csproj @@ -14,13 +14,13 @@ https://github.com/sdcb/sdmap/blob/master/ReleaseNotes.md false false false - 0.16.5 + 0.16.6 Useful extensions for sdmap/Dapper. https://github.com/sdcb/sdmap sdcb MIT - 0.16.5 - 0.16.5 + 0.16.6 + 0.16.6 LICENSE true true diff --git a/sdmap/src/sdmap/sdmap.csproj b/sdmap/src/sdmap/sdmap.csproj index 3ec42ae..367c48b 100644 --- a/sdmap/src/sdmap/sdmap.csproj +++ b/sdmap/src/sdmap/sdmap.csproj @@ -15,9 +15,9 @@ false false false - 0.16.5 - 0.16.5 - 0.16.5 + 0.16.6 + 0.16.6 + 0.16.6 sdcb MIT https://github.com/sdcb/sdmap From 380cd3cd64847a725021cd7b95dacefa035deb03 Mon Sep 17 00:00:00 2001 From: zadykian Date: Fri, 27 Oct 2023 18:20:33 +0400 Subject: [PATCH 3/7] nested key access for IDictionary params in QueryPropertyInfo GetProp() method --- .../sdmap/Macros/Implements/RuntimeMacros.cs | 52 +++++++------------ 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs b/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs index 6a61bfb..94e2ac9 100644 --- a/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs +++ b/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs @@ -440,48 +440,31 @@ private static Result RequireType(Type type, string expected, public static QueryPropertyInfo GetProp(object self, object syntax) { - var props = (syntax as string).Split('.'); - var fronts = props.Take(props.Length - 1); - - if (self is IDictionary dicSelf) + if (syntax is not string propertyAccess) { - if (!dicSelf.Contains(syntax)) - return null; - - var val = dicSelf[syntax]; - if (val == null) - return new QueryPropertyInfo(props[0], typeof(object)); - - return new QueryPropertyInfo(props[0], val.GetType()); + throw new ArgumentException("Variable is expected to be of type string.", nameof(syntax)); } - else - { - var frontValue = fronts.Aggregate(self, (s, p) => - s?.GetType().GetTypeInfo().GetProperty(p)?.GetValue(s)); - - var pi = frontValue - ?.GetType() - .GetTypeInfo() - .GetProperty(props.Last()); - if (pi == null) return null; - return new QueryPropertyInfo(pi.Name, pi.PropertyType); - } + var (name, _, type) = GetPropertyMetadata(self, propertyAccess); + return new(name, type); } - public static object GetPropValue(object self, string prop) + public static object GetPropValue(object self, string prop) => GetPropertyMetadata(self, prop).Value; + + private static (string Name, object Value, Type Type) GetPropertyMetadata(object target, string propertyAccess) { - if (string.IsNullOrWhiteSpace(prop)) + if (string.IsNullOrWhiteSpace(propertyAccess)) { - return default; + return (Name: propertyAccess, Value: default, Type: typeof(object)); } - return prop - .Split('.') - .Aggregate(self, GetByKey); + var properties = propertyAccess.Split('.'); + var value = properties.Aggregate(target, GetValueByKey); + return (Name: properties.LastOrDefault(), Value: value, Type: value?.GetType() ?? typeof(object)); - static object GetByKey(object target, string key) - => target switch + static object GetValueByKey(object target, string key) + { + return target switch { _ when string.IsNullOrWhiteSpace(key) => default, @@ -492,12 +475,13 @@ IDictionary dictionary : default, not null - => GetByMemberInfo(target, key), + => GetValueOfMemberInfo(target, key), _ => default }; + } - static object GetByMemberInfo(object target, string memberName) + static object GetValueOfMemberInfo(object target, string memberName) { var type = target.GetType(); From 68ccd8b16e5cd90bcc5c7acae00f19f045b0ca9f Mon Sep 17 00:00:00 2001 From: zadykian Date: Sun, 29 Oct 2023 14:52:08 +0400 Subject: [PATCH 4/7] implementation of PropertyMetadataRetriever + unit tests --- sdmap/src/sdmap/IsExternalInit.cs | 8 + .../Implements/PropertyMetadataRetriever.cs | 59 ++++ .../sdmap/Macros/Implements/RuntimeMacros.cs | 52 +--- .../test/sdmap.test/GetPropertyValueTests.cs | 246 ---------------- .../PropertyMetadataRetrieverTests.cs | 269 ++++++++++++++++++ sdmap/test/sdmap.test/sdmap.test.csproj | 1 + 6 files changed, 339 insertions(+), 296 deletions(-) create mode 100644 sdmap/src/sdmap/IsExternalInit.cs create mode 100644 sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs delete mode 100644 sdmap/test/sdmap.test/GetPropertyValueTests.cs create mode 100644 sdmap/test/sdmap.test/PropertyMetadataRetrieverTests.cs diff --git a/sdmap/src/sdmap/IsExternalInit.cs b/sdmap/src/sdmap/IsExternalInit.cs new file mode 100644 index 0000000..589db89 --- /dev/null +++ b/sdmap/src/sdmap/IsExternalInit.cs @@ -0,0 +1,8 @@ +// ReSharper disable CheckNamespace +// ReSharper disable UnusedType.Global + +namespace System.Runtime.CompilerServices; + +internal sealed class IsExternalInit +{ +} \ No newline at end of file diff --git a/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs b/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs new file mode 100644 index 0000000..a9eb05d --- /dev/null +++ b/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using System.Linq; + +namespace sdmap.Macros.Implements; + +internal readonly record struct PropertyMetadata(string Name, object Value, Type Type) +{ + public static PropertyMetadata Empty => new(string.Empty, default, typeof(object)); +} + +internal static class PropertyMetadataRetriever +{ + public static PropertyMetadata Get(object target, string propertyAccess) + { + if (string.IsNullOrWhiteSpace(propertyAccess)) + { + return PropertyMetadata.Empty; + } + + var properties = propertyAccess.Split('.'); + var value = properties.Aggregate(target, GetValueByKey); + return new(Name: properties.Last(), Value: value, Type: value?.GetType() ?? typeof(object)); + } + + private static object GetValueByKey(object target, string key) + => target switch + { + _ when string.IsNullOrWhiteSpace(key) + => default, + + IDictionary dictionary + => dictionary.Contains(key) + ? dictionary[key] + : default, + + not null + => GetValueOfMemberInfo(target, key), + + _ => default + }; + + private static object GetValueOfMemberInfo(object target, string memberName) + { + var type = target.GetType(); + + if (type.GetProperty(memberName) is { } property) + { + return property.GetValue(target); + } + + if (type.GetField(memberName) is { } field) + { + return field.GetValue(field); + } + + return default; + } +} \ No newline at end of file diff --git a/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs b/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs index 94e2ac9..ba362b9 100644 --- a/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs +++ b/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs @@ -445,59 +445,11 @@ public static QueryPropertyInfo GetProp(object self, object syntax) throw new ArgumentException("Variable is expected to be of type string.", nameof(syntax)); } - var (name, _, type) = GetPropertyMetadata(self, propertyAccess); + var (name, _, type) = PropertyMetadataRetriever.Get(self, propertyAccess); return new(name, type); } - public static object GetPropValue(object self, string prop) => GetPropertyMetadata(self, prop).Value; - - private static (string Name, object Value, Type Type) GetPropertyMetadata(object target, string propertyAccess) - { - if (string.IsNullOrWhiteSpace(propertyAccess)) - { - return (Name: propertyAccess, Value: default, Type: typeof(object)); - } - - var properties = propertyAccess.Split('.'); - var value = properties.Aggregate(target, GetValueByKey); - return (Name: properties.LastOrDefault(), Value: value, Type: value?.GetType() ?? typeof(object)); - - static object GetValueByKey(object target, string key) - { - return target switch - { - _ when string.IsNullOrWhiteSpace(key) - => default, - - IDictionary dictionary - => dictionary.Contains(key) - ? dictionary[key] - : default, - - not null - => GetValueOfMemberInfo(target, key), - - _ => default - }; - } - - static object GetValueOfMemberInfo(object target, string memberName) - { - var type = target.GetType(); - - if (type.GetProperty(memberName) is { } property) - { - return property.GetValue(target); - } - - if (type.GetField(memberName) is { } field) - { - return field.GetValue(field); - } - - return default; - } - } + public static object GetPropValue(object self, string prop) => PropertyMetadataRetriever.Get(self, prop).Value; public static bool IsEmpty(object v) { diff --git a/sdmap/test/sdmap.test/GetPropertyValueTests.cs b/sdmap/test/sdmap.test/GetPropertyValueTests.cs deleted file mode 100644 index 093c0a2..0000000 --- a/sdmap/test/sdmap.test/GetPropertyValueTests.cs +++ /dev/null @@ -1,246 +0,0 @@ -using System.Collections.Generic; -using sdmap.Macros.Implements; -using Xunit; - -// ReSharper disable UnusedAutoPropertyAccessor.Local - -namespace sdmap.test; - -public class GetPropertyValueTests -{ - [Fact] - public void NullObject_ReturnsNull() - { - var result = DynamicRuntimeMacros.GetPropValue(self: null, "Prop"); - Assert.Null(result); - } - - [Theory] - [InlineData(data: null)] - [InlineData("")] - [InlineData(" ")] - public void NullOrEmptyProp_ReturnsNull(string prop) - { - var obj = new ComplexClass { Prop = "Test" }; - var result = DynamicRuntimeMacros.GetPropValue(obj, prop); - Assert.Null(result); - } - - [Fact] - public void ValidProp_ReturnsValue() - { - var obj = new ComplexClass { Prop = "Test" }; - var result = DynamicRuntimeMacros.GetPropValue(obj, "Prop"); - Assert.Equal("Test", result); - } - - [Fact] - public void ValidField_ReturnsValue() - { - var obj = new ComplexClass { Field = "Test" }; - var result = DynamicRuntimeMacros.GetPropValue(obj, "Field"); - Assert.Equal("Test", result); - } - - [Fact] - public void NestedProp_ReturnsValue() - { - var obj = new ComplexClass - { - Prop = new ComplexClass - { - Prop = "NestedTest" - } - }; - var result = DynamicRuntimeMacros.GetPropValue( - obj, - "Prop.Prop" - ); - Assert.Equal("NestedTest", result); - } - - [Fact] - public void NestedPropAndField_ReturnsValue() - { - var obj = new ComplexClass - { - Prop = new ComplexClass - { - Field = "NestedTest" - } - }; - var result = DynamicRuntimeMacros.GetPropValue( - obj, - "Prop.Field" - ); - Assert.Equal("NestedTest", result); - } - - [Fact] - public void NonExistentProp_ReturnsNull() - { - var obj = new ComplexClass { Prop = "Test" }; - var result = DynamicRuntimeMacros.GetPropValue( - obj, - "NonExistent" - ); - Assert.Null(result); - } - - [Fact] - public void Dictionary_ReturnsValue() - { - var dictionary = new Dictionary - { - ["Key"] = "Value" - }; - var result = DynamicRuntimeMacros.GetPropValue(dictionary, "Key"); - Assert.Equal("Value", result); - } - - [Fact] - public void DictionaryNonExistentKey_ReturnsNull() - { - var dictionary = new Dictionary - { - ["Key"] = "Value" - }; - var result = DynamicRuntimeMacros.GetPropValue( - dictionary, - "NonExistentKey" - ); - Assert.Null(result); - } - - [Fact] - public void DictionaryWithNestedDictionary_ReturnsValue() - { - var nestedDictionary = new Dictionary { ["NestedKey"] = "NestedValue" }; - var dictionary = new Dictionary - { - ["Key"] = nestedDictionary - }; - var result = DynamicRuntimeMacros.GetPropValue( - dictionary, - "Key.NestedKey" - ); - Assert.Equal("NestedValue", result); - } - - [Fact] - public void ObjectWithNestedDictionary_ReturnsValue() - { - var obj = new ComplexClass - { - InnerDictionary = new() - { - ["DictionaryKey"] = "DictionaryValue" - } - }; - - var result = DynamicRuntimeMacros.GetPropValue( - obj, - "InnerDictionary.DictionaryKey" - ); - Assert.Equal("DictionaryValue", result); - } - - [Fact] - public void ObjectWithNestedDictionary_NonExistentKey_ReturnsNull() - { - var obj = new ComplexClass - { - InnerDictionary = new() - { - ["DictionaryKey"] = "DictionaryValue" - } - }; - - var result = DynamicRuntimeMacros.GetPropValue( - obj, - "InnerDictionary.NonExistentKey" - ); - Assert.Null(result); - } - - [Fact] - public void DictionaryWithNestedObject_ReturnsValue() - { - var nestedObj = new ComplexClass { Prop = "NestedObjectValue" }; - var dictionary = new Dictionary - { - ["ObjectKey"] = nestedObj - }; - - var result = DynamicRuntimeMacros.GetPropValue( - dictionary, - "ObjectKey.Prop" - ); - Assert.Equal("NestedObjectValue", result); - } - - [Fact] - public void - DictionaryWithNestedObject_NonExistentProperty_ReturnsNull() - { - var nestedObj = new ComplexClass { Prop = "NestedObjectValue" }; - var dictionary = new Dictionary - { - ["ObjectKey"] = nestedObj - }; - - var result = DynamicRuntimeMacros.GetPropValue( - dictionary, - "ObjectKey.NonExistentProp" - ); - Assert.Null(result); - } - - [Fact] - public void ObjectWithNestedDictionaryAndObject_ReturnsValue() - { - var nestedObj = new ComplexClass { Prop = "NestedObjectValue" }; - var obj = new ComplexClass - { - InnerDictionary = new() - { - ["NestedObjectKey"] = nestedObj - } - }; - - var result = DynamicRuntimeMacros.GetPropValue( - obj, - "InnerDictionary.NestedObjectKey.Prop" - ); - Assert.Equal("NestedObjectValue", result); - } - - [Fact] - public void DictionaryWithNestedObjectAndDictionary_ReturnsValue() - { - var nestedDictionary = new Dictionary - { - ["NestedDictionaryKey"] = "NestedDictionaryValue" - }; - var nestedObj = new ComplexClass { Prop = nestedDictionary }; - var dictionary = new Dictionary - { - ["NestedObjectKey"] = nestedObj - }; - - var result = DynamicRuntimeMacros.GetPropValue( - dictionary, - "NestedObjectKey.Prop.NestedDictionaryKey" - ); - Assert.Equal("NestedDictionaryValue", result); - } - - private sealed class ComplexClass - { - public Dictionary InnerDictionary { get; set; } - - public object Prop { get; set; } - - public object Field { get; set; } - } -} \ No newline at end of file diff --git a/sdmap/test/sdmap.test/PropertyMetadataRetrieverTests.cs b/sdmap/test/sdmap.test/PropertyMetadataRetrieverTests.cs new file mode 100644 index 0000000..3932382 --- /dev/null +++ b/sdmap/test/sdmap.test/PropertyMetadataRetrieverTests.cs @@ -0,0 +1,269 @@ +using System.Collections.Generic; +using FluentAssertions; +using sdmap.Macros.Implements; +using Xunit; + +// ReSharper disable UnusedAutoPropertyAccessor.Local + +namespace sdmap.test; + +public class PropertyMetadataRetrieverTests +{ + [Fact] + public void NullObject_ReturnsNull() + { + var (name, value, type) = PropertyMetadataRetriever.Get(target: null, "Prop"); + + name.Should().BeEmpty(); + value.Should().Be(null); + type.Should().Be(typeof(object)); + } + + [Theory] + [InlineData(data: null)] + [InlineData("")] + [InlineData(" ")] + public void NullOrEmptyProp_ReturnsNull(string propertyAccess) + { + var target = new ComplexObject { Prop = "Test" }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, propertyAccess); + + name.Should().BeEmpty(); + value.Should().Be(null); + type.Should().Be(typeof(object)); + } + + [Fact] + public void NonExistentProp_ReturnsNull() + { + var target = new ComplexObject { Prop = "Test" }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "NonExistent"); + + name.Should().BeEmpty(); + value.Should().Be(null); + type.Should().Be(typeof(object)); + } + + [Fact] + public void ValidProp_ReturnsValue() + { + var target = new ComplexObject { Prop = "Test" }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop"); + + name.Should().Be("Prop"); + value.Should().Be("Test"); + type.Should().Be(typeof(string)); + } + + [Fact] + public void ValidField_ReturnsValue() + { + var target = new ComplexObject { Field = "Test" }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "Field"); + + name.Should().Be("Field"); + value.Should().Be("Test"); + type.Should().Be(typeof(string)); + } + + [Fact] + public void NestedProp_ReturnsValue() + { + var target = new ComplexObject + { + Prop = new ComplexObject + { + Prop = "NestedTest" + } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop.Prop"); + + name.Should().Be("Prop"); + value.Should().Be("NestedTest"); + type.Should().Be(typeof(string)); + } + + [Fact] + public void NestedPropAndField_ReturnsValue() + { + var target = new ComplexObject + { + Prop = new ComplexObject + { + Field = "NestedTest" + } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop.Field"); + + name.Should().Be("Field"); + value.Should().Be("NestedTest"); + type.Should().Be(typeof(string)); + } + + [Fact] + public void Dictionary_ReturnsValue() + { + var target = new Dictionary + { + ["Key"] = "Value" + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "Key"); + + name.Should().Be("Key"); + value.Should().Be("Value"); + type.Should().Be(typeof(string)); + } + + [Fact] + public void DictionaryNonExistentKey_ReturnsNull() + { + var target = new Dictionary + { + ["Key"] = "Value" + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "NonExistentKey"); + + name.Should().BeEmpty(); + value.Should().Be(null); + type.Should().Be(typeof(object)); + } + + [Fact] + public void DictionaryWithNestedDictionary_ReturnsValue() + { + var target = new Dictionary + { + ["Key"] = new Dictionary { ["NestedKey"] = "NestedValue" } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "Key.NestedKey"); + + name.Should().Be("NestedKey"); + value.Should().Be("NestedValue"); + type.Should().Be(typeof(string)); + } + + [Fact] + public void ObjectWithNestedDictionary_ReturnsValue() + { + var target = new ComplexObject + { + Prop = new Dictionary + { + ["DictionaryKey"] = "DictionaryValue" + } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop.DictionaryKey"); + + name.Should().Be("DictionaryKey"); + value.Should().Be("DictionaryValue"); + type.Should().Be(typeof(string)); + } + + [Fact] + public void ObjectWithNestedDictionary_NonExistentKey_ReturnsNull() + { + var target = new ComplexObject + { + Prop = new Dictionary + { + ["DictionaryKey"] = "DictionaryValue" + } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop.NonExistentKey"); + + name.Should().BeEmpty(); + value.Should().Be(null); + type.Should().Be(typeof(object)); + } + + [Fact] + public void DictionaryWithNestedObject_ReturnsValue() + { + var target = new Dictionary + { + ["ObjectKey"] = new ComplexObject { Prop = new ComplexObject() } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "ObjectKey.Prop"); + + name.Should().Be("Prop"); + value.Should().BeEquivalentTo(new ComplexObject()); + type.Should().Be(typeof(ComplexObject)); + } + + [Fact] + public void DictionaryWithNestedObject_NonExistentProperty_ReturnsNull() + { + var target = new Dictionary + { + ["ObjectKey"] = new ComplexObject { Prop = "NestedObjectValue" } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "ObjectKey.NonExistentProp"); + + name.Should().BeEmpty(); + value.Should().Be(null); + type.Should().Be(typeof(object)); + } + + [Fact] + public void ObjectWithNestedDictionaryAndObject_ReturnsValue() + { + var target = new ComplexObject + { + Prop = new Dictionary + { + ["NestedObjectKey"] = new ComplexObject { Prop = "NestedObjectValue" } + } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get( + target, + "Prop.NestedObjectKey.Prop" + ); + + name.Should().Be("Prop"); + value.Should().Be("NestedObjectValue"); + type.Should().Be(typeof(string)); + } + + [Fact] + public void DictionaryWithNestedObjectAndDictionary_ReturnsValue() + { + var target = new Dictionary + { + ["NestedObjectKey"] = new ComplexObject + { + Prop = new Dictionary + { + ["NestedDictionaryKey"] = "NestedDictionaryValue" + } + } + }; + + var (name, value, type) = PropertyMetadataRetriever.Get(target, "NestedObjectKey.Prop.NestedDictionaryKey"); + + name.Should().Be("NestedDictionaryKey"); + value.Should().Be("NestedDictionaryValue"); + type.Should().Be(typeof(string)); + } + + private sealed record ComplexObject + { + public object Prop { get; set; } + + // ReSharper disable once NotAccessedField.Local + public object Field; + } +} \ No newline at end of file diff --git a/sdmap/test/sdmap.test/sdmap.test.csproj b/sdmap/test/sdmap.test/sdmap.test.csproj index 68ed873..991168a 100644 --- a/sdmap/test/sdmap.test/sdmap.test.csproj +++ b/sdmap/test/sdmap.test/sdmap.test.csproj @@ -5,6 +5,7 @@ + all From 46b719bbe866d92209fbd1f765d22441a2762371 Mon Sep 17 00:00:00 2001 From: zadykian Date: Sun, 29 Oct 2023 15:24:22 +0400 Subject: [PATCH 5/7] implementation of PropertyMetadataRetriever + unit tests --- .../Implements/PropertyMetadataRetriever.cs | 40 +++--- .../sdmap/Macros/Implements/RuntimeMacros.cs | 5 +- .../PropertyMetadataRetrieverTests.cs | 126 ++++++++---------- 3 files changed, 84 insertions(+), 87 deletions(-) diff --git a/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs b/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs index a9eb05d..ecf6a93 100644 --- a/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs +++ b/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs @@ -4,9 +4,15 @@ namespace sdmap.Macros.Implements; -internal readonly record struct PropertyMetadata(string Name, object Value, Type Type) +using static PropertyMetadata; + +internal readonly record struct PropertyMetadata(string Name, object Value, bool Exists = true) { - public static PropertyMetadata Empty => new(string.Empty, default, typeof(object)); + public Type Type => Value?.GetType() ?? typeof(object); + + public static PropertyMetadata DoesNotExist => new(string.Empty, default, false); + + public static PropertyMetadata Root(object value) => new(string.Empty, value); } internal static class PropertyMetadataRetriever @@ -15,45 +21,45 @@ public static PropertyMetadata Get(object target, string propertyAccess) { if (string.IsNullOrWhiteSpace(propertyAccess)) { - return PropertyMetadata.Empty; + return DoesNotExist; } - var properties = propertyAccess.Split('.'); - var value = properties.Aggregate(target, GetValueByKey); - return new(Name: properties.Last(), Value: value, Type: value?.GetType() ?? typeof(object)); + return propertyAccess + .Split('.') + .Aggregate(Root(target), (metadata, next) => GetByKey(metadata.Value, next)); } - - private static object GetValueByKey(object target, string key) + + private static PropertyMetadata GetByKey(object target, string key) => target switch { _ when string.IsNullOrWhiteSpace(key) - => default, + => DoesNotExist, IDictionary dictionary => dictionary.Contains(key) - ? dictionary[key] - : default, + ? new(key, dictionary[key]) + : DoesNotExist, not null - => GetValueOfMemberInfo(target, key), + => GetByMemberName(target, key), - _ => default + _ => DoesNotExist }; - private static object GetValueOfMemberInfo(object target, string memberName) + private static PropertyMetadata GetByMemberName(object target, string memberName) { var type = target.GetType(); if (type.GetProperty(memberName) is { } property) { - return property.GetValue(target); + return new(memberName, property.GetValue(target)); } if (type.GetField(memberName) is { } field) { - return field.GetValue(field); + return new(memberName, field.GetValue(field)); } - return default; + return DoesNotExist; } } \ No newline at end of file diff --git a/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs b/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs index ba362b9..003edc7 100644 --- a/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs +++ b/sdmap/src/sdmap/Macros/Implements/RuntimeMacros.cs @@ -4,7 +4,6 @@ using System; using System.Collections; using System.Linq; -using System.Reflection; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using System.Text; @@ -445,8 +444,8 @@ public static QueryPropertyInfo GetProp(object self, object syntax) throw new ArgumentException("Variable is expected to be of type string.", nameof(syntax)); } - var (name, _, type) = PropertyMetadataRetriever.Get(self, propertyAccess); - return new(name, type); + var metadata = PropertyMetadataRetriever.Get(self, propertyAccess); + return metadata.Exists ? new(metadata.Name, metadata.Type) : null; } public static object GetPropValue(object self, string prop) => PropertyMetadataRetriever.Get(self, prop).Value; diff --git a/sdmap/test/sdmap.test/PropertyMetadataRetrieverTests.cs b/sdmap/test/sdmap.test/PropertyMetadataRetrieverTests.cs index 3932382..266b22d 100644 --- a/sdmap/test/sdmap.test/PropertyMetadataRetrieverTests.cs +++ b/sdmap/test/sdmap.test/PropertyMetadataRetrieverTests.cs @@ -12,11 +12,9 @@ public class PropertyMetadataRetrieverTests [Fact] public void NullObject_ReturnsNull() { - var (name, value, type) = PropertyMetadataRetriever.Get(target: null, "Prop"); + var metadata = PropertyMetadataRetriever.Get(target: null, "Prop"); - name.Should().BeEmpty(); - value.Should().Be(null); - type.Should().Be(typeof(object)); + ShouldBeEmpty(metadata); } [Theory] @@ -27,11 +25,9 @@ public void NullOrEmptyProp_ReturnsNull(string propertyAccess) { var target = new ComplexObject { Prop = "Test" }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, propertyAccess); + var metadata = PropertyMetadataRetriever.Get(target, propertyAccess); - name.Should().BeEmpty(); - value.Should().Be(null); - type.Should().Be(typeof(object)); + ShouldBeEmpty(metadata); } [Fact] @@ -39,11 +35,9 @@ public void NonExistentProp_ReturnsNull() { var target = new ComplexObject { Prop = "Test" }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "NonExistent"); + var metadata = PropertyMetadataRetriever.Get(target, "NonExistent"); - name.Should().BeEmpty(); - value.Should().Be(null); - type.Should().Be(typeof(object)); + ShouldBeEmpty(metadata); } [Fact] @@ -51,11 +45,11 @@ public void ValidProp_ReturnsValue() { var target = new ComplexObject { Prop = "Test" }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop"); + var metadata = PropertyMetadataRetriever.Get(target, "Prop"); - name.Should().Be("Prop"); - value.Should().Be("Test"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("Prop"); + metadata.Value.Should().Be("Test"); + metadata.Type.Should().Be(typeof(string)); } [Fact] @@ -63,11 +57,11 @@ public void ValidField_ReturnsValue() { var target = new ComplexObject { Field = "Test" }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "Field"); + var metadata = PropertyMetadataRetriever.Get(target, "Field"); - name.Should().Be("Field"); - value.Should().Be("Test"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("Field"); + metadata.Value.Should().Be("Test"); + metadata.Type.Should().Be(typeof(string)); } [Fact] @@ -81,11 +75,11 @@ public void NestedProp_ReturnsValue() } }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop.Prop"); + var metadata = PropertyMetadataRetriever.Get(target, "Prop.Prop"); - name.Should().Be("Prop"); - value.Should().Be("NestedTest"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("Prop"); + metadata.Value.Should().Be("NestedTest"); + metadata.Type.Should().Be(typeof(string)); } [Fact] @@ -99,11 +93,11 @@ public void NestedPropAndField_ReturnsValue() } }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop.Field"); + var metadata = PropertyMetadataRetriever.Get(target, "Prop.Field"); - name.Should().Be("Field"); - value.Should().Be("NestedTest"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("Field"); + metadata.Value.Should().Be("NestedTest"); + metadata.Type.Should().Be(typeof(string)); } [Fact] @@ -114,11 +108,11 @@ public void Dictionary_ReturnsValue() ["Key"] = "Value" }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "Key"); + var metadata = PropertyMetadataRetriever.Get(target, "Key"); - name.Should().Be("Key"); - value.Should().Be("Value"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("Key"); + metadata.Value.Should().Be("Value"); + metadata.Type.Should().Be(typeof(string)); } [Fact] @@ -129,11 +123,9 @@ public void DictionaryNonExistentKey_ReturnsNull() ["Key"] = "Value" }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "NonExistentKey"); + var metadata = PropertyMetadataRetriever.Get(target, "NonExistentKey"); - name.Should().BeEmpty(); - value.Should().Be(null); - type.Should().Be(typeof(object)); + ShouldBeEmpty(metadata); } [Fact] @@ -144,11 +136,11 @@ public void DictionaryWithNestedDictionary_ReturnsValue() ["Key"] = new Dictionary { ["NestedKey"] = "NestedValue" } }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "Key.NestedKey"); + var metadata = PropertyMetadataRetriever.Get(target, "Key.NestedKey"); - name.Should().Be("NestedKey"); - value.Should().Be("NestedValue"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("NestedKey"); + metadata.Value.Should().Be("NestedValue"); + metadata.Type.Should().Be(typeof(string)); } [Fact] @@ -162,11 +154,11 @@ public void ObjectWithNestedDictionary_ReturnsValue() } }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop.DictionaryKey"); + var metadata = PropertyMetadataRetriever.Get(target, "Prop.DictionaryKey"); - name.Should().Be("DictionaryKey"); - value.Should().Be("DictionaryValue"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("DictionaryKey"); + metadata.Value.Should().Be("DictionaryValue"); + metadata.Type.Should().Be(typeof(string)); } [Fact] @@ -180,11 +172,9 @@ public void ObjectWithNestedDictionary_NonExistentKey_ReturnsNull() } }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "Prop.NonExistentKey"); + var metadata = PropertyMetadataRetriever.Get(target, "Prop.NonExistentKey"); - name.Should().BeEmpty(); - value.Should().Be(null); - type.Should().Be(typeof(object)); + ShouldBeEmpty(metadata); } [Fact] @@ -195,11 +185,11 @@ public void DictionaryWithNestedObject_ReturnsValue() ["ObjectKey"] = new ComplexObject { Prop = new ComplexObject() } }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "ObjectKey.Prop"); + var metadata = PropertyMetadataRetriever.Get(target, "ObjectKey.Prop"); - name.Should().Be("Prop"); - value.Should().BeEquivalentTo(new ComplexObject()); - type.Should().Be(typeof(ComplexObject)); + metadata.Name.Should().Be("Prop"); + metadata.Value.Should().BeEquivalentTo(new ComplexObject()); + metadata.Type.Should().Be(typeof(ComplexObject)); } [Fact] @@ -210,11 +200,9 @@ public void DictionaryWithNestedObject_NonExistentProperty_ReturnsNull() ["ObjectKey"] = new ComplexObject { Prop = "NestedObjectValue" } }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "ObjectKey.NonExistentProp"); + var metadata = PropertyMetadataRetriever.Get(target, "ObjectKey.NonExistentProp"); - name.Should().BeEmpty(); - value.Should().Be(null); - type.Should().Be(typeof(object)); + ShouldBeEmpty(metadata); } [Fact] @@ -228,14 +216,11 @@ public void ObjectWithNestedDictionaryAndObject_ReturnsValue() } }; - var (name, value, type) = PropertyMetadataRetriever.Get( - target, - "Prop.NestedObjectKey.Prop" - ); + var metadata = PropertyMetadataRetriever.Get(target, "Prop.NestedObjectKey.Prop"); - name.Should().Be("Prop"); - value.Should().Be("NestedObjectValue"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("Prop"); + metadata.Value.Should().Be("NestedObjectValue"); + metadata.Type.Should().Be(typeof(string)); } [Fact] @@ -252,11 +237,18 @@ public void DictionaryWithNestedObjectAndDictionary_ReturnsValue() } }; - var (name, value, type) = PropertyMetadataRetriever.Get(target, "NestedObjectKey.Prop.NestedDictionaryKey"); + var metadata = PropertyMetadataRetriever.Get(target, "NestedObjectKey.Prop.NestedDictionaryKey"); - name.Should().Be("NestedDictionaryKey"); - value.Should().Be("NestedDictionaryValue"); - type.Should().Be(typeof(string)); + metadata.Name.Should().Be("NestedDictionaryKey"); + metadata.Value.Should().Be("NestedDictionaryValue"); + metadata.Type.Should().Be(typeof(string)); + } + + private static void ShouldBeEmpty(PropertyMetadata metadata) + { + metadata.Name.Should().BeEmpty(); + metadata.Value.Should().Be(null); + metadata.Type.Should().Be(typeof(object)); } private sealed record ComplexObject From aa8208e8a3b91329b1ddfd26d0ae028340499f3f Mon Sep 17 00:00:00 2001 From: zadykian Date: Sun, 29 Oct 2023 15:26:20 +0400 Subject: [PATCH 6/7] implementation of PropertyMetadataRetriever + unit tests --- sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs b/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs index ecf6a93..63ad896 100644 --- a/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs +++ b/sdmap/src/sdmap/Macros/Implements/PropertyMetadataRetriever.cs @@ -57,7 +57,7 @@ private static PropertyMetadata GetByMemberName(object target, string memberName if (type.GetField(memberName) is { } field) { - return new(memberName, field.GetValue(field)); + return new(memberName, field.GetValue(target)); } return DoesNotExist; From c18a63a49dabe05aa8c80bb63ddf1f56ff312ae8 Mon Sep 17 00:00:00 2001 From: zadykian Date: Sun, 29 Oct 2023 15:58:55 +0400 Subject: [PATCH 7/7] Common.Version.props --- sdmap/Common.Version.props | 14 ++++++++++++++ sdmap/sdmap.sln | 1 + sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj | 5 ++--- sdmap/src/sdmap.ext/sdmap.ext.csproj | 5 ++--- sdmap/src/sdmap/sdmap.csproj | 5 ++--- 5 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 sdmap/Common.Version.props diff --git a/sdmap/Common.Version.props b/sdmap/Common.Version.props new file mode 100644 index 0000000..702704d --- /dev/null +++ b/sdmap/Common.Version.props @@ -0,0 +1,14 @@ + + + + 0.17.0 + + + + $(Version) + $(Version) + $(Version) + $(Version) + + + diff --git a/sdmap/sdmap.sln b/sdmap/sdmap.sln index 2e5d55f..5c13963 100644 --- a/sdmap/sdmap.sln +++ b/sdmap/sdmap.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\README.md = ..\README.md ..\ReleaseNotes.md = ..\ReleaseNotes.md vstool.png = vstool.png + Common.Version.props = Common.Version.props EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{37A082F1-8179-4EEA-93D8-1C282B5AC65A}" diff --git a/sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj b/sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj index 96f42c0..8b87e65 100644 --- a/sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj +++ b/sdmap/src/sdmap.ext.Dapper/sdmap.ext.Dapper.csproj @@ -1,5 +1,7 @@  + + net6.0;netstandard20 sdmap.ext.Dapper @@ -14,13 +16,10 @@ https://github.com/sdcb/sdmap/blob/master/ReleaseNotes.md false false false - 0.16.6 Dapper extensions for sdmap. https://github.com/sdcb/sdmap sdcb MIT - 0.16.6 - 0.16.6 LICENSE true true diff --git a/sdmap/src/sdmap.ext/sdmap.ext.csproj b/sdmap/src/sdmap.ext/sdmap.ext.csproj index cf37935..b3d61cc 100644 --- a/sdmap/src/sdmap.ext/sdmap.ext.csproj +++ b/sdmap/src/sdmap.ext/sdmap.ext.csproj @@ -1,5 +1,7 @@  + + net6.0;netstandard20 sdmap.ext @@ -14,13 +16,10 @@ https://github.com/sdcb/sdmap/blob/master/ReleaseNotes.md false false false - 0.16.6 Useful extensions for sdmap/Dapper. https://github.com/sdcb/sdmap sdcb MIT - 0.16.6 - 0.16.6 LICENSE true true diff --git a/sdmap/src/sdmap/sdmap.csproj b/sdmap/src/sdmap/sdmap.csproj index 367c48b..f85af39 100644 --- a/sdmap/src/sdmap/sdmap.csproj +++ b/sdmap/src/sdmap/sdmap.csproj @@ -1,5 +1,7 @@  + + A template engine for writing dynamic sql. net6;netstandard20 @@ -15,9 +17,6 @@ false false false - 0.16.6 - 0.16.6 - 0.16.6 sdcb MIT https://github.com/sdcb/sdmap