From 63c20392ad8601fc4c75555bcd23f6018be65619 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Fri, 17 Mar 2023 11:41:27 +0100 Subject: [PATCH 1/5] Refactors --- .../Test/ScenarioDataImportTest.ipynb | 6 ++-- .../Test/ScenarioYieldCurveImportTest.ipynb | 6 ++-- ifrs17/Constants/Consts.ipynb | 34 ++++--------------- ifrs17/Import/Importers.ipynb | 2 +- ifrs17/Report/ReportMutableScopes.ipynb | 6 ++-- 5 files changed, 16 insertions(+), 38 deletions(-) diff --git a/ifrs17-template/Test/ScenarioDataImportTest.ipynb b/ifrs17-template/Test/ScenarioDataImportTest.ipynb index 3c558fcd..3f70eeb1 100644 --- a/ifrs17-template/Test/ScenarioDataImportTest.ipynb +++ b/ifrs17-template/Test/ScenarioDataImportTest.ipynb @@ -55,7 +55,7 @@ { "cell_type": "code", "source": [ - "var EnableScenarioBackup = EnableScenario;" + "var EnableScenarioBackup = Scenarios.EnableScenario;" ], "metadata": {}, "execution_count": 0, @@ -64,7 +64,7 @@ { "cell_type": "code", "source": [ - "EnableScenario = true;" + "Scenarios.EnableScenario = true;" ], "metadata": {}, "execution_count": 0, @@ -948,7 +948,7 @@ { "cell_type": "code", "source": [ - "EnableScenario = EnableScenarioBackup;" + "Scenarios.EnableScenario = EnableScenarioBackup;" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17-template/Test/ScenarioYieldCurveImportTest.ipynb b/ifrs17-template/Test/ScenarioYieldCurveImportTest.ipynb index 5e870b40..4e0ebf53 100644 --- a/ifrs17-template/Test/ScenarioYieldCurveImportTest.ipynb +++ b/ifrs17-template/Test/ScenarioYieldCurveImportTest.ipynb @@ -55,7 +55,7 @@ { "cell_type": "code", "source": [ - "var EnableScenarioBackup = EnableScenario;" + "var EnableScenarioBackup = Scenarios.EnableScenario;" ], "metadata": {}, "execution_count": 0, @@ -64,7 +64,7 @@ { "cell_type": "code", "source": [ - "EnableScenario = true;" + "Scenarios.EnableScenario = true;" ], "metadata": {}, "execution_count": 0, @@ -724,7 +724,7 @@ { "cell_type": "code", "source": [ - "EnableScenario = EnableScenarioBackup;" + "Scenarios.EnableScenario = EnableScenarioBackup;" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Constants/Consts.ipynb b/ifrs17/Constants/Consts.ipynb index b3889647..d3077e10 100644 --- a/ifrs17/Constants/Consts.ipynb +++ b/ifrs17/Constants/Consts.ipynb @@ -383,34 +383,12 @@ { "cell_type": "code", "source": [ - "public bool EnableScenario = false;" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public const string ScenarioDefault = \"Best Estimate\";" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public const string ScenariosAll = \"All\";" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public const string ScenariosDelta = \"Delta\";" + "public static class Scenarios{", + "\n public static bool EnableScenario = false;", + "\n public const string Default = \"Best Estimate\";", + "\n public const string All = nameof(All);", + "\n public const string Delta = nameof(Delta);", + "\n}" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 9c4db10f..b78451ff 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -538,7 +538,7 @@ "\n break;", "\n }", "\n }", - "\n return allArgs.Where(x => (!EnableScenario && x.Scenario == null) || EnableScenario).ToArray();", + "\n return allArgs.Where(x => (!Scenarios.EnableScenario && x.Scenario == null) || Scenarios.EnableScenario).ToArray();", "\n}" ], "metadata": {}, diff --git a/ifrs17/Report/ReportMutableScopes.ipynb b/ifrs17/Report/ReportMutableScopes.ipynb index f6cb212f..d77923d7 100644 --- a/ifrs17/Report/ReportMutableScopes.ipynb +++ b/ifrs17/Report/ReportMutableScopes.ipynb @@ -295,10 +295,10 @@ "\n IDataCube Cube { get{", "\n var data = GetScope(Identity.reportType).GetDataCube();", "\n // TODO: suggestion to place the filter here instead of having it in every applicability scope", - "\n if(Identity.scenario != ScenariosAll && Identity.scenario != ScenariosDelta) return data;", - "\n if(Identity.scenario == ScenariosAll) return data.Select(x => x.Scenario == null? x with {Scenario = ScenarioDefault } : x).ToDataCube();", + "\n if(Identity.scenario != Scenarios.All && Identity.scenario != Scenarios.Delta) return data;", + "\n if(Identity.scenario == Scenarios.All) return data.Select(x => x.Scenario == null? x with {Scenario = Scenarios.Default } : x).ToDataCube();", "\n var bestEstimateById = data.Where(x => x.Scenario == null).ToDictionary(x => x.ToIdentityString());", - "\n return data.Select(x => x.Scenario == null ? x with { Scenario = ScenarioDefault } ", + "\n return data.Select(x => x.Scenario == null ? x with { Scenario = Scenarios.Default } ", "\n : x with { Value = x.Value - (bestEstimateById.TryGetValue((x with {Scenario = null}).ToIdentityString(), out var be)? be.Value : 0.0) }).ToDataCube();", "\n }}", "\n} " From da3f8ff1e39e429c58075f57028e2647e8520c15 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Fri, 17 Mar 2023 12:02:39 +0100 Subject: [PATCH 2/5] Replacing ToIdentityString with the ToStringWith. --- ifrs17/Report/ReportMutableScopes.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ifrs17/Report/ReportMutableScopes.ipynb b/ifrs17/Report/ReportMutableScopes.ipynb index d77923d7..41315510 100644 --- a/ifrs17/Report/ReportMutableScopes.ipynb +++ b/ifrs17/Report/ReportMutableScopes.ipynb @@ -297,7 +297,8 @@ "\n // TODO: suggestion to place the filter here instead of having it in every applicability scope", "\n if(Identity.scenario != Scenarios.All && Identity.scenario != Scenarios.Delta) return data;", "\n if(Identity.scenario == Scenarios.All) return data.Select(x => x.Scenario == null? x with {Scenario = Scenarios.Default } : x).ToDataCube();", - "\n var bestEstimateById = data.Where(x => x.Scenario == null).ToDictionary(x => x.ToIdentityString());", + "\n var identityProperties = typeof(ReportVariable).GetIdentityProperties().Select(x=>x.Name).ToArray();", + "\n var bestEstimateById = data.Where(x => x.Scenario == null).ToDictionary(x => x.ToStringWith(identityProperties));", "\n return data.Select(x => x.Scenario == null ? x with { Scenario = Scenarios.Default } ", "\n : x with { Value = x.Value - (bestEstimateById.TryGetValue((x with {Scenario = null}).ToIdentityString(), out var be)? be.Value : 0.0) }).ToDataCube();", "\n }}", From c8582543b1561c985d065d5f657372b96defdbf5 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Fri, 17 Mar 2023 14:20:14 +0100 Subject: [PATCH 3/5] Renaming the method ToStringWith --- ifrs17/Import/Importers.ipynb | 2 +- ifrs17/Report/ReportMutableScopes.ipynb | 2 +- ifrs17/Utils/Extensions.ipynb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index b78451ff..78a50a43 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -667,7 +667,7 @@ "\n var excludedProperties = new[]{nameof(AocType), nameof(Novelty)};", "\n var includingProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Except(excludedProperties).ToArray();", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", - "\n .GroupBy(x => x.ToStringWith(properties: includingProperties),", + "\n .GroupBy(x => x.RecordToStringWith(properties: includingProperties),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, parsedAocSteps) => (properties, mandatoryAocSteps.Except(parsedAocSteps))", "\n );", diff --git a/ifrs17/Report/ReportMutableScopes.ipynb b/ifrs17/Report/ReportMutableScopes.ipynb index 41315510..a8fc0bc8 100644 --- a/ifrs17/Report/ReportMutableScopes.ipynb +++ b/ifrs17/Report/ReportMutableScopes.ipynb @@ -298,7 +298,7 @@ "\n if(Identity.scenario != Scenarios.All && Identity.scenario != Scenarios.Delta) return data;", "\n if(Identity.scenario == Scenarios.All) return data.Select(x => x.Scenario == null? x with {Scenario = Scenarios.Default } : x).ToDataCube();", "\n var identityProperties = typeof(ReportVariable).GetIdentityProperties().Select(x=>x.Name).ToArray();", - "\n var bestEstimateById = data.Where(x => x.Scenario == null).ToDictionary(x => x.ToStringWith(identityProperties));", + "\n var bestEstimateById = data.Where(x => x.Scenario == null).ToDictionary(x => x.RecordToStringWith(properties: identityProperties));", "\n return data.Select(x => x.Scenario == null ? x with { Scenario = Scenarios.Default } ", "\n : x with { Value = x.Value - (bestEstimateById.TryGetValue((x with {Scenario = null}).ToIdentityString(), out var be)? be.Value : 0.0) }).ToDataCube();", "\n }}", diff --git a/ifrs17/Utils/Extensions.ipynb b/ifrs17/Utils/Extensions.ipynb index dec7c53d..3b6fcc4c 100644 --- a/ifrs17/Utils/Extensions.ipynb +++ b/ifrs17/Utils/Extensions.ipynb @@ -236,7 +236,7 @@ { "cell_type": "code", "source": [ - "public static string ToStringWith(this T variable, string[] properties) where T : BaseVariableIdentity", + "public static string RecordToStringWith(this T variable, string[] properties) where T : class", "\n{", "\n var propertiesRead = variable.ToString().Split('{', '}')[1].Split(',');", "\n var propertiesFiltered = propertiesRead.Where(x=> properties.Contains(x.Split('=')[0].Trim()));", From fe61e88c5ecd028b06d08a3938b042ee133d3ec6 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Fri, 17 Mar 2023 17:12:20 +0100 Subject: [PATCH 4/5] Adding IdentityPropertyReader and adapting the code --- ifrs17/Import/Importers.ipynb | 5 ++--- ifrs17/Report/ReportMutableScopes.ipynb | 3 +-- ifrs17/Utils/Extensions.ipynb | 21 ++++++++------------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 78a50a43..2a3a5dfc 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -664,10 +664,9 @@ "using static Systemorph.Vertex.Equality.IdentityPropertyExtensions;", "\npublic async static Task ValidateForMandatoryAocSteps(this IWorkspace workspace, IDataSet dataSet, HashSet mandatoryAocSteps)", "\n{ ", - "\n var excludedProperties = new[]{nameof(AocType), nameof(Novelty)};", - "\n var includingProperties = typeof(RawVariable).GetIdentityProperties().Select(x=>x.Name).Except(excludedProperties).ToArray();", + "\n var ignoreProperties = new[]{nameof(AocType), nameof(Novelty)};", "\n var missingAocStepsByIdentityProperties = (await workspace.Query().ToListAsync())", - "\n .GroupBy(x => x.RecordToStringWith(properties: includingProperties),", + "\n .GroupBy(x => x.ToIdentityString(ignoreProperties),", "\n x => new AocStep(x.AocType, x.Novelty),", "\n (properties, parsedAocSteps) => (properties, mandatoryAocSteps.Except(parsedAocSteps))", "\n );", diff --git a/ifrs17/Report/ReportMutableScopes.ipynb b/ifrs17/Report/ReportMutableScopes.ipynb index a8fc0bc8..d77923d7 100644 --- a/ifrs17/Report/ReportMutableScopes.ipynb +++ b/ifrs17/Report/ReportMutableScopes.ipynb @@ -297,8 +297,7 @@ "\n // TODO: suggestion to place the filter here instead of having it in every applicability scope", "\n if(Identity.scenario != Scenarios.All && Identity.scenario != Scenarios.Delta) return data;", "\n if(Identity.scenario == Scenarios.All) return data.Select(x => x.Scenario == null? x with {Scenario = Scenarios.Default } : x).ToDataCube();", - "\n var identityProperties = typeof(ReportVariable).GetIdentityProperties().Select(x=>x.Name).ToArray();", - "\n var bestEstimateById = data.Where(x => x.Scenario == null).ToDictionary(x => x.RecordToStringWith(properties: identityProperties));", + "\n var bestEstimateById = data.Where(x => x.Scenario == null).ToDictionary(x => x.ToIdentityString());", "\n return data.Select(x => x.Scenario == null ? x with { Scenario = Scenarios.Default } ", "\n : x with { Value = x.Value - (bestEstimateById.TryGetValue((x with {Scenario = null}).ToIdentityString(), out var be)? be.Value : 0.0) }).ToDataCube();", "\n }}", diff --git a/ifrs17/Utils/Extensions.ipynb b/ifrs17/Utils/Extensions.ipynb index 3b6fcc4c..e111ea6e 100644 --- a/ifrs17/Utils/Extensions.ipynb +++ b/ifrs17/Utils/Extensions.ipynb @@ -199,7 +199,7 @@ { "cell_type": "markdown", "source": [ - "# ToIdentityString" + "# Identity property reader" ], "metadata": {}, "execution_count": 0, @@ -208,16 +208,10 @@ { "cell_type": "code", "source": [ - "using System.Text;", - "\npublic static string ToIdentityString(this T v, params string[] excludingProperties) where T : class", + "using static Systemorph.Vertex.Equality.IdentityPropertyExtensions;", + "\npublic static class IdentityPropertyReader where T : class ", "\n{", - "\n StringBuilder sb = new StringBuilder();", - "\n var propertyInfos = v.GetType()", - "\n .GetProperties()", - "\n .Where(x => Attribute.IsDefined(x, typeof(IdentityPropertyAttribute)) && !excludingProperties.Contains(x.Name))", - "\n .OrderByDescending(x => x.PropertyType.Name).ThenByDescending(x => x.Name)", - "\n .Select(x => sb.Append(x.Name).Append(\":\").Append(v.GetType().GetProperty(x.Name)?.GetValue(v, null)).Append(\", \")).ToArray();", - "\n return propertyInfos.Count() == 0? v.ToString() : propertyInfos.Select(p => p.ToString()).ToArray().Last();", + "\n public static string[] IdentityProperties = typeof(T).GetIdentityProperties().Select(x => x.Name).ToArray();", "\n}" ], "metadata": {}, @@ -227,7 +221,7 @@ { "cell_type": "markdown", "source": [ - "# ToString with including properties" + "# ToString with excluding properties" ], "metadata": {}, "execution_count": 0, @@ -236,10 +230,11 @@ { "cell_type": "code", "source": [ - "public static string RecordToStringWith(this T variable, string[] properties) where T : class", + "public static string ToIdentityString(this T variable, string[] ignoreProperties = null) where T : class", "\n{", + "\n if (ignoreProperties == null) ignoreProperties = new string[0];", "\n var propertiesRead = variable.ToString().Split('{', '}')[1].Split(',');", - "\n var propertiesFiltered = propertiesRead.Where(x=> properties.Contains(x.Split('=')[0].Trim()));", + "\n var propertiesFiltered = propertiesRead.Where(x => IdentityPropertyReader.IdentityProperties.Except(ignoreProperties).Contains(x.Split('=')[0].Trim()));", "\n return string.Join(\", \", propertiesFiltered).Trim();", "\n}" ], From ea08d66ec6ffc1edb09e2221177a25d30724b7b3 Mon Sep 17 00:00:00 2001 From: Teo Kukuljan Date: Mon, 20 Mar 2023 12:43:54 +0100 Subject: [PATCH 5/5] IdentityPropertyReader with Expressions --- ifrs17/Utils/Extensions.ipynb | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/ifrs17/Utils/Extensions.ipynb b/ifrs17/Utils/Extensions.ipynb index e111ea6e..c3587cec 100644 --- a/ifrs17/Utils/Extensions.ipynb +++ b/ifrs17/Utils/Extensions.ipynb @@ -209,9 +209,29 @@ "cell_type": "code", "source": [ "using static Systemorph.Vertex.Equality.IdentityPropertyExtensions;", - "\npublic static class IdentityPropertyReader where T : class ", - "\n{", - "\n public static string[] IdentityProperties = typeof(T).GetIdentityProperties().Select(x => x.Name).ToArray();", + "\nusing System.Linq.Expressions;", + "\npublic static class IdentityReader where T : class {", + "\n private static Dictionary> ExpressionsByExcludedProperties = new();", + "\n public static string Concat(string first, string second) => first + \" \" + second;", + "\n public static string GetString(Object item) => (item == null) ? \"\" : item.ToString();", + "\n", + "\n private static Func GetToIdentityExpression(string[] excludedProperties) {", + "\n var pm = Expression.Parameter(typeof(T));", + "\n var expression = typeof(T).GetIdentityProperties().Where(x => !excludedProperties.Contains(x.Name))", + "\n .SelectMany(x => new Expression[]{ Expression.Constant(x.Name.ToString()+\":\"),", + "\n Expression.Call(typeof(IdentityReader).GetMethod(nameof(GetString)), Expression.Convert(Expression.Property(pm, x.Name), typeof(Object))) }", + "\n ).Aggregate((x, y) => Expression.Call(typeof(IdentityReader).GetMethod(nameof(IdentityReader.Concat)), x, y));", + "\n return Expression.Lambda>(expression, pm).Compile();", + "\n }", + "\n", + "\n public static string ToString(T x, string[] excludedProperties) {", + "\n var key = string.Join(\",\", excludedProperties.OrderBy(x => x));", + "\n if(!ExpressionsByExcludedProperties.TryGetValue(key, out var expression)) {", + "\n ExpressionsByExcludedProperties[key] = GetToIdentityExpression(excludedProperties);", + "\n return ExpressionsByExcludedProperties[key](x);", + "\n }", + "\n return expression(x);", + "\n }", "\n}" ], "metadata": {}, @@ -233,9 +253,7 @@ "public static string ToIdentityString(this T variable, string[] ignoreProperties = null) where T : class", "\n{", "\n if (ignoreProperties == null) ignoreProperties = new string[0];", - "\n var propertiesRead = variable.ToString().Split('{', '}')[1].Split(',');", - "\n var propertiesFiltered = propertiesRead.Where(x => IdentityPropertyReader.IdentityProperties.Except(ignoreProperties).Contains(x.Split('=')[0].Trim()));", - "\n return string.Join(\", \", propertiesFiltered).Trim();", + "\n return IdentityReader.ToString(variable, ignoreProperties);", "\n}" ], "metadata": {},