@5minds/processcube_engine
Version:
The ProcessCube Engine. Stores and executes BPMNs.
352 lines • 14.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCleanupOrphanedFlowNodeInstancesQuery = getCleanupOrphanedFlowNodeInstancesQuery;
exports.getCleanupOrphanedExternalTasksQuery = getCleanupOrphanedExternalTasksQuery;
exports.buildWhereClause = buildWhereClause;
exports.buildPagination = buildPagination;
exports.getProcessDefinitionUpdatedAtMaxFilter = getProcessDefinitionUpdatedAtMaxFilter;
exports.buildDateFilter = buildDateFilter;
exports.buildSearchQueryFilter = buildSearchQueryFilter;
exports.buildFlowNodeLaneQuery = buildFlowNodeLaneQuery;
const sequelize_1 = require("sequelize");
const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk");
const dynamicSequelize = sequelize_1.Sequelize;
function getCleanupOrphanedFlowNodeInstancesQuery(dialect, schema) {
if (dialect === 'postgres') {
const tableNamePrefix = schema ? `"${schema}".` : '"public".';
return `
UPDATE ${tableNamePrefix}"FlowNodeInstances"
SET state = pi.state
FROM ${tableNamePrefix}"ProcessInstances" AS pi
WHERE ${tableNamePrefix}"FlowNodeInstances"."processInstanceId" = pi."processInstanceId"
AND ${tableNamePrefix}"FlowNodeInstances".state IN ('suspended', 'running')
AND pi.state != 'running';
`;
}
if (dialect === 'mssql') {
const tableNamePrefix = schema ? `${schema}.` : '';
return `
UPDATE ${tableNamePrefix}FlowNodeInstances
SET FlowNodeInstances.state = processInstance.state
FROM ${tableNamePrefix}FlowNodeInstances AS FlowNodeInstance
INNER JOIN ${tableNamePrefix}ProcessInstances AS ProcessInstance
ON FlowNodeInstance.processInstanceId = ProcessInstance.processInstanceId
WHERE FlowNodeInstance.state IN (N'suspended', N'running')
AND ProcessInstance.state != N'running';`;
}
const tableNamePrefix = schema ? `${schema}.` : '';
return `
UPDATE \`${tableNamePrefix}FlowNodeInstances\`
SET state = (
SELECT state
FROM \`${tableNamePrefix}ProcessInstances\` as pi1
WHERE pi1.processInstanceId = \`${tableNamePrefix}FlowNodeInstances\`.processInstanceId
LIMIT 1
)
WHERE state IN ('suspended', 'running')
AND EXISTS (
SELECT 1 FROM \`${tableNamePrefix}ProcessInstances\` as pi2
WHERE pi2.processInstanceId = \`${tableNamePrefix}FlowNodeInstances\`.processInstanceId
AND pi2.state != 'running'
);
`;
}
function getCleanupOrphanedExternalTasksQuery(dialect, schema) {
if (dialect === 'postgres') {
const tableNamePrefix = schema ? `"${schema}".` : '"public".';
return `
UPDATE ${tableNamePrefix}"ExternalTasks"
SET state = 'finished'
FROM ${tableNamePrefix}"FlowNodeInstances" AS fni
WHERE ${tableNamePrefix}"ExternalTasks"."flowNodeInstanceId" = fni."flowNodeInstanceId"
AND ${tableNamePrefix}"ExternalTasks".state = 'pending'
AND fni.state != 'suspended';
`;
}
if (dialect === 'mssql') {
const tableNamePrefix = schema ? `${schema}.` : '';
return `
UPDATE ${tableNamePrefix}ExternalTasks
SET state = 'finished'
FROM ${tableNamePrefix}ExternalTasks AS et
INNER JOIN ${tableNamePrefix}FlowNodeInstances AS fni
ON et.flowNodeInstanceId = fni.flowNodeInstanceId
WHERE et.state = N'pending'
AND fni.state != N'suspended';`;
}
const tableNamePrefix = schema ? `${schema}.` : '';
return `
UPDATE \`${tableNamePrefix}ExternalTasks\`
SET state = 'finished'
WHERE state = 'pending'
AND EXISTS (
SELECT 1 FROM \`${tableNamePrefix}FlowNodeInstances\` as fni
WHERE fni.flowNodeInstanceId = \`${tableNamePrefix}ExternalTasks\`.flowNodeInstanceId
AND fni.state != 'suspended'
);
`;
}
function buildWhereClause(query) {
const whereClause = {};
const fieldsToQuery = Object.keys(query);
for (const fieldName of fieldsToQuery) {
const fieldValue = query[fieldName];
// null should be allowed, because it is a legitimate db value
if (fieldValue === undefined) {
continue;
}
if (Array.isArray(fieldValue)) {
whereClause[fieldName] = {
[sequelize_1.Op.in]: fieldValue.map(parseValue),
};
}
else {
whereClause[fieldName] = parseValue(fieldValue);
}
}
return whereClause;
}
function parseValue(value) {
// "typeof null" and "typeof Date" return "object", so these must be handled separately.
if (value === null || value instanceof Date) {
return value;
}
if (typeof value === 'object') {
return JSON.stringify(value);
}
return value;
}
function buildPagination(offset, limit) {
const pagination = {};
if (offset > 0) {
pagination.offset = offset;
}
if (limit > 0) {
pagination.limit = limit;
}
return pagination;
}
function getProcessDefinitionUpdatedAtMaxFilter(dialect, schema) {
if (dialect === 'postgres') {
const tableNamePrefix = schema ? `"${schema}".` : '"public".';
return `(
SELECT max("updatedAt")
FROM ${tableNamePrefix}"ProcessDefinitions" AS pd2
WHERE "ProcessDefinition".name = pd2.name
)`;
}
if (dialect === 'mssql') {
const tableNamePrefix = schema ? `${schema}.` : '';
return `(
SELECT max(updatedAt)
FROM ${tableNamePrefix}ProcessDefinitions AS pd2
WHERE ProcessDefinition.name = pd2.name
)`;
}
const tableNamePrefix = schema ? `${schema}.` : '';
return `(
SELECT max(updatedAt)
FROM \`${tableNamePrefix}ProcessDefinitions\` AS pd2
WHERE ProcessDefinition.name = pd2.name
)`;
}
function buildDateFilter(equals, after, before) {
if (!equals && !before && !after) {
return undefined;
}
if (equals && !Array.isArray(equals)) {
equals = [equals];
}
const dateFilter = {};
if (equals) {
dateFilter[sequelize_1.Op.in] = equals;
}
if (before) {
dateFilter[sequelize_1.Op.lt] = before;
}
if (after) {
dateFilter[sequelize_1.Op.gte] = after;
}
return dateFilter;
}
function buildSearchQueryFilter(searchQuery, column, sequelizeInstance, lowerCaseSearchValue = false, forceMostPerformantCasingOption = false) {
if (searchQuery === undefined || searchQuery === null) {
return searchQuery;
}
const whereObject = {};
let params;
let operator;
let filter;
if (typeof searchQuery === 'string') {
params = [searchQuery];
operator = 'or';
}
else if (Array.isArray(searchQuery)) {
params = searchQuery;
operator = 'or';
}
else {
params = searchQuery.searchParams;
operator = searchQuery.operator;
}
if (isSearchQueryArray(params)) {
filter = params.map((param) => buildSearchQueryFilter(param, column, sequelizeInstance, lowerCaseSearchValue, forceMostPerformantCasingOption));
}
else {
filter = buildSearchParamsFilter(params, column, sequelizeInstance, lowerCaseSearchValue, forceMostPerformantCasingOption);
}
if (filter === undefined) {
return undefined;
}
if (operator == 'and') {
whereObject[sequelize_1.Op.and] = filter;
}
else {
whereObject[sequelize_1.Op.or] = filter;
}
return whereObject;
}
function buildFlowNodeLaneQuery(query) {
const flowNodeLanes = query.flowNodeLane;
const requestingUserId = query.requestingUserId;
delete query.flowNodeLane;
delete query.requestingUserEmail;
delete query.requestingUserId;
delete query.requestingUserName;
if (query.processModelName) {
query['$processInstance.processModelName$'] = query['processModelName'];
delete query['processModelName'];
}
const whereClause = buildWhereClause(query);
const lanesAsArray = Array.isArray(flowNodeLanes) ? flowNodeLanes : [flowNodeLanes];
const shouldQueryAllFlowNodesForSpecificLanes = requestingUserId != undefined;
if (shouldQueryAllFlowNodesForSpecificLanes) {
whereClause['flowNodeLane'] = { [sequelize_1.Op.in]: lanesAsArray };
}
return whereClause;
}
function buildSearchParamsFilter(searchParams, column, sequelizeInstance, lowerCaseSearchValue = false, forceMostPerformantCasingOption = false) {
if (!searchParams || searchParams.length === 0) {
return undefined;
}
if (isStringArray(searchParams)) {
searchParams = searchParams.map((searchString) => {
return {
partialMatch: false,
caseSensitive: true,
searchString: lowerCaseSearchValue ? searchString?.toLowerCase() : searchString,
};
});
}
const queryArray = [];
for (const searchParam of searchParams) {
const caseSensitive = searchParam.caseSensitive !== false;
const partialMatch = searchParam.partialMatch === true;
if (!searchParam.searchString || searchParam.searchString.length === 0) {
continue;
}
queryArray.push(buildDialectSpecificQuery(lowerCaseSearchValue ? searchParam.searchString?.toLowerCase() : searchParam.searchString, caseSensitive, partialMatch, column, sequelizeInstance, forceMostPerformantCasingOption));
}
return queryArray;
}
function buildDialectSpecificQuery(searchString, caseSensitive, partialMatch, column, sequelizeInstance, forceMostPerformantCasingOption = false) {
switch (sequelizeInstance.getDialect()) {
case 'sqlite':
return buildSQLiteQuery(searchString, caseSensitive, partialMatch, column, forceMostPerformantCasingOption);
case 'postgres':
return buildPostgresQuery(searchString, caseSensitive, partialMatch, column, forceMostPerformantCasingOption);
case 'mysql':
return buildMySQLQuery(searchString, caseSensitive, partialMatch, column, sequelizeInstance, forceMostPerformantCasingOption);
case 'mssql':
return buildMSSQLQuery(searchString, caseSensitive, partialMatch, column, forceMostPerformantCasingOption);
default:
throw new processcube_engine_sdk_1.InternalServerError(`Unable to build search query for unknown dialect: \`${sequelizeInstance.getDialect()}\`.`, 'setup');
}
}
function buildSQLiteQuery(searchString, caseSensitive, partialMatch, column, forceMostPerformantCasingOption = false) {
if (forceMostPerformantCasingOption) {
caseSensitive = true;
}
if (caseSensitive && partialMatch) {
return dynamicSequelize.where(sequelize_1.Sequelize.fn('instr', sequelize_1.Sequelize.col(column), searchString), sequelize_1.Op.gt, 0);
}
if (caseSensitive && !partialMatch) {
return { [sequelize_1.Op.eq]: searchString };
}
if (!caseSensitive && partialMatch) {
return dynamicSequelize.where(sequelize_1.Sequelize.fn('lower', sequelize_1.Sequelize.col(column)), sequelize_1.Op.substring, sequelize_1.Sequelize.fn('lower', `%${searchString}%`));
}
// !caseSensitive && !partialMatch
return dynamicSequelize.where(sequelize_1.Sequelize.fn('lower', sequelize_1.Sequelize.col(column)), sequelize_1.Op.eq, sequelize_1.Sequelize.fn('lower', searchString));
}
function buildPostgresQuery(searchString, caseSensitive, partialMatch, column, forceMostPerformantCasingOption = false) {
if (forceMostPerformantCasingOption) {
caseSensitive = true;
}
if (caseSensitive && partialMatch) {
return { [sequelize_1.Op.substring]: `%${searchString}%` };
}
if (caseSensitive && !partialMatch) {
return { [sequelize_1.Op.eq]: searchString };
}
if (!caseSensitive && partialMatch) {
return dynamicSequelize.where(sequelize_1.Sequelize.fn('lower', sequelize_1.Sequelize.col(column)), sequelize_1.Op.substring, sequelize_1.Sequelize.fn('lower', `%${searchString}%`));
}
// !caseSensitive && !partialMatch
return dynamicSequelize.where(sequelize_1.Sequelize.fn('lower', sequelize_1.Sequelize.col(column)), sequelize_1.Op.eq, sequelize_1.Sequelize.fn('lower', searchString));
}
function buildMySQLQuery(searchString, caseSensitive, partialMatch, column, sequelizeInstance, forceMostPerformantCasingOption = false) {
if (forceMostPerformantCasingOption) {
caseSensitive = true;
}
if (caseSensitive && partialMatch) {
return dynamicSequelize.literal(`${formatColumnForMySQL(column)} like BINARY ${sequelizeInstance.escape(`%${searchString}%`)}`);
}
if (caseSensitive && !partialMatch) {
return dynamicSequelize.literal(`${formatColumnForMySQL(column)} = BINARY ${sequelizeInstance.escape(`${searchString}`)}`);
}
if (!caseSensitive && partialMatch) {
return dynamicSequelize.where(sequelize_1.Sequelize.fn('lower', sequelize_1.Sequelize.col(column)), sequelize_1.Op.substring, sequelize_1.Sequelize.fn('lower', `%${searchString}%`));
}
// !caseSensitive && !partialMatch
return dynamicSequelize.where(sequelize_1.Sequelize.fn('lower', sequelize_1.Sequelize.col(column)), sequelize_1.Op.eq, sequelize_1.Sequelize.fn('lower', searchString));
}
function formatColumnForMySQL(column) {
return column.split('.').reduce((prev, curr) => {
if (prev) {
return `${prev}.\`${curr}\``;
}
return `\`${curr}\``;
});
}
function buildMSSQLQuery(searchString, caseSensitive, partialMatch, column, forceMostPerformantCasingOption = false) {
if (forceMostPerformantCasingOption) {
caseSensitive = false;
}
if (caseSensitive && partialMatch) {
return dynamicSequelize.literal(`${formatColumnForMSSQL(column)} LIKE '%${searchString}%' COLLATE Latin1_General_CS_AS`);
}
if (caseSensitive && !partialMatch) {
return dynamicSequelize.literal(`${formatColumnForMSSQL(column)} = '${searchString}' COLLATE Latin1_General_CS_AS`);
}
if (!caseSensitive && partialMatch) {
return { [sequelize_1.Op.substring]: `%${searchString}%` };
}
// !caseSensitive && !partialMatch
return { [sequelize_1.Op.eq]: searchString };
}
function formatColumnForMSSQL(column) {
return column.split('.').reduce((prev, curr) => {
if (prev) {
return `${prev}.[${curr}]`;
}
return `[${curr}]`;
});
}
function isSearchQueryArray(objectToCheck) {
return Array.isArray(objectToCheck) && objectToCheck.length > 0 && typeof objectToCheck[0] !== 'string' && 'operator' in objectToCheck[0] && 'searchParams' in objectToCheck[0];
}
function isStringArray(objectToCheck) {
return Array.isArray(objectToCheck) && objectToCheck.length > 0 && typeof objectToCheck[0] === 'string';
}
//# sourceMappingURL=SearchQueryBuilder.js.map