Skip to content

Commit

Permalink
Fixes bchavez#125, use the configured NamingStrategy when translating…
Browse files Browse the repository at this point in the history
… linq queries.
  • Loading branch information
roald-di committed Mar 14, 2018
1 parent 7ec2e2b commit dab3d90
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 8 deletions.
3 changes: 2 additions & 1 deletion Source/RethinkDb.Driver.Linq.Tests/BaseLinqTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using RethinkDb.Driver.Net;
using RethinkDb.Driver.Proto;
using RethinkDb.Driver.Tests;
using RethinkDb.Driver.Utils;

namespace RethinkDb.Driver.Linq.Tests
{
Expand Down Expand Up @@ -101,7 +102,7 @@ protected void SpawnData<T>( List<T> data )
var secondaryIndexes = typeof( T ).GetProperties().Where( x => x.CustomAttributes.Any( a => a.AttributeType == typeof( SecondaryIndexAttribute ) ) );
foreach( var secondaryIndex in secondaryIndexes )
{
RethinkDB.R.Table( TableName ).IndexCreate( secondaryIndex.Name ).Run( Connection );
RethinkDB.R.Table( TableName ).IndexCreate( QueryHelper.GetJsonMemberName( secondaryIndex ) ).Run( Connection );
}
RethinkDB.R.Table( TableName ).IndexWait().Run( Connection );

Expand Down
282 changes: 282 additions & 0 deletions Source/RethinkDb.Driver.Linq.Tests/NamingStrategyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Newtonsoft.Json.Serialization;
using System;
using RethinkDb.Driver.Linq.Attributes;
using RethinkDb.Driver.Net;
using Newtonsoft.Json;

namespace RethinkDb.Driver.Linq.Tests
{
[TestFixture]
public class NamingStrategyTests : BaseLinqTest
{
[DatapointSource]
public DefaultContractResolver[] ContractResolvers =
{
new DefaultContractResolver(),
new CamelCasePropertyNamesContractResolver(),
new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
}
};

readonly List<TestObject> data = new List<TestObject>
{
new TestObject
{
SimpleProperty = "Property value 1",
IndexedProperty = "Indexed property value 1",
SimpleField = 1,
},
new TestObject
{
SimpleProperty = "Property value 2",
IndexedProperty = "Indexed property value 2",
SimpleField = 2,
}
};

[Theory]
public void Where_RespectsConfiguredNamingStrategy(DefaultContractResolver contractResolver)
{
using (WithContractResolver(contractResolver))
{
SpawnData( data );

var namingStrategy = contractResolver.NamingStrategy ?? new DefaultNamingStrategy();

var expected = RethinkDB.R.Table( TableName )
.Filter( x => x[namingStrategy.GetPropertyName( nameof(TestObject.SimpleProperty), false )].Eq( data[0].SimpleProperty ) )
.Filter( x => x[namingStrategy.GetPropertyName( nameof(TestObject.SimpleField), false )].Gt( data[0].SimpleField ) );

var queryable = GetQueryable<TestObject>( TableName, expected );

var result =
(
from testObject in queryable
where testObject.SimpleProperty == data[0].SimpleProperty
where testObject.SimpleField > data[0].SimpleField
select testObject
).ToList();

Assert.NotNull(result);
}
}

[Theory]
public void WhereWithIndex_RespectsConfiguredNamingStrategy(DefaultContractResolver contractResolver)
{
using (WithContractResolver(contractResolver))
{
SpawnData( data );

var namingStrategy = contractResolver.NamingStrategy ?? new DefaultNamingStrategy();

var expected = RethinkDB.R.Table( TableName )
.GetAll( data[0].IndexedProperty )
.OptArg( "index", namingStrategy.GetPropertyName( nameof(TestObject.IndexedProperty), false ) );

var queryable = GetQueryable<TestObject>( TableName, expected );

var result =
(
from testObject in queryable
where testObject.IndexedProperty == data[0].IndexedProperty
select testObject
).ToList();

Assert.NotNull(result);
}
}

[Theory]
public void Orderby_RespectsConfiguredNamingStrategy(DefaultContractResolver contractResolver)
{
using (WithContractResolver(contractResolver))
{
SpawnData( data );

var namingStrategy = contractResolver.NamingStrategy ?? new DefaultNamingStrategy();

var expected = RethinkDB.R.Table( TableName )
.OrderBy( namingStrategy.GetPropertyName( nameof(TestObject.SimpleProperty), false ) );

var queryable = GetQueryable<TestObject>( TableName, expected );

var result =
(
from testObject in queryable
orderby testObject.SimpleProperty
select testObject
).ToList();

Assert.NotNull(result);
}
}

[Theory]
public void OrderbyField_RespectsConfiguredNamingStrategy(DefaultContractResolver contractResolver)
{
using (WithContractResolver(contractResolver))
{
SpawnData( data );

var namingStrategy = contractResolver.NamingStrategy ?? new DefaultNamingStrategy();

var expected = RethinkDB.R.Table( TableName )
.OrderBy( namingStrategy.GetPropertyName( nameof(TestObject.SimpleField), false ) );

var queryable = GetQueryable<TestObject>( TableName, expected );

var result =
(
from testObject in queryable
orderby testObject.SimpleField
select testObject
).ToList();

Assert.NotNull(result);
}
}

[Theory]
public void OrderbyWithIndex_RespectsConfiguredNamingStrategy(DefaultContractResolver contractResolver)
{
using (WithContractResolver(contractResolver))
{
SpawnData( data );

var namingStrategy = contractResolver.NamingStrategy ?? new DefaultNamingStrategy();

var expected = RethinkDB.R.Table( TableName )
.OrderBy( namingStrategy.GetPropertyName( nameof(TestObject.IndexedProperty), false ) )
.OptArg( "index", namingStrategy.GetPropertyName( nameof(TestObject.IndexedProperty), false ) );

var queryable = GetQueryable<TestObject>( TableName, expected );

var result =
(
from testObject in queryable
orderby testObject.IndexedProperty
select testObject
).ToList();

Assert.NotNull(result);
}
}

[Theory]
public void Groupby_RespectsConfiguredNamingStrategy(DefaultContractResolver contractResolver)
{
using (WithContractResolver(contractResolver))
{
SpawnData( data );

var namingStrategy = contractResolver.NamingStrategy ?? new DefaultNamingStrategy();

var expected = RethinkDB.R.Table( TableName )
.Group(namingStrategy.GetPropertyName( nameof(TestObject.SimpleProperty), false ) )
.Ungroup();

var queryable = GetQueryable<TestObject>( TableName, expected );

var result = queryable
.GroupBy(testObject => testObject.SimpleProperty)
.ToList();

Assert.NotNull(result);
}
}

[Theory]
public void GroupbyField_RespectsConfiguredNamingStrategy(DefaultContractResolver contractResolver)
{
using (WithContractResolver(contractResolver))
{
SpawnData( data );

var namingStrategy = contractResolver.NamingStrategy ?? new DefaultNamingStrategy();

var expected = RethinkDB.R.Table( TableName )
.Group(namingStrategy.GetPropertyName( nameof(TestObject.SimpleField), false ) )
.Ungroup();

var queryable = GetQueryable<TestObject>( TableName, expected );

var result = queryable
.GroupBy(testObject => testObject.SimpleField)
.ToList();

Assert.NotNull(result);
}
}

[Theory]
public void GroupbyWithSelector_RespectsConfiguredNamingStrategy(DefaultContractResolver contractResolver)
{
using (WithContractResolver(contractResolver))
{
SpawnData( data );

var namingStrategy = contractResolver.NamingStrategy ?? new DefaultNamingStrategy();

var expected = RethinkDB.R.Table( TableName )
.Group( namingStrategy.GetPropertyName( nameof(TestObject.SimpleProperty), false ) )
.GetField( namingStrategy.GetPropertyName( nameof(TestObject.SimpleField), false ) )
.Ungroup();

var queryable = GetQueryable<TestObject>( TableName, expected );

var result =
(
from testObject in queryable
group testObject.SimpleField by testObject.SimpleProperty into g
select g
).ToList();

Assert.NotNull(result);
}
}

static IDisposable WithContractResolver(IContractResolver contractResolver)
{
var original = Converter.Serializer;

Converter.Serializer = JsonSerializer.Create(new JsonSerializerSettings
{
Converters = Converter.Converters,
ContractResolver = contractResolver
});

return new Disposable(() => Converter.Serializer = original);
}

class TestObject
{
public string SimpleProperty { get; set; }

[SecondaryIndex]
public string IndexedProperty { get; set; }

public int SimpleField;
}

class Disposable : IDisposable
{
readonly Action action;

public Disposable(Action action)
{
this.action = action;
}

public void Dispose()
{
action();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
<Compile Include="LastOrDefaultTests.cs" />
<Compile Include="LastTests.cs" />
<Compile Include="LinqExamples.cs" />
<Compile Include="NamingStrategyTests.cs" />
<Compile Include="OrderByTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestRethinkQueryExecuter.cs" />
Expand Down
3 changes: 2 additions & 1 deletion Source/RethinkDb.Driver.Linq/MemberNameResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Remotion.Linq.Clauses.Expressions;
using RethinkDb.Driver.Ast;
using RethinkDb.Driver.Linq.WhereClauseParsers.SubQueryVisitor;
using RethinkDb.Driver.Utils;

namespace RethinkDb.Driver.Linq
{
Expand All @@ -25,7 +26,7 @@ private static ReqlExpr ResolveMemberExpression( ReqlExpr reqlExpr, MemberExpres
reqlExpr = ResolveMemberExpression( reqlExpr, (MemberExpression)expression.Expression );
if( expression.Expression.NodeType == ExpressionType.Extension && expression.Expression is SubQueryExpression )
reqlExpr = ResolveExtensionExpression( reqlExpr, (SubQueryExpression)expression.Expression );
return reqlExpr[expression.Member.Name];
return reqlExpr[QueryHelper.GetJsonMemberName( expression.Member )];
}

private static ReqlExpr ResolveExtensionExpression( ReqlExpr reqlExpr, SubQueryExpression expression )
Expand Down
14 changes: 9 additions & 5 deletions Source/RethinkDb.Driver.Linq/RethinkDbQueryModelVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using RethinkDb.Driver.Linq.Attributes;
using RethinkDb.Driver.Linq.WhereClauseParsers;
using ExpressionVisitor = RethinkDb.Driver.Linq.WhereClauseParsers.ExpressionVisitor;
using RethinkDb.Driver.Utils;

namespace RethinkDb.Driver.Linq
{
Expand Down Expand Up @@ -102,13 +103,14 @@ public override void VisitOrderByClause( OrderByClause orderByClause, QueryModel

OrderBy reql;
var currentStack = Stack.Pop();
var memberName = QueryHelper.GetJsonMemberName( expression.Member );
if( orderByClause.Orderings[0].OrderingDirection == OrderingDirection.Asc )
reql = currentStack.OrderBy( expression.Member.Name );
reql = currentStack.OrderBy( memberName );
else
reql = currentStack.OrderBy( RethinkDB.R.Desc( expression.Member.Name ) );
reql = currentStack.OrderBy( RethinkDB.R.Desc( memberName ) );

if( currentStack is Table && expression.Member.CustomAttributes.Any( x => x.AttributeType == typeof( PrimaryIndexAttribute ) || x.AttributeType == typeof( SecondaryIndexAttribute ) ) )
reql = reql.OptArg( "index", expression.Member.Name );
reql = reql.OptArg( "index", memberName );

Stack.Push( reql );
}
Expand Down Expand Up @@ -153,10 +155,12 @@ protected override void VisitBodyClauses( ObservableCollection<IBodyClause> body
return;
}

var groupReql = Stack.Pop().Group( ( (MemberExpression)group.KeySelector ).Member.Name );

var keySelector = (MemberExpression)group.KeySelector;
var groupReql = Stack.Pop().Group( QueryHelper.GetJsonMemberName( keySelector.Member ) );

var memberAccess = group.ElementSelector as MemberExpression;
Stack.Push( memberAccess != null ? groupReql.GetField( memberAccess.Member.Name ).Ungroup() : groupReql.Ungroup() );
Stack.Push( memberAccess != null ? groupReql.GetField( QueryHelper.GetJsonMemberName( memberAccess.Member ) ).Ungroup() : groupReql.Ungroup() );
}

public override void VisitResultOperator( ResultOperatorBase resultOperator, QueryModel queryModel, int index )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Remotion.Linq;
using RethinkDb.Driver.Ast;
using RethinkDb.Driver.Linq.Attributes;
using RethinkDb.Driver.Utils;

namespace RethinkDb.Driver.Linq.WhereClauseParsers
{
Expand All @@ -18,7 +19,8 @@ public override ReqlExpr Parse( ReqlExpr expression, QueryModel queryModel, Expr
private static string GetIndexName( BinaryExpression binaryExpression )
{
var left = binaryExpression.Left as MemberExpression;
return left?.Member.Name ?? ( (MemberExpression)binaryExpression.Right ).Member.Name;
var memberExpression = left ?? ( (MemberExpression)binaryExpression.Right );
return QueryHelper.GetJsonMemberName( memberExpression.Member );
}
}
}
Loading

0 comments on commit dab3d90

Please sign in to comment.