Browse Source

Fix for transaction management

pull/3087/head
Andrew Shvayka 6 years ago
parent
commit
9ce9e004c4
  1. 2
      application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java
  2. 214
      dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java
  3. 209
      dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java

2
application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java

@ -286,7 +286,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
int dynamicQueryInvocationCntValue = stats.getDynamicQueryInvocationCnt().getAndSet(0);
long dynamicQueryInvocationTimeValue = stats.getDynamicQueryTimeSpent().getAndSet(0);
long dynamicQueryCnt = subscriptionsBySessionId.values().stream().map(Map::values).count();
if (regularQueryInvocationCntValue > 0 || dynamicQueryInvocationCntValue > 0 || dynamicQueryCnt > 0) {
if (regularQueryInvocationCntValue > 0 || dynamicQueryInvocationCntValue > 0 || dynamicQueryCnt > 0 || alarmQueryInvocationCntValue > 0) {
log.info("Stats: regularQueryInvocationCnt = [{}], regularQueryInvocationTime = [{}], " +
"dynamicQueryCnt = [{}] dynamicQueryInvocationCnt = [{}], dynamicQueryInvocationTime = [{}], " +
"alarmQueryInvocationCnt = [{}], alarmQueryInvocationTime = [{}]",

214
dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java

@ -20,6 +20,9 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
@ -53,7 +56,6 @@ import java.util.stream.Collectors;
public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
private static final Map<String, String> alarmFieldColumnMap = new HashMap<>();
private static final List<String> uniqueAlarmFields = new ArrayList<>();
static {
alarmFieldColumnMap.put("createdTime", ModelConstants.CREATED_TIME_PROPERTY);
@ -72,11 +74,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
alarmFieldColumnMap.put("originator_id", ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY);
alarmFieldColumnMap.put("originator_type", ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY);
alarmFieldColumnMap.put("originator", "originator_name");
uniqueAlarmFields.addAll(new HashSet<>(alarmFieldColumnMap.values()));
}
public static final String SELECT_ORIGINATOR_NAME = " CASE" +
private static final String SELECT_ORIGINATOR_NAME = " CASE" +
" WHEN a.originator_type = " + EntityType.TENANT.ordinal() +
" THEN (select title from tenant where id = a.originator_id)" +
" WHEN a.originator_type = " + EntityType.CUSTOMER.ordinal() +
@ -93,7 +93,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
" THEN (select name from entity_view where id = a.originator_id)" +
" END as originator_name";
public static final String FIELDS_SELECTION = "select a.id as id," +
private static final String FIELDS_SELECTION = "select a.id as id," +
" a.created_time as created_time," +
" a.ack_ts as ack_ts," +
" a.clear_ts as clear_ts," +
@ -109,130 +109,136 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
" a.propagate_relation_types as propagate_relation_types, " +
" a.type as type," + SELECT_ORIGINATOR_NAME + ", ";
public static final String JOIN_RELATIONS = "left join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id and r.from_id in (:entity_ids)";
private static final String JOIN_RELATIONS = "left join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id and r.from_id in (:entity_ids)";
@Autowired
protected NamedParameterJdbcTemplate jdbcTemplate;
protected final NamedParameterJdbcTemplate jdbcTemplate;
private final TransactionTemplate transactionTemplate;
public DefaultAlarmQueryRepository(NamedParameterJdbcTemplate jdbcTemplate, TransactionTemplate transactionTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.transactionTemplate = transactionTemplate;
}
@Override
public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId,
AlarmDataQuery query, Collection<EntityId> orderedEntityIds) {
AlarmDataPageLink pageLink = query.getPageLink();
QueryContext ctx = new QueryContext();
ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList()));
return transactionTemplate.execute(status -> {
AlarmDataPageLink pageLink = query.getPageLink();
QueryContext ctx = new QueryContext();
ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList()));
StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION);
StringBuilder fromPart = new StringBuilder(" from alarm a ");
StringBuilder wherePart = new StringBuilder(" where ");
StringBuilder sortPart = new StringBuilder(" order by ");
boolean addAnd = false;
if (pageLink.isSearchPropagatedAlarms()) {
selectPart.append(" CASE WHEN r.from_id IS NULL THEN a.originator_id ELSE r.from_id END as entity_id ");
fromPart.append(JOIN_RELATIONS);
wherePart.append(buildPermissionsQuery(tenantId, customerId, ctx));
addAnd = true;
} else {
selectPart.append(" a.originator_id as entity_id ");
}
EntityDataSortOrder sortOrder = pageLink.getSortOrder();
if (sortOrder != null && sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) {
String sortOrderKey = sortOrder.getKey().getKey();
sortPart.append(alarmFieldColumnMap.getOrDefault(sortOrderKey, sortOrderKey))
.append(" ").append(sortOrder.getDirection().name());
StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION);
StringBuilder fromPart = new StringBuilder(" from alarm a ");
StringBuilder wherePart = new StringBuilder(" where ");
StringBuilder sortPart = new StringBuilder(" order by ");
boolean addAnd = false;
if (pageLink.isSearchPropagatedAlarms()) {
wherePart.append(" and (a.originator_id in (:entity_ids) or r.from_id IS NOT NULL)");
} else {
addAndIfNeeded(wherePart, addAnd);
selectPart.append(" CASE WHEN r.from_id IS NULL THEN a.originator_id ELSE r.from_id END as entity_id ");
fromPart.append(JOIN_RELATIONS);
wherePart.append(buildPermissionsQuery(tenantId, customerId, ctx));
addAnd = true;
wherePart.append(" a.originator_id in (:entity_ids)");
} else {
selectPart.append(" a.originator_id as entity_id ");
}
} else {
fromPart.append(" left join (select * from (VALUES");
int entityIdIdx = 0;
int lastEntityIdIdx = orderedEntityIds.size() - 1;
for (EntityId entityId : orderedEntityIds) {
fromPart.append("(uuid('").append(entityId.getId().toString()).append("'), ").append(entityIdIdx).append(")");
if (entityIdIdx != lastEntityIdIdx) {
fromPart.append(",");
EntityDataSortOrder sortOrder = pageLink.getSortOrder();
if (sortOrder != null && sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) {
String sortOrderKey = sortOrder.getKey().getKey();
sortPart.append(alarmFieldColumnMap.getOrDefault(sortOrderKey, sortOrderKey))
.append(" ").append(sortOrder.getDirection().name());
if (pageLink.isSearchPropagatedAlarms()) {
wherePart.append(" and (a.originator_id in (:entity_ids) or r.from_id IS NOT NULL)");
} else {
fromPart.append(")");
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
wherePart.append(" a.originator_id in (:entity_ids)");
}
entityIdIdx++;
}
fromPart.append(" as e(id, priority)) e ");
if (pageLink.isSearchPropagatedAlarms()) {
fromPart.append("on (r.from_id IS NULL and a.originator_id = e.id) or (r.from_id IS NOT NULL and r.from_id = e.id)");
} else {
fromPart.append("on a.originator_id = e.id");
fromPart.append(" left join (select * from (VALUES");
int entityIdIdx = 0;
int lastEntityIdIdx = orderedEntityIds.size() - 1;
for (EntityId entityId : orderedEntityIds) {
fromPart.append("(uuid('").append(entityId.getId().toString()).append("'), ").append(entityIdIdx).append(")");
if (entityIdIdx != lastEntityIdIdx) {
fromPart.append(",");
} else {
fromPart.append(")");
}
entityIdIdx++;
}
fromPart.append(" as e(id, priority)) e ");
if (pageLink.isSearchPropagatedAlarms()) {
fromPart.append("on (r.from_id IS NULL and a.originator_id = e.id) or (r.from_id IS NOT NULL and r.from_id = e.id)");
} else {
fromPart.append("on a.originator_id = e.id");
}
sortPart.append("e.priority");
}
sortPart.append("e.priority");
}
long startTs;
long endTs;
if (pageLink.getTimeWindow() > 0) {
endTs = System.currentTimeMillis();
startTs = endTs - pageLink.getTimeWindow();
} else {
startTs = pageLink.getStartTs();
endTs = pageLink.getEndTs();
}
if (startTs > 0) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addLongParameter("startTime", startTs);
wherePart.append("a.created_time >= :startTime");
}
long startTs;
long endTs;
if (pageLink.getTimeWindow() > 0) {
endTs = System.currentTimeMillis();
startTs = endTs - pageLink.getTimeWindow();
} else {
startTs = pageLink.getStartTs();
endTs = pageLink.getEndTs();
}
if (endTs > 0) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addLongParameter("endTime", endTs);
wherePart.append("a.created_time <= :endTime");
}
if (startTs > 0) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addLongParameter("startTime", startTs);
wherePart.append("a.created_time >= :startTime");
}
if (pageLink.getTypeList() != null && !pageLink.getTypeList().isEmpty()) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addStringListParameter("alarmTypes", pageLink.getTypeList());
wherePart.append("a.type in (:alarmTypes)");
}
if (endTs > 0) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addLongParameter("endTime", endTs);
wherePart.append("a.created_time <= :endTime");
}
if (pageLink.getSeverityList() != null && !pageLink.getSeverityList().isEmpty()) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addStringListParameter("alarmSeverities", pageLink.getSeverityList().stream().map(AlarmSeverity::name).collect(Collectors.toList()));
wherePart.append("a.severity in (:alarmSeverities)");
}
if (pageLink.getTypeList() != null && !pageLink.getTypeList().isEmpty()) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addStringListParameter("alarmTypes", pageLink.getTypeList());
wherePart.append("a.type in (:alarmTypes)");
}
if (pageLink.getStatusList() != null && !pageLink.getStatusList().isEmpty()) {
Set<AlarmStatus> statusSet = toStatusSet(pageLink.getStatusList());
if (!statusSet.isEmpty()) {
if (pageLink.getSeverityList() != null && !pageLink.getSeverityList().isEmpty()) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addStringListParameter("alarmStatuses", statusSet.stream().map(AlarmStatus::name).collect(Collectors.toList()));
wherePart.append(" a.status in (:alarmStatuses)");
ctx.addStringListParameter("alarmSeverities", pageLink.getSeverityList().stream().map(AlarmSeverity::name).collect(Collectors.toList()));
wherePart.append("a.severity in (:alarmSeverities)");
}
}
String textSearchQuery = buildTextSearchQuery(ctx, query.getAlarmFields(), pageLink.getTextSearch());
String mainQuery = selectPart.toString() + fromPart.toString() + wherePart.toString();
if (!textSearchQuery.isEmpty()) {
mainQuery = String.format("select * from (%s) a WHERE %s", mainQuery, textSearchQuery);
}
String countQuery = mainQuery;
int totalElements = jdbcTemplate.queryForObject(String.format("select count(*) from (%s) result", countQuery), ctx, Integer.class);
if (pageLink.getStatusList() != null && !pageLink.getStatusList().isEmpty()) {
Set<AlarmStatus> statusSet = toStatusSet(pageLink.getStatusList());
if (!statusSet.isEmpty()) {
addAndIfNeeded(wherePart, addAnd);
addAnd = true;
ctx.addStringListParameter("alarmStatuses", statusSet.stream().map(AlarmStatus::name).collect(Collectors.toList()));
wherePart.append(" a.status in (:alarmStatuses)");
}
}
String dataQuery = mainQuery + sortPart;
String textSearchQuery = buildTextSearchQuery(ctx, query.getAlarmFields(), pageLink.getTextSearch());
String mainQuery = selectPart.toString() + fromPart.toString() + wherePart.toString();
if (!textSearchQuery.isEmpty()) {
mainQuery = String.format("select * from (%s) a WHERE %s", mainQuery, textSearchQuery);
}
String countQuery = mainQuery;
int totalElements = jdbcTemplate.queryForObject(String.format("select count(*) from (%s) result", countQuery), ctx, Integer.class);
int startIndex = pageLink.getPageSize() * pageLink.getPage();
if (pageLink.getPageSize() > 0) {
dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
}
List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx);
return AlarmDataAdapter.createAlarmData(pageLink, rows, totalElements, orderedEntityIds);
String dataQuery = mainQuery + sortPart;
int startIndex = pageLink.getPageSize() * pageLink.getPage();
if (pageLink.getPageSize() > 0) {
dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
}
List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx);
return AlarmDataAdapter.createAlarmData(pageLink, rows, totalElements, orderedEntityIds);
});
}
private String buildTextSearchQuery(QueryContext ctx, List<EntityKey> selectionMapping, String searchText) {

209
dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java

@ -20,6 +20,9 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
@ -58,37 +61,36 @@ import java.util.stream.Collectors;
@Repository
@Slf4j
public class DefaultEntityQueryRepository implements EntityQueryRepository {
//TODO: rafactoring to protect from SQL injections;
private static final Map<EntityType, String> entityTableMap = new HashMap<>();
public static final String SELECT_PHONE = " CASE WHEN entity.entity_type = 'TENANT' THEN (select phone from tenant where id = entity_id)" +
private static final String SELECT_PHONE = " CASE WHEN entity.entity_type = 'TENANT' THEN (select phone from tenant where id = entity_id)" +
" WHEN entity.entity_type = 'CUSTOMER' THEN (select phone from customer where id = entity_id) END as phone";
public static final String SELECT_ZIP = " CASE WHEN entity.entity_type = 'TENANT' THEN (select zip from tenant where id = entity_id)" +
private static final String SELECT_ZIP = " CASE WHEN entity.entity_type = 'TENANT' THEN (select zip from tenant where id = entity_id)" +
" WHEN entity.entity_type = 'CUSTOMER' THEN (select zip from customer where id = entity_id) END as zip";
public static final String SELECT_ADDRESS_2 = " CASE WHEN entity.entity_type = 'TENANT'" +
private static final String SELECT_ADDRESS_2 = " CASE WHEN entity.entity_type = 'TENANT'" +
" THEN (select address2 from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " +
" THEN (select address2 from customer where id = entity_id) END as address2";
public static final String SELECT_ADDRESS = " CASE WHEN entity.entity_type = 'TENANT'" +
private static final String SELECT_ADDRESS = " CASE WHEN entity.entity_type = 'TENANT'" +
" THEN (select address from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " +
" THEN (select address from customer where id = entity_id) END as address";
public static final String SELECT_CITY = " CASE WHEN entity.entity_type = 'TENANT'" +
private static final String SELECT_CITY = " CASE WHEN entity.entity_type = 'TENANT'" +
" THEN (select city from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " +
" THEN (select city from customer where id = entity_id) END as city";
public static final String SELECT_STATE = " CASE WHEN entity.entity_type = 'TENANT'" +
private static final String SELECT_STATE = " CASE WHEN entity.entity_type = 'TENANT'" +
" THEN (select state from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " +
" THEN (select state from customer where id = entity_id) END as state";
public static final String SELECT_COUNTRY = " CASE WHEN entity.entity_type = 'TENANT'" +
private static final String SELECT_COUNTRY = " CASE WHEN entity.entity_type = 'TENANT'" +
" THEN (select country from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " +
" THEN (select country from customer where id = entity_id) END as country";
public static final String SELECT_TITLE = " CASE WHEN entity.entity_type = 'TENANT'" +
private static final String SELECT_TITLE = " CASE WHEN entity.entity_type = 'TENANT'" +
" THEN (select title from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " +
" THEN (select title from customer where id = entity_id) END as title";
public static final String SELECT_LAST_NAME = " CASE WHEN entity.entity_type = 'USER'" +
private static final String SELECT_LAST_NAME = " CASE WHEN entity.entity_type = 'USER'" +
" THEN (select last_name from tb_user where id = entity_id) END as last_name";
public static final String SELECT_FIRST_NAME = " CASE WHEN entity.entity_type = 'USER'" +
private static final String SELECT_FIRST_NAME = " CASE WHEN entity.entity_type = 'USER'" +
" THEN (select first_name from tb_user where id = entity_id) END as first_name";
public static final String SELECT_REGION = " CASE WHEN entity.entity_type = 'TENANT'" +
private static final String SELECT_REGION = " CASE WHEN entity.entity_type = 'TENANT'" +
" THEN (select region from tenant where id = entity_id) END as region";
public static final String SELECT_EMAIL = " CASE" +
private static final String SELECT_EMAIL = " CASE" +
" WHEN entity.entity_type = 'TENANT'" +
" THEN (select email from tenant where id = entity_id)" +
" WHEN entity.entity_type = 'CUSTOMER' " +
@ -96,7 +98,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
" WHEN entity.entity_type = 'USER'" +
" THEN (select email from tb_user where id = entity_id)" +
" END as email";
public static final String SELECT_CUSTOMER_ID = "CASE" +
private static final String SELECT_CUSTOMER_ID = "CASE" +
" WHEN entity.entity_type = 'TENANT'" +
" THEN UUID('" + TenantId.NULL_UUID + "')" +
" WHEN entity.entity_type = 'CUSTOMER' THEN entity_id" +
@ -112,7 +114,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
" WHEN entity.entity_type = 'ENTITY_VIEW'" +
" THEN (select customer_id from entity_view where id = entity_id)" +
" END as customer_id";
public static final String SELECT_TENANT_ID = "SELECT CASE" +
private static final String SELECT_TENANT_ID = "SELECT CASE" +
" WHEN entity.entity_type = 'TENANT' THEN entity_id" +
" WHEN entity.entity_type = 'CUSTOMER'" +
" THEN (select tenant_id from customer where id = entity_id)" +
@ -127,7 +129,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
" WHEN entity.entity_type = 'ENTITY_VIEW'" +
" THEN (select tenant_id from entity_view where id = entity_id)" +
" END as tenant_id";
public static final String SELECT_CREATED_TIME = " CASE" +
private static final String SELECT_CREATED_TIME = " CASE" +
" WHEN entity.entity_type = 'TENANT'" +
" THEN (select created_time from tenant where id = entity_id)" +
" WHEN entity.entity_type = 'CUSTOMER' " +
@ -143,7 +145,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
" WHEN entity.entity_type = 'ENTITY_VIEW'" +
" THEN (select created_time from entity_view where id = entity_id)" +
" END as created_time";
public static final String SELECT_NAME = " CASE" +
private static final String SELECT_NAME = " CASE" +
" WHEN entity.entity_type = 'TENANT'" +
" THEN (select title from tenant where id = entity_id)" +
" WHEN entity.entity_type = 'CUSTOMER' " +
@ -159,7 +161,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
" WHEN entity.entity_type = 'ENTITY_VIEW'" +
" THEN (select name from entity_view where id = entity_id)" +
" END as name";
public static final String SELECT_TYPE = " CASE" +
private static final String SELECT_TYPE = " CASE" +
" WHEN entity.entity_type = 'USER'" +
" THEN (select authority from tb_user where id = entity_id)" +
" WHEN entity.entity_type = 'ASSET'" +
@ -169,7 +171,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
" WHEN entity.entity_type = 'ENTITY_VIEW'" +
" THEN (select type from entity_view where id = entity_id)" +
" ELSE entity.entity_type END as type";
public static final String SELECT_LABEL = " CASE" +
private static final String SELECT_LABEL = " CASE" +
" WHEN entity.entity_type = 'TENANT'" +
" THEN (select title from tenant where id = entity_id)" +
" WHEN entity.entity_type = 'CUSTOMER' " +
@ -196,7 +198,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
entityTableMap.put(EntityType.TENANT, "tenant");
}
public static final String HIERARCHICAL_QUERY_TEMPLATE = " FROM (WITH RECURSIVE related_entities(from_id, from_type, to_id, to_type, relation_type, lvl) AS (" +
private static final String HIERARCHICAL_QUERY_TEMPLATE = " FROM (WITH RECURSIVE related_entities(from_id, from_type, to_id, to_type, relation_type, lvl) AS (" +
" SELECT from_id, from_type, to_id, to_type, relation_type, 1 as lvl" +
" FROM relation" +
" WHERE $in_id = :relation_root_id and $in_type = :relation_root_type and relation_type_group = 'COMMON'" +
@ -209,11 +211,16 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
" SELECT re.$out_id entity_id, re.$out_type entity_type, re.lvl lvl" +
" from related_entities re" +
" %s ) entity";
public static final String HIERARCHICAL_TO_QUERY_TEMPLATE = HIERARCHICAL_QUERY_TEMPLATE.replace("$in", "to").replace("$out", "from");
public static final String HIERARCHICAL_FROM_QUERY_TEMPLATE = HIERARCHICAL_QUERY_TEMPLATE.replace("$in", "from").replace("$out", "to");
private static final String HIERARCHICAL_TO_QUERY_TEMPLATE = HIERARCHICAL_QUERY_TEMPLATE.replace("$in", "to").replace("$out", "from");
private static final String HIERARCHICAL_FROM_QUERY_TEMPLATE = HIERARCHICAL_QUERY_TEMPLATE.replace("$in", "from").replace("$out", "to");
@Autowired
protected NamedParameterJdbcTemplate jdbcTemplate;
private final NamedParameterJdbcTemplate jdbcTemplate;
private final TransactionTemplate transactionTemplate;
public DefaultEntityQueryRepository(NamedParameterJdbcTemplate jdbcTemplate, TransactionTemplate transactionTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.transactionTemplate = transactionTemplate;
}
@Override
public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) {
@ -223,89 +230,91 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
ctx.append(addEntityTableQuery(ctx, query.getEntityFilter(), entityType));
ctx.append(" e where ");
ctx.append(buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), Collections.emptyList(), entityType));
return jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class);
return transactionTemplate.execute(status -> jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class));
}
@Override
public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
QueryContext ctx = new QueryContext();
EntityType entityType = resolveEntityType(query.getEntityFilter());
EntityDataPageLink pageLink = query.getPageLink();
List<EntityKeyMapping> mappings = EntityKeyMapping.prepareKeyMapping(query);
List<EntityKeyMapping> selectionMapping = mappings.stream().filter(EntityKeyMapping::isSelection)
.collect(Collectors.toList());
List<EntityKeyMapping> entityFieldsSelectionMapping = selectionMapping.stream().filter(mapping -> !mapping.isLatest())
.collect(Collectors.toList());
List<EntityKeyMapping> latestSelectionMapping = selectionMapping.stream().filter(EntityKeyMapping::isLatest)
.collect(Collectors.toList());
List<EntityKeyMapping> filterMapping = mappings.stream().filter(EntityKeyMapping::hasFilter)
.collect(Collectors.toList());
List<EntityKeyMapping> entityFieldsFiltersMapping = filterMapping.stream().filter(mapping -> !mapping.isLatest())
.collect(Collectors.toList());
List<EntityKeyMapping> latestFiltersMapping = filterMapping.stream().filter(EntityKeyMapping::isLatest)
.collect(Collectors.toList());
List<EntityKeyMapping> allLatestMappings = mappings.stream().filter(EntityKeyMapping::isLatest)
.collect(Collectors.toList());
String entityWhereClause = this.buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), entityFieldsFiltersMapping, entityType);
String latestJoins = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings);
String whereClause = this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType(), entityType);
String textSearchQuery = this.buildTextSearchQuery(ctx, selectionMapping, pageLink.getTextSearch());
String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType);
String entityTypeStr;
if (query.getEntityFilter().getType().equals(EntityFilterType.RELATIONS_QUERY)) {
entityTypeStr = "e.entity_type";
} else {
entityTypeStr = "'" + entityType.name() + "'";
}
if (!StringUtils.isEmpty(entityFieldsSelection)) {
entityFieldsSelection = String.format("e.id id, %s entity_type, %s", entityTypeStr, entityFieldsSelection);
} else {
entityFieldsSelection = String.format("e.id id, %s entity_type", entityTypeStr);
}
String latestSelection = EntityKeyMapping.buildSelections(latestSelectionMapping, query.getEntityFilter().getType(), entityType);
String topSelection = "entities.*";
if (!StringUtils.isEmpty(latestSelection)) {
topSelection = topSelection + ", " + latestSelection;
}
return transactionTemplate.execute(status -> {
QueryContext ctx = new QueryContext();
EntityType entityType = resolveEntityType(query.getEntityFilter());
EntityDataPageLink pageLink = query.getPageLink();
List<EntityKeyMapping> mappings = EntityKeyMapping.prepareKeyMapping(query);
List<EntityKeyMapping> selectionMapping = mappings.stream().filter(EntityKeyMapping::isSelection)
.collect(Collectors.toList());
List<EntityKeyMapping> entityFieldsSelectionMapping = selectionMapping.stream().filter(mapping -> !mapping.isLatest())
.collect(Collectors.toList());
List<EntityKeyMapping> latestSelectionMapping = selectionMapping.stream().filter(EntityKeyMapping::isLatest)
.collect(Collectors.toList());
List<EntityKeyMapping> filterMapping = mappings.stream().filter(EntityKeyMapping::hasFilter)
.collect(Collectors.toList());
List<EntityKeyMapping> entityFieldsFiltersMapping = filterMapping.stream().filter(mapping -> !mapping.isLatest())
.collect(Collectors.toList());
List<EntityKeyMapping> latestFiltersMapping = filterMapping.stream().filter(EntityKeyMapping::isLatest)
.collect(Collectors.toList());
List<EntityKeyMapping> allLatestMappings = mappings.stream().filter(EntityKeyMapping::isLatest)
.collect(Collectors.toList());
String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), entityFieldsFiltersMapping, entityType);
String latestJoins = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings);
String whereClause = DefaultEntityQueryRepository.this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType(), entityType);
String textSearchQuery = DefaultEntityQueryRepository.this.buildTextSearchQuery(ctx, selectionMapping, pageLink.getTextSearch());
String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType);
String entityTypeStr;
if (query.getEntityFilter().getType().equals(EntityFilterType.RELATIONS_QUERY)) {
entityTypeStr = "e.entity_type";
} else {
entityTypeStr = "'" + entityType.name() + "'";
}
if (!StringUtils.isEmpty(entityFieldsSelection)) {
entityFieldsSelection = String.format("e.id id, %s entity_type, %s", entityTypeStr, entityFieldsSelection);
} else {
entityFieldsSelection = String.format("e.id id, %s entity_type", entityTypeStr);
}
String latestSelection = EntityKeyMapping.buildSelections(latestSelectionMapping, query.getEntityFilter().getType(), entityType);
String topSelection = "entities.*";
if (!StringUtils.isEmpty(latestSelection)) {
topSelection = topSelection + ", " + latestSelection;
}
String fromClause = String.format("from (select %s from (select %s from %s e where %s) entities %s %s) result %s",
topSelection,
entityFieldsSelection,
addEntityTableQuery(ctx, query.getEntityFilter(), entityType),
entityWhereClause,
latestJoins,
whereClause,
textSearchQuery);
int totalElements = jdbcTemplate.queryForObject(String.format("select count(*) %s", fromClause), ctx, Integer.class);
String dataQuery = String.format("select * %s", fromClause);
EntityDataSortOrder sortOrder = pageLink.getSortOrder();
if (sortOrder != null) {
Optional<EntityKeyMapping> sortOrderMappingOpt = mappings.stream().filter(EntityKeyMapping::isSortOrder).findFirst();
if (sortOrderMappingOpt.isPresent()) {
EntityKeyMapping sortOrderMapping = sortOrderMappingOpt.get();
dataQuery = String.format("%s order by %s", dataQuery, sortOrderMapping.getValueAlias());
if (sortOrder.getDirection() == EntityDataSortOrder.Direction.ASC) {
dataQuery += " asc";
} else {
dataQuery += " desc";
String fromClause = String.format("from (select %s from (select %s from %s e where %s) entities %s %s) result %s",
topSelection,
entityFieldsSelection,
addEntityTableQuery(ctx, query.getEntityFilter(), entityType),
entityWhereClause,
latestJoins,
whereClause,
textSearchQuery);
int totalElements = jdbcTemplate.queryForObject(String.format("select count(*) %s", fromClause), ctx, Integer.class);
String dataQuery = String.format("select * %s", fromClause);
EntityDataSortOrder sortOrder = pageLink.getSortOrder();
if (sortOrder != null) {
Optional<EntityKeyMapping> sortOrderMappingOpt = mappings.stream().filter(EntityKeyMapping::isSortOrder).findFirst();
if (sortOrderMappingOpt.isPresent()) {
EntityKeyMapping sortOrderMapping = sortOrderMappingOpt.get();
dataQuery = String.format("%s order by %s", dataQuery, sortOrderMapping.getValueAlias());
if (sortOrder.getDirection() == EntityDataSortOrder.Direction.ASC) {
dataQuery += " asc";
} else {
dataQuery += " desc";
}
}
}
}
int startIndex = pageLink.getPageSize() * pageLink.getPage();
if (pageLink.getPageSize() > 0) {
dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
}
List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx);
return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements);
int startIndex = pageLink.getPageSize() * pageLink.getPage();
if (pageLink.getPageSize() > 0) {
dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
}
List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx);
return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements);
});
}
private String buildEntityWhere(QueryContext ctx,

Loading…
Cancel
Save