refactored service and test classes

This commit is contained in:
IrynaMatveieva 2024-11-12 12:25:59 +02:00
parent 86dd8e725b
commit 444c5bf079
16 changed files with 84 additions and 253 deletions

View File

@ -38,7 +38,7 @@ import org.thingsboard.server.common.data.cf.BaseCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.CalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.CalculatedFieldLink; import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
import org.thingsboard.server.common.data.cf.CalculatedFiledLinkConfiguration; import org.thingsboard.server.common.data.cf.CalculatedFieldLinkConfiguration;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.AssetProfileId;
@ -58,8 +58,6 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
@ -84,8 +82,6 @@ import static org.thingsboard.server.dao.service.Validator.validateEntityId;
public class DefaultTbCalculatedFieldService extends AbstractTbEntityService implements TbCalculatedFieldService { public class DefaultTbCalculatedFieldService extends AbstractTbEntityService implements TbCalculatedFieldService {
private final CalculatedFieldService calculatedFieldService; private final CalculatedFieldService calculatedFieldService;
private final TbDeviceProfileCache deviceProfileCache;
private final TbAssetProfileCache assetProfileCache;
private final AttributesService attributesService; private final AttributesService attributesService;
private final TimeseriesService timeseriesService; private final TimeseriesService timeseriesService;
private ListeningScheduledExecutorService scheduledExecutor; private ListeningScheduledExecutorService scheduledExecutor;
@ -215,6 +211,15 @@ public class DefaultTbCalculatedFieldService extends AbstractTbEntityService imp
return value != null ? value : argument.getDefaultValue(); return value != null ? value : argument.getDefaultValue();
} }
private <T extends EntityId> void initializeForProfile(TenantId tenantId, List<CalculatedFieldLink> links, CalculatedField cf, Iterable<T> profileIds) {
for (T profileId : profileIds) {
for (CalculatedFieldLink link : links) {
CalculatedFieldLinkConfiguration configuration = link.getConfiguration();
initializeStateFromFutures(tenantId, profileId, cf, configuration.getAttributes(), configuration.getTimeSeries());
}
}
}
@Override @Override
public void onCalculatedFieldAdded(TransportProtos.CalculatedFieldAddMsgProto proto, TbCallback callback) { public void onCalculatedFieldAdded(TransportProtos.CalculatedFieldAddMsgProto proto, TbCallback callback) {
try { try {
@ -227,33 +232,24 @@ public class DefaultTbCalculatedFieldService extends AbstractTbEntityService imp
calculatedFields.put(calculatedFieldId, cf); calculatedFields.put(calculatedFieldId, cf);
calculatedFieldLinks.put(calculatedFieldId, links); calculatedFieldLinks.put(calculatedFieldId, links);
switch (entityId.getEntityType()) { switch (entityId.getEntityType()) {
case ASSET, DEVICE: { case ASSET, DEVICE -> {
for (CalculatedFieldLink link : links) { for (CalculatedFieldLink link : links) {
CalculatedFiledLinkConfiguration configuration = link.getConfiguration(); CalculatedFieldLinkConfiguration configuration = link.getConfiguration();
initializeStateFromFutures(tenantId, link.getEntityId(), cf, configuration.getAttributes(), configuration.getTimeSeries()); initializeStateFromFutures(tenantId, link.getEntityId(), cf, configuration.getAttributes(), configuration.getTimeSeries());
} }
} }
case ASSET_PROFILE: { case ASSET_PROFILE -> {
PageDataIterable<AssetId> assetIds = new PageDataIterable<>(pageLink -> PageDataIterable<AssetId> assetIds = new PageDataIterable<>(pageLink ->
assetService.findAssetIdsByTenantIdAndAssetProfileId(tenantId, (AssetProfileId) entityId, pageLink), initFetchPackSize); assetService.findAssetIdsByTenantIdAndAssetProfileId(tenantId, (AssetProfileId) entityId, pageLink), initFetchPackSize);
for (AssetId assetId : assetIds) { initializeForProfile(tenantId, links, cf, assetIds);
for (CalculatedFieldLink link : links) {
CalculatedFiledLinkConfiguration configuration = link.getConfiguration();
initializeStateFromFutures(tenantId, assetId, cf, configuration.getAttributes(), configuration.getTimeSeries());
} }
} case DEVICE_PROFILE -> {
}
case DEVICE_PROFILE: {
PageDataIterable<DeviceId> deviceIds = new PageDataIterable<>(pageLink -> PageDataIterable<DeviceId> deviceIds = new PageDataIterable<>(pageLink ->
deviceService.findDeviceIdsByTenantIdAndDeviceProfileId(tenantId, (DeviceProfileId) entityId, pageLink), initFetchPackSize); deviceService.findDeviceIdsByTenantIdAndDeviceProfileId(tenantId, (DeviceProfileId) entityId, pageLink), initFetchPackSize);
for (DeviceId deviceId : deviceIds) { initializeForProfile(tenantId, links, cf, deviceIds);
for (CalculatedFieldLink link : links) {
CalculatedFiledLinkConfiguration configuration = link.getConfiguration();
initializeStateFromFutures(tenantId, deviceId, cf, configuration.getAttributes(), configuration.getTimeSeries());
} }
} default ->
} throw new IllegalArgumentException("Entity type '" + calculatedFieldId.getEntityType() + "' does not support calculated fields.");
default: throw new IllegalArgumentException("Entity type '" + calculatedFieldId.getEntityType() + "' does not support calculated fields.");
} }
} else { } else {
//Calculated field or entity was probably deleted while message was in queue; //Calculated field or entity was probably deleted while message was in queue;
@ -336,7 +332,8 @@ public class DefaultTbCalculatedFieldService extends AbstractTbEntityService imp
private void checkEntityExistence(TenantId tenantId, EntityId entityId) { private void checkEntityExistence(TenantId tenantId, EntityId entityId) {
switch (entityId.getEntityType()) { switch (entityId.getEntityType()) {
case ASSET, DEVICE, ASSET_PROFILE, DEVICE_PROFILE -> Optional.ofNullable(entityService.fetchEntity(tenantId, entityId)) case ASSET, DEVICE, ASSET_PROFILE, DEVICE_PROFILE ->
Optional.ofNullable(entityService.fetchEntity(tenantId, entityId))
.orElseThrow(() -> new IllegalArgumentException(entityId.getEntityType().getNormalName() + " with id [" + entityId.getId() + "] does not exist.")); .orElseThrow(() -> new IllegalArgumentException(entityId.getEntityType().getNormalName() + " with id [" + entityId.getId() + "] does not exist."));
default -> default ->
throw new IllegalArgumentException("Entity type '" + entityId.getEntityType() + "' does not support calculated fields."); throw new IllegalArgumentException("Entity type '" + entityId.getEntityType() + "' does not support calculated fields.");
@ -357,7 +354,8 @@ public class DefaultTbCalculatedFieldService extends AbstractTbEntityService imp
private <E extends HasId<I> & HasTenantId, I extends EntityId> E findEntity(TenantId tenantId, EntityId entityId) { private <E extends HasId<I> & HasTenantId, I extends EntityId> E findEntity(TenantId tenantId, EntityId entityId) {
return switch (entityId.getEntityType()) { return switch (entityId.getEntityType()) {
case TENANT, CUSTOMER, ASSET, DEVICE -> (E) entityService.fetchEntity(tenantId, entityId).orElse(null); case TENANT, CUSTOMER, ASSET, DEVICE -> (E) entityService.fetchEntity(tenantId, entityId).orElse(null);
default -> throw new IllegalArgumentException("Calculated fields do not support entity type '" + entityId.getEntityType() + "' for referenced entities."); default ->
throw new IllegalArgumentException("Calculated fields do not support entity type '" + entityId.getEntityType() + "' for referenced entities.");
}; };
} }

View File

@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -37,7 +38,7 @@ public abstract class BaseCalculatedFieldConfiguration implements CalculatedFiel
private final ObjectMapper mapper = new ObjectMapper(); private final ObjectMapper mapper = new ObjectMapper();
protected Map<String, Argument> arguments; protected Map<String, Argument> arguments;
protected SimpleCalculatedFieldConfiguration.Output output; protected Output output;
public BaseCalculatedFieldConfiguration() { public BaseCalculatedFieldConfiguration() {
} }
@ -51,13 +52,14 @@ public abstract class BaseCalculatedFieldConfiguration implements CalculatedFiel
@Override @Override
public List<EntityId> getReferencedEntities() { public List<EntityId> getReferencedEntities() {
return arguments.values().stream() return arguments.values().stream()
.map(SimpleCalculatedFieldConfiguration.Argument::getEntityId) .map(Argument::getEntityId)
.filter(Objects::nonNull)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override @Override
public CalculatedFiledLinkConfiguration getReferencedEntityConfig(EntityId entityId) { public CalculatedFieldLinkConfiguration getReferencedEntityConfig(EntityId entityId) {
CalculatedFiledLinkConfiguration linkConfiguration = new CalculatedFiledLinkConfiguration(); CalculatedFieldLinkConfiguration linkConfiguration = new CalculatedFieldLinkConfiguration();
arguments.values().stream() arguments.values().stream()
.filter(argument -> argument.getEntityId().equals(entityId)) .filter(argument -> argument.getEntityId().equals(entityId))
.forEach(argument -> { .forEach(argument -> {

View File

@ -1,43 +0,0 @@
/**
* Copyright © 2016-2024 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;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
import java.util.Map;
@Data
public class CalculatedFieldConfig {
private Map<String, Argument> arguments;
private Output output;
@Data
public static class Argument {
private EntityId entityId;
private String key;
private String type;
private int defaultValue;
}
@Data
public static class Output {
private String type;
private String expression;
}
}

View File

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.common.data.cf; package org.thingsboard.server.common.data.cf;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@ -35,14 +36,18 @@ import java.util.UUID;
}) })
public interface CalculatedFieldConfiguration { public interface CalculatedFieldConfiguration {
@JsonIgnore
String getType(); String getType();
Map<String, BaseCalculatedFieldConfiguration.Argument> getArguments(); Map<String, BaseCalculatedFieldConfiguration.Argument> getArguments();
@JsonIgnore
List<EntityId> getReferencedEntities(); List<EntityId> getReferencedEntities();
CalculatedFiledLinkConfiguration getReferencedEntityConfig(EntityId entityId); @JsonIgnore
CalculatedFieldLinkConfiguration getReferencedEntityConfig(EntityId entityId);
@JsonIgnore
JsonNode calculatedFieldConfigToJson(EntityType entityType, UUID entityId); JsonNode calculatedFieldConfigToJson(EntityType entityType, UUID entityId);
} }

View File

@ -37,7 +37,7 @@ public class CalculatedFieldLink extends BaseData<CalculatedFieldLinkId> {
@Schema(description = "JSON object with the Calculated Field Id. ", accessMode = Schema.AccessMode.READ_ONLY) @Schema(description = "JSON object with the Calculated Field Id. ", accessMode = Schema.AccessMode.READ_ONLY)
private CalculatedFieldId calculatedFieldId; private CalculatedFieldId calculatedFieldId;
@Schema @Schema
private transient CalculatedFiledLinkConfiguration configuration; private transient CalculatedFieldLinkConfiguration configuration;
public CalculatedFieldLink() { public CalculatedFieldLink() {
super(); super();
@ -47,7 +47,7 @@ public class CalculatedFieldLink extends BaseData<CalculatedFieldLinkId> {
super(id); super(id);
} }
public CalculatedFieldLink(TenantId tenantId, EntityId entityId, CalculatedFieldId calculatedFieldId, CalculatedFiledLinkConfiguration configuration) { public CalculatedFieldLink(TenantId tenantId, EntityId entityId, CalculatedFieldId calculatedFieldId, CalculatedFieldLinkConfiguration configuration) {
this.tenantId = tenantId; this.tenantId = tenantId;
this.entityId = entityId; this.entityId = entityId;
this.calculatedFieldId = calculatedFieldId; this.calculatedFieldId = calculatedFieldId;

View File

@ -21,7 +21,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
@Data @Data
public class CalculatedFiledLinkConfiguration { public class CalculatedFieldLinkConfiguration {
private List<String> attributes = new ArrayList<>(); private List<String> attributes = new ArrayList<>();
private List<String> timeSeries = new ArrayList<>(); private List<String> timeSeries = new ArrayList<>();

View File

@ -110,13 +110,8 @@ public class BaseCalculatedFieldService implements CalculatedFieldService {
@Override @Override
public CalculatedFieldLink saveCalculatedFieldLink(TenantId tenantId, CalculatedFieldLink calculatedFieldLink) { public CalculatedFieldLink saveCalculatedFieldLink(TenantId tenantId, CalculatedFieldLink calculatedFieldLink) {
calculatedFieldLinkDataValidator.validate(calculatedFieldLink, CalculatedFieldLink::getTenantId); calculatedFieldLinkDataValidator.validate(calculatedFieldLink, CalculatedFieldLink::getTenantId);
try {
log.trace("Executing save calculated field link, [{}]", calculatedFieldLink); log.trace("Executing save calculated field link, [{}]", calculatedFieldLink);
return calculatedFieldLinkDao.save(tenantId, calculatedFieldLink); return calculatedFieldLinkDao.save(tenantId, calculatedFieldLink);
} catch (Exception e) {
checkConstraintViolation(e, "calculated_field_link_unq_key", "Calculated Field for such entity id is already exists!");
throw e;
}
} }
@Override @Override

View File

@ -1,119 +0,0 @@
/**
* Copyright © 2016-2024 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.dao.cf;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.cf.BaseCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.CalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.SimpleCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class CalculatedFieldConfigUtil {
// public static CalculatedFieldConfiguration toCalculatedFieldConfig(JsonNode config, EntityType entityType, UUID entityId) {
// if (config == null) {
// return null;
// }
// try {
// CalculatedFieldConfiguration calculatedFieldConfig = new BaseCalculatedFieldConfiguration();
// Map<String, Argument> arguments = new HashMap<>();
//
// JsonNode argumentsNode = config.get("arguments");
// if (argumentsNode != null && argumentsNode.isObject()) {
// argumentsNode.fields().forEachRemaining(entry -> {
// String key = entry.getKey();
// JsonNode argumentNode = entry.getValue();
//
// CalculatedFieldConfig.Argument argument = new CalculatedFieldConfig.Argument();
// if (argumentNode.has("entityType") && argumentNode.has("entityId")) {
// String referencedEntityType = argumentNode.get("entityType").asText();
// UUID referencedEntityId = UUID.fromString(argumentNode.get("entityId").asText());
// argument.setEntityId(EntityIdFactory.getByTypeAndUuid(referencedEntityType, referencedEntityId));
// } else {
// argument.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId));
// }
// argument.setKey(argumentNode.get("key").asText());
// argument.setType(argumentNode.get("type").asText());
//
// if (argumentNode.has("defaultValue")) {
// argument.setDefaultValue(argumentNode.get("defaultValue").asInt());
// }
//
// arguments.put(key, argument);
// });
// }
// calculatedFieldConfig.setArguments(arguments);
//
// JsonNode outputNode = config.get("output");
// if (outputNode != null) {
// CalculatedFieldConfig.Output output = new CalculatedFieldConfig.Output();
// output.setType(outputNode.get("type").asText());
// output.setExpression(outputNode.get("expression").asText());
// calculatedFieldConfig.setOutput(output);
// }
//
// return calculatedFieldConfig;
//
// } catch (Exception e) {
// throw new IllegalArgumentException("Failed to convert JsonNode to CalculatedFieldConfig", e);
// }
// }
//
// public static JsonNode calculatedFieldConfigToJson(CalculatedFieldConfiguration calculatedFieldConfig, EntityType entityType, UUID entityId) {
// if (calculatedFieldConfig == null) {
// return null;
// }
// try {
// ObjectNode configNode = JacksonUtil.newObjectNode();
//
// ObjectNode argumentsNode = configNode.putObject("arguments");
// calculatedFieldConfig.getArguments().forEach((key, argument) -> {
// ObjectNode argumentNode = argumentsNode.putObject(key);
// EntityId referencedEntityId = argument.getEntityId();
// if (referencedEntityId != null) {
// argumentNode.put("entityType", referencedEntityId.getEntityType().name());
// argumentNode.put("entityId", referencedEntityId.getId().toString());
// } else {
// argumentNode.put("entityType", entityType.name());
// argumentNode.put("entityId", entityId.toString());
// }
// argumentNode.put("key", argument.getKey());
// argumentNode.put("type", argument.getType());
// argumentNode.put("defaultValue", argument.getDefaultValue());
// });
//
// if (calculatedFieldConfig.getOutput() != null) {
// ObjectNode outputNode = configNode.putObject("output");
// outputNode.put("type", calculatedFieldConfig.getOutput().getType());
// outputNode.put("expression", calculatedFieldConfig.getOutput().getExpression());
// }
//
// return configNode;
//
// } catch (Exception e) {
// throw new IllegalArgumentException("Failed to convert CalculatedFieldConfig to JsonNode", e);
// }
// }
}

View File

@ -118,7 +118,6 @@ public class CalculatedFieldEntity extends BaseSqlEntity<CalculatedField> implem
} }
private CalculatedFieldConfiguration readCalculatedFieldConfiguration(JsonNode config, EntityType entityType, UUID entityId) { private CalculatedFieldConfiguration readCalculatedFieldConfiguration(JsonNode config, EntityType entityType, UUID entityId) {
String type = config.get("type").asText();
switch (type) { switch (type) {
case "SIMPLE": case "SIMPLE":
return new SimpleCalculatedFieldConfiguration(config, entityType, entityId); return new SimpleCalculatedFieldConfiguration(config, entityType, entityId);

View File

@ -25,7 +25,7 @@ import lombok.EqualsAndHashCode;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.cf.CalculatedFieldLink; import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
import org.thingsboard.server.common.data.cf.CalculatedFiledLinkConfiguration; import org.thingsboard.server.common.data.cf.CalculatedFieldLinkConfiguration;
import org.thingsboard.server.common.data.id.CalculatedFieldId; import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.common.data.id.CalculatedFieldLinkId; import org.thingsboard.server.common.data.id.CalculatedFieldLinkId;
import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
@ -86,7 +86,7 @@ public class CalculatedFieldLinkEntity extends BaseSqlEntity<CalculatedFieldLink
calculatedFieldLink.setTenantId(TenantId.fromUUID(tenantId)); calculatedFieldLink.setTenantId(TenantId.fromUUID(tenantId));
calculatedFieldLink.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId)); calculatedFieldLink.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId));
calculatedFieldLink.setCalculatedFieldId(new CalculatedFieldId(calculatedFieldId)); calculatedFieldLink.setCalculatedFieldId(new CalculatedFieldId(calculatedFieldId));
calculatedFieldLink.setConfiguration(JacksonUtil.treeToValue(configuration, CalculatedFiledLinkConfiguration.class)); calculatedFieldLink.setConfiguration(JacksonUtil.treeToValue(configuration, CalculatedFieldLinkConfiguration.class));
return calculatedFieldLink; return calculatedFieldLink;
} }

View File

@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.CalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.CalculatedFieldLink; import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
import org.thingsboard.server.common.data.cf.CalculatedFiledLinkConfiguration; import org.thingsboard.server.common.data.cf.CalculatedFieldLinkConfiguration;
import org.thingsboard.server.common.data.cf.SimpleCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.SimpleCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.CalculatedFieldId; import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.common.data.id.CalculatedFieldLinkId; import org.thingsboard.server.common.data.id.CalculatedFieldLinkId;
@ -88,7 +88,7 @@ public class DefaultNativeCalculatedFieldRepository implements NativeCalculatedF
calculatedField.setType(type); calculatedField.setType(type);
calculatedField.setName(name); calculatedField.setName(name);
calculatedField.setConfigurationVersion(configurationVersion); calculatedField.setConfigurationVersion(configurationVersion);
calculatedField.setConfiguration(readCalculatedFieldConfiguration(configuration, entityType, entityId)); calculatedField.setConfiguration(readCalculatedFieldConfiguration(type, configuration, entityType, entityId));
calculatedField.setVersion(version); calculatedField.setVersion(version);
calculatedField.setExternalId(externalIdObj != null ? new CalculatedFieldId(UUID.fromString((String) externalIdObj)) : null); calculatedField.setExternalId(externalIdObj != null ? new CalculatedFieldId(UUID.fromString((String) externalIdObj)) : null);
@ -125,7 +125,7 @@ public class DefaultNativeCalculatedFieldRepository implements NativeCalculatedF
calculatedFieldLink.setTenantId(new TenantId(tenantId)); calculatedFieldLink.setTenantId(new TenantId(tenantId));
calculatedFieldLink.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId)); calculatedFieldLink.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId));
calculatedFieldLink.setCalculatedFieldId(new CalculatedFieldId(calculatedFieldId)); calculatedFieldLink.setCalculatedFieldId(new CalculatedFieldId(calculatedFieldId));
calculatedFieldLink.setConfiguration(JacksonUtil.treeToValue(configuration, CalculatedFiledLinkConfiguration.class)); calculatedFieldLink.setConfiguration(JacksonUtil.treeToValue(configuration, CalculatedFieldLinkConfiguration.class));
return calculatedFieldLink; return calculatedFieldLink;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
@ -133,8 +133,7 @@ public class DefaultNativeCalculatedFieldRepository implements NativeCalculatedF
}); });
} }
private CalculatedFieldConfiguration readCalculatedFieldConfiguration(JsonNode config, EntityType entityType, UUID entityId) { private CalculatedFieldConfiguration readCalculatedFieldConfiguration(String type, JsonNode config, EntityType entityType, UUID entityId) {
String type = config.get("type").asText();
switch (type) { switch (type) {
case "SIMPLE": case "SIMPLE":
return new SimpleCalculatedFieldConfiguration(config, entityType, entityId); return new SimpleCalculatedFieldConfiguration(config, entityType, entityId);

View File

@ -925,9 +925,7 @@ CREATE TABLE IF NOT EXISTS calculated_field_link (
tenant_id uuid NOT NULL, tenant_id uuid NOT NULL,
entity_type VARCHAR(32), entity_type VARCHAR(32),
entity_id uuid NOT NULL, entity_id uuid NOT NULL,
-- target_id uuid NOT NULL,
calculated_field_id uuid NOT NULL, calculated_field_id uuid NOT NULL,
configuration varchar(1000000), configuration varchar(10000),
CONSTRAINT calculated_field_link_unq_key UNIQUE (entity_id, calculated_field_id),
CONSTRAINT fk_calculated_field_id FOREIGN KEY (calculated_field_id) REFERENCES calculated_field(id) ON DELETE CASCADE CONSTRAINT fk_calculated_field_id FOREIGN KEY (calculated_field_id) REFERENCES calculated_field(id) ON DELETE CASCADE
); );

View File

@ -31,7 +31,7 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetInfo; import org.thingsboard.server.common.data.asset.AssetInfo;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldConfig; import org.thingsboard.server.common.data.cf.SimpleCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -874,25 +874,25 @@ public class AssetServiceTest extends AbstractServiceTest {
CalculatedField calculatedField = new CalculatedField(); CalculatedField calculatedField = new CalculatedField();
calculatedField.setTenantId(tenantId); calculatedField.setTenantId(tenantId);
calculatedField.setName("Test CF"); calculatedField.setName("Test CF");
calculatedField.setType("Simple"); calculatedField.setType("SIMPLE");
calculatedField.setEntityId(savedAssetWithCf.getId()); calculatedField.setEntityId(savedAssetWithCf.getId());
CalculatedFieldConfig config = new CalculatedFieldConfig(); SimpleCalculatedFieldConfiguration config = new SimpleCalculatedFieldConfiguration();
CalculatedFieldConfig.Argument argument = new CalculatedFieldConfig.Argument(); SimpleCalculatedFieldConfiguration.Argument argument = new SimpleCalculatedFieldConfiguration.Argument();
argument.setEntityId(savedAsset.getId()); argument.setEntityId(savedAsset.getId());
argument.setType("TIME_SERIES"); argument.setType("TIME_SERIES");
argument.setKey("temperature"); argument.setKey("temperature");
config.setArguments(Map.of("T", argument)); config.setArguments(Map.of("T", argument));
CalculatedFieldConfig.Output output = new CalculatedFieldConfig.Output(); SimpleCalculatedFieldConfiguration.Output output = new SimpleCalculatedFieldConfiguration.Output();
output.setType("TIME_SERIES"); output.setType("TIME_SERIES");
output.setExpression("T - (100 - H) / 5"); output.setExpression("T - (100 - H) / 5");
config.setOutput(output); config.setOutput(output);
// calculatedField.setConfiguration(config); calculatedField.setConfiguration(config);
CalculatedField savedCalculatedField = calculatedFieldService.save(calculatedField); CalculatedField savedCalculatedField = calculatedFieldService.save(calculatedField);

View File

@ -24,15 +24,17 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldConfig; import org.thingsboard.server.common.data.cf.CalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.CalculatedFieldLink; import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
import org.thingsboard.server.common.data.cf.CalculatedFieldLinkConfiguration;
import org.thingsboard.server.common.data.cf.SimpleCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.CalculatedFieldId; import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.dao.cf.CalculatedFieldService; import org.thingsboard.server.dao.cf.CalculatedFieldService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -128,16 +130,6 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest {
assertThat(calculatedFieldService.findById(tenantId, savedCalculatedField.getId())).isNull(); assertThat(calculatedFieldService.findById(tenantId, savedCalculatedField.getId())).isNull();
} }
@Test
public void testSaveCalculatedFieldLinkIfCalculatedFieldForSuchEntityExists() {
CalculatedField savedCalculatedField = saveValidCalculatedField();
CalculatedFieldLink calculatedFieldLink = getCalculatedFieldLink(savedCalculatedField);
assertThatThrownBy(() -> calculatedFieldService.saveCalculatedFieldLink(tenantId, calculatedFieldLink))
.isInstanceOf(DataValidationException.class)
.hasMessage("Calculated Field for such entity id is already exists!");
}
private CalculatedField saveValidCalculatedField() { private CalculatedField saveValidCalculatedField() {
Device device = createTestDevice(); Device device = createTestDevice();
CalculatedField calculatedField = getCalculatedField(device.getId(), device.getId()); CalculatedField calculatedField = getCalculatedField(device.getId(), device.getId());
@ -148,10 +140,10 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest {
CalculatedField calculatedField = new CalculatedField(); CalculatedField calculatedField = new CalculatedField();
calculatedField.setTenantId(tenantId); calculatedField.setTenantId(tenantId);
calculatedField.setEntityId(entityId); calculatedField.setEntityId(entityId);
calculatedField.setType("Simple"); calculatedField.setType("SIMPLE");
calculatedField.setName("Test Calculated Field"); calculatedField.setName("Test Calculated Field");
calculatedField.setConfigurationVersion(1); calculatedField.setConfigurationVersion(1);
// calculatedField.setConfiguration(getCalculatedFieldConfig(referencedEntityId)); calculatedField.setConfiguration(getCalculatedFieldConfig(referencedEntityId));
calculatedField.setVersion(1L); calculatedField.setVersion(1L);
return calculatedField; return calculatedField;
} }
@ -160,22 +152,28 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest {
CalculatedFieldLink calculatedFieldLink = new CalculatedFieldLink(); CalculatedFieldLink calculatedFieldLink = new CalculatedFieldLink();
calculatedFieldLink.setTenantId(tenantId); calculatedFieldLink.setTenantId(tenantId);
calculatedFieldLink.setEntityId(calculatedField.getEntityId()); calculatedFieldLink.setEntityId(calculatedField.getEntityId());
// calculatedFieldLink.setConfiguration(calculatedField.getConfiguration()); calculatedFieldLink.setConfiguration(getCalculatedFieldLinkConfiguration());
calculatedFieldLink.setCalculatedFieldId(calculatedField.getId()); calculatedFieldLink.setCalculatedFieldId(calculatedField.getId());
return calculatedFieldLink; return calculatedFieldLink;
} }
private CalculatedFieldConfig getCalculatedFieldConfig(EntityId referencedEntityId) { private CalculatedFieldLinkConfiguration getCalculatedFieldLinkConfiguration() {
CalculatedFieldConfig config = new CalculatedFieldConfig(); CalculatedFieldLinkConfiguration calculatedFieldLinkConfiguration = new CalculatedFieldLinkConfiguration();
calculatedFieldLinkConfiguration.setTimeSeries(List.of("temperature"));
return calculatedFieldLinkConfiguration;
}
CalculatedFieldConfig.Argument argument = new CalculatedFieldConfig.Argument(); private CalculatedFieldConfiguration getCalculatedFieldConfig(EntityId referencedEntityId) {
SimpleCalculatedFieldConfiguration config = new SimpleCalculatedFieldConfiguration();
SimpleCalculatedFieldConfiguration.Argument argument = new SimpleCalculatedFieldConfiguration.Argument();
argument.setEntityId(referencedEntityId); argument.setEntityId(referencedEntityId);
argument.setType("TIME_SERIES"); argument.setType("TIME_SERIES");
argument.setKey("temperature"); argument.setKey("temperature");
config.setArguments(Map.of("T", argument)); config.setArguments(Map.of("T", argument));
CalculatedFieldConfig.Output output = new CalculatedFieldConfig.Output(); SimpleCalculatedFieldConfiguration.Output output = new SimpleCalculatedFieldConfiguration.Output();
output.setType("TIME_SERIES"); output.setType("TIME_SERIES");
output.setExpression("T - (100 - H) / 5"); output.setExpression("T - (100 - H) / 5");

View File

@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldConfig; import org.thingsboard.server.common.data.cf.SimpleCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
@ -369,25 +369,25 @@ public class CustomerServiceTest extends AbstractServiceTest {
CalculatedField calculatedField = new CalculatedField(); CalculatedField calculatedField = new CalculatedField();
calculatedField.setTenantId(tenantId); calculatedField.setTenantId(tenantId);
calculatedField.setName("Test CF"); calculatedField.setName("Test CF");
calculatedField.setType("Simple"); calculatedField.setType("SIMPLE");
calculatedField.setEntityId(savedAsset.getId()); calculatedField.setEntityId(savedAsset.getId());
CalculatedFieldConfig config = new CalculatedFieldConfig(); SimpleCalculatedFieldConfiguration config = new SimpleCalculatedFieldConfiguration();
CalculatedFieldConfig.Argument argument = new CalculatedFieldConfig.Argument(); SimpleCalculatedFieldConfiguration.Argument argument = new SimpleCalculatedFieldConfiguration.Argument();
argument.setEntityId(savedCustomer.getId()); argument.setEntityId(savedCustomer.getId());
argument.setType("TIME_SERIES"); argument.setType("TIME_SERIES");
argument.setKey("temperature"); argument.setKey("temperature");
config.setArguments(Map.of("T", argument)); config.setArguments(Map.of("T", argument));
CalculatedFieldConfig.Output output = new CalculatedFieldConfig.Output(); SimpleCalculatedFieldConfiguration.Output output = new SimpleCalculatedFieldConfiguration.Output();
output.setType("TIME_SERIES"); output.setType("TIME_SERIES");
output.setExpression("T - (100 - H) / 5"); output.setExpression("T - (100 - H) / 5");
config.setOutput(output); config.setOutput(output);
// calculatedField.setConfiguration(config); calculatedField.setConfiguration(config);
CalculatedField savedCalculatedField = calculatedFieldService.save(calculatedField); CalculatedField savedCalculatedField = calculatedFieldService.save(calculatedField);

View File

@ -40,7 +40,7 @@ import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldConfig; import org.thingsboard.server.common.data.cf.SimpleCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.OtaPackageId;
@ -1212,25 +1212,25 @@ public class DeviceServiceTest extends AbstractServiceTest {
CalculatedField calculatedField = new CalculatedField(); CalculatedField calculatedField = new CalculatedField();
calculatedField.setTenantId(tenantId); calculatedField.setTenantId(tenantId);
calculatedField.setName("Test CF"); calculatedField.setName("Test CF");
calculatedField.setType("Simple"); calculatedField.setType("SIMPLE");
calculatedField.setEntityId(deviceWithCf.getId()); calculatedField.setEntityId(deviceWithCf.getId());
CalculatedFieldConfig config = new CalculatedFieldConfig(); SimpleCalculatedFieldConfiguration config = new SimpleCalculatedFieldConfiguration();
CalculatedFieldConfig.Argument argument = new CalculatedFieldConfig.Argument(); SimpleCalculatedFieldConfiguration.Argument argument = new SimpleCalculatedFieldConfiguration.Argument();
argument.setEntityId(device.getId()); argument.setEntityId(device.getId());
argument.setType("TIME_SERIES"); argument.setType("TIME_SERIES");
argument.setKey("temperature"); argument.setKey("temperature");
config.setArguments(Map.of("T", argument)); config.setArguments(Map.of("T", argument));
CalculatedFieldConfig.Output output = new CalculatedFieldConfig.Output(); SimpleCalculatedFieldConfiguration.Output output = new SimpleCalculatedFieldConfiguration.Output();
output.setType("TIME_SERIES"); output.setType("TIME_SERIES");
output.setExpression("T - (100 - H) / 5"); output.setExpression("T - (100 - H) / 5");
config.setOutput(output); config.setOutput(output);
// calculatedField.setConfiguration(config); calculatedField.setConfiguration(config);
CalculatedField savedCalculatedField = calculatedFieldService.save(calculatedField); CalculatedField savedCalculatedField = calculatedFieldService.save(calculatedField);
@ -1241,5 +1241,4 @@ public class DeviceServiceTest extends AbstractServiceTest {
calculatedFieldService.deleteCalculatedField(tenantId, savedCalculatedField.getId()); calculatedFieldService.deleteCalculatedField(tenantId, savedCalculatedField.getId());
} }
} }