UNPKG

@comake/skl-js-engine

Version:

Standard Knowledge Language Javascript Engine

147 lines (133 loc) 5.04 kB
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; } } }