diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 1d429e9157..f64dea7b8d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; @@ -41,6 +42,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.query.EntityQueryService; import org.thingsboard.server.service.security.permission.Operation; +import java.util.List; +import java.util.Map; + import static org.thingsboard.server.controller.ControllerConstants.ALARM_DATA_QUERY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_COUNT_QUERY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_DATA_QUERY_DESCRIPTION; @@ -66,6 +70,17 @@ public class EntityQueryController extends BaseController { return this.entityQueryService.countEntitiesByQuery(getCurrentUser(), query); } + @ApiOperation(value = "Count Entities by Entity Types") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") + @RequestMapping(value = "/entitiesTypes/count", method = RequestMethod.POST) + @ResponseBody + public Map countEntitiesByQuery( + @ApiParam(value = "A JSON value representing the entity types array.") + @RequestBody List entityTypes) throws ThingsboardException { + checkNotNull(entityTypes); + return this.entityQueryService.countEntitiesByTypes(getCurrentUser(), entityTypes); + } + @ApiOperation(value = "Find Entity Data by Query", notes = ENTITY_DATA_QUERY_DESCRIPTION) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/find", method = RequestMethod.POST) diff --git a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java index 5a9d0d9edf..154f64202a 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java @@ -102,6 +102,11 @@ public class DefaultEntityQueryService implements EntityQueryService { return entityService.countEntitiesByQuery(securityUser.getTenantId(), securityUser.getCustomerId(), query); } + @Override + public Map countEntitiesByTypes(SecurityUser securityUser, List entityTypes) { + return entityService.countEntitiesByTypes(securityUser.getTenantId(), securityUser.getCustomerId(), entityTypes); + } + @Override public PageData findEntityDataByQuery(SecurityUser securityUser, EntityDataQuery query) { if (query.getKeyFilters() != null) { diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java index b03fb02b33..8a37eadb70 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.query; import org.springframework.http.ResponseEntity; import org.springframework.web.context.request.async.DeferredResult; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; @@ -26,10 +27,15 @@ import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataQuery; import org.thingsboard.server.service.security.model.SecurityUser; +import java.util.List; +import java.util.Map; + public interface EntityQueryService { long countEntitiesByQuery(SecurityUser securityUser, EntityCountQuery query); + Map countEntitiesByTypes(SecurityUser securityUser, List entityTypes); + PageData findEntityDataByQuery(SecurityUser securityUser, EntityDataQuery query); PageData findAlarmDataByQuery(SecurityUser securityUser, AlarmDataQuery query); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java index f2317efa05..23e33b26e5 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.entity; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.NameLabelAndCustomerDetails; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; @@ -24,6 +25,8 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataQuery; +import java.util.List; +import java.util.Map; import java.util.Optional; public interface EntityService { @@ -38,5 +41,7 @@ public interface EntityService { long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); + Map countEntitiesByTypes(TenantId tenantId, CustomerId customerId, List entityTypes); + PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index cbce9e48a1..f4ce434635 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasEmail; import org.thingsboard.server.common.data.HasLabel; @@ -38,6 +39,8 @@ import org.thingsboard.server.common.data.query.EntityFilterType; import org.thingsboard.server.common.data.query.RelationsQueryFilter; import org.thingsboard.server.dao.exception.IncorrectParameterException; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Function; @@ -71,6 +74,14 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe return this.entityQueryDao.countEntitiesByQuery(tenantId, customerId, query); } + @Override + public Map countEntitiesByTypes(TenantId tenantId, CustomerId customerId, List entityTypes) { + log.trace("Executing countEntitiesByQuery, tenantId [{}], customerId [{}], entityTypes [{}]", tenantId, customerId, entityTypes); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + return this.entityQueryDao.countEntitiesByTypes(tenantId, customerId, entityTypes); + } + @Override public PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) { log.trace("Executing findEntityDataByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/EntityQueryDao.java b/dao/src/main/java/org/thingsboard/server/dao/entity/EntityQueryDao.java index 9fafe2e0f0..bcdde392dc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/EntityQueryDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/EntityQueryDao.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.entity; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -22,10 +23,15 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataQuery; +import java.util.List; +import java.util.Map; + public interface EntityQueryDao { long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query); + Map countEntitiesByTypes(TenantId tenantId, CustomerId customerId, List entityTypes); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index 821dbcc011..c4bf057efd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.query.SingleEntityFilter; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -388,6 +389,61 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { return findEntityDataByQuery(tenantId, customerId, query, false); } + @Override + public Map countEntitiesByTypes(TenantId tenantId, CustomerId customerId, List entityTypes) { + int size = entityTypes.size(); + + QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, null, true)); + ctx.append("select "); + + for (int i = 0; i < size; i++) { + ctx.append("(select count(*) from "); + ctx.append(getTableName(entityTypes.get(i))); + ctx.append(")"); + if (i < size - 1) { + ctx.append(", "); + } + } + + return transactionTemplate.execute(status -> { + long startTs = System.currentTimeMillis(); + try { + List counts = jdbcTemplate.query(ctx.getQuery(), rs -> { + List result = new ArrayList<>(); + if (rs.next()) { + for (int i = 1; i <= size; i++) { + result.add(rs.getLong(i)); + } + } + return result; + }); + + Map result = new HashMap<>(size); + for (int i = 0; i < size; i++) { + result.put(entityTypes.get(i), counts.get(i)); + } + return result; + } finally { + queryLog.logQuery(ctx, ctx.getQuery(), System.currentTimeMillis() - startTs); + } + }); + } + + private String getTableName(EntityType entityType) { + switch (entityType) { + case TENANT: + case TENANT_PROFILE: + case CUSTOMER: + case DEVICE: + case ASSET: + return entityType.name().toLowerCase(); + case USER: + return "tb_user"; + default: + throw new IllegalArgumentException("Not supported entity type: " + entityType + "!"); + } + } + public PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query, boolean ignorePermissionCheck) { return transactionTemplate.execute(status -> { EntityType entityType = resolveEntityType(query.getEntityFilter()); @@ -514,7 +570,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { } private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter) { - if(ctx.isIgnorePermissionCheck()){ + if (ctx.isIgnorePermissionCheck()) { return "1=1"; } switch (entityFilter.getType()) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityQueryRepository.java index 7d78a34981..5fd91057ce 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityQueryRepository.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.sql.query; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -22,6 +23,9 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataQuery; +import java.util.List; +import java.util.Map; + public interface EntityQueryRepository { long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); @@ -30,4 +34,6 @@ public interface EntityQueryRepository { PageData findEntityDataByQueryInternal(EntityDataQuery query); + Map countEntitiesByTypes(TenantId tenantId, CustomerId customerId, List entityTypes); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/JpaEntityQueryDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/JpaEntityQueryDao.java index 33d9426bdf..3929c98eec 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/JpaEntityQueryDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/JpaEntityQueryDao.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.sql.query; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -25,6 +26,9 @@ import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataQuery; import org.thingsboard.server.dao.entity.EntityQueryDao; +import java.util.List; +import java.util.Map; + @Component public class JpaEntityQueryDao implements EntityQueryDao { @@ -40,4 +44,9 @@ public class JpaEntityQueryDao implements EntityQueryDao { public PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) { return entityQueryRepository.findEntityDataByQuery(tenantId, customerId, query); } + + @Override + public Map countEntitiesByTypes(TenantId tenantId, CustomerId customerId, List entityTypes) { + return entityQueryRepository.countEntitiesByTypes(tenantId, customerId, entityTypes); + } }