redis / redis-om-dotnet

Object mapping, and more, for Redis and .NET
MIT License
456 stars 76 forks source link

Support for enum flag searching when storing as string #239

Closed VagyokC4 closed 1 year ago

VagyokC4 commented 1 year ago

Hi @slorello89,

Wanted to know your thoughts on the best way to address this issue.

Using the following model:

[Flags]
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum EnumFlags
{
    None = 0,
    Internal = 1 << 0,
    Client = 1 << 1,
    Server = 1 << 2,
    Edited = 1 << 3,
    Deleted = 1 << 4,
    Archived = 1 << 5
}

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

    [JsonConverter(typeof(JsonStringEnumConverter))]
    [Indexed(Separator = ',')]
    public EnumFlags? Flags { get; set; }
}

and inserting the following record in like this:

var coll = RedisDb.GetRedisCollection<EnumFlagTest>();
await coll.InsertAsync(new EnumFlagTest{Flags = EnumFlags.Client|EnumFlags.Server});

produces this result:

{
  "Id": "01GFPFHRZ1GGVQXQ6Q3C5833VK",
  "Flags": "Client, Server"
}

and with the [Indexed(Separator=',')] it looks like we are very close to be able to search on it... if only there was a way.

I would like to do something like this:

var res = coll.Where(x => x.Flags.Contains(EnumFlags.Client)).ToListAsync();

I saw your post about the requests for ideas for Hacktoberfest. Maybe this is a little too advanced... but I thought I'd post it here to start the conversation.

Thoughts?

slorello89 commented 1 year ago

Interesting @VagyokC4 - looks like it's a bug:

"FT.CREATE" "enumflagtest-idx" "ON" "Json" "PREFIX" "1" "TestRedisOm.EnumFlagTest:" "SCHEMA" "$.Id" "AS" "Id" "TAG" "SEPARATOR" "|" "$.Flags" "AS" "Flags" "TAG"

is the index it's spitting out - as you can see it's ~using the default | separator as the separator~ not using a separator at all.

slorello89 commented 1 year ago

@VagyokC4 - so this one's a bit interesting, in RediSearch with hashes, a command would be the default delimiter, however since this is a JSON type, RediSearch does not automatically use a delimiter, so all we really need to do is have it explicitly set a delimiter if the Enum is a flag type enum - opened #241 to address this.

VagyokC4 commented 1 year ago

@VagyokC4 - so this one's a bit interesting, in RediSearch with hashes, a command would be the default delimiter, however since this is a JSON type, RediSearch does not automatically use a delimiter, so all we really need to do is have it explicitly set a delimiter if the Enum is a flag type enum - opened #241 to address this.

@slorello89 So would the end query be a contains query?

slorello89 commented 1 year ago

No it would just be an equals query see my test in the PR