Skip to content

Commit

Permalink
Fix broken LIMITs on CONSTRUCT queries on SPARQL endpoints, Closes #1319
Browse files Browse the repository at this point in the history
  • Loading branch information
rubensworks committed Apr 12, 2024
1 parent 9e70a64 commit f3f7e05
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 15 deletions.
Expand Up @@ -57,7 +57,7 @@ export class QuerySourceSkolemized implements IQuerySource {
return this.innerSource.queryBoolean(operation, context);
}

public queryQuads(operation: Algebra.Construct, context: IActionContext): AsyncIterator<RDF.Quad> {
public queryQuads(operation: Algebra.Operation, context: IActionContext): AsyncIterator<RDF.Quad> {
const operationMapped = deskolemizeOperation(operation, this.sourceId);
if (!operationMapped) {
const it: AsyncIterator<RDF.Quad> = new ArrayIterator<RDF.Quad>([], { autoStart: false });
Expand Down
Expand Up @@ -44,8 +44,14 @@ export class ActorQueryOperationSource extends ActorQueryOperation {
const sourceWrapper: IQuerySourceWrapper = ActorQueryOperation.getOperationSource(action.operation)!;
const mergedContext = sourceWrapper.context ? action.context.merge(sourceWrapper.context) : action.context;

// eslint-disable-next-line ts/switch-exhaustiveness-check
switch (action.operation.type) {
// Special case: allow CONSTRUCT queries that are SLICED to be pushed into sources as well.
case Algebra.types.SLICE:
case Algebra.types.CONSTRUCT: {
if (action.operation.type === Algebra.types.SLICE && action.operation.input.type !== Algebra.types.CONSTRUCT) {
break;
}
const quadStream = sourceWrapper.source.queryQuads(action.operation, mergedContext);
const metadata = getMetadataQuads(quadStream);
return {
Expand All @@ -72,15 +78,14 @@ export class ActorQueryOperationSource extends ActorQueryOperation {
type: 'void',
execute: () => sourceWrapper.source.queryVoid(<Algebra.Update>action.operation, mergedContext),
};
default: {
const bindingsStream = sourceWrapper.source.queryBindings(action.operation, mergedContext);
const metadata = getMetadataBindings(bindingsStream);
return {
type: 'bindings',
bindingsStream,
metadata,
};
}
}

const bindingsStream = sourceWrapper.source.queryBindings(action.operation, mergedContext);
const metadata = getMetadataBindings(bindingsStream);
return {
type: 'bindings',
bindingsStream,
metadata,
};
}
}
Expand Up @@ -74,6 +74,17 @@ describe('ActorQueryOperationSource', () => {
});

describe('run', () => {
it('should handle sliced construct operations', async() => {
const opIn = ActorQueryOperation.assignOperationSource(
AF.createSlice(AF.createConstruct(AF.createNop(), []), 1),
source1,
);
const result: IQueryOperationResultQuads = <any> await actor.run({ operation: opIn, context: ctx });
expect(result.type).toBe('quads');
await expect(result.metadata()).resolves.toEqual({ cardinality: { value: 10 }});
await expect(result.quadStream.toArray()).resolves.toBeRdfIsomorphic([]);
});

it('should handle construct operations', async() => {
const opIn = ActorQueryOperation.assignOperationSource(AF.createConstruct(AF.createNop(), []), source1);
const result: IQueryOperationResultQuads = <any> await actor.run({ operation: opIn, context: ctx });
Expand Down Expand Up @@ -166,6 +177,18 @@ describe('ActorQueryOperationSource', () => {
await expect(result.bindingsStream).toEqualBindingsStream([]);
});

it('should handle sliced bindings operations', async() => {
const opIn = ActorQueryOperation.assignOperationSource(AF.createSlice(AF.createNop(), 1), source1);
const result: IQueryOperationResultBindings = <any> await actor.run({ operation: opIn, context: ctx });
expect(result.type).toBe('bindings');
await expect(result.metadata()).resolves.toEqual({
cardinality: { value: 10 },
canContainUndefs: false,
variables: [],
});
await expect(result.bindingsStream).toEqualBindingsStream([]);
});

it('should handle bindings operations and invokes the logger', async() => {
const parentNode = '';
const logger: IPhysicalQueryPlanLogger = {
Expand Down
Expand Up @@ -423,7 +423,7 @@ export class QuerySourceQpf implements IQuerySource {
}

public queryQuads(
_operation: Algebra.Construct,
_operation: Algebra.Operation,
_context: IActionContext,
): AsyncIterator<RDF.Quad> {
throw new Error('queryQuads is not implemented in QuerySourceQpf');
Expand Down
Expand Up @@ -127,7 +127,7 @@ export class QuerySourceSparql implements IQuerySource {
return bindings;
}

public queryQuads(operation: Algebra.Construct, context: IActionContext): AsyncIterator<RDF.Quad> {
public queryQuads(operation: Algebra.Operation, context: IActionContext): AsyncIterator<RDF.Quad> {
this.lastSourceContext = this.context.merge(context);
const rawStream = this.endpointFetcher.fetchTriples(
this.url,
Expand Down
Expand Up @@ -115,7 +115,7 @@ export class QuerySourceHypermedia implements IQuerySource {
return it;
}

public queryQuads(operation: Algebra.Construct, context: IActionContext): AsyncIterator<RDF.Quad> {
public queryQuads(operation: Algebra.Operation, context: IActionContext): AsyncIterator<RDF.Quad> {
return new TransformIterator(async() => {
const source = await this.getSourceCached({ url: this.firstUrl }, {}, context, this.getAggregateStore(context));
return source.source.queryQuads(operation, context);
Expand Down
Expand Up @@ -139,7 +139,7 @@ export class QuerySourceRdfJs implements IQuerySource {
}

public queryQuads(
_operation: Algebra.Construct,
_operation: Algebra.Operation,
_context: IActionContext,
): AsyncIterator<RDF.Quad> {
throw new Error('queryQuads is not implemented in QuerySourceQpf');
Expand Down
2 changes: 1 addition & 1 deletion packages/types/lib/IQuerySource.ts
Expand Up @@ -89,7 +89,7 @@ export interface IQuerySource {
* @return {AsyncIterator<RDF.Quad>} The resulting quads stream.
*/
queryQuads: (
operation: Algebra.Construct,
operation: Algebra.Operation,
context: IActionContext,
) => AsyncIterator<RDF.Quad>;

Expand Down

0 comments on commit f3f7e05

Please sign in to comment.