diff --git a/application/src/test/java/org/thingsboard/server/controller/EntityQueryControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EntityQueryControllerTest.java index e67707b0c8..8303d8b9fb 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EntityQueryControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EntityQueryControllerTest.java @@ -52,6 +52,7 @@ import org.thingsboard.server.common.data.query.EntityTypeFilter; import org.thingsboard.server.common.data.query.FilterPredicateValue; import org.thingsboard.server.common.data.query.KeyFilter; import org.thingsboard.server.common.data.query.NumericFilterPredicate; +import org.thingsboard.server.common.data.query.StringFilterPredicate; import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.common.data.queue.QueueStats; import org.thingsboard.server.common.data.security.Authority; @@ -642,4 +643,166 @@ public class EntityQueryControllerTest extends AbstractControllerTest { Assert.assertEquals(97, count.longValue()); } + @Test + public void testFindDevicesCountByOwnerNameAndOwnerType() throws Exception { + loginTenantAdmin(); + int numOfDevices = 8; + + for (int i = 0; i < numOfDevices; i++) { + Device device = new Device(); + String name = "Device" + i; + device.setName(name); + device.setType("default"); + + Device savedDevice = doPost("/api/device?accessToken=" + name, device, Device.class); + JsonNode content = JacksonUtil.toJsonNode("{\"alarmActiveTime\": 1" + i + "}"); + doPost("/api/plugins/telemetry/" + EntityType.DEVICE.name() + "/" + savedDevice.getUuidId() + "/SERVER_SCOPE", content) + .andExpect(status().isOk()); + } + + DeviceTypeFilter filter = new DeviceTypeFilter(); + filter.setDeviceTypes(List.of("default")); + filter.setDeviceNameFilter(""); + + KeyFilter activeAlarmTimeFilter = getServerAttributeNumericGreaterThanKeyFilter("alarmActiveTime", 5); + KeyFilter activeAlarmTimeToLongFilter = getServerAttributeNumericGreaterThanKeyFilter("alarmActiveTime", 30); + KeyFilter tenantOwnerNameFilter = getEntityFieldStringEqualToKeyFilter("ownerName", TEST_TENANT_NAME); + KeyFilter wrongOwnerNameFilter = getEntityFieldStringEqualToKeyFilter("ownerName", "wrongName"); + KeyFilter tenantOwnerTypeFilter = getEntityFieldStringEqualToKeyFilter("ownerType", "TENANT"); + KeyFilter customerOwnerTypeFilter = getEntityFieldStringEqualToKeyFilter("ownerType", "CUSTOMER"); + + // all devices with ownerName = TEST TENANT + EntityCountQuery query = new EntityCountQuery(filter, List.of(activeAlarmTimeFilter, tenantOwnerNameFilter)); + checkEntitiesCount(query, numOfDevices); + + // all devices with ownerName = TEST TENANT + EntityCountQuery activeAlarmTimeToLongQuery = new EntityCountQuery(filter, List.of(activeAlarmTimeToLongFilter, tenantOwnerNameFilter)); + checkEntitiesCount(activeAlarmTimeToLongQuery, 0); + + // all devices with wrong ownerName + EntityCountQuery wrongTenantNameQuery = new EntityCountQuery(filter, List.of(activeAlarmTimeFilter, wrongOwnerNameFilter)); + checkEntitiesCount(wrongTenantNameQuery, 0); + + // all devices with owner type = TENANT + EntityCountQuery tenantEntitiesQuery = new EntityCountQuery(filter, List.of(activeAlarmTimeFilter, tenantOwnerTypeFilter)); + checkEntitiesCount(tenantEntitiesQuery, numOfDevices); + + // all devices with owner type = CUSTOMER + EntityCountQuery customerEntitiesQuery = new EntityCountQuery(filter, List.of(activeAlarmTimeFilter, customerOwnerTypeFilter)); + checkEntitiesCount(customerEntitiesQuery, 0); + } + + @Test + public void testFindDevicesByOwnerNameAndOwnerType() throws Exception { + loginTenantAdmin(); + int numOfDevices = 3; + + for (int i = 0; i < numOfDevices; i++) { + Device device = new Device(); + String name = "Device" + i; + device.setName(name); + device.setType("default"); + + Device savedDevice = doPost("/api/device?accessToken=" + name, device, Device.class); + JsonNode content = JacksonUtil.toJsonNode("{\"alarmActiveTime\": 1" + i + "}"); + doPost("/api/plugins/telemetry/" + EntityType.DEVICE.name() + "/" + savedDevice.getUuidId() + "/SERVER_SCOPE", content) + .andExpect(status().isOk()); + } + + DeviceTypeFilter filter = new DeviceTypeFilter(); + filter.setDeviceTypes(List.of("default")); + filter.setDeviceNameFilter(""); + + KeyFilter activeAlarmTimeFilter = getServerAttributeNumericGreaterThanKeyFilter("alarmActiveTime", 5); + KeyFilter tenantOwnerNameFilter = getEntityFieldStringEqualToKeyFilter("ownerName", TEST_TENANT_NAME); + KeyFilter wrongOwnerNameFilter = getEntityFieldStringEqualToKeyFilter("ownerName", "wrongName"); + KeyFilter tenantOwnerTypeFilter = getEntityFieldStringEqualToKeyFilter("ownerType", "TENANT"); + KeyFilter customerOwnerTypeFilter = getEntityFieldStringEqualToKeyFilter("ownerType", "CUSTOMER"); + + EntityDataSortOrder sortOrder = new EntityDataSortOrder( + new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime"), EntityDataSortOrder.Direction.ASC + ); + EntityDataPageLink pageLink = new EntityDataPageLink(10, 0, null, sortOrder); + List entityFields = List.of(new EntityKey(EntityKeyType.ENTITY_FIELD, "name"), new EntityKey(EntityKeyType.ENTITY_FIELD, "ownerName"), + new EntityKey(EntityKeyType.ENTITY_FIELD, "ownerType")); + List latestValues = Collections.singletonList(new EntityKey(EntityKeyType.ATTRIBUTE, "alarmActiveTime")); + + // all devices with ownerName = TEST TENANT + EntityDataQuery query = new EntityDataQuery(filter, pageLink, entityFields, latestValues, List.of(activeAlarmTimeFilter, tenantOwnerNameFilter)); + checkEntitiesByQuery(query, numOfDevices, TEST_TENANT_NAME, "TENANT"); + + // all devices with wrong ownerName + EntityDataQuery wrongTenantNameQuery = new EntityDataQuery(filter, pageLink, entityFields, latestValues, List.of(activeAlarmTimeFilter, wrongOwnerNameFilter)); + checkEntitiesByQuery(wrongTenantNameQuery, 0, null, null); + + // all devices with owner type = TENANT + EntityDataQuery tenantEntitiesQuery = new EntityDataQuery(filter, pageLink, entityFields, latestValues, List.of(activeAlarmTimeFilter, tenantOwnerTypeFilter)); + checkEntitiesByQuery(tenantEntitiesQuery, numOfDevices, TEST_TENANT_NAME, "TENANT"); + + // all devices with owner type = CUSTOMER + EntityDataQuery customerEntitiesQuery = new EntityDataQuery(filter, pageLink, entityFields, latestValues, List.of(activeAlarmTimeFilter, customerOwnerTypeFilter)); + checkEntitiesByQuery(customerEntitiesQuery, 0, null, null); + } + + private void checkEntitiesByQuery(EntityDataQuery query, int expectedNumOfDevices, String expectedOwnerName, String expectedOwnerType) throws Exception { + Awaitility.await() + .alias("data by query") + .atMost(30, TimeUnit.SECONDS) + .until(() -> { + var data = doPostWithTypedResponse("/api/entitiesQuery/find", query, new TypeReference>() {}); + var loadedEntities = new ArrayList<>(data.getData()); + return loadedEntities.size() == expectedNumOfDevices; + }); + if (expectedNumOfDevices == 0) { + return; + } + var data = doPostWithTypedResponse("/api/entitiesQuery/find", query, new TypeReference>() {}); + var loadedEntities = new ArrayList<>(data.getData()); + + Assert.assertEquals(expectedNumOfDevices, loadedEntities.size()); + + for (int i = 0; i < expectedNumOfDevices; i++) { + var entity = loadedEntities.get(i); + String name = entity.getLatest().get(EntityKeyType.ENTITY_FIELD).getOrDefault("name", new TsValue(0, "Invalid")).getValue(); + String ownerName = entity.getLatest().get(EntityKeyType.ENTITY_FIELD).getOrDefault("ownerName", new TsValue(0, "Invalid")).getValue(); + String ownerType = entity.getLatest().get(EntityKeyType.ENTITY_FIELD).getOrDefault("ownerType", new TsValue(0, "Invalid")).getValue(); + String alarmActiveTime = entity.getLatest().get(EntityKeyType.ATTRIBUTE).getOrDefault("alarmActiveTime", new TsValue(0, "-1")).getValue(); + + Assert.assertEquals("Device" + i, name); + Assert.assertEquals( expectedOwnerName, ownerName); + Assert.assertEquals( expectedOwnerType, ownerType); + Assert.assertEquals("1" + i, alarmActiveTime); + } + } + + private void checkEntitiesCount(EntityCountQuery query, int expectedNumOfDevices) { + Awaitility.await() + .alias("count by query") + .atMost(30, TimeUnit.SECONDS) + .until(() -> { + var count = doPost("/api/entitiesQuery/count", query, Integer.class); + return count == expectedNumOfDevices; + }); + } + + private KeyFilter getEntityFieldStringEqualToKeyFilter(String keyName, String value) { + KeyFilter tenantOwnerNameFilter = new KeyFilter(); + tenantOwnerNameFilter.setKey(new EntityKey(EntityKeyType.ENTITY_FIELD, keyName)); + StringFilterPredicate ownerNamePredicate = new StringFilterPredicate(); + ownerNamePredicate.setValue(FilterPredicateValue.fromString(value)); + ownerNamePredicate.setOperation(StringFilterPredicate.StringOperation.EQUAL); + tenantOwnerNameFilter.setPredicate(ownerNamePredicate); + return tenantOwnerNameFilter; + } + + private KeyFilter getServerAttributeNumericGreaterThanKeyFilter(String attribute, int value) { + KeyFilter numericFilter = new KeyFilter(); + numericFilter.setKey(new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, attribute)); + NumericFilterPredicate predicate = new NumericFilterPredicate(); + predicate.setValue(FilterPredicateValue.fromDouble(value)); + predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); + numericFilter.setPredicate(predicate); + return numericFilter; + } + } 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 896fde6644..3203b72eca 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 @@ -359,7 +359,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { List filterMapping = mappings.stream().filter(EntityKeyMapping::hasFilter) .collect(Collectors.toList()); - List entityFieldsFiltersMapping = filterMapping.stream().filter(mapping -> !mapping.isLatest()) + List entityFieldsFiltersMapping = filterMapping.stream().filter(mapping -> !mapping.isLatest() && mapping.getEntityKeyColumn() != null) .collect(Collectors.toList()); List allLatestMappings = mappings.stream().filter(EntityKeyMapping::isLatest) @@ -367,6 +367,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, query.getEntityFilter(), entityFieldsFiltersMapping); + String aliasWhereQuery = DefaultEntityQueryRepository.this.buildAliasWhereQuery(ctx, query.getEntityFilter(), selectionMapping, ""); String latestJoinsCnt = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings, true); String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType); String entityTypeStr; @@ -387,7 +388,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { addEntityTableQuery(ctx, query.getEntityFilter()), entityWhereClause, latestJoinsCnt, - ""); + aliasWhereQuery); String countQuery = String.format("select count(id) %s", fromClauseCount); @@ -418,7 +419,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, entityType, ignorePermissionCheck)); EntityDataPageLink pageLink = query.getPageLink(); - List mappings = EntityKeyMapping.prepareKeyMapping(query); + List mappings = EntityKeyMapping.prepareKeyMapping(entityType, query); List selectionMapping = mappings.stream().filter(EntityKeyMapping::isSelection) .collect(Collectors.toList()); @@ -429,7 +430,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { List filterMapping = mappings.stream().filter(EntityKeyMapping::hasFilter) .collect(Collectors.toList()); - List entityFieldsFiltersMapping = filterMapping.stream().filter(mapping -> !mapping.isLatest()) + List entityFieldsFiltersMapping = filterMapping.stream().filter(mapping -> !mapping.isLatest() && mapping.getEntityKeyColumn() != null) .collect(Collectors.toList()); List allLatestMappings = mappings.stream().filter(EntityKeyMapping::isLatest) @@ -439,7 +440,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, query.getEntityFilter(), entityFieldsFiltersMapping); String latestJoinsCnt = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings, true); String latestJoinsData = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings, false); - String textSearchQuery = DefaultEntityQueryRepository.this.buildTextSearchQuery(ctx, selectionMapping, pageLink.getTextSearch()); + String aliasWhereQuery = DefaultEntityQueryRepository.this.buildAliasWhereQuery(ctx, query.getEntityFilter(), selectionMapping, pageLink.getTextSearch()); String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType); String entityTypeStr; if (query.getEntityFilter().getType().equals(EntityFilterType.RELATIONS_QUERY)) { @@ -465,7 +466,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { addEntityTableQuery(ctx, query.getEntityFilter()), entityWhereClause, latestJoinsCnt, - textSearchQuery); + aliasWhereQuery); String fromClauseData = String.format("from (select %s from (select %s from %s e where %s) entities %s ) result %s", topSelection, @@ -473,7 +474,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { addEntityTableQuery(ctx, query.getEntityFilter()), entityWhereClause, latestJoinsData, - textSearchQuery); + aliasWhereQuery); if (!StringUtils.isEmpty(pageLink.getTextSearch())) { //Unfortunately, we need to sacrifice performance in case of full text search, because it is applied to all joined records. @@ -800,6 +801,21 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { return from; } + private String buildAliasWhereQuery(QueryContext ctx, EntityFilter entityFilter, List selectionMapping, String searchText) { + List aliasFiltersMapping = selectionMapping.stream().filter(mapping -> !mapping.isLatest() && mapping.getEntityKeyColumn() == null) + .collect(Collectors.toList()); + String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, aliasFiltersMapping, entityFilter.getType()); + String searchTextQuery = buildTextSearchQuery(ctx, selectionMapping, searchText); + String result = ""; + if (!entityFieldsQuery.isEmpty()) { + result += " where (" + entityFieldsQuery + ")"; + } + if (!searchTextQuery.isEmpty()) { + result += (result.isEmpty() ? " where ": " and ") + "(" + searchTextQuery + ") "; + } + return result; + } + private String buildTextSearchQuery(QueryContext ctx, List selectionMapping, String searchText) { if (!StringUtils.isEmpty(searchText) && !selectionMapping.isEmpty()) { String sqlSearchText = "%" + searchText + "%"; @@ -811,7 +827,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { } else { searchAliasesExpression = searchAliases.get(0); } - return String.format(" WHERE %s ILIKE :%s", searchAliasesExpression, "lowerSearchTextParam"); + return String.format(" %s ILIKE :%s", searchAliasesExpression, "lowerSearchTextParam"); } else { return ""; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index df285657b3..c125639def 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -38,6 +38,7 @@ import org.thingsboard.server.dao.model.ModelConstants; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -48,6 +49,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static org.thingsboard.server.common.data.StringUtils.splitByCommaWithoutQuotes; +import static org.thingsboard.server.common.data.id.EntityId.NULL_UUID; +import static org.thingsboard.server.dao.sql.query.DefaultEntityQueryRepository.resolveEntityType; @Data public class EntityKeyMapping { @@ -55,6 +58,7 @@ public class EntityKeyMapping { private static final Map> allowedEntityFieldMap = new HashMap<>(); private static final Map entityFieldColumnMap = new HashMap<>(); private static final Map> aliases = new HashMap<>(); + private static final Map> propertiesFunctions = new EnumMap<>(EntityType.class); public static final String CREATED_TIME = "createdTime"; public static final String ENTITY_TYPE = "entityType"; @@ -77,6 +81,18 @@ public class EntityKeyMapping { public static final String RELATED_PARENT_ID = "parentId"; public static final String QUEUE_NAME = "queueName"; public static final String SERVICE_ID = "serviceId"; + public static final String OWNER_NAME = "ownerName"; + public static final String OWNER_TYPE = "ownerType"; + public static final String OWNER_NAME_SELECT_QUERY = "case when e.customer_id = '" + NULL_UUID + "' " + + "then (select title from tenant where id = e.tenant_id) " + + "else (select title from customer where id = e.customer_id) end"; + public static final String OWNER_TYPE_SELECT_QUERY = "case when e.customer_id = '" + NULL_UUID + "' " + + "then 'TENANT' " + + "else 'CUSTOMER' end"; + public static final Map ownerPropertiesFunctions = Map.of( + OWNER_NAME, OWNER_NAME_SELECT_QUERY, + OWNER_TYPE, OWNER_TYPE_SELECT_QUERY + ); public static final List typedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, ADDITIONAL_INFO); public static final List widgetEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME); @@ -145,6 +161,12 @@ public class EntityKeyMapping { aliases.put(EntityType.ENTITY_VIEW, commonEntityAliases); aliases.put(EntityType.WIDGETS_BUNDLE, commonEntityAliases); + propertiesFunctions.put(EntityType.DEVICE, ownerPropertiesFunctions); + propertiesFunctions.put(EntityType.ASSET, ownerPropertiesFunctions); + propertiesFunctions.put(EntityType.ENTITY_VIEW, ownerPropertiesFunctions); + propertiesFunctions.put(EntityType.USER, ownerPropertiesFunctions); + propertiesFunctions.put(EntityType.DASHBOARD, ownerPropertiesFunctions); + Map userEntityAliases = new HashMap<>(); userEntityAliases.put(TITLE, EMAIL); userEntityAliases.put(LABEL, EMAIL); @@ -155,6 +177,7 @@ public class EntityKeyMapping { private int index; private String alias; private boolean isLatest; + private String entityKeyColumn; private boolean isSelection; private boolean isSearchable; private boolean isSortOrder; @@ -184,12 +207,14 @@ public class EntityKeyMapping { if (entityKey.getKey().equals("entityType") && !filterType.equals(EntityFilterType.RELATIONS_QUERY)) { return String.format("'%s' as %s", entityType.name(), getValueAlias()); } else { - Set existingEntityFields = getExistingEntityFields(filterType, entityType); - String alias = getEntityFieldAlias(filterType, entityType); - if (existingEntityFields.contains(alias)) { - String column = entityFieldColumnMap.get(alias); - return String.format("cast(e.%s as varchar) as %s", column, getValueAlias()); + if (getEntityKeyColumn() != null) { + return String.format("cast(e.%s as varchar) as %s", getEntityKeyColumn(), getValueAlias()); } else { + Map entityPropertiesFunctions = propertiesFunctions.get(entityType); + String entityFieldAlias = getEntityFieldAlias(filterType, entityType); + if (entityPropertiesFunctions != null && entityPropertiesFunctions.containsKey(entityFieldAlias)) { + return String.format("%s as %s", entityPropertiesFunctions.get(entityFieldAlias), getValueAlias()); + } return String.format("'' as %s", getValueAlias()); } } @@ -239,7 +264,7 @@ public class EntityKeyMapping { public Stream toQueries(QueryContext ctx, EntityFilterType filterType) { if (hasFilter()) { - String keyAlias = entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) ? "e" : alias; + String keyAlias = (entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) && getEntityKeyColumn() != null) ? "e" : alias; return keyFilters.stream().map(keyFilter -> this.buildKeyQuery(ctx, keyAlias, keyFilter, filterType)); } else { @@ -319,7 +344,9 @@ public class EntityKeyMapping { .collect(Collectors.joining(" AND ")); } - public static List prepareKeyMapping(EntityDataQuery query) { + public static List prepareKeyMapping(EntityType entityType, EntityDataQuery query) { + EntityFilterType entityFilterType = query.getEntityFilter().getType(); + List entityFields = query.getEntityFields() != null ? query.getEntityFields() : Collections.emptyList(); List latestValues = query.getLatestValues() != null ? query.getLatestValues() : Collections.emptyList(); Map> filters = @@ -335,6 +362,7 @@ public class EntityKeyMapping { mapping.setSelection(true); mapping.setSearchable(!key.getKey().equals(ADDITIONAL_INFO)); mapping.setEntityKey(key); + mapping.setEntityKeyColumn(entityType, entityFilterType); return mapping; } ).collect(Collectors.toList()); @@ -366,6 +394,7 @@ public class EntityKeyMapping { sortOrderMapping.setEntityKey(sortOrderKey); sortOrderMapping.setSortOrder(true); sortOrderMapping.setIgnore(true); + sortOrderMapping.setEntityKeyColumn(entityType, entityFilterType); if (sortOrderKey.getType().equals(EntityKeyType.ENTITY_FIELD)) { entityFieldsMappings.add(sortOrderMapping); } else { @@ -393,8 +422,9 @@ public class EntityKeyMapping { mapping.setAlias(String.format("alias%s", index)); mapping.setKeyFilters(filters.get(filterField)); mapping.setLatest(!filterField.getType().equals(EntityKeyType.ENTITY_FIELD)); - mapping.setSelection(false); mapping.setEntityKey(filterField); + mapping.setEntityKeyColumn(entityType, entityFilterType); + mapping.setSelection(mapping.getEntityKeyColumn() == null); mappings.add(mapping); index += 1; } @@ -403,7 +433,18 @@ public class EntityKeyMapping { return mappings; } + private void setEntityKeyColumn(EntityType entityType, EntityFilterType entityFilterType) { + Set existingEntityFields = getExistingEntityFields(entityFilterType, entityType); + String entityFieldAlias = getEntityFieldAlias(entityFilterType, entityType); + if (existingEntityFields.contains(entityFieldAlias)) { + entityKeyColumn = entityFieldColumnMap.get(entityFieldAlias); + } + } + public static List prepareEntityCountKeyMapping(EntityCountQuery query) { + EntityType entityType = resolveEntityType(query.getEntityFilter()); + EntityFilterType entityFilterType = query.getEntityFilter().getType(); + Map> filters = query.getKeyFilters() != null ? query.getKeyFilters().stream().collect(Collectors.groupingBy(KeyFilter::getKey)) : Collections.emptyMap(); @@ -416,8 +457,9 @@ public class EntityKeyMapping { mapping.setAlias(String.format("alias%s", index)); mapping.setKeyFilters(filters.get(filterField)); mapping.setLatest(!filterField.getType().equals(EntityKeyType.ENTITY_FIELD)); - mapping.setSelection(false); mapping.setEntityKey(filterField); + mapping.setEntityKeyColumn(entityType, entityFilterType); + mapping.setSelection(mapping.getEntityKeyColumn() == null); mappings.add(mapping); index += 1; } @@ -494,30 +536,20 @@ public class EntityKeyMapping { private String buildSimplePredicateQuery(QueryContext ctx, String alias, EntityKey key, KeyFilterPredicate predicate, EntityFilterType filterType) { if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) { - Set existingEntityFields = getExistingEntityFields(filterType, ctx.getEntityType()); - String entityFieldAlias = getEntityFieldAlias(filterType, ctx.getEntityType()); - String column = null; - if (existingEntityFields.contains(entityFieldAlias)) { - column = entityFieldColumnMap.get(entityFieldAlias); - } - if (column != null) { - String field = alias + "." + column; - if (predicate.getType().equals(FilterPredicateType.NUMERIC)) { - return this.buildNumericPredicateQuery(ctx, field, (NumericFilterPredicate) predicate); - } else if (predicate.getType().equals(FilterPredicateType.STRING)) { - if (key.getKey().equals("entityType") && !filterType.equals(EntityFilterType.RELATIONS_QUERY)) { - field = ctx.getEntityType().toString(); - return this.buildStringPredicateQuery(ctx, field, (StringFilterPredicate) predicate) - .replace("lower(" + field, "lower('" + field + "'") - .replace(field + " ", "'" + field + "' "); - } else { - return this.buildStringPredicateQuery(ctx, field, (StringFilterPredicate) predicate); - } + String field = (getEntityKeyColumn() != null) ? alias + "." + getEntityKeyColumn() : alias; + if (predicate.getType().equals(FilterPredicateType.NUMERIC)) { + return this.buildNumericPredicateQuery(ctx, field, (NumericFilterPredicate) predicate); + } else if (predicate.getType().equals(FilterPredicateType.STRING)) { + if (key.getKey().equals("entityType") && !filterType.equals(EntityFilterType.RELATIONS_QUERY)) { + field = ctx.getEntityType().toString(); + return this.buildStringPredicateQuery(ctx, field, (StringFilterPredicate) predicate) + .replace("lower(" + field, "lower('" + field + "'") + .replace(field + " ", "'" + field + "' "); } else { - return this.buildBooleanPredicateQuery(ctx, field, (BooleanFilterPredicate) predicate); + return this.buildStringPredicateQuery(ctx, field, (StringFilterPredicate) predicate); } } else { - return null; + return this.buildBooleanPredicateQuery(ctx, field, (BooleanFilterPredicate) predicate); } } else { if (predicate.getType().equals(FilterPredicateType.NUMERIC)) { diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index ce1c26f17d..8777cc9780 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -766,6 +766,8 @@ export class EntityService { entityFieldKeys.push(entityFields.firstName.keyName); entityFieldKeys.push(entityFields.lastName.keyName); entityFieldKeys.push(entityFields.phone.keyName); + entityFieldKeys.push(entityFields.ownerName.keyName); + entityFieldKeys.push(entityFields.ownerType.keyName); break; case EntityType.TENANT: case EntityType.CUSTOMER: @@ -782,6 +784,8 @@ export class EntityService { case EntityType.ENTITY_VIEW: entityFieldKeys.push(entityFields.name.keyName); entityFieldKeys.push(entityFields.type.keyName); + entityFieldKeys.push(entityFields.ownerName.keyName); + entityFieldKeys.push(entityFields.ownerType.keyName); break; case EntityType.DEVICE: case EntityType.EDGE: @@ -789,9 +793,13 @@ export class EntityService { entityFieldKeys.push(entityFields.name.keyName); entityFieldKeys.push(entityFields.type.keyName); entityFieldKeys.push(entityFields.label.keyName); + entityFieldKeys.push(entityFields.ownerName.keyName); + entityFieldKeys.push(entityFields.ownerType.keyName); break; case EntityType.DASHBOARD: entityFieldKeys.push(entityFields.title.keyName); + entityFieldKeys.push(entityFields.ownerName.keyName); + entityFieldKeys.push(entityFields.ownerType.keyName); break; case EntityType.API_USAGE_STATE: entityFieldKeys.push(entityFields.name.keyName); diff --git a/ui-ngx/src/app/shared/models/entity.models.ts b/ui-ngx/src/app/shared/models/entity.models.ts index 9fc5e4fe3c..cf8acd1c33 100644 --- a/ui-ngx/src/app/shared/models/entity.models.ts +++ b/ui-ngx/src/app/shared/models/entity.models.ts @@ -171,6 +171,16 @@ export const entityFields: {[fieldName: string]: EntityField} = { keyName: 'serviceId', name: 'entity-field.service-id', value: 'serviceId' + }, + ownerName: { + keyName: 'ownerName', + name: 'entity-field.owner-name', + value: 'ownerName' + }, + ownerType: { + keyName: 'ownerType', + name: 'entity-field.owner-type', + value: 'ownerType' } }; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 1ba94ab8bb..4117492c6a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2273,7 +2273,9 @@ "phone": "Phone", "label": "Label", "queue-name": "Queue name", - "service-id": "Service Id" + "service-id": "Service Id", + "owner-name": "Owner name", + "owner-type": "Owner type" }, "entity-view": { "entity-view": "Entity view",