Skip to content

Add ToQueryString method to RedisCollection, RedisAggregationSet #487

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

Merged
merged 2 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ We'd love your contributions! If you want to contribute please read our [Contrib
* [@CormacLennon](https://github.com/CormacLennon)
* [@ahmedisam99](https://github.com/ahmedisam99)
* [@kirollosonsi](https://github.com/kirollosonsi)
* [@tgmoore](https://github.com/tgmoore)

<!-- Logo -->
[Logo]: images/logo.svg
Expand Down
22 changes: 22 additions & 0 deletions src/Redis.OM/Aggregation/RedisAggregationSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Redis.OM.Common;
using Redis.OM.Contracts;
using Redis.OM.Modeling;
using Redis.OM.Searching;
Expand Down Expand Up @@ -115,6 +116,27 @@ public async ValueTask<List<AggregationResult<T>>> ToListAsync()
public async ValueTask<AggregationResult<T>[]> ToArrayAsync()
=> (await ToListAsync()).ToArray();

/// <summary>
/// A string representation of the aggregation command and parameters, a serialization of the Expression with all parameters explicitly quoted.
/// Warning: this string may not be suitable for direct execution and is intended only for use in debugging.
/// </summary>
/// <returns>A string representing the Expression serialized to an aggregation command and parameters.</returns>
public string ToQueryString()
{
var serializedArgs = ExpressionTranslator.BuildAggregationFromExpression(Expression, typeof(T)).Serialize().ToList();

if (_useCursor)
{
serializedArgs.Add("WITHCURSOR");
serializedArgs.Add("COUNT");
serializedArgs.Add(_chunkSize.ToString());
}

var quotedArgs = serializedArgs.Select(arg => $"\"{arg}\"");

return $"\"FT.AGGREGATE\" {string.Join(" ", quotedArgs)}";
}

private void Initialize(RedisQueryProvider provider, Expression? expression, bool useCursor)
{
Provider = provider ?? throw new ArgumentNullException(nameof(provider));
Expand Down
7 changes: 7 additions & 0 deletions src/Redis.OM/Searching/IRedisCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,5 +339,12 @@ public interface IRedisCollection<T> : IOrderedQueryable<T>, IAsyncEnumerable<T>
/// <param name="ids">The Ids to look up.</param>
/// <returns>A dictionary correlating the ids provided to the objects in Redis.</returns>
Task<IDictionary<string, T?>> FindByIdsAsync(IEnumerable<string> ids);

/// <summary>
/// A string representation of the Redisearch command and parameters, a serialization of the Expression with all parameters explicitly quoted.
/// Warning: this string may not be suitable for direct execution and is intended only for use in debugging.
/// </summary>
/// <returns>A string representing the Expression serialized to a Redisearch command and parameters.</returns>
string ToQueryString();
}
}
11 changes: 11 additions & 0 deletions src/Redis.OM/Searching/RedisCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,17 @@ public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToke
return new RedisCollectionEnumerator<T>(Expression, provider.Connection, ChunkSize, StateManager, BooleanExpression, SaveState, RootType, typeof(T));
}

/// <inheritdoc/>
public string ToQueryString()
{
var query = ExpressionTranslator.BuildQueryFromExpression(Expression, typeof(T), BooleanExpression, RootType);
query.Limit ??= new SearchLimit { Number = ChunkSize, Offset = 0 };

var quotedArgs = query.SerializeQuery().Select(arg => $"\"{arg}\"");

return $"\"FT.SEARCH\" {string.Join(" ", quotedArgs)}";
}

private static MethodInfo GetMethodInfo<T1, T2>(Func<T1, T2> f, T1 unused)
{
return f.Method;
Expand Down
18 changes: 18 additions & 0 deletions test/Redis.OM.Unit.Tests/RediSearchTests/AggregationSetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -659,5 +659,23 @@ public async Task TestNoCursorDelete()
await _substitute.Received().ExecuteAsync("FT.AGGREGATE", "person-idx", "*", "FILTER", "@TagField == 'foo' && @Address_State == 'FL'");
await _substitute.DidNotReceive().ExecuteAsync("FT.CURSOR", Arg.Any<object[]>());
}

[Fact]
public void TestToQueryString()
{
var collection = new RedisAggregationSet<Person>(_substitute, true, chunkSize: 10000);
var command = "\"FT.AGGREGATE\" \"person-idx\" \"@Salary:[(30.55 inf]\" \"LOAD\" \"*\" \"APPLY\" \"@Address_HouseNumber + 4\" \"AS\" \"house_num_modified\" \"SORTBY\" \"2\" \"@Age\" \"DESC\" \"LIMIT\" \"0\" \"10\" \"WITHCURSOR\" \"COUNT\" \"10000\"";

var queryString = collection
.LoadAll()
.Apply(x => x.RecordShell.Address.HouseNumber + 4, "house_num_modified")
.Where(a => a.RecordShell!.Salary > 30.55M)
.OrderByDescending(p=>p.RecordShell.Age)
.Skip(0)
.Take(10)
.ToQueryString();

Assert.Equal(command, queryString);
}
}
}
12 changes: 12 additions & 0 deletions test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3889,5 +3889,17 @@ await _substitute.Received().ExecuteAsync("FT.SEARCH",
"0",
"100");
}

[Fact]
public void TestToQueryString()
{
_substitute.ClearSubstitute();
var command = "\"FT.SEARCH\" \"person-idx\" \"(((@Name:Ste) | (@Height:[70 inf])) (@Age:[-inf (33]))\" \"LIMIT\" \"100\" \"10\" \"SORTBY\" \"Age\" \"ASC\"";

var collection = new RedisCollection<Person>(_substitute);
var queryString = collection.Where(x => x.Name.Contains("Ste") || x.Height >= 70).Where(x => x.Age < 33).OrderBy(x => x.Age).Skip(100).Take(10).ToQueryString();

Assert.Equal(command, queryString);
}
}
}
Loading