using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Storage;
using NpgsqlTypes;
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping
{
///
/// The type mapping for the PostgreSQL hstore type.
///
///
/// See: https://www.postgresql.org/docs/current/static/hstore.html
///
public class NpgsqlHstoreTypeMapping : NpgsqlTypeMapping
{
static readonly HstoreComparer ComparerInstance = new HstoreComparer();
///
/// Constructs an instance of the class.
///
public NpgsqlHstoreTypeMapping()
: base(
new RelationalTypeMappingParameters(
new CoreTypeMappingParameters(typeof(Dictionary), null, ComparerInstance),
"hstore"
), NpgsqlDbType.Hstore) {}
protected NpgsqlHstoreTypeMapping(RelationalTypeMappingParameters parameters)
: base(parameters, NpgsqlDbType.Hstore) {}
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new NpgsqlHstoreTypeMapping(parameters);
protected override string GenerateNonNullSqlLiteral(object value)
{
var sb = new StringBuilder("HSTORE '");
foreach (var kv in (Dictionary)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);
sb.Append('\'');
return sb.ToString();
}
class HstoreComparer : ValueComparer>
{
public HstoreComparer() : base(
(a, b) => Compare(a,b),
o => o.GetHashCode(),
o => o == null ? null : new Dictionary(o))
{}
static bool Compare(Dictionary a, Dictionary b)
{
if (a == null)
return b == null;
if (b == null)
return false;
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;
}
}
}
}