Skip to content

Commit 7c7d7fd

Browse files
committed
move parameters back to to method, not the builder
1 parent f262659 commit 7c7d7fd

File tree

8 files changed

+187
-37
lines changed

8 files changed

+187
-37
lines changed

src/NRedisStack/PublicAPI/PublicAPI.Unshipped.txt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
[NRS001]NRedisStack.ISearchCommands.HybridSearch(string! indexName, NRedisStack.Search.HybridSearchQuery! query) -> NRedisStack.Search.HybridSearchResult!
2-
[NRS001]NRedisStack.ISearchCommandsAsync.HybridSearchAsync(string! indexName, NRedisStack.Search.HybridSearchQuery! query) -> System.Threading.Tasks.Task<NRedisStack.Search.HybridSearchResult!>!
1+
NRedisStack.Search.Parameters
2+
static NRedisStack.Search.Parameters.From<T>(T obj) -> System.Collections.Generic.IReadOnlyDictionary<string!, object!>!
3+
[NRS001]NRedisStack.ISearchCommands.HybridSearch(string! indexName, NRedisStack.Search.HybridSearchQuery! query, System.Collections.Generic.IReadOnlyDictionary<string!, object!>? parameters = null) -> NRedisStack.Search.HybridSearchResult!
4+
[NRS001]NRedisStack.ISearchCommandsAsync.HybridSearchAsync(string! indexName, NRedisStack.Search.HybridSearchQuery! query, System.Collections.Generic.IReadOnlyDictionary<string!, object!>? parameters = null) -> System.Threading.Tasks.Task<NRedisStack.Search.HybridSearchResult!>!
35
[NRS001]NRedisStack.Search.ApplyExpression
46
[NRS001]NRedisStack.Search.ApplyExpression.Alias.get -> string?
57
[NRS001]NRedisStack.Search.ApplyExpression.ApplyExpression() -> void
68
[NRS001]NRedisStack.Search.ApplyExpression.ApplyExpression(string! expression, string? alias = null) -> void
79
[NRS001]NRedisStack.Search.ApplyExpression.Expression.get -> string!
810
[NRS001]NRedisStack.Search.HybridSearchQuery
11+
[NRS001]NRedisStack.Search.HybridSearchQuery.AllowModification() -> NRedisStack.Search.HybridSearchQuery!
912
[NRS001]NRedisStack.Search.HybridSearchQuery.Apply(NRedisStack.Search.ApplyExpression applyExpression) -> NRedisStack.Search.HybridSearchQuery!
1013
[NRS001]NRedisStack.Search.HybridSearchQuery.Apply(params NRedisStack.Search.ApplyExpression[]! applyExpression) -> NRedisStack.Search.HybridSearchQuery!
1114
[NRS001]NRedisStack.Search.HybridSearchQuery.Combine(NRedisStack.Search.HybridSearchQuery.Combiner! combiner, string? scoreAlias = null) -> NRedisStack.Search.HybridSearchQuery!
@@ -18,7 +21,6 @@
1821
[NRS001]NRedisStack.Search.HybridSearchQuery.HybridSearchQuery() -> void
1922
[NRS001]NRedisStack.Search.HybridSearchQuery.Limit(int offset, int count) -> NRedisStack.Search.HybridSearchQuery!
2023
[NRS001]NRedisStack.Search.HybridSearchQuery.NoSort() -> NRedisStack.Search.HybridSearchQuery!
21-
[NRS001]NRedisStack.Search.HybridSearchQuery.Parameters(System.Collections.Generic.IReadOnlyDictionary<string!, object!>! parameters) -> NRedisStack.Search.HybridSearchQuery!
2224
[NRS001]NRedisStack.Search.HybridSearchQuery.Reduce(NRedisStack.Search.Aggregation.Reducer! reducer) -> NRedisStack.Search.HybridSearchQuery!
2325
[NRS001]NRedisStack.Search.HybridSearchQuery.Reduce(params NRedisStack.Search.Aggregation.Reducer![]! reducers) -> NRedisStack.Search.HybridSearchQuery!
2426
[NRS001]NRedisStack.Search.HybridSearchQuery.ReturnFields(params string![]! fields) -> NRedisStack.Search.HybridSearchQuery!
@@ -61,8 +63,8 @@
6163
[NRS001]NRedisStack.Search.Scorer
6264
[NRS001]NRedisStack.Search.VectorData
6365
[NRS001]NRedisStack.Search.VectorSearchMethod
64-
[NRS001]NRedisStack.SearchCommands.HybridSearch(string! indexName, NRedisStack.Search.HybridSearchQuery! query) -> NRedisStack.Search.HybridSearchResult!
65-
[NRS001]NRedisStack.SearchCommandsAsync.HybridSearchAsync(string! indexName, NRedisStack.Search.HybridSearchQuery! query) -> System.Threading.Tasks.Task<NRedisStack.Search.HybridSearchResult!>!
66+
[NRS001]NRedisStack.SearchCommands.HybridSearch(string! indexName, NRedisStack.Search.HybridSearchQuery! query, System.Collections.Generic.IReadOnlyDictionary<string!, object!>? parameters = null) -> NRedisStack.Search.HybridSearchResult!
67+
[NRS001]NRedisStack.SearchCommandsAsync.HybridSearchAsync(string! indexName, NRedisStack.Search.HybridSearchQuery! query, System.Collections.Generic.IReadOnlyDictionary<string!, object!>? parameters = null) -> System.Threading.Tasks.Task<NRedisStack.Search.HybridSearchResult!>!
6668
[NRS001]override NRedisStack.Search.ApplyExpression.Equals(object? obj) -> bool
6769
[NRS001]override NRedisStack.Search.ApplyExpression.GetHashCode() -> int
6870
[NRS001]override NRedisStack.Search.ApplyExpression.ToString() -> string!
@@ -83,8 +85,9 @@
8385
[NRS001]static NRedisStack.Search.Scorer.TfIdf.get -> NRedisStack.Search.Scorer!
8486
[NRS001]static NRedisStack.Search.Scorer.TfIdfDocNorm.get -> NRedisStack.Search.Scorer!
8587
[NRS001]static NRedisStack.Search.VectorData.Create(System.ReadOnlyMemory<float> vector) -> NRedisStack.Search.VectorData!
86-
[NRS001]static NRedisStack.Search.VectorData.FromBase64(string! base64) -> NRedisStack.Search.VectorData!
8788
[NRS001]static NRedisStack.Search.VectorData.implicit operator NRedisStack.Search.VectorData!(float[]! data) -> NRedisStack.Search.VectorData!
89+
[NRS001]static NRedisStack.Search.VectorData.implicit operator NRedisStack.Search.VectorData!(string! name) -> NRedisStack.Search.VectorData!
8890
[NRS001]static NRedisStack.Search.VectorData.implicit operator NRedisStack.Search.VectorData!(System.ReadOnlyMemory<float> vector) -> NRedisStack.Search.VectorData!
91+
[NRS001]static NRedisStack.Search.VectorData.Parameter(string! name) -> NRedisStack.Search.VectorData!
8992
[NRS001]static NRedisStack.Search.VectorSearchMethod.NearestNeighbour(int count = 10, int? maxTopCandidates = null, string? distanceAlias = null) -> NRedisStack.Search.VectorSearchMethod!
9093
[NRS001]static NRedisStack.Search.VectorSearchMethod.Range(double radius, double? epsilon = null, string? distanceAlias = null) -> NRedisStack.Search.VectorSearchMethod!

src/NRedisStack/Search/ISearchCommands.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,9 @@ public interface ISearchCommands
351351
/// </summary>
352352
/// <param name="indexName">The index name.</param>
353353
/// <param name="query">The query to execute.</param>
354+
/// <param name="parameters">The optional parameters used in this query.</param>
354355
/// <returns>List of TAG field values</returns>
355356
/// <remarks><seealso href="https://redis.io/commands/ft.hybrid"/></remarks>
356357
[Experimental(Experiments.Server_8_4, UrlFormat = Experiments.UrlFormat)]
357-
HybridSearchResult HybridSearch(string indexName, HybridSearchQuery query);
358+
HybridSearchResult HybridSearch(string indexName, HybridSearchQuery query, IReadOnlyDictionary<string, object>? parameters = null);
358359
}

src/NRedisStack/Search/ISearchCommandsAsync.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,5 +350,5 @@ public interface ISearchCommandsAsync
350350

351351
/// <inheritdoc cref="ISearchCommands.HybridSearch"/>
352352
[Experimental(Experiments.Server_8_4, UrlFormat = Experiments.UrlFormat)]
353-
Task<HybridSearchResult> HybridSearchAsync(string indexName, HybridSearchQuery query);
353+
Task<HybridSearchResult> HybridSearchAsync(string indexName, HybridSearchQuery query, IReadOnlyDictionary<string, object>? parameters = null);
354354
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.Collections;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Reflection;
4+
5+
namespace NRedisStack.Search;
6+
7+
/// <summary>
8+
/// Create query parameters from an object template.
9+
/// </summary>
10+
public static class Parameters
11+
{
12+
/// <summary>
13+
/// Create parameters from an object template.
14+
/// </summary>
15+
public static IReadOnlyDictionary<string, object> From<T>(T obj)
16+
=> new TypedParameters<T>(obj);
17+
18+
private sealed class TypedParameters<T>(T obj) : IReadOnlyDictionary<string, object>
19+
{
20+
// ReSharper disable once InconsistentNaming
21+
private static readonly PropertyInfo[] s_properties =
22+
typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
23+
.Where(p => p.CanRead
24+
&& p.GetGetMethod() is not null
25+
&& !p.PropertyType.IsByRef
26+
#if NET || NETSTANDARD2_1_OR_GREATER
27+
&& !p.PropertyType.IsByRefLike
28+
#else
29+
&& !p.PropertyType.GetCustomAttributes().Any(x => x.GetType().FullName == "System.Runtime.CompilerServices.IsByRefLikeAttribute")
30+
#endif
31+
).ToArray();
32+
33+
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
34+
{
35+
foreach (var prop in s_properties)
36+
{
37+
var value = prop.GetValue(obj);
38+
if (value is not null)
39+
{
40+
yield return new KeyValuePair<string, object>(prop.Name, value);
41+
}
42+
}
43+
}
44+
45+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
46+
47+
public int Count => s_properties.Length;
48+
public bool ContainsKey(string key) => TryGetValue(key, out _); // because we need the null-check
49+
50+
public bool TryGetValue(string key, out object value)
51+
{
52+
foreach (var prop in s_properties)
53+
{
54+
if (prop.Name == key)
55+
{
56+
value = prop.GetValue(obj)!;
57+
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
58+
return value is not null;
59+
}
60+
}
61+
62+
value = null!;
63+
return false;
64+
}
65+
66+
public object this[string key] => TryGetValue(key, out var value) ? value : throw new KeyNotFoundException();
67+
68+
public IEnumerable<string> Keys
69+
{
70+
get
71+
{
72+
foreach (var prop in s_properties)
73+
{
74+
var value = prop.GetValue(obj);
75+
if (value is not null)
76+
{
77+
yield return prop.Name;
78+
}
79+
}
80+
}
81+
}
82+
83+
public IEnumerable<object> Values
84+
{
85+
get
86+
{
87+
foreach (var prop in s_properties)
88+
{
89+
var value = prop.GetValue(obj);
90+
if (value is not null)
91+
{
92+
yield return value;
93+
}
94+
}
95+
}
96+
}
97+
}
98+
}

src/NRedisStack/Search/SearchCommands.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,10 @@ public bool SynUpdate(string indexName, string synonymGroupId, bool skipInitialS
318318

319319
/// <inheritdoc/>
320320
[Experimental(Experiments.Server_8_4, UrlFormat = Experiments.UrlFormat)]
321-
public HybridSearchResult HybridSearch(string indexName, HybridSearchQuery query)
321+
public HybridSearchResult HybridSearch(string indexName, HybridSearchQuery query, IReadOnlyDictionary<string, object>? parameters = null)
322322
{
323323
query.Validate();
324-
var args = query.GetArgs(indexName);
324+
var args = query.GetArgs(indexName, parameters);
325325
return HybridSearchResult.Parse(db.Execute(query.Command, args));
326326
}
327327
}

src/NRedisStack/Search/SearchCommandsAsync.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,10 @@ public async Task<bool> SynUpdateAsync(string indexName, string synonymGroupId,
356356

357357
/// <inheritdoc/>
358358
[Experimental(Experiments.Server_8_4, UrlFormat = Experiments.UrlFormat)]
359-
public async Task<HybridSearchResult> HybridSearchAsync(string indexName, HybridSearchQuery query)
359+
public async Task<HybridSearchResult> HybridSearchAsync(string indexName, HybridSearchQuery query, IReadOnlyDictionary<string, object>? parameters = null)
360360
{
361361
query.Validate();
362-
var args = query.GetArgs(indexName);
362+
var args = query.GetArgs(indexName, parameters);
363363
return HybridSearchResult.Parse(await _db.ExecuteAsync(query.Command, args));
364364
}
365365
}

src/NRedisStack/Search/VectorData.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,32 @@ private protected VectorData()
1717
public static VectorData Create(ReadOnlyMemory<float> vector) => new VectorDataSingle(vector);
1818

1919
/// <summary>
20-
/// A pre-formatted base-64 value.
20+
/// Represent a vector as a parameter to be supplied later.
2121
/// </summary>
22-
public static VectorData FromBase64(string base64) => new VectorDataBase64(base64);
22+
public static VectorData Parameter(string name) => new VectorParameter(name);
2323

2424
/// <summary>
2525
/// A vector of <see cref="Single"/> entries.
2626
/// </summary>
2727
public static implicit operator VectorData(float[] data) => new VectorDataSingle(data);
2828

29-
/// <summary>
30-
/// A vector of <see cref="Single"/> entries.
31-
/// </summary>
29+
/// <inheritdoc cref="Create"/>
3230
public static implicit operator VectorData(ReadOnlyMemory<float> vector) => new VectorDataSingle(vector);
3331

34-
internal void AddBase64Args(List<object> args) => args.Add(ToBase64());
35-
internal int Base64ArgsCount() => 1;
36-
private protected abstract string ToBase64();
32+
/// <inheritdoc cref="Parameter"/>
33+
public static implicit operator VectorData(string name) => new VectorParameter(name);
34+
35+
internal abstract object GetSingleArg();
3736

3837
/// <inheritdoc/>
39-
public override string ToString() => ToBase64();
38+
public override string ToString() => GetType().Name;
4039

4140
private sealed class VectorDataSingle(ReadOnlyMemory<float> vector) : VectorData
4241
{
43-
private protected override string ToBase64()
42+
internal override object GetSingleArg() => ToBase64();
43+
public override string ToString() => ToBase64();
44+
45+
private string ToBase64()
4446
{
4547
if (!BitConverter.IsLittleEndian) ThrowBigEndian(); // we could loop and reverse each, but...how to test?
4648
var bytes = MemoryMarshal.AsBytes(vector.Span);
@@ -56,9 +58,19 @@ private protected override string ToBase64()
5658
}
5759
}
5860

59-
private sealed class VectorDataBase64(string vector) : VectorData
61+
private sealed class VectorParameter : VectorData
6062
{
61-
private protected override string ToBase64() => vector;
63+
private readonly string name;
64+
65+
public VectorParameter(string name)
66+
{
67+
if (string.IsNullOrEmpty(name) || name[0] != '$') Throw();
68+
this.name = name;
69+
static void Throw() => throw new ArgumentException("Parameter tokens must start with the character '$'.");
70+
}
71+
72+
public override string ToString() => name;
73+
internal override object GetSingleArg() => name;
6274
}
6375

6476
private protected static void ThrowBigEndian() =>

0 commit comments

Comments
 (0)