Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ print(data.uint64) // UInt64?

print(data.bool) // Bool?

print(data.jsonb) // Data?

print(data.float) // Float?
print(data.double) // Double?

Expand Down
60 changes: 60 additions & 0 deletions Sources/PostgresNIO/Data/PostgresData+JSONB.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Foundation

fileprivate let jsonBVersionBytes: [UInt8] = [0x01]

extension PostgresData {
public init(jsonb jsonData: Data) {
let jsonBDataBytes = [UInt8](jsonData)

var buffer = ByteBufferAllocator().buffer(capacity: jsonBVersionBytes.count + jsonBDataBytes.count)
buffer.writeBytes(jsonBVersionBytes)
buffer.writeBytes(jsonBDataBytes)

self.init(type: .jsonb, formatCode: .binary, value: buffer)
}

public var jsonb: Data? {
guard var value = self.value else {
return nil
}

guard let versionBytes = value.readBytes(length: jsonBVersionBytes.count), [UInt8](versionBytes) == jsonBVersionBytes else {
return nil
}

guard let dataBytes = value.readBytes(length: value.readableBytes) else {
return nil
}

return Data(dataBytes)
}
}

public protocol JSONBCodable: Codable, PostgresDataConvertible {
}

extension JSONBCodable {
public static var postgresDataType: PostgresDataType {
return .jsonb
}

public var postgresData: PostgresData? {
guard let jsonData = try? JSONEncoder().encode(self) else {
return nil
}

return .init(jsonb: jsonData)
}

public init?(postgresData: PostgresData) {
guard let jsonData = postgresData.jsonb else {
return nil
}

guard let value = try? JSONDecoder().decode(Self.self, from: jsonData) else {
return nil
}

self = value
}
}
44 changes: 44 additions & 0 deletions Tests/PostgresNIOTests/NIOPostgresTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,50 @@ final class NIOPostgresTests: XCTestCase {
}
}

func testJSONBSerialize() throws {
struct Object: Codable, JSONBCodable {
let foo: Int
let bar: Int
}

let conn = try PostgresConnection.test(on: eventLoop).wait()
defer { try! conn.close().wait() }
do {
let jsonData = try JSONEncoder().encode(Object(foo: 1, bar: 2))
let postgresData = PostgresData(jsonb: jsonData)

let rows = try conn.query("select $1::jsonb as jsonb", [postgresData]).wait()

let objectA = try JSONDecoder().decode(Object.self, from: rows[0].column("jsonb")?.jsonb ?? Data())
XCTAssertEqual(objectA.foo, 1)
XCTAssertEqual(objectA.bar, 2)

XCTAssertEqual(objectA.postgresData?.type, .jsonb)
XCTAssertEqual(objectA.postgresData?.formatCode, .binary)

let objectB = Object(postgresData: postgresData)
XCTAssertEqual(objectB?.foo, 1)
XCTAssertEqual(objectB?.bar, 2)
}
}

func testJSONBParse() throws {
struct Object: Decodable {
let foo: Int
let bar: Int
}

let conn = try PostgresConnection.test(on: eventLoop).wait()
defer { try! conn.close().wait() }
do {
let rows = try conn.query("select jsonb_build_object('foo',1,'bar',2) as jsonb").wait()

let object = try JSONDecoder().decode(Object.self, from: rows[0].column("jsonb")?.jsonb ?? Data())
XCTAssertEqual(object.foo, 1)
XCTAssertEqual(object.bar, 2)
}
}

func testRemoteTLSServer() throws {
let url = "postgres://uymgphwj:[email protected]:5432/uymgphwj"
let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1)
Expand Down
2 changes: 2 additions & 0 deletions Tests/PostgresNIOTests/XCTestManifests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ extension NIOPostgresTests {
("testAverageLengthNumeric", testAverageLengthNumeric),
("testBindInteger", testBindInteger),
("testBoolSerialize", testBoolSerialize),
("testJSONBSerialize", testJSONBSerialize),
("testJSONBParse", testJSONBParse),
("testColumnsInJoin", testColumnsInJoin),
("testConnectAndClose", testConnectAndClose),
("testDates", testDates),
Expand Down