SwiftAge

SwiftAge 是 PostgresNIO 的一个扩展,它使得可以使用 PostgreSQL 的 Apache AGE 扩展来查询和解析图数据库的响应。

入门

添加依赖

对于使用 Package.swift 文件的 Vapor 或其他项目,可以将 SwiftAge 作为依赖项添加。

  dependencies: [
    .package(url: "https://github.com/joshjacob/SwiftAge", from: "1.0.0-alpha.1"),
    ...
  ]
  ...
  targets: [
    .target(name: "MyTarget", dependencies: [
      ...
      .product(name: "SwiftAge", package: "SwiftAge"),
    ])
  ]

对于在 Xcode 中开发的开发者,可以在目标的 “General” 选项卡中的 “Frameworks and Libraries” 部分添加依赖项。

连接

SwiftAge 在 PostgresNIO 的 PostgresConnection 之上添加了查询扩展,因此连接的创建方式遵循 PostgresNIO 文档。

   let connection = try await PostgresConnection.connect(
     on: eventLoopGroup.next(),
     configuration: config,
     id: 1,
     logger: logger
   ).get()

设置 AGE

每个连接都需要运行命令来设置 AGE。 为此提供了一个便利的方法。

try await connection.setUpAge(logger: logger)
// will run:
//	LOAD 'age';
//	SET search_path = ag_catalog, "$user", public;
//	"SELECT cast(typelem as INTEGER) FROM pg_type WHERE typname='_agtype'"

最后一个调用会获取 _agtype 的 Postgres OID,并配置 PostgresNIO 解码。

使用 SwiftAge 扩展进行查询

之后,就可以进行图查询了。

// with EventLoop...
let agRows = try connection.execCypher(
	"SELECT * FROM cypher('test_graph_1', $$ MATCH (v:Person) RETURN v $$) as (v agtype);", 
	logger: logger).wait()

// ...or Async/Await
let agRows = try await connection.execCypher(
	"SELECT * FROM cypher('test_graph_1', $$ MATCH (v:Person) RETURN v $$) as (v agtype);", 
	logger: logger)

返回的 CypherQueryResult 结构体包含类似于 PostgresQueryResultPostgresQueryMetadata 数据,但 rows 字段是一个 AGValue 数组。 AGValue 类型可以是 Apache AGE 定义的标量类型之一,也可以是一个表示顶点、边或路径的结构体。

使用 PostgresNIO 解码进行查询

除了使用 execCypher() 调用之外,您还可以使用常规的 PostgresNIO 方法进行查询和获取结果。 SwiftAge 将在 AGValueWrapper 中返回 agtype 数据,其值可以强制转换为适当的类型。

let rows = try await connection.query(
	"SELECT * FROM cypher('test_graph_1', $$ MATCH (v:Person) RETURN v $$) as (v agtype);", 
	logger: logger)
for try await (agValue) in rows.decode((AGValueWrapper).self, context: .default) {
	if let vertex = agValue.value as? Vertex {
		print(vertex.label)
	}
}

参数

AGValueWrapper 结构体也可以用于正确编码 Postgres 绑定参数。

let params: Dictionary<String,AGValue> = ["newName": "Little'Bobby'Tables"]
let paramsWrapper: AGValueWrapper = AGValueWrapper.init(value: params)
let agRows = try await connection.execCypher(
	"SELECT * FROM cypher('test_graph_1', $$ CREATE (v:Person {name: $newName}) RETURN v $$, \( paramsWrapper )) as (v agtype);",
	logger: logger)

在 PostgresNIO 和 SwiftAge 之间,这将导致查询被转换为

SELECT * FROM cypher('test_graph_1', $$ CREATE (v:Person {name: $newName}) RETURN v $$, $1) as (v agtype);

并且 $1 参数是 Dictionary 的 jsonb 编码。

入门

请参阅 SwiftAgeExamples 获取更多示例。

已知问题

  1. 不支持在同一运行时连接到不同的数据库。 每个 PostgreSQL + Apache AGE 安装都可以使用不同的标识符配置 AGE 自定义数据类型。 虽然 SwiftAge 会找到并配置标识符的解析,但 PostgresNIO 只允许在运行时范围内进行配置,而不是按连接进行配置。 如果您连接到多个数据库,PostgresNIO 解码很可能会失败。 以下 PostgresNIO 问题跟踪了改进以纠正此问题:vapor/postgres-nio#333
  2. 为了在 Linux 上编译,我必须 fork antlr4 依赖项,并按照此问题引入更改:antlr/antlr4#4236.