NpgsqlHstoreTypeMapping.cs 2.8 KB
Newer Older
1
using System.Collections.Generic;
S
Shay Rojansky 已提交
2
using System.Text;
3
using Microsoft.EntityFrameworkCore.ChangeTracking;
S
Shay Rojansky 已提交
4
using Microsoft.EntityFrameworkCore.Storage;
S
Shay Rojansky 已提交
5 6
using NpgsqlTypes;

7
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping
S
Shay Rojansky 已提交
8
{
9 10 11 12 13 14
    /// <summary>
    /// The type mapping for the PostgreSQL hstore type.
    /// </summary>
    /// <remarks>
    /// See: https://www.postgresql.org/docs/current/static/hstore.html
    /// </remarks>
S
Shay Rojansky 已提交
15 16
    public class NpgsqlHstoreTypeMapping : NpgsqlTypeMapping
    {
17 18
        static readonly HstoreComparer ComparerInstance = new HstoreComparer();

19 20 21
        /// <summary>
        /// Constructs an instance of the <see cref="NpgsqlHstoreTypeMapping"/> class.
        /// </summary>
22
        public NpgsqlHstoreTypeMapping()
S
Shay Rojansky 已提交
23 24 25 26 27 28
            : base(
                new RelationalTypeMappingParameters(
                    new CoreTypeMappingParameters(typeof(Dictionary<string, string>), null, ComparerInstance),
                    "hstore"
                ), NpgsqlDbType.Hstore) {}

29 30
        protected NpgsqlHstoreTypeMapping(RelationalTypeMappingParameters parameters)
            : base(parameters, NpgsqlDbType.Hstore) {}
S
Shay Rojansky 已提交
31

32 33
        protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
            => new NpgsqlHstoreTypeMapping(parameters);
S
Shay Rojansky 已提交
34 35 36

        protected override string GenerateNonNullSqlLiteral(object value)
        {
S
Shay Rojansky 已提交
37
            var sb = new StringBuilder("HSTORE '");
S
Shay Rojansky 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
            foreach (var kv in (Dictionary<string, string>)value)
            {
                sb.Append('"');
                sb.Append(kv.Key);   // TODO: Escape
                sb.Append("\"=>");
                if (kv.Value == null)
                    sb.Append("NULL");
                else
                {
                    sb.Append('"');
                    sb.Append(kv.Value);   // TODO: Escape
                    sb.Append("\",");
                }
            }

            sb.Remove(sb.Length - 1, 1);

S
Shay Rojansky 已提交
55
            sb.Append('\'');
S
Shay Rojansky 已提交
56 57
            return sb.ToString();
        }
58 59 60 61 62

        class HstoreComparer : ValueComparer<Dictionary<string, string>>
        {
            public HstoreComparer() : base(
                (a, b) => Compare(a,b),
63 64
                o => o.GetHashCode(),
                o => o == null ? null : new Dictionary<string, string>(o))
65 66 67 68
            {}

            static bool Compare(Dictionary<string, string> a, Dictionary<string, string> b)
            {
S
Shay Rojansky 已提交
69 70 71 72
                if (a == null)
                    return b == null;
                if (b == null)
                    return false;
73 74 75 76 77 78 79 80
                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;
            }
        }
S
Shay Rojansky 已提交
81 82
    }
}