From 42e4544d795fbaf448edcaf9d7048ba7c3496f38 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 27 Feb 2018 11:57:54 +0200 Subject: [PATCH] Implement value comparer for hstore Closes #306 --- .../Mapping/NpgsqlHstoreTypeMapping.cs | 30 ++++++++++++++++++- .../Storage/NpgsqlTypeMappingTest.cs | 17 +++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlHstoreTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlHstoreTypeMapping.cs index 223aba284..a21eb1741 100644 --- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlHstoreTypeMapping.cs +++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlHstoreTypeMapping.cs @@ -1,14 +1,21 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; using System.Net.NetworkInformation; using System.Text; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using NpgsqlTypes; namespace Microsoft.EntityFrameworkCore.Storage.Internal.Mapping { public class NpgsqlHstoreTypeMapping : NpgsqlTypeMapping { - public NpgsqlHstoreTypeMapping() : base("hstore", typeof(Dictionary), NpgsqlDbType.Hstore) {} + static readonly HstoreComparer ComparerInstance = new HstoreComparer(); + + public NpgsqlHstoreTypeMapping() + : base("hstore", typeof(Dictionary), null, ComparerInstance, NpgsqlDbType.Hstore) {} protected override string GenerateNonNullSqlLiteral(object value) { @@ -33,5 +40,26 @@ protected override string GenerateNonNullSqlLiteral(object value) sb.Append('\''); return sb.ToString(); } + + class HstoreComparer : ValueComparer> + { + public HstoreComparer() : base( + (a, b) => Compare(a,b), + source => Snapshot(source)) + {} + + static bool Compare(Dictionary a, Dictionary b) + { + if (a.Count != b.Count) + return false; + foreach (var kv in a) + if (!b.TryGetValue(kv.Key, out var bValue) || kv.Value != bValue) + return false; + return true; + } + + static Dictionary Snapshot(Dictionary source) + => new Dictionary(source); + } } } diff --git a/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingTest.cs b/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingTest.cs index e516f1b42..5b87cb87d 100644 --- a/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingTest.cs +++ b/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingTest.cs @@ -176,6 +176,23 @@ public void GenerateSqlLiteral_returns_hstore_literal() { "k2", "v2" } })); + [Fact] + public void ValueComparer_hstore() + { + var source = new Dictionary + { + { "k1", "v1"}, + { "k2", "v2"} + }; + + var comparer = GetMapping("hstore").Comparer; + var snapshot = (Dictionary)comparer.SnapshotFunc(source); + Assert.Equal(source, snapshot); + Assert.True(comparer.CompareFunc(source, snapshot)); + snapshot.Remove("k1"); + Assert.False(comparer.CompareFunc(source, snapshot)); + } + [Fact] public void GenerateSqlLiteral_returns_jsonb_literal() => Assert.Equal(@"JSONB '{""a"":1}'", GetMapping("jsonb").GenerateSqlLiteral(@"{""a"":1}"));