Removed RELATION_QUERY type
This commit is contained in:
		
							parent
							
								
									fcba7004f9
								
							
						
					
					
						commit
						eea9e6bf6e
					
				@ -27,7 +27,6 @@ import org.thingsboard.common.util.ThingsBoardExecutors;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.Argument;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ArgumentType;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.RelationPathQueryDynamicSourceConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.RelationQueryDynamicSourceConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.kv.Aggregation;
 | 
			
		||||
@ -164,21 +163,6 @@ public abstract class AbstractCalculatedFieldProcessingService {
 | 
			
		||||
        }
 | 
			
		||||
        var refDynamicSourceConfiguration = value.getRefDynamicSourceConfiguration();
 | 
			
		||||
        return switch (refDynamicSourceConfiguration.getType()) {
 | 
			
		||||
            case RELATION_QUERY -> {
 | 
			
		||||
                var configuration = (RelationQueryDynamicSourceConfiguration) refDynamicSourceConfiguration;
 | 
			
		||||
                if (configuration.isSimpleRelation()) {
 | 
			
		||||
                    yield switch (configuration.getDirection()) {
 | 
			
		||||
                        case FROM ->
 | 
			
		||||
                                Futures.transform(relationService.findByFromAndTypeAsync(tenantId, entityId, configuration.getRelationType(), RelationTypeGroup.COMMON),
 | 
			
		||||
                                        configuration::resolveEntityIds, calculatedFieldCallbackExecutor);
 | 
			
		||||
                        case TO ->
 | 
			
		||||
                                Futures.transform(relationService.findByToAndTypeAsync(tenantId, entityId, configuration.getRelationType(), RelationTypeGroup.COMMON),
 | 
			
		||||
                                        configuration::resolveEntityIds, calculatedFieldCallbackExecutor);
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
                yield Futures.transform(relationService.findByQuery(tenantId, configuration.toEntityRelationsQuery(entityId)),
 | 
			
		||||
                        configuration::resolveEntityIds, calculatedFieldCallbackExecutor);
 | 
			
		||||
            }
 | 
			
		||||
            case RELATION_PATH_QUERY -> {
 | 
			
		||||
                var configuration = (RelationPathQueryDynamicSourceConfiguration) refDynamicSourceConfiguration;
 | 
			
		||||
                yield Futures.transform(relationService.findByRelationPathQueryAsync(tenantId, configuration.toRelationPathQuery(entityId)),
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,6 @@ package org.thingsboard.server.common.data.cf.configuration;
 | 
			
		||||
 | 
			
		||||
public enum CFArgumentDynamicSourceType {
 | 
			
		||||
 | 
			
		||||
    RELATION_QUERY, RELATION_PATH_QUERY
 | 
			
		||||
    RELATION_PATH_QUERY
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ import java.util.List;
 | 
			
		||||
import java.util.NoSuchElementException;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class RelationPathQueryDynamicSourceConfiguration implements CfArgumentDynamicSourceConfiguration, RelationQueryBased {
 | 
			
		||||
public class RelationPathQueryDynamicSourceConfiguration implements CfArgumentDynamicSourceConfiguration {
 | 
			
		||||
 | 
			
		||||
    private List<RelationPathLevel> levels;
 | 
			
		||||
 | 
			
		||||
@ -53,10 +53,11 @@ public class RelationPathQueryDynamicSourceConfiguration implements CfArgumentDy
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @JsonIgnore
 | 
			
		||||
    public int getMaxLevel() {
 | 
			
		||||
        return levels != null ? levels.size() : 0;
 | 
			
		||||
    public void validateMaxRelationLevel(String argumentName, int maxAllowedRelationLevel) {
 | 
			
		||||
        if (levels.size() > maxAllowedRelationLevel) {
 | 
			
		||||
            throw new IllegalArgumentException("Max relation level is greater than configured " +
 | 
			
		||||
                                               "maximum allowed relation level in tenant profile: " + maxAllowedRelationLevel + " for argument: " + argumentName);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public EntityRelationPathQuery toRelationPathQuery(EntityId entityId) {
 | 
			
		||||
@ -64,9 +65,6 @@ public class RelationPathQueryDynamicSourceConfiguration implements CfArgumentDy
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private RelationPathLevel getLastLevel() {
 | 
			
		||||
        if (CollectionsUtil.isEmpty(levels)) {
 | 
			
		||||
            throw new NoSuchElementException();
 | 
			
		||||
        }
 | 
			
		||||
        return levels.get(levels.size() - 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,29 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2025 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.common.data.cf.configuration;
 | 
			
		||||
 | 
			
		||||
public interface RelationQueryBased {
 | 
			
		||||
 | 
			
		||||
    int getMaxLevel();
 | 
			
		||||
 | 
			
		||||
    default void validateMaxRelationLevel(String argumentName, int maxAllowedRelationLevel) {
 | 
			
		||||
        if (getMaxLevel() > maxAllowedRelationLevel) {
 | 
			
		||||
            throw new IllegalArgumentException("Max relation level is greater than configured " +
 | 
			
		||||
                    "maximum allowed relation level in tenant profile: " + maxAllowedRelationLevel + " for argument: " + argumentName);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,79 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2025 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.common.data.cf.configuration;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonIgnore;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.server.common.data.StringUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelation;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class RelationQueryDynamicSourceConfiguration implements CfArgumentDynamicSourceConfiguration, RelationQueryBased {
 | 
			
		||||
 | 
			
		||||
    private int maxLevel;
 | 
			
		||||
    private boolean fetchLastLevelOnly;
 | 
			
		||||
    private EntitySearchDirection direction;
 | 
			
		||||
    private String relationType;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public CFArgumentDynamicSourceType getType() {
 | 
			
		||||
        return CFArgumentDynamicSourceType.RELATION_QUERY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void validate() {
 | 
			
		||||
        if (maxLevel < 1) {
 | 
			
		||||
            throw new IllegalArgumentException("Relation query dynamic source configuration max relation level can't be less than 1!");
 | 
			
		||||
        }
 | 
			
		||||
        if (direction == null) {
 | 
			
		||||
            throw new IllegalArgumentException("Relation query dynamic source configuration direction must be specified!");
 | 
			
		||||
        }
 | 
			
		||||
        if (StringUtils.isBlank(relationType)) {
 | 
			
		||||
            throw new IllegalArgumentException("Relation query dynamic source configuration relation type must be specified!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @JsonIgnore
 | 
			
		||||
    public boolean isSimpleRelation() {
 | 
			
		||||
        return maxLevel == 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public EntityRelationsQuery toEntityRelationsQuery(EntityId rootEntityId) {
 | 
			
		||||
        if (isSimpleRelation()) {
 | 
			
		||||
            throw new IllegalArgumentException("Entity relations query can't be created for a simple relation!");
 | 
			
		||||
        }
 | 
			
		||||
        var entityRelationsQuery = new EntityRelationsQuery();
 | 
			
		||||
        entityRelationsQuery.setParameters(new RelationsSearchParameters(rootEntityId, direction, maxLevel, fetchLastLevelOnly));
 | 
			
		||||
        entityRelationsQuery.setFilters(Collections.singletonList(new RelationEntityTypeFilter(relationType, Collections.emptyList())));
 | 
			
		||||
        return entityRelationsQuery;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<EntityId> resolveEntityIds(List<EntityRelation> relations) {
 | 
			
		||||
        return switch (direction) {
 | 
			
		||||
            case FROM -> relations.stream().map(EntityRelation::getTo).toList();
 | 
			
		||||
            case TO -> relations.stream().map(EntityRelation::getFrom).toList();
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,214 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2025 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.common.data.cf.configuration;
 | 
			
		||||
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
			
		||||
import org.junit.jupiter.params.ParameterizedTest;
 | 
			
		||||
import org.junit.jupiter.params.provider.NullAndEmptySource;
 | 
			
		||||
import org.junit.jupiter.params.provider.ValueSource;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.junit.jupiter.MockitoExtension;
 | 
			
		||||
import org.thingsboard.server.common.data.EntityType;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelation;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatCode;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
@ExtendWith(MockitoExtension.class)
 | 
			
		||||
public class RelationQueryDynamicSourceConfigurationTest {
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    EntityId rootEntityId;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    EntityRelation rel1;
 | 
			
		||||
    @Mock
 | 
			
		||||
    EntityRelation rel2;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void typeShouldBeRelationQuery() {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        assertThat(cfg.getType()).isEqualTo(CFArgumentDynamicSourceType.RELATION_QUERY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void validateShouldThrowWhenMaxLevelLessThanOne() {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(0);
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
 | 
			
		||||
        assertThatThrownBy(cfg::validate)
 | 
			
		||||
                .isInstanceOf(IllegalArgumentException.class)
 | 
			
		||||
                .hasMessage("Relation query dynamic source configuration max relation level can't be less than 1!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void validateShouldThrowWhenMaxLevelGreaterThanMaxAllowedLevelFromTenantProfile() {
 | 
			
		||||
        int maxAllowedRelationLevel = 2;
 | 
			
		||||
        int argumentMaxRelationLevel = 3;
 | 
			
		||||
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(argumentMaxRelationLevel);
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
 | 
			
		||||
        String testRelationArgument = "testRelationArgument";
 | 
			
		||||
        assertThatThrownBy(() -> cfg.validateMaxRelationLevel(testRelationArgument, maxAllowedRelationLevel))
 | 
			
		||||
                .isInstanceOf(IllegalArgumentException.class)
 | 
			
		||||
                .hasMessage("Max relation level is greater than configured " +
 | 
			
		||||
                            "maximum allowed relation level in tenant profile: " + maxAllowedRelationLevel + " for argument: " + testRelationArgument);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void validateShouldPassValidationWhenMaxLevelLessThanMaxAllowedLevelFromTenantProfile() {
 | 
			
		||||
        int maxAllowedRelationLevel = 5;
 | 
			
		||||
        int argumentMaxRelationLevel = 2;
 | 
			
		||||
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(argumentMaxRelationLevel);
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
 | 
			
		||||
        String testRelationArgument = "testRelationArgument";
 | 
			
		||||
        assertThatCode(() -> cfg.validateMaxRelationLevel(testRelationArgument, maxAllowedRelationLevel)).doesNotThrowAnyException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void validateShouldThrowWhenDirectionIsNull() {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(1);
 | 
			
		||||
        cfg.setDirection(null);
 | 
			
		||||
        cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
 | 
			
		||||
        assertThatThrownBy(cfg::validate)
 | 
			
		||||
                .isInstanceOf(IllegalArgumentException.class)
 | 
			
		||||
                .hasMessage("Relation query dynamic source configuration direction must be specified!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ParameterizedTest
 | 
			
		||||
    @ValueSource(strings = {" "})
 | 
			
		||||
    @NullAndEmptySource
 | 
			
		||||
    void validateShouldThrowWhenRelationTypeIsNull(String relationType) {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(1);
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.TO);
 | 
			
		||||
        cfg.setRelationType(relationType);
 | 
			
		||||
 | 
			
		||||
        assertThatThrownBy(cfg::validate)
 | 
			
		||||
                .isInstanceOf(IllegalArgumentException.class)
 | 
			
		||||
                .hasMessage("Relation query dynamic source configuration relation type must be specified!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void isSimpleRelationTrueWhenLevelIsOneAndEntityTypesEmptyOrNull() {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(1);
 | 
			
		||||
        assertThat(cfg.isSimpleRelation()).isTrue();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void isSimpleRelationFalseWhenMaxLevelNotOne() {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(2);
 | 
			
		||||
        assertThat(cfg.isSimpleRelation()).isFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void toEntityRelationsQueryShouldThrowForSimpleRelation() {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(1);
 | 
			
		||||
        cfg.setFetchLastLevelOnly(false);
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
 | 
			
		||||
        assertThatThrownBy(() -> cfg.toEntityRelationsQuery(rootEntityId))
 | 
			
		||||
                .isInstanceOf(IllegalArgumentException.class)
 | 
			
		||||
                .hasMessage("Entity relations query can't be created for a simple relation!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void toEntityRelationsQueryShouldBuildQueryForNonSimpleRelation() {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(2);
 | 
			
		||||
        cfg.setFetchLastLevelOnly(true);
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.TO);
 | 
			
		||||
        cfg.setRelationType(EntityRelation.MANAGES_TYPE);
 | 
			
		||||
 | 
			
		||||
        var query = cfg.toEntityRelationsQuery(rootEntityId);
 | 
			
		||||
 | 
			
		||||
        assertThat(query).isNotNull();
 | 
			
		||||
        RelationsSearchParameters params = query.getParameters();
 | 
			
		||||
        assertThat(params).isNotNull();
 | 
			
		||||
        assertThat(params.getRootId()).isEqualTo(rootEntityId.getId());
 | 
			
		||||
        assertThat(params.getDirection()).isEqualTo(EntitySearchDirection.TO);
 | 
			
		||||
        assertThat(params.getMaxLevel()).isEqualTo(2);
 | 
			
		||||
        assertThat(params.isFetchLastLevelOnly()).isTrue();
 | 
			
		||||
 | 
			
		||||
        assertThat(query.getFilters()).hasSize(1);
 | 
			
		||||
        assertThat(query.getFilters().get(0)).isInstanceOf(RelationEntityTypeFilter.class);
 | 
			
		||||
        RelationEntityTypeFilter filter = query.getFilters().get(0);
 | 
			
		||||
        assertThat(filter.getRelationType()).isEqualTo(EntityRelation.MANAGES_TYPE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void resolveEntityIds_whenDirectionFROM_thenReturnsToIds() {
 | 
			
		||||
        when(rel1.getTo()).thenReturn(mock(EntityId.class));
 | 
			
		||||
        when(rel2.getTo()).thenReturn(mock(EntityId.class));
 | 
			
		||||
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
 | 
			
		||||
        var out = cfg.resolveEntityIds(List.of(rel1, rel2));
 | 
			
		||||
 | 
			
		||||
        assertThat(out).containsExactly(rel1.getTo(), rel2.getTo());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void resolveEntityIds_whenDirectionTO_thenReturnsFromIds() {
 | 
			
		||||
        when(rel1.getFrom()).thenReturn(mock(EntityId.class));
 | 
			
		||||
        when(rel2.getFrom()).thenReturn(mock(EntityId.class));
 | 
			
		||||
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.TO);
 | 
			
		||||
 | 
			
		||||
        var out = cfg.resolveEntityIds(List.of(rel1, rel2));
 | 
			
		||||
 | 
			
		||||
        assertThat(out).containsExactly(rel1.getFrom(), rel2.getFrom());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void validateShouldPassForValidConfig() {
 | 
			
		||||
        var cfg = new RelationQueryDynamicSourceConfiguration();
 | 
			
		||||
        cfg.setMaxLevel(2);
 | 
			
		||||
        cfg.setFetchLastLevelOnly(false);
 | 
			
		||||
        cfg.setDirection(EntitySearchDirection.FROM);
 | 
			
		||||
        cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
 | 
			
		||||
 | 
			
		||||
        assertThatCode(cfg::validate).doesNotThrowAnyException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -504,6 +504,13 @@ public class BaseRelationService implements RelationService {
 | 
			
		||||
        log.trace("Executing findByRelationPathQuery, tenantId [{}], relationPathQuery {}", tenantId, relationPathQuery);
 | 
			
		||||
        validateId(tenantId, id -> "Invalid tenant id: " + id);
 | 
			
		||||
        validate(relationPathQuery);
 | 
			
		||||
        if (relationPathQuery.levels().size() == 1) {
 | 
			
		||||
            RelationPathLevel relationPathLevel = relationPathQuery.levels().get(0);
 | 
			
		||||
            return switch (relationPathLevel.direction()) {
 | 
			
		||||
                case FROM -> findByFromAndTypeAsync(tenantId, relationPathQuery.rootEntityId(), relationPathLevel.relationType(), RelationTypeGroup.COMMON);
 | 
			
		||||
                case TO -> findByToAndTypeAsync(tenantId, relationPathQuery.rootEntityId(), relationPathLevel.relationType(), RelationTypeGroup.COMMON);
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        return executor.submit(() -> relationDao.findByRelationPathQuery(tenantId, relationPathQuery));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.CalculatedField;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.RelationQueryBased;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.RelationPathQueryDynamicSourceConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
 | 
			
		||||
@ -98,10 +98,10 @@ public class CalculatedFieldDataValidator extends DataValidator<CalculatedField>
 | 
			
		||||
        if (!(calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration argumentsBasedCfg)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Map<String, RelationQueryBased> relationQueryBasedArguments = argumentsBasedCfg.getArguments().entrySet()
 | 
			
		||||
        Map<String, RelationPathQueryDynamicSourceConfiguration> relationQueryBasedArguments = argumentsBasedCfg.getArguments().entrySet()
 | 
			
		||||
                .stream()
 | 
			
		||||
                .filter(entry -> entry.getValue().hasDynamicSource())
 | 
			
		||||
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> (RelationQueryBased) entry.getValue().getRefDynamicSourceConfiguration()));
 | 
			
		||||
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> (RelationPathQueryDynamicSourceConfiguration) entry.getValue().getRefDynamicSourceConfiguration()));
 | 
			
		||||
        if (relationQueryBasedArguments.isEmpty()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user