Skip to content

Commit 053966c

Browse files
Ihar YakimushIhar Yakimush
authored andcommitted
suppport Select method
1 parent c93ea29 commit 053966c

File tree

9 files changed

+81
-146
lines changed

9 files changed

+81
-146
lines changed

SolrNet.Linq/Expressions/Context/MemberContext.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Linq;
34
using System.Linq.Expressions;
5+
using System.Reflection;
46
using SolrNet.Impl;
57
using SolrNet.Impl.FieldParsers;
68
using SolrNet.Impl.FieldSerializers;
@@ -9,7 +11,9 @@
911
namespace SolrNet.Linq.Expressions.Context
1012
{
1113
public abstract class MemberContext
12-
{
14+
{
15+
private static readonly ConcurrentDictionary<MemberInfo, string> MemberNames = new ConcurrentDictionary<MemberInfo, string>();
16+
1317
private static readonly DefaultFieldSerializer DefaultFieldSerializer = new DefaultFieldSerializer();
1418
private static IReadOnlyMappingManager DefaultMappingManager { get; } = new AttributesMappingManager();
1519

@@ -21,6 +25,23 @@ public abstract class MemberContext
2125

2226
public abstract bool IsAccessToMember(MemberExpression expression);
2327

28+
public virtual string GetMemberSolrName(MemberInfo info)
29+
{
30+
return MemberNames.GetOrAdd(info, m =>
31+
{
32+
var att = this.MappingManager.GetFields(info.DeclaringType);
33+
34+
SolrFieldModel value = att.Values.FirstOrDefault(f => f.Property == info as PropertyInfo);
35+
if (value != null)
36+
{
37+
return value.FieldName;
38+
}
39+
40+
throw new InvalidOperationException(
41+
$"Unable to get solr name for {m.DeclaringType}.{m.Name}. Mapping manager has mappings only for {string.Join(", ", att.Values.Select(f => f.Property.Name))}");
42+
});
43+
}
44+
2445
public string TrueStringSerialized => this.FieldSerializer.Serialize(true).Single().FieldValue;
2546

2647
public static MemberContext ForType<T>()

SolrNet.Linq/Expressions/Context/SelectContext.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public SelectContext(NewExpression expression, MemberContext parentContext)
1717
{
1818
Expression = expression ?? throw new ArgumentNullException(nameof(expression));
1919
ParentContext = parentContext ?? throw new ArgumentNullException(nameof(parentContext));
20-
20+
2121
for (int i = 0; i < expression.Arguments.Count; i++)
2222
{
2323
Expression argument = expression.Arguments[i];
@@ -34,14 +34,32 @@ public SelectContext(NewExpression expression, MemberContext parentContext)
3434
}
3535
public override bool HasMemberAccess(Expression expression)
3636
{
37-
throw new System.NotImplementedException();
37+
bool hasMemberAccess = expression.HasMemberAccess(this.Expression.Type);
38+
return hasMemberAccess;
3839
}
3940

4041
public override string GetSolrMemberProduct(Expression expression, bool disableFunctions = false)
4142
{
42-
throw new System.NotImplementedException();
43+
if (expression is MemberExpression me)
44+
{
45+
if (Members.ContainsKey(me.Member))
46+
{
47+
return Members[me.Member];
48+
}
49+
}
50+
51+
return expression.GetSolrMemberProduct(this, disableFunctions);
4352
}
4453

54+
public override string GetMemberSolrName(MemberInfo info)
55+
{
56+
if (Members.ContainsKey(info))
57+
{
58+
return Members[info];
59+
}
60+
61+
throw new InvalidOperationException($"Member {info.Name} of type {info.DeclaringType} is calculated field and can't be used in methods other than Select");
62+
}
4563
public override bool IsAccessToMember(MemberExpression expression)
4664
{
4765
return Members.ContainsKey(expression.Member);

SolrNet.Linq/Expressions/MemberExpressionExtensions.cs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,7 @@ public static class MemberExpressionExtensions
2828
{ typeof(Math).FullName + nameof(Math.Sqrt) ,(c,t) => $"sqrt({c.Arguments[0].GetSolrMemberProduct(t)})" },
2929
};
3030

31-
private static readonly ConcurrentDictionary<MemberInfo, string> MemberNames = new ConcurrentDictionary<MemberInfo, string>();
32-
33-
private static string GetMemberSolrName(this MemberInfo info, IReadOnlyMappingManager mappingManager)
34-
{
35-
return MemberNames.GetOrAdd(info, m =>
36-
{
37-
var att = mappingManager.GetFields(info.DeclaringType);
38-
39-
SolrFieldModel value = att.Values.FirstOrDefault(f => f.Property == info as PropertyInfo);
40-
if (value != null)
41-
{
42-
return value.FieldName;
43-
}
44-
45-
throw new InvalidOperationException(
46-
$"Unable to get solr name for {m.DeclaringType}.{m.Name}. Mapping manager has mappings only for {string.Join(", ", att.Values.Select(f => f.Property.Name))}");
47-
});
48-
}
31+
4932

5033
internal static string GetSolrMemberProduct(this Expression exp, MemberContext context, bool disableFunctions = false)
5134
{
@@ -59,7 +42,7 @@ internal static string GetSolrMemberProduct(this Expression exp, MemberContext c
5942

6043
if (context.IsAccessToMember(me))
6144
{
62-
return memberInfo.GetMemberSolrName(context.MappingManager);
45+
return context.GetMemberSolrName(me.Member);
6346
}
6447

6548
if (me.Member.DeclaringType != null &&

SolrNet.Linq/Expressions/SelectQueryProvider.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.

SolrNet.Linq/SolrNet.Linq.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,4 @@
2020
<PackageReference Include="SolrNet.Core" Version="1.0.0" />
2121
</ItemGroup>
2222

23-
<ItemGroup>
24-
<Folder Include="Providers\" />
25-
</ItemGroup>
26-
2723
</Project>

SolrNet.Linq/SolrOperationsExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public static IQueryable<T> AsQueryable<T>(this ISolrBasicReadOnlyOperations<T>
1212
{
1313
SolrNetLinqOptions o = new SolrNetLinqOptions();
1414
setupOptions?.Invoke(o);
15-
return new SolrQuery<T,T>(new SolrQueryProvider<T,T>(operations, o));
15+
return new SolrQuery<T>(new SolrQueryProvider<T>(operations, o, null));
1616
}
1717

1818
public static SolrQueryResults<T> ToSolrQueryResults<T>(this IQueryable<T> queryable)

SolrNet.Linq/SolrQuery.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66

77
namespace SolrNet.Linq
88
{
9-
public class SolrQuery<TEntity,TDocument> : IOrderedQueryable<TEntity>
9+
public class SolrQuery<TEntity> : IOrderedQueryable<TEntity>
1010
{
11-
public SolrQuery(SolrQueryProvider<TEntity, TDocument> provider)
11+
public SolrQuery(SolrQueryProvider<TEntity> provider)
1212
{
1313
this.Provider = provider ?? throw new ArgumentNullException(nameof(provider));
1414
this.Expression = Expression.Constant(this);
1515
}
1616

17-
public SolrQuery(SolrQueryProvider<TEntity, TDocument> provider, Expression expression)
17+
public SolrQuery(SolrQueryProvider<TEntity> provider, Expression expression)
1818
{
1919
this.Expression = expression ?? throw new ArgumentNullException(nameof(expression));
2020

SolrNet.Linq/SolrQueryProvider.cs

Lines changed: 27 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99

1010
namespace SolrNet.Linq
1111
{
12-
public class SolrQueryProvider<TEntity, TDocument> : IQueryProvider, IAsyncProvider<TEntity>
12+
public class SolrQueryProvider<TEntity> : IQueryProvider, IAsyncProvider<TEntity>
1313
{
14-
public ISolrBasicReadOnlyOperations<TDocument> Operations { get; }
14+
public ISolrBasicReadOnlyOperations<TEntity> Operations { get; }
1515
public SolrNetLinqOptions Options { get; }
1616

17-
public SolrQueryProvider(ISolrBasicReadOnlyOperations<TDocument> operations, SolrNetLinqOptions options, MemberContext context = null)
17+
public SolrQueryProvider(ISolrBasicReadOnlyOperations<TEntity> operations, SolrNetLinqOptions options, MemberContext context)
1818
{
1919
Operations = operations ?? throw new ArgumentNullException(nameof(operations));
2020
Options = options ?? throw new ArgumentNullException(nameof(options));
@@ -28,8 +28,7 @@ public SolrQueryProvider(ISolrBasicReadOnlyOperations<TDocument> operations, Sol
2828
else
2929
{
3030
this.MemberContext = context;
31-
}
32-
31+
}
3332
}
3433

3534
public IQueryable CreateQuery(Expression expression)
@@ -38,30 +37,27 @@ public IQueryable CreateQuery(Expression expression)
3837

3938
if (elementType == typeof(TEntity))
4039
{
41-
return new SolrQuery<TEntity, TDocument>(this, expression);
40+
return new SolrQuery<TEntity>(this, expression);
4241
}
4342

4443
if (expression is MethodCallExpression se)
4544
{
4645
if (se.Arguments.Count > 1 && se.Method.DeclaringType == typeof(Queryable) &&
4746
se.Method.Name == nameof(Queryable.Select))
4847
{
49-
if (typeof(TEntity) == typeof(TDocument))
50-
{
51-
return (IQueryable) Activator.CreateInstance(
52-
typeof(SolrQuery<,>).MakeGenericType(elementType, typeof(TDocument)), new object[]
53-
{
54-
Activator.CreateInstance(
55-
typeof(SelectQueryProvider<,>).MakeGenericType(elementType, typeof(TDocument)), new object[]
56-
{
57-
this.Operations,
58-
this.Options,
59-
se,
60-
this.MemberContext
61-
}),
62-
expression
63-
});
64-
}
48+
return (IQueryable) Activator.CreateInstance(
49+
typeof(SolrQuery<>).MakeGenericType(elementType), new object[]
50+
{
51+
Activator.CreateInstance(
52+
typeof(SolrQueryProvider<>).MakeGenericType(elementType),
53+
new object[]
54+
{
55+
this.Operations,
56+
this.Options,
57+
this.MemberContext
58+
}),
59+
expression
60+
});
6561
}
6662
}
6763

@@ -71,46 +67,19 @@ public IQueryable CreateQuery(Expression expression)
7167
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
7268
{
7369
return (IQueryable<TElement>) this.CreateQuery(expression);
74-
//if (typeof(TEntity) == typeof(TElement))
75-
//{
76-
// return new SolrQuery<TElement, TDocument>(this as SolrQueryProvider<TElement, TDocument>, expression);
77-
//}
78-
79-
//if (expression is MethodCallExpression se)
80-
//{
81-
// if (se.Arguments.Count > 1 && se.Method.DeclaringType == typeof(Queryable) &&
82-
// se.Method.Name == nameof(Queryable.Select))
83-
// {
84-
// if (typeof(TEntity) == typeof(TDocument))
85-
// {
86-
// return new SolrQuery<TElement, TDocument>(
87-
// new SelectQueryProvider<TElement, TDocument>(this.Operations, this.Options,
88-
// se), expression);
89-
// }
90-
// }
91-
//}
92-
93-
//throw new InvalidOperationException();
9470
}
9571

9672
public object Execute(Expression expression)
9773
{
98-
Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result = TranslateAndCallBack(expression);
74+
Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result = Translate(expression);
9975

100-
SolrQueryResults<TDocument> solrQueryResults =
76+
SolrQueryResults<TEntity> solrQueryResults =
10177
Operations.Query(this.Options.MainQuery ?? result.Item1, result.Item2);
10278

10379
return HandleResults(result, solrQueryResults);
10480
}
10581

106-
private object HandleResults(Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result, SolrQueryResults<TDocument> solrQueryResults)
107-
{
108-
object results = HandleEnumerateResults(result, solrQueryResults);
109-
110-
return CastToEntityType(results);
111-
}
112-
113-
private static object HandleEnumerateResults(Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result, SolrQueryResults<TDocument> solrQueryResults)
82+
private object HandleResults(Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result, SolrQueryResults<TEntity> solrQueryResults)
11483
{
11584
switch (result.Item3)
11685
{
@@ -120,63 +89,27 @@ private static object HandleEnumerateResults(Tuple<ISolrQuery, QueryOptions, Enu
12089
case EnumeratedResult.SingleOrDefault: return solrQueryResults.SingleOrDefault();
12190
case EnumeratedResult.Any: return solrQueryResults.NumFound > 0;
12291
case EnumeratedResult.Count: return solrQueryResults.NumFound;
123-
case EnumeratedResult.LongCount: return (long) solrQueryResults.NumFound;
92+
case EnumeratedResult.LongCount: return (long)solrQueryResults.NumFound;
12493

12594
default: return solrQueryResults;
12695
}
12796
}
12897

129-
private object CastToEntityType(object document)
130-
{
131-
if (document == null)
132-
{
133-
return null;
134-
}
135-
else if (document is SolrQueryResults<TDocument> sqr)
136-
{
137-
if (typeof(TEntity) != typeof(TDocument))
138-
{
139-
// Entity type not equal document type due to select expression. Try to cast to IEnumerable
140-
return sqr.Select(GetEntity).ToList();
141-
}
142-
}
143-
else if (document is TDocument doc)
144-
{
145-
if (typeof(TEntity) != typeof(TDocument))
146-
{
147-
return GetEntity(doc);
148-
}
149-
}
150-
151-
return document;
152-
}
153-
154-
protected virtual TEntity GetEntity(TDocument document)
155-
{
156-
throw new NotImplementedException();
157-
}
158-
159-
private Tuple<ISolrQuery, QueryOptions, EnumeratedResult> TranslateAndCallBack(Expression expression)
160-
{
161-
Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result = Translate(expression);
162-
this.Options.SetupQueryOptions?.Invoke(result.Item2);
163-
return result;
164-
}
165-
166-
public virtual Tuple<ISolrQuery, QueryOptions, EnumeratedResult> Translate(Expression expression)
98+
private Tuple<ISolrQuery, QueryOptions, EnumeratedResult> Translate(Expression expression)
16799
{
168100
SolrQueryTranslator translator = new SolrQueryTranslator(this.Options, this.MemberContext);
169101
Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result = translator.Translate(this, expression);
102+
this.Options.SetupQueryOptions?.Invoke(result.Item2);
170103
return result;
171104
}
172-
105+
173106
public MemberContext MemberContext { get; set; }
174107

175108
public async Task<object> ExecuteAsync(Expression expression)
176109
{
177-
Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result = TranslateAndCallBack(expression);
110+
Tuple<ISolrQuery, QueryOptions, EnumeratedResult> result = Translate(expression);
178111

179-
SolrQueryResults<TDocument> solrQueryResults =
112+
SolrQueryResults<TEntity> solrQueryResults =
180113
await Operations.QueryAsync(this.Options.MainQuery ?? result.Item1, result.Item2);
181114

182115
return HandleResults(result, solrQueryResults);

SolrNet.Linq/SolrQueryTranslator.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public SolrQueryTranslator(SolrNetLinqOptions solrNetLinqOptions, MemberContext
2424
Context = context ?? throw new ArgumentNullException(nameof(context));
2525
}
2626

27-
public Tuple<ISolrQuery,QueryOptions, EnumeratedResult> Translate<TEntity,TDocument>(SolrQueryProvider<TEntity, TDocument> provider, Expression expression)
27+
public Tuple<ISolrQuery,QueryOptions, EnumeratedResult> Translate<TEntity>(SolrQueryProvider<TEntity> provider, Expression expression)
2828
{
2929
this.Visit(expression);
3030
return new Tuple<ISolrQuery, QueryOptions, EnumeratedResult>(Query, Options, this.EnumeratedResult);
@@ -42,7 +42,10 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
4242
if (!result)
4343
{
4444
result = node.TryVisitSelect(this.Options, this.Context, out var newContext);
45-
this.Context = newContext;
45+
if (result)
46+
{
47+
this.Context = newContext;
48+
}
4649
}
4750

4851
if (!result)

0 commit comments

Comments
 (0)