Browse Source

Refactoring of QueryContext

pull/3104/head
Andrii Shvaika 6 years ago
parent
commit
da0ffdc28a
  1. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java
  2. 53
      dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java
  3. 28
      dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java
  4. 19
      dao/src/main/java/org/thingsboard/server/dao/sql/query/QueryContext.java
  5. 42
      dao/src/main/java/org/thingsboard/server/dao/sql/query/QuerySecurityContext.java

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

@ -124,7 +124,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
AlarmDataQuery query, Collection<EntityId> orderedEntityIds) {
return transactionTemplate.execute(status -> {
AlarmDataPageLink pageLink = query.getPageLink();
QueryContext ctx = new QueryContext();
QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, EntityType.ALARM));
ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList()));
StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION);

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

@ -227,11 +227,11 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
@Override
public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) {
EntityType entityType = resolveEntityType(query.getEntityFilter());
QueryContext ctx = new QueryContext();
QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, entityType));
ctx.append("select count(e.id) from ");
ctx.append(addEntityTableQuery(ctx, query.getEntityFilter(), entityType));
ctx.append(addEntityTableQuery(ctx, query.getEntityFilter()));
ctx.append(" e where ");
ctx.append(buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), Collections.emptyList(), entityType));
ctx.append(buildEntityWhere(ctx, query.getEntityFilter(), Collections.emptyList()));
// log.error("QUERY: {}", ctx.getQuery());
// Arrays.asList(ctx.getParameterNames()).forEach(param -> log.error("QUERY PARAM: {}->{}", param, ctx.getValue(param)));
return transactionTemplate.execute(status -> jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class));
@ -240,8 +240,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
@Override
public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
return transactionTemplate.execute(status -> {
QueryContext ctx = new QueryContext();
EntityType entityType = resolveEntityType(query.getEntityFilter());
QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, entityType));
EntityDataPageLink pageLink = query.getPageLink();
List<EntityKeyMapping> mappings = EntityKeyMapping.prepareKeyMapping(query);
@ -264,9 +264,9 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
.collect(Collectors.toList());
String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), entityFieldsFiltersMapping, entityType);
String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, query.getEntityFilter(), entityFieldsFiltersMapping);
String latestJoins = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings);
String whereClause = DefaultEntityQueryRepository.this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType(), entityType);
String whereClause = DefaultEntityQueryRepository.this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType());
String textSearchQuery = DefaultEntityQueryRepository.this.buildTextSearchQuery(ctx, selectionMapping, pageLink.getTextSearch());
String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType);
String entityTypeStr;
@ -289,7 +289,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
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),
addEntityTableQuery(ctx, query.getEntityFilter()),
entityWhereClause,
latestJoins,
whereClause,
@ -323,15 +323,10 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
});
}
private String buildEntityWhere(QueryContext ctx,
TenantId tenantId,
CustomerId customerId,
EntityFilter entityFilter,
List<EntityKeyMapping> entityFieldsFilters,
EntityType entityType) {
String permissionQuery = this.buildPermissionQuery(ctx, entityFilter, tenantId, customerId, entityType);
private String buildEntityWhere(QueryContext ctx, EntityFilter entityFilter, List<EntityKeyMapping> entityFieldsFilters) {
String permissionQuery = this.buildPermissionQuery(ctx, entityFilter);
String entityFilterQuery = this.buildEntityFilterQuery(ctx, entityFilter);
String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType(), entityType);
String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType());
String result = permissionQuery;
if (!entityFilterQuery.isEmpty()) {
result += " and " + entityFilterQuery;
@ -342,28 +337,28 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
return result;
}
private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter, TenantId tenantId, CustomerId customerId, EntityType entityType) {
private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter) {
switch (entityFilter.getType()) {
case RELATIONS_QUERY:
case DEVICE_SEARCH_QUERY:
case ASSET_SEARCH_QUERY:
case ENTITY_VIEW_SEARCH_QUERY:
return this.defaultPermissionQuery(ctx, tenantId, customerId, entityType);
return this.defaultPermissionQuery(ctx);
default:
if (entityType == EntityType.TENANT) {
ctx.addUuidParameter("permissions_tenant_id", tenantId.getId());
if (ctx.getEntityType() == EntityType.TENANT) {
ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId());
return "e.id=:permissions_tenant_id";
} else {
return this.defaultPermissionQuery(ctx, tenantId, customerId, entityType);
return this.defaultPermissionQuery(ctx);
}
}
}
private String defaultPermissionQuery(QueryContext ctx, TenantId tenantId, CustomerId customerId, EntityType entityType) {
ctx.addUuidParameter("permissions_tenant_id", tenantId.getId());
if (customerId != null && !customerId.isNullUid()) {
ctx.addUuidParameter("permissions_customer_id", customerId.getId());
if (entityType == EntityType.CUSTOMER) {
private String defaultPermissionQuery(QueryContext ctx) {
ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId());
if (ctx.getCustomerId() != null && !ctx.getCustomerId().isNullUid()) {
ctx.addUuidParameter("permissions_customer_id", ctx.getCustomerId().getId());
if (ctx.getEntityType() == EntityType.CUSTOMER) {
return "e.tenant_id=:permissions_tenant_id and e.id=:permissions_customer_id";
} else {
return "e.tenant_id=:permissions_tenant_id and e.customer_id=:permissions_customer_id";
@ -395,7 +390,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
}
}
private String addEntityTableQuery(QueryContext ctx, EntityFilter entityFilter, EntityType entityType) {
private String addEntityTableQuery(QueryContext ctx, EntityFilter entityFilter) {
switch (entityFilter.getType()) {
case RELATIONS_QUERY:
return relationQuery(ctx, (RelationsQueryFilter) entityFilter);
@ -409,7 +404,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
EntityViewSearchQueryFilter entityViewQuery = (EntityViewSearchQueryFilter) entityFilter;
return entitySearchQuery(ctx, entityViewQuery, EntityType.ENTITY_VIEW, entityViewQuery.getEntityViewTypes());
default:
return entityTableMap.get(entityType);
return entityTableMap.get(ctx.getEntityType());
}
}
@ -505,8 +500,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
return from;
}
private String buildWhere(QueryContext ctx, List<EntityKeyMapping> latestFiltersMapping, EntityFilterType filterType, EntityType entityType) {
String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping, filterType, entityType);
private String buildWhere(QueryContext ctx, List<EntityKeyMapping> latestFiltersMapping, EntityFilterType filterType) {
String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping, filterType);
if (!StringUtils.isEmpty(latestFilters)) {
return String.format("where %s", latestFilters);
} else {

28
dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java

@ -214,11 +214,11 @@ public class EntityKeyMapping {
return alias;
}
public Stream<String> toQueries(QueryContext ctx, EntityFilterType filterType, EntityType entityType) {
public Stream<String> toQueries(QueryContext ctx, EntityFilterType filterType) {
if (hasFilter()) {
String keyAlias = entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) ? "e" : alias;
return keyFilters.stream().map(keyFilter ->
this.buildKeyQuery(ctx, keyAlias, keyFilter, filterType, entityType));
this.buildKeyQuery(ctx, keyAlias, keyFilter, filterType));
} else {
return null;
}
@ -271,8 +271,8 @@ public class EntityKeyMapping {
Collectors.joining(" "));
}
public static String buildQuery(QueryContext ctx, List<EntityKeyMapping> mappings, EntityFilterType filterType, EntityType entityType) {
return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx, filterType, entityType)).filter(Objects::nonNull).collect(
public static String buildQuery(QueryContext ctx, List<EntityKeyMapping> mappings, EntityFilterType filterType) {
return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx, filterType)).filter(Objects::nonNull).collect(
Collectors.joining(" AND "));
}
@ -385,33 +385,33 @@ public class EntityKeyMapping {
}
private String buildKeyQuery(QueryContext ctx, String alias, KeyFilter keyFilter,
EntityFilterType filterType, EntityType entityType) {
return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate(), filterType, entityType);
EntityFilterType filterType) {
return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate(), filterType);
}
private String buildPredicateQuery(QueryContext ctx, String alias, EntityKey key,
KeyFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) {
KeyFilterPredicate predicate, EntityFilterType filterType) {
if (predicate.getType().equals(FilterPredicateType.COMPLEX)) {
return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate, filterType, entityType);
return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate, filterType);
} else {
return this.buildSimplePredicateQuery(ctx, alias, key, predicate, filterType, entityType);
return this.buildSimplePredicateQuery(ctx, alias, key, predicate, filterType);
}
}
private String buildComplexPredicateQuery(QueryContext ctx, String alias, EntityKey key,
ComplexFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) {
ComplexFilterPredicate predicate, EntityFilterType filterType) {
return predicate.getPredicates().stream()
.map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate, filterType, entityType))
.map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate, filterType))
.filter(Objects::nonNull).collect(Collectors.joining(
" " + predicate.getOperation().name() + " "
));
}
private String buildSimplePredicateQuery(QueryContext ctx, String alias, EntityKey key,
KeyFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) {
KeyFilterPredicate predicate, EntityFilterType filterType) {
if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) {
Set<String> existingEntityFields = getExistingEntityFields(filterType, entityType);
String entityFieldAlias = getEntityFieldAlias(filterType, entityType);
Set<String> existingEntityFields = getExistingEntityFields(filterType, ctx.getEntityType());
String entityFieldAlias = getEntityFieldAlias(filterType, ctx.getEntityType());
String column = null;
if (existingEntityFields.contains(entityFieldAlias)) {
column = entityFieldColumnMap.get(entityFieldAlias);

19
dao/src/main/java/org/thingsboard/server/dao/sql/query/QueryContext.java

@ -17,6 +17,9 @@ package org.thingsboard.server.dao.sql.query;
import org.hibernate.type.PostgresUUIDType;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import java.sql.Types;
import java.util.HashMap;
@ -27,10 +30,12 @@ import java.util.UUID;
public class QueryContext implements SqlParameterSource {
private static final PostgresUUIDType UUID_TYPE = new PostgresUUIDType();
private final QuerySecurityContext securityCtx;
private final StringBuilder query;
private final Map<String, Parameter> params;
public QueryContext() {
public QueryContext(QuerySecurityContext securityCtx) {
this.securityCtx = securityCtx;
query = new StringBuilder();
params = new HashMap<>();
}
@ -123,4 +128,16 @@ public class QueryContext implements SqlParameterSource {
this.name = name;
}
}
public TenantId getTenantId() {
return securityCtx.getTenantId();
}
public CustomerId getCustomerId() {
return securityCtx.getCustomerId();
}
public EntityType getEntityType() {
return securityCtx.getEntityType();
}
}

42
dao/src/main/java/org/thingsboard/server/dao/sql/query/QuerySecurityContext.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.query;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.hibernate.type.PostgresUUIDType;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import java.sql.Types;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@AllArgsConstructor
public class QuerySecurityContext {
@Getter
private final TenantId tenantId;
@Getter
private final CustomerId customerId;
@Getter
private final EntityType entityType;
}
Loading…
Cancel
Save