Permalink
Browse files

Add support for using Dictionary fields in Hstore data type

  • Loading branch information...
mythz committed Feb 5, 2019
1 parent aa5d47e commit c9b3bac226a82dfd926f60e4d79a92ad77ec2175
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Data;
using Npgsql;
using NpgsqlTypes;
using ServiceStack.OrmLite.Converters;

namespace ServiceStack.OrmLite.PostgreSQL.Converters
{
public class PostgreSqlHstoreConverter : ReferenceTypeConverter
{
public override string ColumnDefinition => "hstore";

public override DbType DbType => DbType.Object;

public override object FromDbValue(Type fieldType, object value)
{
return (IDictionary<string, string>)value;
}

public override object ToDbValue(Type fieldType, object value)
{
return (IDictionary<string, string>)value;
}

public override void InitDbParam(IDbDataParameter p, Type fieldType)
{
var sqlParam = (NpgsqlParameter)p;
sqlParam.NpgsqlDbType = NpgsqlDbType.Hstore;
base.InitDbParam(p, fieldType);
}

public override string GetColumnDefinition(int? stringLength) => ColumnDefinition;
}
}
@@ -57,7 +57,7 @@ public PostgreSqlDialectProvider()

RegisterConverter<byte[]>(new PostrgreSqlByteArrayConverter());

//TODO provide support for pgsql native datastructures:
//TODO provide support for pgsql native data structures:
RegisterConverter<string[]>(new PostgreSqlStringArrayConverter());
RegisterConverter<int[]>(new PostgreSqlIntArrayConverter());
RegisterConverter<long[]>(new PostgreSqlLongArrayConverter());
@@ -72,6 +72,23 @@ public PostgreSqlDialectProvider()
};
}

public bool UseHstore
{
set
{
if (value)
{
RegisterConverter<IDictionary<string, string>>(new PostgreSqlHstoreConverter());
RegisterConverter<Dictionary<string, string>>(new PostgreSqlHstoreConverter());
}
else
{
RemoveConverter<IDictionary<string, string>>();
RemoveConverter<Dictionary<string, string>>();
}
}
}

private bool normalize;
public bool Normalize
{
@@ -229,6 +229,12 @@ public ValueTypeConverter ValueTypeConverter
}
}

public void RemoveConverter<T>()
{
if (Converters.TryRemove(typeof(T), out var converter))
converter.DialectProvider = null;
}

public void RegisterConverter<T>(IOrmLiteConverter converter)
{
if (converter == null)
@@ -829,6 +829,24 @@ public static string StripQuotes(this string quotedExpr)

public static void UnPrintSql() => OrmLiteConfig.BeforeExecFilter = null;

public static StringBuilder CaptureSql()
{
var sb = StringBuilderCache.Allocate();
CaptureSql(sb);
return sb;
}

public static void CaptureSql(StringBuilder sb) =>
OrmLiteConfig.BeforeExecFilter = cmd => sb.AppendLine(cmd.GetDebugString());

public static void UnCaptureSql() => OrmLiteConfig.BeforeExecFilter = null;

public static string UnCaptureSqlAndFree(StringBuilder sb)
{
OrmLiteConfig.BeforeExecFilter = null;
return StringBuilderCache.ReturnAndFree(sb);
}

public static ModelDefinition GetModelDefinition(Type modelType)
{
return modelType.GetModelDefinition();
@@ -0,0 +1,51 @@
using System.Collections.Generic;
using NUnit.Framework;
using ServiceStack.OrmLite.PostgreSQL;

namespace ServiceStack.OrmLite.Tests
{
public class PostgreSqlTypes
{
public int Id { get; set; }

//hstore
public Dictionary<string,string> Dictionary { get; set; }
public IDictionary<string,string> IDictionary { get; set; }
}

public class PostgreSqlDataTypesTests : OrmLiteTestBase
{
public PostgreSqlDataTypesTests() : base(Dialect.PostgreSql) {}

[OneTimeSetUp] public void OneTimeSetup() => PostgreSqlDialectProvider.Instance.UseHstore = true;

[OneTimeTearDown] public void OneTimeTearDown() => PostgreSqlDialectProvider.Instance.UseHstore = false;

[Test]
public void Does_save_string_dictionary_in_hstore_columns()
{
using (var db = OpenDbConnection())
{
var sb = OrmLiteUtils.CaptureSql();

db.DropAndCreateTable<PostgreSqlTypes>();

Assert.That(OrmLiteUtils.UnCaptureSqlAndFree(sb), Does.Contain("hstore"));

db.Insert(new PostgreSqlTypes
{
Id = 1,
Dictionary = new Dictionary<string, string> { {"A", "1"} },
IDictionary = new Dictionary<string, string> { {"B", "2"} },
});

Assert.That(db.Single(db.From<PostgreSqlTypes>().Where("dictionary -> 'A' = '1'")).Id,
Is.EqualTo(1));

var q = db.From<PostgreSqlTypes>();
Assert.That(db.Single(q.Where($"{q.Column<PostgreSqlTypes>(x => x.IDictionary)} -> 'B' = '2'")).Id,
Is.EqualTo(1));
}
}
}
}

0 comments on commit c9b3bac

Please sign in to comment.