From 092b0dce0c84a576d363d559a799cdf6dcbb752b Mon Sep 17 00:00:00 2001 From: Ryhor <125865748+rkukharenka@users.noreply.github.com> Date: Mon, 28 Aug 2023 14:22:24 +0300 Subject: [PATCH 1/2] EPMRPP-85773 || improve jooq query (#920) --- .../dao/TestItemRepositoryCustomImpl.java | 2175 +++++++++-------- 1 file changed, 1151 insertions(+), 1024 deletions(-) diff --git a/src/main/java/com/epam/ta/reportportal/dao/TestItemRepositoryCustomImpl.java b/src/main/java/com/epam/ta/reportportal/dao/TestItemRepositoryCustomImpl.java index 2b4d62b13..aae6d9a74 100644 --- a/src/main/java/com/epam/ta/reportportal/dao/TestItemRepositoryCustomImpl.java +++ b/src/main/java/com/epam/ta/reportportal/dao/TestItemRepositoryCustomImpl.java @@ -16,14 +16,68 @@ package com.epam.ta.reportportal.dao; -import com.epam.ta.reportportal.commons.querygen.*; +import static com.epam.ta.reportportal.commons.querygen.FilterTarget.FILTERED_ID; +import static com.epam.ta.reportportal.commons.querygen.FilterTarget.FILTERED_QUERY; +import static com.epam.ta.reportportal.commons.querygen.QueryBuilder.retrieveOffsetAndApplyBoundaries; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_TEST_CASE_HASH; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_UNIQUE_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.RETRY_PARENT; +import static com.epam.ta.reportportal.dao.constant.LogRepositoryConstants.ITEM; +import static com.epam.ta.reportportal.dao.constant.TestItemRepositoryConstants.ATTACHMENTS_COUNT; +import static com.epam.ta.reportportal.dao.constant.TestItemRepositoryConstants.HAS_CONTENT; +import static com.epam.ta.reportportal.dao.constant.TestItemRepositoryConstants.NESTED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.HISTORY; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.ITEMS; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.LAUNCHES; +import static com.epam.ta.reportportal.dao.constant.WidgetRepositoryConstants.ID; +import static com.epam.ta.reportportal.dao.util.JooqFieldNameTransformer.fieldName; +import static com.epam.ta.reportportal.dao.util.QueryUtils.collectJoinFields; +import static com.epam.ta.reportportal.dao.util.RecordMappers.INDEX_TEST_ITEM_RECORD_MAPPER; +import static com.epam.ta.reportportal.dao.util.RecordMappers.ISSUE_TYPE_RECORD_MAPPER; +import static com.epam.ta.reportportal.dao.util.RecordMappers.NESTED_STEP_RECORD_MAPPER; +import static com.epam.ta.reportportal.dao.util.RecordMappers.TEST_ITEM_RECORD_MAPPER; +import static com.epam.ta.reportportal.dao.util.ResultFetchers.TEST_ITEM_FETCHER; +import static com.epam.ta.reportportal.dao.util.ResultFetchers.TEST_ITEM_RETRY_FETCHER; +import static com.epam.ta.reportportal.jooq.Tables.ATTACHMENT; +import static com.epam.ta.reportportal.jooq.Tables.ISSUE; +import static com.epam.ta.reportportal.jooq.Tables.ISSUE_GROUP; +import static com.epam.ta.reportportal.jooq.Tables.ISSUE_TYPE_PROJECT; +import static com.epam.ta.reportportal.jooq.Tables.LAUNCH; +import static com.epam.ta.reportportal.jooq.Tables.LOG; +import static com.epam.ta.reportportal.jooq.Tables.PARAMETER; +import static com.epam.ta.reportportal.jooq.Tables.PROJECT; +import static com.epam.ta.reportportal.jooq.Tables.STATISTICS; +import static com.epam.ta.reportportal.jooq.Tables.STATISTICS_FIELD; +import static com.epam.ta.reportportal.jooq.tables.JIssueType.ISSUE_TYPE; +import static com.epam.ta.reportportal.jooq.tables.JTestItem.TEST_ITEM; +import static com.epam.ta.reportportal.jooq.tables.JTestItemResults.TEST_ITEM_RESULTS; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; +import static org.jooq.impl.DSL.condition; +import static org.jooq.impl.DSL.field; +import static org.jooq.impl.DSL.max; +import static org.jooq.impl.DSL.name; +import static org.jooq.impl.DSL.with; + +import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.commons.querygen.QueryBuilder; +import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.dao.util.QueryUtils; import com.epam.ta.reportportal.dao.util.TimestampUtils; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.enums.TestItemTypeEnum; -import com.epam.ta.reportportal.entity.item.*; +import com.epam.ta.reportportal.entity.item.ItemPathName; +import com.epam.ta.reportportal.entity.item.LaunchPathName; +import com.epam.ta.reportportal.entity.item.NestedStep; +import com.epam.ta.reportportal.entity.item.PathName; +import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.item.history.TestItemHistory; import com.epam.ta.reportportal.entity.item.issue.IssueType; import com.epam.ta.reportportal.entity.statistics.Statistics; @@ -36,10 +90,35 @@ import com.epam.ta.reportportal.jooq.tables.JTestItem; import com.epam.ta.reportportal.ws.model.analyzer.IndexTestItem; import com.google.common.collect.Lists; +import java.sql.Timestamp; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.logging.log4j.util.Strings; +import org.jooq.CommonTableExpression; import org.jooq.Condition; -import org.jooq.*; +import org.jooq.DSLContext; +import org.jooq.DatePart; +import org.jooq.Field; +import org.jooq.JoinType; +import org.jooq.Log; +import org.jooq.Record; +import org.jooq.Record4; +import org.jooq.Result; +import org.jooq.SelectOnConditionStep; +import org.jooq.SelectQuery; +import org.jooq.Table; import org.jooq.impl.DSL; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -50,1031 +129,1079 @@ import org.springframework.data.util.Pair; import org.springframework.stereotype.Repository; -import java.sql.Timestamp; -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.*; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.FilterTarget.FILTERED_ID; -import static com.epam.ta.reportportal.commons.querygen.FilterTarget.FILTERED_QUERY; -import static com.epam.ta.reportportal.commons.querygen.QueryBuilder.retrieveOffsetAndApplyBoundaries; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.*; -import static com.epam.ta.reportportal.dao.constant.LogRepositoryConstants.ITEM; -import static com.epam.ta.reportportal.dao.constant.LogRepositoryConstants.LOGS; -import static com.epam.ta.reportportal.dao.constant.TestItemRepositoryConstants.*; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; -import static com.epam.ta.reportportal.dao.constant.WidgetRepositoryConstants.ID; -import static com.epam.ta.reportportal.dao.util.JooqFieldNameTransformer.fieldName; -import static com.epam.ta.reportportal.dao.util.QueryUtils.collectJoinFields; -import static com.epam.ta.reportportal.dao.util.RecordMappers.*; -import static com.epam.ta.reportportal.dao.util.ResultFetchers.*; -import static com.epam.ta.reportportal.jooq.Tables.*; -import static com.epam.ta.reportportal.jooq.tables.JIssueType.ISSUE_TYPE; -import static com.epam.ta.reportportal.jooq.tables.JTestItem.TEST_ITEM; -import static com.epam.ta.reportportal.jooq.tables.JTestItemResults.TEST_ITEM_RESULTS; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; -import static org.jooq.impl.DSL.*; - /** * @author Pavel Bortnik */ @Repository public class TestItemRepositoryCustomImpl implements TestItemRepositoryCustom { - private static final String OUTER_ITEM_TABLE = "outer_item_table"; - private static final String INNER_ITEM_TABLE = "inner_item_table"; - private static final String TEST_CASE_ID_TABLE = "test_case_id_table"; - private static final String RESULT_OUTER_TABLE = "resultOuterTable"; - private static final String LATERAL_TABLE = "lateralTable"; - private static final String RESULT_INNER_TABLE = "resultInnerTable"; - - private static final String CHILD_ITEM_TABLE = "child"; - - private static final String BASELINE_TABLE = "baseline"; - - private static final String ITEM_START_TIME = "itemStartTime"; - private static final String LAUNCH_START_TIME = "launchStartTime"; - private static final String ACCUMULATED_STATISTICS = "accumulated_statistics"; - - private DSLContext dsl; - - @Autowired - public void setDsl(DSLContext dsl) { - this.dsl = dsl; - } - - @Override - public Set accumulateStatisticsByFilter(Queryable filter) { - return dsl.fetch(DSL.with(FILTERED_QUERY) - .as(QueryBuilder.newBuilder(filter, QueryUtils.collectJoinFields(filter)).build()) - .select(DSL.sum(STATISTICS.S_COUNTER).as(ACCUMULATED_STATISTICS), STATISTICS_FIELD.NAME) - .from(STATISTICS) - .join(DSL.table(name(FILTERED_QUERY))) - .on(STATISTICS.ITEM_ID.eq(field(name(FILTERED_QUERY, FILTERED_ID), Long.class))) - .join(STATISTICS_FIELD) - .on(STATISTICS.STATISTICS_FIELD_ID.eq(STATISTICS_FIELD.SF_ID)) - .groupBy(STATISTICS_FIELD.NAME) - .getQuery()).intoSet(r -> { - Statistics statistics = new Statistics(); - StatisticsField statisticsField = new StatisticsField(); - statisticsField.setName(r.get(STATISTICS_FIELD.NAME)); - statistics.setStatisticsField(statisticsField); - statistics.setCounter(ofNullable(r.get(ACCUMULATED_STATISTICS, Integer.class)).orElse(0)); - return statistics; - }); - } - - @Override - public Set accumulateStatisticsByFilterNotFromBaseline(Queryable targetFilter, Queryable baselineFilter) { - final QueryBuilder targetBuilder = QueryBuilder.newBuilder(targetFilter, collectJoinFields(targetFilter)); - final QueryBuilder baselineBuilder = QueryBuilder.newBuilder(baselineFilter, collectJoinFields(baselineFilter)); - final SelectQuery contentQuery = getQueryWithBaseline(targetBuilder, baselineBuilder).build(); - - return dsl.fetch(DSL.with(FILTERED_QUERY) - .as(contentQuery) - .select(DSL.sum(STATISTICS.S_COUNTER).as(ACCUMULATED_STATISTICS), STATISTICS_FIELD.NAME) - .from(STATISTICS) - .join(DSL.table(name(FILTERED_QUERY))) - .on(STATISTICS.ITEM_ID.eq(field(name(FILTERED_QUERY, FILTERED_ID), Long.class))) - .join(STATISTICS_FIELD) - .on(STATISTICS.STATISTICS_FIELD_ID.eq(STATISTICS_FIELD.SF_ID)) - .groupBy(STATISTICS_FIELD.NAME) - .getQuery()).intoSet(r -> { - Statistics statistics = new Statistics(); - StatisticsField statisticsField = new StatisticsField(); - statisticsField.setName(r.get(STATISTICS_FIELD.NAME)); - statistics.setStatisticsField(statisticsField); - statistics.setCounter(ofNullable(r.get(ACCUMULATED_STATISTICS, Integer.class)).orElse(0)); - return statistics; - }); - } - - @Override - public Optional findIdByFilter(Queryable filter, Sort sort) { - - final Set joinFields = QueryUtils.collectJoinFields(filter, sort); - - return dsl.select(fieldName(ID)) - .from(QueryBuilder.newBuilder(filter, joinFields).with(sort).with(1).build().asTable(ITEM)) - .fetchOptionalInto(Long.class); - - } - - @Override - public Page findByFilter(boolean isLatest, Queryable launchFilter, Queryable testItemFilter, Pageable launchPageable, - Pageable testItemPageable) { - - Table launchesTable = QueryUtils.createQueryBuilderWithLatestLaunchesOption(launchFilter, - launchPageable.getSort(), - isLatest - ).with(launchPageable).build().asTable(LAUNCHES); - - Set joinFields = QueryUtils.collectJoinFields(testItemFilter, testItemPageable.getSort()); - - return PageableExecutionUtils.getPage(TEST_ITEM_FETCHER.apply(dsl.fetch(QueryBuilder.newBuilder(testItemFilter, joinFields) - .with(testItemPageable) - .addJointToStart(launchesTable, - JoinType.JOIN, - TEST_ITEM.LAUNCH_ID.eq(fieldName(launchesTable.getName(), ID).cast(Long.class)) - ) - .wrap() - .withWrapperSort(testItemPageable.getSort()) - .build())), - testItemPageable, - () -> dsl.fetchCount(QueryBuilder.newBuilder(testItemFilter, joinFields) - .addJointToStart(launchesTable, - JoinType.JOIN, - TEST_ITEM.LAUNCH_ID.eq(fieldName(launchesTable.getName(), ID).cast(Long.class)) - ) - .build()) - ); - } - - @Override - public Page findAllNotFromBaseline(Queryable targetFilter, Queryable baselineFilter, Pageable pageable) { - - final QueryBuilder targetBuilder = QueryBuilder.newBuilder(targetFilter, collectJoinFields(targetFilter, pageable.getSort())); - final QueryBuilder baselineBuilder = QueryBuilder.newBuilder(baselineFilter, collectJoinFields(baselineFilter)); - final SelectQuery contentQuery = getQueryWithBaseline(targetBuilder, baselineBuilder).with(pageable) - .wrap() - .withWrapperSort(pageable.getSort()) - .build(); - - final QueryBuilder targetPagingBuilder = QueryBuilder.newBuilder(targetFilter, collectJoinFields(targetFilter, pageable.getSort())); - final QueryBuilder baselinePagingBuilder = QueryBuilder.newBuilder(baselineFilter, collectJoinFields(baselineFilter)); - final SelectQuery pagingQuery = getQueryWithBaseline(targetPagingBuilder, baselinePagingBuilder).build(); - - return PageableExecutionUtils.getPage(TEST_ITEM_FETCHER.apply(dsl.fetch(contentQuery)), - pageable, - () -> dsl.fetchCount(pagingQuery) - ); - - } - - private QueryBuilder getQueryWithBaseline(QueryBuilder targetBuilder, QueryBuilder baselineBuilder) { - - final SelectQuery baselineQuery = baselineBuilder - .build(); - baselineQuery.addSelect(TEST_ITEM.TEST_CASE_HASH); - final Table baseline = baselineQuery.asTable(BASELINE_TABLE); - - //https://github.com/jOOQ/jOOQ/issues/11238 - final Condition baselineHashIsNull = condition( - "array_agg(baseline.test_case_hash) filter (where baseline.test_case_hash is not null) is null"); - - return targetBuilder - .addJoinToEnd(baseline, - JoinType.LEFT_OUTER_JOIN, - TEST_ITEM.TEST_CASE_HASH.eq(fieldName(baseline.getName(), TEST_ITEM.TEST_CASE_HASH.getName()).cast(Integer.class)) - ) - .addHavingCondition(baselineHashIsNull); - } - - @Override - public Page loadItemsHistoryPage(Queryable filter, Pageable pageable, Long projectId, int historyDepth, - boolean usingHash) { - SelectQuery filteringQuery = QueryBuilder.newBuilder(filter, - QueryUtils.collectJoinFields(filter, pageable.getSort()) - ).with(pageable.getSort()).build(); - Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; - Page historyBaseline = loadHistoryBaseline(filteringQuery, historyGroupingField, LAUNCH.PROJECT_ID.eq(projectId), pageable); - - List itemHistories = historyBaseline.getContent().stream().map(value -> { - List itemIds = loadHistoryItem(getHistoryFilter(filter, usingHash, value), - pageable.getSort(), - LAUNCH.PROJECT_ID.eq(projectId) - ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, historyDepth - 1)).orElseGet(Collections::emptyList); - return new TestItemHistory(value, itemIds); - }).collect(Collectors.toList()); - - return new PageImpl<>(itemHistories, pageable, historyBaseline.getTotalElements()); - - } - - @Override - public Page loadItemsHistoryPage(Queryable filter, Pageable pageable, Long projectId, String launchName, - int historyDepth, boolean usingHash) { - SelectQuery filteringQuery = QueryBuilder.newBuilder(filter, - QueryUtils.collectJoinFields(filter, pageable.getSort()) - ).with(pageable.getSort()).build(); - Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; - Page historyBaseline = loadHistoryBaseline(filteringQuery, - historyGroupingField, - LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)), - pageable - ); - - List itemHistories = historyBaseline.getContent().stream().map(value -> { - List itemIds = loadHistoryItem(getHistoryFilter(filter, usingHash, value), - pageable.getSort(), - LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)) - ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, launchName, historyDepth - 1)) - .orElseGet(Collections::emptyList); - return new TestItemHistory(value, itemIds); - }).collect(Collectors.toList()); - - return new PageImpl<>(itemHistories, pageable, historyBaseline.getTotalElements()); - - } - - @Override - public Page loadItemsHistoryPage(Queryable filter, Pageable pageable, Long projectId, List launchIds, - int historyDepth, boolean usingHash) { - SelectQuery filteringQuery = QueryBuilder.newBuilder(filter, - QueryUtils.collectJoinFields(filter, pageable.getSort()) - ) - .with(pageable.getSort()) - .addCondition(LAUNCH.ID.in(launchIds).and(LAUNCH.PROJECT_ID.eq(projectId))) - .build(); - - Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; - Page historyBaseline = loadHistoryBaseline(filteringQuery, - historyGroupingField, - LAUNCH.ID.in(launchIds).and(LAUNCH.PROJECT_ID.eq(projectId)), - pageable - ); - - List itemHistories = historyBaseline.getContent().stream().map(value -> { - List itemIds = loadHistoryItem(getHistoryFilter(filter, usingHash, value), - pageable.getSort(), - LAUNCH.ID.in(launchIds).and(LAUNCH.PROJECT_ID.eq(projectId)) - ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, historyDepth - 1)).orElseGet(Collections::emptyList); - return new TestItemHistory(value, itemIds); - }).collect(Collectors.toList()); - - return new PageImpl<>(itemHistories, pageable, historyBaseline.getTotalElements()); - - } - - @Override - public Page loadItemsHistoryPage(boolean isLatest, Queryable launchFilter, Queryable testItemFilter, - Pageable launchPageable, Pageable testItemPageable, Long projectId, int historyDepth, boolean usingHash) { - SelectQuery filteringQuery = buildCompositeFilterHistoryQuery(isLatest, - launchFilter, - testItemFilter, - launchPageable, - testItemPageable - ); - - Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; - Page historyBaseline = loadHistoryBaseline(filteringQuery, - historyGroupingField, - LAUNCH.PROJECT_ID.eq(projectId), - testItemPageable - ); - - List itemHistories = historyBaseline.getContent().stream().map(value -> { - List itemIds = loadHistoryItem(getHistoryFilter(testItemFilter, usingHash, value), - testItemPageable.getSort(), - LAUNCH.PROJECT_ID.eq(projectId) - ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, historyDepth - 1)).orElseGet(Collections::emptyList); - return new TestItemHistory(value, itemIds); - }).collect(Collectors.toList()); - - return new PageImpl<>(itemHistories, testItemPageable, historyBaseline.getTotalElements()); - } - - @Override - public Page loadItemsHistoryPage(boolean isLatest, Queryable launchFilter, Queryable testItemFilter, - Pageable launchPageable, Pageable testItemPageable, Long projectId, String launchName, int historyDepth, boolean usingHash) { - SelectQuery filteringQuery = buildCompositeFilterHistoryQuery(isLatest, - launchFilter, - testItemFilter, - launchPageable, - testItemPageable - ); - - Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; - Page historyBaseline = loadHistoryBaseline(filteringQuery, - historyGroupingField, - LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)), - testItemPageable - ); - - List itemHistories = historyBaseline.getContent().stream().map(value -> { - List itemIds = loadHistoryItem(getHistoryFilter(testItemFilter, usingHash, value), - testItemPageable.getSort(), - LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)) - ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, historyDepth - 1)).orElseGet(Collections::emptyList); - return new TestItemHistory(value, itemIds); - }).collect(Collectors.toList()); - - return new PageImpl<>(itemHistories, testItemPageable, historyBaseline.getTotalElements()); - } - - private SelectQuery buildCompositeFilterHistoryQuery(boolean isLatest, Queryable launchFilter, - Queryable testItemFilter, Pageable launchPageable, Pageable testItemPageable) { - Table launchesTable = QueryUtils.createQueryBuilderWithLatestLaunchesOption(launchFilter, - launchPageable.getSort(), - isLatest - ).with(launchPageable).build().asTable(LAUNCHES); - - return QueryBuilder.newBuilder(testItemFilter, QueryUtils.collectJoinFields(testItemFilter, testItemPageable.getSort())) - .with(testItemPageable.getSort()) - .addJointToStart(launchesTable, - JoinType.JOIN, - TEST_ITEM.LAUNCH_ID.eq(fieldName(launchesTable.getName(), ID).cast(Long.class)) - ) - .build(); - } - - private Page loadHistoryBaseline(SelectQuery filteringQuery, Field historyGroupingField, - Condition baselineCondition, Pageable pageable) { - return PageableExecutionUtils.getPage(dsl.with(ITEMS) - .as(filteringQuery) - .select(historyGroupingField) - .from(TEST_ITEM) - .join(ITEMS) - .on(TEST_ITEM.ITEM_ID.eq(fieldName(ITEMS, ID).cast(Long.class))) - .join(LAUNCH) - .on(TEST_ITEM.LAUNCH_ID.eq(LAUNCH.ID)) - .where(baselineCondition) - .and(LAUNCH.MODE.eq(JLaunchModeEnum.DEFAULT)) - .groupBy(historyGroupingField) - .orderBy(max(TEST_ITEM.START_TIME)) - .limit(pageable.getPageSize()) - .offset(retrieveOffsetAndApplyBoundaries(pageable)) - .fetchInto(String.class), - pageable, - () -> dsl.fetchCount(with(ITEMS).as(filteringQuery) - .select(TEST_ITEM.field(historyGroupingField)) - .from(TEST_ITEM) - .join(ITEMS) - .on(TEST_ITEM.ITEM_ID.eq(fieldName(ITEMS, ID).cast(Long.class))) - .groupBy(TEST_ITEM.field(historyGroupingField))) - ); - } - - private Filter getHistoryFilter(Queryable filter, boolean usingHash, String historyValue) { - List commonConditions = filter.getFilterConditions(); - return new Filter(filter.getTarget().getClazz(), Lists.newArrayList()).withConditions(commonConditions) - .withCondition(usingHash ? - FilterCondition.builder().eq(CRITERIA_TEST_CASE_HASH, historyValue).build() : - FilterCondition.builder().eq(CRITERIA_UNIQUE_ID, historyValue).build()) - .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_MODE, LaunchModeEnum.DEFAULT.name()).build()); - } - - private List getHistoryIds(TestItem testItem, boolean usingHash, Long projectId, int historyDepth) { - List historyIds = usingHash ? loadHistory(testItem.getStartTime(), - testItem.getItemId(), - LAUNCH.PROJECT_ID.eq(projectId).and(TEST_ITEM.TEST_CASE_HASH.eq(testItem.getTestCaseHash())), - historyDepth - ) : loadHistory(testItem.getStartTime(), - testItem.getItemId(), - LAUNCH.PROJECT_ID.eq(projectId).and(TEST_ITEM.UNIQUE_ID.eq(testItem.getUniqueId())), - historyDepth - ); - historyIds.add(0, testItem.getItemId()); - return historyIds; - } - - private List getHistoryIds(TestItem testItem, boolean usingHash, Long projectId, String launchName, int historyDepth) { - if (historyDepth > 0) { - List historyIds = usingHash ? loadHistory(testItem.getStartTime(), - testItem.getItemId(), - LAUNCH.PROJECT_ID.eq(projectId) - .and(LAUNCH.NAME.eq(launchName)) - .and(TEST_ITEM.TEST_CASE_HASH.eq(testItem.getTestCaseHash())), - historyDepth - ) : loadHistory(testItem.getStartTime(), - testItem.getItemId(), - LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)).and(TEST_ITEM.UNIQUE_ID.eq(testItem.getUniqueId())), - historyDepth - ); - historyIds.add(0, testItem.getItemId()); - return historyIds; - } - return Lists.newArrayList(testItem.getItemId()); - } - - private Optional loadHistoryItem(Queryable filter, Sort sort, Condition baselineCondition) { - List orders = sort.get().collect(toList()); - orders.add(new Sort.Order(Sort.Direction.DESC, CRITERIA_START_TIME)); - - SelectQuery selectQuery = QueryBuilder.newBuilder(filter, QueryUtils.collectJoinFields(filter, sort)) - .with(Sort.by(orders)) - .with(1) - .build(); - selectQuery.addConditions(baselineCondition); - - return dsl.with(HISTORY) - .as(selectQuery) - .select() - .from(TEST_ITEM) - .join(HISTORY) - .on(TEST_ITEM.ITEM_ID.eq(fieldName(HISTORY, ID).cast(Long.class))) - .fetchInto(TestItem.class) - .stream() - .findFirst(); - } - - private List loadHistory(LocalDateTime startTime, Long itemId, Condition baselineCondition, int historyDepth) { - return dsl.select(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .join(LAUNCH) - .on(TEST_ITEM.LAUNCH_ID.eq(LAUNCH.ID)) - .where(baselineCondition) - .and(TEST_ITEM.ITEM_ID.notEqual(itemId)) - .and(TEST_ITEM.START_TIME.lessOrEqual(Timestamp.valueOf(startTime))) - .and(LAUNCH.MODE.eq(JLaunchModeEnum.DEFAULT)) - .orderBy(TEST_ITEM.START_TIME.desc(), LAUNCH.START_TIME.desc(), LAUNCH.NUMBER.desc()) - .limit(historyDepth) - .fetchInto(Long.class); - } - - @Override - public List selectAllDescendants(Long itemId) { - return commonTestItemDslSelect().where(TEST_ITEM.PARENT_ID.eq(itemId)).fetch(TEST_ITEM_RECORD_MAPPER); - } - - @Override - public List selectAllDescendantsWithChildren(Long itemId) { - JTestItem childTestItem = JTestItem.TEST_ITEM.as("cti"); - return commonTestItemDslSelect().where(TEST_ITEM.PARENT_ID.eq(itemId)) - .and(DSL.exists(DSL.selectOne() - .from(TEST_ITEM) - .join(childTestItem) - .on(TEST_ITEM.ITEM_ID.eq(childTestItem.PARENT_ID)) - .where(TEST_ITEM.PARENT_ID.eq(itemId)))) - .fetch(TEST_ITEM_RECORD_MAPPER); - } - - @Override - public List findTestItemIdsByLaunchId(Long launchId, Pageable pageable) { - JTestItem retryParent = TEST_ITEM.as(RETRY_PARENT); - return dsl.select(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .leftJoin(retryParent) - .on(TEST_ITEM.RETRY_OF.eq(retryParent.ITEM_ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId).or(retryParent.LAUNCH_ID.eq(launchId))) - .orderBy(TEST_ITEM.ITEM_ID) - .limit(pageable.getPageSize()) - .offset(retrieveOffsetAndApplyBoundaries(pageable)) - .fetchInto(Long.class); - } - - @Override - public List selectItemsInStatusByLaunch(Long launchId, StatusEnum... statuses) { - List jStatuses = Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); - return commonTestItemDslSelect().where(TEST_ITEM.LAUNCH_ID.eq(launchId).and(TEST_ITEM_RESULTS.STATUS.in(jStatuses))) - .fetch(TEST_ITEM_RECORD_MAPPER); - } - - @Override - public List selectItemsInStatusByParent(Long itemId, StatusEnum... statuses) { - List jStatuses = Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); - return commonTestItemDslSelect().where(TEST_ITEM.PARENT_ID.eq(itemId).and(TEST_ITEM_RESULTS.STATUS.in(jStatuses))) - .fetch(TEST_ITEM_RECORD_MAPPER); - } - - @Override - public Boolean hasItemsInStatusByLaunch(Long launchId, StatusEnum... statuses) { - List jStatuses = Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); - return dsl.fetchExists(dsl.selectOne() - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .onKey() - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .and(TEST_ITEM_RESULTS.STATUS.in(jStatuses)) - .limit(1)); - } - - @Override - public List findAllNotInIssueByLaunch(Long launchId, String locator) { - return commonTestItemDslSelect().join(ISSUE) - .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE_TYPE) - .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .and(ISSUE_TYPE.LOCATOR.ne(locator)) - .fetch(TEST_ITEM_RECORD_MAPPER); - } - - @Override - public List selectIdsNotInIssueByLaunch(Long launchId, String locator) { - return dsl.select(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE) - .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE_TYPE) - .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .and(ISSUE_TYPE.LOCATOR.ne(locator)) - .fetchInto(Long.class); - } - - @Override - public List findAllNotInIssueGroupByLaunch(Long launchId, TestItemIssueGroup issueGroup) { - return dsl.select() - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE) - .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE_TYPE) - .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) - .join(ISSUE_GROUP) - .on(ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId).and(ISSUE_GROUP.ISSUE_GROUP_.ne(JIssueGroupEnum.valueOf(issueGroup.getValue())))) - .fetch(TEST_ITEM_RECORD_MAPPER); - - } - - @Override - public List selectIdsNotInIssueGroupByLaunch(Long launchId, TestItemIssueGroup issueGroup) { - return dsl.select(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE) - .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE_TYPE) - .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) - .join(ISSUE_GROUP) - .on(ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId).and(ISSUE_GROUP.ISSUE_GROUP_.ne(JIssueGroupEnum.valueOf(issueGroup.getValue())))) - .fetchInto(Long.class); - } - - @Override - public List findAllInIssueGroupByLaunch(Long launchId, TestItemIssueGroup issueGroup) { - return dsl.select() - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE) - .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE_TYPE) - .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) - .join(ISSUE_GROUP) - .on(ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId).and(ISSUE_GROUP.ISSUE_GROUP_.eq(JIssueGroupEnum.valueOf(issueGroup.getValue())))) - .fetch(TEST_ITEM_RECORD_MAPPER); - } - - @Override - public List selectIdsWithIssueByLaunch(Long launchId) { - return dsl.select(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE) - .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .fetchInto(Long.class); - } - - @Override - public Boolean hasItemsInStatusAddedLately(Long launchId, Duration period, StatusEnum... statuses) { - List jStatuses = Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); - return dsl.fetchExists(dsl.selectOne() - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .onKey() - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .and(TEST_ITEM_RESULTS.STATUS.in(jStatuses)) - .and(TEST_ITEM.START_TIME.gt(TimestampUtils.getTimestampBackFromNow(period))) - .limit(1)); - } - - @Override - public Boolean hasLogs(Long launchId, Duration period, StatusEnum... statuses) { - List jStatuses = Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); - return dsl.fetchExists(dsl.selectOne() - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .onKey() - .join(LOG) - .on(TEST_ITEM.ITEM_ID.eq(LOG.ITEM_ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .and(TEST_ITEM_RESULTS.STATUS.in(jStatuses)) - .and(TEST_ITEM.START_TIME.lt(TimestampUtils.getTimestampBackFromNow(period))) - .limit(1)); - } - - @Override - public List selectItemsInIssueByLaunch(Long launchId, String issueType) { - return commonTestItemDslSelect().join(ISSUE) - .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE_TYPE) - .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .and(ISSUE_TYPE.LOCATOR.eq(issueType)) - .fetch(TEST_ITEM_RECORD_MAPPER::map); - } - - @Override - public List selectRetries(List retryOfIds) { - return TEST_ITEM_RETRY_FETCHER.apply(dsl.select() - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .leftJoin(PARAMETER) - .on(TEST_ITEM.ITEM_ID.eq(PARAMETER.ITEM_ID)) - .where(TEST_ITEM.RETRY_OF.in(retryOfIds)) - .and(TEST_ITEM.LAUNCH_ID.isNull()) - .orderBy(TEST_ITEM.START_TIME) - .fetch()); - } - - @Override - public List selectIssueLocatorsByProject(Long projectId) { - return dsl.select() - .from(PROJECT) - .join(ISSUE_TYPE_PROJECT) - .on(PROJECT.ID.eq(ISSUE_TYPE_PROJECT.PROJECT_ID)) - .join(ISSUE_TYPE) - .on(ISSUE_TYPE_PROJECT.ISSUE_TYPE_ID.eq(ISSUE_TYPE.ID)) - .join(ISSUE_GROUP) - .on(Tables.ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) - .where(PROJECT.ID.eq(projectId)) - .fetch(ISSUE_TYPE_RECORD_MAPPER); - } - - @Override - public Optional selectIssueTypeByLocator(Long projectId, String locator) { - return ofNullable(dsl.select() - .from(ISSUE_TYPE) - .join(ISSUE_TYPE_PROJECT) - .on(ISSUE_TYPE_PROJECT.ISSUE_TYPE_ID.eq(ISSUE_TYPE.ID)) - .join(ISSUE_GROUP) - .on(ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) - .where(ISSUE_TYPE_PROJECT.PROJECT_ID.eq(projectId)) - .and(ISSUE_TYPE.LOCATOR.eq(locator)) - .fetchOne(ISSUE_TYPE_RECORD_MAPPER)); - } - - @Override - public Optional> selectPath(String uuid) { - return dsl.select(TEST_ITEM.ITEM_ID, TEST_ITEM.PATH) - .from(TEST_ITEM) - .where(TEST_ITEM.UUID.eq(uuid)) - .fetchOptional(r -> Pair.of(r.get(TEST_ITEM.ITEM_ID), r.get(TEST_ITEM.PATH, String.class))); - } - - /** - * {@link Log} entities are searched from the whole tree under - * {@link TestItem} that matched to the provided `launchId` and `autoAnalyzed` conditions - */ - @Override - public List selectIdsByAnalyzedWithLevelGte(boolean autoAnalyzed, boolean ignoreAnalyzer, Long launchId, int logLevel) { - - JTestItem outerItemTable = TEST_ITEM.as(OUTER_ITEM_TABLE); - JTestItem nestedItemTable = TEST_ITEM.as(NESTED); - - final Condition issueCondition = ISSUE.AUTO_ANALYZED.eq(autoAnalyzed).and(ISSUE.IGNORE_ANALYZER.eq(ignoreAnalyzer)); - - return dsl.selectDistinct(fieldName(ID)) - .from(DSL.select(outerItemTable.ITEM_ID.as(ID)) - .from(outerItemTable) - .join(TEST_ITEM_RESULTS) - .on(outerItemTable.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE) - .on(TEST_ITEM_RESULTS.RESULT_ID.eq(ISSUE.ISSUE_ID)) - .where(outerItemTable.LAUNCH_ID.eq(launchId)) - .and(outerItemTable.HAS_STATS) - .andNot(outerItemTable.HAS_CHILDREN) - .and(issueCondition) - .and(DSL.exists(DSL.selectOne() - .from(nestedItemTable) - .join(LOG) - .on(nestedItemTable.ITEM_ID.eq(LOG.ITEM_ID)) - .where(nestedItemTable.LAUNCH_ID.eq(launchId)) - .andNot(nestedItemTable.HAS_STATS) - .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) - .and(DSL.sql(outerItemTable.PATH + " @> " + nestedItemTable.PATH)))) - .unionAll(DSL.selectDistinct(TEST_ITEM.ITEM_ID.as(ID)) - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE) - .on(TEST_ITEM_RESULTS.RESULT_ID.eq(ISSUE.ISSUE_ID)) - .join(LOG) - .on(TEST_ITEM.ITEM_ID.eq(LOG.ITEM_ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .and(issueCondition) - .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel))) - .asTable(ITEM)) - .fetchInto(Long.class); - } - - @Override - public int updateStatusAndEndTimeById(Long itemId, JStatusEnum status, LocalDateTime endTime) { - - return dsl.update(TEST_ITEM_RESULTS) - .set(TEST_ITEM_RESULTS.STATUS, status) - .set(TEST_ITEM_RESULTS.END_TIME, Timestamp.valueOf(endTime)) - .set(TEST_ITEM_RESULTS.DURATION, - dsl.select(DSL.extract(endTime, DatePart.EPOCH) - .minus(DSL.extract(TEST_ITEM.START_TIME, DatePart.EPOCH)) - .cast(Double.class)).from(TEST_ITEM).where(TEST_ITEM.ITEM_ID.eq(itemId)) - ) - .where(TEST_ITEM_RESULTS.RESULT_ID.eq(itemId)) - .execute(); - } - - @Override - public int updateStatusAndEndTimeByRetryOfId(Long retryOfId, JStatusEnum from, JStatusEnum to, LocalDateTime endTime) { - return dsl.update(TEST_ITEM_RESULTS) - .set(TEST_ITEM_RESULTS.STATUS, to) - .set(TEST_ITEM_RESULTS.END_TIME, Timestamp.valueOf(endTime)) - .set(TEST_ITEM_RESULTS.DURATION, - dsl.select(DSL.extract(endTime, DatePart.EPOCH) - .minus(DSL.extract(TEST_ITEM.START_TIME, DatePart.EPOCH)) - .cast(Double.class)).from(TEST_ITEM).where(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - ) - .where(TEST_ITEM_RESULTS.RESULT_ID.in(DSL.select(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .where(TEST_ITEM.RETRY_OF.eq(retryOfId)))) - .and(TEST_ITEM_RESULTS.STATUS.eq(from)) - .execute(); - } - - @Override - public TestItemTypeEnum getTypeByItemId(Long itemId) { - return dsl.select(TEST_ITEM.TYPE).from(TEST_ITEM).where(TEST_ITEM.ITEM_ID.eq(itemId)).fetchOneInto(TestItemTypeEnum.class); - } - - @Override - public List selectIdsByFilter(Long launchId, Queryable filter, int limit, int offset) { - final SelectQuery selectQuery = QueryBuilder.newBuilder(filter, QueryUtils.collectJoinFields(filter)) - .with(limit) - .withOffset(offset) - .with(Sort.by(Sort.Order.asc(CRITERIA_ID))) - .build(); - selectQuery.addConditions(TEST_ITEM.LAUNCH_ID.eq(launchId)); - return dsl.select(fieldName(ITEMS, ID)).from(selectQuery.asTable(ITEMS)).fetchInto(Long.class); - } - - @Override - public List selectIdsByHasDescendants(Collection itemIds) { - final JTestItem parent = TEST_ITEM.as(OUTER_ITEM_TABLE); - final JTestItem child = TEST_ITEM.as(CHILD_ITEM_TABLE); - return dsl.select(parent.ITEM_ID) - .from(parent) - .join(child) - .on(parent.ITEM_ID.eq(child.PARENT_ID)) - .where(parent.ITEM_ID.in(itemIds)) - .groupBy(parent.ITEM_ID) - .fetchInto(Long.class); - } - - @Override - public List selectIdsByStringLogMessage(Collection itemIds, Integer logLevel, String pattern) { - return dsl.selectDistinct(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .join(LOG) - .on(TEST_ITEM.ITEM_ID.eq(LOG.ITEM_ID)) - .where(TEST_ITEM.ITEM_ID.in(itemIds)) - .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) - .and(LOG.LOG_MESSAGE.like("%" + DSL.escape(pattern, '\\') + "%")) - .fetchInto(Long.class); - } - - @Override - public List selectIdsByRegexLogMessage(Collection itemIds, Integer logLevel, String pattern) { - return dsl.selectDistinct(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .join(LOG) - .on(TEST_ITEM.ITEM_ID.eq(LOG.ITEM_ID)) - .where(TEST_ITEM.ITEM_ID.in(itemIds)) - .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) - .and(LOG.LOG_MESSAGE.likeRegex(pattern)) - .fetchInto(Long.class); - } - - @Override - public List selectIdsUnderByStringLogMessage(Long launchId, Collection itemIds, Integer logLevel, String pattern) { - final JTestItem child = TEST_ITEM.as(CHILD_ITEM_TABLE); - - return dsl.selectDistinct(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .join(child) - .on(TEST_ITEM.PATH + " @> " + child.PATH) - .and(TEST_ITEM.ITEM_ID.notEqual(child.ITEM_ID)) - .join(LOG) - .on(child.ITEM_ID.eq(LOG.ITEM_ID)) - .where(TEST_ITEM.ITEM_ID.in(itemIds)) - .and(child.LAUNCH_ID.eq(launchId)) - .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) - .and(LOG.LOG_MESSAGE.like("%" + DSL.escape(pattern, '\\') + "%")) - .groupBy(TEST_ITEM.ITEM_ID) - .fetchInto(Long.class); - } - - @Override - public List selectIdsUnderByRegexLogMessage(Long launchId, Collection itemIds, Integer logLevel, String pattern) { - final JTestItem child = TEST_ITEM.as(CHILD_ITEM_TABLE); - - return dsl.selectDistinct(TEST_ITEM.ITEM_ID) - .from(TEST_ITEM) - .join(child) - .on(TEST_ITEM.PATH + " @> " + child.PATH) - .and(TEST_ITEM.ITEM_ID.notEqual(child.ITEM_ID)) - .join(LOG) - .on(child.ITEM_ID.eq(LOG.ITEM_ID)) - .where(TEST_ITEM.ITEM_ID.in(itemIds)) - .and(child.LAUNCH_ID.eq(launchId)) - .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) - .and(LOG.LOG_MESSAGE.likeRegex(pattern)) - .groupBy(TEST_ITEM.ITEM_ID) - .fetchInto(Long.class); - } - - /** - * Commons select of an item with it's results and structure - * - * @return Select condition step - */ - private SelectOnConditionStep commonTestItemDslSelect() { - return dsl.select().from(TEST_ITEM).join(TEST_ITEM_RESULTS).on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)); - } - - @Override - public List findByFilter(Queryable filter) { - return TEST_ITEM_FETCHER.apply(dsl.fetch(QueryBuilder.newBuilder(filter, QueryUtils.collectJoinFields(filter)).wrap().build())); - } - - @Override - public Page findByFilter(Queryable filter, Pageable pageable) { - - Set joinFields = QueryUtils.collectJoinFields(filter, pageable.getSort()); - List items = TEST_ITEM_FETCHER.apply(dsl.fetch(QueryBuilder.newBuilder(filter, joinFields) - .with(pageable) - .wrap() - .withWrapperSort(pageable.getSort()) - .build())); - - return PageableExecutionUtils.getPage(items, pageable, () -> dsl.fetchCount(QueryBuilder.newBuilder(filter, joinFields).build())); - } - - @Override - public List findAllNestedStepsByIds(Collection ids, Queryable logFilter, boolean excludePassedLogs) { - JTestItem nested = TEST_ITEM.as(NESTED); - SelectQuery logsSelectQuery = QueryBuilder.newBuilder(logFilter, QueryUtils.collectJoinFields(logFilter)).build(); - - return dsl.select(TEST_ITEM.ITEM_ID, - TEST_ITEM.NAME, - TEST_ITEM.UUID, - TEST_ITEM.START_TIME, - TEST_ITEM.TYPE, - TEST_ITEM_RESULTS.STATUS, - TEST_ITEM_RESULTS.END_TIME, - TEST_ITEM_RESULTS.DURATION, - DSL.field(hasContentQuery(nested, logsSelectQuery, excludePassedLogs)).as(HAS_CONTENT), - DSL.field(dsl.with(LOGS) - .as(logsSelectQuery) - .selectCount() - .from(LOG) - .join(nested) - .on(LOG.ITEM_ID.eq(nested.ITEM_ID)) - .join(LOGS) - .on(LOG.ID.eq(fieldName(LOGS, ID).cast(Long.class))) - .join(ATTACHMENT) - .on(LOG.ATTACHMENT_ID.eq(ATTACHMENT.ID)) - .where(nested.HAS_STATS.isFalse() - .and(DSL.sql(fieldName(NESTED, TEST_ITEM.PATH.getName()) + " <@ cast(? AS LTREE)", TEST_ITEM.PATH)))) - .as(ATTACHMENTS_COUNT) - ) - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .where(TEST_ITEM.ITEM_ID.in(ids)) - .fetch(NESTED_STEP_RECORD_MAPPER); - } - - @Override - public List findIndexTestItemByLaunchId(Long launchId, Collection itemTypes) { - return dsl.select(TEST_ITEM.ITEM_ID, - TEST_ITEM.NAME, - TEST_ITEM.START_TIME, - TEST_ITEM.UNIQUE_ID, - TEST_ITEM.TEST_CASE_HASH, - ISSUE.AUTO_ANALYZED, - ISSUE_TYPE.LOCATOR - ) - .from(TEST_ITEM) - .join(TEST_ITEM_RESULTS) - .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .join(ISSUE) - .on(TEST_ITEM_RESULTS.RESULT_ID.eq(ISSUE.ISSUE_ID)) - .join(ISSUE_TYPE) - .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) - .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) - .and(TEST_ITEM.TYPE.in(itemTypes)) - .and(ISSUE.IGNORE_ANALYZER.isFalse()) - .fetch(INDEX_TEST_ITEM_RECORD_MAPPER); - - } - - private Condition hasContentQuery(JTestItem nested, SelectQuery logsSelectQuery, boolean excludePassedLogs) { - if (excludePassedLogs) { - return DSL.exists(dsl.with(LOGS) - .as(logsSelectQuery) - .select() - .from(LOG) - .join(LOGS) - .on(LOG.ID.eq(fieldName(LOGS, ID).cast(Long.class))) - .join(TEST_ITEM_RESULTS) - .on(LOG.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) - .where(LOG.ITEM_ID.eq(TEST_ITEM.ITEM_ID))) - .and(TEST_ITEM_RESULTS.STATUS.notIn(JStatusEnum.PASSED, JStatusEnum.INFO, JStatusEnum.WARN)); - } else { - return DSL.exists(dsl.with(LOGS) - .as(logsSelectQuery) - .select() - .from(LOG) - .join(LOGS) - .on(LOG.ID.eq(fieldName(LOGS, ID).cast(Long.class))) - .where(LOG.ITEM_ID.eq(TEST_ITEM.ITEM_ID))) - .orExists(dsl.select().from(nested).where(nested.PARENT_ID.eq(TEST_ITEM.ITEM_ID).and(nested.HAS_STATS.isFalse()))); - } - } - - /** - * @return Map - */ - @Override - public Map selectPathNames(Collection testItems) { - if (CollectionUtils.isEmpty(testItems)) return new HashMap<>(); - - // Item ids for search - Set testItemIds = new HashSet<>(); - // Structure for creating return object - Map> testItemWithPathIds = new HashMap<>(); - - for (TestItem testItem : testItems) { - String path = testItem.getPath(); - // For normal case is redundant, but not sure for current situation, better to check - // and skip testItem without path, cause of incorrect state. - if (Strings.isBlank(path)) { - continue; - } - String[] pathIds = path.split("\\."); - Arrays.asList(pathIds).forEach( - pathItemId -> { - long itemIdFromPath = Long.parseLong(pathItemId); - testItemIds.add(itemIdFromPath); - - List itemPaths = testItemWithPathIds.getOrDefault(testItem.getItemId(), new ArrayList<>()); - itemPaths.add(itemIdFromPath); - testItemWithPathIds.put(testItem.getItemId(), itemPaths); - } - ); - } - - Map> resultMap = new HashMap<>(); - // Convert database data to more useful form - getTestItemAndLaunchIdName(testItemIds).forEach(record -> resultMap.put( - record.get(fieldName("item_id"), Long.class), record - )); - - Map testItemPathNames = new HashMap<>(); - testItemWithPathIds.forEach((testItemId, pathIds) -> { - var record = resultMap.get(testItemId); - if (record == null) { - return; - } - - LaunchPathName launchPathName = new LaunchPathName( - record.get(fieldName("launch_name"), String.class), - record.get(fieldName("number"), Integer.class) - ); - - List itemPathNames = new ArrayList<>(); - pathIds.forEach(pathItemId -> { - // Base testItem don't add - if (!testItemId.equals(pathItemId) && resultMap.containsKey(pathItemId)) { - var record2 = resultMap.get(pathItemId); - String pathItemName = record2.get(fieldName("name"), String.class); - itemPathNames.add(new ItemPathName(pathItemId, pathItemName)); - } - }); - PathName pathName = new PathName(launchPathName, itemPathNames); - testItemPathNames.put(testItemId, pathName); - }); - - - return testItemPathNames; - } - - /** - * @param testItemIds Collection - * @return Result> - */ - private Result> getTestItemAndLaunchIdName(Collection testItemIds) { - return dsl.select(TEST_ITEM.ITEM_ID, TEST_ITEM.NAME, LAUNCH.NUMBER, LAUNCH.NAME.as("launch_name")) - .from(TEST_ITEM) - .join(LAUNCH) - .on(TEST_ITEM.LAUNCH_ID.eq(LAUNCH.ID)) - .where(TEST_ITEM.ITEM_ID.in(testItemIds)) - .fetch(); - } + private static final String OUTER_ITEM_TABLE = "outer_item_table"; + private static final String INNER_ITEM_TABLE = "inner_item_table"; + private static final String TEST_CASE_ID_TABLE = "test_case_id_table"; + private static final String RESULT_OUTER_TABLE = "resultOuterTable"; + private static final String LATERAL_TABLE = "lateralTable"; + private static final String RESULT_INNER_TABLE = "resultInnerTable"; + + private static final String CHILD_ITEM_TABLE = "child"; + + private static final String BASELINE_TABLE = "baseline"; + + private static final String ITEM_START_TIME = "itemStartTime"; + private static final String LAUNCH_START_TIME = "launchStartTime"; + private static final String ACCUMULATED_STATISTICS = "accumulated_statistics"; + + private DSLContext dsl; + + @Autowired + public void setDsl(DSLContext dsl) { + this.dsl = dsl; + } + + @Override + public Set accumulateStatisticsByFilter(Queryable filter) { + return dsl.fetch(DSL.with(FILTERED_QUERY) + .as(QueryBuilder.newBuilder(filter, QueryUtils.collectJoinFields(filter)).build()) + .select(DSL.sum(STATISTICS.S_COUNTER).as(ACCUMULATED_STATISTICS), STATISTICS_FIELD.NAME) + .from(STATISTICS) + .join(DSL.table(name(FILTERED_QUERY))) + .on(STATISTICS.ITEM_ID.eq(field(name(FILTERED_QUERY, FILTERED_ID), Long.class))) + .join(STATISTICS_FIELD) + .on(STATISTICS.STATISTICS_FIELD_ID.eq(STATISTICS_FIELD.SF_ID)) + .groupBy(STATISTICS_FIELD.NAME) + .getQuery()).intoSet(r -> { + Statistics statistics = new Statistics(); + StatisticsField statisticsField = new StatisticsField(); + statisticsField.setName(r.get(STATISTICS_FIELD.NAME)); + statistics.setStatisticsField(statisticsField); + statistics.setCounter(ofNullable(r.get(ACCUMULATED_STATISTICS, Integer.class)).orElse(0)); + return statistics; + }); + } + + @Override + public Set accumulateStatisticsByFilterNotFromBaseline(Queryable targetFilter, + Queryable baselineFilter) { + final QueryBuilder targetBuilder = + QueryBuilder.newBuilder(targetFilter, collectJoinFields(targetFilter)); + final QueryBuilder baselineBuilder = + QueryBuilder.newBuilder(baselineFilter, collectJoinFields(baselineFilter)); + final SelectQuery contentQuery = + getQueryWithBaseline(targetBuilder, baselineBuilder).build(); + + return dsl.fetch(DSL.with(FILTERED_QUERY) + .as(contentQuery) + .select(DSL.sum(STATISTICS.S_COUNTER).as(ACCUMULATED_STATISTICS), STATISTICS_FIELD.NAME) + .from(STATISTICS) + .join(DSL.table(name(FILTERED_QUERY))) + .on(STATISTICS.ITEM_ID.eq(field(name(FILTERED_QUERY, FILTERED_ID), Long.class))) + .join(STATISTICS_FIELD) + .on(STATISTICS.STATISTICS_FIELD_ID.eq(STATISTICS_FIELD.SF_ID)) + .groupBy(STATISTICS_FIELD.NAME) + .getQuery()).intoSet(r -> { + Statistics statistics = new Statistics(); + StatisticsField statisticsField = new StatisticsField(); + statisticsField.setName(r.get(STATISTICS_FIELD.NAME)); + statistics.setStatisticsField(statisticsField); + statistics.setCounter(ofNullable(r.get(ACCUMULATED_STATISTICS, Integer.class)).orElse(0)); + return statistics; + }); + } + + @Override + public Optional findIdByFilter(Queryable filter, Sort sort) { + + final Set joinFields = QueryUtils.collectJoinFields(filter, sort); + + return dsl.select(fieldName(ID)) + .from(QueryBuilder.newBuilder(filter, joinFields).with(sort).with(1).build().asTable(ITEM)) + .fetchOptionalInto(Long.class); + + } + + @Override + public Page findByFilter(boolean isLatest, Queryable launchFilter, + Queryable testItemFilter, Pageable launchPageable, + Pageable testItemPageable) { + + Table launchesTable = + QueryUtils.createQueryBuilderWithLatestLaunchesOption(launchFilter, + launchPageable.getSort(), + isLatest + ).with(launchPageable).build().asTable(LAUNCHES); + + Set joinFields = + QueryUtils.collectJoinFields(testItemFilter, testItemPageable.getSort()); + + return PageableExecutionUtils.getPage( + TEST_ITEM_FETCHER.apply(dsl.fetch(QueryBuilder.newBuilder(testItemFilter, joinFields) + .with(testItemPageable) + .addJointToStart(launchesTable, + JoinType.JOIN, + TEST_ITEM.LAUNCH_ID.eq(fieldName(launchesTable.getName(), ID).cast(Long.class)) + ) + .wrap() + .withWrapperSort(testItemPageable.getSort()) + .build())), + testItemPageable, + () -> dsl.fetchCount(QueryBuilder.newBuilder(testItemFilter, joinFields) + .addJointToStart(launchesTable, + JoinType.JOIN, + TEST_ITEM.LAUNCH_ID.eq(fieldName(launchesTable.getName(), ID).cast(Long.class)) + ) + .build()) + ); + } + + @Override + public Page findAllNotFromBaseline(Queryable targetFilter, Queryable baselineFilter, + Pageable pageable) { + + final QueryBuilder targetBuilder = + QueryBuilder.newBuilder(targetFilter, collectJoinFields(targetFilter, pageable.getSort())); + final QueryBuilder baselineBuilder = + QueryBuilder.newBuilder(baselineFilter, collectJoinFields(baselineFilter)); + final SelectQuery contentQuery = + getQueryWithBaseline(targetBuilder, baselineBuilder).with(pageable) + .wrap() + .withWrapperSort(pageable.getSort()) + .build(); + + final QueryBuilder targetPagingBuilder = + QueryBuilder.newBuilder(targetFilter, collectJoinFields(targetFilter, pageable.getSort())); + final QueryBuilder baselinePagingBuilder = + QueryBuilder.newBuilder(baselineFilter, collectJoinFields(baselineFilter)); + final SelectQuery pagingQuery = + getQueryWithBaseline(targetPagingBuilder, baselinePagingBuilder).build(); + + return PageableExecutionUtils.getPage(TEST_ITEM_FETCHER.apply(dsl.fetch(contentQuery)), + pageable, + () -> dsl.fetchCount(pagingQuery) + ); + + } + + private QueryBuilder getQueryWithBaseline(QueryBuilder targetBuilder, + QueryBuilder baselineBuilder) { + + final SelectQuery baselineQuery = baselineBuilder + .build(); + baselineQuery.addSelect(TEST_ITEM.TEST_CASE_HASH); + final Table baseline = baselineQuery.asTable(BASELINE_TABLE); + + //https://github.com/jOOQ/jOOQ/issues/11238 + final Condition baselineHashIsNull = condition( + "array_agg(baseline.test_case_hash) filter (where baseline.test_case_hash is not null) is null"); + + return targetBuilder + .addJoinToEnd(baseline, + JoinType.LEFT_OUTER_JOIN, + TEST_ITEM.TEST_CASE_HASH.eq( + fieldName(baseline.getName(), TEST_ITEM.TEST_CASE_HASH.getName()).cast( + Integer.class)) + ) + .addHavingCondition(baselineHashIsNull); + } + + @Override + public Page loadItemsHistoryPage(Queryable filter, Pageable pageable, + Long projectId, int historyDepth, + boolean usingHash) { + SelectQuery filteringQuery = QueryBuilder.newBuilder(filter, + QueryUtils.collectJoinFields(filter, pageable.getSort()) + ).with(pageable.getSort()).build(); + Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; + Page historyBaseline = + loadHistoryBaseline(filteringQuery, historyGroupingField, LAUNCH.PROJECT_ID.eq(projectId), + pageable); + + List itemHistories = historyBaseline.getContent().stream().map(value -> { + List itemIds = loadHistoryItem(getHistoryFilter(filter, usingHash, value), + pageable.getSort(), + LAUNCH.PROJECT_ID.eq(projectId) + ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, historyDepth - 1)) + .orElseGet(Collections::emptyList); + return new TestItemHistory(value, itemIds); + }).collect(Collectors.toList()); + + return new PageImpl<>(itemHistories, pageable, historyBaseline.getTotalElements()); + + } + + @Override + public Page loadItemsHistoryPage(Queryable filter, Pageable pageable, + Long projectId, String launchName, + int historyDepth, boolean usingHash) { + SelectQuery filteringQuery = QueryBuilder.newBuilder(filter, + QueryUtils.collectJoinFields(filter, pageable.getSort()) + ).with(pageable.getSort()).build(); + Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; + Page historyBaseline = loadHistoryBaseline(filteringQuery, + historyGroupingField, + LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)), + pageable + ); + + List itemHistories = historyBaseline.getContent().stream().map(value -> { + List itemIds = loadHistoryItem(getHistoryFilter(filter, usingHash, value), + pageable.getSort(), + LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)) + ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, launchName, historyDepth - 1)) + .orElseGet(Collections::emptyList); + return new TestItemHistory(value, itemIds); + }).collect(Collectors.toList()); + + return new PageImpl<>(itemHistories, pageable, historyBaseline.getTotalElements()); + + } + + @Override + public Page loadItemsHistoryPage(Queryable filter, Pageable pageable, + Long projectId, List launchIds, + int historyDepth, boolean usingHash) { + SelectQuery filteringQuery = QueryBuilder.newBuilder(filter, + QueryUtils.collectJoinFields(filter, pageable.getSort()) + ) + .with(pageable.getSort()) + .addCondition(LAUNCH.ID.in(launchIds).and(LAUNCH.PROJECT_ID.eq(projectId))) + .build(); + + Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; + Page historyBaseline = loadHistoryBaseline(filteringQuery, + historyGroupingField, + LAUNCH.ID.in(launchIds).and(LAUNCH.PROJECT_ID.eq(projectId)), + pageable + ); + + List itemHistories = historyBaseline.getContent().stream().map(value -> { + List itemIds = loadHistoryItem(getHistoryFilter(filter, usingHash, value), + pageable.getSort(), + LAUNCH.ID.in(launchIds).and(LAUNCH.PROJECT_ID.eq(projectId)) + ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, historyDepth - 1)) + .orElseGet(Collections::emptyList); + return new TestItemHistory(value, itemIds); + }).collect(Collectors.toList()); + + return new PageImpl<>(itemHistories, pageable, historyBaseline.getTotalElements()); + + } + + @Override + public Page loadItemsHistoryPage(boolean isLatest, Queryable launchFilter, + Queryable testItemFilter, + Pageable launchPageable, Pageable testItemPageable, Long projectId, int historyDepth, + boolean usingHash) { + SelectQuery filteringQuery = buildCompositeFilterHistoryQuery(isLatest, + launchFilter, + testItemFilter, + launchPageable, + testItemPageable + ); + + Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; + Page historyBaseline = loadHistoryBaseline(filteringQuery, + historyGroupingField, + LAUNCH.PROJECT_ID.eq(projectId), + testItemPageable + ); + + List itemHistories = historyBaseline.getContent().stream().map(value -> { + List itemIds = loadHistoryItem(getHistoryFilter(testItemFilter, usingHash, value), + testItemPageable.getSort(), + LAUNCH.PROJECT_ID.eq(projectId) + ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, historyDepth - 1)) + .orElseGet(Collections::emptyList); + return new TestItemHistory(value, itemIds); + }).collect(Collectors.toList()); + + return new PageImpl<>(itemHistories, testItemPageable, historyBaseline.getTotalElements()); + } + + @Override + public Page loadItemsHistoryPage(boolean isLatest, Queryable launchFilter, + Queryable testItemFilter, + Pageable launchPageable, Pageable testItemPageable, Long projectId, String launchName, + int historyDepth, boolean usingHash) { + SelectQuery filteringQuery = buildCompositeFilterHistoryQuery(isLatest, + launchFilter, + testItemFilter, + launchPageable, + testItemPageable + ); + + Field historyGroupingField = usingHash ? TEST_ITEM.TEST_CASE_HASH : TEST_ITEM.UNIQUE_ID; + Page historyBaseline = loadHistoryBaseline(filteringQuery, + historyGroupingField, + LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)), + testItemPageable + ); + + List itemHistories = historyBaseline.getContent().stream().map(value -> { + List itemIds = loadHistoryItem(getHistoryFilter(testItemFilter, usingHash, value), + testItemPageable.getSort(), + LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)) + ).map(testItem -> getHistoryIds(testItem, usingHash, projectId, historyDepth - 1)) + .orElseGet(Collections::emptyList); + return new TestItemHistory(value, itemIds); + }).collect(Collectors.toList()); + + return new PageImpl<>(itemHistories, testItemPageable, historyBaseline.getTotalElements()); + } + + private SelectQuery buildCompositeFilterHistoryQuery(boolean isLatest, + Queryable launchFilter, + Queryable testItemFilter, Pageable launchPageable, Pageable testItemPageable) { + Table launchesTable = + QueryUtils.createQueryBuilderWithLatestLaunchesOption(launchFilter, + launchPageable.getSort(), + isLatest + ).with(launchPageable).build().asTable(LAUNCHES); + + return QueryBuilder.newBuilder(testItemFilter, + QueryUtils.collectJoinFields(testItemFilter, testItemPageable.getSort())) + .with(testItemPageable.getSort()) + .addJointToStart(launchesTable, + JoinType.JOIN, + TEST_ITEM.LAUNCH_ID.eq(fieldName(launchesTable.getName(), ID).cast(Long.class)) + ) + .build(); + } + + private Page loadHistoryBaseline(SelectQuery filteringQuery, + Field historyGroupingField, + Condition baselineCondition, Pageable pageable) { + return PageableExecutionUtils.getPage(dsl.with(ITEMS) + .as(filteringQuery) + .select(historyGroupingField) + .from(TEST_ITEM) + .join(ITEMS) + .on(TEST_ITEM.ITEM_ID.eq(fieldName(ITEMS, ID).cast(Long.class))) + .join(LAUNCH) + .on(TEST_ITEM.LAUNCH_ID.eq(LAUNCH.ID)) + .where(baselineCondition) + .and(LAUNCH.MODE.eq(JLaunchModeEnum.DEFAULT)) + .groupBy(historyGroupingField) + .orderBy(max(TEST_ITEM.START_TIME)) + .limit(pageable.getPageSize()) + .offset(retrieveOffsetAndApplyBoundaries(pageable)) + .fetchInto(String.class), + pageable, + () -> dsl.fetchCount(with(ITEMS).as(filteringQuery) + .select(TEST_ITEM.field(historyGroupingField)) + .from(TEST_ITEM) + .join(ITEMS) + .on(TEST_ITEM.ITEM_ID.eq(fieldName(ITEMS, ID).cast(Long.class))) + .groupBy(TEST_ITEM.field(historyGroupingField))) + ); + } + + private Filter getHistoryFilter(Queryable filter, boolean usingHash, String historyValue) { + List commonConditions = filter.getFilterConditions(); + return new Filter(filter.getTarget().getClazz(), Lists.newArrayList()).withConditions( + commonConditions) + .withCondition(usingHash ? + FilterCondition.builder().eq(CRITERIA_TEST_CASE_HASH, historyValue).build() : + FilterCondition.builder().eq(CRITERIA_UNIQUE_ID, historyValue).build()) + .withCondition( + FilterCondition.builder().eq(CRITERIA_LAUNCH_MODE, LaunchModeEnum.DEFAULT.name()) + .build()); + } + + private List getHistoryIds(TestItem testItem, boolean usingHash, Long projectId, + int historyDepth) { + List historyIds = usingHash ? loadHistory(testItem.getStartTime(), + testItem.getItemId(), + LAUNCH.PROJECT_ID.eq(projectId) + .and(TEST_ITEM.TEST_CASE_HASH.eq(testItem.getTestCaseHash())), + historyDepth + ) : loadHistory(testItem.getStartTime(), + testItem.getItemId(), + LAUNCH.PROJECT_ID.eq(projectId).and(TEST_ITEM.UNIQUE_ID.eq(testItem.getUniqueId())), + historyDepth + ); + historyIds.add(0, testItem.getItemId()); + return historyIds; + } + + private List getHistoryIds(TestItem testItem, boolean usingHash, Long projectId, + String launchName, int historyDepth) { + if (historyDepth > 0) { + List historyIds = usingHash ? loadHistory(testItem.getStartTime(), + testItem.getItemId(), + LAUNCH.PROJECT_ID.eq(projectId) + .and(LAUNCH.NAME.eq(launchName)) + .and(TEST_ITEM.TEST_CASE_HASH.eq(testItem.getTestCaseHash())), + historyDepth + ) : loadHistory(testItem.getStartTime(), + testItem.getItemId(), + LAUNCH.PROJECT_ID.eq(projectId).and(LAUNCH.NAME.eq(launchName)) + .and(TEST_ITEM.UNIQUE_ID.eq(testItem.getUniqueId())), + historyDepth + ); + historyIds.add(0, testItem.getItemId()); + return historyIds; + } + return Lists.newArrayList(testItem.getItemId()); + } + + private Optional loadHistoryItem(Queryable filter, Sort sort, + Condition baselineCondition) { + List orders = sort.get().collect(toList()); + orders.add(new Sort.Order(Sort.Direction.DESC, CRITERIA_START_TIME)); + + SelectQuery selectQuery = + QueryBuilder.newBuilder(filter, QueryUtils.collectJoinFields(filter, sort)) + .with(Sort.by(orders)) + .with(1) + .build(); + selectQuery.addConditions(baselineCondition); + + return dsl.with(HISTORY) + .as(selectQuery) + .select() + .from(TEST_ITEM) + .join(HISTORY) + .on(TEST_ITEM.ITEM_ID.eq(fieldName(HISTORY, ID).cast(Long.class))) + .fetchInto(TestItem.class) + .stream() + .findFirst(); + } + + private List loadHistory(LocalDateTime startTime, Long itemId, Condition baselineCondition, + int historyDepth) { + return dsl.select(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .join(LAUNCH) + .on(TEST_ITEM.LAUNCH_ID.eq(LAUNCH.ID)) + .where(baselineCondition) + .and(TEST_ITEM.ITEM_ID.notEqual(itemId)) + .and(TEST_ITEM.START_TIME.lessOrEqual(Timestamp.valueOf(startTime))) + .and(LAUNCH.MODE.eq(JLaunchModeEnum.DEFAULT)) + .orderBy(TEST_ITEM.START_TIME.desc(), LAUNCH.START_TIME.desc(), LAUNCH.NUMBER.desc()) + .limit(historyDepth) + .fetchInto(Long.class); + } + + @Override + public List selectAllDescendants(Long itemId) { + return commonTestItemDslSelect().where(TEST_ITEM.PARENT_ID.eq(itemId)) + .fetch(TEST_ITEM_RECORD_MAPPER); + } + + @Override + public List selectAllDescendantsWithChildren(Long itemId) { + JTestItem childTestItem = JTestItem.TEST_ITEM.as("cti"); + return commonTestItemDslSelect().where(TEST_ITEM.PARENT_ID.eq(itemId)) + .and(DSL.exists(DSL.selectOne() + .from(TEST_ITEM) + .join(childTestItem) + .on(TEST_ITEM.ITEM_ID.eq(childTestItem.PARENT_ID)) + .where(TEST_ITEM.PARENT_ID.eq(itemId)))) + .fetch(TEST_ITEM_RECORD_MAPPER); + } + + @Override + public List findTestItemIdsByLaunchId(Long launchId, Pageable pageable) { + JTestItem retryParent = TEST_ITEM.as(RETRY_PARENT); + return dsl.select(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .leftJoin(retryParent) + .on(TEST_ITEM.RETRY_OF.eq(retryParent.ITEM_ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId).or(retryParent.LAUNCH_ID.eq(launchId))) + .orderBy(TEST_ITEM.ITEM_ID) + .limit(pageable.getPageSize()) + .offset(retrieveOffsetAndApplyBoundaries(pageable)) + .fetchInto(Long.class); + } + + @Override + public List selectItemsInStatusByLaunch(Long launchId, StatusEnum... statuses) { + List jStatuses = + Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); + return commonTestItemDslSelect().where( + TEST_ITEM.LAUNCH_ID.eq(launchId).and(TEST_ITEM_RESULTS.STATUS.in(jStatuses))) + .fetch(TEST_ITEM_RECORD_MAPPER); + } + + @Override + public List selectItemsInStatusByParent(Long itemId, StatusEnum... statuses) { + List jStatuses = + Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); + return commonTestItemDslSelect().where( + TEST_ITEM.PARENT_ID.eq(itemId).and(TEST_ITEM_RESULTS.STATUS.in(jStatuses))) + .fetch(TEST_ITEM_RECORD_MAPPER); + } + + @Override + public Boolean hasItemsInStatusByLaunch(Long launchId, StatusEnum... statuses) { + List jStatuses = + Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); + return dsl.fetchExists(dsl.selectOne() + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .onKey() + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .and(TEST_ITEM_RESULTS.STATUS.in(jStatuses)) + .limit(1)); + } + + @Override + public List findAllNotInIssueByLaunch(Long launchId, String locator) { + return commonTestItemDslSelect().join(ISSUE) + .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE_TYPE) + .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .and(ISSUE_TYPE.LOCATOR.ne(locator)) + .fetch(TEST_ITEM_RECORD_MAPPER); + } + + @Override + public List selectIdsNotInIssueByLaunch(Long launchId, String locator) { + return dsl.select(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE) + .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE_TYPE) + .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .and(ISSUE_TYPE.LOCATOR.ne(locator)) + .fetchInto(Long.class); + } + + @Override + public List findAllNotInIssueGroupByLaunch(Long launchId, + TestItemIssueGroup issueGroup) { + return dsl.select() + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE) + .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE_TYPE) + .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) + .join(ISSUE_GROUP) + .on(ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId) + .and(ISSUE_GROUP.ISSUE_GROUP_.ne(JIssueGroupEnum.valueOf(issueGroup.getValue())))) + .fetch(TEST_ITEM_RECORD_MAPPER); + + } + + @Override + public List selectIdsNotInIssueGroupByLaunch(Long launchId, TestItemIssueGroup issueGroup) { + return dsl.select(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE) + .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE_TYPE) + .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) + .join(ISSUE_GROUP) + .on(ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId) + .and(ISSUE_GROUP.ISSUE_GROUP_.ne(JIssueGroupEnum.valueOf(issueGroup.getValue())))) + .fetchInto(Long.class); + } + + @Override + public List findAllInIssueGroupByLaunch(Long launchId, TestItemIssueGroup issueGroup) { + return dsl.select() + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE) + .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE_TYPE) + .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) + .join(ISSUE_GROUP) + .on(ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId) + .and(ISSUE_GROUP.ISSUE_GROUP_.eq(JIssueGroupEnum.valueOf(issueGroup.getValue())))) + .fetch(TEST_ITEM_RECORD_MAPPER); + } + + @Override + public List selectIdsWithIssueByLaunch(Long launchId) { + return dsl.select(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE) + .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .fetchInto(Long.class); + } + + @Override + public Boolean hasItemsInStatusAddedLately(Long launchId, Duration period, + StatusEnum... statuses) { + List jStatuses = + Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); + return dsl.fetchExists(dsl.selectOne() + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .onKey() + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .and(TEST_ITEM_RESULTS.STATUS.in(jStatuses)) + .and(TEST_ITEM.START_TIME.gt(TimestampUtils.getTimestampBackFromNow(period))) + .limit(1)); + } + + @Override + public Boolean hasLogs(Long launchId, Duration period, StatusEnum... statuses) { + List jStatuses = + Arrays.stream(statuses).map(it -> JStatusEnum.valueOf(it.name())).collect(toList()); + return dsl.fetchExists(dsl.selectOne() + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .onKey() + .join(LOG) + .on(TEST_ITEM.ITEM_ID.eq(LOG.ITEM_ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .and(TEST_ITEM_RESULTS.STATUS.in(jStatuses)) + .and(TEST_ITEM.START_TIME.lt(TimestampUtils.getTimestampBackFromNow(period))) + .limit(1)); + } + + @Override + public List selectItemsInIssueByLaunch(Long launchId, String issueType) { + return commonTestItemDslSelect().join(ISSUE) + .on(ISSUE.ISSUE_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE_TYPE) + .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .and(ISSUE_TYPE.LOCATOR.eq(issueType)) + .fetch(TEST_ITEM_RECORD_MAPPER::map); + } + + @Override + public List selectRetries(List retryOfIds) { + return TEST_ITEM_RETRY_FETCHER.apply(dsl.select() + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .leftJoin(PARAMETER) + .on(TEST_ITEM.ITEM_ID.eq(PARAMETER.ITEM_ID)) + .where(TEST_ITEM.RETRY_OF.in(retryOfIds)) + .and(TEST_ITEM.LAUNCH_ID.isNull()) + .orderBy(TEST_ITEM.START_TIME) + .fetch()); + } + + @Override + public List selectIssueLocatorsByProject(Long projectId) { + return dsl.select() + .from(PROJECT) + .join(ISSUE_TYPE_PROJECT) + .on(PROJECT.ID.eq(ISSUE_TYPE_PROJECT.PROJECT_ID)) + .join(ISSUE_TYPE) + .on(ISSUE_TYPE_PROJECT.ISSUE_TYPE_ID.eq(ISSUE_TYPE.ID)) + .join(ISSUE_GROUP) + .on(Tables.ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) + .where(PROJECT.ID.eq(projectId)) + .fetch(ISSUE_TYPE_RECORD_MAPPER); + } + + @Override + public Optional selectIssueTypeByLocator(Long projectId, String locator) { + return ofNullable(dsl.select() + .from(ISSUE_TYPE) + .join(ISSUE_TYPE_PROJECT) + .on(ISSUE_TYPE_PROJECT.ISSUE_TYPE_ID.eq(ISSUE_TYPE.ID)) + .join(ISSUE_GROUP) + .on(ISSUE_TYPE.ISSUE_GROUP_ID.eq(ISSUE_GROUP.ISSUE_GROUP_ID)) + .where(ISSUE_TYPE_PROJECT.PROJECT_ID.eq(projectId)) + .and(ISSUE_TYPE.LOCATOR.eq(locator)) + .fetchOne(ISSUE_TYPE_RECORD_MAPPER)); + } + + @Override + public Optional> selectPath(String uuid) { + return dsl.select(TEST_ITEM.ITEM_ID, TEST_ITEM.PATH) + .from(TEST_ITEM) + .where(TEST_ITEM.UUID.eq(uuid)) + .fetchOptional(r -> Pair.of(r.get(TEST_ITEM.ITEM_ID), r.get(TEST_ITEM.PATH, String.class))); + } + + /** + * {@link Log} entities are searched from the whole tree under {@link TestItem} that matched to + * the provided `launchId` and `autoAnalyzed` conditions + */ + @Override + public List selectIdsByAnalyzedWithLevelGte(boolean autoAnalyzed, boolean ignoreAnalyzer, + Long launchId, int logLevel) { + + JTestItem outerItemTable = TEST_ITEM.as(OUTER_ITEM_TABLE); + JTestItem nestedItemTable = TEST_ITEM.as(NESTED); + + final Condition issueCondition = + ISSUE.AUTO_ANALYZED.eq(autoAnalyzed).and(ISSUE.IGNORE_ANALYZER.eq(ignoreAnalyzer)); + + return dsl.selectDistinct(fieldName(ID)) + .from(DSL.select(outerItemTable.ITEM_ID.as(ID)) + .from(outerItemTable) + .join(TEST_ITEM_RESULTS) + .on(outerItemTable.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE) + .on(TEST_ITEM_RESULTS.RESULT_ID.eq(ISSUE.ISSUE_ID)) + .where(outerItemTable.LAUNCH_ID.eq(launchId)) + .and(outerItemTable.HAS_STATS) + .andNot(outerItemTable.HAS_CHILDREN) + .and(issueCondition) + .and(DSL.exists(DSL.selectOne() + .from(nestedItemTable) + .join(LOG) + .on(nestedItemTable.ITEM_ID.eq(LOG.ITEM_ID)) + .where(nestedItemTable.LAUNCH_ID.eq(launchId)) + .andNot(nestedItemTable.HAS_STATS) + .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) + .and(DSL.sql(outerItemTable.PATH + " @> " + nestedItemTable.PATH)))) + .unionAll(DSL.selectDistinct(TEST_ITEM.ITEM_ID.as(ID)) + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE) + .on(TEST_ITEM_RESULTS.RESULT_ID.eq(ISSUE.ISSUE_ID)) + .join(LOG) + .on(TEST_ITEM.ITEM_ID.eq(LOG.ITEM_ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .and(issueCondition) + .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel))) + .asTable(ITEM)) + .fetchInto(Long.class); + } + + @Override + public int updateStatusAndEndTimeById(Long itemId, JStatusEnum status, LocalDateTime endTime) { + + return dsl.update(TEST_ITEM_RESULTS) + .set(TEST_ITEM_RESULTS.STATUS, status) + .set(TEST_ITEM_RESULTS.END_TIME, Timestamp.valueOf(endTime)) + .set(TEST_ITEM_RESULTS.DURATION, + dsl.select(DSL.extract(endTime, DatePart.EPOCH) + .minus(DSL.extract(TEST_ITEM.START_TIME, DatePart.EPOCH)) + .cast(Double.class)).from(TEST_ITEM).where(TEST_ITEM.ITEM_ID.eq(itemId)) + ) + .where(TEST_ITEM_RESULTS.RESULT_ID.eq(itemId)) + .execute(); + } + + @Override + public int updateStatusAndEndTimeByRetryOfId(Long retryOfId, JStatusEnum from, JStatusEnum to, + LocalDateTime endTime) { + return dsl.update(TEST_ITEM_RESULTS) + .set(TEST_ITEM_RESULTS.STATUS, to) + .set(TEST_ITEM_RESULTS.END_TIME, Timestamp.valueOf(endTime)) + .set(TEST_ITEM_RESULTS.DURATION, + dsl.select(DSL.extract(endTime, DatePart.EPOCH) + .minus(DSL.extract(TEST_ITEM.START_TIME, DatePart.EPOCH)) + .cast(Double.class)).from(TEST_ITEM) + .where(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + ) + .where(TEST_ITEM_RESULTS.RESULT_ID.in(DSL.select(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .where(TEST_ITEM.RETRY_OF.eq(retryOfId)))) + .and(TEST_ITEM_RESULTS.STATUS.eq(from)) + .execute(); + } + + @Override + public TestItemTypeEnum getTypeByItemId(Long itemId) { + return dsl.select(TEST_ITEM.TYPE).from(TEST_ITEM).where(TEST_ITEM.ITEM_ID.eq(itemId)) + .fetchOneInto(TestItemTypeEnum.class); + } + + @Override + public List selectIdsByFilter(Long launchId, Queryable filter, int limit, int offset) { + final SelectQuery selectQuery = + QueryBuilder.newBuilder(filter, QueryUtils.collectJoinFields(filter)) + .with(limit) + .withOffset(offset) + .with(Sort.by(Sort.Order.asc(CRITERIA_ID))) + .build(); + selectQuery.addConditions(TEST_ITEM.LAUNCH_ID.eq(launchId)); + return dsl.select(fieldName(ITEMS, ID)).from(selectQuery.asTable(ITEMS)).fetchInto(Long.class); + } + + @Override + public List selectIdsByHasDescendants(Collection itemIds) { + final JTestItem parent = TEST_ITEM.as(OUTER_ITEM_TABLE); + final JTestItem child = TEST_ITEM.as(CHILD_ITEM_TABLE); + return dsl.select(parent.ITEM_ID) + .from(parent) + .join(child) + .on(parent.ITEM_ID.eq(child.PARENT_ID)) + .where(parent.ITEM_ID.in(itemIds)) + .groupBy(parent.ITEM_ID) + .fetchInto(Long.class); + } + + @Override + public List selectIdsByStringLogMessage(Collection itemIds, Integer logLevel, + String pattern) { + return dsl.selectDistinct(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .join(LOG) + .on(TEST_ITEM.ITEM_ID.eq(LOG.ITEM_ID)) + .where(TEST_ITEM.ITEM_ID.in(itemIds)) + .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) + .and(LOG.LOG_MESSAGE.like("%" + DSL.escape(pattern, '\\') + "%")) + .fetchInto(Long.class); + } + + @Override + public List selectIdsByRegexLogMessage(Collection itemIds, Integer logLevel, + String pattern) { + return dsl.selectDistinct(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .join(LOG) + .on(TEST_ITEM.ITEM_ID.eq(LOG.ITEM_ID)) + .where(TEST_ITEM.ITEM_ID.in(itemIds)) + .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) + .and(LOG.LOG_MESSAGE.likeRegex(pattern)) + .fetchInto(Long.class); + } + + @Override + public List selectIdsUnderByStringLogMessage(Long launchId, Collection itemIds, + Integer logLevel, String pattern) { + final JTestItem child = TEST_ITEM.as(CHILD_ITEM_TABLE); + + return dsl.selectDistinct(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .join(child) + .on(TEST_ITEM.PATH + " @> " + child.PATH) + .and(TEST_ITEM.ITEM_ID.notEqual(child.ITEM_ID)) + .join(LOG) + .on(child.ITEM_ID.eq(LOG.ITEM_ID)) + .where(TEST_ITEM.ITEM_ID.in(itemIds)) + .and(child.LAUNCH_ID.eq(launchId)) + .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) + .and(LOG.LOG_MESSAGE.like("%" + DSL.escape(pattern, '\\') + "%")) + .groupBy(TEST_ITEM.ITEM_ID) + .fetchInto(Long.class); + } + + @Override + public List selectIdsUnderByRegexLogMessage(Long launchId, Collection itemIds, + Integer logLevel, String pattern) { + final JTestItem child = TEST_ITEM.as(CHILD_ITEM_TABLE); + + return dsl.selectDistinct(TEST_ITEM.ITEM_ID) + .from(TEST_ITEM) + .join(child) + .on(TEST_ITEM.PATH + " @> " + child.PATH) + .and(TEST_ITEM.ITEM_ID.notEqual(child.ITEM_ID)) + .join(LOG) + .on(child.ITEM_ID.eq(LOG.ITEM_ID)) + .where(TEST_ITEM.ITEM_ID.in(itemIds)) + .and(child.LAUNCH_ID.eq(launchId)) + .and(LOG.LOG_LEVEL.greaterOrEqual(logLevel)) + .and(LOG.LOG_MESSAGE.likeRegex(pattern)) + .groupBy(TEST_ITEM.ITEM_ID) + .fetchInto(Long.class); + } + + /** + * Commons select of an item with it's results and structure + * + * @return Select condition step + */ + private SelectOnConditionStep commonTestItemDslSelect() { + return dsl.select().from(TEST_ITEM).join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)); + } + + @Override + public List findByFilter(Queryable filter) { + return TEST_ITEM_FETCHER.apply(dsl.fetch( + QueryBuilder.newBuilder(filter, QueryUtils.collectJoinFields(filter)).wrap().build())); + } + + @Override + public Page findByFilter(Queryable filter, Pageable pageable) { + + Set joinFields = QueryUtils.collectJoinFields(filter, pageable.getSort()); + List items = + TEST_ITEM_FETCHER.apply(dsl.fetch(QueryBuilder.newBuilder(filter, joinFields) + .with(pageable) + .wrap() + .withWrapperSort(pageable.getSort()) + .build())); + + return PageableExecutionUtils.getPage(items, pageable, + () -> dsl.fetchCount(QueryBuilder.newBuilder(filter, joinFields).build())); + } + + @Override + public List findAllNestedStepsByIds(Collection ids, Queryable logFilter, + boolean excludePassedLogs) { + JTestItem nested = TEST_ITEM.as(NESTED); + + CommonTableExpression logsCte = DSL.name("logsCTE") + .as(QueryBuilder.newBuilder(logFilter, QueryUtils.collectJoinFields(logFilter)).build()); + + return dsl.with(logsCte).select(TEST_ITEM.ITEM_ID, + TEST_ITEM.NAME, + TEST_ITEM.UUID, + TEST_ITEM.START_TIME, + TEST_ITEM.TYPE, + TEST_ITEM_RESULTS.STATUS, + TEST_ITEM_RESULTS.END_TIME, + TEST_ITEM_RESULTS.DURATION, + DSL.field(hasContentQuery(nested, logsCte, excludePassedLogs)).as(HAS_CONTENT), + DSL.field(dsl.selectCount() + .from(LOG) + .join(nested) + .on(LOG.ITEM_ID.eq(nested.ITEM_ID)) + .join(logsCte) + .on(LOG.ID.eq(logsCte.field(ID).cast(Long.class))) + .join(ATTACHMENT) + .on(LOG.ATTACHMENT_ID.eq(ATTACHMENT.ID)) + .where(nested.HAS_STATS.isFalse().and(DSL.sql( + fieldName(NESTED, TEST_ITEM.PATH.getName()) + " <@ cast(? AS LTREE)", + TEST_ITEM.PATH)))) + .as(ATTACHMENTS_COUNT) + ) + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .where(TEST_ITEM.ITEM_ID.in(ids)) + .fetch(NESTED_STEP_RECORD_MAPPER); + } + + @Override + public List findIndexTestItemByLaunchId(Long launchId, + Collection itemTypes) { + return dsl.select(TEST_ITEM.ITEM_ID, + TEST_ITEM.NAME, + TEST_ITEM.START_TIME, + TEST_ITEM.UNIQUE_ID, + TEST_ITEM.TEST_CASE_HASH, + ISSUE.AUTO_ANALYZED, + ISSUE_TYPE.LOCATOR + ) + .from(TEST_ITEM) + .join(TEST_ITEM_RESULTS) + .on(TEST_ITEM.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .join(ISSUE) + .on(TEST_ITEM_RESULTS.RESULT_ID.eq(ISSUE.ISSUE_ID)) + .join(ISSUE_TYPE) + .on(ISSUE.ISSUE_TYPE.eq(ISSUE_TYPE.ID)) + .where(TEST_ITEM.LAUNCH_ID.eq(launchId)) + .and(TEST_ITEM.TYPE.in(itemTypes)) + .and(ISSUE.IGNORE_ANALYZER.isFalse()) + .fetch(INDEX_TEST_ITEM_RECORD_MAPPER); + + } + + private Condition hasContentQuery(JTestItem nested, CommonTableExpression logsCte, + boolean excludePassedLogs) { + if (excludePassedLogs) { + return DSL.exists(dsl.select() + .from(LOG) + .join(logsCte) + .on(LOG.ID.eq(logsCte.field(ID).cast(Long.class))) + .join(TEST_ITEM_RESULTS) + .on(LOG.ITEM_ID.eq(TEST_ITEM_RESULTS.RESULT_ID)) + .where(LOG.ITEM_ID.eq(TEST_ITEM.ITEM_ID))) + .and(TEST_ITEM_RESULTS.STATUS.notIn(JStatusEnum.PASSED, JStatusEnum.INFO, + JStatusEnum.WARN)); + } else { + return DSL.exists(dsl.select() + .from(LOG) + .join(logsCte) + .on(LOG.ID.eq(logsCte.field(ID).cast(Long.class))) + .where(LOG.ITEM_ID.eq(TEST_ITEM.ITEM_ID))) + .orExists(dsl.select().from(nested) + .where(nested.PARENT_ID.eq(TEST_ITEM.ITEM_ID).and(nested.HAS_STATS.isFalse()))); + } + } + + /** + * @return Map + */ + @Override + public Map selectPathNames(Collection testItems) { + if (CollectionUtils.isEmpty(testItems)) { + return new HashMap<>(); + } + + // Item ids for search + Set testItemIds = new HashSet<>(); + // Structure for creating return object + Map> testItemWithPathIds = new HashMap<>(); + + for (TestItem testItem : testItems) { + String path = testItem.getPath(); + // For normal case is redundant, but not sure for current situation, better to check + // and skip testItem without path, cause of incorrect state. + if (Strings.isBlank(path)) { + continue; + } + String[] pathIds = path.split("\\."); + Arrays.asList(pathIds).forEach( + pathItemId -> { + long itemIdFromPath = Long.parseLong(pathItemId); + testItemIds.add(itemIdFromPath); + + List itemPaths = + testItemWithPathIds.getOrDefault(testItem.getItemId(), new ArrayList<>()); + itemPaths.add(itemIdFromPath); + testItemWithPathIds.put(testItem.getItemId(), itemPaths); + } + ); + } + + Map> resultMap = new HashMap<>(); + // Convert database data to more useful form + getTestItemAndLaunchIdName(testItemIds).forEach(record -> resultMap.put( + record.get(fieldName("item_id"), Long.class), record + )); + + Map testItemPathNames = new HashMap<>(); + testItemWithPathIds.forEach((testItemId, pathIds) -> { + var record = resultMap.get(testItemId); + if (record == null) { + return; + } + + LaunchPathName launchPathName = new LaunchPathName( + record.get(fieldName("launch_name"), String.class), + record.get(fieldName("number"), Integer.class) + ); + + List itemPathNames = new ArrayList<>(); + pathIds.forEach(pathItemId -> { + // Base testItem don't add + if (!testItemId.equals(pathItemId) && resultMap.containsKey(pathItemId)) { + var record2 = resultMap.get(pathItemId); + String pathItemName = record2.get(fieldName("name"), String.class); + itemPathNames.add(new ItemPathName(pathItemId, pathItemName)); + } + }); + PathName pathName = new PathName(launchPathName, itemPathNames); + testItemPathNames.put(testItemId, pathName); + }); + + return testItemPathNames; + } + + /** + * @param testItemIds Collection + * @return Result> + */ + private Result> getTestItemAndLaunchIdName( + Collection testItemIds) { + return dsl.select(TEST_ITEM.ITEM_ID, TEST_ITEM.NAME, LAUNCH.NUMBER, + LAUNCH.NAME.as("launch_name")) + .from(TEST_ITEM) + .join(LAUNCH) + .on(TEST_ITEM.LAUNCH_ID.eq(LAUNCH.ID)) + .where(TEST_ITEM.ITEM_ID.in(testItemIds)) + .fetch(); + } } From ee00dee802b46798bfd9d44f0bb1fa13ff58af7e Mon Sep 17 00:00:00 2001 From: Ivan_Kustau Date: Mon, 28 Aug 2023 15:49:42 +0300 Subject: [PATCH 2/2] Release 5.10.0 --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 2826bb097..f73958772 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ repositories { dependencyManagement { imports { - mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + getProperty('bom.version') : 'com.github.reportportal:commons-bom:80a17605') + mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + getProperty('bom.version') : 'com.github.reportportal:commons-bom:6aa55fc0') mavenBom('io.zonky.test.postgres:embedded-postgres-binaries-bom:12.9.0') } } @@ -61,9 +61,9 @@ dependencies { compile 'com.epam.reportportal:commons-rules' compile 'com.epam.reportportal:commons-model' } else { - compile 'com.github.reportportal:commons:def053af' + compile 'com.github.reportportal:commons:ce2166b5' compile 'com.github.reportportal:commons-rules:5.10.0' - compile 'com.github.reportportal:commons-model:5918181' + compile 'com.github.reportportal:commons-model:232e69a5' } //https://nvd.nist.gov/vuln/detail/CVE-2020-10683 (dom4j 2.1.3 version dependency) AND https://nvd.nist.gov/vuln/detail/CVE-2019-14900