Skip to content

Commit

Permalink
1.1.0 Release
Browse files Browse the repository at this point in the history
Notable changes:
* Support for JanusGraph 1.1.0
* Gremlin.Net updated to 3.7.3 (JanusGraph 1.1.0 also uses TinkerPop
3.7.3)
* Missing text predicates added (mostly negations, but also
`TextContainsPhrase`)

Fixes #165

Signed-off-by: Florian Hockmann <[email protected]>
  • Loading branch information
FlorianHockmann committed Dec 19, 2024
1 parent 5375dfd commit 0b4dfd5
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@ jobs:
env:
VALIDATE_ALL_CODEBASE: false
VALIDATE_JSCPD: false # need to find a way to ignore license headers for duplicate detection
VALIDATE_JSON_PRETTIER: false # this unfortunately conflicts with our .editorconfig for no final new line
VALIDATE_MARKDOWN_PRETTIER: false # this unfortunately conflicts with our .editorconfig for no final new line
DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,14 @@ The lowest supported JanusGraph version is 0.3.0.
The following table shows the supported JanusGraph versions for each version
of JanusGraph.Net:

| JanusGraph.Net | JanusGraph |
| -------------- | ---------------------- |
| 0.1.z | 0.3.z |
| 0.2.z | 0.4.z, 0.5.z |
| 0.3.z | 0.4.z, 0.5.z, 0.6.z |
| 0.4.z | (0.4.z, 0.5.z,) 0.6.z |
| 1.0.z | (0.6.z,) 1.0.z |
| JanusGraph.Net | JanusGraph |
| -------------- | --------------------- |
| 0.1.z | 0.3.z |
| 0.2.z | 0.4.z, 0.5.z |
| 0.3.z | 0.4.z, 0.5.z, 0.6.z |
| 0.4.z | (0.4.z, 0.5.z,) 0.6.z |
| 1.0.z | (0.6.z,) 1.0.z |
| 1.1.z | 1.0.0, 1.1.z |

While it should also be possible to use JanusGraph.Net with other versions of
JanusGraph than mentioned here, compatibility is not tested and some
Expand Down Expand Up @@ -132,7 +133,7 @@ Not all of the JanusGraph-specific types are already supported by both formats:
| Format | RelationIdentifier | Text predicates | Geoshapes | Geo predicates |
| ----------- | ------------------ | --------------- | --------- | -------------- |
| GraphSON3 | x | x | `Point` | - |
| GraphBinary | x | x | `Point`* | - |
| GraphBinary | x | x | `Point`\* | - |

\* Since version 1.0.0 of JanusGraph.Net.
JanusGraph also needs to be on version 1.0.0 or higher.
Expand Down
2 changes: 1 addition & 1 deletion src/JanusGraph.Net/JanusGraph.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<Version>1.0.0</Version>
<Version>1.1.0</Version>
<Title>JanusGraph.Net</Title>
<Authors>JanusGraph</Authors>
<Description>
Expand Down
66 changes: 66 additions & 0 deletions src/JanusGraph.Net/Text.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,41 @@ public static class Text
/// <returns>The text predicate.</returns>
public static P TextContains(string query) => new JanusGraphP("textContains", query);

/// <summary>
/// Is true if no words inside the text string match the query string.
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextNotContains(string query) => new JanusGraphP("textNotContains", query);

/// <summary>
/// Is true if (at least) one word inside the text string begins with the query string.
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextContainsPrefix(string query) => new JanusGraphP("textContainsPrefix", query);

/// <summary>
/// Is true if no words inside the text string begin with the query string.
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextNotContainsPrefix(string query) => new JanusGraphP("textNotContainsPrefix", query);

/// <summary>
/// Is true if (at least) one word inside the text string matches the given regular expression.
/// </summary>
/// <param name="regex">The regular expression.</param>
/// <returns>The text predicate.</returns>
public static P TextContainsRegex(string regex) => new JanusGraphP("textContainsRegex", regex);

/// <summary>
/// Is true if no words inside the text string match the given regular expression.
/// </summary>
/// <param name="regex">The regular expression.</param>
/// <returns>The text predicate.</returns>
public static P TextNotContainsRegex(string regex) => new JanusGraphP("textNotContainsRegex", regex);

/// <summary>
/// Is true if (at least) one word inside the text string is similar to the query String (based on
/// Levenshtein edit distance).
Expand All @@ -55,25 +77,69 @@ public static class Text
/// <returns>The text predicate.</returns>
public static P TextContainsFuzzy(string query) => new JanusGraphP("textContainsFuzzy", query);

/// <summary>
/// Is true if no words inside the text string are similar to the query string (based on Levenshtein edit
/// distance).
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextNotContainsFuzzy(string query) => new JanusGraphP("textNotContainsFuzzy", query);

/// <summary>
/// Is true if the text string does contain the sequence of words in the query string.
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextContainsPhrase(string query) => new JanusGraphP("textContainsPhrase", query);

/// <summary>
/// Is true if the text string does not contain the sequence of words in the query string.
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextNotContainsPhrase(string query) => new JanusGraphP("textNotContainsPhrase", query);

/// <summary>
/// Is true if the string value starts with the given query string.
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextPrefix(string query) => new JanusGraphP("textPrefix", query);

/// <summary>
/// Is true if the string value does not start with the given query string.
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextNotPrefix(string query) => new JanusGraphP("textNotPrefix", query);

/// <summary>
/// Is true if the string value matches the given regular expression in its entirety.
/// </summary>
/// <param name="regex">The regular expression.</param>
/// <returns>The text predicate.</returns>
public static P TextRegex(string regex) => new JanusGraphP("textRegex", regex);

/// <summary>
/// Is true if the string value does not match the given regular expression in its entirety.
/// </summary>
/// <param name="regex">The regular expression.</param>
/// <returns>The text predicate.</returns>
public static P TextNotRegex(string regex) => new JanusGraphP("textNotRegex", regex);

/// <summary>
/// Is true if the string value is similar to the given query string (based on Levenshtein edit distance).
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextFuzzy(string query) => new JanusGraphP("textFuzzy", query);

/// <summary>
/// Is true if the string value is not similar to the given query string (based on Levenshtein edit
/// distance).
/// </summary>
/// <param name="query">The query to search.</param>
/// <returns>The text predicate.</returns>
public static P TextNotFuzzy(string query) => new JanusGraphP("textNotFuzzy", query);
}
}
137 changes: 130 additions & 7 deletions test/JanusGraph.Net.IntegrationTest/TextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public abstract class TextTests : IDisposable
[Theory]
[InlineData("loves", 2)]
[InlineData("shouldNotBeFound", 0)]
public async Task TextContainsgivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
public async Task TextContainsGivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

Expand All @@ -42,11 +42,23 @@ public async Task TextContainsgivenSearchText_ExpectedCountOfElements(string sea
Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("loves", 1)]
[InlineData("shouldNotBeFound", 3)]
public async Task TextNotContainsGivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.E().Has("reason", Text.TextNotContains(searchText)).Count().Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("wave", 1)]
[InlineData("f", 2)]
[InlineData("shouldNotBeFound", 0)]
public async Task TextContainsPrefixgivenSearchText_ExpectedCountOfElements(string searchText,
public async Task TextContainsPrefixGivenSearchText_ExpectedCountOfElements(string searchText,
int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());
Expand All @@ -56,11 +68,26 @@ public async Task TextContainsPrefixgivenSearchText_ExpectedCountOfElements(stri
Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("wave", 2)]
[InlineData("f", 1)]
[InlineData("shouldNotBeFound", 3)]
public async Task TextNotContainsPrefixGivenSearchText_ExpectedCountOfElements(string searchText,
int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.E().Has("reason", Text.TextNotContainsPrefix(searchText)).Count()
.Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData(".*ave.*", 1)]
[InlineData("f.{3,4}", 2)]
[InlineData("shouldNotBeFound", 0)]
public async Task TextContainsRegexgivenRegex_ExpectedCountOfElements(string regex, int expectedCount)
public async Task TextContainsRegexGivenRegex_ExpectedCountOfElements(string regex, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

Expand All @@ -69,10 +96,23 @@ public async Task TextContainsRegexgivenRegex_ExpectedCountOfElements(string reg
Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData(".*ave.*", 2)]
[InlineData("f.{3,4}", 1)]
[InlineData("shouldNotBeFound", 3)]
public async Task TextNotContainsRegexGivenRegex_ExpectedCountOfElements(string regex, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.E().Has("reason", Text.TextNotContainsRegex(regex)).Count().Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("waxes", 1)]
[InlineData("shouldNotBeFound", 0)]
public async Task TextContainsFuzzygivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
public async Task TextContainsFuzzyGivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

Expand All @@ -81,11 +121,55 @@ public async Task TextContainsFuzzygivenSearchText_ExpectedCountOfElements(strin
Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("waxes", 2)]
[InlineData("shouldNotBeFound", 3)]
public async Task TextNotContainsFuzzyGivenSearchText_ExpectedCountOfElements(string searchText,
int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.E().Has("reason", Text.TextNotContainsFuzzy(searchText)).Count().Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("fresh breezes", 1)]
[InlineData("no fear", 1)]
[InlineData("fear of", 1)]
[InlineData("shouldNotBeFound", 0)]
public async Task TextContainsPhraseGivenSearchText_ExpectedCountOfElements(string searchText,
int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.E().Has("reason", Text.TextContainsPhrase(searchText)).Count().Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("fresh breezes", 2)]
[InlineData("no fear", 2)]
[InlineData("fear of", 2)]
[InlineData("shouldNotBeFound", 3)]
public async Task TextNotContainsPhraseGivenSearchText_ExpectedCountOfElements(string searchText,
int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.E().Has("reason", Text.TextNotContainsPhrase(searchText)).Count()
.Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("herc", 1)]
[InlineData("s", 3)]
[InlineData("shouldNotBeFound", 0)]
public async Task TextPrefixgivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
public async Task TextPrefixGivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

Expand All @@ -94,11 +178,24 @@ public async Task TextPrefixgivenSearchText_ExpectedCountOfElements(string searc
Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("herc", 11)]
[InlineData("s", 9)]
[InlineData("shouldNotBeFound", 12)]
public async Task TextNotPrefixGivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.V().Has("name", Text.TextNotPrefix(searchText)).Count().Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData(".*rcule.*", 1)]
[InlineData("s.{2}", 2)]
[InlineData("shouldNotBeFound", 0)]
public async Task TextRegexgivenRegex_ExpectedCountOfElements(string regex, int expectedCount)
public async Task TextRegexGivenRegex_ExpectedCountOfElements(string regex, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

Expand All @@ -107,11 +204,24 @@ public async Task TextRegexgivenRegex_ExpectedCountOfElements(string regex, int
Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData(".*rcule.*", 11)]
[InlineData("s.{2}", 10)]
[InlineData("shouldNotBeFound", 12)]
public async Task TextNotRegexGivenRegex_ExpectedCountOfElements(string regex, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.V().Has("name", Text.TextNotRegex(regex)).Count().Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("herculex", 1)]
[InlineData("ska", 2)]
[InlineData("shouldNotBeFound", 0)]
public async Task TextFuzzygivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
public async Task TextFuzzyGivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

Expand All @@ -120,6 +230,19 @@ public async Task TextFuzzygivenSearchText_ExpectedCountOfElements(string search
Assert.Equal(expectedCount, count);
}

[Theory]
[InlineData("herculex", 11)]
[InlineData("ska", 10)]
[InlineData("shouldNotBeFound", 12)]
public async Task TextNotFuzzyGivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount)
{
var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection());

var count = await g.V().Has("name", Text.TextNotFuzzy(searchText)).Count().Promise(t => t.Next());

Assert.Equal(expectedCount, count);
}

public void Dispose()
{
ConnectionFactory?.Dispose();
Expand Down
2 changes: 1 addition & 1 deletion test/JanusGraph.Net.IntegrationTest/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"dockerImage": "janusgraph/janusgraph:1.0.0"
"dockerImage": "janusgraph/janusgraph:1.1.0"
}

0 comments on commit 0b4dfd5

Please sign in to comment.