警告
此库目前正在积极开发中。它可能包含错误,并且在发布第一个稳定版本之前,其 API 可能会发生更改。请谨慎使用,并预计未来更新中可能存在破坏性更改。
这是一个 Swift 包,它提供了一种方便的方式,使用 Bolt 协议 v5.4 与 Neo4J 服务器进行通信。
🚀 并发性: 使用 Swift 6 构建,利用 async/await 实现高效并发。
🔒 SSL: 支持与数据库的安全连接。
⚙️ 灵活性: 允许对 Bolt 连接进行高级自动化和低级控制。
☁️ AuraDB: 兼容 Neo4J AuraDB。
该软件包包括以下库
提示
使用 Neo4J 库开始,只有在真正需要时才使用 Bolt 库。
要将此软件包添加为依赖项,请将其包含在您的 Package.swift
中
.package(url: "https://github.com/GiacomoLeopizzi/neo4j-driver-swift.git", from: "0.0.0"),
将 Neo4J
添加到您的应用程序的目标依赖项中
.product(name: "Neo4J", package: "neo4j-driver-swift")
这是一个如何在程序中使用 Neo4JConnection
的示例
import Neo4J
import Logging
import NIOPosix
import ServiceLifecycle
@main
struct Example {
// Use the shared singleton instance of MultiThreadedEventLoopGroup.
static let eventLoopGroup = MultiThreadedEventLoopGroup.singleton
// Initialize the logger.
static let logger = Logger(label: "neo4j")
static func main() async throws {
let configuration = Neo4JConfiguration(
host: "127.0.0.1",
userAgent: "Example/0.0.0",
auth: .basic(password: "12345678"),
logger: logger)
// Instantiate a new Neo4JConnection actor.
let neo4jConnection = Neo4JConnection(configuration: configuration, eventLoopGroup: eventLoopGroup)
// Initialize the service group.
let serviceGroup = ServiceGroup(services: [neo4jConnection], logger: self.logger)
try await withThrowingTaskGroup(of: Void.self) { group in
// Add the connection actor's run function to the task group.
// This opens the connection and handles requests until the task is canceled or the connection is closed.
group.addTask { try await serviceGroup.run() }
// Execute a query with parameters.
try await neo4jConnection.run(query: #"CREATE (r:Person {name: $name, born: $born})"#, parameters: [
"name" : "Robert Zemeckis",
"born" : 1952
])
// Execute a query without parameters.
try await neo4jConnection.run(query: """
CREATE (bttf:Movie {title: "Back to the Future", released: 1985,
tagline: "He's the only kid ever to get into trouble before he was born."})
""")
// Create a relationship between the two nodes.
try await neo4jConnection.run(query: """
MATCH (director:Person {name: "Robert Zemeckis"}), (movie:Movie {title: "Back to the Future"})
CREATE (director)-[:DIRECTED]->(movie)
""")
// Use the run method to return data. The `decodingResultsAs` parameter
// allows decoding the data already cast to the correct Swift type.
// For example, in this case, only the node is returned.
let result = try await neo4jConnection.run(
query: "MATCH (m: Movie) WHERE m.released = $year RETURN m",
parameters: ["year" : 1985],
decodingResultsAs: Node<Movie>.self)
if let bttf = result.first {
print(bttf.properties.tagline ?? "")
}
// In this case, two nodes and a relationship are returned.
// The first is the movie; for the other parameters, the generic Bolt types are used.
let result2 = try await neo4jConnection.run(
query: "MATCH (m: Movie)<-[r:DIRECTED]-(p:Person) WHERE m.released = $year RETURN m, r, p",
parameters: ["year" : 1985],
decodingResultsAs: (Node<Movie>, Bolt.Relationship, Bolt.Node).self)
if let data = result2.first {
// Because of the generic parameter pack, the type of `data` is: (Node<Movie>, Bolt.Relationship, Bolt.Node)
print(data.0.properties.title, data.1.type, data.2.properties)
}
// Delete the nodes and the relationship.
let metadata = try await neo4jConnection.run(query: """
MATCH (director:Person {name: "Robert Zemeckis"}), (movie:Movie {title: "Back to the Future"})
DETACH DELETE director, movie
""")
print(metadata.stats?.description ?? "")
// Cancel all tasks in the task group.
// This also results in the connection to Neo4J being closed.
group.cancelAll()
}
}
}
该驱动程序还支持连接到 Neo4J AuraDB。 要使前面的示例与 AuraDB 一起使用,唯一需要的更改是在配置对象中,可以使用 connectionURI
初始化器参数轻松创建该对象。 一个例子是
let configuration = try Neo4JConfiguration(connectionURI: "neo4j+s://xxxxxxxx.databases.neo4j.io", userAgent: "Example/0.0.0", auth: .basic(password: "the provided password"), logger: logger)
该驱动程序包含连接池机制的初始版本,可以按如下方式使用
Neo4JConnectionPool
:创建 Neo4JConnection
实例池。BoltConnectionPool
:创建 BoltConnection
实例池。每个池都是为提供的 EventLoopGroup
中的每个 EventLoop
创建的。 连接池被实现为服务,因此需要将它们添加到 ServiceGroup
才能正常运行。
Neo4J 连接池的示例
// Create the Neo4J connection pool with the event loop group.
let eventLoopGroupPool = Neo4JConnectionPool(eventLoopGroup: eventLoopGroup, poolConfiguration: poolConfiguration, neo4JConfiguration: neo4JConfiguration)
// Initialize the service group and add the pool as a service.
let serviceGroup = ServiceGroup(services: [eventLoopGroupPool], logger: self.logger)
Neo4JConnection
Actor 提供了一种并发安全且高效的方式与 Neo4J 数据库交互,利用底层 BoltConnection
执行各种协议请求。 此 Actor 包括多种旨在确保连接在其整个生命周期中得到正确准备和管理的方法,使其成为并发环境中异步操作的理想选择。
prepareIfNeeded(function: String = #function): 通过自动发送 hello
、logon
和 reset
请求(基于服务器的当前状态)来准备底层连接。 此方法确保连接已准备好进行后续操作。 它由 Actor 中的其他方法自动调用,因此除非您计划直接与 underlyingConnection
交互,否则通常不需要手动调用。
withinTransaction(extra: BeginExtra = .none, _ closure: (TransactionConnection) async throws -> Void): 在事务中执行一组操作。 此方法启动一个事务,运行提供的闭包,并在成功时提交事务,或在发生错误时回滚事务。 在开始事务之前,会自动调用 prepareIfNeeded
方法以确保连接处于适当状态。
run<each T: Decodable & Sendable>(query: String, parameters: [String: any Encodable & Sendable] = [:], extra: RunExtra = .none, decodingResultsAs types: (repeat each T).Type) async throws -> [(repeat each T)]: 执行 Cypher 查询并自动检索所有结果并将其解码为元组数组,其中每个元组代表一行数据。 此方法非常适合返回数据的查询,确保每个结果都正确解码为指定的类型。 调用 prepareIfNeeded
方法以保证在执行查询之前准备好连接。
run(query: String, parameters: [String: any Encodable & Sendable] = [:], extra: RunExtra = .none) async throws -> SuccessMetadata: 执行不返回数据的 Cypher 查询,例如数据操作。 此方法自动丢弃所有记录,仅返回查询生成的元数据。 与其他方法一样,它调用 prepareIfNeeded
以确保正确初始化连接。
BoltConnection
扩展提供了一组全面的受支持的 Bolt 协议请求,从而可以与 Bolt 服务器进行无缝交互。 这些请求包括
SuccessMetadata
对象。SuccessMetadata
对象。SuccessMetadata
对象。SuccessMetadata
对象。SuccessMetadata
对象。SuccessMetadata
对象。SuccessMetadata
对象。PackStreamValue
数组列表和 SuccessMetadata
对象的元组返回。SuccessMetadata
对象。SuccessMetadata
对象。SuccessMetadata
对象。SuccessMetadata
对象。Bolt
库包括以下可在运行查询时使用的数据类型
除了 Bolt
库中包含的类型外,Neo4J
库还支持
Bolt.Node
将属性作为字典返回。Bolt.Relationship
将属性作为字典返回。非常鼓励大家贡献,因为该库仍在开发中。 一些待处理的功能包括
特别感谢 @SMartorelli 和 @ndPPPhz 对该项目的贡献!