Skip to content

Commit 8df72ca

Browse files
committed
Use mapper for values and names
1 parent dad3415 commit 8df72ca

File tree

6 files changed

+169
-33
lines changed

6 files changed

+169
-33
lines changed

StaTypPocoQueries.PetaPoco.Tests/QueryTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Moq;
1111
using System.Collections.Generic;
1212
using AutoFixture.Xunit2;
13+
using System.Reflection;
1314

1415
namespace StaTypPocoQueries.PetaPoco.Tests
1516
{
@@ -37,6 +38,8 @@ private class MyClass
3738

3839
[FoodEnumConverter]
3940
public FoodEnum ConvertedFood { get; set; }
41+
42+
public string MultiWordName { get; set; }
4043
}
4144

4245
public enum FoodEnum { Apple, Banana, Carrot };
@@ -60,6 +63,17 @@ public QueryTests()
6063
_mockDb.Setup(m => m.Delete<MyClass>(It.IsAny<Sql>()))
6164
.Callback<Sql>(s => _lastSql = s);
6265
_mockDb.Setup(m => m.Provider).Returns(new AngleDatabaseProvider());
66+
_mockDb.Setup(m => m.DefaultMapper).Returns(new ConventionMapper());
67+
68+
FlushPocoDataCache();
69+
}
70+
71+
private void FlushPocoDataCache()
72+
{
73+
// This avoids having to upgrade PP just to get FlushCaches()
74+
var cache = typeof(PocoData).GetField("_pocoDatas", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
75+
var flush = cache.GetType().GetMethod("Flush");
76+
flush.Invoke(cache, null);
6377
}
6478

6579
[Theory, AutoData]
@@ -96,5 +110,21 @@ public void Query_Should_Use_Plain_Value_With_No_Value_Converter(FoodEnum food)
96110
_mockDb.Object.Query<MyClass>(c => c.PlainFood == food);
97111
_lastSql.Should().BeEquivalentTo(new Sql("WHERE <PlainFood> = @0", (int)food));
98112
}
113+
114+
[Theory, AutoData]
115+
public void Query_Should_Use_Mapper_For_Names(string value)
116+
{
117+
_mockDb.Setup(m => m.DefaultMapper).Returns(new UnderscoreMapper());
118+
_mockDb.Object.Query<MyClass>(c => c.MultiWordName == value);
119+
_lastSql.Should().BeEquivalentTo(new Sql("WHERE <multi_word_name> = @0", value));
120+
}
121+
122+
[Theory, AutoData]
123+
public void Query_Should_Use_Mapper_For_Values(string value)
124+
{
125+
_mockDb.Setup(m => m.DefaultMapper).Returns(new SubstituteStringMapper());
126+
_mockDb.Object.Query<MyClass>(c => c.Name == value);
127+
_lastSql.Should().BeEquivalentTo(new Sql("WHERE <Name> = @0", "SUBSTITUTE STRING"));
128+
}
99129
}
100130
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using PetaPoco;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace StaTypPocoQueries.PetaPoco.Tests
9+
{
10+
public class SubstituteStringMapper : ConventionMapper
11+
{
12+
public SubstituteStringMapper()
13+
{
14+
ToDbConverter = pi =>
15+
{
16+
if (pi.PropertyType == typeof(string))
17+
return o => "SUBSTITUTE STRING";
18+
else
19+
return base.ToDbConverter(pi);
20+
};
21+
}
22+
}
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using PetaPoco;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace StaTypPocoQueries.PetaPoco.Tests
9+
{
10+
public class UnderscoreMapper : ConventionMapper
11+
{
12+
public UnderscoreMapper()
13+
{
14+
InflectColumnName = (i, cn) => i.Underscore(cn);
15+
InflectTableName = (i, tn) => i.Underscore(tn);
16+
}
17+
}
18+
}

StaTypPocoQueries.PetaPoco/DatabaseExtensions.FSharp.cs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,10 @@ namespace PetaPoco
2828
{
2929
public static partial class DatabaseExtensions
3030
{
31-
private static readonly FSharpFunc<MemberInfo, string> FsExtractColumnName
32-
= ExpressionToSql.AsFsFunc<MemberInfo, string>(ExtractColumnName);
33-
34-
// Helpful precis: https://codeblog.jonskeet.uk/2012/01/30/currying-vs-partial-function-application/
35-
private static readonly FSharpFunc<PropertyInfo, FSharpFunc<object, object>> FsInvokeValueConverter
36-
= ExpressionToSql.AsFsFunc<PropertyInfo, FSharpFunc<object, object>>(
37-
pi => ExpressionToSql.AsFsFunc<object, object>(
38-
input => InvokeValueConverter(pi, input)
39-
)
40-
);
41-
4231
private static Sql ToSql<T>(this FSharpExpr<FSharpFunc<T, bool>> query, IDatabase db)
4332
{
44-
var translated = ExpressionToSql.Translate(new DatabaseQuoter(db), query,
45-
includeWhere: true,
46-
customNameExtractor: FsExtractColumnName,
47-
customParameterValueMap: FsInvokeValueConverter);
48-
return new Sql(translated.Item1, translated.Item2);
33+
var translator = new SqlTranslator(db);
34+
return translator.Translate(query);
4935
}
5036

5137

StaTypPocoQueries.PetaPoco/DatabaseExtensions.cs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,10 @@ namespace PetaPoco
2727
{
2828
public static partial class DatabaseExtensions
2929
{
30-
private static string ExtractColumnName(MemberInfo mi)
31-
{
32-
return mi.GetCustomAttribute<ColumnAttribute>()?.Name ?? mi.Name;
33-
}
34-
35-
private static object InvokeValueConverter(PropertyInfo pi, object input)
36-
{
37-
var converter = pi.GetCustomAttribute<ValueConverterAttribute>(true);
38-
39-
return converter == null ? input : converter.ConvertToDb(input);
40-
}
41-
4230
private static Sql ToSql<T>(this Expression<Func<T, bool>> query, IDatabase db)
4331
{
44-
var translated = ExpressionToSql.Translate(new DatabaseQuoter(db), query,
45-
includeWhere: true,
46-
customNameExtractor: ExtractColumnName,
47-
customParameterValueMap: InvokeValueConverter);
48-
return new Sql(translated.Item1, translated.Item2);
32+
var translator = new SqlTranslator(db);
33+
return translator.Translate(query);
4934
}
5035

5136

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* Copyright 2018-2020 Aaron Sherber
3+
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using Microsoft.FSharp.Core;
18+
using Microsoft.FSharp.Quotations;
19+
using PetaPoco;
20+
using PetaPoco.Core;
21+
using StaTypPocoQueries.Core;
22+
using System;
23+
using System.Collections.Generic;
24+
using System.Linq;
25+
using System.Linq.Expressions;
26+
using System.Reflection;
27+
using System.Text;
28+
using System.Threading.Tasks;
29+
30+
namespace StaTypPocoQueries.PetaPoco
31+
{
32+
public class SqlTranslator
33+
{
34+
private readonly IDatabase _db;
35+
36+
public SqlTranslator(IDatabase db)
37+
{
38+
_db = db;
39+
}
40+
41+
public Sql Translate<T>(Expression<Func<T, bool>> query)
42+
{
43+
var translated = ExpressionToSql.Translate(
44+
quoter: new DatabaseQuoter(_db),
45+
conditions: query,
46+
includeWhere: true,
47+
customNameExtractor: ExtractColumnName,
48+
customParameterValueMap: InvokeValueConverter);
49+
50+
return new Sql(translated.Item1, translated.Item2);
51+
}
52+
53+
public Sql Translate<T>(FSharpExpr<FSharpFunc<T, bool>> query)
54+
{
55+
var translated = ExpressionToSql.Translate(
56+
quoter: new DatabaseQuoter(_db),
57+
conditions: query,
58+
includeWhere: true,
59+
customNameExtractor: FsExtractColumnName,
60+
customParameterValueMap: FsInvokeValueConverter);
61+
62+
return new Sql(translated.Item1, translated.Item2);
63+
}
64+
65+
private string ExtractColumnName(MemberInfo mi)
66+
{
67+
if (mi is PropertyInfo pi)
68+
{
69+
var pd = PocoData.ForType(mi.DeclaringType, _db.DefaultMapper);
70+
return pd.GetColumnName(pi.Name);
71+
}
72+
else
73+
return mi.Name;
74+
}
75+
76+
77+
private object InvokeValueConverter(PropertyInfo pi, object input)
78+
{
79+
var converter = _db.DefaultMapper.GetToDbConverter(pi);
80+
return converter == null ? input : converter(input);
81+
}
82+
83+
private FSharpFunc<MemberInfo, string> FsExtractColumnName
84+
=> ExpressionToSql.AsFsFunc<MemberInfo, string>(ExtractColumnName);
85+
86+
// Helpful precis: https://codeblog.jonskeet.uk/2012/01/30/currying-vs-partial-function-application/
87+
private FSharpFunc<PropertyInfo, FSharpFunc<object, object>> FsInvokeValueConverter
88+
=> ExpressionToSql.AsFsFunc<PropertyInfo, FSharpFunc<object, object>>(
89+
pi => ExpressionToSql.AsFsFunc<object, object>(
90+
input => InvokeValueConverter(pi, input)
91+
)
92+
);
93+
}
94+
}

0 commit comments

Comments
 (0)