Merge pull request #12991 from dashevchenko/edqs_numeric_sort_fix
Fixed edqs sorting for numeric values
This commit is contained in:
		
						commit
						d92d32eec0
					
				@ -110,7 +110,7 @@ public class EdqsEntityServiceTest extends EntityServiceTest {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected List<EntityData> findByQueryAndCheckTelemetry(EntityDataQuery query, EntityKeyType entityKeyType, String key, List<String> expectedTelemetries) {
 | 
			
		||||
        return await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> findEntitiesTelemetry(query, entityKeyType, key, expectedTelemetries),
 | 
			
		||||
        return await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> loadAllData(query, expectedTelemetries.size()),
 | 
			
		||||
                loadedEntities -> loadedEntities.stream().map(entityData -> entityData.getLatest().get(entityKeyType).get(key).getValue()).toList().containsAll(expectedTelemetries));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1698,6 +1698,19 @@ public class EntityServiceTest extends AbstractControllerTest {
 | 
			
		||||
        query = new EntityDataQuery(filter, pageLink, entityFields, latestValues, keyFilters);
 | 
			
		||||
        findByQueryAndCheckTelemetry(query, EntityKeyType.TIME_SERIES, "temperature", deviceHighTemperatures);
 | 
			
		||||
 | 
			
		||||
        // change sort order to sort by temperature
 | 
			
		||||
        temperatures.sort(Comparator.naturalOrder());
 | 
			
		||||
        List<String> expectedSortedList = temperatures.stream().map(aDouble -> Double.toString(aDouble)).collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        EntityDataSortOrder sortByTempOrder = new EntityDataSortOrder(
 | 
			
		||||
                new EntityKey(EntityKeyType.TIME_SERIES, "temperature"), EntityDataSortOrder.Direction.ASC);
 | 
			
		||||
        EntityDataPageLink sortByTempPageLink = new EntityDataPageLink(10, 0, null, sortByTempOrder);
 | 
			
		||||
        EntityDataQuery querySortByTemp = new EntityDataQuery(filter, sortByTempPageLink, entityFields, latestValues, null);
 | 
			
		||||
 | 
			
		||||
        List<EntityData> loadedEntities = loadAllData(querySortByTemp, deviceTemperatures.size());
 | 
			
		||||
        List<String> entitiesTelemetry = loadedEntities.stream().map(entityData -> entityData.getLatest().get(EntityKeyType.TIME_SERIES).get("temperature").getValue()).toList();
 | 
			
		||||
        assertThat(entitiesTelemetry).containsExactlyElementsOf(expectedSortedList);
 | 
			
		||||
 | 
			
		||||
        deviceService.deleteDevicesByTenantId(tenantId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2377,14 +2390,14 @@ public class EntityServiceTest extends AbstractControllerTest {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected List<EntityData> findByQueryAndCheckTelemetry(EntityDataQuery query, EntityKeyType entityKeyType, String key, List<String> expectedTelemetry) {
 | 
			
		||||
        List<EntityData> loadedEntities = findEntitiesTelemetry(query, entityKeyType, key, expectedTelemetry);
 | 
			
		||||
        List<EntityData> loadedEntities = loadAllData(query, expectedTelemetry.size());
 | 
			
		||||
        List<String> entitiesTelemetry = loadedEntities.stream().map(entityData -> entityData.getLatest().get(entityKeyType).get(key).getValue()).toList();
 | 
			
		||||
        assertThat(entitiesTelemetry).containsExactlyInAnyOrderElementsOf(expectedTelemetry);
 | 
			
		||||
        return loadedEntities;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected List<EntityData> findEntitiesTelemetry(EntityDataQuery query, EntityKeyType entityKeyType, String key, List<String> expectedTelemetries) {
 | 
			
		||||
        PageData<EntityData> data = findByQueryAndCheck(query, expectedTelemetries.size());
 | 
			
		||||
    protected List<EntityData> loadAllData(EntityDataQuery query, int expectedSize) {
 | 
			
		||||
        PageData<EntityData> data = findByQueryAndCheck(query, expectedSize);
 | 
			
		||||
        List<EntityData> loadedEntities = new ArrayList<>(data.getData());
 | 
			
		||||
        while (data.hasNext()) {
 | 
			
		||||
            query = query.next();
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.edqs;
 | 
			
		||||
 | 
			
		||||
import org.thingsboard.server.common.data.kv.DataType;
 | 
			
		||||
 | 
			
		||||
public interface DataPoint {
 | 
			
		||||
public interface DataPoint extends Comparable<DataPoint> {
 | 
			
		||||
 | 
			
		||||
    String NOT_SUPPORTED = "Not supported!";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ package org.thingsboard.server.edqs.data.dp;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.edqs.DataPoint;
 | 
			
		||||
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
@ -54,4 +55,9 @@ public abstract class AbstractDataPoint implements DataPoint {
 | 
			
		||||
        return valueToString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int compareTo(DataPoint dataPoint) {
 | 
			
		||||
        return StringUtils.compareIgnoreCase(valueToString(), dataPoint.valueToString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
package org.thingsboard.server.edqs.data.dp;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import org.thingsboard.server.common.data.edqs.DataPoint;
 | 
			
		||||
import org.thingsboard.server.common.data.kv.DataType;
 | 
			
		||||
 | 
			
		||||
public class BoolDataPoint extends AbstractDataPoint {
 | 
			
		||||
@ -43,4 +44,8 @@ public class BoolDataPoint extends AbstractDataPoint {
 | 
			
		||||
        return Boolean.toString(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int compareTo(DataPoint dataPoint) {
 | 
			
		||||
        return Boolean.compare(value, dataPoint.getBool());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
package org.thingsboard.server.edqs.data.dp;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import org.thingsboard.server.common.data.edqs.DataPoint;
 | 
			
		||||
import org.thingsboard.server.common.data.kv.DataType;
 | 
			
		||||
 | 
			
		||||
public class DoubleDataPoint extends AbstractDataPoint {
 | 
			
		||||
@ -43,4 +44,8 @@ public class DoubleDataPoint extends AbstractDataPoint {
 | 
			
		||||
        return Double.toString(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int compareTo(DataPoint dataPoint) {
 | 
			
		||||
        return Double.compare(value, dataPoint.getDouble());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
package org.thingsboard.server.edqs.data.dp;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import org.thingsboard.server.common.data.edqs.DataPoint;
 | 
			
		||||
import org.thingsboard.server.common.data.kv.DataType;
 | 
			
		||||
 | 
			
		||||
public class LongDataPoint extends AbstractDataPoint {
 | 
			
		||||
@ -47,4 +48,9 @@ public class LongDataPoint extends AbstractDataPoint {
 | 
			
		||||
    public String valueToString() {
 | 
			
		||||
        return Long.toString(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int compareTo(DataPoint dataPoint) {
 | 
			
		||||
        return Long.compare(value, dataPoint.getLong());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
package org.thingsboard.server.edqs.query;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.server.common.data.edqs.DataPoint;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityIdFactory;
 | 
			
		||||
import org.thingsboard.server.edqs.data.EntityData;
 | 
			
		||||
@ -26,7 +27,7 @@ import java.util.UUID;
 | 
			
		||||
public class SortableEntityData {
 | 
			
		||||
 | 
			
		||||
    private final EntityData entityData;
 | 
			
		||||
    private String sortValue;
 | 
			
		||||
    private DataPoint sortValue;
 | 
			
		||||
 | 
			
		||||
    public UUID getId(){
 | 
			
		||||
        return entityData.getId();
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
package org.thingsboard.server.edqs.query.processor;
 | 
			
		||||
 | 
			
		||||
import org.thingsboard.server.common.data.EntityType;
 | 
			
		||||
import org.thingsboard.server.common.data.edqs.DataPoint;
 | 
			
		||||
import org.thingsboard.server.common.data.permission.QueryContext;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityFilter;
 | 
			
		||||
import org.thingsboard.server.edqs.data.EntityData;
 | 
			
		||||
@ -50,7 +51,7 @@ public abstract class AbstractQueryProcessor<T extends EntityFilter> implements
 | 
			
		||||
 | 
			
		||||
    protected SortableEntityData toSortData(EntityData<?> ed) {
 | 
			
		||||
        SortableEntityData sortData = new SortableEntityData(ed);
 | 
			
		||||
        sortData.setSortValue(getSortValue(ed, sortKey));
 | 
			
		||||
        sortData.setSortValue(getSortValue(ed, sortKey, ctx));
 | 
			
		||||
        return sortData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,7 @@ import java.util.List;
 | 
			
		||||
import java.util.Queue;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public abstract class AbstractRelationQueryProcessor<T extends EntityFilter> extends AbstractQueryProcessor<T> {
 | 
			
		||||
@ -89,7 +90,7 @@ public abstract class AbstractRelationQueryProcessor<T extends EntityFilter> ext
 | 
			
		||||
    private List<SortableEntityData> processTenantQuery(Set<EntityData<?>> entities) {
 | 
			
		||||
        return entities.stream()
 | 
			
		||||
                .map(this::toSortData)
 | 
			
		||||
                .toList();
 | 
			
		||||
                .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private List<SortableEntityData> processCustomerQuery(Set<EntityData<?>> entities) {
 | 
			
		||||
 | 
			
		||||
@ -67,10 +67,10 @@ import static org.thingsboard.server.common.data.query.ComplexFilterPredicate.Co
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class RepositoryUtils {
 | 
			
		||||
 | 
			
		||||
    public static final Comparator<SortableEntityData> SORT_ASC = Comparator.comparing((SortableEntityData sed) -> Optional.ofNullable(sed.getSortValue()).orElse(""), String.CASE_INSENSITIVE_ORDER)
 | 
			
		||||
    public static final Comparator<SortableEntityData> SORT_ASC = Comparator.comparing(SortableEntityData::getSortValue, Comparator.nullsFirst(Comparator.naturalOrder()))
 | 
			
		||||
            .thenComparing(sp -> sp.getId().toString());
 | 
			
		||||
 | 
			
		||||
    public static final Comparator<SortableEntityData> SORT_DESC = Comparator.comparing((SortableEntityData sed) -> Optional.ofNullable(sed.getSortValue()).orElse(""), String.CASE_INSENSITIVE_ORDER)
 | 
			
		||||
    public static final Comparator<SortableEntityData> SORT_DESC =  Comparator.comparing(SortableEntityData::getSortValue, Comparator.nullsFirst(Comparator.naturalOrder()))
 | 
			
		||||
            .thenComparing(sp -> sp.getId().toString()).reversed();
 | 
			
		||||
 | 
			
		||||
    public static EntityType resolveEntityType(EntityFilter entityFilter) {
 | 
			
		||||
@ -348,24 +348,11 @@ public class RepositoryUtils {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getSortValue(EntityData entity, DataKey sortKey) {
 | 
			
		||||
    public static DataPoint getSortValue(EntityData entity, DataKey sortKey, QueryContext queryContext) {
 | 
			
		||||
        if (sortKey == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        switch (sortKey.type()) {
 | 
			
		||||
            case ENTITY_FIELD -> {
 | 
			
		||||
                return entity.getField(sortKey.key());
 | 
			
		||||
            }
 | 
			
		||||
            case ATTRIBUTE, CLIENT_ATTRIBUTE, SHARED_ATTRIBUTE, SERVER_ATTRIBUTE -> {
 | 
			
		||||
                var dp = entity.getAttr(sortKey.keyId(), sortKey.type());
 | 
			
		||||
                return dp != null ? dp.valueToString() : "";
 | 
			
		||||
            }
 | 
			
		||||
            case TIME_SERIES -> {
 | 
			
		||||
                var dp = entity.getTs(sortKey.keyId());
 | 
			
		||||
                return dp != null ? dp.valueToString() : "";
 | 
			
		||||
            }
 | 
			
		||||
            default -> throw new IllegalStateException("toSortKey is not implemented for type: " + sortKey.type());
 | 
			
		||||
        }
 | 
			
		||||
       return entity.getDataPoint(sortKey, queryContext);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean checkFilters(EdqsQuery query, EntityData entity) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user