diff --git a/application/src/main/data/upgrade/basic/schema_update.sql b/application/src/main/data/upgrade/basic/schema_update.sql index 0add4c0545..495aee00e2 100644 --- a/application/src/main/data/upgrade/basic/schema_update.sql +++ b/application/src/main/data/upgrade/basic/schema_update.sql @@ -46,3 +46,10 @@ WHERE NOT ( ); -- UPDATE TENANT PROFILE CONFIGURATION END + +-- CALCULATED FIELD UNIQUE CONSTRAINT UPDATE START + +ALTER TABLE calculated_field DROP CONSTRAINT IF EXISTS calculated_field_unq_key; +ALTER TABLE calculated_field ADD CONSTRAINT calculated_field_unq_key UNIQUE (entity_id, type, name); + +-- CALCULATED FIELD UNIQUE CONSTRAINT UPDATE END diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/alarm/AlarmCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/alarm/AlarmCalculatedFieldState.java index 657fa80f63..c140ba78af 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/alarm/AlarmCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/alarm/AlarmCalculatedFieldState.java @@ -189,6 +189,8 @@ public class AlarmCalculatedFieldState extends BaseCalculatedFieldState { @Override public ListenableFuture performCalculation(Map updatedArgs, CalculatedFieldCtx ctx) { initCurrentAlarm(ctx); + // FIXME: don't create alarm if attrs were deleted, or config is updated + // TODO: what if expression is changed? do we reevaluate? or only on new events? TbAlarmResult result = createOrClearAlarms(state -> { if (updatedArgs != null) { boolean newEvent = !updatedArgs.isEmpty(); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/cf/BaseCalculatedFieldProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/cf/BaseCalculatedFieldProcessor.java index 4ef6ec7ba2..c3f9300e24 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/cf/BaseCalculatedFieldProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/cf/BaseCalculatedFieldProcessor.java @@ -53,7 +53,7 @@ public abstract class BaseCalculatedFieldProcessor extends BaseEdgeProcessor { } String calculatedFieldName = calculatedField.getName(); - CalculatedField calculatedFieldByName = edgeCtx.getCalculatedFieldService().findByEntityIdAndName(calculatedField.getEntityId(), calculatedFieldName); + CalculatedField calculatedFieldByName = edgeCtx.getCalculatedFieldService().findByEntityIdAndTypeAndName(calculatedField.getEntityId(), calculatedField.getType(), calculatedFieldName); if (calculatedFieldByName != null && !calculatedFieldByName.getId().equals(calculatedFieldId)) { calculatedFieldName = calculatedFieldName + "_" + StringUtils.randomAlphabetic(15); log.warn("[{}] calculatedField with name {} already exists. Renaming calculatedField name to {}", diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/cf/CalculatedFieldService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/cf/CalculatedFieldService.java index e0481b6705..57c6df3c7f 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/cf/CalculatedFieldService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/cf/CalculatedFieldService.java @@ -36,7 +36,7 @@ public interface CalculatedFieldService extends EntityDaoService { CalculatedField findById(TenantId tenantId, CalculatedFieldId calculatedFieldId); - CalculatedField findByEntityIdAndName(EntityId entityId, String name); + CalculatedField findByEntityIdAndTypeAndName(EntityId entityId, CalculatedFieldType type, String name); List findCalculatedFieldIdsByEntityId(TenantId tenantId, EntityId entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java b/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java index 2efa32215a..6b46d3dfb3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java @@ -89,8 +89,9 @@ public class BaseCalculatedFieldService extends AbstractEntityService implements return savedCalculatedField; } catch (Exception e) { checkConstraintViolation(e, - "calculated_field_unq_key", "Calculated Field with such name is already in exists!", - "calculated_field_external_id_unq_key", "Calculated Field with such external id already exists!"); + "calculated_field_unq_key", calculatedField.getType() == CalculatedFieldType.ALARM ? + "Alarm rule with such type already exists" : "Calculated field with such name and type already exists", + "calculated_field_external_id_unq_key", "Calculated field with such external id already exists"); throw e; } } @@ -104,10 +105,10 @@ public class BaseCalculatedFieldService extends AbstractEntityService implements } @Override - public CalculatedField findByEntityIdAndName(EntityId entityId, String name) { - log.trace("Executing findByEntityIdAndName [{}], calculatedFieldName[{}]", entityId, name); + public CalculatedField findByEntityIdAndTypeAndName(EntityId entityId, CalculatedFieldType type, String name) { + log.trace("Executing findByEntityIdAndTypeAndName entityId [{}], type [{}], name [{}]", entityId, type, name); validateId(entityId.getId(), id -> INCORRECT_ENTITY_ID + id); - return calculatedFieldDao.findByEntityIdAndName(entityId, name); + return calculatedFieldDao.findByEntityIdAndTypeAndName(entityId, type, name); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/cf/CalculatedFieldDao.java b/dao/src/main/java/org/thingsboard/server/dao/cf/CalculatedFieldDao.java index 40517fe78b..21b63e8d27 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cf/CalculatedFieldDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cf/CalculatedFieldDao.java @@ -37,7 +37,7 @@ public interface CalculatedFieldDao extends Dao { List findAll(); - CalculatedField findByEntityIdAndName(EntityId entityId, String name); + CalculatedField findByEntityIdAndTypeAndName(EntityId entityId, CalculatedFieldType type, String name); PageData findAll(PageLink pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/CalculatedFieldRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/CalculatedFieldRepository.java index f2c3525a4f..9a1f904788 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/CalculatedFieldRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/CalculatedFieldRepository.java @@ -19,6 +19,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.thingsboard.server.common.data.cf.CalculatedFieldType; import org.thingsboard.server.common.data.id.CalculatedFieldId; import org.thingsboard.server.dao.model.sql.CalculatedFieldEntity; @@ -29,7 +30,7 @@ public interface CalculatedFieldRepository extends JpaRepository findCalculatedFieldIdsByTenantIdAndEntityId(UUID tenantId, UUID entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/JpaCalculatedFieldDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/JpaCalculatedFieldDao.java index 7a8c914e74..e0e5ef60c4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/JpaCalculatedFieldDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/JpaCalculatedFieldDao.java @@ -68,8 +68,8 @@ public class JpaCalculatedFieldDao extends JpaAbstractDao calculatedFieldService.save(calculatedField)) .isInstanceOf(DataValidationException.class) - .hasMessage("Calculated Field with such name is already in exists!"); + .hasMessage("Calculated field with such name and type already exists"); } @Test