sparql-engine
Advanced tools
Comparing version 0.7.1 to 0.7.2
@@ -232,2 +232,13 @@ /** | ||
groupBy<T, K, R>(input: PipelineStage<T>, keySelector: (value: T) => K, elementSelector?: (value: T) => R): PipelineStage<[K, R[]]>; | ||
/** | ||
* Peek values from the input pipeline stage, and use them to decide | ||
* between two candidate pipeline stages to continue the pipeline. | ||
* @param input - Input pipeline stage | ||
* @param count - How many items to peek from the input? | ||
* @param predicate - Predicate function invoked with the values | ||
* @param ifCase - Callback invoked if the predicate function evaluates to True | ||
* @param elseCase - Callback invoked if the predicate function evaluates to False | ||
* @return A pipeline stage | ||
*/ | ||
peekIf<T, O>(input: PipelineStage<T>, count: number, predicate: (values: T[]) => boolean, ifCase: (values: T[]) => PipelineStage<O>, elseCase: (values: T[]) => PipelineStage<O>): PipelineStage<O>; | ||
} |
@@ -188,4 +188,23 @@ /* file : pipeline-engine.ts | ||
}; | ||
/** | ||
* Peek values from the input pipeline stage, and use them to decide | ||
* between two candidate pipeline stages to continue the pipeline. | ||
* @param input - Input pipeline stage | ||
* @param count - How many items to peek from the input? | ||
* @param predicate - Predicate function invoked with the values | ||
* @param ifCase - Callback invoked if the predicate function evaluates to True | ||
* @param elseCase - Callback invoked if the predicate function evaluates to False | ||
* @return A pipeline stage | ||
*/ | ||
PipelineEngine.prototype.peekIf = function (input, count, predicate, ifCase, elseCase) { | ||
var peekable = this.limit(this.clone(input), count); | ||
return this.mergeMap(this.collect(peekable), function (values) { | ||
if (predicate(values)) { | ||
return ifCase(values); | ||
} | ||
return elseCase(values); | ||
}); | ||
}; | ||
return PipelineEngine; | ||
}()); | ||
exports.PipelineEngine = PipelineEngine; |
@@ -258,3 +258,3 @@ /* file : plan-builder.ts | ||
var graphIterator; | ||
if (query.where != null && query.where.length > 0) { | ||
if (query.where.length > 0) { | ||
graphIterator = this._buildWhere(source, query.where, context); | ||
@@ -323,10 +323,15 @@ } | ||
switch (g.type) { | ||
case 'graph': | ||
if (utils_1.rdf.isVariable(g.name)) { | ||
return 5; | ||
} | ||
return 0; | ||
case 'bgp': | ||
return 0; | ||
case 'values': | ||
return 2; | ||
return 3; | ||
case 'filter': | ||
return 3; | ||
return 4; | ||
default: | ||
return 0; | ||
return 1; | ||
} | ||
@@ -343,3 +348,3 @@ }); | ||
var group = groups[i]; | ||
if (group.type === 'bgp' && prec != null && prec.type === 'bgp') { | ||
if (group.type === 'bgp' && prec !== null && prec.type === 'bgp') { | ||
var lastGroup = newGroups[newGroups.length - 1]; | ||
@@ -346,0 +351,0 @@ lastGroup.triples = lastGroup.triples.concat(group.triples); |
@@ -93,14 +93,31 @@ /* file : graph-executor.ts | ||
} | ||
var engine = pipeline_1.Pipeline.getInstance(); | ||
// handle the case where the GRAPh IRI is a SPARQL variable | ||
if (utils_1.rdf.isVariable(node.name) && context.namedGraphs.length > 0) { | ||
if (utils_1.rdf.isVariable(node.name)) { | ||
// clone the source first | ||
source = engine.clone(source); | ||
// execute the subquery using each graph, and bound the graph var to the graph iri | ||
var iterators = context.namedGraphs.map(function (iri) { | ||
return engine.map(_this._buildIterator(source, iri, subquery, context), function (b) { | ||
return b.extendMany([[node.name, iri]]); | ||
}); | ||
source = pipeline_1.Pipeline.getInstance().clone(source); | ||
var namedGraphs_1 = []; | ||
// use named graphs is provided, otherwise use all named graphs | ||
if (context.namedGraphs.length > 0) { | ||
namedGraphs_1 = context.namedGraphs; | ||
} | ||
else { | ||
namedGraphs_1 = this._dataset.getAllGraphs(true).map(function (g) { return g.iri; }); | ||
} | ||
// build a pipeline stage that allows to peek on the first set of input bindings | ||
return pipeline_1.Pipeline.getInstance().peekIf(source, 1, function (values) { | ||
return values[0].has(node.name); | ||
}, function (values) { | ||
// if the input bindings bound the graph's variable, use it as graph IRI | ||
var graphIRI = values[0].get(node.name); | ||
return _this._buildIterator(source, graphIRI, subquery, context); | ||
}, function () { | ||
var _a; | ||
// otherwise, execute the subquery using each graph, and bound the graph var to the graph iri | ||
return (_a = pipeline_1.Pipeline.getInstance()).merge.apply(_a, __spread(namedGraphs_1.map(function (iri) { | ||
var stage = _this._buildIterator(source, iri, subquery, context); | ||
return pipeline_1.Pipeline.getInstance().map(stage, function (bindings) { | ||
return bindings.extendMany([[node.name, iri]]); | ||
}); | ||
}))); | ||
}); | ||
return engine.merge.apply(engine, __spread(iterators)); | ||
} | ||
@@ -107,0 +124,0 @@ // otherwise, execute the subquery using the Graph |
{ | ||
"name": "sparql-engine", | ||
"version": "0.7.1", | ||
"version": "0.7.2", | ||
"description": "A framework for building SPARQL query engines in Javascript", | ||
@@ -5,0 +5,0 @@ "main": "dist/api.js", |
@@ -171,3 +171,2 @@ # sparql-engine | ||
const query = ` | ||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> | ||
PREFIX foaf: <http://xmlns.com/foaf/0.1/> | ||
@@ -177,3 +176,3 @@ SELECT ?name | ||
?s a foaf:Person . | ||
?s rdfs:label ?label . | ||
?s foaf:name ?name . | ||
}` | ||
@@ -180,0 +179,0 @@ |
@@ -364,2 +364,22 @@ /* file : pipeline-engine.ts | ||
} | ||
/** | ||
* Peek values from the input pipeline stage, and use them to decide | ||
* between two candidate pipeline stages to continue the pipeline. | ||
* @param input - Input pipeline stage | ||
* @param count - How many items to peek from the input? | ||
* @param predicate - Predicate function invoked with the values | ||
* @param ifCase - Callback invoked if the predicate function evaluates to True | ||
* @param elseCase - Callback invoked if the predicate function evaluates to False | ||
* @return A pipeline stage | ||
*/ | ||
peekIf<T, O> (input: PipelineStage<T>, count: number, predicate: (values: T[]) => boolean, ifCase: (values: T[]) => PipelineStage<O>, elseCase: (values: T[]) => PipelineStage<O>): PipelineStage<O> { | ||
const peekable = this.limit(this.clone(input), count) | ||
return this.mergeMap(this.collect(peekable), values => { | ||
if (predicate(values)) { | ||
return ifCase(values) | ||
} | ||
return elseCase(values) | ||
}) | ||
} | ||
} |
@@ -271,3 +271,3 @@ /* file : plan-builder.ts | ||
let graphIterator: PipelineStage<Bindings> | ||
if (query.where != null && query.where.length > 0) { | ||
if (query.where.length > 0) { | ||
graphIterator = this._buildWhere(source, query.where, context) | ||
@@ -342,10 +342,15 @@ } else { | ||
switch (g.type) { | ||
case 'graph': | ||
if (rdf.isVariable((g as Algebra.GraphNode).name)) { | ||
return 5 | ||
} | ||
return 0 | ||
case 'bgp': | ||
return 0 | ||
case 'values': | ||
return 2 | ||
return 3 | ||
case 'filter': | ||
return 3 | ||
return 4 | ||
default: | ||
return 0 | ||
return 1 | ||
} | ||
@@ -364,3 +369,3 @@ }) | ||
let group = groups[i] | ||
if (group.type === 'bgp' && prec != null && prec.type === 'bgp') { | ||
if (group.type === 'bgp' && prec !== null && prec.type === 'bgp') { | ||
let lastGroup = newGroups[newGroups.length - 1] as Algebra.BGPNode | ||
@@ -367,0 +372,0 @@ lastGroup.triples = lastGroup.triples.concat((group as Algebra.BGPNode).triples) |
@@ -50,3 +50,3 @@ /* file : graph-executor.ts | ||
if (node.patterns[0].type === 'query') { | ||
subquery = (<Algebra.RootNode> node.patterns[0]) | ||
subquery = node.patterns[0] as Algebra.RootNode | ||
} else { | ||
@@ -61,14 +61,29 @@ subquery = { | ||
} | ||
const engine = Pipeline.getInstance() | ||
// handle the case where the GRAPh IRI is a SPARQL variable | ||
if (rdf.isVariable(node.name) && context.namedGraphs.length > 0) { | ||
if (rdf.isVariable(node.name)) { | ||
// clone the source first | ||
source = engine.clone(source) | ||
// execute the subquery using each graph, and bound the graph var to the graph iri | ||
const iterators = context.namedGraphs.map((iri: string) => { | ||
return engine.map(this._buildIterator(source, iri, subquery, context), (b: Bindings) => { | ||
return b.extendMany([[node.name, iri]]) | ||
}) | ||
source = Pipeline.getInstance().clone(source) | ||
let namedGraphs: string[] = [] | ||
// use named graphs is provided, otherwise use all named graphs | ||
if (context.namedGraphs.length > 0) { | ||
namedGraphs = context.namedGraphs | ||
} else { | ||
namedGraphs = this._dataset.getAllGraphs(true).map(g => g.iri) | ||
} | ||
// build a pipeline stage that allows to peek on the first set of input bindings | ||
return Pipeline.getInstance().peekIf(source, 1, values => { | ||
return values[0].has(node.name) | ||
}, values => { | ||
// if the input bindings bound the graph's variable, use it as graph IRI | ||
const graphIRI = values[0].get(node.name)! | ||
return this._buildIterator(source, graphIRI, subquery, context) | ||
}, () => { | ||
// otherwise, execute the subquery using each graph, and bound the graph var to the graph iri | ||
return Pipeline.getInstance().merge(...namedGraphs.map((iri: string) => { | ||
const stage = this._buildIterator(source, iri, subquery, context) | ||
return Pipeline.getInstance().map(stage, bindings => { | ||
return bindings.extendMany([[node.name, iri]]) | ||
}) | ||
})) | ||
}) | ||
return engine.merge(...iterators) | ||
} | ||
@@ -75,0 +90,0 @@ // otherwise, execute the subquery using the Graph |
960800
21751
474