diff --git a/CHANGELOG.md b/CHANGELOG.md index 0143756..7e10c85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,17 @@ # Changelog +## Version 2.0.2 + +- Extend KeyDimensionLink with ShapePropertyMetadata + ## Version 2.0.1 + - Introduce DataType to DimensionValue ## Version 2.0.0 + BREAKING CHANGE: multiple renamings + - IServiceCollection.AddCubeRawData -> IServiceCollection.AddRawDataService - ICubeRawDataService -> IRawDataService - DimensionValue.Value -> DimensionValue.Object @@ -15,7 +22,9 @@ IRawDataService.CreateTriples: observationSetUri param has been removed. Static code analysis (Roslyn Rules) enabled. ## Version 1.0.1 + fix: add proper metadata for values properties #BKDO-1565 ## Version 1.0.0 -Initial publication on GitHub \ No newline at end of file + +Initial publication on GitHub diff --git a/src/Swiss.FCh.Cube.RawData.Tests/Services/RawDataServiceTests.cs b/src/Swiss.FCh.Cube.RawData.Tests/Services/RawDataServiceTests.cs index 986b4e7..ff76914 100644 --- a/src/Swiss.FCh.Cube.RawData.Tests/Services/RawDataServiceTests.cs +++ b/src/Swiss.FCh.Cube.RawData.Tests/Services/RawDataServiceTests.cs @@ -36,7 +36,21 @@ public void CreateTriples_WithValidInput_ReturnsTriplesCorrectly() ]; dataRows[0].KeyDimensionLinks.Add( - new KeyDimensionLink { Predicate = "example:hasProperty", Uri = "example:someValue"}); + new KeyDimensionLink + { + Predicate = "example:hasProperty", Uri = "example:someValue", ShapePropertyMetadata = new ShapePropertyMetadata + { + NodeKind = "w3:ns/shacl#IRI", + Type = "cube:MeasureDimension", + NameDe = "DE_Foo", + NameFr = "FR_Foo", + NameIt = "IT_Foo", + NameEn = "EN_Foo", + ScaleType = "qudt:NominalScale", + MinCount = 1, + MaxCount = 1 + } + }); dataRows[0].Values.Add(new DimensionValue { Predicate = "example:hasSomeOtherProperty", Object = "a value"}); @@ -67,7 +81,7 @@ public void CreateTriples_WithValidInput_ReturnsTriplesCorrectly() ValidateTriple(result, "http://example.com/cube/observationSet", "https://cube.link/observation", "http://example.com/key/1", "Observation set must have an observation"); ValidateTriple(result, "http://example.com/key/1", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "https://cube.link/Observation", "Type of observation must be set"); ValidateTriple(result, "http://example.com/key/1", "https://cube.link/observedBy", "https://ld.admin.ch/FCh", "Observation must have 'observed by' property"); - ValidateTriple(result, "http://example.com/key/1", "http://example.com/hasProperty", "http://example.com/someValue", "Observation must have linkt to a key dimension"); + ValidateTriple(result, "http://example.com/key/1", "http://example.com/hasProperty", "http://example.com/someValue", "Observation must have link to a key dimension"); ValidateTriple(result, "http://example.com/key/1", "http://schema.org/validFrom", "2020-01-01", "valid from of key/1 must be set"); ValidateTriple(result, "http://example.com/key/1", "http://schema.org/validTo", "2020-02-02", "valid to of key/1 must be set"); @@ -75,7 +89,7 @@ public void CreateTriples_WithValidInput_ReturnsTriplesCorrectly() ValidateTriple(result, "http://example.com/cube/observationSet", "https://cube.link/observation", "http://example.com/key/2", "Observation set must have an observation"); ValidateTriple(result, "http://example.com/key/2", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "https://cube.link/Observation", "Type of observation must be set"); ValidateTriple(result, "http://example.com/key/2", "https://cube.link/observedBy", "https://ld.admin.ch/FCh", "Observation must have 'observed by' property"); - ValidateTriple(result, "http://example.com/key/2", "http://example.com/hasProperty", "http://example.com/someOtherValue", "Observation must have linkt to a key dimension"); + ValidateTriple(result, "http://example.com/key/2", "http://example.com/hasProperty", "http://example.com/someOtherValue", "Observation must have link to a key dimension"); ValidateTriple(result, "http://example.com/key/2", "http://schema.org/validFrom", "2021-01-01", "valid from of key/2 must be set"); ValidateTriple(result, "http://example.com/key/2", "http://schema.org/validTo", "2021-02-02", "valid to of key/2 must be set"); @@ -83,6 +97,17 @@ public void CreateTriples_WithValidInput_ReturnsTriplesCorrectly() ValidateTriple(result, "http://example.com/cube/shape", "http://www.w3.org/ns/shacl#property", "_:blank_example_hasProperty", "Shape must contain blank not referencing 'hasProperty'"); ValidateTriple(result, "_:blank_example_hasProperty", "http://www.w3.org/ns/shacl#path", "http://example.com/hasProperty", "blank node for 'hasProperty' must have a path attached"); + //shape property metadata for 'hasProperty' (must be written only once) + ValidateTriple(result, "_:blank_example_hasProperty", "http://www.w3.org/ns/shacl#nodeKind", "http://www.w3.org/ns/shacl#IRI", "blank node for 'hasProperty' must have a node kind attached"); + ValidateTriple(result, "_:blank_example_hasProperty", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "https://cube.link/MeasureDimension", "blank node for 'hasProperty' must have a type attached"); + ValidateTriple(result, "_:blank_example_hasProperty", "http://schema.org/name", "DE_Foo", "blank node for 'hasProperty' must have a german name attached", "de"); + ValidateTriple(result, "_:blank_example_hasProperty", "http://schema.org/name", "FR_Foo", "blank node for 'hasProperty' must have a french name attached", "fr"); + ValidateTriple(result, "_:blank_example_hasProperty", "http://schema.org/name", "IT_Foo", "blank node for 'hasProperty' must have a italian name attached", "it"); + ValidateTriple(result, "_:blank_example_hasProperty", "http://schema.org/name", "EN_Foo", "blank node for 'hasProperty' must have a english name attached", "en"); + ValidateTriple(result, "_:blank_example_hasProperty", "http://www.w3.org/ns/shacl#minCount", "1", "blank node for 'hasProperty' must have min attached"); + ValidateTriple(result, "_:blank_example_hasProperty", "http://www.w3.org/ns/shacl#maxCount", "1", "blank node for 'hasProperty' must have max attached"); + ValidateTriple(result, "_:blank_example_hasProperty", "https://qudt.org/schema/scaleType", "qudt:NominalScale", "blank node for 'hasProperty' must have scale type attached"); + //shacl path for 'validFrom' ValidateTriple(result, "http://example.com/cube/shape", "http://www.w3.org/ns/shacl#property", "_:shape_blank_validFrom", "must have blank node for 'validFrom' path"); ValidateTriple(result, "_:shape_blank_validFrom", "http://www.w3.org/ns/shacl#path", "http://schema.org/validFrom", "must have shacl path for 'validFrom'"); diff --git a/src/Swiss.FCh.Cube.RawData/Model/KeyDimensionLink.cs b/src/Swiss.FCh.Cube.RawData/Model/KeyDimensionLink.cs index 63e99cb..397ebf7 100644 --- a/src/Swiss.FCh.Cube.RawData/Model/KeyDimensionLink.cs +++ b/src/Swiss.FCh.Cube.RawData/Model/KeyDimensionLink.cs @@ -5,5 +5,7 @@ public class KeyDimensionLink public string Predicate { get; set; } public string Uri { get; set; } + + public ShapePropertyMetadata ShapePropertyMetadata { get; set; } } } diff --git a/src/Swiss.FCh.Cube.RawData/Model/ShapePropertyMetadata.cs b/src/Swiss.FCh.Cube.RawData/Model/ShapePropertyMetadata.cs new file mode 100644 index 0000000..6a53bbf --- /dev/null +++ b/src/Swiss.FCh.Cube.RawData/Model/ShapePropertyMetadata.cs @@ -0,0 +1,15 @@ +namespace Swiss.FCh.Cube.RawData.Model +{ + public class ShapePropertyMetadata + { + public string NodeKind { get; set; } + public string Type { get; set; } + public string NameDe { get; set; } + public string NameFr { get; set; } + public string NameIt { get; set; } + public string NameEn { get; set; } + public string ScaleType { get; set; } + public int? MinCount { get; set; } + public int? MaxCount { get; set; } + } +} diff --git a/src/Swiss.FCh.Cube.RawData/Services/RawDataService.cs b/src/Swiss.FCh.Cube.RawData/Services/RawDataService.cs index 5e95d79..4895ecb 100644 --- a/src/Swiss.FCh.Cube.RawData/Services/RawDataService.cs +++ b/src/Swiss.FCh.Cube.RawData/Services/RawDataService.cs @@ -21,12 +21,13 @@ public IEnumerable CreateTriples( graph.NamespaceMap.AddNamespace("ld", new Uri("https://ld.admin.ch")); graph.NamespaceMap.AddNamespace("w3", new Uri("http://www.w3.org/")); graph.NamespaceMap.AddNamespace("cube", new Uri("https://cube.link/")); + graph.NamespaceMap.AddNamespace("qudt", new Uri("https://qudt.org/schema/")); var observationSetUri = $"{cubeUri}/observationSet"; var predicatesAlreadyAddedToShape = new List(); - // shape triples (constaint) + // shape triples (constraint) yield return new Triple( graph.CreateUriNode(cubeUri), graph.CreateUriNode("cube:observationConstraint"), @@ -97,6 +98,83 @@ public IEnumerable CreateTriples( graph.CreateUriNode("w3:ns/shacl#path"), graph.CreateUriNode(keyDimensionLink.Predicate)); + if (keyDimensionLink.ShapePropertyMetadata != null) + { + var shapeMetadata = keyDimensionLink.ShapePropertyMetadata; + + if (!string.IsNullOrWhiteSpace(keyDimensionLink.ShapePropertyMetadata.NodeKind)) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("w3:ns/shacl#nodeKind"), + graph.CreateUriNode(shapeMetadata.NodeKind)); + } + + if (!string.IsNullOrWhiteSpace(keyDimensionLink.ShapePropertyMetadata.Type)) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("rdf:type"), + graph.CreateUriNode(shapeMetadata.Type)); + } + + if (!string.IsNullOrWhiteSpace(keyDimensionLink.ShapePropertyMetadata.NameDe)) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("schema:name"), + graph.CreateLiteralNode(keyDimensionLink.ShapePropertyMetadata.NameDe, "de")); + } + + if (!string.IsNullOrWhiteSpace(keyDimensionLink.ShapePropertyMetadata.NameFr)) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("schema:name"), + graph.CreateLiteralNode(keyDimensionLink.ShapePropertyMetadata.NameFr, "fr")); + } + + if (!string.IsNullOrWhiteSpace(keyDimensionLink.ShapePropertyMetadata.NameIt)) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("schema:name"), + graph.CreateLiteralNode(keyDimensionLink.ShapePropertyMetadata.NameIt, "it")); + } + + if (!string.IsNullOrWhiteSpace(keyDimensionLink.ShapePropertyMetadata.NameEn)) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("schema:name"), + graph.CreateLiteralNode(keyDimensionLink.ShapePropertyMetadata.NameEn, "en")); + } + + if (!string.IsNullOrWhiteSpace(keyDimensionLink.ShapePropertyMetadata.ScaleType)) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("qudt:scaleType"), + graph.CreateLiteralNode(keyDimensionLink.ShapePropertyMetadata.ScaleType)); + } + + if (keyDimensionLink.ShapePropertyMetadata.MinCount != null) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("w3:ns/shacl#minCount"), + graph.CreateLiteralNode(keyDimensionLink.ShapePropertyMetadata.MinCount.Value.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#integer"))); + } + + if (keyDimensionLink.ShapePropertyMetadata.MaxCount != null) + { + yield return new Triple( + graph.CreateBlankNode(blankNodeId), + graph.CreateUriNode("w3:ns/shacl#maxCount"), + graph.CreateLiteralNode(keyDimensionLink.ShapePropertyMetadata.MaxCount.Value.ToString(), new Uri("http://www.w3.org/2001/XMLSchema#integer"))); + } + } + predicatesAlreadyAddedToShape.Add(keyDimensionLink.Predicate); } }