Neo4J Swift 驱动

警告

此库目前正在积极开发中。它可能包含错误,并且在发布第一个稳定版本之前,其 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)

连接池

该驱动程序包含连接池机制的初始版本,可以按如下方式使用

每个池都是为提供的 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)

Neo4J 连接 API

Neo4JConnection Actor 提供了一种并发安全且高效的方式与 Neo4J 数据库交互,利用底层 BoltConnection 执行各种协议请求。 此 Actor 包括多种旨在确保连接在其整个生命周期中得到正确准备和管理的方法,使其成为并发环境中异步操作的理想选择。

Bolt 连接 API

BoltConnection 扩展提供了一组全面的受支持的 Bolt 协议请求,从而可以与 Bolt 服务器进行无缝交互。 这些请求包括

支持的数据类型

Bolt 库包括以下可在运行查询时使用的数据类型

除了 Bolt 库中包含的类型外,Neo4J 库还支持

贡献

非常鼓励大家贡献,因为该库仍在开发中。 一些待处理的功能包括

特别感谢 @SMartorelli@ndPPPhz 对该项目的贡献!