Skip to content

Modularizes Queryable and SparqlQueryable interfaces #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 72 additions & 58 deletions query/queryable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ import * as RDF from '../data-model';
import { Bindings, Query, ResultStream } from './common';

/**
* Context objects provide a way to pass additional bits information to the query engine when executing a query.
* Context properties provide a way to pass additional bits information to the query engine when executing a query.
*/
export interface QueryContext<SourceType> {
/**
* An array of data sources the query engine must use.
*/
sources?: [SourceType, ...SourceType[]];
export interface QueryContext {
/**
* The date that should be used by SPARQL operations such as NOW().
*/
Expand All @@ -23,9 +19,9 @@ export interface QueryContext<SourceType> {
}

/**
* Context object in the case the passed query is a string.
* Context properties in the case the passed query is a string.
*/
export interface QueryStringContext<SourceType> extends QueryContext<SourceType> {
export interface QueryStringContext extends QueryContext {
/**
* The format in which the query string is defined.
* Defaults to { language: 'sparql', version: '1.1' }
Expand All @@ -38,9 +34,19 @@ export interface QueryStringContext<SourceType> extends QueryContext<SourceType>
}

/**
* Context object in the case the passed query is an algebra object.
* Context properties in the case the passed query is an algebra object.
*/
export type QueryAlgebraContext<SourceType> = QueryContext<SourceType>;
export type QueryAlgebraContext = QueryContext;

/**
* Context properties for engines that can query upon dynamic sets of sources.
*/
export interface QuerySourceContext<SourceType> {
/**
* An array of data sources the query engine must use.
*/
sources: [SourceType, ...SourceType[]];
}

/**
* Represents a specific query format
Expand All @@ -61,83 +67,91 @@ export interface QueryFormat {
extensions?: string[];
}

/**
* Placeholder to represent SPARQL Algebra trees.
* Algebra typings are TBD. Reference implementations include:
* - https://www.npmjs.com/package/sparqlalgebrajs
*/
export type Algebra = any;

/**
* Generic query engine interfaces.
* It allow engines to return any type of result object for any type of query.
* @param QueryFormatTypesAvailable The format of the query, either string or algebra object.
* @param SourceType The allowed sources over which queries can be executed.
* It allow engines to return any type of result object for string queries.
* @param SupportedMetadataType The allowed metadata types.
* @param QueryType The allowed query types.
* @param QueryStringContextType Type of the string-based query context.
* @param QueryAlgebraContextType Type of the algebra-based query context.
*/
export interface Queryable<
QueryFormatTypesAvailable extends string | Algebra,
SourceType,
export interface StringQueryable<
SupportedMetadataType,
QueryType extends Query<SupportedMetadataType>,
QueryStringContextType extends QueryStringContext<SourceType>,
QueryAlgebraContextType extends QueryAlgebraContext<SourceType>,
QueryStringContextType extends QueryStringContext = QueryStringContext,
> {
/**
* Initiate a given query.
* Initiate a given query provided as a string.
*
* This will produce a future to a query result, which has to be executed to obtain the query results.
*
* This can reject given an unsupported or invalid query.
*
* @see Query
*/
query<QueryFormatType extends QueryFormatTypesAvailable>(
query: QueryFormatType,
context?: QueryFormatType extends string ? QueryStringContextType : QueryAlgebraContextType,
): Promise<QueryType>;
query(query: string, context?: QueryStringContextType): Promise<Query<SupportedMetadataType>>;
}

/**
* SPARQL-constrained query interface.
* Generic query engine interfaces.
* It allow engines to return any type of result object for Algebra queries.
* @param AlgebraType The supported algebra types.
* @param SupportedMetadataType The allowed metadata types.
* @param QueryStringContextType Type of the algebra-based query context.
*/
export interface AlgebraQueryable<
AlgebraType,
SupportedMetadataType,
QueryAlgebraContextType extends QueryAlgebraContext = QueryAlgebraContext,
> {
/**
* Initiate a given query provided as an Algebra object.
*
* This will produce a future to a query result, which has to be executed to obtain the query results.
*
* This can reject given an unsupported or invalid query.
*
* @see Query
*/
query(query: AlgebraType, context?: QueryAlgebraContextType): Promise<Query<SupportedMetadataType>>;
}

/**
* SPARQL-constrained query interface for queries provided as strings.
*
* This interface guarantees that result objects are of the expected type as defined by the SPARQL spec.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tsdoc doesn't mention the fact that it's string-queryable.

*/
export type SparqlQueryable<
QueryFormatTypesAvailable extends string | Algebra,
SourceType,
QueryStringContextType extends QueryStringContext<SourceType>,
QueryAlgebraContextType extends QueryAlgebraContext<SourceType>,
SupportedResultType,
> = unknown
export type StringSparqlQueryable<SupportedResultType, QueryStringContextType extends QueryStringContext = QueryStringContext> = unknown
& (SupportedResultType extends BindingsResultSupport ? {
queryBindings<QueryFormatType extends QueryFormatTypesAvailable>(
query: QueryFormatType,
context?: QueryFormatType extends string ? QueryStringContextType : QueryAlgebraContextType,
): Promise<ResultStream<Bindings>>;
queryBindings(query: string, context?: QueryStringContextType): Promise<ResultStream<Bindings>>;
} : unknown)
& (SupportedResultType extends BooleanResultSupport ? {
queryBoolean<QueryFormatType extends QueryFormatTypesAvailable>(
query: QueryFormatType,
context?: QueryFormatType extends string ? QueryStringContextType : QueryAlgebraContextType,
): Promise<boolean>;
queryBoolean(query: string, context?: QueryStringContextType): Promise<boolean>;
} : unknown)
& (SupportedResultType extends QuadsResultSupport ? {
queryQuads<QueryFormatType extends QueryFormatTypesAvailable>(
query: QueryFormatType,
context?: QueryFormatType extends string ? QueryStringContextType : QueryAlgebraContextType,
): Promise<ResultStream<RDF.Quad>>;
queryQuads(query: string, context?: QueryStringContextType): Promise<ResultStream<RDF.Quad>>;
} : unknown)
& (SupportedResultType extends VoidResultSupport ? {
queryVoid<QueryFormatType extends QueryFormatTypesAvailable>(
query: QueryFormatType,
context?: QueryFormatType extends string ? QueryStringContextType : QueryAlgebraContextType,
): Promise<void>;
queryVoid(query: string, context?: QueryStringContextType): Promise<void>;
} : unknown)
;

/**
* SPARQL-constrainted query interface for queries provided as Algebra objects.
*
* This interface guarantees that result objects are of the expected type as defined by the SPARQL spec.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tsdoc doesn't mention the fact that it's algebra-queryable.

*/
export type AlgebraSparqlQueryable<AlgebraType, SupportedResultType, QueryAlgebraContextType extends QueryAlgebraContext = QueryAlgebraContext> = unknown
& (SupportedResultType extends BindingsResultSupport ? {
queryBindings(query: AlgebraType, context?: QueryAlgebraContextType): Promise<ResultStream<Bindings>>;
} : unknown)
& (SupportedResultType extends BooleanResultSupport ? {
queryBoolean(query: AlgebraType, context?: QueryAlgebraContextType): Promise<boolean>;
} : unknown)
& (SupportedResultType extends QuadsResultSupport ? {
queryQuads(query: AlgebraType, context?: QueryAlgebraContextType): Promise<ResultStream<RDF.Quad>>;
} : unknown)
& (SupportedResultType extends VoidResultSupport ? {
queryVoid(query: AlgebraType, context?: QueryAlgebraContextType): Promise<void>;
} : unknown)
;
;

export type SparqlResultSupport = BindingsResultSupport & VoidResultSupport & QuadsResultSupport & BooleanResultSupport;
export type BindingsResultSupport = { bindings: true };
Expand Down
50 changes: 42 additions & 8 deletions rdf-js-query-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@ import {
BindingsFactory,
Bindings,
Term,
Queryable,
StringQueryable,
AlgebraQueryable,
SparqlResultSupport,
MetadataOpts,
QueryStringContext,
QueryAlgebraContext,
AllMetadataSupport, Query, Variable, ResultStream, Quad, SparqlQueryable, BindingsResultSupport, QuadsResultSupport
AllMetadataSupport,
Query,
Variable,
ResultStream,
Quad,
StringSparqlQueryable,
AlgebraSparqlQueryable,
BindingsResultSupport,
QuadsResultSupport,
} from ".";

function test_bindings() {
Expand Down Expand Up @@ -38,8 +47,8 @@ function test_bindings() {
}
}

async function test_queryable() {
const engine: Queryable<string, string, AllMetadataSupport, Query<SparqlResultSupport>, QueryStringContext<string>, QueryAlgebraContext<string>> = <any> {};
async function test_stringqueryable() {
const engine: StringQueryable<AllMetadataSupport, QueryAlgebraContext> = <any> {};

const query: Query<SparqlResultSupport> = await engine.query('SELECT * WHERE { ... }');
switch (query.resultType) {
Expand All @@ -61,17 +70,30 @@ async function test_queryable() {
}
}

async function test_sparqlqueryable() {
const engine: SparqlQueryable<string, string, QueryStringContext<string>, QueryAlgebraContext<string>, SparqlResultSupport> = <any> {};
async function test_stringsparqlqueryable() {
const engine: StringSparqlQueryable<SparqlResultSupport> = <any> {};

const bindings: ResultStream<Bindings> = await engine.queryBindings('SELECT * WHERE { ... }');
const quads: ResultStream<Quad> = await engine.queryQuads('CONSTRUCT WHERE { ... }');
const bool: boolean = await engine.queryBoolean('ASK WHERE { ... }');
const done: void = await engine.queryVoid('INSERT WHERE { ... }');
}

async function test_sparqlqueryable_partial() {
const engine: SparqlQueryable<string, string, QueryStringContext<string>, QueryAlgebraContext<string>, BindingsResultSupport & QuadsResultSupport> = <any> {};
async function test_algebrasparqlqueryable() {
interface AlgebraType { mock: 'algebra' }
const engine: AlgebraSparqlQueryable<AlgebraType, SparqlResultSupport> = <any> {};

const bindings: ResultStream<Bindings> = await engine.queryBindings({ mock: 'algebra' });
const quads: ResultStream<Quad> = await engine.queryQuads({ mock: 'algebra' });
const bool: boolean = await engine.queryBoolean({ mock: 'algebra' });
const done: void = await engine.queryVoid({ mock: 'algebra' });

// @ts-ignore
await engine.queryBoolean('ASK WHERE { ... }'); // Query type doesn't match AlgebraType
}

async function test_stringsparqlqueryable_partial() {
const engine: StringSparqlQueryable<BindingsResultSupport & QuadsResultSupport> = <any> {};

const bindings: ResultStream<Bindings> = await engine.queryBindings('SELECT * WHERE { ... }');
const quads: ResultStream<Quad> = await engine.queryQuads('CONSTRUCT WHERE { ... }');
Expand All @@ -80,3 +102,15 @@ async function test_sparqlqueryable_partial() {
// @ts-ignore
const done: void = await engine.queryVoid('INSERT WHERE { ... }'); // Unsupported
}

async function test_algebrasparqlqueryable_partial() {
interface AlgebraType { mock: 'algebra' }
const engine: AlgebraSparqlQueryable<AlgebraType, BindingsResultSupport & QuadsResultSupport> = <any> {};

const bindings: ResultStream<Bindings> = await engine.queryBindings({ mock: 'algebra' });
const quads: ResultStream<Quad> = await engine.queryQuads({ mock: 'algebra' });
// @ts-ignore
const bool: boolean = await engine.queryBoolean({ mock: 'algebra' }); // Unsupported
// @ts-ignore
const done: void = await engine.queryVoid({ mock: 'algebra' }); // Unsupported
}