@comake/skl-js-engine
Version:
Standard Knowledge Language Javascript Engine
147 lines (133 loc) • 5.04 kB
text/typescript
import type { Literal, Quad } from '@rdfjs/types';
import SparqlClient from 'sparql-http-client';
import type {
AskQuery,
ConstructQuery,
SelectQuery,
SparqlGenerator,
Update
} from 'sparqljs';
import { Generator } from 'sparqljs';
import { Logger } from '../../../../logger';
import { PerformanceLogger } from '../../../../util/PerformanceLogger';
import type { QueryExecutor, SelectVariableQueryResult } from './SparqlQueryExecutor';
export interface SparqlEndpointQueryExecutorOptions {
/**
* The location of the SPARQL endpoint. This value is required.
*/
readonly endpointUrl: string;
/**
* The location of the SPARQL update endpoint. Defaults to the value of endpointUrl if not set.
*/
readonly updateUrl?: string;
}
export class SparqlEndpointQueryExecutor implements QueryExecutor {
private readonly sparqlClient: SparqlClient;
private readonly sparqlGenerator: SparqlGenerator;
private readonly logger: Logger;
public constructor(options: SparqlEndpointQueryExecutorOptions) {
this.sparqlClient = new SparqlClient({
endpointUrl: options.endpointUrl,
updateUrl: options.updateUrl ?? options.endpointUrl
});
this.sparqlGenerator = new Generator();
this.logger = Logger.getInstance();
}
public async executeSparqlSelectAndGetData<
TQuery extends SelectQuery | ConstructQuery,
TReturn extends SelectVariableQueryResult<any> | Quad =
TQuery extends SelectQuery ? SelectVariableQueryResult<any> : Quad
>(
query: TQuery
): Promise<TReturn[]> {
const generatedQuery = this.sparqlGenerator.stringify(query);
return this.executeSparqlSelectAndGetDataRaw(generatedQuery);
}
public async executeSparqlSelectAndGetDataRaw<T extends Quad | SelectVariableQueryResult<any> = Quad>(
query: string
): Promise<T[]> {
const span = PerformanceLogger.startSpan('SPARQL.SELECT', { query });
try {
// This.logger.debug(query);
const stream = await this.sparqlClient.query.select(query, { operation: 'postUrlencoded' });
const result = await new Promise<T[]>((resolve, reject): void => {
const data: T[] = [];
stream.on('data', (row): void => {
data.push(row);
});
stream.on('end', (): void => {
resolve(data);
});
stream.on('error', (error): void => {
reject(error);
});
});
PerformanceLogger.endSpan(span, { resultCount: result.length });
return result;
} catch (error) {
PerformanceLogger.endSpan(span, { error: true });
throw error;
}
}
public async executeSparqlConstructAndGetDataRaw(query: string): Promise<Quad[]> {
const span = PerformanceLogger.startSpan('SPARQL.CONSTRUCT', { query });
try {
const result = await this.executeSparqlSelectAndGetDataRaw(query);
PerformanceLogger.endSpan(span, { resultCount: result.length });
return result;
} catch (error) {
PerformanceLogger.endSpan(span, { error: true });
throw error;
}
}
public async executeSparqlUpdate(query: Update): Promise<void> {
const generatedQuery = this.sparqlGenerator.stringify(query);
await this.executeRawSparqlUpdate(generatedQuery);
}
public async executeRawSparqlUpdate(query: string): Promise<void> {
const span = PerformanceLogger.startSpan('SPARQL.UPDATE', { query });
try {
await this.sparqlClient.query.update(query);
PerformanceLogger.endSpan(span);
} catch (error) {
PerformanceLogger.endSpan(span, { error: true });
throw error;
}
}
public async executeAskQueryAndGetResponse(query: AskQuery): Promise<boolean> {
const generatedQuery = this.sparqlGenerator.stringify(query);
const span = PerformanceLogger.startSpan('SPARQL.ASK', { query: generatedQuery });
try {
const result = await this.sparqlClient.query.ask(generatedQuery);
PerformanceLogger.endSpan(span, { result });
return result;
} catch (error) {
PerformanceLogger.endSpan(span, { error: true });
throw error;
}
}
public async executeSelectCountAndGetResponse(query: SelectQuery): Promise<number> {
const generatedQuery = this.sparqlGenerator.stringify(query);
const span = PerformanceLogger.startSpan('SPARQL.COUNT', { query: generatedQuery });
try {
const stream = await this.sparqlClient.query.select(generatedQuery, { operation: 'postUrlencoded' });
const countValue = await new Promise<number>((resolve, reject): void => {
let count: number;
stream.on('data', (row: { count: Literal }): void => {
count = Number.parseInt(row.count.value, 10);
});
stream.on('end', (): void => {
resolve(count);
});
stream.on('error', (error): void => {
reject(error);
});
});
PerformanceLogger.endSpan(span, { count: countValue });
return countValue;
} catch (error) {
PerformanceLogger.endSpan(span, { error: true });
throw error;
}
}
}