Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String extension method MatchContains throws System.InvalidOperationException: Unable to parse method MatchContains #481

Open
obradl opened this issue Sep 10, 2024 · 4 comments

Comments

@obradl
Copy link

obradl commented Sep 10, 2024

Hi,

I am trying to use the String extension method MatchContains in my Where clause on IRedisCollection.
This is my search where I want to perform an infix search:

redisCollection.Where(x => x.Address.MatchContains("road")); - inspired by this test

When I execute the query this exception appears:
System.InvalidOperationException: Unable to parse method MatchContains

The property on my model is of type string and marked with an Searchable attribute. I have also tried using the Indexed attribute but this also resulted in the same exception. A quick search in the git repo points me to the method TranslateMethodStandardQuerySyntax in ExpressionParserUtilities.cs

Versions:
Redis OM v. 0.7.4
RediSearch v. 2.8.13
RedisJson v. 2.6.10

@slorello89
Copy link
Member

@obradl, can you share your model and the code you are using? Or some minimal reproduction. I can't get this to happen on my end.

@obradl
Copy link
Author

obradl commented Oct 3, 2024

I also get this error on MatchStartsWith and MatchEndsWith.

Model:

[Document(
    StorageType = StorageType.Json,
    Prefixes = ["House"],
    Language = "norwegian")]
public class House
{
    [RedisIdField]
    [Indexed]
    public required Ulid Id { get; set; };

    [Searchable(Aggregatable = true, Sortable = true)]
    public string Address { get; set; }  
}

The calling code:

  var houses = await housesCollection.Where(x =>
      x.Address.MatchStartsWith("wood")).ToListAsync();

StackTrace:
System.InvalidOperationException: Unable to parse method MatchStartsWith
at Redis.OM.Common.ExpressionParserUtilities.TranslateMethodStandardQuerySyntax(MethodCallExpression exp, List1 parameters) at Redis.OM.Common.ExpressionParserUtilities.GetOperandStringForQueryArgs(Expression exp, List1 parameters, Boolean treatEnumsAsInt, Boolean negate, Boolean treatBooleanMemberAsUnary)
at Redis.OM.Common.ExpressionTranslator.TranslateBinaryExpression(BinaryExpression binExpression, List1 parameters) at Redis.OM.Common.ExpressionTranslator.TranslateBinaryExpression(BinaryExpression binExpression, List1 parameters)
at Redis.OM.Common.ExpressionTranslator.TranslateBinaryExpression(BinaryExpression binExpression, List1 parameters) at Redis.OM.Common.ExpressionTranslator.BuildQueryFromExpression(Expression exp, List1 parameters)
at Redis.OM.Common.ExpressionTranslator.BuildQueryFromExpression(Expression expression, Type type, Expression mainBooleanExpression, Type rootType)
at Redis.OM.Searching.RedisCollectionEnumerator1..ctor(Expression exp, IRedisConnection connection, Int32 chunkSize, RedisCollectionStateManager stateManager, Expression1 booleanExpression, Boolean saveState, Type rootType, Type type)
at Redis.OM.Searching.RedisCollection1.GetAsyncEnumerator(CancellationToken cancellationToken) at Redis.OM.Searching.RedisCollection1.ToListAsync()

@slorello89
Copy link
Member

@obradl - Using your model (I cleaned it up a bit because the syntax was off):

[Document(StorageType = StorageType.Json, Prefixes = new[] {"House"}, Language = "norwegian")]
public class House
{
    [RedisIdField]
    [Indexed]
    public required Ulid Id { get; set; }

    [Searchable(Aggregatable = true, Sortable = true)]
    public string Address { get; set; }  
}

I ran the following with Redis OM .NET 0.7.4:

var muxer = ConnectionMultiplexer.Connect("localhost:6379");
var provider = new RedisConnectionProvider(muxer);
provider.Connection.DropIndexAndAssociatedRecords(typeof(House));
provider.Connection.CreateIndex(typeof(House));
var collection = provider.RedisCollection<House>();
var str = "wood";
await collection.Where(x => x.Address.MatchContains(str)).ToListAsync();
await collection.Where(x => x.Address.MatchStartsWith(str)).ToListAsync();
await collection.Where(x => x.Address.MatchEndsWith(str)).ToListAsync();

and could not replicate your issue, the correct query is created and sent. Can you send over a full, minimal reproduction that I can run and actually see it break?

@obradl
Copy link
Author

obradl commented Oct 4, 2024

I observe that MatchContains works if it is the only operator in the query, so your example works fine for me as well. However, if I do something like this ( using MatchContains on both City and Address) it fails :

using Redis.OM;
using Redis.OM.Modeling;
using StackExchange.Redis;

var muxer = ConnectionMultiplexer.Connect("localhost:6379");
var provider = new RedisConnectionProvider(muxer);
provider.Connection.DropIndexAndAssociatedRecords(typeof(House));
provider.Connection.CreateIndex(typeof(House));
var collection = provider.RedisCollection<House>();

var str = "someText";

var result = await collection.Where(x => 
    x.Address.MatchContains(str) ||
    x.City.MatchStartsWith(str))
    .ToListAsync();


[Document(StorageType = StorageType.Json, Prefixes = new[] {"House"}, Language = "norwegian")]
public class House
{
    [RedisIdField]
    [Indexed]
    public required Ulid Id { get; set; }

    [Searchable(Aggregatable = true, Sortable = true)]
    public string Address { get; set; }  

    [Searchable(Aggregatable = true, Sortable = true)]
    public string City { get; set; }  

    [Searchable(Aggregatable = true, Sortable = true)]
    public string Region { get; set; }  
}

Am I using it wrong ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants