diff --git a/Ramitta/Database/Neo4j.cs b/Ramitta/Database/Neo4j.cs new file mode 100644 index 0000000..4edf68b --- /dev/null +++ b/Ramitta/Database/Neo4j.cs @@ -0,0 +1,203 @@ +using Neo4j.Driver; +using NPOI; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; + +namespace Ramitta +{ + public class Neo4jtool + { + private IDriver _driver; + + public Neo4jtool(string uri, string user, string password) + { + _driver = GraphDatabase.Driver(uri, AuthTokens.Basic(user, password)); + } + + public void Close() + { + _driver?.Dispose(); + } + + private string dictToLimit(Dictionary nodeProperties) + { + return string.Join(", ", nodeProperties.Select(prop => $"{prop.Key}: '{prop.Value.Replace("'", "\\'")}'")); + } + + + #region 增 + public async Task CreateNodeAsync(string nodeType, Dictionary properties, bool alway_create = false) + { + using (var session = _driver.AsyncSession()) + { + // 通过 dictToLimit 将字典转换成条件字符串 + var propertyString = dictToLimit(properties); + + // 构建查询语句 + var query = (alway_create ? "CREATE" : "MERGE") + + $" (n:{nodeType} {{{propertyString}}})"; + + await session.RunAsync(query); + } + } + + + // 创建任意关系,支持动态定义关系类型 + public enum ArrowDirection + { + Left, // 反向关系 + Right, // 正向关系(默认) + Both // 双向关系 + } + public async Task CreateRelationshipAsync( + string relationshipType, + string nodeType1, Dictionary nodeProperties1, // 使用字典替代单独的参数 + string nodeType2, Dictionary nodeProperties2, // 使用字典替代单独的参数 + ArrowDirection arrow = ArrowDirection.Right, + Dictionary relationshipProperties = null // 可选字典参数 + ){ + using (var session = _driver.AsyncSession()) + { + // 构建查询的 MATCH 部分,动态地使用字典中的键值对来构造节点的属性 + var node1Properties = string.Join(", ", nodeProperties1.Select(kv => $"{kv.Key}: \"{kv.Value}\"")); + var node2Properties = string.Join(", ", nodeProperties2.Select(kv => $"{kv.Key}: \"{kv.Value}\"")); + + var query = $"MATCH (a:{nodeType1} {{{node1Properties}}}), (b:{nodeType2} {{{node2Properties}}}) "; + + // 动态构造关系属性部分 + string relationshipPropertiesPart = ""; + if (relationshipProperties != null && relationshipProperties.Count > 0) + { + var properties = string.Join(", ", relationshipProperties.Select(kv => $"{kv.Key}: \"{kv.Value}\"")); + relationshipPropertiesPart = $"{{{properties}}}"; + } + + // 根据箭头方向来决定关系的方向,并可能附加关系的属性 + if (arrow == ArrowDirection.Right) + query += $"MERGE (a)-[:{relationshipType} {relationshipPropertiesPart}]->(b)"; + else if (arrow == ArrowDirection.Left) + query += $"MERGE (b)-[:{relationshipType} {relationshipPropertiesPart}]->(a)"; + else if (arrow == ArrowDirection.Both) + { + query += $"MERGE (a)-[:{relationshipType} {relationshipPropertiesPart}]->(b)"; + query += $"MERGE (b)-[:{relationshipType} {relationshipPropertiesPart}]->(a)"; + } + + // 执行查询 + await session.RunAsync(query); + } + } + #endregion + + #region 查 + // 寻找指定节点 + // await neo4jService.GetRelatedNodesAsync("文件", properties); + public async Task>> GetRelatedNodesAsync( + string nodeLabel, + Dictionary? nodeProperties=null) + { + string query; + if (nodeProperties == null) + { + query = $@" + MATCH (h:{nodeLabel})-[r]-(related) + RETURN DISTINCT h,related"; + } + else + { + query = $@" + MATCH (h:{nodeLabel} {{{dictToLimit(nodeProperties)}}})-[r]-(related) + RETURN DISTINCT h,related"; + } + var resultList = new List>(); + using (var session = _driver.AsyncSession()) + { + var result = await session.RunAsync(query); + await result.ForEachAsync(record => + { + var hNode = record["h"].As(); + var dict = new Dictionary(); + // 添加所有属性 + foreach (var property in hNode.Properties) + { + dict[property.Key] = property.Value?.ToString() ?? string.Empty; + } + resultList.Add(dict); + }); + } + + return resultList; + } + + + + public async Task> slavenode( + string nodeLabel, + Dictionary? nodeProperties = null) + { + string query; + if (nodeProperties == null) + { + query = $@" + MATCH (h:{nodeLabel})-[r]-(related) + RETURN DISTINCT h,r,related"; + } + else + { + query = $@" + MATCH (h:{nodeLabel} {{{dictToLimit(nodeProperties)}}})-[r]-(related) + RETURN DISTINCT h,r,related"; + } + + var resultList = new List<(INode h, IRelationship r, INode related)>(); + + using (var session = _driver.AsyncSession()) + { + var result = await session.RunAsync(query); + await result.ForEachAsync(record => + { + var hNode = record["h"].As(); + var rRelation = record["r"].As(); + var relatedNode = record["related"].As(); + + // 将h, r, related 作为元组加入结果列表 + resultList.Add((hNode, rRelation, relatedNode)); + }); + } + + return resultList; + } + + #endregion + + #region 删 + public async Task DeleteNodeAsync(string nodeType, Dictionary nodeProperties) + { + using (var session = _driver.AsyncSession()) + { + // 构建查询条件 + var queryConditions = string.Join(" AND ", nodeProperties.Keys.Select(k => $"n.{k} = ${k}")); + + // 运行查询并传递字典参数 + await session.RunAsync( + $"MATCH (n:{nodeType}) WHERE {queryConditions} DETACH DELETE n", + nodeProperties + ); + } + } + + // 删除所有节点和关系 + public async Task DeleteAllNodesAndRelationshipsAsync() + { + using (var session = _driver.AsyncSession()) + { + await session.RunAsync("MATCH (n) DETACH DELETE n"); + } + } + #endregion + + } +} diff --git a/Ramitta/PostgreSqlDriver.cs b/Ramitta/Database/PostgreSQL.cs similarity index 98% rename from Ramitta/PostgreSqlDriver.cs rename to Ramitta/Database/PostgreSQL.cs index db8bbc2..9906c27 100644 --- a/Ramitta/PostgreSqlDriver.cs +++ b/Ramitta/Database/PostgreSQL.cs @@ -8,11 +8,11 @@ using System.Threading.Tasks; namespace Ramitta { - public partial class PostgreSqlDriver + public partial class PostgreSql { private readonly string _connectionString; - public PostgreSqlDriver(string connectionString) + public PostgreSql(string connectionString) { _connectionString = connectionString; } diff --git a/Ramitta/SQLite.cs b/Ramitta/Database/SQLite.cs similarity index 100% rename from Ramitta/SQLite.cs rename to Ramitta/Database/SQLite.cs diff --git a/Ramitta/Neo4jService.cs b/Ramitta/Neo4jService.cs deleted file mode 100644 index 694d1f2..0000000 --- a/Ramitta/Neo4jService.cs +++ /dev/null @@ -1,339 +0,0 @@ -using Neo4j.Driver; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using System.Threading.Tasks; - -namespace Ramitta -{ - public class Neo4jService - { - private IDriver _driver; - - public Neo4jService(string uri, string user, string password) - { - _driver = GraphDatabase.Driver(uri, AuthTokens.Basic(user, password)); - } - - public void Close() - { - _driver?.Dispose(); - } - - // 创建任意节点,支持更多属性 - public async Task CreateNodeAsync(string nodeType, Dictionary properties) - { - using (var session = _driver.AsyncSession()) - { - // 动态生成属性字符串 - var propertyString = string.Join(", ", properties.Keys); - var values = new Dictionary(); - foreach (var prop in properties) - { - values.Add(prop.Key, prop.Value); - } - - var query = $"CREATE (n:{nodeType} {{{string.Join(", ", properties.Keys.Select(k => $"{k}: ${k}"))}}})"; - await session.RunAsync(query, values); - } - } - - - public async Task>> GetRelatedNodesAsync( - string nodeLabel, - Dictionary nodeProperties) - { - // 构建属性条件字符串 - var propertyConditions = new List(); - foreach (var prop in nodeProperties) - { - propertyConditions.Add($"{prop.Key}: '{prop.Value.Replace("'", "\\'")}'"); - } - - var propertiesString = string.Join(", ", propertyConditions); - - var query = $@" -MATCH (h:{nodeLabel} {{{propertiesString}}})-[r]-(related) -RETURN DISTINCT h"; - - var resultList = new List>(); - - using (var session = _driver.AsyncSession()) - { - var result = await session.RunAsync(query); - - await result.ForEachAsync(record => - { - var hNode = record["h"].As(); - resultList.Add(ConvertNodeToDictionary(hNode)); - }); - } - - return resultList; - } - - private Dictionary ConvertNodeToDictionary(INode node) - { - var dict = new Dictionary(); - - - // 添加所有属性 - foreach (var property in node.Properties) - { - dict[property.Key] = property.Value?.ToString() ?? string.Empty; - } - - - return dict; - } - - - - - - // 创建或合并节点 - public async Task MergeNodeAsync(string nodeType, Dictionary properties) - { - using (var session = _driver.AsyncSession()) - { - // 动态生成属性字符串 - var propertyString = string.Join(", ", properties.Keys); - var values = new Dictionary(); - foreach (var prop in properties) - { - values.Add(prop.Key, prop.Value); - } - - var query = $"MERGE (n:{nodeType} {{{string.Join(", ", properties.Keys.Select(k => $"{k}: ${k}"))}}})"; - await session.RunAsync(query, values); - } - } - - public async Task>> GetNodesAsync(string nodeType = null) - { - var result = new List>(); - - var query = nodeType == null - ? "MATCH (n) RETURN n" - : $"MATCH (n:{nodeType}) RETURN n"; - - using (var session = _driver.AsyncSession()) - { - var cursor = await session.RunAsync(query); - - while (await cursor.FetchAsync()) - { - var node = cursor.Current["n"].As(); - var nodeProperties = new Dictionary(node.Properties); - - // 添加节点ID和标签信息 - nodeProperties["_id"] = node.Id; - nodeProperties["_labels"] = node.Labels.ToArray(); - - result.Add(nodeProperties); - } - } - - return result; - } - - - // 创建任意关系,支持动态定义关系类型 - public enum ArrowDirection - { - Left, // 反向关系 - Right, // 正向关系(默认) - Both // 双向关系 - } - public async Task CreateRelationshipAsync( - string relationshipType, - string nodeType1, string nodeTap1, string nodeName1, - string nodeType2, string nodeTap2, string nodeName2, - ArrowDirection arrow = ArrowDirection.Right - ) - { - using (var session = _driver.AsyncSession()) - { - var query = $"MATCH (a:{nodeType1} {{{nodeTap1}: $name1}}), (b:{nodeType2} {{{nodeTap2}: $name2}}) "; - - if (arrow == ArrowDirection.Right) - query+=$"MERGE (a)-[:{relationshipType}]->(b)"; - else if (arrow == ArrowDirection.Left) - query += $"MERGE (b)-[:{relationshipType}]->(a)"; - else if (arrow == ArrowDirection.Both) { - query += $"MERGE (a)-[:{relationshipType}]->(b)"; - query += $"MERGE (b)-[:{relationshipType}]->(a)"; - } - await session.RunAsync(query, new { name1 = nodeName1, name2 = nodeName2 }); - } - } - public async Task>> GetRelatedNodesAsync( - string nodeName, - string nodeType, // 默认值为 "Person" - string relationshipType = null, - Dictionary additionalNodeFilters = null, // 可选的节点属性过滤 - Dictionary additionalRelationshipFilters = null // 可选的关系属性过滤 -) - { - var result = new List>(); - - // 构建基本的查询部分 - var query = new StringBuilder($"MATCH (a:{nodeType} {{name: $name}})"); - - // 如果有额外的节点过滤条件,加入到查询中 - if (additionalNodeFilters != null && additionalNodeFilters.Count > 0) - { - foreach (var filter in additionalNodeFilters) - { - query.Append($" AND a.{filter.Key} = ${filter.Key}"); - } - } - - // 根据关系类型添加关系部分 - var relationshipFilter = relationshipType != null ? $":{relationshipType}" : ""; - query.Append($"-[r{relationshipFilter}]->(b)"); - - // 如果有关系的额外过滤条件,加入到查询中 - if (additionalRelationshipFilters != null && additionalRelationshipFilters.Count > 0) - { - foreach (var filter in additionalRelationshipFilters) - { - query.Append($" AND r.{filter.Key} = ${filter.Key}"); - } - } - - // 添加返回部分 - query.Append(" RETURN b"); - - // 合并所有的参数 - var parameters = new Dictionary { { "name", nodeName } }; - - // 如果有节点过滤条件,合并到参数中 - if (additionalNodeFilters != null) - { - foreach (var filter in additionalNodeFilters) - { - parameters[filter.Key] = filter.Value; - } - } - - // 如果有关系过滤条件,合并到参数中 - if (additionalRelationshipFilters != null) - { - foreach (var filter in additionalRelationshipFilters) - { - parameters[filter.Key] = filter.Value; - } - } - - using (var session = _driver.AsyncSession()) - { - var cursor = await session.RunAsync(query.ToString(), parameters); - - // 遍历查询结果 - while (await cursor.FetchAsync()) - { - var relatedNode = cursor.Current["b"].As(); // 获取目标节点对象 - - // 将节点的所有属性加入结果 - var nodeProperties = new Dictionary(); - foreach (var property in relatedNode.Properties) - { - nodeProperties[property.Key] = property.Value; - } - result.Add(nodeProperties); - } - } - - return result; - } - - - public async Task>> GetRelationshipsAsync( - string nodeName, - string nodeType = null, - string relationshipType = null, - bool includeIncoming = false, - bool includeOutgoing = true) - { - var result = new List>(); - var relationshipQuery = ""; - - // 根据关系方向构建查询 - if (relationshipType != null) - { - if (includeOutgoing && includeIncoming) - { - relationshipQuery = $"-[:{relationshipType}]-"; - } - else if (includeOutgoing) - { - relationshipQuery = $"-[:{relationshipType}]->"; - } - else if (includeIncoming) - { - relationshipQuery = $"<-[:{relationshipType}]-"; - } - } - else - { - if (includeOutgoing && includeIncoming) - { - relationshipQuery = "-[]-"; - } - else if (includeOutgoing) - { - relationshipQuery = "-[]->"; - } - else if (includeIncoming) - { - relationshipQuery = "<-[]-"; - } - } - - // 构造MATCH查询 - var query = $"MATCH (a:{nodeType ?? "Person"} {{name: $name}}){relationshipQuery}(b) RETURN b"; - - using (var session = _driver.AsyncSession()) - { - var cursor = await session.RunAsync(query, new { name = nodeName }); - - // 遍历查询结果 - while (await cursor.FetchAsync()) - { - var relatedNode = cursor.Current["b"].As(); // 获取目标节点对象 - - // 将节点的所有属性加入结果 - var nodeProperties = new Dictionary(); - foreach (var property in relatedNode.Properties) - { - nodeProperties[property.Key] = property.Value; - } - result.Add(nodeProperties); - } - } - - return result; - } - - - // 删除特定节点和它的关系 - public async Task DeleteNodeAsync(string nodeType, string nodeName) - { - using (var session = _driver.AsyncSession()) - { - await session.RunAsync($"MATCH (n:{nodeType} {{name: $name}}) DETACH DELETE n", new { name = nodeName }); - } - } - - // 删除所有节点和关系 - public async Task DeleteAllNodesAndRelationshipsAsync() - { - using (var session = _driver.AsyncSession()) - { - await session.RunAsync("MATCH (n) DETACH DELETE n"); - } - } - } -} diff --git a/Ramitta/Ramitta.csproj b/Ramitta/Ramitta.csproj index b838ca4..2da97bf 100644 --- a/Ramitta/Ramitta.csproj +++ b/Ramitta/Ramitta.csproj @@ -9,6 +9,7 @@ + diff --git a/Ramitta/Themes/vsStyle.xaml b/Ramitta/Themes/vsStyle.xaml index 4b5571f..33b9805 100644 --- a/Ramitta/Themes/vsStyle.xaml +++ b/Ramitta/Themes/vsStyle.xaml @@ -16,6 +16,62 @@ + + + + +