Skip to content

Commit e9193f4

Browse files
author
IharYakimush
authored
Merge pull request #3 from IharYakimush/develop
support select method
2 parents 871a2bd + 4c0794a commit e9193f4

21 files changed

+547
-118
lines changed

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,30 @@ IQueryable<Product> solrLinq = solr.AsQueryable(setup =>
102102
// cat:(qwe)
103103
Product[] result = solrLinq.Where(p => p.Categories.Any(s => s == "qwe")).ToArray();
104104
```
105+
### Select
106+
- Anonymous and regular types with fields, pseudo field, functions and transformers
107+
```
108+
var result = solrLinq.Select(p =>
109+
new {
110+
p.Id,
111+
p.Categories,
112+
Qwe = Math.Pow(2,2), // evaluated locally
113+
Next = new Product2 {Id = p.Id} // evaluated locally after selecting required info from solr
114+
ValStr = SolrExpr.Transformers.Value("qwe"), // value transformer evaluated in solr
115+
Score= SolrExpr.Fields.Score() // score pseudo field evaluated in solr
116+
}).OrderBy(arg => arg.Score) // allowed to use expressions evaluated in solr for ordering
117+
.ToSolrQueryResults();
118+
```
119+
- Combine Select with other methods
120+
```
121+
var result = solrLinq
122+
.Where(p => p.Id != null)
123+
.Select(p => new {p.Id, p.Price, p.Categories, Score= SolrExpr.Fields.Score()})
124+
.Where(arg => arg.Categories.Any(s => s == "electronics"))
125+
.OrderBy(arg => arg.Id).ThenBy(arg=>arg.Score)
126+
.Select(arg => new {arg.Id})
127+
.FirstOrDefault(arg2 => arg2.Id != null);
128+
```
105129
### Paging
106130
- Top
107131
- Skip

SolrNet.IntegrationOData/Controllers/ValuesController.cs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Threading.Tasks;
55
using Community.OData.Linq;
66
using Community.OData.Linq.AspNetCore;
7+
using Community.OData.Linq.Json;
78
using Microsoft.AspNetCore.Mvc;
89
using SolrNet.Impl.FieldSerializers;
910
using SolrNet.Linq;
@@ -31,12 +32,13 @@ public IActionResult Get()
3132
"/api/values/1?$filter=Popularity ne null",
3233
"/api/values/1?$filter=Popularity eq null",
3334
"/api/values/1?$filter=Categories/any(c: c eq 'electronics')",
35+
"/api/values/2?$select=Id,Price,Categories",
3436
});
3537
}
3638

3739
// GET api/values/5
38-
[HttpGet("{id}")]
39-
public ActionResult<string> Get(int id, ODataQueryOptions odata)
40+
[HttpGet("1")]
41+
public ActionResult<string> Get1(ODataQueryOptions odata)
4042
{
4143
IQueryable<Product> query = this.Solr.AsQueryable(options =>
4244
{
@@ -61,22 +63,13 @@ public ActionResult<string> Get(int id, ODataQueryOptions odata)
6163
return this.Ok(query.OData().ApplyQueryOptionsWithoutSelectExpand(odata).ToSolrQueryResults());
6264
}
6365

64-
// POST api/values
65-
[HttpPost]
66-
public void Post([FromBody] string value)
67-
{
68-
}
69-
70-
// PUT api/values/5
71-
[HttpPut("{id}")]
72-
public void Put(int id, [FromBody] string value)
66+
// GET api/values/5
67+
[HttpGet("2")]
68+
public ActionResult<string> Get2(ODataQueryOptions odata)
7369
{
74-
}
70+
IQueryable<Product> query = this.Solr.AsQueryable();
7571

76-
// DELETE api/values/5
77-
[HttpDelete("{id}")]
78-
public void Delete(int id)
79-
{
72+
return this.Ok(query.OData().ApplyQueryOptions(odata).ToJson());
8073
}
8174
}
8275
}

SolrNet.IntegrationOData/SolrNet.IntegrationOData.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
<ItemGroup>
1212
<PackageReference Include="Community.OData.Linq.AspNetCore" Version="1.4.0" />
13+
<PackageReference Include="Community.OData.Linq.Json" Version="1.4.0" />
1314
<PackageReference Include="Microsoft.AspNetCore.App" />
1415
<PackageReference Include="SolrNet.Microsoft.DependencyInjection" Version="1.0.10" />
1516
</ItemGroup>

SolrNet.Linq.IntegrationTests/SelectTests.cs

Lines changed: 115 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class Product2
1414

1515
public decimal Price { get; set; }
1616

17-
public double Qwe { get; set; }
17+
public double Score { get; set; }
1818
}
1919
public class SelectTests
2020
{
@@ -23,10 +23,9 @@ public void AnonymousClass()
2323
{
2424
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
2525
{
26-
Assert.Equal("Qwe:pow(2,2)", qo.Fields.ElementAt(0));
27-
Assert.Equal("Id:id", qo.Fields.ElementAt(1));
28-
Assert.Equal("Price:price", qo.Fields.ElementAt(2));
29-
Assert.Equal("Categories:cat", qo.Fields.ElementAt(3));
26+
Assert.Equal("id", qo.Fields.ElementAt(0));
27+
Assert.Equal("price", qo.Fields.ElementAt(1));
28+
Assert.Equal("cat", qo.Fields.ElementAt(2));
3029
}).Where(p => p.Id != null)
3130
.Select(p => new {p.Id, p.Price, p.Categories, Qwe = Math.Pow(2,2) })
3231
.Where(arg => arg.Categories.Any(s => s == "electronics"))
@@ -40,6 +39,89 @@ public void AnonymousClass()
4039
Assert.True(t1.Price > 0);
4140
}
4241

42+
[Fact]
43+
public void AnonymousMemberWithConversion()
44+
{
45+
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
46+
{
47+
Assert.Equal("id", qo.Fields.ElementAt(0));
48+
Assert.Equal("price", qo.Fields.ElementAt(1));
49+
Assert.Equal("cat", qo.Fields.ElementAt(2));
50+
}).Where(p => p.Id != null)
51+
.Select(p => new { p.Id, Price = (int)p.Price, p.Categories, Qwe = Math.Pow(2, 2) })
52+
.Where(arg => arg.Categories.Any(s => s == "electronics"))
53+
.OrderBy(arg => arg.Id)
54+
.FirstOrDefault();
55+
56+
Assert.NotNull(t1);
57+
Assert.NotNull(t1.Id);
58+
Assert.Equal(4, t1.Qwe);
59+
Assert.True(t1.Categories.Count > 0);
60+
Assert.True(t1.Price > 0);
61+
}
62+
63+
[Fact]
64+
public void AnonymousWithConstAndNext()
65+
{
66+
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
67+
{
68+
Assert.Equal("id", qo.Fields.ElementAt(0));
69+
Assert.Equal("price", qo.Fields.ElementAt(1));
70+
Assert.Equal("cat", qo.Fields.ElementAt(2));
71+
}).Where(p => p.Id != null)
72+
.Select(p => new {p.Id, p.Price, p.Categories, Qwe = "qwe", Next = new {p.Id}})
73+
.Where(arg => arg.Categories.Any(s => s == "electronics"))
74+
.OrderBy(arg => arg.Id)
75+
.FirstOrDefault();
76+
77+
Assert.NotNull(t1);
78+
Assert.NotNull(t1.Id);
79+
Assert.NotNull(t1.Next);
80+
Assert.Equal(t1.Next.Id, t1.Id);
81+
Assert.Equal("qwe", t1.Qwe);
82+
Assert.True(t1.Categories.Count > 0);
83+
Assert.True(t1.Price > 0);
84+
}
85+
86+
[Fact]
87+
public void AnonymousIdAndScore()
88+
{
89+
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
90+
{
91+
Assert.Equal("id", qo.Fields.ElementAt(0));
92+
Assert.Equal("v1731e0:score", qo.Fields.ElementAt(1));
93+
})
94+
.Select(p => new { p.Id, Score= SolrExpr.Fields.Score()})
95+
.OrderBy(arg => arg.Score)
96+
.FirstOrDefault();
97+
98+
Assert.NotNull(t1);
99+
Assert.NotNull(t1.Id);
100+
Assert.Equal(1, t1.Score);
101+
}
102+
103+
[Fact]
104+
public void AnonymousOrderByScore()
105+
{
106+
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
107+
{
108+
Assert.Equal("id", qo.Fields.ElementAt(0));
109+
Assert.Equal("price", qo.Fields.ElementAt(1));
110+
Assert.Equal("cat", qo.Fields.ElementAt(2));
111+
Assert.Equal("v1731e0:score", qo.Fields.ElementAt(3));
112+
}).Where(p => p.Id != null)
113+
.Select(p => new { p.Id, p.Price, p.Categories, Score = SolrExpr.Fields.Score() })
114+
.Where(arg => arg.Categories.Any(s => s == "electronics"))
115+
.OrderBy(arg => arg.Id).ThenBy(arg=>arg.Score)
116+
.FirstOrDefault();
117+
118+
Assert.NotNull(t1);
119+
Assert.NotNull(t1.Id);
120+
Assert.Equal(1, t1.Score);
121+
Assert.True(t1.Categories.Count > 0);
122+
Assert.True(t1.Price > 0);
123+
}
124+
43125
[Fact]
44126
public void AnonymousClassSolrResult()
45127
{
@@ -63,9 +145,9 @@ public void MultipleSelects()
63145
{
64146
Assert.Equal(1, qo.Fields.Count);
65147
Assert.Equal(3, qo.FilterQueries.Count);
66-
Assert.Equal("Id:id", qo.Fields.ElementAt(0));
148+
Assert.Equal("id", qo.Fields.ElementAt(0));
67149
}).Where(p => p.Id != null)
68-
.Select(p => new {p.Id, p.Price, p.Categories, Qwe = Math.Pow(2, 2)})
150+
.Select(p => new {p.Id, p.Price, p.Categories})
69151
.Where(arg => arg.Categories.Any(s => s == "electronics"))
70152
.OrderBy(arg => arg.Id)
71153
.Select(arg => new {arg.Id})
@@ -87,14 +169,23 @@ public void Transformers()
87169
ValFloat = SolrExpr.Transformers.Value((float) 2),
88170
ValDouble = SolrExpr.Transformers.Value((double) 3),
89171
ValDate = SolrExpr.Transformers.Value(dateTime),
90-
})
172+
ExplText = SolrExpr.Transformers.ExplainText(),
173+
ExplHtml = SolrExpr.Transformers.ExplainHtml(),
174+
DocId = SolrExpr.Transformers.DocId()
175+
}).Skip(1)
91176
.First();
92177

93178
Assert.Equal("qwe", t1.ValStr);
94179
Assert.Equal(1, t1.ValInt);
95180
Assert.Equal(2f, t1.ValFloat);
96181
Assert.Equal(3d, t1.ValDouble);
97182
Assert.Equal(dateTime, t1.ValDate);
183+
184+
Assert.NotNull(t1.ExplText);
185+
186+
Assert.NotNull(t1.ExplHtml);
187+
188+
Assert.Equal(1, t1.DocId);
98189
}
99190

100191
[Fact]
@@ -103,22 +194,21 @@ public void Product2()
103194
var t1 = Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
104195
{
105196
Assert.Equal(4, qo.Fields.Count);
106-
Assert.Equal("Qwe:pow(2,2)", qo.Fields.ElementAt(0));
107-
Assert.Equal("Id:id", qo.Fields.ElementAt(1));
108-
Assert.Equal("Price:price", qo.Fields.ElementAt(2));
109-
Assert.Equal("Categories:cat", qo.Fields.ElementAt(3));
197+
Assert.Equal("id", qo.Fields.ElementAt(0));
198+
Assert.Equal("price", qo.Fields.ElementAt(1));
199+
Assert.Equal("cat", qo.Fields.ElementAt(2));
200+
Assert.Equal("v1731e0:score", qo.Fields.ElementAt(3));
110201

111-
Assert.Equal(3, qo.OrderBy.Count);
202+
Assert.Equal(2, qo.OrderBy.Count);
112203
Assert.Equal("id", qo.OrderBy.ElementAt(0).FieldName);
113-
Assert.Equal("pow(2,2)", qo.OrderBy.ElementAt(1).FieldName);
114-
Assert.Equal("pow(2,3)", qo.OrderBy.ElementAt(2).FieldName);
204+
Assert.Equal("score", qo.OrderBy.ElementAt(1).FieldName);
115205

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

118208
}).Where(p => p.Id != null)
119-
.Select(p => new Product2 {Id = p.Id, Price = p.Price, Categories = p.Categories, Qwe = Math.Pow(2, 2)})
209+
.Select(p => new Product2 {Id = p.Id, Price = p.Price, Categories = p.Categories, Score = SolrExpr.Fields.Score()})
120210
.Where(arg => arg.Categories.Any(s => s == "electronics"))
121-
.OrderBy(arg => arg.Id).ThenBy(arg => arg.Qwe).ThenBy(arg => Math.Pow(2,3))
211+
.OrderBy(arg => arg.Id).ThenBy(arg => arg.Score)
122212
.FirstOrDefault();
123213

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

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

@@ -146,21 +236,19 @@ public void Product2WithMemberProduct()
146236
{
147237
Assert.Throws<SolrConnectionException>(() => Product.SolrOperations.Value.AsQueryable(lo => lo.SetupQueryOptions = qo =>
148238
{
149-
Assert.Equal(4, qo.Fields.Count);
150-
Assert.Equal("Price:sum(price,1)", qo.Fields.ElementAt(0));
151-
Assert.Equal("Qwe:pow(2,2)", qo.Fields.ElementAt(1));
152-
Assert.Equal("Id:id", qo.Fields.ElementAt(2));
153-
Assert.Equal("Categories:cat", qo.Fields.ElementAt(3));
239+
Assert.Equal(3, qo.Fields.Count);
240+
Assert.Equal("id", qo.Fields.ElementAt(0));
241+
Assert.Equal("price", qo.Fields.ElementAt(1));
242+
Assert.Equal("v1731e0:score", qo.Fields.ElementAt(2));
154243

155244
Assert.Equal(3, qo.OrderBy.Count);
156245
Assert.Equal("id", qo.OrderBy.ElementAt(0).FieldName);
157246
Assert.Equal("sum(price,1)", qo.OrderBy.ElementAt(1).FieldName);
158-
Assert.Equal("pow(2,3)", qo.OrderBy.ElementAt(2).FieldName);
247+
Assert.Equal("sum(score,1)", qo.OrderBy.ElementAt(2).FieldName);
159248
}).Where(p => p.Id != null)
160249
.Select(p =>
161-
new Product2 {Id = p.Id, Price = p.Price + 1, Categories = p.Categories, Qwe = Math.Pow(2, 2)})
162-
.Where(arg => arg.Categories.Any(s => s == "electronics"))
163-
.OrderBy(arg => arg.Id).ThenBy(arg => arg.Price).ThenBy(arg => Math.Pow(2, 3))
250+
new Product2 {Id = p.Id, Price = p.Price + 1, Score = SolrExpr.Fields.Score() + 1})
251+
.OrderBy(arg => arg.Id).ThenBy(arg => arg.Price).ThenBy(arg => arg.Score)
164252
.FirstOrDefault());
165253
}
166254
}

SolrNet.Linq/Expressions/Context/SelectContext.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public class SelectContext : MemberContext
1414
public Dictionary<MemberInfo, string> Members { get; } = new Dictionary<MemberInfo, string>();
1515
public Dictionary<MemberInfo, string> Aliases { get; } = new Dictionary<MemberInfo, string>();
1616

17+
public Dictionary<MemberInfo, Expression> Calculated { get; } = new Dictionary<MemberInfo, Expression>();
18+
1719
public SelectContext(NewExpression expression, MemberContext parentContext)
1820
{
1921
NewExpression = expression ?? throw new ArgumentNullException(nameof(expression));
@@ -22,13 +24,19 @@ public SelectContext(NewExpression expression, MemberContext parentContext)
2224
for (int i = 0; i < expression.Arguments.Count; i++)
2325
{
2426
Expression argument = expression.Arguments[i];
25-
if (argument.NodeType != ExpressionType.MemberAccess)
27+
if (argument is MemberExpression me && parentContext.IsAccessToMember(me))
28+
{
29+
Members.Add(expression.Members[i], parentContext.GetSolrMemberProduct(argument, true));
30+
}
31+
else if (argument is MethodCallExpression mc &&
32+
(mc.Method.DeclaringType == typeof(SolrExpr.Transformers) ||
33+
mc.Method.DeclaringType == typeof(SolrExpr.Fields)))
2634
{
2735
Aliases.Add(expression.Members[i], parentContext.GetSolrMemberProduct(argument));
2836
}
2937
else
3038
{
31-
Members.Add(expression.Members[i], parentContext.GetSolrMemberProduct(argument, true));
39+
Calculated.Add(expression.Members[i], argument);
3240
}
3341
}
3442
}
@@ -40,13 +48,19 @@ public SelectContext(MemberInitExpression expression, MemberContext parentContex
4048

4149
foreach (MemberAssignment binding in expression.Bindings.OfType<MemberAssignment>())
4250
{
43-
if (binding.Expression.NodeType != ExpressionType.MemberAccess)
51+
if (binding.Expression is MemberExpression me && parentContext.IsAccessToMember(me))
52+
{
53+
Members.Add(binding.Member, parentContext.GetSolrMemberProduct(binding.Expression, true));
54+
}
55+
else if (binding.Expression is MethodCallExpression mc &&
56+
(mc.Method.DeclaringType == typeof(SolrExpr.Transformers) ||
57+
mc.Method.DeclaringType == typeof(SolrExpr.Fields)))
4458
{
4559
Aliases.Add(binding.Member, parentContext.GetSolrMemberProduct(binding.Expression));
4660
}
4761
else
4862
{
49-
Members.Add(binding.Member, parentContext.GetSolrMemberProduct(binding.Expression, true));
63+
Calculated.Add(binding.Member, binding.Expression);
5064
}
5165
}
5266
}
@@ -70,6 +84,11 @@ public override string GetSolrMemberProduct(Expression expression, bool disableF
7084
{
7185
return Aliases[me.Member];
7286
}
87+
88+
if (Calculated.ContainsKey(me.Member) && disableFunctions == false)
89+
{
90+
return ParentContext.GetSolrMemberProduct(Calculated[me.Member]);
91+
}
7392
}
7493

7594
return expression.GetSolrMemberProduct(this, disableFunctions);

0 commit comments

Comments
 (0)