Skip to content

Commit

Permalink
Add ActionContext in IAction
Browse files Browse the repository at this point in the history
This is an abstraction of the query operation context,
and allows data to be passed to any actor.

Closes #109
  • Loading branch information
rubensworks committed Jul 24, 2018
1 parent ff45932 commit 59349a8
Show file tree
Hide file tree
Showing 47 changed files with 503 additions and 356 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {ActorContextPreprocess, IActionContextPreprocess,
import {ActorContextPreprocess,
IActorContextPreprocessOutput} from "@comunica/bus-context-preprocess";
import {IActionRdfSourceIdentifier, IActorRdfSourceIdentifierOutput} from "@comunica/bus-rdf-source-identifier";
import {Actor, IActorArgs, IActorTest, Mediator} from "@comunica/core";
import {Actor, IAction, IActorArgs, IActorTest, Mediator} from "@comunica/core";
import {KEY_CONTEXT_SOURCES} from "../../bus-rdf-resolve-quad-pattern";

/**
* A comunica RDF Source Identifier Context Preprocess Actor.
Expand All @@ -15,14 +16,13 @@ export class ActorContextPreprocessRdfSourceIdentifier extends ActorContextPrepr
super(args);
}

public async test(action: IActionContextPreprocess): Promise<IActorTest> {
public async test(action: IAction): Promise<IActorTest> {
return true;
}

public async run(action: IActionContextPreprocess): Promise<IActorContextPreprocessOutput> {
if (action.context && action.context.sources) {
const context = { ...action.context };
const sources = context.sources;
public async run(action: IAction): Promise<IActorContextPreprocessOutput> {
if (action.context && action.context.get(KEY_CONTEXT_SOURCES)) {
const sources = action.context.get(KEY_CONTEXT_SOURCES);
const autoSources = sources.map((source: any, id: number) => ({ id, source }))
.filter((entry: any) => entry.source.type === 'auto');
const autoSourceTypePromises: Promise<IActorRdfSourceIdentifierOutput>[] = autoSources.map(
Expand All @@ -35,15 +35,15 @@ export class ActorContextPreprocessRdfSourceIdentifier extends ActorContextPrepr
sources[sourceId].type = sourceType;
}
}
return { context };
return { context: action.context.set(KEY_CONTEXT_SOURCES, sources) };
}
return action;
}

}

export interface IActorContextPreprocessRdfSourceIdentifierArgs
extends IActorArgs<IActionContextPreprocess, IActorTest, IActorContextPreprocessOutput> {
extends IActorArgs<IAction, IActorTest, IActorContextPreprocessOutput> {
mediatorRdfSourceIdentifier: Mediator<Actor<IActionRdfSourceIdentifier, IActorTest,
IActorRdfSourceIdentifierOutput>, IActionRdfSourceIdentifier, IActorTest, IActorRdfSourceIdentifierOutput>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ActorContextPreprocess} from "@comunica/bus-context-preprocess";
import {Bus} from "@comunica/core";
import {ActionContext, Bus} from "@comunica/core";
import {ActorContextPreprocessRdfSourceIdentifier} from "../lib/ActorContextPreprocessRdfSourceIdentifier";

describe('ActorContextPreprocessRdfSourceIdentifier', () => {
Expand Down Expand Up @@ -46,35 +46,44 @@ describe('ActorContextPreprocessRdfSourceIdentifier', () => {
});

it('should run for an empty context', () => {
return expect(actor.run({ context: {} })).resolves.toMatchObject({ context: {} });
return expect(actor.run({ context: ActionContext({}) })).resolves.toMatchObject({ context: {} });
});

it('should run for a context with zero sources', () => {
return expect(actor.run({ context: { sources: [] } })).resolves
.toMatchObject({ context: { sources: [] } });
return expect(actor.run({ context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[] }) })).resolves
.toMatchObject({ context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources': [] }) });
});

it('should run for a context with two dummy sources', () => {
return expect(actor.run({ context: { sources: [{ type: 'dummy' }, { type: 'dummy' }] } })).resolves
.toMatchObject({ context: { sources: [{ type: 'dummy' }, { type: 'dummy' }] } });
return expect(actor.run({ context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[{ type: 'dummy' }, { type: 'dummy' }] }) })).resolves
.toMatchObject({ context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[{ type: 'dummy' }, { type: 'dummy' }] }) });
});

it('should run for a context with two auto sources', () => {
const context = { context: { sources: [{ type: 'auto', value: 'abc' }, { type: 'auto', value: 'def' }] } };
const context = { context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[{ type: 'auto', value: 'abc' }, { type: 'auto', value: 'def' }] }) };
return expect(actor.run(context)).resolves
.toMatchObject({ context: { sources: [{ type: 'a', value: 'abc' }, { type: 'd', value: 'def' }] } });
.toMatchObject({ context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[{ type: 'a', value: 'abc' }, { type: 'd', value: 'def' }] }) });
});

it('should run for a context with a auto and a dummy source', () => {
const context = { context: { sources: [{ type: 'auto', value: 'abc' }, { type: 'dummy' }] } };
const context = { context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[{ type: 'auto', value: 'abc' }, { type: 'dummy' }] }) };
return expect(actor.run(context)).resolves
.toMatchObject({ context: { sources: [{ type: 'a', value: 'abc' }, { type: 'dummy' }] } });
.toMatchObject({ context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[{ type: 'a', value: 'abc' }, { type: 'dummy' }] }) });
});

it('should run and keep the auto type if the mediator fails', () => {
const context = { context: { sources: [{ type: 'auto' }] } };
const context = { context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[{ type: 'auto' }] }) };
return expect(actor.run(context)).resolves
.toMatchObject({ context: { sources: [{ type: 'auto' }] } });
.toMatchObject({ context: ActionContext({ '@comunica/bus-rdf-resolve-quad-pattern:sources':
[{ type: 'auto' }] }) });
});
});
});
20 changes: 12 additions & 8 deletions packages/actor-init-sparql/lib/ActorInitSparql-browser.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {IActionContextPreprocess, IActorContextPreprocessOutput} from "@comunica/bus-context-preprocess";
import {IActorContextPreprocessOutput} from "@comunica/bus-context-preprocess";
import {ActorInit, IActionInit, IActorOutputInit} from "@comunica/bus-init";
import {Bindings, IActionQueryOperation, IActorQueryOperationOutput} from "@comunica/bus-query-operation";
import {IActionSparqlParse, IActorSparqlParseOutput} from "@comunica/bus-sparql-parse";
import {IActionRootSparqlParse, IActorOutputRootSparqlParse,
IActorTestRootSparqlParse} from "@comunica/bus-sparql-serialize";
import {IActorSparqlSerializeOutput} from "@comunica/bus-sparql-serialize";
import {Actor, IActorArgs, IActorTest, Mediator} from "@comunica/core";
import {ActionContext, Actor, IAction, IActorArgs, IActorTest, Mediator} from "@comunica/core";
import * as RDF from "rdf-js";
import {termToString} from "rdf-string";
import {QUAD_TERM_NAMES} from "rdf-terms";
Expand All @@ -27,8 +27,8 @@ export class ActorInitSparql extends ActorInit implements IActorInitSparqlArgs {
public readonly mediatorSparqlSerializeMediaTypeCombiner: Mediator<Actor<IActionRootSparqlParse,
IActorTestRootSparqlParse, IActorOutputRootSparqlParse>, IActionRootSparqlParse, IActorTestRootSparqlParse,
IActorOutputRootSparqlParse>;
public readonly mediatorContextPreprocess: Mediator<Actor<IActionContextPreprocess, IActorTest,
IActorContextPreprocessOutput>, IActionContextPreprocess, IActorTest, IActorContextPreprocessOutput>;
public readonly mediatorContextPreprocess: Mediator<Actor<IAction, IActorTest,
IActorContextPreprocessOutput>, IAction, IActorTest, IActorContextPreprocessOutput>;
public readonly queryString?: string;
public readonly context?: string;

Expand Down Expand Up @@ -90,6 +90,8 @@ export class ActorInitSparql extends ActorInit implements IActorInitSparqlArgs {
* @return {Promise<IActorQueryOperationOutput>} A promise that resolves to the query output.
*/
public async query(query: string, context?: any): Promise<IActorQueryOperationOutput> {
context = ActionContext(context);

// Start, but don't await, context pre-processing
const combinationPromise = this.mediatorContextPreprocess.mediate({ context });

Expand All @@ -100,8 +102,8 @@ export class ActorInitSparql extends ActorInit implements IActorInitSparqlArgs {
context = (await combinationPromise).context;

// Apply initial bindings in context
if (context.initialBindings) {
operation = ActorInitSparql.applyInitialBindings(operation, context.initialBindings);
if (context.has(KEY_CONTEXT_INITIALBINDINGS)) {
operation = ActorInitSparql.applyInitialBindings(operation, context.get(KEY_CONTEXT_INITIALBINDINGS));
}

// Execute query
Expand Down Expand Up @@ -156,8 +158,10 @@ export interface IActorInitSparqlArgs extends IActorArgs<IActionInit, IActorTest
mediatorSparqlSerializeMediaTypeCombiner: Mediator<Actor<IActionRootSparqlParse,
IActorTestRootSparqlParse, IActorOutputRootSparqlParse>, IActionRootSparqlParse, IActorTestRootSparqlParse,
IActorOutputRootSparqlParse>;
mediatorContextPreprocess: Mediator<Actor<IActionContextPreprocess, IActorTest, IActorContextPreprocessOutput>,
IActionContextPreprocess, IActorTest, IActorContextPreprocessOutput>;
mediatorContextPreprocess: Mediator<Actor<IAction, IActorTest, IActorContextPreprocessOutput>,
IAction, IActorTest, IActorContextPreprocessOutput>;
queryString?: string;
context?: string;
}

export const KEY_CONTEXT_INITIALBINDINGS: string = '@comunica/actor-init-sparql:initialBindings';
5 changes: 3 additions & 2 deletions packages/actor-init-sparql/lib/ActorInitSparql.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {IActionInit, IActorOutputInit} from "@comunica/bus-init";
import {IActorQueryOperationOutput} from "@comunica/bus-query-operation";
import {KEY_CONTEXT_SOURCES} from "@comunica/bus-rdf-resolve-quad-pattern";
import {exec} from "child_process";
import {existsSync, readFileSync} from "fs";
import minimist = require('minimist');
Expand Down Expand Up @@ -92,7 +93,7 @@ Options:

// Add sources to context
if (args._.length > 0) {
context.sources = context.sources || [];
context[KEY_CONTEXT_SOURCES] = context[KEY_CONTEXT_SOURCES] || [];
args._.forEach((sourceValue: string) => {
const source: {[id: string]: string} = {};
const splitValues: string[] = sourceValue.split('@', 2);
Expand All @@ -103,7 +104,7 @@ Options:
source.type = splitValues[0];
}
source.value = splitValues[splitValues.length - 1];
context.sources.push(source);
context[KEY_CONTEXT_SOURCES].push(source);
});
}

Expand Down
2 changes: 1 addition & 1 deletion packages/actor-init-sparql/test/ActorInitSparql-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ describe('ActorInitSparql', () => {

describe('query', () => {
it('should apply bindings when initialBindings are passed via the context', () => {
const ctx = { initialBindings: Bindings({ '?s': literal('sl') }) };
const ctx = { '@comunica/actor-init-sparql:initialBindings': Bindings({ '?s': literal('sl') }) };
return expect(actor.query('SELECT * WHERE { ?s ?p ?o }', ctx))
.resolves.toBeTruthy();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ActorQueryOperation, ActorQueryOperationTypedMediated, IActorQueryOperationOutput,
IActorQueryOperationOutputBindings, IActorQueryOperationOutputBoolean,
IActorQueryOperationTypedMediatedArgs} from "@comunica/bus-query-operation";
import {IActorTest} from "@comunica/core";
import {ActionContext, IActorTest} from "@comunica/core";
import {Algebra} from "sparqlalgebrajs";

/**
Expand All @@ -13,11 +13,11 @@ export class ActorQueryOperationAsk extends ActorQueryOperationTypedMediated<Alg
super(args, 'ask');
}

public async testOperation(pattern: Algebra.Ask, context?: {[id: string]: any}): Promise<IActorTest> {
public async testOperation(pattern: Algebra.Ask, context?: ActionContext): Promise<IActorTest> {
return true;
}

public async runOperation(pattern: Algebra.Ask, context?: {[id: string]: any})
public async runOperation(pattern: Algebra.Ask, context?: ActionContext)
: Promise<IActorQueryOperationOutputBoolean> {
// Call other query operations like this:
const output: IActorQueryOperationOutput = await this.mediatorQueryOperation.mediate(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ActorQueryOperationTyped, IActionQueryOperation,
IActorQueryOperationOutput, IActorQueryOperationOutputBindings} from "@comunica/bus-query-operation";
import {IActorArgs, IActorTest} from "@comunica/core";
import {ActionContext, IActorArgs, IActorTest} from "@comunica/core";
import {EmptyIterator} from "asynciterator";
import {Algebra} from "sparqlalgebrajs";

Expand All @@ -13,14 +13,14 @@ export class ActorQueryOperationBgpEmpty extends ActorQueryOperationTyped<Algebr
super(args, 'bgp');
}

public async testOperation(pattern: Algebra.Bgp, context?: {[id: string]: any}): Promise<IActorTest> {
public async testOperation(pattern: Algebra.Bgp, context?: ActionContext): Promise<IActorTest> {
if (pattern.patterns.length !== 0) {
throw new Error('Actor ' + this.name + ' can only operate on empty BGPs.');
}
return true;
}

public async runOperation(pattern: Algebra.Bgp, context?: {[id: string]: any})
public async runOperation(pattern: Algebra.Bgp, context?: ActionContext)
: Promise<IActorQueryOperationOutputBindings> {
return {
bindingsStream: new EmptyIterator(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
IActorQueryOperationOutputBindings,
IActorQueryOperationTypedMediatedArgs,
} from "@comunica/bus-query-operation";
import {IActorTest} from "@comunica/core";
import {ActionContext, IActorTest} from "@comunica/core";
import {EmptyIterator, MultiTransformIterator} from "asynciterator";
import {PromiseProxyIterator} from "asynciterator-promiseproxy";
import * as RDF from "rdf-js";
Expand Down Expand Up @@ -158,14 +158,14 @@ export class ActorQueryOperationBgpLeftDeepSmallestSort extends ActorQueryOperat
return false;
}

public async testOperation(pattern: Algebra.Bgp, context?: {[id: string]: any}): Promise<IActorTest> {
public async testOperation(pattern: Algebra.Bgp, context?: ActionContext): Promise<IActorTest> {
if (pattern.patterns.length < 2) {
throw new Error('Actor ' + this.name + ' can only operate on BGPs with at least two patterns.');
}
return true;
}

public async runOperation(pattern: Algebra.Bgp, context?: {[id: string]: any})
public async runOperation(pattern: Algebra.Bgp, context?: ActionContext)
: Promise<IActorQueryOperationOutputBindings> {
// Get the total number of items for all patterns by resolving the quad patterns
const patternOutputs: IActorQueryOperationOutputBindings[] = (await Promise.all(pattern.patterns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
IActorQueryOperationOutputBindings,
IActorQueryOperationTypedMediatedArgs,
} from "@comunica/bus-query-operation";
import {IActorTest} from "@comunica/core";
import {ActionContext, IActorTest} from "@comunica/core";
import {EmptyIterator, MultiTransformIterator} from "asynciterator";
import {PromiseProxyIterator} from "asynciterator-promiseproxy";
import * as RDF from "rdf-js";
Expand Down Expand Up @@ -166,14 +166,14 @@ export class ActorQueryOperationBgpLeftDeepSmallest extends ActorQueryOperationT
return false;
}

public async testOperation(pattern: Algebra.Bgp, context?: {[id: string]: any}): Promise<IActorTest> {
public async testOperation(pattern: Algebra.Bgp, context?: ActionContext): Promise<IActorTest> {
if (pattern.patterns.length < 2) {
throw new Error('Actor ' + this.name + ' can only operate on BGPs with at least two patterns.');
}
return true;
}

public async runOperation(pattern: Algebra.Bgp, context?: {[id: string]: any})
public async runOperation(pattern: Algebra.Bgp, context?: ActionContext)
: Promise<IActorQueryOperationOutputBindings> {
// Get the total number of items for all patterns by resolving the quad patterns
const patternOutputs: IActorQueryOperationOutputBindings[] = (await Promise.all(pattern.patterns
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ActorQueryOperationTypedMediated, IActorQueryOperationOutput,
IActorQueryOperationTypedMediatedArgs} from "@comunica/bus-query-operation";
import {IActorTest} from "@comunica/core";
import {ActionContext, IActorTest} from "@comunica/core";
import {Algebra} from "sparqlalgebrajs";

/**
Expand All @@ -12,14 +12,14 @@ export class ActorQueryOperationBgpSingle extends ActorQueryOperationTypedMediat
super(args, 'bgp');
}

public async testOperation(pattern: Algebra.Bgp, context?: {[id: string]: any}): Promise<IActorTest> {
public async testOperation(pattern: Algebra.Bgp, context?: ActionContext): Promise<IActorTest> {
if (pattern.patterns.length !== 1) {
throw new Error('Actor ' + this.name + ' can only operate on BGPs with a single pattern.');
}
return true;
}

public runOperation(pattern: Algebra.Bgp, context?: {[id: string]: any}): Promise<IActorQueryOperationOutput> {
public runOperation(pattern: Algebra.Bgp, context?: ActionContext): Promise<IActorQueryOperationOutput> {
return this.mediatorQueryOperation.mediate({ operation: pattern.patterns[0], context });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
IActorQueryOperationOutputQuads,
IActorQueryOperationTypedMediatedArgs,
} from "@comunica/bus-query-operation";
import {IActorTest} from "@comunica/core";
import {ActionContext, IActorTest} from "@comunica/core";
import {AsyncIterator, EmptyIterator, MultiTransformIterator} from "asynciterator";
import * as RDF from "rdf-js";
import {getTerms, getVariables, uniqTerms} from "rdf-terms";
Expand All @@ -30,11 +30,11 @@ export class ActorQueryOperationConstruct extends ActorQueryOperationTypedMediat
return uniqTerms([].concat.apply([], patterns.map((pattern) => getVariables(getTerms(pattern)))));
}

public async testOperation(pattern: Algebra.Construct, context?: {[id: string]: any}): Promise<IActorTest> {
public async testOperation(pattern: Algebra.Construct, context?: ActionContext): Promise<IActorTest> {
return true;
}

public async runOperation(pattern: Algebra.Construct, context?: {[id: string]: any})
public async runOperation(pattern: Algebra.Construct, context?: ActionContext)
: Promise<IActorQueryOperationOutputQuads> {
// If our template is empty or contains no variables, no need to resolve a query.
const variables: RDF.Variable[] = ActorQueryOperationConstruct.getVariables(pattern.template);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ActorQueryOperationUnion} from "@comunica/actor-query-operation-union";
import {ActorQueryOperation, ActorQueryOperationTypedMediated,
IActorQueryOperationOutputQuads, IActorQueryOperationTypedMediatedArgs} from "@comunica/bus-query-operation";
import {IActorTest} from "@comunica/core";
import {ActionContext, IActorTest} from "@comunica/core";
import {RoundRobinUnionIterator} from "asynciterator-union";
import {triple, variable} from "rdf-data-model";
import * as RDF from "rdf-js";
Expand All @@ -16,11 +16,11 @@ export class ActorQueryOperationDescribeSubject extends ActorQueryOperationTyped
super(args, 'describe');
}

public async testOperation(pattern: Algebra.Describe, context?: {[id: string]: any}): Promise<IActorTest> {
public async testOperation(pattern: Algebra.Describe, context?: ActionContext): Promise<IActorTest> {
return true;
}

public async runOperation(pattern: Algebra.Describe, context?: {[id: string]: any})
public async runOperation(pattern: Algebra.Describe, context?: ActionContext)
: Promise<IActorQueryOperationOutputQuads> {
// Create separate construct queries for all non-variable terms
const operations: Algebra.Construct[] = pattern.terms
Expand Down
Loading

0 comments on commit 59349a8

Please sign in to comment.