UNPKG

@jahed/sparql-engine

Version:

SPARQL query engine for servers and web browsers.

69 lines (67 loc) 2.56 kB
// SPDX-License-Identifier: MIT import type { BGPCache } from "../engine/cache/types.ts"; import ExecutionContext from "../engine/context/execution-context.ts"; import ContextSymbols from "../engine/context/symbols.ts"; import type { PipelineStage } from "../engine/pipeline/pipeline-engine.ts"; import { Pipeline } from "../engine/pipeline/pipeline.ts"; import BGPStageBuilder from "../engine/stages/bgp-stage-builder.ts"; import { Bindings } from "../rdf/bindings.ts"; import Graph from "../rdf/graph.ts"; import type { EngineTriple } from "../types.ts"; /** * Evaluate a Basic Graph pattern on a RDF graph using a cache * @param bgp - Basic Graph pattern to evaluate * @param graph - RDF graph * @param cache - Cache used * @return A pipeline stage that produces the evaluation results */ export async function cacheEvalBGP( patterns: EngineTriple[], graph: Graph, cache: BGPCache, builder: BGPStageBuilder, context: ExecutionContext ): Promise<PipelineStage<Bindings>> { const bgp = { patterns, graphIRI: graph.iri, }; const [subsetBGP, missingBGP] = cache.findSubset(bgp); // case 1: no subset of the BGP are in cache => classic evaluation (most frequent) if (subsetBGP.length === 0) { // we cannot cache the BGP if the query has a LIMIT and/or OFFSET modiifier // otherwise we will cache incomplete results. So, we just evaluate the BGP if ( context.hasProperty(ContextSymbols.HAS_LIMIT_OFFSET) && context.getProperty(ContextSymbols.HAS_LIMIT_OFFSET) ) { return graph.evalBGP(patterns, context); } // generate an unique writer ID const writerID = crypto.randomUUID(); // evaluate the BGP while saving all solutions into the cache const iterator = Pipeline.getInstance().tap( graph.evalBGP(patterns, context), (b) => { cache.update(bgp, b, writerID); } ); // commit the cache entry when the BGP evaluation is done return Pipeline.getInstance().finalize(iterator, () => { cache.commit(bgp, writerID); }); } // case 2: no missing patterns => the complete BGP is in the cache if (missingBGP.length === 0) { return cache.getAsPipeline(bgp, () => graph.evalBGP(patterns, context)); } const cachedBGP = { patterns: subsetBGP, graphIRI: graph.iri, }; // case 3: evaluate the subset BGP using the cache, then join with the missing patterns const iterator = cache.getAsPipeline(cachedBGP, () => graph.evalBGP(subsetBGP, context) ); return builder.execute(iterator, missingBGP, context); }