Skip to content

Commit cdefde9

Browse files
Fix filter in a collection of primitive values.
1 parent e97e196 commit cdefde9

File tree

2 files changed

+89
-1
lines changed

2 files changed

+89
-1
lines changed

src/Microsoft.OData.Core/UriParser/Binders/InBinder.cs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace Microsoft.OData.UriParser
1313
using System.Text;
1414
using Microsoft.OData.Edm;
1515
using Microsoft.OData.Core;
16+
using System.Collections.Generic;
1617

1718
/// <summary>
1819
/// Class that knows how to bind the In operator.
@@ -129,7 +130,7 @@ private CollectionNode GetCollectionOperandFromToken(QueryToken queryToken, IEdm
129130
Debug.Assert(expectedType.IsCollection());
130131
string expectedTypeFullName = expectedType.Definition.AsElementType().FullTypeName();
131132

132-
if (expectedTypeFullName.Equals("Edm.String", StringComparison.Ordinal) || expectedTypeFullName.Equals("Edm.Untyped", StringComparison.Ordinal))
133+
if (expectedTypeFullName.Equals("Edm.String", StringComparison.Ordinal) || (expectedTypeFullName.Equals("Edm.Untyped", StringComparison.Ordinal) && IsCollectionContentEmptyOrSpaces(bracketLiteralText)))
133134
{
134135
// For collection of strings, need to convert single-quoted string to double-quoted string,
135136
// and also, per ABNF, a single quote within a string literal is "encoded" as two consecutive single quotes in either
@@ -423,5 +424,76 @@ private static string NormalizeDateTimeCollectionItems(string bracketLiteralText
423424

424425
return "[" + String.Join(",", items) + "]";
425426
}
427+
428+
private static bool IsCollectionContentEmptyOrSpaces(string bracketLiteralText)
429+
{
430+
if (string.IsNullOrWhiteSpace(bracketLiteralText) || bracketLiteralText.Length < 2)
431+
{
432+
return true;
433+
}
434+
435+
string content = bracketLiteralText[1..^1].Trim();
436+
437+
if (string.IsNullOrWhiteSpace(content))
438+
{
439+
return true;
440+
}
441+
442+
bool isEmptyOrHasOnlySpaces = true;
443+
bool isCharinsideQuotes = false;
444+
char quoteChar = '\0';
445+
Span<char> buffer = stackalloc char[content.Length];
446+
int bufferIndex = 0;
447+
448+
for (int i = 0; i < content.Length; i++)
449+
{
450+
char c = content[i];
451+
452+
if (isCharinsideQuotes)
453+
{
454+
if (c == quoteChar)
455+
{
456+
isCharinsideQuotes = false;
457+
}
458+
buffer[bufferIndex++] = c;
459+
}
460+
else
461+
{
462+
if (c == '"' || c == '\'')
463+
{
464+
isCharinsideQuotes = true;
465+
quoteChar = c;
466+
buffer[bufferIndex++] = c;
467+
}
468+
else if (c == ',')
469+
{
470+
string item = new string(buffer[..bufferIndex]).Trim().Trim('\'', '"');
471+
472+
if (!string.IsNullOrWhiteSpace(item))
473+
{
474+
isEmptyOrHasOnlySpaces = false;
475+
break;
476+
}
477+
bufferIndex = 0;
478+
}
479+
else
480+
{
481+
buffer[bufferIndex++] = c;
482+
}
483+
}
484+
}
485+
486+
if (bufferIndex > 0)
487+
{
488+
string lastItem = new string(buffer[..bufferIndex]).Trim().Trim('\'', '"');
489+
490+
if (!string.IsNullOrWhiteSpace(lastItem))
491+
{
492+
isEmptyOrHasOnlySpaces = false;
493+
}
494+
}
495+
496+
return isEmptyOrHasOnlySpaces;
497+
}
426498
}
427499
}

test/UnitTests/Microsoft.OData.Core.Tests/ScenarioTests/UriParser/FilterAndOrderByFunctionalTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2130,6 +2130,22 @@ public void FilterWithInOperationWithParensCollection()
21302130
Assert.Equal("(1,2,3)", Assert.IsType<CollectionConstantNode>(inNode.Right).LiteralText);
21312131
}
21322132

2133+
[Theory]
2134+
[InlineData("TestInt", "(1,2,3)")]
2135+
[InlineData("TestDouble", "(1.1,2.2,3.3)")]
2136+
[InlineData("TestBool", "(true,false)")]
2137+
[InlineData("TestString", "('a','b','c')")]
2138+
[InlineData("TestDecimal", "(1.1,2.2,3.3)")]
2139+
public void FilterWithInOperationWithParensCollectionConsistingOfDynamicPrimitiveProperties(string propertyName, string values)
2140+
{
2141+
string filterExpression = $"{propertyName} in {values}";
2142+
FilterClause filter = ParseFilter(filterExpression, HardCodedTestModel.TestModel, HardCodedTestModel.GetOpenEmployeeType());
2143+
2144+
var inNode = Assert.IsType<InNode>(filter.Expression);
2145+
Assert.IsType<SingleValueOpenPropertyAccessNode>(inNode.Left);
2146+
Assert.Equal(values, Assert.IsType<CollectionConstantNode>(inNode.Right).LiteralText);
2147+
}
2148+
21332149
[Fact]
21342150
public void FilterWithInOperationWithParensCollectionAndLogicalNotOperator()
21352151
{

0 commit comments

Comments
 (0)