feat(core): Add support for partial-match execution filters (#15797)

This commit is contained in:
Daria
2025-06-04 09:37:35 +03:00
committed by GitHub
parent 7639cfbaa7
commit 1335af05d5
8 changed files with 99 additions and 21 deletions

View File

@@ -175,7 +175,7 @@ export namespace ExecutionSummaries {
status: ExecutionStatus[];
workflowId: string;
waitTill: boolean;
metadata: Array<{ key: string; value: string }>;
metadata: Array<{ key: string; value: string; exactMatch?: boolean }>;
startedAfter: string;
startedBefore: string;
annotationTags: string[]; // tag IDs
@@ -341,7 +341,7 @@ export interface IGetExecutionsQueryFilter {
workflowId?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
waitTill?: FindOperator<any> | boolean;
metadata?: Array<{ key: string; value: string }>;
metadata?: Array<{ key: string; value: string; exactMatch?: boolean }>;
startedAfter?: string;
startedBefore?: string;
}

View File

@@ -68,7 +68,7 @@ export interface IGetExecutionsQueryFilter {
workflowId?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
waitTill?: FindOperator<any> | boolean;
metadata?: Array<{ key: string; value: string }>;
metadata?: Array<{ key: string; value: string; exactMatch?: boolean }>;
startedAfter?: string;
startedBefore?: string;
}
@@ -88,7 +88,11 @@ function parseFiltersToQueryBuilder(
if (filters?.metadata) {
qb.leftJoin(ExecutionMetadata, 'md', 'md.executionId = execution.id');
for (const md of filters.metadata) {
qb.andWhere('md.key = :key AND md.value = :value', md);
if (md.exactMatch) {
qb.andWhere('md.key = :key AND md.value = :value', md);
} else {
qb.andWhere('md.key = :key AND LOWER(md.value) LIKE LOWER(:value)', md);
}
}
}
if (filters?.startedAfter) {
@@ -983,16 +987,18 @@ export class ExecutionRepository extends Repository<ExecutionEntity> {
if (startedAfter) qb.andWhere({ startedAt: moreThanOrEqual(startedAfter) });
if (metadata?.length === 1) {
const [{ key, value }] = metadata;
const [{ key, value, exactMatch }] = metadata;
qb.innerJoin(
ExecutionMetadata,
'md',
'md.executionId = execution.id AND md.key = :key AND md.value = :value',
);
const executionIdMatch = 'md.executionId = execution.id';
const keyMatch = exactMatch ? 'md.key = :key' : 'LOWER(md.key) = LOWER(:key)';
const valueMatch = exactMatch ? 'md.value = :value' : 'LOWER(md.value) LIKE LOWER(:value)';
const matches = [executionIdMatch, keyMatch, valueMatch];
qb.innerJoin(ExecutionMetadata, 'md', matches.join(' AND '));
qb.setParameter('key', key);
qb.setParameter('value', value);
qb.setParameter('value', exactMatch ? value : `%${value}%`);
}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing