Updated validation logic for existing and geofencing CF

This commit is contained in:
dshvaika 2025-08-12 18:56:53 +03:00
parent ac3f81195d
commit 67f08da7a0
7 changed files with 17 additions and 37 deletions

View File

@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
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.CFArgumentDynamicSourceType;
import org.thingsboard.server.common.data.cf.configuration.OutputType;
import org.thingsboard.server.common.data.cf.configuration.RelationQueryDynamicSourceConfiguration;
import org.thingsboard.server.common.data.id.CalculatedFieldId;
@ -162,7 +161,7 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP
Set<Entry<String, Argument>> entries = ctx.getArguments().entrySet();
if (dynamicArgumentsOnly) {
entries = entries.stream()
.filter(entry -> CFArgumentDynamicSourceType.RELATION_QUERY.equals(entry.getValue().getRefDynamicSource()))
.filter(entry -> entry.getValue().hasDynamicSource())
.collect(Collectors.toSet());
}
for (var entry : entries) {
@ -293,13 +292,13 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP
if (value.getRefEntityId() != null) {
return Futures.immediateFuture(List.of(value.getRefEntityId()));
}
var refDynamicSource = value.getRefDynamicSource();
if (refDynamicSource == null) {
if (!value.hasDynamicSource()) {
return Futures.immediateFuture(List.of(entityId));
}
return switch (value.getRefDynamicSource()) {
var refDynamicSourceConfiguration = value.getRefDynamicSourceConfiguration();
return switch (refDynamicSourceConfiguration.getType()) {
case RELATION_QUERY -> {
var configuration = (RelationQueryDynamicSourceConfiguration) value.getRefDynamicSourceConfiguration();
var configuration = (RelationQueryDynamicSourceConfiguration) refDynamicSourceConfiguration;
if (configuration.isSimpleRelation()) {
yield switch (configuration.getDirection()) {
case FROM ->

View File

@ -90,7 +90,7 @@ public class CalculatedFieldCtx {
for (Map.Entry<String, Argument> entry : arguments.entrySet()) {
var refId = entry.getValue().getRefEntityId();
var refKey = entry.getValue().getRefEntityKey();
if (refId == null && entry.getValue().getRefDynamicSource() != null) {
if (refId == null && entry.getValue().hasDynamicSource()) {
continue;
}
if (refId == null || refId.equals(calculatedField.getEntityId())) {

View File

@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
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.CFArgumentDynamicSourceType;
import org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.GeofencingEvent;
import org.thingsboard.server.common.data.cf.configuration.GeofencingZoneGroupConfiguration;
@ -681,7 +680,6 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
allowedZonesRefDynamicSourceConfiguration.setMaxLevel(1);
allowedZonesRefDynamicSourceConfiguration.setFetchLastLevelOnly(true);
allowedZones.setRefEntityKey(new ReferencedEntityKey("zone", ArgumentType.ATTRIBUTE, AttributeScope.SERVER_SCOPE));
allowedZones.setRefDynamicSource(CFArgumentDynamicSourceType.RELATION_QUERY);
allowedZones.setRefDynamicSourceConfiguration(allowedZonesRefDynamicSourceConfiguration);
Argument restrictedZones = new Argument();
@ -691,7 +689,6 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
restrictedZonesRefDynamicSourceConfiguration.setMaxLevel(1);
restrictedZonesRefDynamicSourceConfiguration.setFetchLastLevelOnly(true);
restrictedZones.setRefEntityKey(new ReferencedEntityKey("zone", ArgumentType.ATTRIBUTE, AttributeScope.SERVER_SCOPE));
restrictedZones.setRefDynamicSource(CFArgumentDynamicSourceType.RELATION_QUERY);
restrictedZones.setRefDynamicSourceConfiguration(restrictedZonesRefDynamicSourceConfiguration);
cfg.setArguments(Map.of(

View File

@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
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.CFArgumentDynamicSourceType;
import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.GeofencingEvent;
@ -323,7 +322,6 @@ public class GeofencingCalculatedFieldStateTest {
refDynamicSourceConfiguration3.setMaxLevel(1);
refDynamicSourceConfiguration3.setFetchLastLevelOnly(true);
argument3.setRefEntityKey(refEntityKey3);
argument3.setRefDynamicSource(CFArgumentDynamicSourceType.RELATION_QUERY);
argument3.setRefDynamicSourceConfiguration(refDynamicSourceConfiguration3);
Argument argument4 = new Argument();
@ -334,7 +332,6 @@ public class GeofencingCalculatedFieldStateTest {
refDynamicSourceConfiguration4.setMaxLevel(1);
refDynamicSourceConfiguration4.setFetchLastLevelOnly(true);
argument4.setRefEntityKey(refEntityKey4);
argument4.setRefDynamicSource(CFArgumentDynamicSourceType.RELATION_QUERY);
argument4.setRefDynamicSourceConfiguration(refDynamicSourceConfiguration4);
config.setArguments(Map.of("latitude", argument1, "longitude", argument2, "allowedZones", argument3, "restrictedZones", argument4));

View File

@ -26,7 +26,7 @@ public class Argument {
@Nullable
private EntityId refEntityId;
private CFArgumentDynamicSourceType refDynamicSource;
// TODO: add upgrade in PE version -> CFArgumentDynamicSourceType to CFArgumentDynamicSourceConfiguration
private CfArgumentDynamicSourceConfiguration refDynamicSourceConfiguration;
private ReferencedEntityKey refEntityKey;
private String defaultValue;
@ -34,4 +34,8 @@ public class Argument {
private Integer limit;
private Long timeWindow;
public boolean hasDynamicSource() {
return refDynamicSourceConfiguration != null;
}
}

View File

@ -58,14 +58,10 @@ public abstract class BaseCalculatedFieldConfiguration implements CalculatedFiel
return link;
}
// TODO: update validate method in PE version.
@Override
public void validate() {
boolean hasDynamicSourceRelationQuery = arguments.values()
.stream()
.anyMatch(arg -> CFArgumentDynamicSourceType.RELATION_QUERY.equals(arg.getRefDynamicSource()));
if (hasDynamicSourceRelationQuery) {
throw new IllegalArgumentException("Calculated field with type: '" + getType() + "' doesn't support arguments with 'RELATION_QUERY' dynamic source type!");
if (arguments.values().stream().anyMatch(Argument::hasDynamicSource)) {
throw new IllegalArgumentException("Calculated field with type: '" + getType() + "' doesn't support dynamic source configuration!");
}
}

View File

@ -27,8 +27,6 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.cf.configuration.CFArgumentDynamicSourceType.RELATION_QUERY;
@Data
@EqualsAndHashCode(callSuper = true)
public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements CalculatedFieldConfiguration {
@ -55,7 +53,7 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
@Override
public boolean isScheduledUpdateEnabled() {
return scheduledUpdateIntervalSec > 0 && arguments.values().stream().anyMatch(arg -> arg.getRefDynamicSource() != null);
return scheduledUpdateIntervalSec > 0 && arguments.values().stream().anyMatch(Argument::hasDynamicSource);
}
// TODO: update validate method in PE version.
@ -67,9 +65,6 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
if (arguments.size() < 3) {
throw new IllegalArgumentException("Geofencing calculated field must contain at least 3 arguments!");
}
if (arguments.size() > 5) {
throw new IllegalArgumentException("Geofencing calculated field size exceeds limit of 5 arguments!");
}
validateCoordinateArguments();
Map<String, Argument> zoneGroupsArguments = getZoneGroupArguments();
@ -129,7 +124,7 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
if (!ArgumentType.TS_LATEST.equals(refEntityKey.getType())) {
throw new IllegalArgumentException("Argument '" + coordinateKey + "' must be of type TS_LATEST.");
}
if (argument.getRefDynamicSource() != null) {
if (argument.hasDynamicSource()) {
throw new IllegalArgumentException("Dynamic source is not allowed for argument: '" + coordinateKey + "'.");
}
}
@ -144,17 +139,9 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
if (!ArgumentType.ATTRIBUTE.equals(refEntityKey.getType())) {
throw new IllegalArgumentException("Argument '" + argumentKey + "' must be of type ATTRIBUTE.");
}
var dynamicSource = argument.getRefDynamicSource();
if (dynamicSource == null) {
return;
if (argument.hasDynamicSource()) {
argument.getRefDynamicSourceConfiguration().validate();
}
if (!RELATION_QUERY.equals(dynamicSource)) {
throw new IllegalArgumentException("Only relation query dynamic source is supported for argument: '" + argumentKey + "'.");
}
if (argument.getRefDynamicSourceConfiguration() == null) {
throw new IllegalArgumentException("Missing dynamic source configuration for argument: '" + argumentKey + "'.");
}
argument.getRefDynamicSourceConfiguration().validate();
});
}