Skip to content

Commit

Permalink
Add enableDatatypeDiscovery capability to RDFAsyncGraph
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco De Salvo committed May 27, 2024
1 parent c172cd1 commit 947987a
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 12 deletions.
116 changes: 112 additions & 4 deletions RDFSharp.Test/Model/RDFAsyncGraphTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ limitations under the License.
using System;
using System.Collections.Generic;
using Wmhelp.XPath2.yyParser;
using System.Linq;

namespace RDFSharp.Test.Model
{
Expand Down Expand Up @@ -300,6 +301,17 @@ public async Task ShouldNotAddNullCollection()
Assert.IsTrue(asyncGraph.TriplesCount == 0);
}

[TestMethod]
public async Task ShouldAddDatatype()
{
RDFAsyncGraph asyncGraph = new RDFAsyncGraph();
RDFDatatype exlength6 = new RDFDatatype(new Uri("ex:exlength6"), RDFModelEnums.RDFDatatypes.XSD_STRING, [
new RDFLengthFacet(6), new RDFPatternFacet("^ex") ]);
await asyncGraph.AddDatatypeAsync(exlength6);

Assert.IsTrue(asyncGraph.TriplesCount == 11);
}

[TestMethod]
public async Task ShouldRemoveTriple()
{
Expand Down Expand Up @@ -1556,8 +1568,8 @@ public async Task ShouldImportFromFileAsync(string fileExtension, RDFModelEnums.
RDFTriple triple2 = new RDFTriple(new RDFResource("http://ex/subj/"), new RDFResource("http://ex/pred/"), new RDFResource("http://ex/obj/"));
await (await asyncGraph1.AddTripleAsync(triple1))
.AddTripleAsync(triple2);
await asyncGraph1.ToFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportFromFile{fileExtension}"));
RDFAsyncGraph asyncGraph2 = await RDFAsyncGraph.FromFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportFromFile{fileExtension}"));
await asyncGraph1.ToFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportFromFileAsync{fileExtension}"));
RDFAsyncGraph asyncGraph2 = await RDFAsyncGraph.FromFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportFromFileAsync{fileExtension}"));

Assert.IsNotNull(asyncGraph2);
Assert.IsTrue(asyncGraph2.TriplesCount == 2);
Expand All @@ -1576,6 +1588,43 @@ public async Task ShouldImportFromFileAsync(string fileExtension, RDFModelEnums.
}
}

[DataTestMethod]
[DataRow(".nt", RDFModelEnums.RDFFormats.NTriples)]
[DataRow(".rdf", RDFModelEnums.RDFFormats.RdfXml)]
[DataRow(".trix", RDFModelEnums.RDFFormats.TriX)]
[DataRow(".ttl", RDFModelEnums.RDFFormats.Turtle)]
public async Task ShouldImportFromFileAsyncWithEnabledDatatypeDiscovery(string fileExtension, RDFModelEnums.RDFFormats format)
{
RDFAsyncGraph asyncGraph1 = new RDFAsyncGraph();
RDFTriple triple1 = new RDFTriple(new RDFResource("http://ex/subj/"), new RDFResource("http://ex/pred/"), new RDFPlainLiteral("lit", "en-US"));
RDFTriple triple2 = new RDFTriple(new RDFResource("http://ex/subj/"), new RDFResource("http://ex/pred/"), new RDFResource("http://ex/obj/"));
await (await asyncGraph1.AddTripleAsync(triple1))
.AddTripleAsync(triple2);
await asyncGraph1.AddDatatypeAsync(new RDFDatatype(new Uri($"ex:mydtK{(int)format}"), RDFModelEnums.RDFDatatypes.XSD_STRING, [
new RDFPatternFacet("^ex$") ]));
await asyncGraph1.ToFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportFromFileAsync{fileExtension}WithEnabledDatatypeDiscovery"));
RDFAsyncGraph asyncGraph2 = await RDFAsyncGraph.FromFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportFromFileAsync{fileExtension}WithEnabledDatatypeDiscovery"), true);

Assert.IsNotNull(asyncGraph2);
Assert.IsTrue(asyncGraph2.TriplesCount == 9);
//RDF/XML uses xsd:qname for encoding predicates. In this test we demonstrate that
//triples with a predicate ending with "/" will loose this character once abbreviated:
//this is correct (being a glitch of RDF/XML specs) so at the end the AsyncGraphs will differ
if (format == RDFModelEnums.RDFFormats.RdfXml)
{
Assert.IsFalse(asyncGraph2.Equals(asyncGraph1));
Assert.IsTrue((await asyncGraph2.SelectTriplesByPredicateAsync(new RDFResource("http://ex/pred/"))).TriplesCount == 0);
Assert.IsTrue((await asyncGraph2.SelectTriplesByPredicateAsync(new RDFResource("http://ex/pred"))).TriplesCount == 2);
}
else
{
Assert.IsTrue(asyncGraph2.Equals(asyncGraph1));
}
//Test that automatic datatype discovery happened successfully
Assert.IsTrue(RDFDatatypeRegister.GetDatatype($"ex:mydtK{(int)format}").TargetDatatype == RDFModelEnums.RDFDatatypes.XSD_STRING);
Assert.IsTrue(RDFDatatypeRegister.GetDatatype($"ex:mydtK{(int)format}").Facets.Single() is RDFPatternFacet fct && fct.Pattern == "^ex$");
}

[DataTestMethod]
[DataRow(".nt", RDFModelEnums.RDFFormats.NTriples)]
[DataRow(".rdf", RDFModelEnums.RDFFormats.RdfXml)]
Expand All @@ -1584,8 +1633,8 @@ public async Task ShouldImportFromFileAsync(string fileExtension, RDFModelEnums.
public async Task ShouldImportEmptyFromFileAsync(string fileExtension, RDFModelEnums.RDFFormats format)
{
RDFAsyncGraph asyncGraph1 = new RDFAsyncGraph();
await asyncGraph1.ToFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportEmptyFromFile{fileExtension}"));
RDFAsyncGraph asyncGraph2 = await RDFAsyncGraph.FromFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportEmptyFromFile{fileExtension}"));
await asyncGraph1.ToFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportEmptyFromFileAsync{fileExtension}"));
RDFAsyncGraph asyncGraph2 = await RDFAsyncGraph.FromFileAsync(format, Path.Combine(Environment.CurrentDirectory, $"RDFAsyncGraphTest_ShouldImportEmptyFromFileAsync{fileExtension}"));

Assert.IsNotNull(asyncGraph2);
Assert.IsTrue(asyncGraph2.TriplesCount == 0);
Expand Down Expand Up @@ -1633,6 +1682,44 @@ public async Task ShouldImportFromStreamAsync(RDFModelEnums.RDFFormats format)
}
}

[DataTestMethod]
[DataRow(RDFModelEnums.RDFFormats.NTriples)]
[DataRow(RDFModelEnums.RDFFormats.RdfXml)]
[DataRow(RDFModelEnums.RDFFormats.TriX)]
[DataRow(RDFModelEnums.RDFFormats.Turtle)]
public async Task ShouldImportFromStreamAsyncWithEnabledDatatypeDiscovery(RDFModelEnums.RDFFormats format)
{
MemoryStream stream = new MemoryStream();
RDFAsyncGraph asyncGraph1 = new RDFAsyncGraph();
RDFTriple triple1 = new RDFTriple(new RDFResource("http://ex/subj/"), new RDFResource("http://ex/pred/"), new RDFPlainLiteral("lit", "en-US"));
RDFTriple triple2 = new RDFTriple(new RDFResource("http://ex/subj/"), new RDFResource("http://ex/pred/"), new RDFResource("http://ex/obj/"));
await (await asyncGraph1.AddTripleAsync(triple1))
.AddTripleAsync(triple2);
await asyncGraph1.AddDatatypeAsync(new RDFDatatype(new Uri($"ex:mydtKK{(int)format}"), RDFModelEnums.RDFDatatypes.XSD_STRING, [
new RDFPatternFacet("^ex$") ]));
await asyncGraph1.ToStreamAsync(format, stream);
RDFAsyncGraph asyncGraph2 = await RDFAsyncGraph.FromStreamAsync(format, new MemoryStream(stream.ToArray()), true);

Assert.IsNotNull(asyncGraph2);
Assert.IsTrue(asyncGraph2.TriplesCount == 9);
//RDF/XML uses xsd:qname for encoding predicates. In this test we demonstrate that
//triples with a predicate ending with "/" will loose this character once abbreviated:
//this is correct (being a glitch of RDF/XML specs) so at the end the AsyncGraphs will differ
if (format == RDFModelEnums.RDFFormats.RdfXml)
{
Assert.IsFalse(asyncGraph2.Equals(asyncGraph1));
Assert.IsTrue((await asyncGraph2.SelectTriplesByPredicateAsync(new RDFResource("http://ex/pred/"))).TriplesCount == 0);
Assert.IsTrue((await asyncGraph2.SelectTriplesByPredicateAsync(new RDFResource("http://ex/pred"))).TriplesCount == 2);
}
else
{
Assert.IsTrue(asyncGraph2.Equals(asyncGraph1));
}
//Test that automatic datatype discovery happened successfully
Assert.IsTrue(RDFDatatypeRegister.GetDatatype($"ex:mydtKK{(int)format}").TargetDatatype == RDFModelEnums.RDFDatatypes.XSD_STRING);
Assert.IsTrue(RDFDatatypeRegister.GetDatatype($"ex:mydtKK{(int)format}").Facets.Single() is RDFPatternFacet fct && fct.Pattern == "^ex$");
}

[DataTestMethod]
[DataRow(RDFModelEnums.RDFFormats.NTriples)]
[DataRow(RDFModelEnums.RDFFormats.RdfXml)]
Expand Down Expand Up @@ -1669,6 +1756,27 @@ public async Task ShouldImportFromDataTableAsync()
Assert.IsTrue(asyncGraph2.Equals(asyncGraph1));
}

[TestMethod]
public async Task ShouldImportFromDataTableAsyncWithEnabledDatatypeDiscovery()
{
RDFAsyncGraph asyncGraph1 = new RDFAsyncGraph();
RDFTriple triple1 = new RDFTriple(new RDFResource("http://subj/"), new RDFResource("http://pred/"), new RDFPlainLiteral("lit", "en-US"));
RDFTriple triple2 = new RDFTriple(new RDFResource("http://subj/"), new RDFResource("http://pred/"), new RDFResource("http://obj/"));
await (await asyncGraph1.AddTripleAsync(triple1))
.AddTripleAsync(triple2);
await asyncGraph1.AddDatatypeAsync(new RDFDatatype(new Uri("ex:mydtR"), RDFModelEnums.RDFDatatypes.XSD_STRING, [
new RDFPatternFacet("^ex$") ]));
DataTable table = await asyncGraph1.ToDataTableAsync();
RDFAsyncGraph asyncGraph2 = await RDFAsyncGraph.FromDataTableAsync(table, true);

Assert.IsNotNull(asyncGraph2);
Assert.IsTrue(asyncGraph2.TriplesCount == 9);
Assert.IsTrue(asyncGraph2.Equals(asyncGraph1));
//Test that automatic datatype discovery happened successfully
Assert.IsTrue(RDFDatatypeRegister.GetDatatype("ex:mydtR").TargetDatatype == RDFModelEnums.RDFDatatypes.XSD_STRING);
Assert.IsTrue(RDFDatatypeRegister.GetDatatype("ex:mydtR").Facets.Single() is RDFPatternFacet fct && fct.Pattern == "^ex$");
}

[TestMethod]
public async Task ShouldImportEmptyFromDataTableAsync()
{
Expand Down
23 changes: 15 additions & 8 deletions RDFSharp/Model/RDFAsyncGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.IO;
using System.Threading.Tasks;
Expand Down Expand Up @@ -162,6 +163,12 @@ public Task<RDFAsyncGraph> AddContainerAsync(RDFContainer container)
/// </summary>
public Task<RDFAsyncGraph> AddCollectionAsync(RDFCollection collection)
=> Task.Run(() => { WrappedGraph.AddCollection(collection); return this; });

/// <summary>
/// Adds the given datatype to the asynchronous graph
/// </summary>
public Task<RDFAsyncGraph> AddDatatypeAsync(RDFDatatype datatype)
=> Task.Run(() => { WrappedGraph.AddDatatype(datatype); return this; });
#endregion

#region Remove
Expand Down Expand Up @@ -323,26 +330,26 @@ public Task<DataTable> ToDataTableAsync()
/// <summary>
/// Reads an asynchronous graph from a file of the given RDF format
/// </summary>
public static Task<RDFAsyncGraph> FromFileAsync(RDFModelEnums.RDFFormats rdfFormat, string filepath)
=> Task.Run(() => new RDFAsyncGraph(RDFGraph.FromFile(rdfFormat, filepath)));
public static Task<RDFAsyncGraph> FromFileAsync(RDFModelEnums.RDFFormats rdfFormat, string filepath, bool enableDatatypeDiscovery=false)
=> Task.Run(() => new RDFAsyncGraph(RDFGraph.FromFile(rdfFormat, filepath, enableDatatypeDiscovery)));

/// <summary>
/// Reads an asynchronous graph from a stream of the given RDF format
/// </summary>
public static Task<RDFAsyncGraph> FromStreamAsync(RDFModelEnums.RDFFormats rdfFormat, Stream inputStream)
=> Task.Run(() => new RDFAsyncGraph(RDFGraph.FromStream(rdfFormat, inputStream)));
public static Task<RDFAsyncGraph> FromStreamAsync(RDFModelEnums.RDFFormats rdfFormat, Stream inputStream, bool enableDatatypeDiscovery=false)
=> Task.Run(() => new RDFAsyncGraph(RDFGraph.FromStream(rdfFormat, inputStream, enableDatatypeDiscovery)));

/// <summary>
/// Reads an asynchronous graph from a datatable with "Subject-Predicate-Object" columns
/// </summary>
public static Task<RDFAsyncGraph> FromDataTableAsync(DataTable table)
=> Task.Run(() => new RDFAsyncGraph(RDFGraph.FromDataTable(table)));
public static Task<RDFAsyncGraph> FromDataTableAsync(DataTable table, bool enableDatatypeDiscovery=false)
=> Task.Run(() => new RDFAsyncGraph(RDFGraph.FromDataTable(table, enableDatatypeDiscovery)));

/// <summary>
/// Reads an asynchronous graph by trying to dereference the given Uri
/// </summary>
public static Task<RDFAsyncGraph> FromUriAsync(Uri uri, int timeoutMilliseconds = 20000)
=> Task.Run(() => new RDFAsyncGraph(RDFGraph.FromUri(uri, timeoutMilliseconds)));
public static Task<RDFAsyncGraph> FromUriAsync(Uri uri, int timeoutMilliseconds=20000, bool enableDatatypeDiscovery=false)
=> Task.Run(() => new RDFAsyncGraph(RDFGraph.FromUri(uri, timeoutMilliseconds, enableDatatypeDiscovery)));
#endregion

#endregion
Expand Down

0 comments on commit 947987a

Please sign in to comment.