diff --git a/Directory.Build.props b/Directory.Build.props
index 008d7f4e..13e3103d 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -23,7 +23,7 @@
truetruetrue
- $(NoWarn);CS1591
+ $(NoWarn);CS1591;NRS003$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::get_Windows())))
diff --git a/Directory.Packages.props b/Directory.Packages.props
index b61ed977..31c1d6bc 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -12,7 +12,7 @@
-
+
diff --git a/docs/exp/NRS003.md b/docs/exp/NRS003.md
new file mode 100644
index 00000000..c9db3317
--- /dev/null
+++ b/docs/exp/NRS003.md
@@ -0,0 +1,33 @@
+`REDUCE COLLECT` is gated behind the server's *unstable features* flag; the feature and its API may be subject to change.
+
+*COLLECT* is an `FT.AGGREGATE` reducer that gathers per-document projections within a `GROUPBY` group and returns them
+as an array of per-entry maps under the reducer alias, optionally sorted and bounded.
+
+The server does not expose it by default: it must be enabled explicitly, for example via
+
+```
+CONFIG SET search-enable-unstable-features yes
+```
+
+In a cluster the coordinator fans the query out to every shard, so the flag must be enabled on all nodes rather than
+only the one a given connection happens to route to. Without it, the server replies with an error.
+
+The corresponding library feature must also be considered subject to change:
+
+1. Existing bindings may cease working correctly if the underlying server API changes.
+2. Changes to the server API may require changes to the library API, manifesting in either/both of build-time
+ or run-time breaks.
+
+Because the server itself still classes this as an unstable feature, such changes are rather more likely here than for
+a feature that has simply not been out for long. If you acknowledge this, you can suppress this warning by adding the
+following to your `csproj` file:
+
+```xml
+$(NoWarn);NRS003
+```
+
+or more granularly / locally in C#:
+
+```c#
+#pragma warning disable NRS003
+```
diff --git a/src/NRedisStack/Experiments.cs b/src/NRedisStack/Experiments.cs
index eee7520f..0c5e266f 100644
--- a/src/NRedisStack/Experiments.cs
+++ b/src/NRedisStack/Experiments.cs
@@ -9,6 +9,8 @@ namespace NRedisStack
// NRS002 - Redis 8.8 multi-aggregate time-series
internal static class Experiments
{
+ public const string SearchCollect = "NRS003";
+
// {0} is substituted with the diagnostic id, e.g. NRS042 -> https://redis.github.io/NRedisStack/exp/NRS042
public const string UrlFormat = "https://redis.github.io/NRedisStack/exp/{0}";
}
diff --git a/src/NRedisStack/PublicAPI/PublicAPI.Shipped.txt b/src/NRedisStack/PublicAPI/PublicAPI.Shipped.txt
index 5085b70e..8f015a70 100644
--- a/src/NRedisStack/PublicAPI/PublicAPI.Shipped.txt
+++ b/src/NRedisStack/PublicAPI/PublicAPI.Shipped.txt
@@ -1670,13 +1670,13 @@ NRedisStack.ISearchCommandsAsync.AliasListAsync(string! index) -> System.Threadi
NRedisStack.SearchCommands.AliasList(string! index) -> StackExchange.Redis.RedisResult![]!
NRedisStack.SearchCommandsAsync.AliasListAsync(string! index) -> System.Threading.Tasks.Task!
static NRedisStack.SearchCommandBuilder.AliasList(string! index) -> NRedisStack.RedisStackCommands.SerializedCommand!
-NRedisStack.Search.Aggregation.CollectReducer
-override NRedisStack.Search.Aggregation.CollectReducer.Name.get -> string!
-NRedisStack.Search.Aggregation.CollectReducer.Fields(params string![]! fields) -> NRedisStack.Search.Aggregation.CollectReducer!
-NRedisStack.Search.Aggregation.CollectReducer.FieldsAll() -> NRedisStack.Search.Aggregation.CollectReducer!
-NRedisStack.Search.Aggregation.CollectReducer.SortBy(params NRedisStack.Search.Aggregation.SortedField![]! fields) -> NRedisStack.Search.Aggregation.CollectReducer!
-NRedisStack.Search.Aggregation.CollectReducer.SortByAsc(string! field) -> NRedisStack.Search.Aggregation.CollectReducer!
-NRedisStack.Search.Aggregation.CollectReducer.SortByDesc(string! field) -> NRedisStack.Search.Aggregation.CollectReducer!
-NRedisStack.Search.Aggregation.CollectReducer.Limit(int count) -> NRedisStack.Search.Aggregation.CollectReducer!
-NRedisStack.Search.Aggregation.CollectReducer.Limit(int offset, int count) -> NRedisStack.Search.Aggregation.CollectReducer!
-static NRedisStack.Search.Aggregation.Reducers.Collect() -> NRedisStack.Search.Aggregation.CollectReducer!
+[NRS003]NRedisStack.Search.Aggregation.CollectReducer
+[NRS003]override NRedisStack.Search.Aggregation.CollectReducer.Name.get -> string!
+[NRS003]NRedisStack.Search.Aggregation.CollectReducer.Fields(params string![]! fields) -> NRedisStack.Search.Aggregation.CollectReducer!
+[NRS003]NRedisStack.Search.Aggregation.CollectReducer.FieldsAll() -> NRedisStack.Search.Aggregation.CollectReducer!
+[NRS003]NRedisStack.Search.Aggregation.CollectReducer.SortBy(params NRedisStack.Search.Aggregation.SortedField![]! fields) -> NRedisStack.Search.Aggregation.CollectReducer!
+[NRS003]NRedisStack.Search.Aggregation.CollectReducer.SortByAsc(string! field) -> NRedisStack.Search.Aggregation.CollectReducer!
+[NRS003]NRedisStack.Search.Aggregation.CollectReducer.SortByDesc(string! field) -> NRedisStack.Search.Aggregation.CollectReducer!
+[NRS003]NRedisStack.Search.Aggregation.CollectReducer.Limit(int count) -> NRedisStack.Search.Aggregation.CollectReducer!
+[NRS003]NRedisStack.Search.Aggregation.CollectReducer.Limit(int offset, int count) -> NRedisStack.Search.Aggregation.CollectReducer!
+[NRS003]static NRedisStack.Search.Aggregation.Reducers.Collect() -> NRedisStack.Search.Aggregation.CollectReducer!
diff --git a/src/NRedisStack/Search/CollectReducer.cs b/src/NRedisStack/Search/CollectReducer.cs
index 878697cc..08b9d1bb 100644
--- a/src/NRedisStack/Search/CollectReducer.cs
+++ b/src/NRedisStack/Search/CollectReducer.cs
@@ -1,4 +1,5 @@
-using NRedisStack.Search.Literals;
+using System.Diagnostics.CodeAnalysis;
+using NRedisStack.Search.Literals;
namespace NRedisStack.Search.Aggregation;
@@ -33,6 +34,7 @@ namespace NRedisStack.Search.Aggregation;
///
///
///
+[Experimental(Experiments.SearchCollect, UrlFormat = Experiments.UrlFormat)]
public sealed class CollectReducer : Reducer
{
private bool _allFields = false;
diff --git a/src/NRedisStack/Search/Reducers.cs b/src/NRedisStack/Search/Reducers.cs
index d8a20e23..b348d032 100644
--- a/src/NRedisStack/Search/Reducers.cs
+++ b/src/NRedisStack/Search/Reducers.cs
@@ -1,4 +1,6 @@
-namespace NRedisStack.Search.Aggregation;
+using System.Diagnostics.CodeAnalysis;
+
+namespace NRedisStack.Search.Aggregation;
public static class Reducers
{
@@ -92,6 +94,7 @@ protected override void AddOwnArgs(List