Browse Source

updated metric default value to double and added logic to handle relations when direction to

pull/14770/head
IrynaMatveieva 9 months ago
parent
commit
7a638c2151
  1. 22
      application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java
  2. 16
      application/src/main/java/org/thingsboard/server/service/cf/AbstractCalculatedFieldProcessingService.java
  3. 18
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java
  4. 23
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesArgumentEntry.java
  5. 4
      application/src/main/java/org/thingsboard/server/utils/CalculatedFieldArgumentUtils.java
  6. 4
      application/src/test/java/org/thingsboard/server/cf/EntityAggregationCalculatedFieldTest.java
  7. 2
      application/src/test/java/org/thingsboard/server/controller/CalculatedFieldControllerTest.java
  8. 2
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/AggMetric.java
  9. 6
      dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java

22
application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java

@ -595,22 +595,12 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
Predicate<EntityId> matchesCfEntity = relatedEntity -> cfEntityId.equals(relatedEntity) || cfEntityId.equals(getProfileId(tenantId, relatedEntity)); Predicate<EntityId> matchesCfEntity = relatedEntity -> cfEntityId.equals(relatedEntity) || cfEntityId.equals(getProfileId(tenantId, relatedEntity));
if (byRelationPathQuery != null && !byRelationPathQuery.isEmpty()) { if (byRelationPathQuery != null && !byRelationPathQuery.isEmpty()) {
switch (relation.direction()) { switch (relation.direction()) {
case FROM -> { case FROM -> byRelationPathQuery.stream()
if (byRelationPathQuery.size() > 1) { .filter(entityRelation -> matchesCfEntity.test(entityRelation.getFrom()))
throw new IllegalStateException("More than one relation found with direction 'TO' " + .forEach(entityRelation -> result.add(new CalculatedFieldEntityCtxId(tenantId, cf.getCfId(), entityRelation.getFrom())));
"for relation type '" + relation.relationType() + "'. Found: " + byRelationPathQuery.size()); case TO -> byRelationPathQuery.stream()
} .filter(entityRelation -> matchesCfEntity.test(entityRelation.getTo()))
EntityRelation entityRelation = byRelationPathQuery.get(0); // only one supported .forEach(entityRelation -> result.add(new CalculatedFieldEntityCtxId(tenantId, cf.getCfId(), entityRelation.getTo())));
EntityId relatedId = entityRelation.getFrom();
if (matchesCfEntity.test(relatedId)) {
result.add(new CalculatedFieldEntityCtxId(tenantId, cf.getCfId(), relatedId));
}
}
case TO -> {
byRelationPathQuery.stream()
.filter(entityRelation -> matchesCfEntity.test(entityRelation.getTo()))
.forEach(entityRelation -> result.add(new CalculatedFieldEntityCtxId(tenantId, cf.getCfId(), entityRelation.getTo())));
}
} }
} }
} }

16
application/src/main/java/org/thingsboard/server/service/cf/AbstractCalculatedFieldProcessingService.java

@ -247,20 +247,8 @@ public abstract class AbstractCalculatedFieldProcessingService {
} }
return switch (relation.direction()) { return switch (relation.direction()) {
case FROM -> relations.stream() case FROM -> relations.stream().map(EntityRelation::getTo).toList();
.map(EntityRelation::getTo) case TO -> relations.stream().map(EntityRelation::getFrom).toList();
.toList();
case TO -> {
if (relations.size() > 1) {
throw new IllegalStateException("More than one relation found with direction 'TO' " +
"for relation type '" + relation.relationType() + "'. Found: " + relations.size());
}
yield relations.stream()
.map(EntityRelation::getFrom)
.findFirst()
.map(List::of)
.orElseGet(Collections::emptyList);
}
}; };
}, calculatedFieldCallbackExecutor); }, calculatedFieldCallbackExecutor);
} }

18
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java

@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.cf.configuration.aggregation.AggKeyInp
import org.thingsboard.server.common.data.cf.configuration.aggregation.AggMetric; import org.thingsboard.server.common.data.cf.configuration.aggregation.AggMetric;
import org.thingsboard.server.common.data.cf.configuration.aggregation.RelatedEntitiesAggregationCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.aggregation.RelatedEntitiesAggregationCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.service.cf.CalculatedFieldResult; import org.thingsboard.server.service.cf.CalculatedFieldResult;
import org.thingsboard.server.service.cf.TelemetryCalculatedFieldResult; import org.thingsboard.server.service.cf.TelemetryCalculatedFieldResult;
@ -300,8 +301,25 @@ public class RelatedEntitiesAggregationCalculatedFieldState extends BaseCalculat
if (argumentEntry == null || argumentEntry.isEmpty()) { if (argumentEntry == null || argumentEntry.isEmpty()) {
return ReadinessStatus.notReady(MISSING_AGGREGATION_ENTITIES_ERROR); return ReadinessStatus.notReady(MISSING_AGGREGATION_ENTITIES_ERROR);
} }
if (argumentEntry instanceof RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry) {
try {
checkConstraintByDirection(relatedEntitiesArgumentEntry);
} catch (Exception e) {
return ReadinessStatus.notReady(e.getMessage());
}
}
} }
return ReadinessStatus.READY; return ReadinessStatus.READY;
} }
public void checkConstraintByDirection(RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry) {
if (ctx.getCalculatedField().getConfiguration() instanceof RelatedEntitiesAggregationCalculatedFieldConfiguration config) {
if (EntitySearchDirection.TO == config.getRelation().direction()) {
if (relatedEntitiesArgumentEntry.getEntityInputs().size() > 1) {
throw new IllegalArgumentException("More than one related entity is not supported for relation direction 'TO'. Found: " + relatedEntitiesArgumentEntry.getEntityInputs().size() + ".");
}
}
}
}
} }

23
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesArgumentEntry.java

@ -66,29 +66,28 @@ public class RelatedEntitiesArgumentEntry implements ArgumentEntry, HasLatestTs
@Override @Override
public boolean updateEntry(ArgumentEntry entry, CalculatedFieldCtx ctx) { public boolean updateEntry(ArgumentEntry entry, CalculatedFieldCtx ctx) {
if (entry instanceof RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry) { if (entry instanceof RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry) {
checkMaxRelatedEntitiesPerArgument(ctx); checkRelatedEntitiesNumber(ctx);
entityInputs.putAll(relatedEntitiesArgumentEntry.entityInputs); entityInputs.putAll(relatedEntitiesArgumentEntry.entityInputs);
return true;
} else if (entry instanceof SingleValueArgumentEntry singleValueArgumentEntry) { } else if (entry instanceof SingleValueArgumentEntry singleValueArgumentEntry) {
if (entry.isForceResetPrevious()) { if (entry.isForceResetPrevious()) {
checkMaxRelatedEntitiesPerArgument(ctx); checkRelatedEntitiesNumber(ctx);
entityInputs.put(singleValueArgumentEntry.getEntityId(), singleValueArgumentEntry); entityInputs.put(singleValueArgumentEntry.getEntityId(), singleValueArgumentEntry);
return true;
}
ArgumentEntry argumentEntry = entityInputs.get(singleValueArgumentEntry.getEntityId());
if (argumentEntry != null) {
argumentEntry.updateEntry(singleValueArgumentEntry, ctx);
} else { } else {
checkMaxRelatedEntitiesPerArgument(ctx); ArgumentEntry argumentEntry = entityInputs.get(singleValueArgumentEntry.getEntityId());
entityInputs.put(singleValueArgumentEntry.getEntityId(), singleValueArgumentEntry); if (argumentEntry != null) {
argumentEntry.updateEntry(singleValueArgumentEntry, ctx);
} else {
checkRelatedEntitiesNumber(ctx);
entityInputs.put(singleValueArgumentEntry.getEntityId(), singleValueArgumentEntry);
}
} }
return true;
} else { } else {
throw new IllegalArgumentException("Unsupported argument entry type for aggregation argument entry: " + entry.getType()); throw new IllegalArgumentException("Unsupported argument entry type for aggregation argument entry: " + entry.getType());
} }
return true;
} }
private void checkMaxRelatedEntitiesPerArgument(CalculatedFieldCtx ctx) { private void checkRelatedEntitiesNumber(CalculatedFieldCtx ctx) {
if (entityInputs.size() >= ctx.getMaxRelatedEntitiesPerCfArgument()) { if (entityInputs.size() >= ctx.getMaxRelatedEntitiesPerCfArgument()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Exceeded the maximum allowed related entities per argument '" "Exceeded the maximum allowed related entities per argument '"

4
application/src/main/java/org/thingsboard/server/utils/CalculatedFieldArgumentUtils.java

@ -68,9 +68,9 @@ public class CalculatedFieldArgumentUtils {
} }
public static ArgumentEntry createDefaultMetricArgumentEntry(String argKey, AggMetric metric) { public static ArgumentEntry createDefaultMetricArgumentEntry(String argKey, AggMetric metric) {
Long defaultValue = metric.getDefaultValue(); Double defaultValue = metric.getDefaultValue();
if (defaultValue != null) { if (defaultValue != null) {
return ArgumentEntry.createSingleValueArgument(new DoubleDataEntry(argKey, defaultValue.doubleValue())); return ArgumentEntry.createSingleValueArgument(new DoubleDataEntry(argKey, defaultValue));
} }
return new SingleValueArgumentEntry(); return new SingleValueArgumentEntry();
} }

4
application/src/test/java/org/thingsboard/server/cf/EntityAggregationCalculatedFieldTest.java

@ -254,7 +254,7 @@ public class EntityAggregationCalculatedFieldTest extends AbstractControllerTest
AggMetric consumption = new AggMetric(); AggMetric consumption = new AggMetric();
consumption.setFunction(AggFunction.SUM); consumption.setFunction(AggFunction.SUM);
consumption.setInput(new AggKeyInput("en")); consumption.setInput(new AggKeyInput("en"));
consumption.setDefaultValue(9999L); consumption.setDefaultValue(9999.0);
aggMetrics.put("consumption", consumption); aggMetrics.put("consumption", consumption);
AggMetric avgEnergyConsumption = new AggMetric(); AggMetric avgEnergyConsumption = new AggMetric();
@ -319,7 +319,7 @@ public class EntityAggregationCalculatedFieldTest extends AbstractControllerTest
AggMetric consumption = new AggMetric(); AggMetric consumption = new AggMetric();
consumption.setFunction(AggFunction.SUM); consumption.setFunction(AggFunction.SUM);
consumption.setInput(new AggKeyInput("en")); consumption.setInput(new AggKeyInput("en"));
consumption.setDefaultValue(9999L); consumption.setDefaultValue(9999.0);
aggMetrics.put("consumption", consumption); aggMetrics.put("consumption", consumption);
AggMetric avgTemperature = new AggMetric(); AggMetric avgTemperature = new AggMetric();

2
application/src/test/java/org/thingsboard/server/controller/CalculatedFieldControllerTest.java

@ -382,7 +382,7 @@ public class CalculatedFieldControllerTest extends AbstractControllerTest {
AggMetric metric = new AggMetric(); AggMetric metric = new AggMetric();
metric.setInput(new AggKeyInput("en")); metric.setInput(new AggKeyInput("en"));
metric.setDefaultValue(9999L); metric.setDefaultValue(9999.0);
config.setMetrics(Map.of("consumption", metric)); config.setMetrics(Map.of("consumption", metric));
config.setWatermark(new Watermark(TimeUnit.DAYS.toSeconds(1))); config.setWatermark(new Watermark(TimeUnit.DAYS.toSeconds(1)));

2
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/AggMetric.java

@ -27,6 +27,6 @@ public class AggMetric {
private AggFunction function; private AggFunction function;
private String filter; private String filter;
private AggInput input; private AggInput input;
private Long defaultValue; private Double defaultValue;
} }

6
dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java

@ -52,11 +52,11 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.eventsourcing.RelationActionEvent; import org.thingsboard.server.dao.eventsourcing.RelationActionEvent;
import org.thingsboard.server.exception.DataValidationException;
import org.thingsboard.server.dao.service.ConstraintValidator; import org.thingsboard.server.dao.service.ConstraintValidator;
import org.thingsboard.server.dao.sql.JpaExecutorService; import org.thingsboard.server.dao.sql.JpaExecutorService;
import org.thingsboard.server.dao.sql.relation.JpaRelationQueryExecutorService; import org.thingsboard.server.dao.sql.relation.JpaRelationQueryExecutorService;
import org.thingsboard.server.dao.usagerecord.ApiLimitService; import org.thingsboard.server.dao.usagerecord.ApiLimitService;
import org.thingsboard.server.exception.DataValidationException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -547,7 +547,9 @@ class BaseRelationService implements RelationService {
case FROM -> findByFromAndType(tenantId, relationPathQuery.rootEntityId(), relationPathLevel.relationType(), RelationTypeGroup.COMMON); case FROM -> findByFromAndType(tenantId, relationPathQuery.rootEntityId(), relationPathLevel.relationType(), RelationTypeGroup.COMMON);
case TO -> findByToAndType(tenantId, relationPathQuery.rootEntityId(), relationPathLevel.relationType(), RelationTypeGroup.COMMON); case TO -> findByToAndType(tenantId, relationPathQuery.rootEntityId(), relationPathLevel.relationType(), RelationTypeGroup.COMMON);
}; };
return relations.size() > limit ? relations.subList(0, limit) : relations; ArrayList<EntityRelation> entityRelations = new ArrayList<>(relations);
entityRelations.sort(Comparator.comparing(r -> r.getFrom().getId()));
return entityRelations.size() > limit ? entityRelations.subList(0, limit) : entityRelations;
} }
return relationDao.findByRelationPathQuery(tenantId, relationPathQuery, limit); return relationDao.findByRelationPathQuery(tenantId, relationPathQuery, limit);
} }

Loading…
Cancel
Save