origintrail-node
Version:
OriginTrail Node - Decentralized Knowledge Graph Node Library
151 lines (130 loc) • 5.28 kB
JavaScript
import Command from '../command.js';
import {
TRIPLE_STORE_REPOSITORIES,
QUERY_TYPES,
OPERATION_ID_STATUS,
ERROR_TYPE,
COMMAND_PRIORITY,
} from '../../constants/constants.js';
class QueryCommand extends Command {
constructor(ctx) {
super(ctx);
this.dataService = ctx.dataService;
this.tripleStoreService = ctx.tripleStoreService;
this.paranetService = ctx.paranetService;
this.ualService = ctx.ualService;
this.errorType = ERROR_TYPE.QUERY.LOCAL_QUERY_ERROR;
}
async execute(command) {
const { operationId, queryType, paranetUAL } = command.data;
let { query, repository } = command.data;
await this.operationIdService.updateOperationIdStatus(
operationId,
null,
OPERATION_ID_STATUS.QUERY.QUERY_START,
);
let data;
if (paranetUAL) {
repository = this.paranetService.getParanetRepositoryName(paranetUAL);
}
// TODO: Review federated query logic for V8
// check if it's federated query
const pattern = /SERVICE\s+<([^>]+)>/g;
const matches = query.match(pattern);
if (matches?.length > 0) {
for (const match of matches) {
const repositoryInOriginalQuery = match.split('<')[1].split('>')[0];
const repositoryName = this.validateRepositoryName(repositoryInOriginalQuery);
const federatedQueryRepositoryEndpoint =
this.tripleStoreService.getRepositorySparqlEndpoint(repositoryName);
query = query.replace(repositoryInOriginalQuery, federatedQueryRepositoryEndpoint);
}
}
try {
switch (queryType) {
case QUERY_TYPES.CONSTRUCT: {
if (Array.isArray(repository)) {
const dataV6 = await this.tripleStoreService.construct(
query,
repository[0],
);
const dataV8 = await this.tripleStoreService.construct(
query,
repository[1],
);
data = this.dataService.removeDuplicateObjectsFromArray([
...dataV6,
...dataV8,
]);
} else {
data = await this.tripleStoreService.construct(query, repository);
}
break;
}
case QUERY_TYPES.SELECT: {
if (Array.isArray(repository)) {
const dataV6 = await this.tripleStoreService.select(query, repository[0]);
const dataV8 = await this.tripleStoreService.select(query, repository[1]);
data = this.dataService.removeDuplicateObjectsFromArray([
...dataV6,
...dataV8,
]);
} else {
data = await this.tripleStoreService.select(query, repository);
}
break;
}
default:
throw new Error(`Unknown query type ${queryType}`);
}
await this.operationIdService.cacheOperationIdDataToMemory(operationId, data);
await this.operationIdService.cacheOperationIdDataToFile(operationId, data);
await this.operationIdService.updateOperationIdStatus(
operationId,
null,
OPERATION_ID_STATUS.QUERY.QUERY_END,
);
await this.operationIdService.updateOperationIdStatus(
operationId,
null,
OPERATION_ID_STATUS.COMPLETED,
);
} catch (e) {
await this.handleError(operationId, null, e.message, this.errorType, true);
}
return Command.empty();
}
validateRepositoryName(repository) {
let isParanetRepoValid = false;
if (this.ualService.isUAL(repository)) {
const paranetRepoName = this.paranetService.getParanetRepositoryName(repository);
isParanetRepoValid = this.config.assetSync?.syncParanets.includes(repository);
if (isParanetRepoValid) {
return paranetRepoName;
}
}
const isTripleStoreRepoValid =
Object.values(TRIPLE_STORE_REPOSITORIES).includes(repository);
if (isTripleStoreRepoValid) {
return repository;
}
if (!isParanetRepoValid && !isTripleStoreRepoValid) {
throw new Error(`Query failed! Repository with name: ${repository} doesn't exist`);
}
}
/**
* Builds default queryCommand
* @param map
* @returns {{add, data: *, delay: *, deadline: *}}
*/
default(map) {
const command = {
name: 'queryCommand',
priority: COMMAND_PRIORITY.HIGHEST,
transactional: false,
};
Object.assign(command, map);
return command;
}
}
export default QueryCommand;