Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 58af46e

Browse files
authored
Merge pull request #593 from KevinHoward/master
Update Unit Tests and made some changes around the SQL Server 2016 JSON functions
2 parents cf8b312 + d4658f0 commit 58af46e

17 files changed

+252
-151
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Data;
3+
using System.Data.SqlClient;
4+
using ServiceStack.DataAnnotations;
5+
using ServiceStack.OrmLite.Converters;
6+
using ServiceStack.Text;
7+
8+
namespace ServiceStack.OrmLite.SqlServer.Converters
9+
{
10+
public class SqlServerJsonStringConverter : SqlServerStringConverter
11+
{
12+
// json string to object
13+
public override object FromDbValue(Type fieldType, object value)
14+
{
15+
if (value is string raw && fieldType.HasAttribute<SqlJsonAttribute>())
16+
return JsonSerializer.DeserializeFromString(raw, fieldType);
17+
18+
return base.FromDbValue(fieldType, value);
19+
}
20+
21+
// object to json string
22+
public override object ToDbValue(Type fieldType, object value)
23+
{
24+
if (value.GetType().HasAttribute<SqlJsonAttribute>())
25+
return JsonSerializer.SerializeToString(value, value.GetType());
26+
27+
return base.ToDbValue(fieldType, value);
28+
}
29+
}
30+
31+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
32+
public class SqlJsonAttribute : Attribute
33+
{ }
34+
}

src/ServiceStack.OrmLite.SqlServer/SqlServer2016OrmLiteDialectProvider.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
using System;
2-
using System.Data;
3-
using System.Text;
4-
using ServiceStack.Text;
2+
3+
using ServiceStack.OrmLite.SqlServer.Converters;
54

65
namespace ServiceStack.OrmLite.SqlServer
76
{
87
public class SqlServer2016OrmLiteDialectProvider : SqlServer2014OrmLiteDialectProvider
98
{
9+
public SqlServer2016OrmLiteDialectProvider() : base()
10+
{
11+
base.RegisterConverter<String>(new SqlServerJsonStringConverter());
12+
}
13+
1014
public new static SqlServer2016OrmLiteDialectProvider Instance = new SqlServer2016OrmLiteDialectProvider();
1115

1216
public override SqlExpression<T> SqlExpression<T>() => new SqlServer2016Expression<T>(this);

src/ServiceStack.OrmLite.SqlServerTests/Converters/ConvertersOrmLiteTestBase.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace ServiceStack.OrmLite.SqlServerTests.Converters
88
{
99
public class SqlServer2012ConvertersOrmLiteTestBase : OrmLiteTestBase
1010
{
11-
[TestFixtureSetUp]
11+
[OneTimeSetUp]
1212
public override void TestFixtureSetUp()
1313
{
1414
try
@@ -33,7 +33,7 @@ public override void TestFixtureSetUp()
3333

3434
public class SqlServer2014ConvertersOrmLiteTestBase : SqlServer2012ConvertersOrmLiteTestBase
3535
{
36-
[TestFixtureSetUp]
36+
[OneTimeSetUp]
3737
public override void TestFixtureSetUp()
3838
{
3939
try
@@ -58,7 +58,7 @@ public override void TestFixtureSetUp()
5858

5959
public class SqlServer2016ConvertersOrmLiteTestBase : SqlServer2014ConvertersOrmLiteTestBase
6060
{
61-
[TestFixtureSetUp]
61+
[OneTimeSetUp]
6262
public override void TestFixtureSetUp()
6363
{
6464
try

src/ServiceStack.OrmLite.SqlServerTests/Converters/SqlGeographyTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class SqlGeographyTests : SqlServer2012ConvertersOrmLiteTestBase
1212
{
1313
public string ColumnDefinition { get; set; }
1414

15-
[TestFixtureSetUp]
15+
[OneTimeSetUp]
1616
public new void TestFixtureSetUp()
1717
{
1818
base.TestFixtureSetUp();

src/ServiceStack.OrmLite.SqlServerTests/Converters/SqlGeometryTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class SqlGeometryTests : SqlServer2012ConvertersOrmLiteTestBase
1212
{
1313
public string ColumnDefinition { get; set; }
1414

15-
[TestFixtureSetUp]
15+
[OneTimeSetUp]
1616
public new void TestFixtureSetUp()
1717
{
1818
base.TestFixtureSetUp();

src/ServiceStack.OrmLite.SqlServerTests/Converters/SqlHierarchyIdTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class SqlHierarchyIdTests : SqlServer2012ConvertersOrmLiteTestBase
1010
{
1111
public string ColumnDefinition { get; set; }
1212

13-
[TestFixtureSetUp]
13+
[OneTimeSetUp]
1414
public new void TestFixtureSetUp()
1515
{
1616
base.TestFixtureSetUp();

src/ServiceStack.OrmLite.SqlServerTests/Expressions/AuthorUseCase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ public void AuthorUsesCases()
304304
bool r6 = db.Scalar<Author, bool>(e => Sql.Max(e.Active));
305305
Assert.AreEqual(expectedBool, r6);
306306
}
307-
catch (Exception e)
307+
catch //(Exception e)
308308
{
309309
//????
310310
//if (dialect.Name == "PostgreSQL")
Lines changed: 154 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,159 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Configuration;
4+
5+
using ServiceStack.Logging;
6+
using ServiceStack.OrmLite;
7+
using ServiceStack.OrmLite.SqlServer.Converters;
8+
29
using NUnit.Framework;
310

411
namespace ServiceStack.OrmLite.SqlServerTests.Expressions
512
{
6-
public class JsonExpressionsTest : OrmLiteTestBase
7-
{
8-
[Test]
9-
public void Can_select_json_scalar_value()
10-
{
11-
using (var db = OpenDbConnection(dialectProvider: SqlServer2016Dialect.Provider))
12-
{
13-
db.DropAndCreateTable<TestType>();
14-
15-
var obj = new
16-
{
17-
Address = new Address
18-
{
19-
Line1 = "1234 Main Street",
20-
Line2 = "Apt. 404",
21-
City = "Las Vegas",
22-
State = "NV"
23-
}
24-
};
25-
26-
//{ "Address": { "Line1": "1234 Main Street", "Line2": "Apt. 404", "City": "Las Vegas", "State": "NV" } }
27-
var stringValue = obj.ToJson();
28-
29-
db.Insert(new TestType { StringColumn = stringValue });
30-
31-
List<TestType> actual = db.Select<TestType>(q =>
32-
Sql.JsonValue(q.StringColumn, "$.address.state") == "NV");
33-
34-
Assert.That(actual, Is.EqualTo(obj.Address.State));
35-
}
36-
}
37-
38-
[Test]
39-
public void Can_select_json_object_value()
40-
{
41-
using (var db = OpenDbConnection(dialectProvider: SqlServer2016Dialect.Provider))
42-
{
43-
db.DropAndCreateTable<TestType>();
44-
45-
var expected = new Address
46-
{
47-
Line1 = "1234 Main Street",
48-
Line2 = "Apt. 404",
49-
City = "Las Vegas",
50-
State = "NV"
51-
};
52-
var obj = new { Address = expected };
53-
54-
//{ "Address": { "Line1": "1234 Main Street", "Line2": "Apt. 404", "City": "Las Vegas", "State": "NV" } }
55-
var stringValue = obj.ToJson();
56-
57-
db.Insert(new TestType { StringColumn = stringValue });
58-
59-
SqlExpression<TestType> q = db.From<TestType>().Select(x =>
60-
Sql.JsonQuery<Address>(x.StringColumn, "$.address"));
61-
62-
var address = q.ConvertTo<Address>();
63-
64-
Assert.That(address, Is.EqualTo(obj.Address));
65-
}
66-
}
67-
68-
internal class Address
69-
{
70-
public string Line1 { get; set; }
71-
public string Line2 { get; set; }
72-
public string City { get; set; }
73-
public string State { get; set; }
74-
}
75-
}
13+
public class JsonExpressionsTest : OrmLiteTestBase
14+
{
15+
public static Address Addr { get; set; }
16+
= new Address
17+
{
18+
Line1 = "1234 Main Street",
19+
Line2 = "Apt. 404",
20+
City = "Las Vegas",
21+
State = "NV"
22+
};
23+
24+
[OneTimeSetUp]
25+
public override void TestFixtureSetUp()
26+
{
27+
LogManager.LogFactory = new ConsoleLogFactory();
28+
29+
OrmLiteConfig.DialectProvider = SqlServer2016Dialect.Provider;
30+
OrmLiteConfig.DialectProvider.RegisterConverter<string>(new SqlServerJsonStringConverter());
31+
OrmLiteConfig.DialectProvider.RegisterConverter<Address>(new SqlServerJsonStringConverter());
32+
33+
ConnectionString = ConfigurationManager.ConnectionStrings["testDb"].ConnectionString;
34+
35+
Db = OpenDbConnection();
36+
37+
// Load test data
38+
Db.DropAndCreateTable<TestType>();
39+
Db.Insert(new TestType { Id = 1, StringColumn = "not json" });
40+
Db.Insert(new TestType { Id = 2, StringColumn = Addr.ToJson() });
41+
}
42+
43+
[OneTimeTearDown]
44+
public void TextFixtureTearDown()
45+
{
46+
if (Db != null)
47+
{
48+
if (Db.State == System.Data.ConnectionState.Open)
49+
Db.Close();
50+
51+
Db.Dispose();
52+
}
53+
}
54+
55+
56+
[Test]
57+
public void Can_test_if_string_field_contains_json()
58+
{
59+
// test if string field is not JSON with Sql.IsJson
60+
var j = Db.From<TestType>()
61+
.Select(x => Sql.IsJson(x.StringColumn))
62+
.Where(x => x.Id == 1);
63+
var isJson = Db.Scalar<bool>(j);
64+
65+
Assert.IsFalse(isJson);
66+
67+
// test if string field is JSON with Sql.IsJson
68+
j = Db.From<TestType>()
69+
.Select(x => Sql.IsJson(x.StringColumn))
70+
.Where(x => x.Id == 2);
71+
isJson = Db.Scalar<bool>(j);
72+
73+
Assert.IsTrue(isJson);
74+
}
75+
76+
[Test]
77+
public void Can_select_using_a_json_scalar_filter()
78+
{
79+
// retrieve records where City in Address is NV (1 record)
80+
var actual = Db.Select<TestType>(q =>
81+
Sql.JsonValue(q.StringColumn, "$.State") == "NV"
82+
&& q.Id == 2
83+
);
84+
85+
Assert.IsNotEmpty(actual);
86+
87+
// retrieve records where City in Address is FL (0 records)
88+
actual = Db.Select<TestType>(q =>
89+
Sql.JsonValue(q.StringColumn, "$.State") == "FL"
90+
&& q.Id == 2
91+
);
92+
93+
Assert.IsEmpty(actual);
94+
}
95+
96+
[Test]
97+
public void Can_select_a_json_scalar_value()
98+
{
99+
// retrieve only the State in a field that contains a JSON Address
100+
var state = Db.Scalar<string>(
101+
Db.From<TestType>()
102+
.Where(q => q.Id == 2)
103+
.Select(q =>
104+
Sql.JsonValue(q.StringColumn, "$.State")
105+
)
106+
);
107+
108+
Assert.AreEqual(state, Addr.State);
109+
}
110+
111+
[Test]
112+
public void Can_select_a_json_object_value()
113+
{
114+
// demo how to retrieve inserted JSON string directly to an object
115+
var address = Db.Scalar<Address>(
116+
Db.From<TestType>()
117+
.Where(q => q.Id == 2)
118+
.Select(q => q.StringColumn)
119+
);
120+
121+
Assert.That(Addr.Line1, Is.EqualTo(address.Line1));
122+
Assert.That(Addr.Line2, Is.EqualTo(address.Line2));
123+
Assert.That(Addr.City, Is.EqualTo(address.City));
124+
Assert.That(Addr.State, Is.EqualTo(address.State));
125+
}
126+
127+
[Ignore("Not functioning properly, issue with converter")]
128+
[Test]
129+
public void Can_insert_an_object_directly_to_json()
130+
{
131+
var tableName = Db.GetDialectProvider().GetQuotedTableName(ModelDefinition<TestType>.Definition);
132+
var sql = $"INSERT {tableName} (StringColumn) VALUES (@Address);";
133+
134+
// breaks here with an invalid conversion error from Address to string
135+
Db.ExecuteSql(sql, new { Id = 3, Address = Addr });
136+
137+
// demo how to retrieve inserted JSON string directly to an object
138+
var address = Db.Single<Address>(
139+
Db.From<TestType>()
140+
.Where(q => q.Id == 3)
141+
.Select(q => q.StringColumn)
142+
);
143+
144+
Assert.That(Addr.Line1, Is.EqualTo(address.Line1));
145+
Assert.That(Addr.Line2, Is.EqualTo(address.Line2));
146+
Assert.That(Addr.City, Is.EqualTo(address.City));
147+
Assert.That(Addr.State, Is.EqualTo(address.State));
148+
}
149+
150+
[SqlJson]
151+
public class Address
152+
{
153+
public string Line1 { get; set; }
154+
public string Line2 { get; set; }
155+
public string City { get; set; }
156+
public string State { get; set; }
157+
}
158+
}
76159
}

src/ServiceStack.OrmLite.SqlServerTests/ForeignKeyAttributeTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace ServiceStack.OrmLite.SqlServerTests
66
[TestFixture]
77
public class ForeignKeyAttributeTests : OrmLiteTestBase
88
{
9-
[TestFixtureSetUp]
9+
[OneTimeSetUp]
1010
public void Setup()
1111
{
1212
using (var dbConn = OpenDbConnection())

src/ServiceStack.OrmLite.SqlServerTests/OrmLiteTestBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class OrmLiteTestBase
1212

1313
public IDbConnection Db { get; set; }
1414

15-
[TestFixtureSetUp]
15+
[OneTimeSetUp]
1616
public virtual void TestFixtureSetUp()
1717
{
1818
LogManager.LogFactory = new ConsoleLogFactory();

0 commit comments

Comments
 (0)