sparqlalgebrajs
Advanced tools
Comparing version 4.0.1 to 4.0.2
@@ -73,4 +73,5 @@ "use strict"; | ||
throw new Error('Translate only works on complete query or update objects.'); | ||
const vars = new Set(Object.keys(inScopeVariables(sparql)).map(factory.createTerm.bind(factory))); | ||
let res; | ||
// find ALL variables here to fill `variables` array | ||
findAllVariables(sparql); | ||
if (sparql.type === 'query') { | ||
@@ -80,3 +81,3 @@ // group and where are identical, having only 1 makes parsing easier, can be undefined in DESCRIBE | ||
res = translateGroupGraphPattern(group); | ||
res = translateAggregates(sparql, res, vars); | ||
res = translateAggregates(sparql, res); | ||
} | ||
@@ -87,3 +88,3 @@ else if (sparql.type === 'update') { | ||
if (blankToVariable) { | ||
res = translateBlankNodesToVariables(res, vars); | ||
res = translateBlankNodesToVariables(res); | ||
} | ||
@@ -95,38 +96,99 @@ return res; | ||
} | ||
function isObject(o) { | ||
return o !== null && typeof o === 'object'; | ||
function isTerm(term) { | ||
return Boolean(term === null || term === void 0 ? void 0 : term.termType); | ||
} | ||
// This is not completely correct but this way we also catch SPARQL.js triples | ||
function isTriple(triple) { | ||
return triple.subject && triple.predicate && triple.object; | ||
} | ||
function isVariable(term) { | ||
return (term === null || term === void 0 ? void 0 : term.termType) === 'Variable'; | ||
} | ||
// Will be used to make sure new variables don't overlap | ||
function findAllVariables(thingy) { | ||
if (isTerm(thingy)) { | ||
if (isVariable(thingy)) { | ||
// Variables don't store the `?` | ||
variables.add(`?${thingy.value}`); | ||
} | ||
} | ||
else if (Array.isArray(thingy)) { | ||
for (const entry of thingy) | ||
findAllVariables(entry); | ||
} | ||
else if (thingy && typeof thingy === 'object') { | ||
for (let key of Object.keys(thingy)) { | ||
// Some variables are hidden in keys (specifically for VALUES) | ||
if (key.startsWith('?')) | ||
variables.add(key); | ||
findAllVariables(thingy[key]); | ||
} | ||
} | ||
} | ||
// 18.2.1 | ||
function inScopeVariables(thingy) { | ||
let inScope = {}; | ||
if (isVariable(thingy)) { | ||
inScope[(0, rdf_string_1.termToString)(thingy)] = true; | ||
variables.add(thingy.value); // keep track of all variables so we don't generate duplicates | ||
if (isTriple(thingy)) { | ||
// Note that this could both be an actual Quad or a SPARQL.js triple (without graph) | ||
const result = [ | ||
inScopeVariables(thingy.subject), | ||
inScopeVariables(thingy.predicate), | ||
inScopeVariables(thingy.object), | ||
thingy.graph ? inScopeVariables(thingy.graph) : {} | ||
]; | ||
Object.assign(inScope, ...result); | ||
} | ||
else if (isObject(thingy)) { | ||
if (thingy.type === 'bind') { | ||
inScopeVariables(thingy.expression); // to fill `variables` | ||
Object.assign(inScope, inScopeVariables(thingy.variable)); | ||
else if (isTerm(thingy)) { | ||
if (isVariable(thingy)) | ||
inScope[thingy.value] = thingy; | ||
} | ||
else if (thingy.type === 'bgp') { | ||
// Slightly cheating but this is a subset of what we support so is fine | ||
const quads = thingy.triples; | ||
Object.assign(inScope, ...quads.map(inScopeVariables)); | ||
} | ||
else if (thingy.type === 'path') { | ||
// A path predicate should not have variables but just iterating so we could theoretically support this | ||
Object.assign(inScope, ...thingy.items.map(inScopeVariables)); | ||
} | ||
else if (thingy.type === 'group' || thingy.type === 'union' || thingy.type === 'optional') { | ||
Object.assign(inScope, ...thingy.patterns.map(inScopeVariables)); | ||
} | ||
else if (thingy.type === 'service' || thingy.type === 'graph') { | ||
Object.assign(inScope, inScopeVariables(thingy.name)); | ||
Object.assign(inScope, ...thingy.patterns.map(inScopeVariables)); | ||
} | ||
else if (thingy.type === 'bind') { | ||
Object.assign(inScope, inScopeVariables(thingy.variable)); | ||
} | ||
else if (thingy.type === 'values') { | ||
if (thingy.values.length > 0) { | ||
const vars = Object.keys(thingy.values[0]).map(v => factory.createTerm(v)); | ||
Object.assign(inScope, ...vars.map(inScopeVariables)); | ||
} | ||
else if (thingy.queryType === 'SELECT') { | ||
let all = inScopeVariables(thingy.where); // always executing this makes sure `variables` gets filled correctly | ||
for (let v of thingy.variables) { | ||
if (util_1.default.isWildcard(v)) | ||
Object.assign(inScope, all); | ||
else if (v.variable) // aggregates | ||
} | ||
else if (thingy.type === 'query') { | ||
if (thingy.queryType === 'SELECT' || thingy.queryType === 'DESCRIBE') { | ||
if (thingy.where && thingy.variables.some(util_1.default.isWildcard)) | ||
Object.assign(inScope, ...thingy.where.map(inScopeVariables)); | ||
for (const v of thingy.variables) { | ||
if (isVariable(v)) | ||
Object.assign(inScope, inScopeVariables(v)); | ||
else if (v.variable) | ||
Object.assign(inScope, inScopeVariables(v.variable)); | ||
else | ||
Object.assign(inScope, inScopeVariables(v)); | ||
} | ||
// TODO: I'm not 100% sure if you always add these or only when '*' was selected | ||
if (thingy.group) | ||
for (let v of thingy.group) | ||
Object.assign(inScope, inScopeVariables(v)); | ||
if (thingy.queryType === 'SELECT') { | ||
if (thingy.group) { | ||
// Grouping can be a VariableExpression, typings are wrong | ||
for (const g of thingy.group) { | ||
if (g.variable) | ||
Object.assign(inScope, inScopeVariables(g.variable)); | ||
} | ||
} | ||
if (thingy.values) { | ||
const values = { type: 'values', values: thingy.values }; | ||
Object.assign(inScope, inScopeVariables(values)); | ||
} | ||
} | ||
} | ||
else | ||
for (let key of Object.keys(thingy)) | ||
Object.assign(inScope, inScopeVariables(thingy[key])); | ||
} | ||
@@ -434,3 +496,3 @@ return inScope; | ||
// --------------------------------------- AGGREGATES | ||
function translateAggregates(query, res, variables) { | ||
function translateAggregates(query, res) { | ||
// Typings for ConstructQuery are wrong and missing several fields so we will cast quite often to SelectQuery to have partial typings | ||
@@ -471,6 +533,8 @@ const select = query; | ||
// 18.2.4.4 | ||
let PV = new Set(); | ||
let PV = []; | ||
if (query.queryType === 'SELECT' || query.queryType === 'DESCRIBE') { | ||
// Sort variables for consistent output | ||
if (query.variables.some((e) => e && util_1.default.isWildcard(e))) | ||
PV = variables; | ||
PV = Object.values(inScopeVariables(query)) | ||
.sort((left, right) => left.value.localeCompare(right.value)); | ||
else { | ||
@@ -481,6 +545,6 @@ // Wildcard has been filtered out above | ||
if (isVariable(v) || !('variable' in v)) | ||
PV.add(v); | ||
PV.push(v); | ||
else if (v.variable) // ... AS ?x | ||
{ | ||
PV.add(v.variable); | ||
PV.push(v.variable); | ||
E.push(v); | ||
@@ -508,3 +572,3 @@ } | ||
// Named nodes are only possible in a DESCRIBE so this cast is safe | ||
res = factory.createProject(res, Array.from(PV)); | ||
res = factory.createProject(res, PV); | ||
// 18.2.5.3 | ||
@@ -522,3 +586,3 @@ if (select.distinct) | ||
else if (query.queryType === 'DESCRIBE') | ||
res = factory.createDescribe(res, Array.from(PV)); | ||
res = factory.createDescribe(res, PV); | ||
// Slicing needs to happen after construct/describe | ||
@@ -648,6 +712,6 @@ // 18.2.5.5 | ||
} | ||
function translateBlankNodesToVariables(res, variables) { | ||
function translateBlankNodesToVariables(res) { | ||
const blankToVariableMapping = {}; | ||
const variablesRaw = Array.from(variables).reduce((acc, variable) => { | ||
acc[variable.value] = true; | ||
acc[variable] = true; | ||
return acc; | ||
@@ -675,3 +739,3 @@ }, {}); | ||
return { | ||
result: factory.createConstruct(translateBlankNodesToVariables(op.input, variables), op.template), | ||
result: factory.createConstruct(translateBlankNodesToVariables(op.input), op.template), | ||
recurse: false, | ||
@@ -678,0 +742,0 @@ }; |
{ | ||
"name": "sparqlalgebrajs", | ||
"version": "4.0.1", | ||
"version": "4.0.2", | ||
"description": "Convert SPARQL to SPARQL algebra", | ||
@@ -5,0 +5,0 @@ "author": "Joachim Van Herwegen", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
120309
2702