@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.permission.QueryContext ;
import org.thingsboard.server.common.data.query.ApiUsageStateFilter ;
import org.thingsboard.server.common.data.query.AssetSearchQueryFilter ;
import org.thingsboard.server.common.data.query.ComplexOperation ;
import org.thingsboard.server.common.data.query.AssetTypeFilter ;
import org.thingsboard.server.common.data.query.DeviceSearchQueryFilter ;
import org.thingsboard.server.common.data.query.DeviceTypeFilter ;
@ -54,6 +55,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 ;
@ -351,25 +353,48 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
}
} ) ;
} else {
List < EntityKeyMapping > mappings = EntityKeyMapping . prepareEntityCountKeyMapping ( query ) ;
ComplexOperation operation = query . getKeyFiltersOperationOrDefault ( ) ;
boolean isOr = operation = = ComplexOperation . OR ;
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 > mappings = EntityKeyMapping . prepareEntityCountKeyMapping ( query ) ;
List < EntityKeyMapping > selectionMapping = new ArrayList < > ( mappings . stream ( ) . filter ( EntityKeyMapping : : isSelection )
. collect ( Collectors . toList ( ) ) ) ;
List < EntityKeyMapping > filterMapping = mappings . stream ( ) . filter ( EntityKeyMapping : : hasFilter )
. collect ( Collectors . toList ( ) ) ;
List < EntityKeyMapping > entityFieldsFiltersMapping = filterMapping . stream ( ) . filter ( mapping - > ! mapping . isLatest ( ) & & mapping . getEntityKeyColumn ( ) ! = null )
. collect ( Collectors . toList ( ) ) ;
// Under OR: entity field filter columns must be in inner SELECT for outer WHERE reference
if ( isOr ) {
for ( EntityKeyMapping m : entityFieldsFiltersMapping ) {
if ( ! selectionMapping . contains ( m ) ) {
selectionMapping . add ( m ) ;
}
}
}
List < EntityKeyMapping > entityFieldsSelectionMapping = selectionMapping . stream ( ) . filter ( mapping - > ! mapping . isLatest ( ) )
. collect ( Collectors . toList ( ) ) ;
List < EntityKeyMapping > allLatestMappings = mappings . stream ( ) . filter ( EntityKeyMapping : : isLatest )
. collect ( Collectors . toList ( ) ) ;
// Under OR: entity field filters move to outer WHERE (not inner WHERE)
List < EntityKeyMapping > innerEntityFieldsFilters = isOr ? Collections . emptyList ( ) : entityFieldsFiltersMapping ;
String entityWhereClause = DefaultEntityQueryRepository . this . buildEntityWhere ( ctx , query . getEntityFilter ( ) , innerEntityFieldsFilters ) ;
String latestJoinsCnt = EntityKeyMapping . buildLatestJoins ( ctx , query . getEntityFilter ( ) , entityType , allLatestMappings , true , isOr ) ;
// Under OR: combine ALL filter mappings (entity fields + aliases) in outer WHERE with OR joiner
String aliasWhereQuery ;
if ( isOr ) {
String combinedFilterQuery = EntityKeyMapping . buildQuery ( ctx , filterMapping , query . getEntityFilter ( ) . getType ( ) , ComplexOperation . OR ) ;
aliasWhereQuery = combinedFilterQuery . isEmpty ( ) ? "" : " where (" + combinedFilterQuery + ")" ;
} else {
aliasWhereQuery = DefaultEntityQueryRepository . this . buildAliasWhereQuery ( ctx , query . getEntityFilter ( ) , selectionMapping , "" ) ;
}
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 ;
if ( query . getEntityFilter ( ) . getType ( ) . equals ( EntityFilterType . RELATIONS_QUERY ) ) {
@ -419,13 +444,13 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
EntityType entityType = resolveEntityType ( query . getEntityFilter ( ) ) ;
SqlQueryContext ctx = new SqlQueryContext ( new QueryContext ( tenantId , customerId , entityType , ignorePermissionCheck ) ) ;
EntityDataPageLink pageLink = query . getPageLink ( ) ;
ComplexOperation operation = query . getKeyFiltersOperationOrDefault ( ) ;
boolean isOr = operation = = ComplexOperation . OR ;
List < EntityKeyMapping > mappings = EntityKeyMapping . prepareKeyMapping ( entityType , 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 > selectionMapping = new ArrayList < > ( mappings . stream ( ) . filter ( EntityKeyMapping : : isSelection )
. collect ( Collectors . toList ( ) ) ) ;
List < EntityKeyMapping > latestSelectionMapping = selectionMapping . stream ( ) . filter ( EntityKeyMapping : : isLatest )
. collect ( Collectors . toList ( ) ) ;
@ -434,14 +459,44 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
List < EntityKeyMapping > entityFieldsFiltersMapping = filterMapping . stream ( ) . filter ( mapping - > ! mapping . isLatest ( ) & & mapping . getEntityKeyColumn ( ) ! = null )
. collect ( Collectors . toList ( ) ) ;
// Under OR: entity field filter columns must be in inner SELECT for outer WHERE reference
if ( isOr ) {
for ( EntityKeyMapping m : entityFieldsFiltersMapping ) {
if ( ! selectionMapping . contains ( m ) ) {
selectionMapping . add ( m ) ;
}
}
}
List < EntityKeyMapping > entityFieldsSelectionMapping = selectionMapping . stream ( ) . filter ( mapping - > ! mapping . isLatest ( ) )
. collect ( Collectors . toList ( ) ) ;
List < EntityKeyMapping > allLatestMappings = mappings . stream ( ) . filter ( EntityKeyMapping : : isLatest )
. collect ( Collectors . toList ( ) ) ;
// Under OR: entity field filters move to outer WHERE (not inner WHERE)
List < EntityKeyMapping > innerEntityFieldsFilters = isOr ? Collections . emptyList ( ) : entityFieldsFiltersMapping ;
String entityWhereClause = DefaultEntityQueryRepository . this . buildEntityWhere ( ctx , query . getEntityFilter ( ) , innerEntityFieldsFilters ) ;
String latestJoinsCnt = EntityKeyMapping . buildLatestJoins ( ctx , query . getEntityFilter ( ) , entityType , allLatestMappings , true , isOr ) ;
String latestJoinsData = EntityKeyMapping . buildLatestJoins ( ctx , query . getEntityFilter ( ) , entityType , allLatestMappings , false , isOr ) ;
// Under OR: combine ALL filter mappings (entity fields + aliases) in outer WHERE with OR joiner
String aliasWhereQuery ;
if ( isOr ) {
String combinedFilterQuery = EntityKeyMapping . buildQuery ( ctx , filterMapping , query . getEntityFilter ( ) . getType ( ) , ComplexOperation . OR ) ;
String searchTextQuery = buildTextSearchQuery ( ctx , selectionMapping , pageLink . getTextSearch ( ) ) ;
aliasWhereQuery = "" ;
if ( ! combinedFilterQuery . isEmpty ( ) ) {
aliasWhereQuery = " where (" + combinedFilterQuery + ")" ;
}
if ( ! searchTextQuery . isEmpty ( ) ) {
aliasWhereQuery + = ( aliasWhereQuery . isEmpty ( ) ? " where " : " and " ) + "(" + searchTextQuery + ") " ;
}
} else {
aliasWhereQuery = DefaultEntityQueryRepository . this . buildAliasWhereQuery ( ctx , query . getEntityFilter ( ) , selectionMapping , pageLink . getTextSearch ( ) ) ;
}
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 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 ) ) {