Skip to content

Commit 0309d7c

Browse files
authored
Consolidate OneOrMany implementation and its usage. (#513)
1 parent 2176ce2 commit 0309d7c

File tree

5 files changed

+61
-15
lines changed

5 files changed

+61
-15
lines changed

src/Ardalis.Specification.EntityFrameworkCore/Evaluators/SearchEvaluator.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,9 @@ public IQueryable<T> GetQuery<T>(IQueryable<T> query, ISpecification<T> specific
2020
return query.ApplySingleLike(searchExpression);
2121
}
2222

23-
if (spec.OneOrManySearchExpressions.Values is List<SearchExpressionInfo<T>> list)
24-
{
25-
var span = CollectionsMarshal.AsSpan(list);
26-
return ApplyLike(query, span);
27-
}
23+
// The search expressions are already sorted by SearchGroup.
24+
var span = CollectionsMarshal.AsSpan(spec.OneOrManySearchExpressions.List);
25+
return ApplyLike(query, span);
2826
}
2927

3028

src/Ardalis.Specification/Evaluators/SearchMemoryEvaluator.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@ public IEnumerable<T> Evaluate<T>(IEnumerable<T> query, ISpecification<T> specif
1818
return new SpecSingleLikeIterator<T>(query, searchExpression);
1919
}
2020

21-
if (spec.OneOrManySearchExpressions.Values is List<SearchExpressionInfo<T>> list)
22-
{
23-
// The search expressions are already sorted by SearchGroup.
24-
return new SpecLikeIterator<T>(query, list);
25-
}
21+
// The search expressions are already sorted by SearchGroup.
22+
return new SpecLikeIterator<T>(query, spec.OneOrManySearchExpressions.List);
2623
}
2724

2825
return query;

src/Ardalis.Specification/Internals/OneOrMany.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,27 @@ public void AddSorted(T item, IComparer<T> comparer)
6868
}
6969
}
7070

71+
/// <summary>
72+
/// Gets the list value stored in the instance.
73+
/// </summary>
74+
/// <exception cref="InvalidOperationException">Thrown if the value is Empty or Single.</exception>
75+
public readonly List<T> List
76+
{
77+
get
78+
{
79+
if (_value is List<T> list)
80+
{
81+
return list;
82+
}
83+
84+
throw new InvalidOperationException("The value is not a list.");
85+
}
86+
}
87+
88+
/// <summary>
89+
/// Gets the single value stored in the instance.
90+
/// </summary>
91+
/// <exception cref="InvalidOperationException">Thrown if the value is Empty or Many.</exception>
7192
public readonly T Single
7293
{
7394
get
@@ -81,6 +102,10 @@ public readonly T Single
81102
}
82103
}
83104

105+
/// <summary>
106+
/// Gets the single value stored in the instance.
107+
/// If the value is Empty or Many, returns null.
108+
/// </summary>
84109
public readonly T? SingleOrDefault
85110
{
86111
get

src/Ardalis.Specification/Validators/SearchValidator.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,8 @@ public bool IsValid<T>(T entity, ISpecification<T> specification)
1616
return searchExpression.SelectorFunc(entity)?.Like(searchExpression.SearchTerm) ?? false;
1717
}
1818

19-
if (spec.OneOrManySearchExpressions.Values is List<SearchExpressionInfo<T>> list)
20-
{
21-
// The search expressions are already sorted by SearchGroup.
22-
return IsValid<T>(entity, list);
23-
}
19+
// The search expressions are already sorted by SearchGroup.
20+
return IsValid(entity, spec.OneOrManySearchExpressions.List);
2421
}
2522

2623
return true;

tests/Ardalis.Specification.Tests/Internals/OneOrManyTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,35 @@ public void AddSorted_DoesNothing_GivenInvalidState()
184184
value.Should().BeEquivalentTo(new string[] { "foo", "bar" });
185185
}
186186

187+
[Fact]
188+
public void List_ReturnsList_GivenMultipleItems()
189+
{
190+
var oneOrMany = new OneOrMany<string>();
191+
Accessors.ValueOf(ref oneOrMany) = new List<string> { "foo", "bar" };
192+
193+
oneOrMany.List.Should().BeOfType<List<string>>();
194+
oneOrMany.List.Should().Equal(new List<string> { "foo", "bar" });
195+
}
196+
197+
[Fact]
198+
public void List_Throws_GivenEmptyStruct()
199+
{
200+
var oneOrMany = new OneOrMany<string>();
201+
202+
var action = () => oneOrMany.List;
203+
action.Should().Throw<InvalidOperationException>();
204+
}
205+
206+
[Fact]
207+
public void List_Throws_GivenSingleItem()
208+
{
209+
var oneOrMany = new OneOrMany<string>();
210+
Accessors.ValueOf(ref oneOrMany) = "foo";
211+
212+
var action = () => _ = oneOrMany.List;
213+
action.Should().Throw<InvalidOperationException>();
214+
}
215+
187216
[Fact]
188217
public void Single_ReturnsSingleItem_GivenSingleItem()
189218
{

0 commit comments

Comments
 (0)