REQ-3540: 备份

This commit is contained in:
yanglin 2025-03-17 10:43:35 +08:00
parent 7cbb6fd549
commit 91747f3eea
5 changed files with 26 additions and 26 deletions

View File

@ -60,7 +60,7 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
} }
public IndexNode findValidChildByName(IndexNodeParentScope parentNode, IndexNodeType nodeType, String name) { public IndexNode findValidChildByName(IndexNodeParentScope parentNode, IndexNodeType nodeType, String name) {
return parentOrScopeQuery(parentNode) // return parentOrScopeRootQuery(parentNode) //
.eq(IndexNode::getName, name) // .eq(IndexNode::getName, name) //
.eq(IndexNode::getNodeType, nodeType) // .eq(IndexNode::getNodeType, nodeType) //
.eq(IndexNode::getState, IndexNodeState.VALID) // .eq(IndexNode::getState, IndexNodeState.VALID) //
@ -70,7 +70,7 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
public List<IndexNode> findValidChildrenNameRightLike(IndexNodeParentScope parentNode, IndexNodeType nodeType, public List<IndexNode> findValidChildrenNameRightLike(IndexNodeParentScope parentNode, IndexNodeType nodeType,
String name) { String name) {
return parentOrScopeQuery(parentNode) // return parentOrScopeRootQuery(parentNode) //
.likeRight(IndexNode::getName, name) // .likeRight(IndexNode::getName, name) //
.eq(IndexNode::getNodeType, nodeType) // .eq(IndexNode::getNodeType, nodeType) //
.eq(IndexNode::getState, IndexNodeState.VALID) // .eq(IndexNode::getState, IndexNodeState.VALID) //
@ -140,9 +140,9 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
.update(); .update();
} }
private LambdaQueryChainWrapper<IndexNode> parentOrScopeQuery(IndexNodeParentScope parentScope) { private LambdaQueryChainWrapper<IndexNode> parentOrScopeRootQuery(IndexNodeParentScope parentScope) {
if (StringUtils.isBlank(parentScope.parentCode())) if (StringUtils.isBlank(parentScope.parentCode()))
return scopeQuery(parentScope.nodeScope()); return scopeQuery(parentScope.nodeScope()).eq(IndexNode::getParentCode, "");
return lambdaQuery().eq(IndexNode::getParentCode, parentScope.parentCode()); return lambdaQuery().eq(IndexNode::getParentCode, parentScope.parentCode());
} }

View File

@ -148,6 +148,10 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeValue, Index
return Path.wrap(path); return Path.wrap(path);
} }
public static boolean idEquals(IndexNode n1, IndexNode n2) {
return Objects.equals(n1.getId(), n2.getId());
}
@JsonIgnore @JsonIgnore
@JSONField(serialize = false, deserialize = false) @JSONField(serialize = false, deserialize = false)
public boolean isFile() { public boolean isFile() {

View File

@ -172,7 +172,6 @@ public class IndexManager {
BizAssertions.assertFalse(srcNode.isDirectory() && destParentNode.isFile(), "不能移动文件夹到文件下"); BizAssertions.assertFalse(srcNode.isDirectory() && destParentNode.isFile(), "不能移动文件夹到文件下");
return async(() -> { return async(() -> {
RootNode<IndexNode> moveRoot = TreeBuilder.build(collectValidSubtreeAsValueRoot(srcNode)); RootNode<IndexNode> moveRoot = TreeBuilder.build(collectValidSubtreeAsValueRoot(srcNode));
//noinspection SpringTransactionalMethodCallsInspection
return transaction.execute(unused -> connectNodes(moveRoot, destParentNode)); return transaction.execute(unused -> connectNodes(moveRoot, destParentNode));
}); });
} }
@ -181,8 +180,7 @@ public class IndexManager {
public IndexNode copySubTree(IndexNode src, @Nullable IndexNode destParent, CopyNodeVisitor copyNodeVisitor) { public IndexNode copySubTree(IndexNode src, @Nullable IndexNode destParent, CopyNodeVisitor copyNodeVisitor) {
RootNode<IndexNode> srcRoot = TreeUtils.transform(collectValidSubtreeAsValueRoot(src), IndexNode.class); RootNode<IndexNode> srcRoot = TreeUtils.transform(collectValidSubtreeAsValueRoot(src), IndexNode.class);
srcRoot.walkDown(copyNodeVisitor); srcRoot.walkDown(copyNodeVisitor);
List<IndexNode> copiedNodes = TreeUtils.collectValues(srcRoot); indexNodeDao.saveBatch(TreeUtils.collectValues(srcRoot));
indexNodeDao.saveBatch(copiedNodes);
return connectNodes(srcRoot, destParent); return connectNodes(srcRoot, destParent);
} }
@ -197,20 +195,14 @@ public class IndexManager {
/** /**
* connect tree nodes and resolve name issue * connect tree nodes and resolve name issue
*/ */
@BizTransactional private IndexNode connectNodes(RootNode<IndexNode> connectRoot, @Nullable IndexNode destParent) {
public IndexNode connectNodes(RootNode<IndexNode> connectRoot, @Nullable IndexNode destParent) {
// rebuild parent id, parent code and the most important path // rebuild parent id, parent code and the most important path
connectRoot.walkDown(new ConnectNodeVisitor(destParent)); connectRoot.walkDown(new ConnectNodeVisitor(destParent));
indexNodeDao.connectNodes(TreeUtils.collectValues(connectRoot)); indexNodeDao.connectNodes(TreeUtils.collectValues(connectRoot));
IndexNode copiedRoot = connectRoot.getChildren().get(0).<IndexNode> asValueNode().getValue(); IndexNode copiedRoot = connectRoot.getChildren().get(0).<IndexNode> asValueNode().getValue();
// resolve the name issue // resolve the name issue
if (destParent != null) { if (destParent != null)
String newName = indexSupport.lockAndMaybeIncrChildName(destParent, copiedRoot.getNodeType(), indexSupport.incrNameIfDuplicate(destParent, copiedRoot.getNodeType(), copiedRoot);
copiedRoot.getName());
// don't update if the name is good
if (!copiedRoot.getName().equals(newName))
indexNodeDao.rename(copiedRoot.getCode(), newName);
}
// get the coped root with full props // get the coped root with full props
return indexNodeDao.findOrNull(copiedRoot.getCode()); return indexNodeDao.findOrNull(copiedRoot.getCode());
} }

View File

@ -14,7 +14,6 @@ import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import cn.axzo.nanopart.doc.file.index.copy.SetScopeProcessor;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationManager;
@ -31,6 +30,7 @@ import cn.axzo.nanopart.doc.dao.DocLockDao;
import cn.axzo.nanopart.doc.dao.IndexNodeDao; import cn.axzo.nanopart.doc.dao.IndexNodeDao;
import cn.axzo.nanopart.doc.entity.IndexNode; import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.entity.domain.Path; import cn.axzo.nanopart.doc.entity.domain.Path;
import cn.axzo.nanopart.doc.file.index.copy.SetScopeProcessor;
import cn.axzo.nanopart.doc.file.index.domain.NameUsedException; import cn.axzo.nanopart.doc.file.index.domain.NameUsedException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -97,15 +97,17 @@ class IndexSupport {
BizAssertions.assertFalse(parent.isFile(), "不能在文件下建立文件夹"); BizAssertions.assertFalse(parent.isFile(), "不能在文件下建立文件夹");
} }
String lockAndMaybeIncrChildName(IndexNode parentNode, IndexNodeType nodeType, String name) { void incrNameIfDuplicate(IndexNode parentNode, IndexNodeType nodeType, IndexNode rename) {
lockParentAndReleaseOnCommit(parentNode); lockParentAndReleaseOnCommit(parentNode);
IndexNode sameName = indexNodeDao.findValidChildByName(parentNode, nodeType, name); List<IndexNode> nameLikeNodes = indexNodeDao.findValidChildrenNameRightLike(parentNode, nodeType,
if (sameName == null) rename.getName());
return name; if (nameLikeNodes.size() == 1 && IndexNode.idEquals(rename, nameLikeNodes.get(0)))
List<IndexNode> nameLikeNodes = indexNodeDao.findValidChildrenNameRightLike(parentNode, nodeType, name); return;
Pattern pattern = Pattern.compile(Pattern.quote(name) + "\\((\\d+)\\)"); Pattern pattern = Pattern.compile(Pattern.quote(rename.getName()) + "\\((\\d+)\\)");
int maxSeq = 0; int maxSeq = 0;
for (IndexNode indexNode : nameLikeNodes) { for (IndexNode indexNode : nameLikeNodes) {
if (indexNode.getId().equals(rename.getId()))
continue;
Matcher matcher = pattern.matcher(indexNode.getName()); Matcher matcher = pattern.matcher(indexNode.getName());
if (matcher.matches()) { if (matcher.matches()) {
int seq = Integer.parseInt(matcher.group(1)); int seq = Integer.parseInt(matcher.group(1));
@ -114,7 +116,8 @@ class IndexSupport {
} }
} }
maxSeq = maxSeq == 0 ? 1 : maxSeq + 1; maxSeq = maxSeq == 0 ? 1 : maxSeq + 1;
return String.format("%s(%d)", name, maxSeq); String newName = String.format("%s(%d)", rename.getName(), maxSeq);
indexNodeDao.rename(rename.getCode(), newName);
} }
void ensureChildNameNotUsed(NodeCreate create, IndexNodeType nodeType) { void ensureChildNameNotUsed(NodeCreate create, IndexNodeType nodeType) {

View File

@ -17,10 +17,11 @@ import cn.axzo.nanopart.doc.entity.IndexNode;
@Mapper @Mapper
public interface IndexNodeMapper extends BaseMapper<IndexNode> { public interface IndexNodeMapper extends BaseMapper<IndexNode> {
@Insert("<script>\n" + "INSERT INTO doc_index_node (code, parent_id, root_code, path)\n" + "VALUES\n" @Insert("<script>\n" + "INSERT INTO doc_index_node (code, parent_id, parent_code, root_code, path)\n" + "VALUES\n"
+ " <foreach collection='nodes' item='node' separator=','>\n" + " <foreach collection='nodes' item='node' separator=','>\n"
+ " (#{node.code}, #{node.parentId}, #{node.rootCode}, #{node.path})\n" + "</foreach>\n" + " (#{node.code}, #{node.parentId}, #{node.parentCode}, #{node.rootCode}, #{node.path})\n" + "</foreach>\n"
+ " ON DUPLICATE KEY UPDATE parent_id = values(parent_id),\n" + " ON DUPLICATE KEY UPDATE parent_id = values(parent_id),\n"
+ " parent_code = values(parent_code),\n"
+ " root_code = values(root_code),\n" + " root_code = values(root_code),\n"
+ " path = values(path)\n" + "</script>") + " path = values(path)\n" + "</script>")
void connectNodes(@Param("nodes") List<IndexNode> nodes); void connectNodes(@Param("nodes") List<IndexNode> nodes);