SwiftAge

1.0.0-alpha.2

Swift drive for Apache AGE
joshjacob/SwiftAge

What's New

SwiftAge 1.0.0-alpha.2

2023-10-27T17:51:47Z

Update dependencies and added tests for macOS and linux.

SwiftAge

SwiftAge is an extension to PostgresNIO that enables quering and response parsing of graph databases with the Apache AGE extension to PostgreSQL.

Getting started

Adding the dependency

For Vapor of other projects using a Package.swift file, SwiftAge can be added as a dependency:

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

For those developing in Xcode, the dependency can be added in the "Frameworks and Libraries" section of the "General" tab for your target.

Connection

SwiftAge adds querying extensions on top of the PostgresNIO PostgresConnection so creation of that connection happens according to PostgresNIO documentation:

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

Set up AGE

Each connection needs commands run to set up AGE. A convenience method is provided for this:

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'"

The last call fetches the Postgres OID for _agtype and configures PostgresNIO decoding.

Querying with SwiftAge Extensions

After that, graph querying can happen:

// 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)

The returned CypherQueryResult struct contains the PostgresQueryMetadata data similar to PostgresQueryResult but the rows field is an AGValue array. The AGValue type can be one of the scalar types defined by Apache AGE as well as a struct to represent a Vertex, Edge or Path.

Querying with PostgresNIO Decoding

Instead of using the execCypher() calls, you can use the normal PostgresNIO methods for querying and fetching results. SwiftAge will return agtype data in a AGValueWrapper whose value can be cast to appropriate types:

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)
	}
}

Parameters

The AGValueWrapper struct can also be used to properly encode Postgres binding parameters:

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)

Between PostgresNIO and SwiftAge, this will result in the query being converted to:

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

And the $1 parameter being a jsonb encoding of the Dictionary.

Getting started

See SwiftAgeExamples for additional examples.

Known Issues

  1. No support for connections to different databases in the same runtime. Each PostgreSQL + Apache AGE installation can configure the AGE custom data type with different identifiers. While SwiftAge will find and configure the parsing for the identifier, PostgresNIO only allows that configuration at the runtime scope and not scoped per connection. If you are connecting to multiple databases, PostgresNIO Decoding will likely fail. The folowing PostgresNIO issue tracks an improvement to correct this: vapor/postgres-nio#333
  2. In order to compile on Linux, I had to fork the antlr4 dependency and introduce a change per this issue: antlr/antlr4#4236.

Description

  • Swift Tools 5.6.0
View More Packages from this Author

Dependencies

Last updated: Wed May 01 2024 17:10:44 GMT-0900 (Hawaii-Aleutian Daylight Time)