diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/ICypherGraphService.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/ICypherGraphService.cs
new file mode 100644
index 000000000..7cb9bf7ec
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/ICypherGraphService.cs
@@ -0,0 +1,14 @@
+namespace BotSharp.Abstraction.Knowledges;
+
+///
+/// Graph-based semantic knowledge service that supports complex relationships and connections between entities.
+/// This service allows for executing Cypher queries to traverse and analyze graph data structures.
+///
+public interface ICypherGraphService
+{
+ Task Execute(string graphId, string query, Dictionary? args = null);
+
+ Task MergeNode(string graphId, GraphNode node);
+
+ Task DeleteNode(string graphId, string nodeId);
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/CyperGraphModels.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/CyperGraphModels.cs
new file mode 100644
index 000000000..3d89488d4
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/CyperGraphModels.cs
@@ -0,0 +1,24 @@
+namespace BotSharp.Abstraction.Knowledges.Models;
+
+public class GraphQueryResult
+{
+ public string[] Columns { get; set; } = [];
+ public Dictionary[] Items { get; set; } = [];
+}
+
+public class GraphNode
+{
+ public string Id { get; set; } = string.Empty;
+
+ public List Labels { get; set; } = new();
+
+ public object Properties { get; set; } = new();
+
+ public DateTime Time { get; set; } = DateTime.UtcNow;
+
+ public override string ToString()
+ {
+ var labelsString = Labels.Count > 0 ? string.Join(", ", Labels) : "No Labels";
+ return $"Node ({labelsString}: {Id})";
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.Membase/MembasePlugin.cs b/src/Plugins/BotSharp.Plugin.Membase/MembasePlugin.cs
index ad53d29f7..2368e6283 100644
--- a/src/Plugins/BotSharp.Plugin.Membase/MembasePlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.Membase/MembasePlugin.cs
@@ -1,11 +1,4 @@
-using BotSharp.Abstraction.Plugins;
-using BotSharp.Abstraction.Settings;
-using BotSharp.Plugin.Membase.Services;
-using BotSharp.Plugin.Membase.Settings;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
using Refit;
-using System.Threading.Tasks;
namespace BotSharp.Plugin.Membase;
@@ -29,5 +22,7 @@ public void RegisterDI(IServiceCollection services, IConfiguration config)
Task.FromResult($"Bearer {dbSettings.ApiKey}")
})
.ConfigureHttpClient(c => c.BaseAddress = new Uri(dbSettings.Host));
+
+ services.AddScoped();
}
}
diff --git a/src/Plugins/BotSharp.Plugin.Membase/Models/CypherQueryRequest.cs b/src/Plugins/BotSharp.Plugin.Membase/Models/CypherQueryRequest.cs
new file mode 100644
index 000000000..2a85f1530
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.Membase/Models/CypherQueryRequest.cs
@@ -0,0 +1,17 @@
+namespace BotSharp.Plugin.Membase.Models;
+
+public class CypherQueryRequest
+{
+ public string Query { get; set; } = string.Empty;
+
+ public Dictionary Parameters { get; set; } = [];
+
+ public bool IncludeExecutionPlan { get; set; } = false;
+
+ ///
+ /// Whether to profile the query execution.
+ ///
+ public bool Profile { get; set; } = false;
+
+ public int? TimeoutMs { get; set; }
+}
diff --git a/src/Plugins/BotSharp.Plugin.Membase/Models/CypherQueryResponse.cs b/src/Plugins/BotSharp.Plugin.Membase/Models/CypherQueryResponse.cs
new file mode 100644
index 000000000..724704785
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.Membase/Models/CypherQueryResponse.cs
@@ -0,0 +1,17 @@
+namespace BotSharp.Plugin.Membase.Models;
+
+public class CypherQueryResponse
+{
+ public string[] Columns { get; set; } = [];
+ public Dictionary[] Data { get; set; } = [];
+
+ public CypherNotification[] Notifications { get; set; } = [];
+ public int RowCount { get; set; }
+}
+
+public class CypherNotification
+{
+ public string Code { get; set; } = string.Empty;
+ public string Title { get; set; } = string.Empty;
+ public string Description { get; set; } = string.Empty;
+}
diff --git a/src/Plugins/BotSharp.Plugin.Membase/Models/Node.cs b/src/Plugins/BotSharp.Plugin.Membase/Models/Node.cs
index 27cc76127..f1807b019 100644
--- a/src/Plugins/BotSharp.Plugin.Membase/Models/Node.cs
+++ b/src/Plugins/BotSharp.Plugin.Membase/Models/Node.cs
@@ -13,7 +13,7 @@ public class Node
public List Labels { get; set; } = new();
- public Dictionary Properties { get; set; } = new();
+ public object Properties { get; set; } = new();
public DateTime Time { get; set; } = DateTime.UtcNow;
diff --git a/src/Plugins/BotSharp.Plugin.Membase/Models/NodeCreationModel.cs b/src/Plugins/BotSharp.Plugin.Membase/Models/NodeCreationModel.cs
index 810f26d55..d32dfd3a6 100644
--- a/src/Plugins/BotSharp.Plugin.Membase/Models/NodeCreationModel.cs
+++ b/src/Plugins/BotSharp.Plugin.Membase/Models/NodeCreationModel.cs
@@ -4,7 +4,8 @@ public class NodeCreationModel
{
public string? Id { get; set; }
public string[]? Labels { get; set; }
- public Dictionary? Properties { get; set; }
+ public object? Properties { get; set; }
+ public DateTime? Time { get; set; }
public Node ToNode()
{
@@ -12,8 +13,8 @@ public Node ToNode()
{
Id = Id,
Labels = Labels?.ToList() ?? new List(),
- Properties = Properties ?? new Dictionary(),
- Time = DateTime.UtcNow
+ Properties = Properties ?? new(),
+ Time = Time ?? DateTime.UtcNow
};
}
}
diff --git a/src/Plugins/BotSharp.Plugin.Membase/Models/NodeUpdateModel.cs b/src/Plugins/BotSharp.Plugin.Membase/Models/NodeUpdateModel.cs
index a89d2220e..1a8746552 100644
--- a/src/Plugins/BotSharp.Plugin.Membase/Models/NodeUpdateModel.cs
+++ b/src/Plugins/BotSharp.Plugin.Membase/Models/NodeUpdateModel.cs
@@ -1,19 +1,22 @@
+using System.Text.Json;
+
namespace BotSharp.Plugin.Membase.Models;
public class NodeUpdateModel
{
public string Id { get; set; } = null!;
public string[]? Labels { get; set; }
- public Dictionary? Properties { get; set; }
+ public object? Properties { get; set; }
+ public DateTime? Time { get; set; }
public Node ToNode()
{
return new Node
{
Id = Id,
- Labels = Labels?.ToList() ?? new List(),
- Properties = Properties ?? new Dictionary(),
- Time = DateTime.UtcNow
+ Labels = Labels?.ToList() ?? [],
+ Properties = Properties ?? new(),
+ Time = Time ?? DateTime.UtcNow
};
}
}
diff --git a/src/Plugins/BotSharp.Plugin.Membase/Services/IMembaseApi.cs b/src/Plugins/BotSharp.Plugin.Membase/Services/IMembaseApi.cs
index e5def687f..5455c3457 100644
--- a/src/Plugins/BotSharp.Plugin.Membase/Services/IMembaseApi.cs
+++ b/src/Plugins/BotSharp.Plugin.Membase/Services/IMembaseApi.cs
@@ -4,17 +4,27 @@
namespace BotSharp.Plugin.Membase.Services;
+///
+/// Membase REST API interface
+/// https://membase.dev/graph-api-reference
+///
public interface IMembaseApi
{
+ [Post("/cypher/execute?graphId={graphId}")]
+ Task CypherQueryAsync(string graphId, CypherQueryRequest request);
+
[Post("/graph/{graphId}/node")]
- Task CreateNode(string graphId, [Body] NodeCreationModel node);
+ Task CreateNodeAsync(string graphId, [Body] NodeCreationModel node);
[Get("/graph/{graphId}/node/{nodeId}")]
- Task GetNode(string graphId, string nodeId);
+ Task GetNodeAsync(string graphId, string nodeId);
[Put("/graph/{graphId}/node/{nodeId}")]
- Task UpdateNode(string graphId, string nodeId, [Body] NodeUpdateModel node);
+ Task UpdateNodeAsync(string graphId, string nodeId, [Body] NodeUpdateModel node);
+
+ [Put("/graph/{graphId}/node/{nodeId}/merge")]
+ Task MergeNodeAsync(string graphId, string nodeId, [Body] NodeUpdateModel node);
[Delete("/graph/{graphId}/node/{nodeId}")]
- Task DeleteNode(string graphId, string nodeId);
+ Task DeleteNodeAsync(string graphId, string nodeId);
}
diff --git a/src/Plugins/BotSharp.Plugin.Membase/Services/MembaseService.cs b/src/Plugins/BotSharp.Plugin.Membase/Services/MembaseService.cs
index 42d4f7e09..530ab715c 100644
--- a/src/Plugins/BotSharp.Plugin.Membase/Services/MembaseService.cs
+++ b/src/Plugins/BotSharp.Plugin.Membase/Services/MembaseService.cs
@@ -1,5 +1,52 @@
+using BotSharp.Abstraction.Knowledges;
+using BotSharp.Abstraction.Knowledges.Models;
+using BotSharp.Plugin.Membase.Models;
+using System.Threading.Tasks;
+
namespace BotSharp.Plugin.Membase.Services;
-public class MembaseService
+public class MembaseService : ICypherGraphService
{
+ private readonly IServiceProvider _services;
+ private readonly IMembaseApi _membase;
+
+ public MembaseService(IServiceProvider services, IMembaseApi membase)
+ {
+ _services = services;
+ _membase = membase;
+ }
+
+ public async Task Execute(string graphId, string query, Dictionary? args = null)
+ {
+ var response = await _membase.CypherQueryAsync(graphId, new CypherQueryRequest
+ {
+ Query = query,
+ Parameters = args ?? []
+ });
+
+ return new GraphQueryResult
+ {
+ Columns = response.Columns,
+ Items = response.Data
+ };
+ }
+
+ public async Task MergeNode(string graphId, GraphNode node)
+ {
+ var newNode = await _membase.MergeNodeAsync(graphId, node.Id, new NodeUpdateModel
+ {
+ Id = node.Id,
+ Labels = [.. node.Labels],
+ Properties = node.Properties,
+ Time = node.Time
+ });
+
+ return node;
+ }
+
+ public async Task DeleteNode(string graphId, string nodeId)
+ {
+ await _membase.DeleteNodeAsync(graphId, nodeId);
+ return true;
+ }
}
diff --git a/src/Plugins/BotSharp.Plugin.Membase/Using.cs b/src/Plugins/BotSharp.Plugin.Membase/Using.cs
index 95b43e02b..6f368942d 100644
--- a/src/Plugins/BotSharp.Plugin.Membase/Using.cs
+++ b/src/Plugins/BotSharp.Plugin.Membase/Using.cs
@@ -1,8 +1,16 @@
global using System;
global using System.Collections.Generic;
global using System.Linq;
+global using System.Threading.Tasks;
global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Mvc;
+global using Microsoft.Extensions.Configuration;
+global using Microsoft.Extensions.DependencyInjection;
global using BotSharp.Abstraction.Users;
+global using BotSharp.Abstraction.Knowledges;
+global using BotSharp.Abstraction.Plugins;
+global using BotSharp.Abstraction.Settings;
+global using BotSharp.Plugin.Membase.Services;
+global using BotSharp.Plugin.Membase.Settings;