From a01e238c9eeb14b442bd14ac8d0a0920444bcd34 Mon Sep 17 00:00:00 2001 From: Lorenz Buehmann Date: Tue, 19 Jan 2021 12:57:53 +0100 Subject: [PATCH] fixes tests # Conflicts: # sansa-rdf/sansa-rdf-common/src/main/scala/net/sansa_stack/rdf/common/partition/r2rml/R2rmlUtils.scala --- .../common/partition/r2rml/R2rmlUtils.scala | 97 ++++++++++++++----- .../core/RdfPartitionerDefaultTests.scala | 22 ++--- 2 files changed, 86 insertions(+), 33 deletions(-) diff --git a/sansa-rdf/sansa-rdf-common/src/main/scala/net/sansa_stack/rdf/common/partition/r2rml/R2rmlUtils.scala b/sansa-rdf/sansa-rdf-common/src/main/scala/net/sansa_stack/rdf/common/partition/r2rml/R2rmlUtils.scala index 2b370183c..1d1b1c9f6 100644 --- a/sansa-rdf/sansa-rdf-common/src/main/scala/net/sansa_stack/rdf/common/partition/r2rml/R2rmlUtils.scala +++ b/sansa-rdf/sansa-rdf-common/src/main/scala/net/sansa_stack/rdf/common/partition/r2rml/R2rmlUtils.scala @@ -26,26 +26,48 @@ object R2rmlUtils { def createR2rmlMappings(partitioner: RdfPartitioner[RdfPartitionStateDefault], partition: RdfPartitionStateDefault, model: Model, - explodeLanguageTags: Boolean): Seq[TriplesMap] = { + explodeLanguageTags: Boolean, + escapeIdentifiers: Boolean): Seq[TriplesMap] = { createR2rmlMappings( partitioner, partition, x => createDefaultTableName(x), // Map the partition to a name new SqlEscaperBacktick, model, - explodeLanguageTags) + explodeLanguageTags, + escapeIdentifiers) } def createR2rmlMappings(partitioner: RdfPartitioner[RdfPartitionStateDefault], partitions: Seq[RdfPartitionStateDefault], model: Model, - explodeLanguageTags: Boolean): Seq[TriplesMap] = { + explodeLanguageTags: Boolean, + escapeIdentifiers: Boolean): Seq[TriplesMap] = { partitions .flatMap(p => createR2rmlMappings( partitioner, p, model, - explodeLanguageTags)) + explodeLanguageTags, + escapeIdentifiers)) + } + + def createR2rmlMappings(partitioner: RdfPartitioner[RdfPartitionStateDefault], + partitions: Seq[RdfPartitionStateDefault], + extractTableName: RdfPartitionStateDefault => String, + sqlEscaper: SqlEscaper, + model: Model, + explodeLanguageTags: Boolean, + escapeIdentifiers: Boolean): Seq[TriplesMap] = { + partitions + .flatMap(p => createR2rmlMappings( + partitioner, + p, + extractTableName, + sqlEscaper, + model, + explodeLanguageTags, + escapeIdentifiers)) } @@ -63,6 +85,7 @@ object R2rmlUtils { * @param outModel The output model * @param explodeLanguageTags If true then a mapping is generated for each language tag listed in the partition state. * Otherwise a generic language column is introduces + * @param escapeIdentifiers if all SQL identifiers have to be escaped * @return The set of {@link TriplesMap}s added to the output model */ def createR2rmlMappings(partitioner: RdfPartitioner[RdfPartitionStateDefault], @@ -70,41 +93,71 @@ object R2rmlUtils { extractTableName: RdfPartitionStateDefault => String, sqlEscaper: SqlEscaper, outModel: Model, - explodeLanguageTags: Boolean): Seq[TriplesMap] = { + explodeLanguageTags: Boolean, + escapeIdentifiers: Boolean): Seq[TriplesMap] = { val p = partitionState // Shorthand val t = partitioner.determineLayout(partitionState).schema - val attrNames = t.members.sorted.collect({ case m: MethodSymbol if m.isCaseAccessor => m.name.toString }) + var attrNames = t.members.sorted.collect({ case m: MethodSymbol if m.isCaseAccessor => m.name.toString }) + if (escapeIdentifiers) { + attrNames = attrNames.map(sqlEscaper.escapeColumnName) + } val predicateIri: String = partitionState.predicate - val tableName = extractTableName(partitionState) + var tableName = extractTableName(partitionState) + if (escapeIdentifiers) { + tableName = sqlEscaper.escapeTableName(tableName) + } if (explodeLanguageTags && attrNames.length == 3) { - val langColSql = sqlEscaper.escapeColumnName(attrNames(2)) - val columnsSql = attrNames.slice(0, 2).map(sqlEscaper.escapeColumnName).mkString(", ") - - p.languages.map(lang => { - val tableNameSql = sqlEscaper.escapeTableName(tableName) - val langSql = sqlEscaper.escapeStringLiteral(lang) - + val escapedColumns = if (escapeIdentifiers) attrNames else attrNames.map(sqlEscaper.escapeColumnName) + val projectedColumns = escapedColumns.slice(0, 2) + val columnsSql = projectedColumns.mkString(", ") + val langColSql = escapedColumns(2) + + // if there is only one language tag, we can omit the SQL query with the FILTER on the lang column + if (p.languages.size == 1) { + // TODO put to outer if-else and just add rr:language attribute + // TODO for this case we wouldn'T even need a table with a lang column, as long as the mapping keeps track of the language val tm: TriplesMap = outModel.createResource.as(classOf[TriplesMap]) + val pom: PredicateObjectMap = tm.addNewPredicateObjectMap() + pom.addPredicate(predicateIri) // create subject map val sm: SubjectMap = tm.getOrSetSubjectMap() setTermMapForNode(sm, 0, attrNames, p.subjectType, "", false) - val pom: PredicateObjectMap = tm.addNewPredicateObjectMap() - pom.addPredicate(predicateIri) - + // and the object map val om: ObjectMap = pom.addNewObjectMap() - om.setColumn(attrNames(1)) - om.setLanguage(lang) + om.setColumn(escapedColumns(1)) + if (p.languages.head.trim.nonEmpty) om.setLanguage(p.languages.head) + + tm.getOrSetLogicalTable().asBaseTableOrView().setTableName(tableName) + + Seq(tm) + } else { + p.languages.map(lang => { + val tableNameSql = if (escapeIdentifiers) tableName else sqlEscaper.escapeTableName(tableName) + val langSql = sqlEscaper.escapeStringLiteral(lang) + + val tm: TriplesMap = outModel.createResource.as(classOf[TriplesMap]) + + // create subject map + val sm: SubjectMap = tm.getOrSetSubjectMap() + setTermMapForNode(sm, 0, escapedColumns, p.subjectType, "", false) + + val pom: PredicateObjectMap = tm.addNewPredicateObjectMap() + pom.addPredicate(predicateIri) + val om: ObjectMap = pom.addNewObjectMap() + om.setColumn(escapedColumns(1)) + if (lang.trim.nonEmpty) om.setLanguage(lang) - tm.getOrSetLogicalTable().asR2rmlView().setSqlQuery(s"SELECT $columnsSql FROM $tableNameSql WHERE $langColSql = $langSql") + tm.getOrSetLogicalTable().asR2rmlView().setSqlQuery(s"SELECT $columnsSql FROM $tableNameSql WHERE $langColSql = $langSql") - tm - }).toSeq + tm + }).toSeq + } } else { val tm: TriplesMap = outModel.createResource.as(classOf[TriplesMap]) val pom: PredicateObjectMap = tm.addNewPredicateObjectMap() diff --git a/sansa-rdf/sansa-rdf-common/src/test/scala/net/sansa_stack/rdf/common/partition/core/RdfPartitionerDefaultTests.scala b/sansa-rdf/sansa-rdf-common/src/test/scala/net/sansa_stack/rdf/common/partition/core/RdfPartitionerDefaultTests.scala index b0a27bb9d..f8ad489a4 100644 --- a/sansa-rdf/sansa-rdf-common/src/test/scala/net/sansa_stack/rdf/common/partition/core/RdfPartitionerDefaultTests.scala +++ b/sansa-rdf/sansa-rdf-common/src/test/scala/net/sansa_stack/rdf/common/partition/core/RdfPartitionerDefaultTests.scala @@ -56,7 +56,7 @@ class RdfPartitionerDefaultTests extends FunSuite { | |[ rr:logicalTable [ rr:tableName "http://xmlns.com/foaf/0.1/givenName_XMLSchema#string_lang" ] ; | rr:predicateObjectMap [ rr:objectMap [ rr:column "o" ; - | rr:langColumn "l" + | rr:languageColumn "l" | ] ; | rr:predicate | ] ; @@ -71,7 +71,7 @@ class RdfPartitionerDefaultTests extends FunSuite { val model = ModelFactory.createDefaultModel() - val triplesMaps = R2rmlUtils.createR2rmlMappings(RdfPartitionerDefault, partitionState, model, false) + val triplesMaps = R2rmlUtils.createR2rmlMappings(RdfPartitionerDefault, partitionState, model, false, false) // There must be just a single triples map assert(triplesMaps.size == 1) @@ -79,7 +79,7 @@ class RdfPartitionerDefaultTests extends FunSuite { val triplesMap = triplesMaps(0) val actual = triplesMap.getModel - assert(expected.isIsomorphicWith(actual)) + assert(expected.isIsomorphicWith(model)) } test("export partition with lang tags exploded as R2RML should result in a separate TriplesMap per language tag") { @@ -89,34 +89,34 @@ class RdfPartitionerDefaultTests extends FunSuite { """ | @base . |[ <#logicalTable> [ <#sqlQuery> "SELECT `s`, `o` FROM `http://xmlns.com/foaf/0.1/givenName_XMLSchema#string_lang` WHERE `l` = 'fr'" ] ; - | <#predicateObjectMap> [ <#objectMap> [ <#column> "o" ; + | <#predicateObjectMap> [ <#objectMap> [ <#column> "`o`" ; | <#language> "fr" | ] ; | <#predicate> | ] ; - | <#subjectMap> [ <#column> "s" ; + | <#subjectMap> [ <#column> "`s`" ; | <#datatype> <#IRI> | ] |] . | |[ <#logicalTable> [ <#sqlQuery> "SELECT `s`, `o` FROM `http://xmlns.com/foaf/0.1/givenName_XMLSchema#string_lang` WHERE `l` = 'de'" ] ; - | <#predicateObjectMap> [ <#objectMap> [ <#column> "o" ; + | <#predicateObjectMap> [ <#objectMap> [ <#column> "`o`" ; | <#language> "de" | ] ; | <#predicate> | ] ; - | <#subjectMap> [ <#column> "s" ; + | <#subjectMap> [ <#column> "`s`" ; | <#datatype> <#IRI> | ] |] . | |[ <#logicalTable> [ <#sqlQuery> "SELECT `s`, `o` FROM `http://xmlns.com/foaf/0.1/givenName_XMLSchema#string_lang` WHERE `l` = 'en'" ] ; - | <#predicateObjectMap> [ <#objectMap> [ <#column> "o" ; + | <#predicateObjectMap> [ <#objectMap> [ <#column> "`o`" ; | <#language> "en" | ] ; | <#predicate> | ] ; - | <#subjectMap> [ <#column> "s" ; + | <#subjectMap> [ <#column> "`s`" ; | <#datatype> <#IRI> | ] |] . @@ -129,7 +129,7 @@ class RdfPartitionerDefaultTests extends FunSuite { val actual = ModelFactory.createDefaultModel() - val triplesMaps = R2rmlUtils.createR2rmlMappings(RdfPartitionerDefault, partitionState, actual, true) + val triplesMaps = R2rmlUtils.createR2rmlMappings(RdfPartitionerDefault, partitionState, actual, true, true) RDFDataMgr.write(System.out, actual, RDFFormat.TURTLE_PRETTY) @@ -144,7 +144,7 @@ class RdfPartitionerDefaultTests extends FunSuite { 2, "http://www.w3.org/2001/XMLSchema#string", true, Set("en", "de", "fr")) val exportModel = ModelFactory.createDefaultModel() - val triplesMaps = R2rmlUtils.createR2rmlMappings(RdfPartitionerDefault, partitionState, exportModel, true) + val triplesMaps = R2rmlUtils.createR2rmlMappings(RdfPartitionerDefault, partitionState, exportModel, true, true) // val exportModel = exportModel // RdfPartitionImportExport.exportAsR2RML(RdfPartitionerDefault, partitionState, true) exportModel.write(System.out, "Turtle", "http://www.w3.org/ns/r2rml#")