|
@@ -0,0 +1,289 @@
|
|
|
+package com.qizhen.healsphere.repository.postgresql;
|
|
|
+
|
|
|
+import cn.hutool.core.map.MapUtil;
|
|
|
+import com.qizhen.healsphere.repository.neo4j.entity.BaseEntity;
|
|
|
+import com.qizhen.healsphere.repository.neo4j.param.MergeNodeParam;
|
|
|
+import com.qizhen.healsphere.web.dto.NodeDTO;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
+import org.springframework.jdbc.core.RowMapper;
|
|
|
+import org.springframework.stereotype.Repository;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+@Repository
|
|
|
+public class NodeRepository {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private JdbcTemplate jdbcTemplate;
|
|
|
+
|
|
|
+ private final RowMapper<Map<String, Object>> nodeMapper = (rs, rowNum) -> {
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
+ map.put("id", rs.getLong("id"));
|
|
|
+ map.put("name", rs.getString("name"));
|
|
|
+ map.put("category", rs.getString("category"));
|
|
|
+ map.put("layout", rs.getString("layout"));
|
|
|
+ map.put("version", rs.getString("version"));
|
|
|
+ map.put("status", rs.getInt("status"));
|
|
|
+ return map;
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据名字和标签查询实体属性
|
|
|
+ * @param category
|
|
|
+ * @param name
|
|
|
+ * @return 实体map
|
|
|
+ */
|
|
|
+ public Map<String, Object> findNodeByName(String category, String name) {
|
|
|
+ String sql = "SELECT * FROM kg_nodes WHERE category = ? AND name = ? AND status != -1";
|
|
|
+ List<Map<String, Object>> results = jdbcTemplate.query(sql, nodeMapper, category, name);
|
|
|
+ return results.isEmpty() ? new HashMap<>() : results.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<NodeDTO> findNodeByNameLike(String category, String name) {
|
|
|
+ String sql = "SELECT id, name, category FROM kg_nodes WHERE category = ? AND name LIKE ? AND status != -1 LIMIT 20";
|
|
|
+ return jdbcTemplate.query(sql, (rs, rowNum) -> {
|
|
|
+ NodeDTO nodeDTO = new NodeDTO();
|
|
|
+ nodeDTO.setNodeId(rs.getLong("id"));
|
|
|
+ nodeDTO.setName(rs.getString("name"));
|
|
|
+ nodeDTO.setLabel(rs.getString("category"));
|
|
|
+ return nodeDTO;
|
|
|
+ }, category, "%" + name + "%");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据id查询实体属性
|
|
|
+ * @param id
|
|
|
+ * @return 实体map
|
|
|
+ */
|
|
|
+ public Map<String, Object> findNodeById(Long id) {
|
|
|
+ String sql = "SELECT * FROM kg_nodes WHERE id = ? AND status != -1";
|
|
|
+ List<Map<String, Object>> results = jdbcTemplate.query(sql, nodeMapper, id);
|
|
|
+ return results.isEmpty() ? new HashMap<>() : results.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据名字模糊查询实体
|
|
|
+ * @param category
|
|
|
+ * @param name
|
|
|
+ * @return 实体map列表
|
|
|
+ */
|
|
|
+ public List<Map<String, Object>> findNodeListByName(String category, String name) {
|
|
|
+ String sql = "SELECT * FROM kg_nodes WHERE category = ? AND name LIKE ? AND status != -1";
|
|
|
+ List<Map<String, Object>> mapList = jdbcTemplate.query(sql, nodeMapper, category, "%" + name + "%");
|
|
|
+ if (!mapList.isEmpty()) {
|
|
|
+ mapList.forEach(map -> {
|
|
|
+ HashMap<Object, Object> hashMap = MapUtil.newHashMap();
|
|
|
+ hashMap.put("name", map.get("name"));
|
|
|
+ map.put("properties", hashMap);
|
|
|
+ List<String> list = new ArrayList<>();
|
|
|
+ list.add(map.get("category").toString());
|
|
|
+ map.put("labels",list);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return mapList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增实体
|
|
|
+ * @param category
|
|
|
+ * @param properties
|
|
|
+ * @return 实体map
|
|
|
+ */
|
|
|
+ public Map<String, Object> createNode(String category, Map<String, Object> properties) {
|
|
|
+ String sql = "INSERT INTO kg_nodes (name, category, status) VALUES (?, ?, 0) RETURNING *";
|
|
|
+ List<Map<String, Object>> results = jdbcTemplate.query(
|
|
|
+ sql,
|
|
|
+ nodeMapper,
|
|
|
+ properties.get("name"),
|
|
|
+ category
|
|
|
+ );
|
|
|
+ return results.isEmpty() ? new HashMap<>() : results.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新实体名称
|
|
|
+ * @param nodeId
|
|
|
+ * @param name
|
|
|
+ * @return 实体map
|
|
|
+ */
|
|
|
+ public Map<String, Object> updateNode(Long nodeId, String name) {
|
|
|
+ String sql = "UPDATE kg_nodes SET name = ? WHERE id = ? AND status != -1 RETURNING *";
|
|
|
+ List<Map<String, Object>> results = jdbcTemplate.query(sql, nodeMapper, name, nodeId);
|
|
|
+ return results.isEmpty() ? new HashMap<>() : results.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除实体
|
|
|
+ * @param nodeId
|
|
|
+ */
|
|
|
+ public void deleteNode(Long nodeId) {
|
|
|
+ String sql = "UPDATE kg_nodes SET status = -1 WHERE id = ?";
|
|
|
+ jdbcTemplate.update(sql, nodeId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取所有实体
|
|
|
+ * @param category
|
|
|
+ * @return 实体列表
|
|
|
+ */
|
|
|
+ public List<BaseEntity> getAll(String category) {
|
|
|
+ String sql = "SELECT * FROM kg_nodes WHERE category = ? AND status != -1";
|
|
|
+ return jdbcTemplate.query(sql, (rs, rowNum) -> {
|
|
|
+ BaseEntity entity = new BaseEntity();
|
|
|
+ entity.setId(rs.getLong("id"));
|
|
|
+ entity.setName(rs.getString("name"));
|
|
|
+ ArrayList<String> labels = new ArrayList<>();
|
|
|
+ labels.add(rs.getString("category"));
|
|
|
+ entity.setLabel(labels);
|
|
|
+
|
|
|
+ Map<String, Object> properties = new HashMap<>();
|
|
|
+ properties.put("layout", rs.getString("layout"));
|
|
|
+ properties.put("version", rs.getString("version"));
|
|
|
+ properties.put("status", rs.getInt("status"));
|
|
|
+ entity.setProperties(properties);
|
|
|
+
|
|
|
+ return entity;
|
|
|
+ }, category);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据名字和标签查询实体
|
|
|
+ * @param label 标签
|
|
|
+ * @param name 名称
|
|
|
+ * @return 实体
|
|
|
+ */
|
|
|
+ public BaseEntity byName(String label, String name) {
|
|
|
+ String sql = "SELECT * FROM kg_nodes WHERE category = ? AND name = ? AND status != -1";
|
|
|
+ List<BaseEntity> results = jdbcTemplate.query(sql, (rs, rowNum) -> {
|
|
|
+ BaseEntity entity = new BaseEntity();
|
|
|
+ entity.setId(rs.getLong("id"));
|
|
|
+ entity.setName(rs.getString("name"));
|
|
|
+ ArrayList<String> labels = new ArrayList<>();
|
|
|
+ labels.add(rs.getString("category"));
|
|
|
+ entity.setLabel(labels);
|
|
|
+
|
|
|
+ Map<String, Object> properties = new HashMap<>();
|
|
|
+ properties.put("layout", rs.getString("layout"));
|
|
|
+ properties.put("version", rs.getString("version"));
|
|
|
+ properties.put("status", rs.getInt("status"));
|
|
|
+ entity.setProperties(properties);
|
|
|
+
|
|
|
+ return entity;
|
|
|
+ }, label, name);
|
|
|
+ return results.isEmpty() ? null : results.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建新实体
|
|
|
+ * @param label 标签
|
|
|
+ * @param properties 属性
|
|
|
+ * @return 实体
|
|
|
+ */
|
|
|
+ public BaseEntity create(String label, Map<String, Object> properties) {
|
|
|
+ if (properties == null) {
|
|
|
+ properties = new HashMap<>();
|
|
|
+ }
|
|
|
+ properties.put("is_deleted", "N");
|
|
|
+
|
|
|
+ String sql = "INSERT INTO kg_nodes (name, category, layout, version, status) VALUES (?, ?, ?, ?, 0) RETURNING *";
|
|
|
+ List<BaseEntity> results = jdbcTemplate.query(
|
|
|
+ sql,
|
|
|
+ (rs, rowNum) -> {
|
|
|
+ BaseEntity entity = new BaseEntity();
|
|
|
+ entity.setId(rs.getLong("id"));
|
|
|
+ entity.setName(rs.getString("name"));
|
|
|
+ ArrayList<String> labels = new ArrayList<>();
|
|
|
+ labels.add(rs.getString("category"));
|
|
|
+ entity.setLabel(labels);
|
|
|
+
|
|
|
+ Map<String, Object> props = new HashMap<>();
|
|
|
+ props.put("layout", rs.getString("layout"));
|
|
|
+ props.put("version", rs.getString("version"));
|
|
|
+ props.put("status", rs.getInt("status"));
|
|
|
+ entity.setProperties(props);
|
|
|
+
|
|
|
+ return entity;
|
|
|
+ },
|
|
|
+ properties.get("name"),
|
|
|
+ label,
|
|
|
+ properties.get("layout"),
|
|
|
+ properties.get("version")
|
|
|
+ );
|
|
|
+ return results.isEmpty() ? null : results.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 合并两个实体
|
|
|
+ * @param mergeNodeParam 合并参数
|
|
|
+ * @return 合并后的实体
|
|
|
+ */
|
|
|
+ public Map<String, Object> mergeNode(MergeNodeParam mergeNodeParam) {
|
|
|
+ // 1. 获取原始节点的属性
|
|
|
+ Map<String, Object> firstNode = findNodeById(mergeNodeParam.getFirstId());
|
|
|
+ Map<String, Object> secondNode = findNodeById(mergeNodeParam.getSecondId());
|
|
|
+
|
|
|
+ if (firstNode.isEmpty() || secondNode.isEmpty()) {
|
|
|
+ throw new RuntimeException("One or both nodes not found");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 创建新节点,合并属性
|
|
|
+ Map<String, Object> newNodeProps = new HashMap<>();
|
|
|
+ newNodeProps.put("name", mergeNodeParam.getNewName());
|
|
|
+ newNodeProps.put("category", mergeNodeParam.getNewLabel());
|
|
|
+ newNodeProps.put("status", 0);
|
|
|
+ newNodeProps.put("layout", firstNode.get("layout"));
|
|
|
+ newNodeProps.put("version", firstNode.get("version"));
|
|
|
+
|
|
|
+ String insertSql = "INSERT INTO kg_nodes (name, category, layout, version, status) VALUES (?, ?, ?, ?, ?) RETURNING *";
|
|
|
+ List<Map<String, Object>> newNodeResults = jdbcTemplate.query(
|
|
|
+ insertSql,
|
|
|
+ nodeMapper,
|
|
|
+ newNodeProps.get("name"),
|
|
|
+ newNodeProps.get("category"),
|
|
|
+ newNodeProps.get("layout"),
|
|
|
+ newNodeProps.get("version"),
|
|
|
+ newNodeProps.get("status")
|
|
|
+ );
|
|
|
+
|
|
|
+ if (newNodeResults.isEmpty()) {
|
|
|
+ throw new RuntimeException("Failed to create new node");
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> newNode = newNodeResults.get(0);
|
|
|
+ Long newNodeId = (Long) newNode.get("id");
|
|
|
+
|
|
|
+ // 3. 在事务中迁移关系并删除原节点
|
|
|
+ org.springframework.transaction.support.TransactionTemplate transactionTemplate =
|
|
|
+ new org.springframework.transaction.support.TransactionTemplate(
|
|
|
+ new org.springframework.jdbc.datasource.DataSourceTransactionManager(jdbcTemplate.getDataSource()));
|
|
|
+
|
|
|
+ transactionTemplate.execute(status -> {
|
|
|
+ try {
|
|
|
+ // 处理出向关系
|
|
|
+ String updateOutgoingEdgesSql = "UPDATE kg_edges SET src_id = ? WHERE src_id = ? AND status != -1";
|
|
|
+ jdbcTemplate.update(updateOutgoingEdgesSql, newNodeId, mergeNodeParam.getFirstId());
|
|
|
+ jdbcTemplate.update(updateOutgoingEdgesSql, newNodeId, mergeNodeParam.getSecondId());
|
|
|
+
|
|
|
+ // 处理入向关系
|
|
|
+ String updateIncomingEdgesSql = "UPDATE kg_edges SET dest_id = ? WHERE dest_id = ? AND status != -1";
|
|
|
+ jdbcTemplate.update(updateIncomingEdgesSql, newNodeId, mergeNodeParam.getFirstId());
|
|
|
+ jdbcTemplate.update(updateIncomingEdgesSql, newNodeId, mergeNodeParam.getSecondId());
|
|
|
+
|
|
|
+ // 将原节点标记为删除
|
|
|
+ String updateSql = "UPDATE kg_nodes SET status = -1 WHERE id IN (?, ?)";
|
|
|
+ jdbcTemplate.update(updateSql, mergeNodeParam.getFirstId(), mergeNodeParam.getSecondId());
|
|
|
+
|
|
|
+ return null;
|
|
|
+ } catch (Exception e) {
|
|
|
+ status.setRollbackOnly();
|
|
|
+ throw new RuntimeException("Failed to merge nodes: " + e.getMessage(), e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return newNode;
|
|
|
+ }
|
|
|
+}
|