-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added support for SPARQLConstraint
- Loading branch information
Showing
44 changed files
with
1,971 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { BindingsFactory } from '@comunica/bindings-factory' | ||
import { QueryEngine } from '@comunica/query-sparql-rdfjs' | ||
import { Readable } from 'readable-stream' | ||
|
||
function bindingsToObject (row) { | ||
const args = {} | ||
|
||
for (const [key, value] of [...row]) { | ||
args[key.value] = value | ||
} | ||
|
||
return args | ||
} | ||
|
||
async function select ({ bindings, dataset, factory, query }) { | ||
const store = new DatasetSource(dataset) | ||
const engine = new QueryEngine() | ||
|
||
const bindingsFactory = new BindingsFactory(factory) | ||
const initialBindings = bindingsFactory.bindings(bindings) | ||
|
||
const stream = await engine.queryBindings(query, { | ||
sources: [store], | ||
initialBindings | ||
}) | ||
|
||
return stream.toArray() | ||
} | ||
|
||
function stringifyPath (path) { | ||
if (!path) { | ||
return null | ||
} | ||
|
||
return path.map(pathStep => { | ||
let sparqlPath = '' | ||
|
||
if (pathStep.start === 'object' && pathStep.end === 'subject') { | ||
sparqlPath += '^' | ||
} | ||
|
||
sparqlPath += pathStep.predicates.map(p => `<${p.value}>`).join('|') | ||
|
||
if (pathStep.quantifier === 'oneOrMore') { | ||
sparqlPath += '+' | ||
} else if (pathStep.quantifier === 'zeroOrMore') { | ||
sparqlPath += '*' | ||
} else if (pathStep.quantifier === 'zeroOrOne') { | ||
sparqlPath += '?' | ||
} | ||
|
||
return sparqlPath | ||
}).join('/') | ||
} | ||
|
||
class DatasetSource { | ||
constructor (dataset) { | ||
this.dataset = dataset | ||
} | ||
|
||
match (subject, predicate, object, graph) { | ||
return Readable.from(this.dataset.match(subject, predicate, object, graph)) | ||
} | ||
} | ||
|
||
export { | ||
bindingsToObject, | ||
select, | ||
stringifyPath | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import * as ns from '../namespaces.js' | ||
import parsePath from '../parsePath.js' | ||
import { bindingsToObject, select, stringifyPath } from '../sparql.js' | ||
|
||
function stringifyPrefixes (ptr, prefixes = []) { | ||
for (const imports of ptr.out([ns.owl.imports])) { | ||
stringifyPrefixes(imports, prefixes) | ||
} | ||
|
||
for (const declare of ptr.out([ns.sh.declare])) { | ||
const prefix = declare.out([ns.sh.prefix]).value | ||
const namespace = declare.out([ns.sh.namespace]).value | ||
|
||
prefixes.push(`PREFIX ${prefix}: <${namespace}>`) | ||
} | ||
|
||
return prefixes | ||
} | ||
|
||
function compileSparql (shape) { | ||
const select = shape.sparql.out([ns.sh.select]).value | ||
const prefixes = stringifyPrefixes(shape.sparql.out([ns.sh.prefixes])) | ||
const sparqlPath = stringifyPath(shape.path) | ||
const message = shape.sparql.out([ns.sh.message]).terms | ||
|
||
const query = [...prefixes, select] | ||
.filter(Boolean) | ||
.join('\n') | ||
.split('$PATH') | ||
.join(sparqlPath) | ||
|
||
return { | ||
generic: validateSparql({ message, query, source: shape.sparql.terms }) | ||
} | ||
} | ||
|
||
function validateSparql ({ message, query, source }) { | ||
return async context => { | ||
const dataset = context.focusNode.dataset | ||
const factory = context.factory | ||
const bindings = [[factory.variable('this'), context.focusNode.term]] | ||
const rows = await select({ bindings, dataset, factory, query }) | ||
|
||
for (const row of rows) { | ||
const args = bindingsToObject(row) | ||
const path = row.has('path') && parsePath(context.focusNode.node([row.get('path')])) | ||
const value = context.focusNode.node([row.get('value') || context.focusNode.term]) | ||
|
||
context.violation(ns.sh.SPARQLConstraintComponent, { args, message, path, source, value }) | ||
} | ||
|
||
if (rows.length === 0) { | ||
context.debug(ns.sh.SPARQLConstraintComponent, { source }) | ||
} | ||
} | ||
} | ||
|
||
export { | ||
compileSparql | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,4 +5,5 @@ | |
<> | ||
a mf:Manifest ; | ||
mf:include <core/manifest.ttl> ; | ||
mf:include <sparql/manifest.ttl> ; | ||
. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> . | ||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | ||
@prefix sht: <http://www.w3.org/ns/shacl-test#> . | ||
|
||
<> | ||
a mf:Manifest ; | ||
rdfs:label "Tests converted from http://datashapes.org/sh/tests/tests/sparql/component" ; | ||
mf:include <optional-001.ttl> ; | ||
mf:include <propertyValidator-select-001.ttl> ; | ||
mf:include <validator-001.ttl> ; | ||
. |
83 changes: 83 additions & 0 deletions
83
test/assets/data-shapes/sparql/component/nodeValidator-001.ttl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
@prefix dash: <http://datashapes.org/dash#> . | ||
@prefix ex: <http://datashapes.org/sh/tests/sparql/component/nodeValidator-001.test#> . | ||
@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> . | ||
@prefix owl: <http://www.w3.org/2002/07/owl#> . | ||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . | ||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | ||
@prefix sh: <http://www.w3.org/ns/shacl#> . | ||
@prefix sht: <http://www.w3.org/ns/shacl-test#> . | ||
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . | ||
|
||
<http://datashapes.org/sh/tests/sparql/component/nodeValidator-001.test> | ||
sh:declare [ | ||
rdf:type sh:PrefixDeclaration ; | ||
sh:namespace "http://datashapes.org/sh/tests/sparql/component/nodeValidator-001.test#"^^xsd:anyURI ; | ||
sh:prefix "ex" ; | ||
] ; | ||
. | ||
ex:InvalidResource1 | ||
ex:property "Other" ; | ||
. | ||
ex:TestConstraintComponent | ||
rdf:type sh:ConstraintComponent ; | ||
rdfs:label "Test constraint component" ; | ||
sh:nodeValidator [ | ||
rdf:type sh:SPARQLSelectValidator ; | ||
sh:select """ | ||
SELECT DISTINCT $this | ||
WHERE { | ||
$this ?p ?o . | ||
FILTER NOT EXISTS { | ||
$this ex:property ?requiredParam . | ||
}}""" ; | ||
sh:prefixes <http://datashapes.org/sh/tests/sparql/component/nodeValidator-001.test> ; | ||
] ; | ||
sh:parameter [ | ||
sh:path ex:optionalParam ; | ||
sh:datatype xsd:integer ; | ||
sh:name "optional param" ; | ||
sh:optional "true"^^xsd:boolean ; | ||
] ; | ||
sh:parameter [ | ||
sh:path ex:requiredParam ; | ||
sh:datatype xsd:string ; | ||
sh:name "required param" ; | ||
] ; | ||
. | ||
ex:TestShape | ||
rdf:type sh:NodeShape ; | ||
ex:requiredParam "Value" ; | ||
rdfs:label "Test shape" ; | ||
sh:targetNode ex:InvalidResource1 ; | ||
sh:targetNode ex:ValidResource1 ; | ||
. | ||
ex:ValidResource1 | ||
ex:property "Value" ; | ||
. | ||
<> | ||
rdf:type mf:Manifest ; | ||
mf:entries ( | ||
<nodeValidator-001> | ||
) ; | ||
. | ||
<nodeValidator-001> | ||
rdf:type sht:Validate ; | ||
rdfs:label "Test of sh:nodeValidator 001" ; | ||
mf:action [ | ||
sht:dataGraph <> ; | ||
sht:shapesGraph <> ; | ||
] ; | ||
mf:result [ | ||
rdf:type sh:ValidationReport ; | ||
sh:conforms "false"^^xsd:boolean ; | ||
sh:result [ | ||
rdf:type sh:ValidationResult ; | ||
sh:focusNode ex:InvalidResource1 ; | ||
sh:resultSeverity sh:Violation ; | ||
sh:sourceConstraintComponent ex:TestConstraintComponent ; | ||
sh:sourceShape ex:TestShape ; | ||
sh:value ex:InvalidResource1 ; | ||
] ; | ||
] ; | ||
mf:status sht:proposed ; | ||
. |
Oops, something went wrong.