Browse Source

AI rule node: add version control support

pull/13371/head
Dmytro Skarzhynets 1 year ago
parent
commit
c653a2b695
No known key found for this signature in database GPG Key ID: 2B51652F224037DF
  1. 4
      application/src/main/data/upgrade/basic/schema_update.sql
  2. 4
      application/src/main/java/org/thingsboard/server/controller/AiModelSettingsController.java
  3. 2
      application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
  4. 4
      application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java
  5. 1
      application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiModelSettingsService.java
  6. 3
      application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
  7. 36
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AiModelSettingsExportService.java
  8. 77
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AiModelSettingsImportService.java
  9. 7
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  10. 4
      application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java
  11. 26
      common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModelSettings.java
  12. 7
      common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java
  13. 4
      dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsDao.java
  14. 4
      dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsServiceImpl.java
  15. 5
      dao/src/main/java/org/thingsboard/server/dao/model/sql/AiModelSettingsEntity.java
  16. 13
      dao/src/main/java/org/thingsboard/server/dao/sql/ai/AiModelSettingsRepository.java
  17. 31
      dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiModelSettingsDao.java
  18. 4
      dao/src/main/resources/sql/schema-entities.sql
  19. 4
      ui-ngx/src/app/shared/models/entity-type.models.ts

4
application/src/main/data/upgrade/basic/schema_update.sql

@ -16,10 +16,12 @@
CREATE TABLE ai_model_settings ( CREATE TABLE ai_model_settings (
id UUID NOT NULL PRIMARY KEY, id UUID NOT NULL PRIMARY KEY,
external_id UUID,
created_time BIGINT NOT NULL, created_time BIGINT NOT NULL,
tenant_id UUID NOT NULL, tenant_id UUID NOT NULL,
version BIGINT NOT NULL DEFAULT 1, version BIGINT NOT NULL DEFAULT 1,
name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
configuration JSONB NOT NULL, configuration JSONB NOT NULL,
CONSTRAINT ai_model_settings_name_unq_key UNIQUE (tenant_id, name) CONSTRAINT ai_model_settings_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT ai_model_settings_external_id_unq_key UNIQUE (tenant_id, external_id)
); );

4
application/src/main/java/org/thingsboard/server/controller/AiModelSettingsController.java

@ -38,7 +38,7 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import static org.thingsboard.server.controller.ControllerConstants.AI_SETTINGS_TEXT_SEARCH_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.AI_MODEL_SETTINGS_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
@ -99,7 +99,7 @@ public class AiModelSettingsController extends BaseController {
@RequestParam int pageSize, @RequestParam int pageSize,
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true) @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page, @RequestParam int page,
@Parameter(description = AI_SETTINGS_TEXT_SEARCH_DESCRIPTION) @Parameter(description = AI_MODEL_SETTINGS_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch, @RequestParam(required = false) String textSearch,
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"})) @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"}))
@RequestParam(required = false) String sortProperty, @RequestParam(required = false) String sortProperty,

2
application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java

@ -90,7 +90,7 @@ public class ControllerConstants {
protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the tenant profile name."; protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the tenant profile name.";
protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the rule chain name."; protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the rule chain name.";
protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the device profile name."; protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the device profile name.";
protected static final String AI_SETTINGS_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the AI model settings name, provider and model ID."; protected static final String AI_MODEL_SETTINGS_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the AI model settings name, provider and model ID.";
protected static final String ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the asset profile name."; protected static final String ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the asset profile name.";
protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the customer title."; protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the customer title.";

4
application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java

@ -97,7 +97,7 @@ public abstract class AbstractTbEntityService {
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
} }
protected ListenableFuture<UUID> autoCommit(User user, EntityId entityId) throws Exception { protected ListenableFuture<UUID> autoCommit(User user, EntityId entityId) {
if (vcService != null) { if (vcService != null) {
return vcService.autoCommit(user, entityId); return vcService.autoCommit(user, entityId);
} else { } else {
@ -106,7 +106,7 @@ public abstract class AbstractTbEntityService {
} }
} }
protected ListenableFuture<UUID> autoCommit(User user, EntityType entityType, List<UUID> entityIds) throws Exception { protected ListenableFuture<UUID> autoCommit(User user, EntityType entityType, List<UUID> entityIds) {
if (vcService != null) { if (vcService != null) {
return vcService.autoCommit(user, entityType, entityIds); return vcService.autoCommit(user, entityType, entityIds);
} else { } else {

1
application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiModelSettingsService.java

@ -44,6 +44,7 @@ class DefaultTbAiModelSettingsService extends AbstractTbEntityService implements
AiModelSettings savedSettings; AiModelSettings savedSettings;
try { try {
savedSettings = aiModelSettingsService.save(settings); savedSettings = aiModelSettingsService.save(settings);
autoCommit(user, savedSettings.getId());
} catch (Exception e) { } catch (Exception e) {
logEntityActionService.logEntityAction(tenantId, requireNonNullElseGet(settings.getId(), () -> emptyId(EntityType.AI_MODEL_SETTINGS)), settings, actionType, user, e); logEntityActionService.logEntityAction(tenantId, requireNonNullElseGet(settings.getId(), () -> emptyId(EntityType.AI_MODEL_SETTINGS)), settings, actionType, user, e);
throw e; throw e;

3
application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java

@ -69,7 +69,8 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
EntityType.DASHBOARD, EntityType.ASSET_PROFILE, EntityType.ASSET, EntityType.DASHBOARD, EntityType.ASSET_PROFILE, EntityType.ASSET,
EntityType.DEVICE_PROFILE, EntityType.DEVICE, EntityType.DEVICE_PROFILE, EntityType.DEVICE,
EntityType.ENTITY_VIEW, EntityType.WIDGET_TYPE, EntityType.WIDGETS_BUNDLE, EntityType.ENTITY_VIEW, EntityType.WIDGET_TYPE, EntityType.WIDGETS_BUNDLE,
EntityType.NOTIFICATION_TEMPLATE, EntityType.NOTIFICATION_TARGET, EntityType.NOTIFICATION_RULE EntityType.NOTIFICATION_TEMPLATE, EntityType.NOTIFICATION_TARGET, EntityType.NOTIFICATION_RULE,
EntityType.AI_MODEL_SETTINGS
); );
@Override @Override

36
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AiModelSettingsExportService.java

@ -0,0 +1,36 @@
/**
* 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.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ai.AiModelSettings;
import org.thingsboard.server.common.data.id.AiModelSettingsId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.Set;
@Service
@TbCoreComponent
class AiModelSettingsExportService extends BaseEntityExportService<AiModelSettingsId, AiModelSettings, EntityExportData<AiModelSettings>> {
@Override
public Set<EntityType> getSupportedEntityTypes() {
return Set.of(EntityType.AI_MODEL_SETTINGS);
}
}

77
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AiModelSettingsImportService.java

@ -0,0 +1,77 @@
/**
* 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 lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ai.AiModelSettings;
import org.thingsboard.server.common.data.id.AiModelSettingsId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.dao.ai.AiModelSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
@Service
@TbCoreComponent
@RequiredArgsConstructor
class AiModelSettingsImportService extends BaseEntityImportService<AiModelSettingsId, AiModelSettings, EntityExportData<AiModelSettings>> {
private final AiModelSettingsService aiModelSettingsService;
@Override
protected void setOwner(
TenantId tenantId,
AiModelSettings settings,
BaseEntityImportService<AiModelSettingsId, AiModelSettings, EntityExportData<AiModelSettings>>.IdProvider idProvider
) {
settings.setTenantId(tenantId);
}
@Override
protected AiModelSettings prepare(
EntitiesImportCtx ctx,
AiModelSettings settings,
AiModelSettings oldEntity,
EntityExportData<AiModelSettings> exportData,
BaseEntityImportService<AiModelSettingsId, AiModelSettings, EntityExportData<AiModelSettings>>.IdProvider idProvider
) {
return settings;
}
@Override
protected AiModelSettings deepCopy(AiModelSettings settings) {
return new AiModelSettings(settings);
}
@Override
protected AiModelSettings saveOrUpdate(
EntitiesImportCtx ctx,
AiModelSettings settings,
EntityExportData<AiModelSettings> exportData,
BaseEntityImportService<AiModelSettingsId, AiModelSettings, EntityExportData<AiModelSettings>>.IdProvider idProvider,
CompareResult compareResult
) {
return aiModelSettingsService.save(settings);
}
@Override
public EntityType getEntityType() {
return EntityType.AI_MODEL_SETTINGS;
}
}

7
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -114,9 +114,8 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
private final TbTransactionalCache<UUID, VersionControlTaskCacheEntry> taskCache; private final TbTransactionalCache<UUID, VersionControlTaskCacheEntry> taskCache;
private final VersionControlExecutor executor; private final VersionControlExecutor executor;
@SuppressWarnings("UnstableApiUsage")
@Override @Override
public ListenableFuture<UUID> saveEntitiesVersion(User user, VersionCreateRequest request) throws Exception { public ListenableFuture<UUID> saveEntitiesVersion(User user, VersionCreateRequest request) {
checkBranchName(request.getBranch()); checkBranchName(request.getBranch());
var pendingCommit = gitServiceQueue.prepareCommit(user, request); var pendingCommit = gitServiceQueue.prepareCommit(user, request);
DonAsynchron.withCallback(pendingCommit, commit -> { DonAsynchron.withCallback(pendingCommit, commit -> {
@ -546,7 +545,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} }
@Override @Override
public ListenableFuture<UUID> autoCommit(User user, EntityId entityId) throws Exception { public ListenableFuture<UUID> autoCommit(User user, EntityId entityId) {
var repositorySettings = repositorySettingsService.get(user.getTenantId()); var repositorySettings = repositorySettingsService.get(user.getTenantId());
if (repositorySettings == null || repositorySettings.isReadOnly()) { if (repositorySettings == null || repositorySettings.isReadOnly()) {
return Futures.immediateFuture(null); return Futures.immediateFuture(null);
@ -573,7 +572,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} }
@Override @Override
public ListenableFuture<UUID> autoCommit(User user, EntityType entityType, List<UUID> entityIds) throws Exception { public ListenableFuture<UUID> autoCommit(User user, EntityType entityType, List<UUID> entityIds) {
var repositorySettings = repositorySettingsService.get(user.getTenantId()); var repositorySettings = repositorySettingsService.get(user.getTenantId());
if (repositorySettings == null || repositorySettings.isReadOnly()) { if (repositorySettings == null || repositorySettings.isReadOnly()) {
return Futures.immediateFuture(null); return Futures.immediateFuture(null);

4
application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java

@ -69,9 +69,9 @@ public interface EntitiesVersionControlService {
ListenableFuture<Void> checkVersionControlAccess(TenantId tenantId, RepositorySettings settings) throws Exception; ListenableFuture<Void> checkVersionControlAccess(TenantId tenantId, RepositorySettings settings) throws Exception;
ListenableFuture<UUID> autoCommit(User user, EntityId entityId) throws Exception; ListenableFuture<UUID> autoCommit(User user, EntityId entityId);
ListenableFuture<UUID> autoCommit(User user, EntityType entityType, List<UUID> entityIds) throws Exception; ListenableFuture<UUID> autoCommit(User user, EntityType entityType, List<UUID> entityIds);
ListenableFuture<EntityDataInfo> getEntityDataInfo(User user, EntityId entityId, String versionId); ListenableFuture<EntityDataInfo> getEntityDataInfo(User user, EntityId entityId, String versionId);

26
common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModelSettings.java

@ -21,7 +21,7 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.HasVersion; import org.thingsboard.server.common.data.HasVersion;
import org.thingsboard.server.common.data.ai.model.AiModel; import org.thingsboard.server.common.data.ai.model.AiModel;
@ -34,7 +34,7 @@ import java.io.Serial;
@Builder @Builder
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public final class AiModelSettings extends BaseData<AiModelSettingsId> implements HasTenantId, HasVersion, HasName { public final class AiModelSettings extends BaseData<AiModelSettingsId> implements HasTenantId, HasVersion, ExportableEntity<AiModelSettingsId> {
@Serial @Serial
private static final long serialVersionUID = 9017108678716011604L; private static final long serialVersionUID = 9017108678716011604L;
@ -45,7 +45,7 @@ public final class AiModelSettings extends BaseData<AiModelSettingsId> implement
description = "JSON object representing the ID of the tenant associated with these AI model settings", description = "JSON object representing the ID of the tenant associated with these AI model settings",
example = "e3c4b7d2-5678-4a9b-0c1d-2e3f4a5b6c7d" example = "e3c4b7d2-5678-4a9b-0c1d-2e3f4a5b6c7d"
) )
TenantId tenantId; private TenantId tenantId;
@Schema( @Schema(
requiredMode = Schema.RequiredMode.REQUIRED, requiredMode = Schema.RequiredMode.REQUIRED,
@ -54,22 +54,24 @@ public final class AiModelSettings extends BaseData<AiModelSettingsId> implement
example = "7", example = "7",
defaultValue = "1" defaultValue = "1"
) )
Long version; private Long version;
@Schema( @Schema(
requiredMode = Schema.RequiredMode.REQUIRED, requiredMode = Schema.RequiredMode.REQUIRED,
accessMode = Schema.AccessMode.READ_WRITE, accessMode = Schema.AccessMode.READ_WRITE,
description = "Human-readable name of the AI model settings; must be unique within the scope of the tenant", description = "Human-readable name of the AI model settings; must be unique within the scope of the tenant",
example = "Default AI Settings" example = "Rule node assistant"
) )
String name; private String name;
@Schema( @Schema(
requiredMode = Schema.RequiredMode.NOT_REQUIRED, requiredMode = Schema.RequiredMode.NOT_REQUIRED,
accessMode = Schema.AccessMode.READ_WRITE, accessMode = Schema.AccessMode.READ_WRITE,
description = "Configuration of the AI model" description = "Configuration of the AI model"
) )
AiModel<?> configuration; private AiModel<?> configuration;
private AiModelSettingsId externalId;
public AiModelSettings() {} public AiModelSettings() {}
@ -77,4 +79,14 @@ public final class AiModelSettings extends BaseData<AiModelSettingsId> implement
super(id); super(id);
} }
public AiModelSettings(AiModelSettings settings) {
super(settings.getId());
createdTime = settings.getCreatedTime();
tenantId = settings.getTenantId();
version = settings.getVersion();
name = settings.getName();
configuration = settings.getConfiguration();
externalId = settings.getExternalId() == null ? null : new AiModelSettingsId(settings.getExternalId().getId());
}
} }

7
common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java

@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.ai.AiModelSettings;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRule;
@ -58,8 +59,8 @@ import java.lang.annotation.Target;
@Type(name = "NOTIFICATION_TEMPLATE", value = NotificationTemplate.class), @Type(name = "NOTIFICATION_TEMPLATE", value = NotificationTemplate.class),
@Type(name = "NOTIFICATION_TARGET", value = NotificationTarget.class), @Type(name = "NOTIFICATION_TARGET", value = NotificationTarget.class),
@Type(name = "NOTIFICATION_RULE", value = NotificationRule.class), @Type(name = "NOTIFICATION_RULE", value = NotificationRule.class),
@Type(name = "TB_RESOURCE", value = TbResource.class) @Type(name = "TB_RESOURCE", value = TbResource.class),
@Type(name = "AI_MODEL_SETTINGS", value = AiModelSettings.class)
}) })
@JsonIgnoreProperties(value = {"tenantId", "createdTime", "version"}, ignoreUnknown = true) @JsonIgnoreProperties(value = {"tenantId", "createdTime", "version"}, ignoreUnknown = true)
public @interface JsonTbEntity { public @interface JsonTbEntity {}
}

4
dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsDao.java

@ -18,12 +18,12 @@ package org.thingsboard.server.dao.ai;
import org.thingsboard.server.common.data.ai.AiModelSettings; import org.thingsboard.server.common.data.ai.AiModelSettings;
import org.thingsboard.server.common.data.id.AiModelSettingsId; import org.thingsboard.server.common.data.id.AiModelSettingsId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityDao;
import java.util.Optional; import java.util.Optional;
public interface AiModelSettingsDao extends Dao<AiModelSettings>, TenantEntityDao<AiModelSettings> { public interface AiModelSettingsDao extends TenantEntityDao<AiModelSettings>, ExportableEntityDao<AiModelSettingsId, AiModelSettings> {
Optional<AiModelSettings> findByTenantIdAndId(TenantId tenantId, AiModelSettingsId settingsId); Optional<AiModelSettings> findByTenantIdAndId(TenantId tenantId, AiModelSettingsId settingsId);

4
dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsServiceImpl.java

@ -65,7 +65,9 @@ class AiModelSettingsServiceImpl extends CachedVersionedEntityService<AiModelSet
try { try {
savedSettings = aiModelSettingsDao.saveAndFlush(settings.getTenantId(), settings); savedSettings = aiModelSettingsDao.saveAndFlush(settings.getTenantId(), settings);
} catch (Exception e) { } catch (Exception e) {
checkConstraintViolation(e, "ai_model_settings_name_unq_key", "AI model settings with such name already exist!"); checkConstraintViolation(e,
"ai_model_settings_name_unq_key", "AI model settings with such name already exist!",
"ai_model_settings_external_id_unq_key", "AI model settings with such external ID already exist!");
throw e; throw e;
} }

5
dao/src/main/java/org/thingsboard/server/dao/model/sql/AiModelSettingsEntity.java

@ -56,6 +56,9 @@ public class AiModelSettingsEntity extends BaseVersionedEntity<AiModelSettings>
@Column(name = ModelConstants.AI_MODEL_SETTINGS_CONFIGURATION_COLUMN_NAME, nullable = false, columnDefinition = "JSONB") @Column(name = ModelConstants.AI_MODEL_SETTINGS_CONFIGURATION_COLUMN_NAME, nullable = false, columnDefinition = "JSONB")
private AiModel<?> configuration; private AiModel<?> configuration;
@Column(name = ModelConstants.EXTERNAL_ID_PROPERTY, columnDefinition = "UUID")
private UUID externalId;
public AiModelSettingsEntity() {} public AiModelSettingsEntity() {}
public AiModelSettingsEntity(AiModelSettings aiModelSettings) { public AiModelSettingsEntity(AiModelSettings aiModelSettings) {
@ -63,6 +66,7 @@ public class AiModelSettingsEntity extends BaseVersionedEntity<AiModelSettings>
tenantId = getTenantUuid(aiModelSettings.getTenantId()); tenantId = getTenantUuid(aiModelSettings.getTenantId());
name = aiModelSettings.getName(); name = aiModelSettings.getName();
configuration = aiModelSettings.getConfiguration(); configuration = aiModelSettings.getConfiguration();
externalId = getUuid(aiModelSettings.getExternalId());
} }
@Override @Override
@ -73,6 +77,7 @@ public class AiModelSettingsEntity extends BaseVersionedEntity<AiModelSettings>
settings.setTenantId(TenantId.fromUUID(tenantId)); settings.setTenantId(TenantId.fromUUID(tenantId));
settings.setName(name); settings.setName(name);
settings.setConfiguration(configuration); settings.setConfiguration(configuration);
settings.setExternalId(getEntityId(externalId, AiModelSettingsId::new));
return settings; return settings;
} }

13
dao/src/main/java/org/thingsboard/server/dao/sql/ai/AiModelSettingsRepository.java

@ -22,13 +22,18 @@ import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.dao.ExportableEntityRepository;
import org.thingsboard.server.dao.model.sql.AiModelSettingsEntity; import org.thingsboard.server.dao.model.sql.AiModelSettingsEntity;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
interface AiModelSettingsRepository extends JpaRepository<AiModelSettingsEntity, UUID> { interface AiModelSettingsRepository extends JpaRepository<AiModelSettingsEntity, UUID>, ExportableEntityRepository<AiModelSettingsEntity> {
Optional<AiModelSettingsEntity> findByTenantIdAndId(UUID tenantId, UUID id);
Optional<AiModelSettingsEntity> findByTenantIdAndName(UUID tenantId, String name);
@Query(nativeQuery = true, value = """ @Query(nativeQuery = true, value = """
SELECT * SELECT *
@ -41,7 +46,11 @@ interface AiModelSettingsRepository extends JpaRepository<AiModelSettingsEntity,
""") """)
Page<AiModelSettingsEntity> findByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); Page<AiModelSettingsEntity> findByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable);
Optional<AiModelSettingsEntity> findByTenantIdAndId(UUID tenantId, UUID id); @Query("SELECT ai_model.id FROM AiModelSettingsEntity ai_model WHERE ai_model.tenantId = :tenantId")
Page<UUID> findIdsByTenantId(@Param("tenantId") UUID tenantId, Pageable pageable);
@Query("SELECT externalId FROM AiModelSettingsEntity WHERE id = :id")
Optional<UUID> getExternalIdById(@Param("id") UUID id);
long countByTenantId(UUID tenantId); long countByTenantId(UUID tenantId);

31
dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiSettingsDao.java → dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiModelSettingsDao.java

@ -38,7 +38,7 @@ import java.util.UUID;
@SqlDao @SqlDao
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
class JpaAiSettingsDao extends JpaAbstractDao<AiModelSettingsEntity, AiModelSettings> implements AiModelSettingsDao { class JpaAiModelSettingsDao extends JpaAbstractDao<AiModelSettingsEntity, AiModelSettings> implements AiModelSettingsDao {
private final AiModelSettingsRepository aiModelSettingsRepository; private final AiModelSettingsRepository aiModelSettingsRepository;
@ -47,13 +47,40 @@ class JpaAiSettingsDao extends JpaAbstractDao<AiModelSettingsEntity, AiModelSett
return aiModelSettingsRepository.findByTenantIdAndId(tenantId.getId(), settingsId.getId()).map(DaoUtil::getData); return aiModelSettingsRepository.findByTenantIdAndId(tenantId.getId(), settingsId.getId()).map(DaoUtil::getData);
} }
@Override
public AiModelSettings findByTenantIdAndName(UUID tenantId, String name) {
return DaoUtil.getData(aiModelSettingsRepository.findByTenantIdAndName(tenantId, name));
}
@Override
public AiModelSettings findByTenantIdAndExternalId(UUID tenantId, UUID externalId) {
return DaoUtil.getData(aiModelSettingsRepository.findByTenantIdAndExternalId(tenantId, externalId));
}
@Override @Override
public PageData<AiModelSettings> findAllByTenantId(TenantId tenantId, PageLink pageLink) { public PageData<AiModelSettings> findAllByTenantId(TenantId tenantId, PageLink pageLink) {
return findByTenantId(tenantId.getId(), pageLink);
}
@Override
public PageData<AiModelSettings> findByTenantId(UUID tenantId, PageLink pageLink) {
return DaoUtil.toPageData(aiModelSettingsRepository.findByTenantId( return DaoUtil.toPageData(aiModelSettingsRepository.findByTenantId(
tenantId.getId(), StringUtils.defaultIfEmpty(pageLink.getTextSearch(), null), DaoUtil.toPageable(pageLink, AiModelSettingsEntity.COLUMN_MAP)) tenantId, StringUtils.defaultIfEmpty(pageLink.getTextSearch(), null), DaoUtil.toPageable(pageLink, AiModelSettingsEntity.COLUMN_MAP))
);
}
@Override
public PageData<AiModelSettingsId> findIdsByTenantId(UUID tenantId, PageLink pageLink) {
return DaoUtil.pageToPageData(
aiModelSettingsRepository.findIdsByTenantId(tenantId, DaoUtil.toPageable(pageLink, AiModelSettingsEntity.COLUMN_MAP)).map(AiModelSettingsId::new)
); );
} }
@Override
public AiModelSettingsId getExternalIdByInternal(AiModelSettingsId internalId) {
return aiModelSettingsRepository.getExternalIdById(internalId.getId()).map(AiModelSettingsId::new).orElse(null);
}
@Override @Override
public Long countByTenantId(TenantId tenantId) { public Long countByTenantId(TenantId tenantId) {
return aiModelSettingsRepository.countByTenantId(tenantId.getId()); return aiModelSettingsRepository.countByTenantId(tenantId.getId());

4
dao/src/main/resources/sql/schema-entities.sql

@ -951,10 +951,12 @@ CREATE TABLE IF NOT EXISTS cf_debug_event (
CREATE TABLE IF NOT EXISTS ai_model_settings ( CREATE TABLE IF NOT EXISTS ai_model_settings (
id UUID NOT NULL PRIMARY KEY, id UUID NOT NULL PRIMARY KEY,
external_id UUID,
created_time BIGINT NOT NULL, created_time BIGINT NOT NULL,
tenant_id UUID NOT NULL, tenant_id UUID NOT NULL,
version BIGINT NOT NULL DEFAULT 1, version BIGINT NOT NULL DEFAULT 1,
name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
configuration JSONB NOT NULL, configuration JSONB NOT NULL,
CONSTRAINT ai_model_settings_name_unq_key UNIQUE (tenant_id, name) CONSTRAINT ai_model_settings_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT ai_model_settings_external_id_unq_key UNIQUE (tenant_id, external_id)
); );

4
ui-ngx/src/app/shared/models/entity-type.models.ts

@ -51,7 +51,7 @@ export enum EntityType {
MOBILE_APP_BUNDLE = 'MOBILE_APP_BUNDLE', MOBILE_APP_BUNDLE = 'MOBILE_APP_BUNDLE',
MOBILE_APP = 'MOBILE_APP', MOBILE_APP = 'MOBILE_APP',
CALCULATED_FIELD = 'CALCULATED_FIELD', CALCULATED_FIELD = 'CALCULATED_FIELD',
AI_SETTINGS = 'AI_SETTINGS', AI_MODEL_SETTINGS = 'AI_MODEL_SETTINGS',
} }
export enum AliasEntityType { export enum AliasEntityType {
@ -494,7 +494,7 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
} }
], ],
[ [
EntityType.AI_SETTINGS, EntityType.AI_MODEL_SETTINGS,
{ {
type: 'entity.type-ai-model-settings', type: 'entity.type-ai-model-settings',
typePlural: 'entity.type-ai-model-settings' typePlural: 'entity.type-ai-model-settings'

Loading…
Cancel
Save