Skip to content
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
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,30 @@ IQueryable<Product> solrLinq = solr.AsQueryable(setup =>
// cat:(qwe)
Product[] result = solrLinq.Where(p => p.Categories.Any(s => s == "qwe")).ToArray();
```
### Select
- Anonymous and regular types with fields, pseudo field, functions and transformers
```
var result = solrLinq.Select(p =>
new {
p.Id,
p.Categories,
Qwe = Math.Pow(2,2), // evaluated locally
Next = new Product2 {Id = p.Id} // evaluated locally after selecting required info from solr
ValStr = SolrExpr.Transformers.Value("qwe"), // value transformer evaluated in solr
Score= SolrExpr.Fields.Score() // score pseudo field evaluated in solr
}).OrderBy(arg => arg.Score) // allowed to use expressions evaluated in solr for ordering
.ToSolrQueryResults();
```
- Combine Select with other methods
```
var result = solrLinq
.Where(p => p.Id != null)
.Select(p => new {p.Id, p.Price, p.Categories, Score= SolrExpr.Fields.Score()})
.Where(arg => arg.Categories.Any(s => s == "electronics"))
.OrderBy(arg => arg.Id).ThenBy(arg=>arg.Score)
.Select(arg => new {arg.Id})
.FirstOrDefault(arg2 => arg2.Id != null);
```
### Paging
- Top
- Skip
Expand Down
25 changes: 9 additions & 16 deletions SolrNet.IntegrationOData/Controllers/ValuesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading.Tasks;
using Community.OData.Linq;
using Community.OData.Linq.AspNetCore;
using Community.OData.Linq.Json;
using Microsoft.AspNetCore.Mvc;
using SolrNet.Impl.FieldSerializers;
using SolrNet.Linq;
Expand Down Expand Up @@ -31,12 +32,13 @@ public IActionResult Get()
"/api/values/1?$filter=Popularity ne null",
"/api/values/1?$filter=Popularity eq null",
"/api/values/1?$filter=Categories/any(c: c eq 'electronics')",
"/api/values/2?$select=Id,Price,Categories",
});
}

// GET api/values/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id, ODataQueryOptions odata)
[HttpGet("1")]
public ActionResult<string> Get1(ODataQueryOptions odata)
{
IQueryable<Product> query = this.Solr.AsQueryable(options =>
{
Expand All @@ -61,22 +63,13 @@ public ActionResult<string> Get(int id, ODataQueryOptions odata)
return this.Ok(query.OData().ApplyQueryOptionsWithoutSelectExpand(odata).ToSolrQueryResults());
}

// POST api/values
[HttpPost]
public void Post([FromBody] string value)
{
}

// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
// GET api/values/5
[HttpGet("2")]
public ActionResult<string> Get2(ODataQueryOptions odata)
{
}
IQueryable<Product> query = this.Solr.AsQueryable();

// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
return this.Ok(query.OData().ApplyQueryOptions(odata).ToJson());
}
}
}
1 change: 1 addition & 0 deletions SolrNet.IntegrationOData/SolrNet.IntegrationOData.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<PackageReference Include="Community.OData.Linq.AspNetCore" Version="1.4.0" />
<PackageReference Include="Community.OData.Linq.Json" Version="1.4.0" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="SolrNet.Microsoft.DependencyInjection" Version="1.0.10" />
</ItemGroup>
Expand Down
142 changes: 115 additions & 27 deletions SolrNet.Linq.IntegrationTests/SelectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class Product2

public decimal Price { get; set; }

public double Qwe { get; set; }
public double Score { get; set; }
}
public class SelectTests
{
Expand All @@ -23,10 +23,9 @@ public void AnonymousClass()
{
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
{
Assert.Equal("Qwe:pow(2,2)", qo.Fields.ElementAt(0));
Assert.Equal("Id:id", qo.Fields.ElementAt(1));
Assert.Equal("Price:price", qo.Fields.ElementAt(2));
Assert.Equal("Categories:cat", qo.Fields.ElementAt(3));
Assert.Equal("id", qo.Fields.ElementAt(0));
Assert.Equal("price", qo.Fields.ElementAt(1));
Assert.Equal("cat", qo.Fields.ElementAt(2));
}).Where(p => p.Id != null)
.Select(p => new {p.Id, p.Price, p.Categories, Qwe = Math.Pow(2,2) })
.Where(arg => arg.Categories.Any(s => s == "electronics"))
Expand All @@ -40,6 +39,89 @@ public void AnonymousClass()
Assert.True(t1.Price > 0);
}

[Fact]
public void AnonymousMemberWithConversion()
{
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
{
Assert.Equal("id", qo.Fields.ElementAt(0));
Assert.Equal("price", qo.Fields.ElementAt(1));
Assert.Equal("cat", qo.Fields.ElementAt(2));
}).Where(p => p.Id != null)
.Select(p => new { p.Id, Price = (int)p.Price, p.Categories, Qwe = Math.Pow(2, 2) })
.Where(arg => arg.Categories.Any(s => s == "electronics"))
.OrderBy(arg => arg.Id)
.FirstOrDefault();

Assert.NotNull(t1);
Assert.NotNull(t1.Id);
Assert.Equal(4, t1.Qwe);
Assert.True(t1.Categories.Count > 0);
Assert.True(t1.Price > 0);
}

[Fact]
public void AnonymousWithConstAndNext()
{
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
{
Assert.Equal("id", qo.Fields.ElementAt(0));
Assert.Equal("price", qo.Fields.ElementAt(1));
Assert.Equal("cat", qo.Fields.ElementAt(2));
}).Where(p => p.Id != null)
.Select(p => new {p.Id, p.Price, p.Categories, Qwe = "qwe", Next = new {p.Id}})
.Where(arg => arg.Categories.Any(s => s == "electronics"))
.OrderBy(arg => arg.Id)
.FirstOrDefault();

Assert.NotNull(t1);
Assert.NotNull(t1.Id);
Assert.NotNull(t1.Next);
Assert.Equal(t1.Next.Id, t1.Id);
Assert.Equal("qwe", t1.Qwe);
Assert.True(t1.Categories.Count > 0);
Assert.True(t1.Price > 0);
}

[Fact]
public void AnonymousIdAndScore()
{
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
{
Assert.Equal("id", qo.Fields.ElementAt(0));
Assert.Equal("v1731e0:score", qo.Fields.ElementAt(1));
})
.Select(p => new { p.Id, Score= SolrExpr.Fields.Score()})
.OrderBy(arg => arg.Score)
.FirstOrDefault();

Assert.NotNull(t1);
Assert.NotNull(t1.Id);
Assert.Equal(1, t1.Score);
}

[Fact]
public void AnonymousOrderByScore()
{
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
{
Assert.Equal("id", qo.Fields.ElementAt(0));
Assert.Equal("price", qo.Fields.ElementAt(1));
Assert.Equal("cat", qo.Fields.ElementAt(2));
Assert.Equal("v1731e0:score", qo.Fields.ElementAt(3));
}).Where(p => p.Id != null)
.Select(p => new { p.Id, p.Price, p.Categories, Score = SolrExpr.Fields.Score() })
.Where(arg => arg.Categories.Any(s => s == "electronics"))
.OrderBy(arg => arg.Id).ThenBy(arg=>arg.Score)
.FirstOrDefault();

Assert.NotNull(t1);
Assert.NotNull(t1.Id);
Assert.Equal(1, t1.Score);
Assert.True(t1.Categories.Count > 0);
Assert.True(t1.Price > 0);
}

[Fact]
public void AnonymousClassSolrResult()
{
Expand All @@ -63,9 +145,9 @@ public void MultipleSelects()
{
Assert.Equal(1, qo.Fields.Count);
Assert.Equal(3, qo.FilterQueries.Count);
Assert.Equal("Id:id", qo.Fields.ElementAt(0));
Assert.Equal("id", qo.Fields.ElementAt(0));
}).Where(p => p.Id != null)
.Select(p => new {p.Id, p.Price, p.Categories, Qwe = Math.Pow(2, 2)})
.Select(p => new {p.Id, p.Price, p.Categories})
.Where(arg => arg.Categories.Any(s => s == "electronics"))
.OrderBy(arg => arg.Id)
.Select(arg => new {arg.Id})
Expand All @@ -87,14 +169,23 @@ public void Transformers()
ValFloat = SolrExpr.Transformers.Value((float) 2),
ValDouble = SolrExpr.Transformers.Value((double) 3),
ValDate = SolrExpr.Transformers.Value(dateTime),
})
ExplText = SolrExpr.Transformers.ExplainText(),
ExplHtml = SolrExpr.Transformers.ExplainHtml(),
DocId = SolrExpr.Transformers.DocId()
}).Skip(1)
.First();

Assert.Equal("qwe", t1.ValStr);
Assert.Equal(1, t1.ValInt);
Assert.Equal(2f, t1.ValFloat);
Assert.Equal(3d, t1.ValDouble);
Assert.Equal(dateTime, t1.ValDate);

Assert.NotNull(t1.ExplText);

Assert.NotNull(t1.ExplHtml);

Assert.Equal(1, t1.DocId);
}

[Fact]
Expand All @@ -103,22 +194,21 @@ public void Product2()
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
{
Assert.Equal(4, qo.Fields.Count);
Assert.Equal("Qwe:pow(2,2)", qo.Fields.ElementAt(0));
Assert.Equal("Id:id", qo.Fields.ElementAt(1));
Assert.Equal("Price:price", qo.Fields.ElementAt(2));
Assert.Equal("Categories:cat", qo.Fields.ElementAt(3));
Assert.Equal("id", qo.Fields.ElementAt(0));
Assert.Equal("price", qo.Fields.ElementAt(1));
Assert.Equal("cat", qo.Fields.ElementAt(2));
Assert.Equal("v1731e0:score", qo.Fields.ElementAt(3));

Assert.Equal(3, qo.OrderBy.Count);
Assert.Equal(2, qo.OrderBy.Count);
Assert.Equal("id", qo.OrderBy.ElementAt(0).FieldName);
Assert.Equal("pow(2,2)", qo.OrderBy.ElementAt(1).FieldName);
Assert.Equal("pow(2,3)", qo.OrderBy.ElementAt(2).FieldName);
Assert.Equal("score", qo.OrderBy.ElementAt(1).FieldName);

Assert.Equal(2, qo.FilterQueries.Count);

}).Where(p => p.Id != null)
.Select(p => new Product2 {Id = p.Id, Price = p.Price, Categories = p.Categories, Qwe = Math.Pow(2, 2)})
.Select(p => new Product2 {Id = p.Id, Price = p.Price, Categories = p.Categories, Score = SolrExpr.Fields.Score()})
.Where(arg => arg.Categories.Any(s => s == "electronics"))
.OrderBy(arg => arg.Id).ThenBy(arg => arg.Qwe).ThenBy(arg => Math.Pow(2,3))
.OrderBy(arg => arg.Id).ThenBy(arg => arg.Score)
.FirstOrDefault();

Assert.NotNull(t1);
Expand All @@ -133,7 +223,7 @@ public void Product2()
Assert.Equal(t2.Id, t1.Id);

SolrQueryResults<Product2> t3 = Product.SolrOperations.Value.AsQueryable().Where(p => p.Id != null)
.Select(p => new Product2 {Id = p.Id, Price = p.Price, Categories = p.Categories, Qwe = Math.Pow(2, 2)})
.Select(p => new Product2 {Id = p.Id, Price = p.Price, Categories = p.Categories})
.Where(arg => arg.Categories.Any(s => s == "electronics"))
.OrderBy(arg => arg.Id).Take(1).ToSolrQueryResults();

Expand All @@ -146,21 +236,19 @@ public void Product2WithMemberProduct()
{
Assert.Throws<SolrConnectionException>(() => Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
{
Assert.Equal(4, qo.Fields.Count);
Assert.Equal("Price:sum(price,1)", qo.Fields.ElementAt(0));
Assert.Equal("Qwe:pow(2,2)", qo.Fields.ElementAt(1));
Assert.Equal("Id:id", qo.Fields.ElementAt(2));
Assert.Equal("Categories:cat", qo.Fields.ElementAt(3));
Assert.Equal(3, qo.Fields.Count);
Assert.Equal("id", qo.Fields.ElementAt(0));
Assert.Equal("price", qo.Fields.ElementAt(1));
Assert.Equal("v1731e0:score", qo.Fields.ElementAt(2));

Assert.Equal(3, qo.OrderBy.Count);
Assert.Equal("id", qo.OrderBy.ElementAt(0).FieldName);
Assert.Equal("sum(price,1)", qo.OrderBy.ElementAt(1).FieldName);
Assert.Equal("pow(2,3)", qo.OrderBy.ElementAt(2).FieldName);
Assert.Equal("sum(score,1)", qo.OrderBy.ElementAt(2).FieldName);
}).Where(p => p.Id != null)
.Select(p =>
new Product2 {Id = p.Id, Price = p.Price + 1, Categories = p.Categories, Qwe = Math.Pow(2, 2)})
.Where(arg => arg.Categories.Any(s => s == "electronics"))
.OrderBy(arg => arg.Id).ThenBy(arg => arg.Price).ThenBy(arg => Math.Pow(2, 3))
new Product2 {Id = p.Id, Price = p.Price + 1, Score = SolrExpr.Fields.Score() + 1})
.OrderBy(arg => arg.Id).ThenBy(arg => arg.Price).ThenBy(arg => arg.Score)
.FirstOrDefault());
}
}
Expand Down
27 changes: 23 additions & 4 deletions SolrNet.Linq/Expressions/Context/SelectContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class SelectContext : MemberContext
public Dictionary<MemberInfo, string> Members { get; } = new Dictionary<MemberInfo, string>();
public Dictionary<MemberInfo, string> Aliases { get; } = new Dictionary<MemberInfo, string>();

public Dictionary<MemberInfo, Expression> Calculated { get; } = new Dictionary<MemberInfo, Expression>();

public SelectContext(NewExpression expression, MemberContext parentContext)
{
NewExpression = expression ?? throw new ArgumentNullException(nameof(expression));
Expand All @@ -22,13 +24,19 @@ public SelectContext(NewExpression expression, MemberContext parentContext)
for (int i = 0; i < expression.Arguments.Count; i++)
{
Expression argument = expression.Arguments[i];
if (argument.NodeType != ExpressionType.MemberAccess)
if (argument is MemberExpression me && parentContext.IsAccessToMember(me))
{
Members.Add(expression.Members[i], parentContext.GetSolrMemberProduct(argument, true));
}
else if (argument is MethodCallExpression mc &&
(mc.Method.DeclaringType == typeof(SolrExpr.Transformers) ||
mc.Method.DeclaringType == typeof(SolrExpr.Fields)))
{
Aliases.Add(expression.Members[i], parentContext.GetSolrMemberProduct(argument));
}
else
{
Members.Add(expression.Members[i], parentContext.GetSolrMemberProduct(argument, true));
Calculated.Add(expression.Members[i], argument);
}
}
}
Expand All @@ -40,13 +48,19 @@ public SelectContext(MemberInitExpression expression, MemberContext parentContex

foreach (MemberAssignment binding in expression.Bindings.OfType<MemberAssignment>())
{
if (binding.Expression.NodeType != ExpressionType.MemberAccess)
if (binding.Expression is MemberExpression me && parentContext.IsAccessToMember(me))
{
Members.Add(binding.Member, parentContext.GetSolrMemberProduct(binding.Expression, true));
}
else if (binding.Expression is MethodCallExpression mc &&
(mc.Method.DeclaringType == typeof(SolrExpr.Transformers) ||
mc.Method.DeclaringType == typeof(SolrExpr.Fields)))
{
Aliases.Add(binding.Member, parentContext.GetSolrMemberProduct(binding.Expression));
}
else
{
Members.Add(binding.Member, parentContext.GetSolrMemberProduct(binding.Expression, true));
Calculated.Add(binding.Member, binding.Expression);
}
}
}
Expand All @@ -70,6 +84,11 @@ public override string GetSolrMemberProduct(Expression expression, bool disableF
{
return Aliases[me.Member];
}

if (Calculated.ContainsKey(me.Member) && disableFunctions == false)
{
return ParentContext.GetSolrMemberProduct(Calculated[me.Member]);
}
}

return expression.GetSolrMemberProduct(this, disableFunctions);
Expand Down
Loading