Migration script

This commit is contained in:
Andrii Shvaika 2021-12-03 11:57:31 +02:00
parent 9cf0ab6900
commit bbd1d8ae86
11 changed files with 153 additions and 7 deletions

View File

@ -210,6 +210,9 @@ public class ThingsboardInstallService {
log.info("Upgrading ThingsBoard from version 3.3.0 to 3.3.1 ..."); log.info("Upgrading ThingsBoard from version 3.3.0 to 3.3.1 ...");
case "3.3.1": case "3.3.1":
log.info("Upgrading ThingsBoard from version 3.3.1 to 3.3.2 ..."); log.info("Upgrading ThingsBoard from version 3.3.1 to 3.3.2 ...");
case "3.3.2":
log.info("Upgrading ThingsBoard from version 3.3.2 to 3.3.3 ...");
dataUpdateService.updateData("3.3.2");
log.info("Updating system data..."); log.info("Updating system data...");
systemDataLoaderService.updateSystemWidgets(); systemDataLoaderService.updateSystemWidgets();
break; break;

View File

@ -25,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNode;
import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
@ -34,6 +36,8 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmQuery;
import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
@ -43,8 +47,11 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.query.DynamicValue; import org.thingsboard.server.common.data.query.DynamicValue;
import org.thingsboard.server.common.data.query.FilterPredicateValue; import org.thingsboard.server.common.data.query.FilterPredicateValue;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.alarm.AlarmDao; import org.thingsboard.server.dao.alarm.AlarmDao;
@ -52,7 +59,9 @@ import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; import org.thingsboard.server.dao.model.sql.DeviceProfileEntity;
import org.thingsboard.server.dao.model.sql.RelationEntity;
import org.thingsboard.server.dao.oauth2.OAuth2Service; import org.thingsboard.server.dao.oauth2.OAuth2Service;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.sql.device.DeviceProfileRepository; import org.thingsboard.server.dao.sql.device.DeviceProfileRepository;
import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.tenant.TenantService;
@ -76,6 +85,9 @@ public class DefaultDataUpdateService implements DataUpdateService {
@Autowired @Autowired
private TenantService tenantService; private TenantService tenantService;
@Autowired
private RelationService relationService;
@Autowired @Autowired
private RuleChainService ruleChainService; private RuleChainService ruleChainService;
@ -125,6 +137,10 @@ public class DefaultDataUpdateService implements DataUpdateService {
deviceProfileEntityDynamicConditionsUpdater.updateEntities(null); deviceProfileEntityDynamicConditionsUpdater.updateEntities(null);
updateOAuth2Params(); updateOAuth2Params();
break; break;
case "3.3.2":
log.info("Updating data from version 3.3.2 to 3.3.3 ...");
nestedRuleNodeUpdater.updateEntities(null);
break;
default: default:
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
} }
@ -209,6 +225,74 @@ public class DefaultDataUpdateService implements DataUpdateService {
} }
}; };
private final PaginatedUpdater<String, Tenant> nestedRuleNodeUpdater =
new PaginatedUpdater<>() {
@Override
protected String getName() {
return "Tenants nested rule chain updater";
}
@Override
protected boolean forceReportTotal() {
return true;
}
@Override
protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
return tenantService.findTenants(pageLink);
}
@Override
protected void updateEntity(Tenant tenant) {
try {
var tenantId = tenant.getId();
var packSize = 1024;
boolean hasNext = true;
while (hasNext) {
List<EntityRelation> relations = relationService.findRuleNodeToRuleChainRelations(tenantId, RuleChainType.CORE, packSize);
hasNext = relations.size() == packSize;
for (EntityRelation relation : relations) {
RuleNode sourceNode = ruleChainService.findRuleNodeById(tenantId, new RuleNodeId(relation.getFrom().getId()));
RuleChainId sourceRuleChainId = sourceNode.getRuleChainId();
RuleChain targetRuleChain = ruleChainService.findRuleChainById(tenantId, new RuleChainId(relation.getTo().getId()));
RuleNode targetNode = new RuleNode();
targetNode.setName(targetRuleChain.getName());
targetNode.setRuleChainId(sourceRuleChainId);
targetNode.setType(TbRuleChainInputNode.class.getName());
TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration();
configuration.setRuleChainId(targetRuleChain.getId().toString());
targetNode.setConfiguration(JacksonUtil.valueToTree(configuration));
targetNode.setAdditionalInfo(relation.getAdditionalInfo());
targetNode.setDebugMode(false);
targetNode = ruleChainService.saveRuleNode(tenantId, targetNode);
EntityRelation sourceRuleChainToRuleNode = new EntityRelation();
sourceRuleChainToRuleNode.setFrom(sourceRuleChainId);
sourceRuleChainToRuleNode.setTo(targetNode.getId());
sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE);
sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN);
relationService.saveRelation(tenantId, sourceRuleChainToRuleNode);
EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation();
sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId());
sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId());
sourceRuleNodeToTargetRuleNode.setType(relation.getType());
sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE);
sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo());
relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode);
//Delete old relation
relationService.deleteRelation(tenantId, relation);
}
}
} catch (Exception e) {
log.error("Unable to update Tenant", e);
}
}
};
private final PaginatedUpdater<String, Tenant> tenantsDefaultEdgeRuleChainUpdater = private final PaginatedUpdater<String, Tenant> tenantsDefaultEdgeRuleChainUpdater =
new PaginatedUpdater<>() { new PaginatedUpdater<>() {

View File

@ -193,6 +193,6 @@ public class DefaultTbRuleChainService implements TbRuleChainService {
} }
private boolean isRuleNode(RuleNode ruleNode, Class<?> clazz) { private boolean isRuleNode(RuleNode ruleNode, Class<?> clazz) {
return ruleNode.getType().equals(clazz.getName()); return ruleNode != null && ruleNode.getType().equals(clazz.getName());
} }
} }

View File

@ -16,12 +16,16 @@
package org.thingsboard.server.dao.relation; package org.thingsboard.server.dao.relation;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationInfo;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType;
import java.util.List; import java.util.List;
@ -78,6 +82,8 @@ public interface RelationService {
void removeRelations(TenantId tenantId, EntityId entityId); void removeRelations(TenantId tenantId, EntityId entityId);
List<EntityRelation> findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit);
// TODO: This method may be useful for some validations in the future // TODO: This method may be useful for some validations in the future
// ListenableFuture<Boolean> checkRecursiveRelation(EntityId from, EntityId to); // ListenableFuture<Boolean> checkRecursiveRelation(EntityId from, EntityId to);

View File

@ -91,4 +91,6 @@ public interface RuleChainService {
PageData<RuleChain> findAutoAssignToEdgeRuleChainsByTenantId(TenantId tenantId, PageLink pageLink); PageData<RuleChain> findAutoAssignToEdgeRuleChainsByTenantId(TenantId tenantId, PageLink pageLink);
List<RuleNode> findRuleNodesByTenantIdAndType(TenantId tenantId, String name, String toString); List<RuleNode> findRuleNodesByTenantIdAndType(TenantId tenantId, String name, String toString);
RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode);
} }

View File

@ -30,8 +30,11 @@ import org.springframework.cache.annotation.Caching;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationInfo;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
@ -39,6 +42,7 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.ConstraintValidator; import org.thingsboard.server.dao.service.ConstraintValidator;
@ -54,6 +58,7 @@ import java.util.concurrent.ExecutionException;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import static org.thingsboard.server.common.data.CacheConstants.RELATIONS_CACHE; import static org.thingsboard.server.common.data.CacheConstants.RELATIONS_CACHE;
import static org.thingsboard.server.dao.service.Validator.validateId;
/** /**
* Created by ashvayka on 28.04.17. * Created by ashvayka on 28.04.17.
@ -556,6 +561,14 @@ public class BaseRelationService implements RelationService {
} }
} }
@Override
public List<EntityRelation> findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) {
log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}] and limit {}",
tenantId, limit);
validateId(tenantId, "Invalid tenant id: " + tenantId);
return relationDao.findRuleNodeToRuleChainRelations(tenantId, ruleChainType, limit);
}
protected void validate(EntityRelation relation) { protected void validate(EntityRelation relation) {
if (relation == null) { if (relation == null) {
throw new DataValidationException("Relation type should be specified!"); throw new DataValidationException("Relation type should be specified!");

View File

@ -16,13 +16,11 @@
package org.thingsboard.server.dao.relation; package org.thingsboard.server.dao.relation;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType;
import java.util.List; import java.util.List;
@ -63,4 +61,5 @@ public interface RelationDao {
ListenableFuture<Boolean> deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity); ListenableFuture<Boolean> deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity);
List<EntityRelation> findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit);
} }

View File

@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
@ -670,6 +671,11 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
return ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId, type, search); return ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId, type, search);
} }
@Override
public RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode) {
return ruleNodeDao.save(tenantId, ruleNode);
}
private void checkRuleNodesAndDelete(TenantId tenantId, RuleChainId ruleChainId) { private void checkRuleNodesAndDelete(TenantId tenantId, RuleChainId ruleChainId) {
try { try {
ruleChainDao.removeById(tenantId, ruleChainId.getId()); ruleChainDao.removeById(tenantId, ruleChainId.getId());

View File

@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.RelationCompositeKey; import org.thingsboard.server.dao.model.sql.RelationCompositeKey;
import org.thingsboard.server.dao.model.sql.RelationEntity; import org.thingsboard.server.dao.model.sql.RelationEntity;
@ -196,6 +198,11 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple
}); });
} }
@Override
public List<EntityRelation> findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) {
return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(tenantId.getId(), ruleChainType, PageRequest.of(0, limit)));
}
private Specification<RelationEntity> getEntityFieldsSpec(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType) { private Specification<RelationEntity> getEntityFieldsSpec(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType) {
return (root, criteriaQuery, criteriaBuilder) -> { return (root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>(); List<Predicate> predicates = new ArrayList<>();

View File

@ -15,11 +15,20 @@
*/ */
package org.thingsboard.server.dao.sql.relation; package org.thingsboard.server.dao.sql.relation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.dao.model.sql.RelationCompositeKey; import org.thingsboard.server.dao.model.sql.RelationCompositeKey;
import org.thingsboard.server.dao.model.sql.RelationEntity; import org.thingsboard.server.dao.model.sql.RelationEntity;
import org.thingsboard.server.dao.model.sql.RuleChainEntity;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -48,6 +57,17 @@ public interface RelationRepository
List<RelationEntity> findAllByFromIdAndFromType(UUID fromId, List<RelationEntity> findAllByFromIdAndFromType(UUID fromId,
String fromType); String fromType);
@Query("SELECT r FROM RelationEntity r WHERE " +
"r.fromId in (SELECT id from RuleNodeEntity where ruleChainId in " +
"(SELECT id from RuleChainEntity where tenantId = :tenantId and type = :ruleChainType ))" +
"AND r.fromType = 'RULE_NODE' " +
"AND r.toType = 'RULE_CHAIN' " +
"AND r.relationTypeGroup = 'RULE_NODE'")
List<RelationEntity> findRuleNodeToRuleChainRelations(
@Param("tenantId") UUID tenantId,
@Param("ruleChainType") RuleChainType ruleChainType,
Pageable page);
@Transactional @Transactional
<S extends RelationEntity> S save(S entity); <S extends RelationEntity> S save(S entity);
@ -56,4 +76,5 @@ public interface RelationRepository
@Transactional @Transactional
void deleteByFromIdAndFromType(UUID fromId, String fromType); void deleteByFromIdAndFromType(UUID fromId, String fromType);
} }

View File

@ -20,7 +20,11 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.dao.model.sql.RelationEntity;
import org.thingsboard.server.dao.model.sql.RuleChainEntity; import org.thingsboard.server.dao.model.sql.RuleChainEntity;
import java.util.List; import java.util.List;
@ -59,6 +63,7 @@ public interface RuleChainRepository extends PagingAndSortingRepository<RuleChai
@Param("searchText") String searchText, @Param("searchText") String searchText,
Pageable pageable); Pageable pageable);
RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType); RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType);
Long countByTenantId(UUID tenantId); Long countByTenantId(UUID tenantId);