Skip to content

support Cast method #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,13 @@ IQueryable<Product> solrLinq = solr.AsQueryable(setup =>
- SingleAsync
- SingleOrDefault
- SingleOrDefaultAsync
### Cast
Cast to interface and get SolrQueryResults object of interface type
```
SolrQueryResults<IProduct> result = solrLinq
.Where(p => p.Id != null)
.Cast<IProduct>
.ToSolrQueryResults();
```
## Nuget
https://www.nuget.org/packages/SolrNet.Linq
10 changes: 10 additions & 0 deletions SolrNet.IntegrationOData/Controllers/ValuesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public IActionResult Get()
"/api/values/1?$filter=Popularity eq null",
"/api/values/1?$filter=Categories/any(c: c eq 'electronics')",
"/api/values/2?$select=Id,Price,Categories",
"/api/values/3?$select=Id,Price,Categories",
});
}

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

return this.Ok(query.OData().ApplyQueryOptions(odata).ToJson());
}

// GET api/values/5
[HttpGet("3")]
public ActionResult<string> Get3(ODataQueryOptions odata)
{
IQueryable<Product> query = this.Solr.AsQueryable();

return this.Ok(query.OData().ApplyQueryOptions(odata).ToJson());
}
}
}
12 changes: 12 additions & 0 deletions SolrNet.Linq.IntegrationTests/DerivedProduct.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace SolrNet.Linq.IntegrationTests
{
public class DerivedProduct : Product
{
public string Id2 { get; set; }
}

public class DerivedDerivedProduct : DerivedProduct
{
public string Id3 { get; set; }
}
}
7 changes: 6 additions & 1 deletion SolrNet.Linq.IntegrationTests/Product.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@

namespace SolrNet.Linq.IntegrationTests
{
public class Product
public interface IProduct
{
string Id { get; set; }
ICollection<string> Categories { get; set; }
}
public class Product : IProduct
{
[DataMember]
[SolrUniqueKey("id")]
Expand Down
141 changes: 141 additions & 0 deletions SolrNet.Linq.IntegrationTests/SelectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,147 @@ public void AnonymousClassSolrResult()
Assert.True(t1.NumFound > 0);
}

[Fact]
public void SelectDerivedWithCast()
{
IQueryable<DerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
.Where(p => p.Id != null && p.Categories.Any())
.Select(p => new DerivedProduct { Id2 = p.Id, Categories = p.Categories})
.Where(p => p.Id2 != null);

IQueryable<Product> q2 = derivedProducts.Cast<Product>();

var t1 = q2.ToSolrQueryResults();

Assert.NotNull(t1);
Assert.NotNull(t1[0].Categories);
Assert.Null(t1[0].Id);
Assert.True(t1.NumFound > 0);
}

[Fact]
public void SelectDerivedWithCastToInterface()
{
IQueryable<DerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
.Where(p => p.Id != null && p.Categories.Any())
.Select(p => new DerivedProduct { Id2 = p.Id, Categories = p.Categories })
.Where(p => p.Id2 != null);

IQueryable<IProduct> q2 = derivedProducts.Cast<IProduct>();

SolrQueryResults<IProduct> t1 = q2.ToSolrQueryResults();

Assert.NotNull(t1);
Assert.NotNull(t1[0].Categories);
Assert.Null(t1[0].Id);
Assert.True(t1.NumFound > 0);
}

[Fact]
public void SelectDerivedWithDoubleCast()
{
IQueryable<DerivedDerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
.Where(p => p.Id != null && p.Categories.Any())
.Select(p => new DerivedDerivedProduct { Id2 = p.Id, Id3 = p.Id, Categories = p.Categories })
.Where(p => p.Id3 != null);

IQueryable<Product> q2 = derivedProducts.Cast<DerivedProduct>().Cast<Product>();

var t1 = q2.ToSolrQueryResults();

Assert.NotNull(t1);
Assert.NotNull(t1[0].Categories);
Assert.Null(t1[0].Id);
Assert.True(t1.NumFound > 0);
}

[Fact]
public void FilterAfterCastNotWorking()
{
IQueryable<DerivedDerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
.Where(p => p.Id != null && p.Categories.Any())
.Select(p => new DerivedDerivedProduct { Id2 = p.Id, Id3 = p.Id, Categories = p.Categories })
.Where(p => p.Id3 != null);

IQueryable<Product> q2 = derivedProducts.Cast<Product>().Where(p => p.Id != null);

Assert.Throws<InvalidOperationException>(() => q2.ToSolrQueryResults());
}

[Fact]
public void CastToWrongTypeNotWorking()
{
IQueryable<DerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
.Where(p => p.Id != null && p.Categories.Any())
.Select(p => new DerivedProduct { Id2 = p.Id, Categories = p.Categories })
.Where(p => p.Id2 != null);

var q2 = derivedProducts.Cast<DerivedDerivedProduct>();

Assert.Throws<InvalidCastException>(() => q2.ToSolrQueryResults());
}

[Fact]
public void MethodsWhichNotNeedContextWorksAfterCast()
{
IQueryable<DerivedDerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
.Where(p => p.Id != null && p.Categories.Any())
.Select(p => new DerivedDerivedProduct { Id2 = p.Id, Id3 = p.Id, Categories = p.Categories })
.Where(p => p.Id3 != null);

Product q2 = derivedProducts.Cast<Product>().Skip(1).Take(1).FirstOrDefault();

Assert.NotNull(q2);
}

[Fact]
public void SelectMultipleCopiesOfField()
{
IQueryable<DerivedDerivedProduct> q1 = Product.SolrOperations.Value.AsQueryable()
.Where(p => p.Id != null && p.Categories.Any())
.Select(p => new DerivedDerivedProduct { Id2 = p.Id, Id3 = p.Id, Categories = p.Categories })
.Where(p => p.Id2 != null);

var t1 = q1.ToSolrQueryResults();

Assert.NotNull(t1);
Assert.NotNull(t1[0].Id2);
Assert.Equal(t1[0].Id2, t1[0].Id3);
Assert.NotNull(t1[0].Categories);
Assert.Null(t1[0].Id);
Assert.True(t1.NumFound > 0);
}

[Fact]
public void SelectAnyAfterSelect()
{
IQueryable<DerivedProduct> derivedProducts = Product.SolrOperations.Value.AsQueryable()
.Where(p => p.Id != null)
.Select(p => new DerivedProduct {Id2 = p.Id, Categories = p.Categories})
.Where(p => p.Id2 != null && p.Categories.Any());

IQueryable<Product> q2 = derivedProducts.Cast<Product>();

var t1 = q2.ToSolrQueryResults();

Assert.NotNull(t1);
Assert.NotNull(t1[0].Categories);
Assert.Null(t1[0].Id);
Assert.True(t1.NumFound > 0);
}

[Fact]
public void SelectSameParameter()
{
var t1 = Product.SolrOperations.Value.AsQueryable().Where(p => p.Id != null)
.Select(p => p).Where(p => p.Id != null)
.ToSolrQueryResults();

Assert.NotNull(t1);
Assert.NotNull(t1[0].Id);
Assert.True(t1.NumFound > 0);
}

[Fact]
public void MultipleSelects()
{
Expand Down
2 changes: 1 addition & 1 deletion SolrNet.Linq/Expressions/ExpressionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static bool HasMemberAccess(this Expression expression, Type type)

if (expression is MemberExpression me)
{
if (me.Member.DeclaringType == type)
if (me.Member.DeclaringType!= null && me.Member.DeclaringType.IsAssignableFrom(type))
{
return true;
}
Expand Down
10 changes: 8 additions & 2 deletions SolrNet.Linq/Expressions/SelectMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace SolrNet.Linq.Expressions
public static class SelectMethod
{
public const string Select = nameof(Queryable.Select);
public static bool TryVisitSelect(this MethodCallExpression node, SelectExpressionsCollection options, MemberContext context, out SelectContext newContext)
public static bool TryVisitSelect(this MethodCallExpression node, SelectExpressionsCollection options, MemberContext context, out MemberContext newContext)
{
newContext = null;
bool result = node.Method.DeclaringType == typeof(Queryable) && node.Method.Name == Select;
Expand All @@ -31,14 +31,20 @@ public static bool TryVisitSelect(this MethodCallExpression node, SelectExpressi
newContext = new SelectContext(memberInit, context);
}

if (lambda.Body is ParameterExpression)
{
newContext = context;
return result;
}

if (newContext != null)
{
options.Fields.Clear();
SelectFieldsVisitor visitor = new SelectFieldsVisitor(context, options);
visitor.Visit(lambda.Body);

return result;
}
}
}

throw new InvalidOperationException($"Unable to translate '{Select}' method.");
Expand Down
19 changes: 19 additions & 0 deletions SolrNet.Linq/Impl/CastResponseParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Linq;
using SolrNet.Impl;

namespace SolrNet.Linq.Impl
{
public class CastResponseParser<TNew, TOld> : TransformationResponseParser<TNew, TOld>
{
public CastResponseParser(ISolrDocumentResponseParser<TOld> inner,
ISolrDocumentResponseParser<Dictionary<string, object>> dictionaryParser) : base(inner, dictionaryParser)
{
}

protected override TNew GetResult(TOld old, Dictionary<string, object> dictionary)
{
return Enumerable.Repeat(old, 1).Cast<TNew>().Single();
}
}
}
Loading