From f467fc009e2d2e29484799bec0941378188c407c Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Mon, 3 Mar 2025 16:58:26 +0200 Subject: [PATCH] Refactor cf vc --- .../DefaultEntitiesExportImportService.java | 7 +- .../ie/exporting/impl/AssetExportService.java | 18 +-- .../impl/AssetProfileExportService.java | 17 +-- .../BaseCalculatedFieldsExportService.java | 51 -------- .../impl/DefaultEntityExportService.java | 21 +++ .../exporting/impl/DeviceExportService.java | 11 +- .../impl/DeviceProfileExportService.java | 17 +-- .../ie/importing/impl/AssetImportService.java | 22 ++-- .../impl/AssetProfileImportService.java | 22 ++-- .../BaseCalculatedFieldsImportService.java | 123 ------------------ .../impl/BaseEntityImportService.java | 57 +++++++- .../importing/impl/DeviceImportService.java | 40 ++---- .../impl/DeviceProfileImportService.java | 22 ++-- .../sync/vc/data/EntitiesImportCtx.java | 6 +- .../sync/ie/ExportImportServiceSqlTest.java | 2 - .../service/sync/vc/VersionControlTest.java | 6 +- .../common/data/cf/CalculatedField.java | 37 +++--- .../common/data/id/CalculatedFieldId.java | 3 + .../server/common/data/sync/JsonTbEntity.java | 4 +- .../common/data/sync/ie/AssetExportData.java | 28 ---- .../data/sync/ie/AssetProfileExportData.java | 28 ---- .../sync/ie/CalculatedFieldExportData.java | 56 -------- .../common/data/sync/ie/DeviceExportData.java | 2 +- .../data/sync/ie/DeviceProfileExportData.java | 28 ---- .../common/data/sync/ie/EntityExportData.java | 14 +- .../server/dao/cf/CalculatedFieldDao.java | 3 +- .../server/dao/model/ModelConstants.java | 1 - .../dao/model/sql/CalculatedFieldEntity.java | 10 -- .../dao/sql/cf/CalculatedFieldRepository.java | 11 +- ...efaultNativeCalculatedFieldRepository.java | 1 - .../dao/sql/cf/JpaCalculatedFieldDao.java | 20 --- .../main/resources/sql/schema-entities.sql | 4 +- .../service/CalculatedFieldServiceTest.java | 14 -- 33 files changed, 181 insertions(+), 525 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseCalculatedFieldsExportService.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseCalculatedFieldsImportService.java delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/AssetExportData.java delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/AssetProfileExportData.java delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/CalculatedFieldExportData.java delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceProfileExportData.java diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java index 94b0ddc07e..d45f32c918 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java @@ -23,6 +23,7 @@ import org.thingsboard.server.cache.limits.RateLimitService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; @@ -129,10 +130,10 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS relation, ctx.getUser(), ActionType.RELATION_ADD_OR_UPDATE, null, relation); } - ctx.getCalculatedFields().forEach((calculatedField, created) -> { + for (CalculatedField calculatedField : ctx.getCalculatedFields()) { var savedCalculatedField = calculatedFieldService.save(calculatedField); - logEntityActionService.logEntityAction(ctx.getTenantId(), savedCalculatedField.getId(), savedCalculatedField, created ? ActionType.ADDED : ActionType.UPDATED, ctx.getUser()); - }); + logEntityActionService.logEntityAction(ctx.getTenantId(), savedCalculatedField.getId(), savedCalculatedField, ActionType.ADDED, ctx.getUser()); + } } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetExportService.java index 6f56fa5145..fbda92b6be 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetExportService.java @@ -15,12 +15,12 @@ */ package org.thingsboard.server.service.sync.ie.exporting.impl; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.sync.ie.AssetExportData; -import org.thingsboard.server.dao.cf.CalculatedFieldService; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx; @@ -28,22 +28,18 @@ import java.util.Set; @Service @TbCoreComponent -public class AssetExportService extends BaseCalculatedFieldsExportService { - - protected AssetExportService(CalculatedFieldService calculatedFieldService) { - super(calculatedFieldService); - } +@RequiredArgsConstructor +public class AssetExportService extends BaseEntityExportService> { @Override - protected void setRelatedEntities(EntitiesExportCtx ctx, Asset asset, AssetExportData exportData) { + protected void setRelatedEntities(EntitiesExportCtx ctx, Asset asset, EntityExportData exportData) { asset.setCustomerId(getExternalIdOrElseInternal(ctx, asset.getCustomerId())); asset.setAssetProfileId(getExternalIdOrElseInternal(ctx, asset.getAssetProfileId())); - setCalculatedFields(ctx, asset, exportData); } @Override - protected AssetExportData newExportData() { - return new AssetExportData(); + protected EntityExportData newExportData() { + return new EntityExportData<>(); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetProfileExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetProfileExportService.java index 2314db92f5..b670daf06c 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetProfileExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AssetProfileExportService.java @@ -19,8 +19,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.id.AssetProfileId; -import org.thingsboard.server.common.data.sync.ie.AssetProfileExportData; -import org.thingsboard.server.dao.cf.CalculatedFieldService; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx; @@ -28,23 +27,13 @@ import java.util.Set; @Service @TbCoreComponent -public class AssetProfileExportService extends BaseCalculatedFieldsExportService { - - protected AssetProfileExportService(CalculatedFieldService calculatedFieldService) { - super(calculatedFieldService); - } +public class AssetProfileExportService extends BaseEntityExportService> { @Override - protected void setRelatedEntities(EntitiesExportCtx ctx, AssetProfile assetProfile, AssetProfileExportData exportData) { + protected void setRelatedEntities(EntitiesExportCtx ctx, AssetProfile assetProfile, EntityExportData exportData) { assetProfile.setDefaultDashboardId(getExternalIdOrElseInternal(ctx, assetProfile.getDefaultDashboardId())); assetProfile.setDefaultRuleChainId(getExternalIdOrElseInternal(ctx, assetProfile.getDefaultRuleChainId())); assetProfile.setDefaultEdgeRuleChainId(getExternalIdOrElseInternal(ctx, assetProfile.getDefaultEdgeRuleChainId())); - setCalculatedFields(ctx, assetProfile, exportData); - } - - @Override - protected AssetProfileExportData newExportData() { - return new AssetProfileExportData(); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseCalculatedFieldsExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseCalculatedFieldsExportService.java deleted file mode 100644 index e28f8aaa79..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseCalculatedFieldsExportService.java +++ /dev/null @@ -1,51 +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.service.sync.ie.exporting.impl; - -import org.thingsboard.server.common.data.ExportableEntity; -import org.thingsboard.server.common.data.HasTenantId; -import org.thingsboard.server.common.data.cf.CalculatedField; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.sync.ie.CalculatedFieldExportData; -import org.thingsboard.server.dao.cf.CalculatedFieldService; -import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx; - -import java.util.List; - -public abstract class BaseCalculatedFieldsExportService & HasTenantId, D extends CalculatedFieldExportData> extends BaseEntityExportService { - - protected final CalculatedFieldService calculatedFieldService; - - protected BaseCalculatedFieldsExportService(CalculatedFieldService calculatedFieldService) { - this.calculatedFieldService = calculatedFieldService; - } - - protected void setCalculatedFields(EntitiesExportCtx ctx, E entity, D exportData) { - if (ctx.getSettings().isExportCalculatedFields()) { - List calculatedFields = calculatedFieldService.findCalculatedFieldsByEntityId(ctx.getTenantId(), entity.getId()); - calculatedFields.forEach(calculatedField -> { - calculatedField.getConfiguration().getArguments().values().forEach(argument -> { - if (argument.getRefEntityId() != null) { - EntityId externalId = getExternalIdOrElseInternal(ctx, argument.getRefEntityId()); - argument.setRefEntityId(externalId); - } - }); - }); - exportData.setCalculatedFields(calculatedFields); - } - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java index b0bea68290..5c2fcc7dc6 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.HasVersion; +import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.sync.ie.AttributeExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.cf.CalculatedFieldService; import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.ie.exporting.EntityExportService; @@ -59,6 +61,8 @@ public class DefaultEntityExportService ctx, I entityId) throws ThingsboardException { @@ -98,6 +102,10 @@ public class DefaultEntityExportService> attributes = exportAttributes(ctx, entity); exportData.setAttributes(attributes); } + if (ctx.getSettings().isExportCalculatedFields()) { + List calculatedFields = exportCalculatedFields(ctx, entity.getId()); + exportData.setCalculatedFields(calculatedFields); + } } private List exportRelations(EntitiesExportCtx ctx, E entity) throws ThingsboardException { @@ -141,6 +149,19 @@ public class DefaultEntityExportService exportCalculatedFields(EntitiesExportCtx ctx, EntityId entityId) { + List calculatedFields = calculatedFieldService.findCalculatedFieldsByEntityId(ctx.getTenantId(), entityId); + calculatedFields.forEach(calculatedField -> { + calculatedField.setEntityId(getExternalIdOrElseInternal(ctx, entityId)); + calculatedField.getConfiguration().getArguments().values().forEach(argument -> { + if (argument.getRefEntityId() != null) { + argument.setRefEntityId(getExternalIdOrElseInternal(ctx, argument.getRefEntityId())); + } + }); + }); + return calculatedFields; + } + protected ID getExternalIdOrElseInternal(EntitiesExportCtx ctx, ID internalId) { if (internalId == null || internalId.isNullUid()) return internalId; var result = ctx.getExternalId(internalId); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceExportService.java index f1b5ade487..7d5f7ee57e 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceExportService.java @@ -15,12 +15,12 @@ */ package org.thingsboard.server.service.sync.ie.exporting.impl; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.sync.ie.DeviceExportData; -import org.thingsboard.server.dao.cf.CalculatedFieldService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx; @@ -29,15 +29,11 @@ import java.util.Set; @Service @TbCoreComponent -public class DeviceExportService extends BaseCalculatedFieldsExportService { +@RequiredArgsConstructor +public class DeviceExportService extends BaseEntityExportService { private final DeviceCredentialsService deviceCredentialsService; - public DeviceExportService(CalculatedFieldService calculatedFieldService, DeviceCredentialsService deviceCredentialsService) { - super(calculatedFieldService); - this.deviceCredentialsService = deviceCredentialsService; - } - @Override protected void setRelatedEntities(EntitiesExportCtx ctx, Device device, DeviceExportData exportData) { device.setCustomerId(getExternalIdOrElseInternal(ctx, device.getCustomerId())); @@ -48,7 +44,6 @@ public class DeviceExportService extends BaseCalculatedFieldsExportService { - - protected DeviceProfileExportService(CalculatedFieldService calculatedFieldService) { - super(calculatedFieldService); - } +public class DeviceProfileExportService extends BaseEntityExportService> { @Override - protected void setRelatedEntities(EntitiesExportCtx ctx, DeviceProfile deviceProfile, DeviceProfileExportData exportData) { + protected void setRelatedEntities(EntitiesExportCtx ctx, DeviceProfile deviceProfile, EntityExportData exportData) { deviceProfile.setDefaultDashboardId(getExternalIdOrElseInternal(ctx, deviceProfile.getDefaultDashboardId())); deviceProfile.setDefaultRuleChainId(getExternalIdOrElseInternal(ctx, deviceProfile.getDefaultRuleChainId())); deviceProfile.setDefaultEdgeRuleChainId(getExternalIdOrElseInternal(ctx, deviceProfile.getDefaultEdgeRuleChainId())); - setCalculatedFields(ctx, deviceProfile, exportData); - } - - @Override - protected DeviceProfileExportData newExportData() { - return new DeviceProfileExportData(); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetImportService.java index 0b0649072e..7cd4c3aca1 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetImportService.java @@ -15,28 +15,24 @@ */ package org.thingsboard.server.service.sync.ie.importing.impl; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.sync.ie.AssetExportData; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.cf.CalculatedFieldService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx; @Service @TbCoreComponent -public class AssetImportService extends BaseCalculatedFieldsImportService { +@RequiredArgsConstructor +public class AssetImportService extends BaseEntityImportService> { private final AssetService assetService; - public AssetImportService(CalculatedFieldService calculatedFieldService, AssetService assetService) { - super(calculatedFieldService); - this.assetService = assetService; - } - @Override protected void setOwner(TenantId tenantId, Asset asset, IdProvider idProvider) { asset.setTenantId(tenantId); @@ -44,14 +40,18 @@ public class AssetImportService extends BaseCalculatedFieldsImportService exportData, IdProvider idProvider) { asset.setAssetProfileId(idProvider.getInternalId(asset.getAssetProfileId())); return asset; } @Override - protected Asset saveOrUpdate(EntitiesImportCtx ctx, Asset asset, AssetExportData exportData, IdProvider idProvider) { - return saveOrUpdateEntity(ctx, asset, exportData, idProvider, assetService::saveAsset); + protected Asset saveOrUpdate(EntitiesImportCtx ctx, Asset asset, EntityExportData exportData, IdProvider idProvider) { + Asset savedAsset = assetService.saveAsset(asset); + if (ctx.isFinalImportAttempt() || ctx.getCurrentImportResult().isUpdatedAllExternalIds()) { + importCalculatedFields(ctx, savedAsset, exportData, idProvider); + } + return savedAsset; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java index 6797c92c81..32a0090a4a 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.sync.ie.importing.impl; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; @@ -22,30 +23,25 @@ import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.sync.ie.AssetProfileExportData; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.dao.asset.AssetProfileService; -import org.thingsboard.server.dao.cf.CalculatedFieldService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx; @Service @TbCoreComponent -public class AssetProfileImportService extends BaseCalculatedFieldsImportService { +@RequiredArgsConstructor +public class AssetProfileImportService extends BaseEntityImportService> { private final AssetProfileService assetProfileService; - public AssetProfileImportService(CalculatedFieldService calculatedFieldService, AssetProfileService assetProfileService) { - super(calculatedFieldService); - this.assetProfileService = assetProfileService; - } - @Override protected void setOwner(TenantId tenantId, AssetProfile assetProfile, IdProvider idProvider) { assetProfile.setTenantId(tenantId); } @Override - protected AssetProfile prepare(EntitiesImportCtx ctx, AssetProfile assetProfile, AssetProfile old, AssetProfileExportData exportData, IdProvider idProvider) { + protected AssetProfile prepare(EntitiesImportCtx ctx, AssetProfile assetProfile, AssetProfile old, EntityExportData exportData, IdProvider idProvider) { assetProfile.setDefaultRuleChainId(idProvider.getInternalId(assetProfile.getDefaultRuleChainId())); assetProfile.setDefaultDashboardId(idProvider.getInternalId(assetProfile.getDefaultDashboardId())); assetProfile.setDefaultEdgeRuleChainId(idProvider.getInternalId(assetProfile.getDefaultEdgeRuleChainId())); @@ -53,8 +49,12 @@ public class AssetProfileImportService extends BaseCalculatedFieldsImportService } @Override - protected AssetProfile saveOrUpdate(EntitiesImportCtx ctx, AssetProfile assetProfile, AssetProfileExportData exportData, IdProvider idProvider) { - return saveOrUpdateEntity(ctx, assetProfile, exportData, idProvider, assetProfileService::saveAssetProfile); + protected AssetProfile saveOrUpdate(EntitiesImportCtx ctx, AssetProfile assetProfile, EntityExportData exportData, IdProvider idProvider) { + AssetProfile saved = assetProfileService.saveAssetProfile(assetProfile); + if (ctx.isFinalImportAttempt() || ctx.getCurrentImportResult().isUpdatedAllExternalIds()) { + importCalculatedFields(ctx, saved, exportData, idProvider); + } + return saved; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseCalculatedFieldsImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseCalculatedFieldsImportService.java deleted file mode 100644 index ffa51938f0..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseCalculatedFieldsImportService.java +++ /dev/null @@ -1,123 +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.service.sync.ie.importing.impl; - -import org.thingsboard.server.common.data.ExportableEntity; -import org.thingsboard.server.common.data.HasTenantId; -import org.thingsboard.server.common.data.cf.CalculatedField; -import org.thingsboard.server.common.data.id.CalculatedFieldId; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.sync.ie.CalculatedFieldExportData; -import org.thingsboard.server.dao.cf.CalculatedFieldService; -import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -public abstract class BaseCalculatedFieldsImportService & HasTenantId, D extends CalculatedFieldExportData> extends BaseEntityImportService { - - private final CalculatedFieldService calculatedFieldService; - - protected BaseCalculatedFieldsImportService(CalculatedFieldService calculatedFieldService) { - this.calculatedFieldService = calculatedFieldService; - } - - protected E saveOrUpdateEntity(EntitiesImportCtx ctx, E entity, D exportData, IdProvider idProvider, Function saveFunction) { - E savedEntity = saveFunction.apply(entity); - - if (ctx.isFinalImportAttempt() || ctx.getCurrentImportResult().isUpdatedAllExternalIds()) { - saveCalculatedFields(ctx, savedEntity, exportData, idProvider); - } - return savedEntity; - } - - protected void saveCalculatedFields(EntitiesImportCtx ctx, E savedEntity, D exportData, IdProvider idProvider) { - if (exportData.getCalculatedFields() == null || !ctx.isSaveCalculatedFields()) { - return; - } - - exportData.getCalculatedFields().forEach(calculatedField -> { - calculatedField.setTenantId(savedEntity.getTenantId()); - calculatedField.setExternalId(calculatedField.getId()); - calculatedField.setId(idProvider.getInternalId(calculatedField.getId(), false)); - calculatedField.setEntityId(savedEntity.getId()); - - calculatedField.getConfiguration().getArguments().values().forEach(argument -> { - if (argument.getRefEntityId() != null) { - argument.setRefEntityId(idProvider.getInternalId(argument.getRefEntityId(), false)); - } - }); - - calculatedFieldService.save(calculatedField); - }); - } - - @Override - protected boolean updateRelatedEntitiesIfUnmodified(EntitiesImportCtx ctx, E prepared, D exportData, IdProvider idProvider) { - boolean updated = super.updateRelatedEntitiesIfUnmodified(ctx, prepared, exportData, idProvider); - updated |= updateCalculatedFields(ctx, prepared, exportData, idProvider); - return updated; - } - - private boolean updateCalculatedFields(EntitiesImportCtx ctx, E prepared, D exportData, IdProvider idProvider) { - var calculatedFields = exportData.getCalculatedFields(); - if (calculatedFields == null || !ctx.isSaveCalculatedFields()) { - return false; - } - Map calculatedFieldMap = calculatedFields.stream() - .peek(newField -> { - newField.setTenantId(ctx.getTenantId()); - newField.setExternalId(newField.getId()); - newField.setId(idProvider.getInternalId(newField.getId(), false)); - newField.setEntityId(prepared.getId()); - newField.getConfiguration().getArguments().values().forEach(argument -> { - argument.setRefEntityId(idProvider.getInternalId(argument.getRefEntityId(), false)); - }); - }) - .collect(Collectors.toMap(CalculatedField::getId, field -> field)); - - List existingFields = calculatedFieldService.findCalculatedFieldsByEntityId(ctx.getTenantId(), prepared.getId()); - boolean updated = false; - - Map result = new LinkedHashMap<>(); - for (CalculatedField existingField : existingFields) { - if (calculatedFieldMap.containsKey(existingField.getId())) { - CalculatedField newField = calculatedFieldMap.get(existingField.getId()); - if (!newField.equals(existingField)) { - result.put(newField, false); - } - calculatedFieldMap.remove(existingField.getId()); - } else { - updated = true; - calculatedFieldService.deleteCalculatedField(ctx.getTenantId(), existingField.getId()); - } - } - - for (CalculatedField newField : calculatedFieldMap.values()) { - result.put(newField, true); - } - - if (!result.isEmpty()) { - updated = true; - ctx.addCalculatedFields(result); - } - return updated; - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java index 7044b235a0..65f2b4f032 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.HasDefaultOption; import org.thingsboard.server.common.data.HasVersion; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -50,6 +51,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.sync.ie.AttributeExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityImportResult; +import org.thingsboard.server.dao.cf.CalculatedFieldService; import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.service.action.EntityActionService; @@ -78,6 +80,8 @@ public abstract class BaseEntityImportService existing = calculatedFieldService.findCalculatedFieldsByEntityId(ctx.getTenantId(), savedEntity.getId()); + List fieldsToSave = exportData.getCalculatedFields().stream() + .peek(calculatedField -> { + calculatedField.setTenantId(ctx.getTenantId()); + calculatedField.setEntityId(savedEntity.getId()); + calculatedField.getConfiguration().getArguments().values().forEach(argument -> { + if (argument.getRefEntityId() != null) { + argument.setRefEntityId(idProvider.getInternalId(argument.getRefEntityId(), false)); + } + }); + }).toList(); + + for (CalculatedField existingField : existing) { + boolean found = fieldsToSave.stream().anyMatch(importedField -> compareCalculatedFields(existingField, importedField)); + if (!found) { + calculatedFieldService.deleteCalculatedField(ctx.getTenantId(), existingField.getId()); + updated = true; + } + } + + for (CalculatedField calculatedField : fieldsToSave) { + boolean found = existing.stream().anyMatch(existingField -> compareCalculatedFields(existingField, calculatedField)); + if (!found) { + calculatedFieldService.save(calculatedField); + updated = true; + } + } + return updated; + } + + private boolean compareCalculatedFields(CalculatedField existingField, CalculatedField newField) { + CalculatedField oldCopy = new CalculatedField(existingField); + CalculatedField newCopy = new CalculatedField(newField); + oldCopy.setId(null); + newCopy.setId(null); + oldCopy.setVersion(null); + newCopy.setVersion(null); + oldCopy.setCreatedTime(0); + newCopy.setCreatedTime(0); + return oldCopy.equals(newCopy); + } + protected void onEntitySaved(User user, E savedEntity, E oldEntity) throws ThingsboardException { logEntityActionService.logEntityAction(user.getTenantId(), savedEntity.getId(), savedEntity, null, oldEntity == null ? ActionType.ADDED : ActionType.UPDATED, user); } - @SuppressWarnings("unchecked") protected E findExistingEntity(EntitiesImportCtx ctx, E entity, IdProvider idProvider) { return (E) Optional.ofNullable(entitiesService.findEntityByTenantIdAndExternalId(ctx.getTenantId(), entity.getId())) @@ -313,10 +364,10 @@ public abstract class BaseEntityImportService new MissingEntityException(externalId)); } - @SuppressWarnings("unchecked") @RequiredArgsConstructor protected class IdProvider { + private final EntitiesImportCtx ctx; private final EntityImportResult importResult; diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceImportService.java index c8e99cdbc1..92bdb1e294 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceImportService.java @@ -15,13 +15,13 @@ */ package org.thingsboard.server.service.sync.ie.importing.impl; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.sync.ie.DeviceExportData; -import org.thingsboard.server.dao.cf.CalculatedFieldService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -29,17 +29,12 @@ import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx; @Service @TbCoreComponent -public class DeviceImportService extends BaseCalculatedFieldsImportService { +@RequiredArgsConstructor +public class DeviceImportService extends BaseEntityImportService { private final DeviceService deviceService; private final DeviceCredentialsService credentialsService; - public DeviceImportService(CalculatedFieldService calculatedFieldService, DeviceService deviceService, DeviceCredentialsService credentialsService) { - super(calculatedFieldService); - this.deviceService = deviceService; - this.credentialsService = credentialsService; - } - @Override protected void setOwner(TenantId tenantId, Device device, IdProvider idProvider) { device.setTenantId(tenantId); @@ -78,7 +73,7 @@ public class DeviceImportService extends BaseCalculatedFieldsImportService { +@RequiredArgsConstructor +public class DeviceProfileImportService extends BaseEntityImportService> { private final DeviceProfileService deviceProfileService; - public DeviceProfileImportService(CalculatedFieldService calculatedFieldService, DeviceProfileService deviceProfileService) { - super(calculatedFieldService); - this.deviceProfileService = deviceProfileService; - } - @Override protected void setOwner(TenantId tenantId, DeviceProfile deviceProfile, IdProvider idProvider) { deviceProfile.setTenantId(tenantId); } @Override - protected DeviceProfile prepare(EntitiesImportCtx ctx, DeviceProfile deviceProfile, DeviceProfile old, DeviceProfileExportData exportData, IdProvider idProvider) { + protected DeviceProfile prepare(EntitiesImportCtx ctx, DeviceProfile deviceProfile, DeviceProfile old, EntityExportData exportData, IdProvider idProvider) { deviceProfile.setDefaultRuleChainId(idProvider.getInternalId(deviceProfile.getDefaultRuleChainId())); deviceProfile.setDefaultEdgeRuleChainId(idProvider.getInternalId(deviceProfile.getDefaultEdgeRuleChainId())); deviceProfile.setDefaultDashboardId(idProvider.getInternalId(deviceProfile.getDefaultDashboardId())); @@ -55,8 +51,12 @@ public class DeviceProfileImportService extends BaseCalculatedFieldsImportServic } @Override - protected DeviceProfile saveOrUpdate(EntitiesImportCtx ctx, DeviceProfile deviceProfile, DeviceProfileExportData exportData, IdProvider idProvider) { - return saveOrUpdateEntity(ctx, deviceProfile, exportData, idProvider, deviceProfileService::saveDeviceProfile); + protected DeviceProfile saveOrUpdate(EntitiesImportCtx ctx, DeviceProfile deviceProfile, EntityExportData exportData, IdProvider idProvider) { + DeviceProfile saved = deviceProfileService.saveDeviceProfile(deviceProfile); + if (ctx.isFinalImportAttempt() || ctx.getCurrentImportResult().isUpdatedAllExternalIds()) { + importCalculatedFields(ctx, saved, exportData, idProvider); + } + return saved; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesImportCtx.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesImportCtx.java index c1a8dad161..726dd12102 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesImportCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesImportCtx.java @@ -56,7 +56,7 @@ public class EntitiesImportCtx { private final Set notFoundIds = new HashSet<>(); private final Set relations = new LinkedHashSet<>(); - private final Map calculatedFields = new LinkedHashMap<>(); + private final Set calculatedFields = new LinkedHashSet<>(); private boolean finalImportAttempt = false; private EntityImportSettings settings; @@ -127,8 +127,8 @@ public class EntitiesImportCtx { relations.addAll(values); } - public void addCalculatedFields(Map calculatedFieldMap) { - calculatedFields.putAll(calculatedFieldMap); + public void addCalculatedFields(Collection values) { + calculatedFields.addAll(values); } public void addReferenceCallback(EntityId externalId, ThrowingRunnable tr) { diff --git a/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java b/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java index 9184a3c034..a75fbba095 100644 --- a/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java @@ -288,7 +288,6 @@ public class ExportImportServiceSqlTest extends AbstractControllerTest { assertThat(calculatedFields.size()).isOne(); var importedCalculatedField = calculatedFields.get(0); assertThat(importedCalculatedField.getName()).isEqualTo(calculatedField.getName()); - assertThat(importedCalculatedField.getExternalId()).isEqualTo(calculatedField.getId()); EntityExportData updatedDeviceEntity = getAndClone(entitiesExportData, EntityType.DEVICE); updatedDeviceEntity.getEntity().setLabel("t" + updatedDeviceEntity.getEntity().getLabel()); @@ -303,7 +302,6 @@ public class ExportImportServiceSqlTest extends AbstractControllerTest { calculatedFields = calculatedFieldService.findCalculatedFieldsByEntityId(tenantId2, importedDevice.getId()); assertThat(calculatedFields.size()).isOne(); importedCalculatedField = calculatedFields.get(0); - assertThat(importedCalculatedField.getExternalId()).isEqualTo(calculatedField.getId()); assertThat(importedCalculatedField.getName()).startsWith("t_"); } diff --git a/application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java b/application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java index 453fea676f..d90ca60333 100644 --- a/application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java @@ -575,7 +575,7 @@ public class VersionControlTest extends AbstractControllerTest { public void testVcWithCalculatedFields_betweenTenants() throws Exception { Asset asset = createAsset(null, null, "Asset 1"); Device device = createDevice(null, null, "Device 1", "test1"); - CalculatedField calculatedField = createCalculatedField("CalculatedField1", device.getId(), asset.getId()); + createCalculatedField("CalculatedField1", device.getId(), asset.getId()); String versionId = createVersion("calculated fields of asset and device", EntityType.ASSET, EntityType.DEVICE, EntityType.DEVICE_PROFILE, EntityType.ASSET_PROFILE); loginTenant2(); @@ -588,13 +588,13 @@ public class VersionControlTest extends AbstractControllerTest { CalculatedField importedCalculatedField = findCalculatedFieldByEntityId(importedDevice.getId()); checkImportedEntity(tenantId1, device, tenantId2, importedDevice); checkImportedEntity(tenantId1, asset, tenantId2, importedAsset); - checkImportedEntity(tenantId1, calculatedField, tenantId2, importedCalculatedField); List importedCalculatedFields = findCalculatedFieldsByEntityId(importedDevice.getId()); assertThat(importedCalculatedFields).size().isOne(); assertThat(importedCalculatedFields.get(0)).satisfies(importedField -> { assertThat(importedField.getName()).isEqualTo(importedCalculatedField.getName()); assertThat(importedField.getType()).isEqualTo(importedCalculatedField.getType()); + assertThat(importedField.getId()).isNotEqualTo(importedCalculatedField.getId()); }); } @@ -606,7 +606,7 @@ public class VersionControlTest extends AbstractControllerTest { loadVersion(versionId, EntityType.ASSET); CalculatedField importedCalculatedField = findCalculatedFieldByEntityId(asset.getId()); - checkImportedEntity(tenantId1, calculatedField, tenantId1, importedCalculatedField); + assertThat(importedCalculatedField.getId()).isEqualTo(calculatedField.getId()); assertThat(importedCalculatedField.getName()).isEqualTo(calculatedField.getName()); assertThat(importedCalculatedField.getConfiguration()).isEqualTo(calculatedField.getConfiguration()); assertThat(importedCalculatedField.getType()).isEqualTo(calculatedField.getType()); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/CalculatedField.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/CalculatedField.java index b45d7c6921..b86f30ca78 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/CalculatedField.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/CalculatedField.java @@ -23,7 +23,6 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import org.thingsboard.server.common.data.BaseData; -import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.HasDebugSettings; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; @@ -42,7 +41,7 @@ import java.io.Serial; @Schema @Data @EqualsAndHashCode(callSuper = true) -public class CalculatedField extends BaseData implements HasName, HasTenantId, HasVersion, ExportableEntity, HasDebugSettings { +public class CalculatedField extends BaseData implements HasName, HasTenantId, HasVersion, HasDebugSettings { @Serial private static final long serialVersionUID = 4491966747773381420L; @@ -69,9 +68,6 @@ public class CalculatedField extends BaseData implements HasN @Getter @Setter private Long version; - @Getter - @Setter - private CalculatedFieldId externalId; public CalculatedField() { super(); @@ -81,21 +77,7 @@ public class CalculatedField extends BaseData implements HasN super(id); } - public CalculatedField(CalculatedField other) { - super(other); - this.tenantId = other.tenantId; - this.entityId = other.entityId; - this.type = other.type; - this.name = other.name; - this.configurationVersion = other.configurationVersion; - this.configuration = other.configuration; - this.version = other.version; - this.externalId = other.externalId; - this.debugMode = other.debugMode; - this.debugSettings = other.debugSettings; - } - - public CalculatedField(TenantId tenantId, EntityId entityId, CalculatedFieldType type, String name, int configurationVersion, CalculatedFieldConfiguration configuration, Long version, CalculatedFieldId externalId) { + public CalculatedField(TenantId tenantId, EntityId entityId, CalculatedFieldType type, String name, int configurationVersion, CalculatedFieldConfiguration configuration, Long version) { this.tenantId = tenantId; this.entityId = entityId; this.type = type; @@ -103,7 +85,19 @@ public class CalculatedField extends BaseData implements HasN this.configurationVersion = configurationVersion; this.configuration = configuration; this.version = version; - this.externalId = externalId; + } + + public CalculatedField(CalculatedField calculatedField) { + super(calculatedField); + this.tenantId = calculatedField.tenantId; + this.entityId = calculatedField.entityId; + this.type = calculatedField.type; + this.name = calculatedField.name; + this.debugMode = calculatedField.debugMode; + this.debugSettings = calculatedField.debugSettings; + this.configurationVersion = calculatedField.configurationVersion; + this.configuration = calculatedField.configuration; + this.version = calculatedField.version; } @Schema(description = "JSON object with the Calculated Field Id. Referencing non-existing Calculated Field Id will cause error.") @@ -129,7 +123,6 @@ public class CalculatedField extends BaseData implements HasN .append(", configurationVersion=").append(configurationVersion) .append(", configuration=").append(configuration) .append(", version=").append(version) - .append(", externalId=").append(externalId) .append(", createdTime=").append(createdTime) .append(", id=").append(id).append(']') .toString(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/CalculatedFieldId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/CalculatedFieldId.java index 0a83f1a19f..e17a066d88 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/CalculatedFieldId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/CalculatedFieldId.java @@ -20,11 +20,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import org.thingsboard.server.common.data.EntityType; +import java.io.Serial; import java.util.UUID; @Schema public class CalculatedFieldId extends UUIDBased implements EntityId { + @Serial private static final long serialVersionUID = 1L; @JsonCreator @@ -41,4 +43,5 @@ public class CalculatedFieldId extends UUIDBased implements EntityId { public EntityType getEntityType() { return EntityType.CALCULATED_FIELD; } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java index 5dfe6ac8b2..c763daeb7f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java @@ -28,7 +28,6 @@ import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; -import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; @@ -59,8 +58,7 @@ import java.lang.annotation.Target; @Type(name = "NOTIFICATION_TEMPLATE", value = NotificationTemplate.class), @Type(name = "NOTIFICATION_TARGET", value = NotificationTarget.class), @Type(name = "NOTIFICATION_RULE", value = NotificationRule.class), - @Type(name = "TB_RESOURCE", value = TbResource.class), - @Type(name = "CALCULATED_FIELD", value = CalculatedField.class) + @Type(name = "TB_RESOURCE", value = TbResource.class) }) @JsonIgnoreProperties(value = {"tenantId", "createdTime", "version"}, ignoreUnknown = true) public @interface JsonTbEntity { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/AssetExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/AssetExportData.java deleted file mode 100644 index 4bb836d5d9..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/AssetExportData.java +++ /dev/null @@ -1,28 +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.sync.ie; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.thingsboard.server.common.data.asset.Asset; - -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Data -public class AssetExportData extends CalculatedFieldExportData { - -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/AssetProfileExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/AssetProfileExportData.java deleted file mode 100644 index 42d9523828..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/AssetProfileExportData.java +++ /dev/null @@ -1,28 +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.sync.ie; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.thingsboard.server.common.data.asset.AssetProfile; - -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Data -public class AssetProfileExportData extends CalculatedFieldExportData { - -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/CalculatedFieldExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/CalculatedFieldExportData.java deleted file mode 100644 index 7741f88822..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/CalculatedFieldExportData.java +++ /dev/null @@ -1,56 +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.sync.ie; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.thingsboard.server.common.data.ExportableEntity; -import org.thingsboard.server.common.data.cf.CalculatedField; - -import java.util.Comparator; -import java.util.List; - -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CalculatedFieldExportData> extends EntityExportData { - - public static final Comparator calculatedFieldsComparator = Comparator.comparing(CalculatedField::getName); - - @JsonProperty(index = 102) - @JsonIgnoreProperties({"entityId", "createdTime", "version"}) - private List calculatedFields; - - @JsonIgnore - @Override - public boolean hasCalculatedFields() { - return calculatedFields != null; - } - - @Override - public CalculatedFieldExportData sort() { - super.sort(); - if (calculatedFields != null && !calculatedFields.isEmpty()) { - calculatedFields.sort(calculatedFieldsComparator); - } - return this; - } - -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java index a391067c74..98948ca642 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Data -public class DeviceExportData extends CalculatedFieldExportData { +public class DeviceExportData extends EntityExportData { @JsonProperty(index = 3) @JsonIgnoreProperties({"id", "deviceId", "createdTime", "version"}) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceProfileExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceProfileExportData.java deleted file mode 100644 index b6b4d9bdcf..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceProfileExportData.java +++ /dev/null @@ -1,28 +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.sync.ie; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.thingsboard.server.common.data.DeviceProfile; - -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Data -public class DeviceProfileExportData extends CalculatedFieldExportData { - -} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java index 5b7d95db1a..072be6acf2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import lombok.Data; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; +import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.sync.JsonTbEntity; @@ -37,10 +38,7 @@ import java.util.Map; @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "entityType", include = As.EXISTING_PROPERTY, visible = true, defaultImpl = EntityExportData.class) @JsonSubTypes({ - @Type(name = "DEVICE_PROFILE", value = DeviceProfileExportData.class), - @Type(name = "ASSET_PROFILE", value = AssetProfileExportData.class), @Type(name = "DEVICE", value = DeviceExportData.class), - @Type(name = "ASSET", value = AssetExportData.class), @Type(name = "RULE_CHAIN", value = RuleChainExportData.class), @Type(name = "WIDGET_TYPE", value = WidgetTypeExportData.class), @Type(name = "WIDGETS_BUNDLE", value = WidgetsBundleExportData.class) @@ -58,6 +56,8 @@ public class EntityExportData> { public static final Comparator attrComparator = Comparator .comparing(AttributeExportData::getKey).thenComparing(AttributeExportData::getLastUpdateTs); + public static final Comparator calculatedFieldsComparator = Comparator.comparing(CalculatedField::getName); + @JsonProperty(index = 2) @JsonTbEntity private E entity; @@ -68,6 +68,9 @@ public class EntityExportData> { private List relations; @JsonProperty(index = 101) private Map> attributes; + @JsonProperty(index = 102) + @JsonIgnoreProperties({"id", "entityId", "createdTime", "version"}) + private List calculatedFields; public EntityExportData sort() { if (relations != null && !relations.isEmpty()) { @@ -76,6 +79,9 @@ public class EntityExportData> { if (attributes != null && !attributes.isEmpty()) { attributes.values().forEach(list -> list.sort(attrComparator)); } + if (calculatedFields != null && !calculatedFields.isEmpty()) { + calculatedFields.sort(calculatedFieldsComparator); + } return this; } @@ -101,7 +107,7 @@ public class EntityExportData> { @JsonIgnore public boolean hasCalculatedFields() { - return false; + return calculatedFields != null; } } 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 3f04ab6c67..a966977968 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 @@ -22,11 +22,10 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.Dao; -import org.thingsboard.server.dao.ExportableEntityDao; import java.util.List; -public interface CalculatedFieldDao extends Dao, ExportableEntityDao { +public interface CalculatedFieldDao extends Dao { List findAllByTenantId(TenantId tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index e2b21ed59b..148908d063 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -729,7 +729,6 @@ public class ModelConstants { public static final String CALCULATED_FIELD_CONFIGURATION_VERSION = "configuration_version"; public static final String CALCULATED_FIELD_CONFIGURATION = "configuration"; public static final String CALCULATED_FIELD_VERSION = "version"; - public static final String CALCULATED_FIELD_EXTERNAL_ID = "external_id"; /** * Calculated field links constants. diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/CalculatedFieldEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/CalculatedFieldEntity.java index 349091a1ae..de6a1365b1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/CalculatedFieldEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/CalculatedFieldEntity.java @@ -40,7 +40,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_C import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_CONFIGURATION_VERSION; import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_ENTITY_ID; import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_ENTITY_TYPE; -import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_EXTERNAL_ID; import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_NAME; import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_TABLE_NAME; import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_TENANT_ID_COLUMN; @@ -82,9 +81,6 @@ public class CalculatedFieldEntity extends BaseVersionedEntity @Column(name = DEBUG_SETTINGS) private String debugSettings; - @Column(name = CALCULATED_FIELD_EXTERNAL_ID) - private UUID externalId; - public CalculatedFieldEntity() { super(); } @@ -101,9 +97,6 @@ public class CalculatedFieldEntity extends BaseVersionedEntity this.configuration = JacksonUtil.valueToTree(calculatedField.getConfiguration()); this.version = calculatedField.getVersion(); this.debugSettings = JacksonUtil.toString(calculatedField.getDebugSettings()); - if (calculatedField.getExternalId() != null) { - this.externalId = calculatedField.getExternalId().getId(); - } } @Override @@ -118,9 +111,6 @@ public class CalculatedFieldEntity extends BaseVersionedEntity calculatedField.setConfiguration(JacksonUtil.treeToValue(configuration, CalculatedFieldConfiguration.class)); calculatedField.setVersion(version); calculatedField.setDebugSettings(JacksonUtil.fromString(debugSettings, DebugSettings.class)); - if (externalId != null) { - calculatedField.setExternalId(new CalculatedFieldId(externalId)); - } return calculatedField; } 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 e7e41ed2d0..0f48f3b00d 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 @@ -18,16 +18,13 @@ package org.thingsboard.server.dao.sql.cf; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import org.thingsboard.server.common.data.id.CalculatedFieldId; -import org.thingsboard.server.dao.ExportableEntityRepository; import org.thingsboard.server.dao.model.sql.CalculatedFieldEntity; import java.util.List; import java.util.UUID; -@Repository -public interface CalculatedFieldRepository extends JpaRepository, ExportableEntityRepository { +public interface CalculatedFieldRepository extends JpaRepository { boolean existsByTenantIdAndEntityId(UUID tenantId, UUID entityId); @@ -37,16 +34,10 @@ public interface CalculatedFieldRepository extends JpaRepository findAllByTenantIdAndEntityId(UUID tenantId, UUID entityId, Pageable pageable); - Page findByTenantId(UUID tenantId, Pageable pageable); - List findAllByTenantId(UUID tenantId); List removeAllByTenantIdAndEntityId(UUID tenantId, UUID entityId); long countByTenantIdAndEntityId(UUID tenantId, UUID entityId); - CalculatedFieldId findExternalIdById(UUID id); - - CalculatedFieldEntity findByTenantIdAndName(UUID tenantId, String name); - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/DefaultNativeCalculatedFieldRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/DefaultNativeCalculatedFieldRepository.java index fae3468f1e..e59ff3f4e6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/cf/DefaultNativeCalculatedFieldRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/cf/DefaultNativeCalculatedFieldRepository.java @@ -92,7 +92,6 @@ public class DefaultNativeCalculatedFieldRepository implements NativeCalculatedF calculatedField.setConfiguration(JacksonUtil.treeToValue(configuration, CalculatedFieldConfiguration.class)); calculatedField.setVersion(version); calculatedField.setDebugSettings(JacksonUtil.fromString(debugSettings, DebugSettings.class)); - calculatedField.setExternalId(externalIdObj != null ? new CalculatedFieldId(UUID.fromString((String) externalIdObj)) : null); return calculatedField; }).collect(Collectors.toList()); 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 01e7888fbf..8922eaca4e 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 @@ -88,26 +88,6 @@ public class JpaCalculatedFieldDao extends JpaAbstractDao findByTenantId(UUID tenantId, PageLink pageLink) { - return DaoUtil.toPageData(calculatedFieldRepository.findByTenantId(tenantId, DaoUtil.toPageable(pageLink))); - } - - @Override - public CalculatedField findByTenantIdAndName(UUID tenantId, String name) { - return DaoUtil.getData(calculatedFieldRepository.findByTenantIdAndName(tenantId, name)); - } - - @Override - public CalculatedField findByTenantIdAndExternalId(UUID tenantId, UUID externalId) { - return DaoUtil.getData(calculatedFieldRepository.findByTenantIdAndExternalId(tenantId, externalId)); - } - - @Override - public CalculatedFieldId getExternalIdByInternal(CalculatedFieldId internalId) { - return calculatedFieldRepository.findExternalIdById(internalId.getId()); - } - @Override protected Class getEntityClass() { return CalculatedFieldEntity.class; diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 5bd34c4f1d..d158912690 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -936,9 +936,7 @@ CREATE TABLE IF NOT EXISTS calculated_field ( configuration varchar(1000000), version BIGINT DEFAULT 1, debug_settings varchar(1024), - external_id UUID, - CONSTRAINT calculated_field_unq_key UNIQUE (entity_id, name), - CONSTRAINT calculated_field_external_id_unq_key UNIQUE (tenant_id, external_id) + CONSTRAINT calculated_field_unq_key UNIQUE (entity_id, name) ); CREATE TABLE IF NOT EXISTS calculated_field_link ( diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/CalculatedFieldServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/CalculatedFieldServiceTest.java index 5a783355d7..2985aa7620 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/CalculatedFieldServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/CalculatedFieldServiceTest.java @@ -101,20 +101,6 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest { .hasMessage("Calculated Field with such name is already in exists!"); } - @Test - public void testSaveCalculatedFieldWithExistingExternalId() { - Device device = createTestDevice(); - CalculatedField calculatedField = getCalculatedField(device.getId(), device.getId()); - calculatedField.setExternalId(new CalculatedFieldId(UUID.fromString("2ef69d0a-89cf-4868-86f8-c50551d87ebe"))); - - calculatedFieldService.save(calculatedField); - - calculatedField.setName("Test 2"); - assertThatThrownBy(() -> calculatedFieldService.save(calculatedField)) - .isInstanceOf(DataValidationException.class) - .hasMessage("Calculated Field with such external id already exists!"); - } - @Test public void testFindCalculatedFieldById() { CalculatedField savedCalculatedField = saveValidCalculatedField();