Skip to content

Commit

Permalink
storing what we have so far
Browse files Browse the repository at this point in the history
  • Loading branch information
slorello89 committed Nov 20, 2024
1 parent 7783fa3 commit dcd1fe0
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/Redis.OM/Common/ExpressionParserUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,44 @@ internal static string EscapeTagField(string text)
return sb.ToString();
}

/// <summary>
/// Checks the expression if it resolves to null.
/// </summary>
/// <param name="expression">The expression to check.</param>
/// <returns>whether it resolves to null.</returns>
internal static bool ExpressionResolvesToNull(Expression expression)
{
if (expression.NodeType is ExpressionType.Constant && ((ConstantExpression)expression).Value is null)
{
return true;
}

if (expression.NodeType is ExpressionType.MemberAccess)
{
var parentExpression = expression;
var memberInfos = new Stack<MemberInfo>();
while (parentExpression is MemberExpression parentMember)
{
var info = ((MemberExpression)parentExpression).Member;
memberInfos.Push(info);
parentExpression = parentMember.Expression;
}

if (parentExpression is ConstantExpression c)
{
var resolved = c.Value;
foreach (var info in memberInfos)
{
resolved = GetValue(info, resolved);
}

return resolved is null;
}
}

return false;
}

private static string GetOperandStringForMember(MemberExpression member, bool treatEnumsAsInt = false, bool negate = false, bool treatBooleanMemberAsUnary = false)
{
var memberPath = new List<string>();
Expand Down
7 changes: 7 additions & 0 deletions src/Redis.OM/Common/ExpressionTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,13 @@ internal static string TranslateBinaryExpression(BinaryExpression binExpression,
{
var leftContent = ExpressionParserUtilities.GetOperandStringForQueryArgs(binExpression.Left, parameters, treatBooleanMemberAsUnary: true);

var rightResolvesToNull = ExpressionParserUtilities.ExpressionResolvesToNull(binExpression.Right);

if (rightResolvesToNull)
{
return $"(ismissing({leftContent}))";
}

var rightContent = ExpressionParserUtilities.GetOperandStringForQueryArgs(binExpression.Right, parameters, treatBooleanMemberAsUnary: true);

if (binExpression.Left is MemberExpression member)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Redis.OM.Modeling;

namespace Redis.OM.Unit.Tests.RediSearchTests;

[Document(StorageType = StorageType.Json)]
public class ObjectWithNullableStrings
{
[RedisIdField]
[Indexed]
public string Id { get; set; }

[Indexed]
public string? String1 { get; set; }

[Indexed]
public string? String2 { get; set; }
}
53 changes: 53 additions & 0 deletions test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4026,5 +4026,58 @@ public void TestToQueryString()

Assert.Equal(command, queryString);
}

[Fact]
public async Task TestQueryForNull()
{
_substitute.ClearSubstitute();
_substitute.ExecuteAsync(Arg.Any<string>(), Arg.Any<object[]>()).Returns(_mockReply);
var collection = new RedisCollection<ObjectWithNullableStrings>(_substitute);
string? val = null;
await collection.Where(x => x.String1 == null).ToListAsync();
await _substitute.Received().ExecuteAsync("FT.SEARCH",
$"{nameof(ObjectWithNullableStrings).ToLower()}-idx",
"(ismissing(@String1))",
"LIMIT",
"DIALECT",
2,
"0",
"100");

_substitute.ClearSubstitute();
_substitute.ExecuteAsync(Arg.Any<string>(), Arg.Any<object[]>()).Returns(_mockReply);
await collection.Where(x => x.String1 == val).ToListAsync();
await _substitute.Received().ExecuteAsync("FT.SEARCH",
$"{nameof(ObjectWithNullableStrings).ToLower()}-idx",
"(ismissing(@String1))",
"LIMIT",
"DIALECT",
2,
"0",
"100");

_substitute.ClearSubstitute();

var obj = new
{
inner = new
{
val = (string?)null
}
};

_substitute.ExecuteAsync(Arg.Any<string>(), Arg.Any<object[]>()).Returns(_mockReply);
await collection.Where(x => x.String2 == obj.inner.val).ToListAsync();
await _substitute.Received().ExecuteAsync("FT.SEARCH",
$"{nameof(ObjectWithNullableStrings).ToLower()}-idx",
"(ismissing(@String2))",
"LIMIT",
"DIALECT",
2,
"0",
"100");

}

}
}

0 comments on commit dcd1fe0

Please sign in to comment.