Commit 80d7d50a authored by Nick Craver's avatar Nick Craver

Cleanup for NRediSearch

Lots of documentation and formatting fixes, no functional changes.
parent 965453e2
......@@ -10,18 +10,20 @@ namespace NRediSearch.Test.ClientTests
public class ClientTest : RediSearchTestBase
{
public ClientTest(ITestOutputHelper output) : base(output) { }
[Fact]
public void search()
public void Search()
{
Client cl = GetClient();
Schema sc = new Schema().AddTextField("title", 1.0).AddTextField("body", 1.0);
Assert.True(cl.CreateIndex(sc, Client.IndexOptions.Default));
var fields = new Dictionary<string, RedisValue>();
fields.Add("title", "hello world");
fields.Add("body", "lorem ipsum");
var fields = new Dictionary<string, RedisValue>
{
{ "title", "hello world" },
{ "body", "lorem ipsum" }
};
for (int i = 0; i < 100; i++)
{
Assert.True(cl.AddDocument($"doc{i}", fields, (double)i / 100.0));
......@@ -45,16 +47,12 @@ public void search()
Assert.True(cl.DropIndex());
var ex = Assert.Throws<RedisServerException>(() =>
{
cl.Search(new Query("hello world"));
});
var ex = Assert.Throws<RedisServerException>(() => cl.Search(new Query("hello world")));
Assert.Equal("Unknown Index name", ex.Message);
}
[Fact]
public void testNumericFilter()
public void TestNumericFilter()
{
Client cl = GetClient();
......@@ -62,12 +60,13 @@ public void testNumericFilter()
Assert.True(cl.CreateIndex(sc, Client.IndexOptions.Default));
for (int i = 0; i < 100; i++)
{
var fields = new Dictionary<string, RedisValue>();
fields.Add("title", "hello world");
fields.Add("price", i);
var fields = new Dictionary<string, RedisValue>
{
{ "title", "hello world" },
{ "price", i }
};
Assert.True(cl.AddDocument($"doc{i}", fields));
}
......@@ -104,30 +103,30 @@ public void testNumericFilter()
}
res = cl.Search(new Query("hello world").
AddFilter(new Query.NumericFilter("price", 20, Double.PositiveInfinity)));
AddFilter(new Query.NumericFilter("price", 20, double.PositiveInfinity)));
Assert.Equal(80, res.TotalResults);
Assert.Equal(10, res.Documents.Count);
res = cl.Search(new Query("hello world").
AddFilter(new Query.NumericFilter("price", Double.NegativeInfinity, 10)));
AddFilter(new Query.NumericFilter("price", double.NegativeInfinity, 10)));
Assert.Equal(11, res.TotalResults);
Assert.Equal(10, res.Documents.Count);
}
[Fact]
public void testStopwords()
public void TestStopwords()
{
Client cl = GetClient();
Schema sc = new Schema().AddTextField("title", 1.0);
Assert.True(cl.CreateIndex(sc,
Client.IndexOptions.Default.SetStopwords("foo", "bar", "baz")));
var fields = new Dictionary<string, RedisValue>();
fields.Add("title", "hello world foo bar");
var fields = new Dictionary<string, RedisValue>
{
{ "title", "hello world foo bar" }
};
Assert.True(cl.AddDocument("doc1", fields));
SearchResult res = cl.Search(new Query("hello world"));
Assert.Equal(1, res.TotalResults);
......@@ -138,8 +137,10 @@ public void testStopwords()
Assert.True(cl.CreateIndex(sc,
Client.IndexOptions.Default | Client.IndexOptions.DisableStopWords));
fields = new Dictionary<string, RedisValue>();
fields.Add("title", "hello world foo bar to be or not to be");
fields = new Dictionary<string, RedisValue>
{
{ "title", "hello world foo bar to be or not to be" }
};
Assert.True(cl.AddDocument("doc1", fields));
Assert.Equal(1, cl.Search(new Query("hello world")).TotalResults);
......@@ -147,18 +148,19 @@ public void testStopwords()
Assert.Equal(1, cl.Search(new Query("to be or not to be")).TotalResults);
}
[Fact]
public void testGeoFilter()
public void TestGeoFilter()
{
Client cl = GetClient();
Schema sc = new Schema().AddTextField("title", 1.0).AddGeoField("loc");
Assert.True(cl.CreateIndex(sc, Client.IndexOptions.Default));
var fields = new Dictionary<string, RedisValue>();
fields.Add("title", "hello world");
fields.Add("loc", "-0.441,51.458");
var fields = new Dictionary<string, RedisValue>
{
{ "title", "hello world" },
{ "loc", "-0.441,51.458" }
};
Assert.True(cl.AddDocument("doc1", fields));
fields["loc"] = "-0.1,51.2";
......@@ -180,7 +182,7 @@ public void testGeoFilter()
}
[Fact]
public void testPayloads()
public void TestPayloads()
{
Client cl = GetClient();
......@@ -188,9 +190,11 @@ public void testPayloads()
Assert.True(cl.CreateIndex(sc, Client.IndexOptions.Default));
var fields = new Dictionary<string, RedisValue>();
fields.Add("title", "hello world");
string payload = "foo bar";
var fields = new Dictionary<string, RedisValue>
{
{ "title", "hello world" }
};
const string payload = "foo bar";
Assert.True(cl.AddDocument("doc1", fields, 1.0, false, false, Encoding.UTF8.GetBytes(payload)));
SearchResult res = cl.Search(new Query("hello world") { WithPayloads = true });
Assert.Equal(1, res.TotalResults);
......@@ -200,7 +204,7 @@ public void testPayloads()
}
[Fact]
public void testQueryFlags()
public void TestQueryFlags()
{
Client cl = GetClient();
......@@ -209,7 +213,6 @@ public void testQueryFlags()
Assert.True(cl.CreateIndex(sc, Client.IndexOptions.Default));
var fields = new Dictionary<string, RedisValue>();
for (int i = 0; i < 100; i++)
{
fields["title"] = i % 2 == 1 ? "hello worlds" : "hello world";
......@@ -226,7 +229,7 @@ public void testQueryFlags()
{
Assert.StartsWith("doc", d.Id);
Assert.True(d.Score != 1.0);
Assert.StartsWith("hello world", ((string)d["title"]));
Assert.StartsWith("hello world", (string)d["title"]);
}
q = new Query("hello").SetNoContent();
......@@ -253,15 +256,16 @@ public void testQueryFlags()
}
[Fact]
public void testSortQueryFlags()
public void TestSortQueryFlags()
{
Client cl = GetClient();
Schema sc = new Schema().AddSortableTextField("title", 1.0);
Assert.True(cl.CreateIndex(sc, Client.IndexOptions.Default));
var fields = new Dictionary<string, RedisValue>();
fields["title"] = "b title";
var fields = new Dictionary<string, RedisValue>
{
["title"] = "b title"
};
cl.AddDocument("doc1", fields, 1.0, false, true, null);
fields["title"] = "a title";
......@@ -285,7 +289,7 @@ public void testSortQueryFlags()
}
[Fact]
public void testAddHash()
public void TestAddHash()
{
Client cl = GetClient();
......@@ -302,7 +306,7 @@ public void testAddHash()
}
[Fact]
public void testDrop()
public void TestDrop()
{
Client cl = GetClient();
Db.Execute("FLUSHDB"); // yeah, this is horrible, deal with it
......@@ -310,8 +314,10 @@ public void testDrop()
Schema sc = new Schema().AddTextField("title", 1.0);
Assert.True(cl.CreateIndex(sc, Client.IndexOptions.Default));
var fields = new Dictionary<string, RedisValue>();
fields.Add("title", "hello world");
var fields = new Dictionary<string, RedisValue>
{
{ "title", "hello world" }
};
for (int i = 0; i < 100; i++)
{
Assert.True(cl.AddDocument($"doc{i}", fields));
......@@ -330,16 +336,18 @@ public void testDrop()
}
[Fact]
public void testNoStem()
public void TestNoStem()
{
Client cl = GetClient();
Schema sc = new Schema().AddTextField("stemmed", 1.0).AddField(new Schema.TextField("notStemmed", 1.0, false, true));
Assert.True(cl.CreateIndex(sc, Client.IndexOptions.Default));
var doc = new Dictionary<string, RedisValue>();
doc.Add("stemmed", "located");
doc.Add("notStemmed", "located");
var doc = new Dictionary<string, RedisValue>
{
{ "stemmed", "located" },
{ "notStemmed", "located" }
};
// Store it
Assert.True(cl.AddDocument("doc", doc));
......@@ -352,7 +360,7 @@ public void testNoStem()
}
[Fact]
public void testInfo()
public void TestInfo()
{
Client cl = GetClient();
......@@ -361,11 +369,10 @@ public void testInfo()
var info = cl.GetInfo();
Assert.Equal((string)cl.IndexName, (string)info["index_name"]);
}
[Fact]
public void testNoIndex()
public void TestNoIndex()
{
Client cl = GetClient();
......@@ -374,10 +381,11 @@ public void testNoIndex()
.AddField(new Schema.TextField("f2", 1.0));
cl.CreateIndex(sc, Client.IndexOptions.Default);
var mm = new Dictionary<string, RedisValue>();
mm.Add("f1", "MarkZZ");
mm.Add("f2", "MarkZZ");
var mm = new Dictionary<string, RedisValue>
{
{ "f1", "MarkZZ" },
{ "f2", "MarkZZ" }
};
cl.AddDocument("doc1", mm);
mm.Clear();
......@@ -398,11 +406,10 @@ public void testNoIndex()
res = cl.Search(new Query("@f2:Mark*").SetSortBy("f1", true));
Assert.Equal("doc2", res.Documents[0].Id);
}
[Fact]
public void testReplacePartial()
public void TestReplacePartial()
{
Client cl = GetClient();
......@@ -412,9 +419,11 @@ public void testReplacePartial()
.AddTextField("f3", 1.0);
cl.CreateIndex(sc, Client.IndexOptions.Default);
var mm = new Dictionary<string, RedisValue>();
mm.Add("f1", "f1_val");
mm.Add("f2", "f2_val");
var mm = new Dictionary<string, RedisValue>
{
{ "f1", "f1_val" },
{ "f2", "f2_val" }
};
cl.AddDocument("doc1", mm);
cl.AddDocument("doc2", mm);
......@@ -426,7 +435,7 @@ public void testReplacePartial()
cl.ReplaceDocument("doc2", mm, 1.0);
// Search for f3 value. All documents should have it.
SearchResult res = cl.Search(new Query(("@f3:f3_Val")));
SearchResult res = cl.Search(new Query("@f3:f3_Val"));
Assert.Equal(2, res.TotalResults);
res = cl.Search(new Query("@f3:f3_val @f2:f2_val @f1:f1_val"));
......@@ -434,7 +443,7 @@ public void testReplacePartial()
}
[Fact]
public void testExplain()
public void TestExplain()
{
Client cl = GetClient();
......@@ -451,14 +460,16 @@ public void testExplain()
}
[Fact]
public void testHighlightSummarize()
public void TestHighlightSummarize()
{
Client cl = GetClient();
Schema sc = new Schema().AddTextField("text", 1.0);
cl.CreateIndex(sc, Client.IndexOptions.Default);
var doc = new Dictionary<string, RedisValue>();
doc.Add("text", "Redis is often referred as a data structures server. What this means is that Redis provides access to mutable data structures via a set of commands, which are sent using a server-client model with TCP sockets and a simple protocol. So different processes can query and modify the same data structures in a shared way");
var doc = new Dictionary<string, RedisValue>
{
{ "text", "Redis is often referred as a data structures server. What this means is that Redis provides access to mutable data structures via a set of commands, which are sent using a server-client model with TCP sockets and a simple protocol. So different processes can query and modify the same data structures in a shared way" }
};
// Add a document
cl.AddDocument("foo", doc, 1.0);
Query q = new Query("data").HighlightFields().SummarizeFields();
......@@ -469,7 +480,7 @@ public void testHighlightSummarize()
}
[Fact]
public void testLanguage()
public void TestLanguage()
{
Client cl = GetClient();
Schema sc = new Schema().AddTextField("text", 1.0);
......@@ -482,26 +493,20 @@ public void testLanguage()
options.SetLanguage("ybreski");
cl.DeleteDocument(d.Id);
var ex = Assert.Throws<RedisServerException>(() =>
{
cl.AddDocument(d, options);
});
var ex = Assert.Throws<RedisServerException>(() => cl.AddDocument(d, options));
Assert.Equal("Unsupported Language", ex.Message);
}
[Fact]
public void testDropMissing()
public void TestDropMissing()
{
Client cl = GetClient();
var ex = Assert.Throws<RedisServerException>(() =>
{
cl.DropIndex();
});
var ex = Assert.Throws<RedisServerException>(() => cl.DropIndex());
Assert.Equal("Unknown Index name", ex.Message);
}
[Fact]
public void testGet()
public void TestGet()
{
Client cl = GetClient();
cl.CreateIndex(new Schema().AddTextField("txt1", 1.0), Client.IndexOptions.Default);
......
......@@ -17,7 +17,7 @@ public class BuilderTest : RediSearchTestBase
public BuilderTest(ITestOutputHelper output) : base(output) { }
[Fact]
public void testTag()
public void TestTag()
{
Value v = Tags("foo");
Assert.Equal("{foo}", v.ToString());
......@@ -26,16 +26,13 @@ public void testTag()
}
[Fact]
public void testEmptyTag()
public void TestEmptyTag()
{
Assert.Throws<ArgumentException>(() =>
{
Tags();
});
Assert.Throws<ArgumentException>(() => Tags());
}
[Fact]
public void testRange()
public void TestRange()
{
Value v = Between(1, 10);
Assert.Equal("[1.0 10.0]", v.ToString());
......@@ -60,7 +57,7 @@ public void testRange()
}
[Fact]
public void testIntersectionBasic()
public void TestIntersectionBasic()
{
INode n = Intersect().Add("name", "mark");
Assert.Equal("@name:mark", n.ToString());
......@@ -70,7 +67,7 @@ public void testIntersectionBasic()
}
[Fact]
public void testIntersectionNested()
public void TestIntersectionNested()
{
INode n = Intersect().
Add(Union("name", Value("mark"), Value("dvir"))).
......@@ -79,14 +76,15 @@ public void testIntersectionNested()
Assert.Equal("(@name:(mark|dvir) @time:[100.0 200.0] -@created:[-inf (1000.0])", n.ToString());
}
static string GetArgsString(AggregationRequest request)
private static string GetArgsString(AggregationRequest request)
{
var args = new List<object>();
request.SerializeRedisArgs(args);
return string.Join(" ", args);
}
[Fact]
public void testAggregation()
public void TestAggregation()
{
Assert.Equal("*", GetArgsString(new AggregationRequest()));
AggregationRequest r = new AggregationRequest().
......
......@@ -10,7 +10,7 @@ namespace NRediSearch.Test
public abstract class RediSearchTestBase : IDisposable
{
protected readonly ITestOutputHelper Output;
public RediSearchTestBase(ITestOutputHelper output)
protected RediSearchTestBase(ITestOutputHelper output)
{
muxer = GetWithFT(output);
Output = output;
......@@ -82,7 +82,7 @@ internal static ConnectionMultiplexer GetWithFT(ITestOutputHelper output)
return conn;
}
static Dictionary<string, RedisValue> Parse(RedisResult module)
private static Dictionary<string, RedisValue> Parse(RedisResult module)
{
var data = new Dictionary<string, RedisValue>();
var lines = (RedisResult[])module;
......
......@@ -9,7 +9,7 @@ namespace NRediSearch.Aggregation.Reducers
public abstract class Reducer
{
public override string ToString() => Name;
private string _field;
private readonly string _field;
internal Reducer(string field) => _field = field;
......
......@@ -6,23 +6,22 @@ namespace NRediSearch.Aggregation.Reducers
{
public static class Reducers
{
public static Reducer Count() => CountReducer.Instance;
sealed class CountReducer : Reducer
private sealed class CountReducer : Reducer
{
internal static readonly Reducer Instance = new CountReducer();
private CountReducer() : base(null) { }
public override string Name => "COUNT";
}
sealed class SingleFieldReducer : Reducer
private sealed class SingleFieldReducer : Reducer
{
private readonly string _name;
public override string Name { get; }
internal SingleFieldReducer(string name, string field) : base(field)
{
_name = name;
Name = name;
}
public override string Name => _name;
}
public static Reducer CountDistinct(string field) => new SingleFieldReducer("COUNT_DISTINCT", field);
......@@ -41,7 +40,7 @@ internal SingleFieldReducer(string name, string field) : base(field)
public static Reducer Quantile(string field, double percentile) => new QuantileReducer(field, percentile);
sealed class QuantileReducer : Reducer
private sealed class QuantileReducer : Reducer
{
private readonly double _percentile;
public QuantileReducer(string field, double percentile) : base(field)
......@@ -57,7 +56,7 @@ protected override void AddOwnArgs(List<object> args)
public override string Name => "QUANTILE";
}
public static Reducer FirstValue(string field, SortedField sortBy) => new FirstValueReducer(field, sortBy);
sealed class FirstValueReducer : Reducer
private sealed class FirstValueReducer : Reducer
{
private readonly SortedField? _sortBy;
public FirstValueReducer(string field, SortedField? sortBy) : base(field)
......@@ -85,7 +84,7 @@ protected override void AddOwnArgs(List<object> args)
public static Reducer RandomSample(string field, int size) => new RandomSampleReducer(field, size);
sealed class RandomSampleReducer : Reducer
private sealed class RandomSampleReducer : Reducer
{
private readonly int _size;
public RandomSampleReducer(string field, int size) : base(field)
......@@ -100,6 +99,5 @@ protected override void AddOwnArgs(List<object> args)
args.Add(_size.Boxed());
}
}
}
}
......@@ -50,9 +50,11 @@ public ConfiguredIndexOptions(IndexOptions options)
{
_options = options;
}
/// <summary>
/// Set a custom stopword list
/// Set a custom stopword list.
/// </summary>
/// <param name="stopwords">The new stopwords to use.</param>
public ConfiguredIndexOptions SetStopwords(params string[] stopwords)
{
_stopwords = stopwords ?? throw new ArgumentNullException(nameof(stopwords));
......@@ -179,7 +181,6 @@ public async Task<bool> CreateIndexAsync(Schema schema, IndexOptions options)
return (string)await _db.ExecuteAsync("FT.CREATE", args).ConfigureAwait(false) == "OK";
}
/// <summary>
/// Create the index definition in redis
/// </summary>
......@@ -435,7 +436,6 @@ public async Task<bool> AddHashAsync(RedisKey docId, double score, bool replace)
private static Dictionary<string, RedisValue> ParseGetInfo(RedisResult value)
{
var res = (RedisResult[])value;
var info = new Dictionary<string, RedisValue>();
for (int i = 0; i < res.Length; i += 2)
......@@ -659,40 +659,47 @@ public async Task<string> ExplainAsync(Query q)
}
/// <summary>
/// Get a document from the index
/// Get a document from the index.
/// </summary>
/// <param name="docId">The document ID to retrieve</param>
/// <param name="docId">The document ID to retrieve.</param>
/// <returns>The document as stored in the index. If the document does not exist, null is returned.</returns>
public Document GetDocument(string docId)
=> Document.Parse(docId, DbSync.Execute("FT.GET", _boxedIndexName, docId));
/// <summary>
/// Get a document from the index
/// Get a document from the index.
/// </summary>
/// <param name="docId">The document ID to retrieve</param>
/// <param name="docId">The document ID to retrieve.</param>
/// <returns>The document as stored in the index. If the document does not exist, null is returned.</returns>
public async Task<Document> GetDocumentAsync(string docId)
=> Document.Parse(docId, await _db.ExecuteAsync("FT.GET", _boxedIndexName, docId));
=> Document.Parse(docId, await _db.ExecuteAsync("FT.GET", _boxedIndexName, docId).ConfigureAwait(false));
/// <summary>
/// Replace specific fields in a document. Unlike #replaceDocument(), fields not present in the field list
/// are not erased, but retained. This avoids reindexing the entire document if the new values are not
/// indexed (though a reindex will happen
/// indexed (though a reindex will happen).
/// </summary>
/// <param name="docId">The ID of the document.</param>
/// <param name="fields">The fields and values to update.</param>
/// <param name="score">The new score of the document.</param>
public bool UpdateDocument(string docId, Dictionary<string, RedisValue> fields, double score = 1.0)
{
var args = BuildAddDocumentArgs(docId, fields, score, false, AddOptions.ReplacementPolicy.Partial, null, null);
return (string)DbSync.Execute("FT.ADD", args) == "OK";
}
/// <summary>
/// Replace specific fields in a document. Unlike #replaceDocument(), fields not present in the field list
/// are not erased, but retained. This avoids reindexing the entire document if the new values are not
/// indexed (though a reindex will happen
/// </summary>
/// <param name="docId">The ID of the document.</param>
/// <param name="fields">The fields and values to update.</param>
/// <param name="score">The new score of the document.</param>
public async Task<bool> UpdateDocumentAsync(string docId, Dictionary<string, RedisValue> fields, double score = 1.0)
{
var args = BuildAddDocumentArgs(docId, fields, score, false, AddOptions.ReplacementPolicy.Partial, null, null);
return ((string)await _db.ExecuteAsync("FT.ADD", args).ConfigureAwait(false) == "OK");
return (string)await _db.ExecuteAsync("FT.ADD", args).ConfigureAwait(false) == "OK";
}
}
}
......@@ -30,7 +30,6 @@ public Document(string id, Dictionary<string, RedisValue> fields, double score,
public IEnumerable<KeyValuePair<string, RedisValue>> GetProperties() => _properties;
public static Document Load(string id, double score, byte[] payload, RedisValue[] fields)
{
Document ret = new Document(id, score, payload);
......@@ -57,7 +56,7 @@ internal static Document Parse(string docId, RedisResult result)
if (result == null || result.IsNull) return null;
var arr = (RedisResult[])result;
var doc = new Document(docId);
for(int i = 0; i < arr.Length; )
{
doc[(string)arr[i++]] = (RedisValue)arr[i++];
......
......@@ -12,12 +12,13 @@ public static class Extensions
/// <summary>
/// Set a custom stopword list
/// </summary>
/// <param name="options">The <see cref="IndexOptions"/> to set stopwords on.</param>
/// <param name="stopwords">The stopwords to set.</param>
public static ConfiguredIndexOptions SetStopwords(this IndexOptions options, params string[] stopwords)
=> new ConfiguredIndexOptions(options).SetStopwords(stopwords);
internal static string AsRedisString(this double value, bool forceDecimal = false)
{
if (double.IsNegativeInfinity(value))
{
return "-inf";
......
......@@ -38,13 +38,13 @@ public static object Literal(this string value)
return boxed;
}
const int BOXED_MIN = -1, BOXED_MAX = 20;
static readonly object[] s_Boxed = Enumerable.Range(BOXED_MIN, BOXED_MAX - BOXED_MIN).Select(i => (object)i).ToArray();
private const int BOXED_MIN = -1, BOXED_MAX = 20;
private static readonly object[] s_Boxed = Enumerable.Range(BOXED_MIN, BOXED_MAX - BOXED_MIN).Select(i => (object)i).ToArray();
/// <summary>
/// Obtain a pre-boxed integer if possible, else box the inbound value
/// </summary>
/// <param name="value">The value to get a pre-boxed integer for.</param>
public static object Boxed(this int value) => value >= BOXED_MIN && value <= BOXED_MAX ? s_Boxed[value - BOXED_MIN] : value;
}
}
......@@ -3,15 +3,14 @@
namespace NRediSearch.QueryBuilder
{
/// <summary>
/// <para>
/// This class contains methods to construct query nodes. These query nodes can be added to parent query
/// nodes (building a chain) or used as the root query node.
///
/// You can use <pre>using static</pre> for these helper methods.
/// </para>
/// <para>You can use <pre>using static</pre> for these helper methods.</para>
/// </summary>
public static class QueryBuilder
{
public static QueryNode Intersect() => new IntersectNode();
/// <summary>
......@@ -20,147 +19,105 @@ public static class QueryBuilder
/// </summary>
/// <param name="n">sub-condition to add</param>
/// <returns>The node</returns>
public static QueryNode Intersect(params INode[] n)
{
return Intersect().Add(n);
}
public static QueryNode Intersect(params INode[] n) => Intersect().Add(n);
///
/// <summary>
/// Create a new intersection node with a field-value pair.
/// @param field The field that should contain this value. If this value is empty, then any field
/// will be checked.
/// @param values Value to check for. The node will be true only if the field (or any field)
/// contains <i>all</i> of the values
/// @return The node
///
public static QueryNode Intersect(string field, params Value[] values)
{
return Intersect().Add(field, values);
}
///
/// </summary>
/// <param name="field">The field that should contain this value. If this value is empty, then any field will be checked.</param>
/// <param name="values">Value to check for. The node will be true only if the field (or any field) contains *all* of the values.</param>
/// <returns>The query node.</returns>
public static QueryNode Intersect(string field, params Value[] values) => Intersect().Add(field, values);
/// <summary>
/// Helper method to create a new intersection node with a string value.
/// @param field The field to check. If left null or empty, all fields will be checked.
/// @param stringValue The value to check
/// @return The node
///
public static QueryNode Intersect(string field, string stringValue)
{
return Intersect(field, Values.Value(stringValue));
}
/// </summary>
/// <param name="field">The field to check. If left null or empty, all fields will be checked.</param>
/// <param name="stringValue">The value to check.</param>
/// <returns>The query node.</returns>
public static QueryNode Intersect(string field, string stringValue) => Intersect(field, Values.Value(stringValue));
public static QueryNode Union() => new UnionNode();
///
/// Create a union node. Union nodes evaluate to true if <i>any</i> of its children are true
/// @param n Child node
/// @return The union node
///
public static QueryNode Union(params INode[] n)
{
return Union().Add(n);
}
///
/// Create a union node which can match an one or more values
/// @param field Field to check. If empty, all fields are checked
/// @param values Values to search for. The node evaluates to true if {@code field} matches
/// any of the values
/// @return The union node
///
public static QueryNode Union(string field, params Value[] values)
{
return Union().Add(field, values);
}
///
/// Convenience method to match one or more strings. This is equivalent to
/// {@code union(field, value(v1), value(v2), value(v3)) ...}
/// @param field Field to match
/// @param values Strings to check for
/// @return The union node
///
public static QueryNode Union(string field, params string[] values)
{
return Union(field, Values.Value(values));
}
/// <summary>
/// Create a union node. Union nodes evaluate to true if <i>any</i> of its children are true.
/// </summary>
/// <param name="n">Child node.</param>
/// <returns>The union node.</returns>
public static QueryNode Union(params INode[] n) => Union().Add(n);
/// <summary>
/// Create a union node which can match an one or more values.
/// </summary>
/// <param name="field">Field to check. If empty, all fields are checked.</param>
/// <param name="values">Values to search for. The node evaluates to true if <paramref name="field"/> matches any of the values.</param>
/// <returns>The union node.</returns>
public static QueryNode Union(string field, params Value[] values) => Union().Add(field, values);
/// <summary>
/// Convenience method to match one or more strings. This is equivalent to <see cref="Union(string, Value[])"/>.
/// </summary>
/// <param name="field">Field to match.</param>
/// <param name="values">Strings to check for.</param>
/// <returns>The union node.</returns>
public static QueryNode Union(string field, params string[] values) => Union(field, Values.Value(values));
public static QueryNode Disjunct() => new DisjunctNode();
///
/// <summary>
/// Create a disjunct node. Disjunct nodes are true iff <b>any</b> of its children are <b>not</b> true.
/// Conversely, this node evaluates to false if <b>all</b> its children are true.
/// @param n Child nodes to add
/// @return The disjunct node
///
public static QueryNode Disjunct(params INode[] n)
{
return Disjunct().Add(n);
}
///
/// Create a disjunct node using one or more values. The node will evaluate to true iff the field does not
/// match <b>any</b> of the values.
/// @param field Field to check for (empty or null for any field)
/// @param values The values to check for
/// @return The node
///
public static QueryNode Disjunct(string field, params Value[] values)
{
return Disjunct().Add(field, values);
}
///
/// Create a disjunct node using one or more values. The node will evaluate to true iff the field does not
/// match <b>any</b> of the values.
/// @param field Field to check for (empty or null for any field)
/// @param values The values to check for
/// @return The node
///
public static QueryNode Disjunct(string field, params string[] values)
{
return Disjunct(field, Values.Value(values));
}
/// </summary>
/// <param name="n">Child nodes to add.</param>
/// <returns>The disjunct node.</returns>
public static QueryNode Disjunct(params INode[] n) => Disjunct().Add(n);
/// <summary>
/// Create a disjunct node using one or more values. The node will evaluate to true iff the field does not
/// match <b>any</b> of the values.
/// </summary>
/// <param name="field">Field to check for (empty or null for any field).</param>
/// <param name="values">The values to check for.</param>
/// <returns>The disjunct node.</returns>
public static QueryNode Disjunct(string field, params Value[] values) => Disjunct().Add(field, values);
/// <summary>
/// Create a disjunct node using one or more values. The node will evaluate to true iff the field does not
/// match <b>any</b> of the values.
/// </summary>
/// <param name="field">Field to check for (empty or null for any field).</param>
/// <param name="values">The values to check for.</param>
/// <returns>The disjunct node.</returns>
public static QueryNode Disjunct(string field, params string[] values) => Disjunct(field, Values.Value(values));
public static QueryNode DisjunctUnion() => new DisjunctUnionNode();
///
/// <summary>
/// Create a disjunct union node. This node evaluates to true if <b>all</b> of its children are not true.
/// Conversely, this node evaluates as false if <b>any</b> of its children are true.
/// @param n
/// @return The node
///
public static QueryNode DisjunctUnion(params INode[] n)
{
return DisjunctUnion().Add(n);
}
public static QueryNode DisjunctUnion(string field, params Value[] values)
{
return DisjunctUnion().Add(field, values);
}
public static QueryNode DisjunctUnion(string field, params string[] values)
{
return DisjunctUnion(field, Values.Value(values));
}
/// </summary>
/// <param name="n">The nodes to union.</param>
/// <returns>The node.</returns>
public static QueryNode DisjunctUnion(params INode[] n) => DisjunctUnion().Add(n);
public static QueryNode DisjunctUnion(string field, params Value[] values) => DisjunctUnion().Add(field, values);
public static QueryNode DisjunctUnion(string field, params string[] values) => DisjunctUnion(field, Values.Value(values));
/// <summary>
/// Creates a new <see cref="OptionalNode"/>.
/// </summary>
/// <returns>The new <see cref="OptionalNode"/>.</returns>
public static QueryNode Optional() => new OptionalNode();
///
/// <summary>
/// Create an optional node. Optional nodes do not affect which results are returned but they influence
/// ordering and scoring.
/// @param n The node to evaluate as optional
/// @return The new node
///
public static QueryNode Optional(params INode[] n)
{
return Optional().Add(n);
}
public static QueryNode Optional(string field, params Value[] values)
{
return Optional().Add(field, values);
}
/// </summary>
/// <param name="n">The nodes to evaluate as optional.</param>
/// <returns>The new node.</returns>
public static QueryNode Optional(params INode[] n) => Optional().Add(n);
public static QueryNode Optional(string field, params Value[] values) => Optional().Add(field, values);
}
}
......@@ -74,20 +74,20 @@ protected bool ShouldUseParens(ParenMode mode)
}
}
public virtual string ToString(ParenMode parenMode)
public virtual string ToString(ParenMode mode)
{
StringBuilder sb = new StringBuilder();
if (ShouldUseParens(parenMode))
if (ShouldUseParens(mode))
{
sb.Append("(");
}
var sj = new StringJoiner(sb, GetJoinString());
foreach (var n in children)
{
sj.Add(n.ToString(parenMode));
sj.Add(n.ToString(mode));
}
if (ShouldUseParens(parenMode))
if (ShouldUseParens(mode))
{
sb.Append(")");
}
......
......@@ -6,7 +6,7 @@ namespace NRediSearch.QueryBuilder
{
public sealed class RangeValue : Value
{
private double from, to;
private readonly double from, to;
private bool inclusiveMin = true, inclusiveMax = true;
public override bool IsCombinable() => false;
......
......@@ -6,9 +6,9 @@ namespace NRediSearch.QueryBuilder
{
internal ref struct StringJoiner // this is to replace a Java feature cleanly
{
readonly StringBuilder _sb;
readonly string _delimiter;
bool _isFirst;
private readonly StringBuilder _sb;
private readonly string _delimiter;
private bool _isFirst;
public StringJoiner(StringBuilder sb, string delimiter)
{
_sb = sb;
......
......@@ -16,7 +16,7 @@ public ValueNode(string field, string joinstr, params Value[] values)
_joinString = joinstr;
}
private static Value[] fromStrings(string[] values)
private static Value[] FromStrings(string[] values)
{
Value[] objs = new Value[values.Length];
for (int i = 0; i < values.Length; i++)
......@@ -27,7 +27,7 @@ private static Value[] fromStrings(string[] values)
}
public ValueNode(string field, string joinstr, params string[] values)
: this(field, joinstr, fromStrings(values)) { }
: this(field, joinstr, FromStrings(values)) { }
private string FormatField()
{
......@@ -69,7 +69,7 @@ private string ToStringDefault(ParenMode mode)
var sj = new StringJoiner(sb, _joinString);
foreach (var v in _values)
{
sj.Add(FormatField() + v.ToString());
sj.Add(FormatField() + v);
}
if (useParen)
{
......
......@@ -23,7 +23,6 @@ public ValueValue(string s)
internal static Value[] Value(string[] s) => Array.ConvertAll(s, _ => Value(_));
public static RangeValue Between(double from, double to) => new RangeValue(from, to);
public static RangeValue Between(int from, int to) => new RangeValue((double)from, (double)to);
......@@ -47,7 +46,7 @@ public static Value Tags(params string[] tags)
}
return new TagValue("{" + string.Join(" | ", tags) + "}");
}
sealed class TagValue : Value
private sealed class TagValue : Value
{
private readonly string s;
public TagValue(string s) { this.s = s; }
......
......@@ -80,9 +80,10 @@ internal override void SerializeRedisArgs(List<object> args)
public List<Field> Fields { get; } = new List<Field>();
/// <summary>
/// Add a field to the schema
/// Add a field to the schema.
/// </summary>
/// <returns>the schema object</returns>
/// <param name="field">The <see cref="Field"/> to add.</param>
/// <returns>The <see cref="Schema"/> object.</returns>
public Schema AddField(Field field)
{
Fields.Add(field ?? throw new ArgumentNullException(nameof(field)));
......@@ -90,11 +91,11 @@ public Schema AddField(Field field)
}
/// <summary>
/// Add a text field to the schema with a given weight
/// Add a text field to the schema with a given weight.
/// </summary>
/// <param name="name">the field's name</param>
/// <param name="weight">its weight, a positive floating point number</param>
/// <returns>the schema object</returns>
/// <param name="name">The field's name.</param>
/// <param name="weight">Its weight, a positive floating point number.</param>
/// <returns>The <see cref="Schema"/> object.</returns>
public Schema AddTextField(string name, double weight = 1.0)
{
Fields.Add(new TextField(name, weight));
......@@ -102,11 +103,11 @@ public Schema AddTextField(string name, double weight = 1.0)
}
/// <summary>
/// Add a text field that can be sorted on
/// Add a text field that can be sorted on.
/// </summary>
/// <param name="name">the field's name</param>
/// <param name="weight">its weight, a positive floating point number</param>
/// <returns>the schema object</returns>
/// <param name="name">The field's name.</param>
/// <param name="weight">Its weight, a positive floating point number.</param>
/// <returns>The <see cref="Schema"/> object.</returns>
public Schema AddSortableTextField(string name, double weight = 1.0)
{
Fields.Add(new TextField(name, weight, true));
......@@ -114,10 +115,10 @@ public Schema AddSortableTextField(string name, double weight = 1.0)
}
/// <summary>
/// Add a numeric field to the schema
/// Add a numeric field to the schema.
/// </summary>
/// <param name="name">the field's name</param>
/// <returns>the schema object</returns>
/// <param name="name">The field's name.</param>
/// <returns>The <see cref="Schema"/> object.</returns>
public Schema AddGeoField(string name)
{
Fields.Add(new Field(name, FieldType.Geo, false));
......@@ -125,10 +126,10 @@ public Schema AddGeoField(string name)
}
/// <summary>
/// Add a numeric field to the schema
/// Add a numeric field to the schema.
/// </summary>
/// <param name="name">the field's name</param>
/// <returns>the schema object</returns>
/// <param name="name">The field's name.</param>
/// <returns>The <see cref="Schema"/> object.</returns>
public Schema AddNumericField(string name)
{
Fields.Add(new Field(name, FieldType.Numeric, false));
......@@ -136,10 +137,10 @@ public Schema AddNumericField(string name)
}
/// <summary>
/// Add a numeric field that can be sorted on
/// Add a numeric field that can be sorted on.
/// </summary>
/// <param name="name">the field's name</param>
/// <returns>the schema object</returns>
/// <param name="name">The field's name.</param>
/// <returns>The <see cref="Schema"/> object.</returns>
public Schema AddSortableNumericField(string name)
{
Fields.Add(new Field(name, FieldType.Numeric, true));
......@@ -166,11 +167,11 @@ internal override void SerializeRedisArgs(List<object> args)
}
/// <summary>
/// Add a TAG field
/// Add a TAG field.
/// </summary>
/// <param name="name">the field's name</param>
/// <param name="separator">tag separator</param>
/// <returns>the schema object</returns>
/// <param name="name">The field's name.</param>
/// <param name="separator">The tag separator.</param>
/// <returns>The <see cref="Schema"/> object.</returns>
public Schema AddTagField(string name, string separator = ",")
{
Fields.Add(new TagField(name, separator));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment