Skip to content

Commit e827788

Browse files
author
IharYakimush
authored
Merge pull request #4 from IharYakimush/develop
support Cast method
2 parents 8219078 + 5c1f70c commit e827788

15 files changed

+301
-115
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,5 +147,13 @@ IQueryable<Product> solrLinq = solr.AsQueryable(setup =>
147147
- SingleAsync
148148
- SingleOrDefault
149149
- SingleOrDefaultAsync
150+
### Cast
151+
Cast to interface and get SolrQueryResults object of interface type
152+
```
153+
SolrQueryResults<IProduct> result = solrLinq
154+
.Where(p => p.Id != null)
155+
.Cast<IProduct>
156+
.ToSolrQueryResults();
157+
```
150158
## Nuget
151159
https://www.nuget.org/packages/SolrNet.Linq

SolrNet.IntegrationOData/Controllers/ValuesController.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public IActionResult Get()
3333
"/api/values/1?$filter=Popularity eq null",
3434
"/api/values/1?$filter=Categories/any(c: c eq 'electronics')",
3535
"/api/values/2?$select=Id,Price,Categories",
36+
"/api/values/3?$select=Id,Price,Categories",
3637
});
3738
}
3839

@@ -71,5 +72,14 @@ public ActionResult<string> Get2(ODataQueryOptions odata)
7172

7273
return this.Ok(query.OData().ApplyQueryOptions(odata).ToJson());
7374
}
75+
76+
// GET api/values/5
77+
[HttpGet("3")]
78+
public ActionResult<string> Get3(ODataQueryOptions odata)
79+
{
80+
IQueryable<Product> query = this.Solr.AsQueryable();
81+
82+
return this.Ok(query.OData().ApplyQueryOptions(odata).ToJson());
83+
}
7484
}
7585
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace SolrNet.Linq.IntegrationTests
2+
{
3+
public class DerivedProduct : Product
4+
{
5+
public string Id2 { get; set; }
6+
}
7+
8+
public class DerivedDerivedProduct : DerivedProduct
9+
{
10+
public string Id3 { get; set; }
11+
}
12+
}

SolrNet.Linq.IntegrationTests/Product.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77

88
namespace SolrNet.Linq.IntegrationTests
99
{
10-
public class Product
10+
public interface IProduct
11+
{
12+
string Id { get; set; }
13+
ICollection<string> Categories { get; set; }
14+
}
15+
public class Product : IProduct
1116
{
1217
[DataMember]
1318
[SolrUniqueKey("id")]

SolrNet.Linq.IntegrationTests/SelectTests.cs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,147 @@ public void AnonymousClassSolrResult()
138138
Assert.True(t1.NumFound > 0);
139139
}
140140

141+
[Fact]
142+
public void SelectDerivedWithCast()
143+
{
144+
IQueryable<DerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
145+
.Where(p => p.Id != null && p.Categories.Any())
146+
.Select(p => new DerivedProduct { Id2 = p.Id, Categories = p.Categories})
147+
.Where(p => p.Id2 != null);
148+
149+
IQueryable<Product> q2 = derivedProducts.Cast<Product>();
150+
151+
var t1 = q2.ToSolrQueryResults();
152+
153+
Assert.NotNull(t1);
154+
Assert.NotNull(t1[0].Categories);
155+
Assert.Null(t1[0].Id);
156+
Assert.True(t1.NumFound > 0);
157+
}
158+
159+
[Fact]
160+
public void SelectDerivedWithCastToInterface()
161+
{
162+
IQueryable<DerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
163+
.Where(p => p.Id != null && p.Categories.Any())
164+
.Select(p => new DerivedProduct { Id2 = p.Id, Categories = p.Categories })
165+
.Where(p => p.Id2 != null);
166+
167+
IQueryable<IProduct> q2 = derivedProducts.Cast<IProduct>();
168+
169+
SolrQueryResults<IProduct> t1 = q2.ToSolrQueryResults();
170+
171+
Assert.NotNull(t1);
172+
Assert.NotNull(t1[0].Categories);
173+
Assert.Null(t1[0].Id);
174+
Assert.True(t1.NumFound > 0);
175+
}
176+
177+
[Fact]
178+
public void SelectDerivedWithDoubleCast()
179+
{
180+
IQueryable<DerivedDerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
181+
.Where(p => p.Id != null && p.Categories.Any())
182+
.Select(p => new DerivedDerivedProduct { Id2 = p.Id, Id3 = p.Id, Categories = p.Categories })
183+
.Where(p => p.Id3 != null);
184+
185+
IQueryable<Product> q2 = derivedProducts.Cast<DerivedProduct>().Cast<Product>();
186+
187+
var t1 = q2.ToSolrQueryResults();
188+
189+
Assert.NotNull(t1);
190+
Assert.NotNull(t1[0].Categories);
191+
Assert.Null(t1[0].Id);
192+
Assert.True(t1.NumFound > 0);
193+
}
194+
195+
[Fact]
196+
public void FilterAfterCastNotWorking()
197+
{
198+
IQueryable<DerivedDerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
199+
.Where(p => p.Id != null && p.Categories.Any())
200+
.Select(p => new DerivedDerivedProduct { Id2 = p.Id, Id3 = p.Id, Categories = p.Categories })
201+
.Where(p => p.Id3 != null);
202+
203+
IQueryable<Product> q2 = derivedProducts.Cast<Product>().Where(p => p.Id != null);
204+
205+
Assert.Throws<InvalidOperationException>(() => q2.ToSolrQueryResults());
206+
}
207+
208+
[Fact]
209+
public void CastToWrongTypeNotWorking()
210+
{
211+
IQueryable<DerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
212+
.Where(p => p.Id != null && p.Categories.Any())
213+
.Select(p => new DerivedProduct { Id2 = p.Id, Categories = p.Categories })
214+
.Where(p => p.Id2 != null);
215+
216+
var q2 = derivedProducts.Cast<DerivedDerivedProduct>();
217+
218+
Assert.Throws<InvalidCastException>(() => q2.ToSolrQueryResults());
219+
}
220+
221+
[Fact]
222+
public void MethodsWhichNotNeedContextWorksAfterCast()
223+
{
224+
IQueryable<DerivedDerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
225+
.Where(p => p.Id != null && p.Categories.Any())
226+
.Select(p => new DerivedDerivedProduct { Id2 = p.Id, Id3 = p.Id, Categories = p.Categories })
227+
.Where(p => p.Id3 != null);
228+
229+
Product q2 = derivedProducts.Cast<Product>().Skip(1).Take(1).FirstOrDefault();
230+
231+
Assert.NotNull(q2);
232+
}
233+
234+
[Fact]
235+
public void SelectMultipleCopiesOfField()
236+
{
237+
IQueryable<DerivedDerivedProduct> q1 = Product.SolrOperations.Value.AsQueryable()
238+
.Where(p => p.Id != null && p.Categories.Any())
239+
.Select(p => new DerivedDerivedProduct { Id2 = p.Id, Id3 = p.Id, Categories = p.Categories })
240+
.Where(p => p.Id2 != null);
241+
242+
var t1 = q1.ToSolrQueryResults();
243+
244+
Assert.NotNull(t1);
245+
Assert.NotNull(t1[0].Id2);
246+
Assert.Equal(t1[0].Id2, t1[0].Id3);
247+
Assert.NotNull(t1[0].Categories);
248+
Assert.Null(t1[0].Id);
249+
Assert.True(t1.NumFound > 0);
250+
}
251+
252+
[Fact]
253+
public void SelectAnyAfterSelect()
254+
{
255+
IQueryable<DerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
256+
.Where(p => p.Id != null)
257+
.Select(p => new DerivedProduct {Id2 = p.Id, Categories = p.Categories})
258+
.Where(p => p.Id2 != null && p.Categories.Any());
259+
260+
IQueryable<Product> q2 = derivedProducts.Cast<Product>();
261+
262+
var t1 = q2.ToSolrQueryResults();
263+
264+
Assert.NotNull(t1);
265+
Assert.NotNull(t1[0].Categories);
266+
Assert.Null(t1[0].Id);
267+
Assert.True(t1.NumFound > 0);
268+
}
269+
270+
[Fact]
271+
public void SelectSameParameter()
272+
{
273+
var t1 = Product.SolrOperations.Value.AsQueryable().Where(p => p.Id != null)
274+
.Select(p => p).Where(p => p.Id != null)
275+
.ToSolrQueryResults();
276+
277+
Assert.NotNull(t1);
278+
Assert.NotNull(t1[0].Id);
279+
Assert.True(t1.NumFound > 0);
280+
}
281+
141282
[Fact]
142283
public void MultipleSelects()
143284
{

SolrNet.Linq/Expressions/ExpressionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static bool HasMemberAccess(this Expression expression, Type type)
4343

4444
if (expression is MemberExpression me)
4545
{
46-
if (me.Member.DeclaringType == type)
46+
if (me.Member.DeclaringType!= null && me.Member.DeclaringType.IsAssignableFrom(type))
4747
{
4848
return true;
4949
}

SolrNet.Linq/Expressions/SelectMethod.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace SolrNet.Linq.Expressions
99
public static class SelectMethod
1010
{
1111
public const string Select = nameof(Queryable.Select);
12-
public static bool TryVisitSelect(this MethodCallExpression node, SelectExpressionsCollection options, MemberContext context, out SelectContext newContext)
12+
public static bool TryVisitSelect(this MethodCallExpression node, SelectExpressionsCollection options, MemberContext context, out MemberContext newContext)
1313
{
1414
newContext = null;
1515
bool result = node.Method.DeclaringType == typeof(Queryable) && node.Method.Name == Select;
@@ -31,14 +31,20 @@ public static bool TryVisitSelect(this MethodCallExpression node, SelectExpressi
3131
newContext = new SelectContext(memberInit, context);
3232
}
3333

34+
if (lambda.Body is ParameterExpression)
35+
{
36+
newContext = context;
37+
return result;
38+
}
39+
3440
if (newContext != null)
3541
{
3642
options.Fields.Clear();
3743
SelectFieldsVisitor visitor = new SelectFieldsVisitor(context, options);
3844
visitor.Visit(lambda.Body);
3945

4046
return result;
41-
}
47+
}
4248
}
4349

4450
throw new InvalidOperationException($"Unable to translate '{Select}' method.");
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using SolrNet.Impl;
4+
5+
namespace SolrNet.Linq.Impl
6+
{
7+
public class CastResponseParser<TNew, TOld> : TransformationResponseParser<TNew, TOld>
8+
{
9+
public CastResponseParser(ISolrDocumentResponseParser<TOld> inner,
10+
ISolrDocumentResponseParser<Dictionary<string, object>> dictionaryParser) : base(inner, dictionaryParser)
11+
{
12+
}
13+
14+
protected override TNew GetResult(TOld old, Dictionary<string, object> dictionary)
15+
{
16+
return Enumerable.Repeat(old, 1).Cast<TNew>().Single();
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)