@comunica/actor-optimize-query-operation-prune-empty-source-operations 3.0.1-alpha.43.0 → 3.0.1-alpha.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ActorOptimizeQueryOperationPruneEmptySourceOperations = void 0;
4
4
  const bus_optimize_query_operation_1 = require("@comunica/bus-optimize-query-operation");
5
5
  const bus_query_operation_1 = require("@comunica/bus-query-operation");
6
+ const context_entries_1 = require("@comunica/context-entries");
6
7
  const rdf_data_factory_1 = require("rdf-data-factory");
7
8
  const sparqlalgebrajs_1 = require("sparqlalgebrajs");
8
9
  const AF = new sparqlalgebrajs_1.Factory();
@@ -94,6 +95,10 @@ class ActorOptimizeQueryOperationPruneEmptySourceOperations extends bus_optimize
94
95
  * @param context The query context.
95
96
  */
96
97
  async hasSourceResults(source, input, context) {
98
+ // Traversal sources should never be considered empty at optimization time.
99
+ if (source.context?.get(context_entries_1.KeysQuerySourceIdentify.traverse)) {
100
+ return true;
101
+ }
97
102
  // Send an ASK query
98
103
  if (this.useAskIfSupported) {
99
104
  const askOperation = AF.createAsk(input);
@@ -1 +1 @@
1
- {"version":3,"file":"ActorOptimizeQueryOperationPruneEmptySourceOperations.js","sourceRoot":"","sources":["ActorOptimizeQueryOperationPruneEmptySourceOperations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IActionOptimizeQueryOperation,\n IActorOptimizeQueryOperationOutput, IActorOptimizeQueryOperationArgs } from '@comunica/bus-optimize-query-operation';\nimport { ActorOptimizeQueryOperation } from '@comunica/bus-optimize-query-operation';\nimport { ActorQueryOperation } from '@comunica/bus-query-operation';\nimport type { IActorTest } from '@comunica/core';\nimport type { IActionContext, IQuerySourceWrapper, MetadataBindings } from '@comunica/types';\nimport { DataFactory } from 'rdf-data-factory';\nimport { Algebra, Factory, Util } from 'sparqlalgebrajs';\n\nconst AF = new Factory();\nconst DF = new DataFactory();\n\n/**\n * A comunica Prune Empty Source Operations Optimize Query Operation Actor.\n */\nexport class ActorOptimizeQueryOperationPruneEmptySourceOperations extends ActorOptimizeQueryOperation {\n private readonly useAskIfSupported: boolean;\n\n public constructor(args: IActorOptimizeQueryOperationPruneEmptySourceOperationsArgs) {\n super(args);\n }\n\n public async test(action: IActionOptimizeQueryOperation): Promise<IActorTest> {\n if (ActorQueryOperation.getOperationSource(action.operation)) {\n throw new Error(`Actor ${this.name} does not work with top-level operation sources.`);\n }\n return true;\n }\n\n public async run(action: IActionOptimizeQueryOperation): Promise<IActorOptimizeQueryOperationOutput> {\n let operation = action.operation;\n\n // Collect all operations with source types\n // Only consider unions of patterns or alts of links, since these are created during exhaustive source assignment.\n const collectedOperations: (Algebra.Pattern | Algebra.Link)[] = [];\n // eslint-disable-next-line @typescript-eslint/no-this-alias,consistent-this\n const self = this;\n Util.recurseOperation(operation, {\n [Algebra.types.UNION](subOperation) {\n self.collectMultiOperationInputs(subOperation.input, collectedOperations, Algebra.types.PATTERN);\n return true;\n },\n [Algebra.types.ALT](subOperation) {\n self.collectMultiOperationInputs(subOperation.input, collectedOperations, Algebra.types.LINK);\n return false;\n },\n [Algebra.types.SERVICE](subOperation) {\n return false;\n },\n });\n\n // Determine in an async manner whether or not these sources return non-empty results\n const emptyOperations: Set<Algebra.Operation> = new Set();\n await Promise.all(collectedOperations.map(async collectedOperation => {\n const checkOperation = collectedOperation.type === 'link' ?\n AF.createPattern(DF.variable('?s'), collectedOperation.iri, DF.variable('?o')) :\n collectedOperation;\n if (!await this.hasSourceResults(\n ActorQueryOperation.getOperationSource(collectedOperation)!,\n checkOperation,\n action.context,\n )) {\n emptyOperations.add(collectedOperation);\n }\n }));\n\n // Only perform next mapping if we have at least one empty operation\n this.logDebug(action.context, `Pruning ${emptyOperations.size} source-specific operations`);\n if (emptyOperations.size > 0) {\n // Rewrite operations by removing the empty children\n operation = Util.mapOperation(operation, {\n [Algebra.types.UNION](subOperation, factory) {\n return self.mapMultiOperation(subOperation, emptyOperations, children => factory.createUnion(children));\n },\n [Algebra.types.ALT](subOperation, factory) {\n return self.mapMultiOperation(subOperation, emptyOperations, children => factory.createAlt(children));\n },\n });\n }\n\n return { operation, context: action.context };\n }\n\n protected collectMultiOperationInputs(\n inputs: Algebra.Operation[],\n collectedOperations: (Algebra.Pattern | Algebra.Link)[],\n inputType: (Algebra.Pattern | Algebra.Link)['type'],\n ): void {\n for (const input of inputs) {\n if (ActorQueryOperation.getOperationSource(input) && input.type === inputType) {\n collectedOperations.push(input);\n }\n }\n }\n\n protected mapMultiOperation<O extends Algebra.Union | Algebra.Alt>(\n operation: O,\n emptyOperations: Set<Algebra.Operation>,\n multiOperationFactory: (input: O['input']) => Algebra.Operation,\n ): {\n result: Algebra.Operation;\n recurse: boolean;\n } {\n // Determine which operations return non-empty results\n const nonEmptyInputs = operation.input.filter(input => !emptyOperations.has(input));\n\n // Remove empty operations\n if (nonEmptyInputs.length === operation.input.length) {\n return { result: operation, recurse: true };\n }\n if (nonEmptyInputs.length === 0) {\n return { result: multiOperationFactory([]), recurse: false };\n }\n if (nonEmptyInputs.length === 1) {\n return { result: nonEmptyInputs[0], recurse: true };\n }\n return { result: multiOperationFactory(nonEmptyInputs), recurse: true };\n }\n\n /**\n * Check if the given query operation will produce at least one result in the given source.\n * @param source A query source.\n * @param input A query operation.\n * @param context The query context.\n */\n public async hasSourceResults(\n source: IQuerySourceWrapper,\n input: Algebra.Operation,\n context: IActionContext,\n ): Promise<boolean> {\n // Send an ASK query\n if (this.useAskIfSupported) {\n const askOperation = AF.createAsk(input);\n if (ActorQueryOperation\n .doesShapeAcceptOperation(await source.source.getSelectorShape(context), askOperation)) {\n return source.source.queryBoolean(askOperation, context);\n }\n }\n\n // Send the operation as-is and check the response cardinality\n const bindingsStream = source.source.queryBindings(input, context);\n return new Promise((resolve, reject) => {\n bindingsStream.on('error', reject);\n bindingsStream.getProperty('metadata', (metadata: MetadataBindings) => {\n bindingsStream.destroy();\n resolve(metadata.cardinality.value > 0);\n });\n });\n }\n}\n\nexport interface IActorOptimizeQueryOperationPruneEmptySourceOperationsArgs extends IActorOptimizeQueryOperationArgs {\n /**\n * If true, ASK queries will be sent to the source instead of COUNT queries to check emptiness for patterns.\n * This will only be done for sources that accept ASK queries.\n * @default {false}\n */\n useAskIfSupported: boolean;\n}\n"]}
1
+ {"version":3,"file":"ActorOptimizeQueryOperationPruneEmptySourceOperations.js","sourceRoot":"","sources":["ActorOptimizeQueryOperationPruneEmptySourceOperations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IActionOptimizeQueryOperation,\n IActorOptimizeQueryOperationOutput, IActorOptimizeQueryOperationArgs } from '@comunica/bus-optimize-query-operation';\nimport { ActorOptimizeQueryOperation } from '@comunica/bus-optimize-query-operation';\nimport { ActorQueryOperation } from '@comunica/bus-query-operation';\nimport { KeysQuerySourceIdentify } from '@comunica/context-entries';\nimport type { IActorTest } from '@comunica/core';\nimport type { IActionContext, IQuerySourceWrapper, MetadataBindings } from '@comunica/types';\nimport { DataFactory } from 'rdf-data-factory';\nimport { Algebra, Factory, Util } from 'sparqlalgebrajs';\n\nconst AF = new Factory();\nconst DF = new DataFactory();\n\n/**\n * A comunica Prune Empty Source Operations Optimize Query Operation Actor.\n */\nexport class ActorOptimizeQueryOperationPruneEmptySourceOperations extends ActorOptimizeQueryOperation {\n private readonly useAskIfSupported: boolean;\n\n public constructor(args: IActorOptimizeQueryOperationPruneEmptySourceOperationsArgs) {\n super(args);\n }\n\n public async test(action: IActionOptimizeQueryOperation): Promise<IActorTest> {\n if (ActorQueryOperation.getOperationSource(action.operation)) {\n throw new Error(`Actor ${this.name} does not work with top-level operation sources.`);\n }\n return true;\n }\n\n public async run(action: IActionOptimizeQueryOperation): Promise<IActorOptimizeQueryOperationOutput> {\n let operation = action.operation;\n\n // Collect all operations with source types\n // Only consider unions of patterns or alts of links, since these are created during exhaustive source assignment.\n const collectedOperations: (Algebra.Pattern | Algebra.Link)[] = [];\n // eslint-disable-next-line @typescript-eslint/no-this-alias,consistent-this\n const self = this;\n Util.recurseOperation(operation, {\n [Algebra.types.UNION](subOperation) {\n self.collectMultiOperationInputs(subOperation.input, collectedOperations, Algebra.types.PATTERN);\n return true;\n },\n [Algebra.types.ALT](subOperation) {\n self.collectMultiOperationInputs(subOperation.input, collectedOperations, Algebra.types.LINK);\n return false;\n },\n [Algebra.types.SERVICE](subOperation) {\n return false;\n },\n });\n\n // Determine in an async manner whether or not these sources return non-empty results\n const emptyOperations: Set<Algebra.Operation> = new Set();\n await Promise.all(collectedOperations.map(async collectedOperation => {\n const checkOperation = collectedOperation.type === 'link' ?\n AF.createPattern(DF.variable('?s'), collectedOperation.iri, DF.variable('?o')) :\n collectedOperation;\n if (!await this.hasSourceResults(\n ActorQueryOperation.getOperationSource(collectedOperation)!,\n checkOperation,\n action.context,\n )) {\n emptyOperations.add(collectedOperation);\n }\n }));\n\n // Only perform next mapping if we have at least one empty operation\n this.logDebug(action.context, `Pruning ${emptyOperations.size} source-specific operations`);\n if (emptyOperations.size > 0) {\n // Rewrite operations by removing the empty children\n operation = Util.mapOperation(operation, {\n [Algebra.types.UNION](subOperation, factory) {\n return self.mapMultiOperation(subOperation, emptyOperations, children => factory.createUnion(children));\n },\n [Algebra.types.ALT](subOperation, factory) {\n return self.mapMultiOperation(subOperation, emptyOperations, children => factory.createAlt(children));\n },\n });\n }\n\n return { operation, context: action.context };\n }\n\n protected collectMultiOperationInputs(\n inputs: Algebra.Operation[],\n collectedOperations: (Algebra.Pattern | Algebra.Link)[],\n inputType: (Algebra.Pattern | Algebra.Link)['type'],\n ): void {\n for (const input of inputs) {\n if (ActorQueryOperation.getOperationSource(input) && input.type === inputType) {\n collectedOperations.push(input);\n }\n }\n }\n\n protected mapMultiOperation<O extends Algebra.Union | Algebra.Alt>(\n operation: O,\n emptyOperations: Set<Algebra.Operation>,\n multiOperationFactory: (input: O['input']) => Algebra.Operation,\n ): {\n result: Algebra.Operation;\n recurse: boolean;\n } {\n // Determine which operations return non-empty results\n const nonEmptyInputs = operation.input.filter(input => !emptyOperations.has(input));\n\n // Remove empty operations\n if (nonEmptyInputs.length === operation.input.length) {\n return { result: operation, recurse: true };\n }\n if (nonEmptyInputs.length === 0) {\n return { result: multiOperationFactory([]), recurse: false };\n }\n if (nonEmptyInputs.length === 1) {\n return { result: nonEmptyInputs[0], recurse: true };\n }\n return { result: multiOperationFactory(nonEmptyInputs), recurse: true };\n }\n\n /**\n * Check if the given query operation will produce at least one result in the given source.\n * @param source A query source.\n * @param input A query operation.\n * @param context The query context.\n */\n public async hasSourceResults(\n source: IQuerySourceWrapper,\n input: Algebra.Operation,\n context: IActionContext,\n ): Promise<boolean> {\n // Traversal sources should never be considered empty at optimization time.\n if (source.context?.get(KeysQuerySourceIdentify.traverse)) {\n return true;\n }\n\n // Send an ASK query\n if (this.useAskIfSupported) {\n const askOperation = AF.createAsk(input);\n if (ActorQueryOperation\n .doesShapeAcceptOperation(await source.source.getSelectorShape(context), askOperation)) {\n return source.source.queryBoolean(askOperation, context);\n }\n }\n\n // Send the operation as-is and check the response cardinality\n const bindingsStream = source.source.queryBindings(input, context);\n return new Promise((resolve, reject) => {\n bindingsStream.on('error', reject);\n bindingsStream.getProperty('metadata', (metadata: MetadataBindings) => {\n bindingsStream.destroy();\n resolve(metadata.cardinality.value > 0);\n });\n });\n }\n}\n\nexport interface IActorOptimizeQueryOperationPruneEmptySourceOperationsArgs extends IActorOptimizeQueryOperationArgs {\n /**\n * If true, ASK queries will be sent to the source instead of COUNT queries to check emptiness for patterns.\n * This will only be done for sources that accept ASK queries.\n * @default {false}\n */\n useAskIfSupported: boolean;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comunica/actor-optimize-query-operation-prune-empty-source-operations",
3
- "version": "3.0.1-alpha.43.0",
3
+ "version": "3.0.1-alpha.45.0",
4
4
  "description": "A prune-empty-source-operations optimize-query-operation actor",
5
5
  "lsd:module": true,
6
6
  "main": "lib/index.js",
@@ -32,10 +32,11 @@
32
32
  "lib/**/*.js.map"
33
33
  ],
34
34
  "dependencies": {
35
- "@comunica/bus-optimize-query-operation": "3.0.1-alpha.43.0",
36
- "@comunica/bus-query-operation": "3.0.1-alpha.43.0",
37
- "@comunica/core": "3.0.1-alpha.43.0",
38
- "@comunica/types": "3.0.1-alpha.43.0",
35
+ "@comunica/bus-optimize-query-operation": "3.0.1-alpha.45.0",
36
+ "@comunica/bus-query-operation": "3.0.1-alpha.45.0",
37
+ "@comunica/context-entries": "3.0.1-alpha.45.0",
38
+ "@comunica/core": "3.0.1-alpha.45.0",
39
+ "@comunica/types": "3.0.1-alpha.45.0",
39
40
  "rdf-data-factory": "^1.1.2",
40
41
  "sparqlalgebrajs": "^4.3.3"
41
42
  },
@@ -44,5 +45,5 @@
44
45
  "build:ts": "node \"../../node_modules/typescript/bin/tsc\"",
45
46
  "build:components": "componentsjs-generator"
46
47
  },
47
- "gitHead": "d11e44cf07d4699f9d2c51d5851b5ed443de1997"
48
+ "gitHead": "b5a3900c24e29fa7b3243ab50bc9745d286fbce8"
48
49
  }