-
-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add proper support for
Decimal
(#194)
* Use `PostgresNumeric` for `Decimal` instead of String * Make `Decimal` conform to `PSQLCodable` * Fix support for text decimals * Add integration test for decimal string serialization * Test inserting decimal to text column Co-authored-by: Gwynne Raskind <gwynne@darkrainfall.org>
- Loading branch information
1 parent
f91f23d
commit 2c49bee
Showing
5 changed files
with
128 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import NIOCore | ||
import struct Foundation.Decimal | ||
|
||
extension Decimal: PSQLCodable { | ||
var psqlType: PSQLDataType { | ||
.numeric | ||
} | ||
|
||
var psqlFormat: PSQLFormat { | ||
.binary | ||
} | ||
|
||
static func decode(from byteBuffer: inout ByteBuffer, type: PSQLDataType, format: PSQLFormat, context: PSQLDecodingContext) throws -> Decimal { | ||
switch (format, type) { | ||
case (.binary, .numeric): | ||
guard let numeric = PostgresNumeric(buffer: &byteBuffer) else { | ||
throw PSQLCastingError.failure(targetType: Self.self, type: type, postgresData: byteBuffer, context: context) | ||
} | ||
return numeric.decimal | ||
case (.text, .numeric): | ||
guard let string = byteBuffer.readString(length: byteBuffer.readableBytes), let value = Decimal(string: string) else { | ||
throw PSQLCastingError.failure(targetType: Self.self, type: type, postgresData: byteBuffer, context: context) | ||
} | ||
return value | ||
default: | ||
throw PSQLCastingError.failure(targetType: Self.self, type: type, postgresData: byteBuffer, context: context) | ||
} | ||
} | ||
|
||
func encode(into byteBuffer: inout ByteBuffer, context: PSQLEncodingContext) { | ||
let numeric = PostgresNumeric(decimal: self) | ||
byteBuffer.writeInteger(numeric.ndigits) | ||
byteBuffer.writeInteger(numeric.weight) | ||
byteBuffer.writeInteger(numeric.sign) | ||
byteBuffer.writeInteger(numeric.dscale) | ||
var value = numeric.value | ||
byteBuffer.writeBuffer(&value) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
Tests/PostgresNIOTests/New/Data/Decimal+PSQLCodableTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import XCTest | ||
import NIOCore | ||
@testable import PostgresNIO | ||
|
||
class Decimal_PSQLCodableTests: XCTestCase { | ||
|
||
func testRoundTrip() { | ||
let values: [Decimal] = [1.1, .pi, -5e-12] | ||
|
||
for value in values { | ||
var buffer = ByteBuffer() | ||
value.encode(into: &buffer, context: .forTests()) | ||
XCTAssertEqual(value.psqlType, .numeric) | ||
let data = PSQLData(bytes: buffer, dataType: .numeric, format: .binary) | ||
|
||
var result: Decimal? | ||
XCTAssertNoThrow(result = try data.decode(as: Decimal.self, context: .forTests())) | ||
XCTAssertEqual(value, result) | ||
} | ||
} | ||
|
||
func testDecodeFailureInvalidType() { | ||
var buffer = ByteBuffer() | ||
buffer.writeInteger(Int64(0)) | ||
let data = PSQLData(bytes: buffer, dataType: .int8, format: .binary) | ||
|
||
XCTAssertThrowsError(try data.decode(as: Decimal.self, context: .forTests())) { error in | ||
XCTAssert(error is PSQLCastingError) | ||
} | ||
} | ||
|
||
} |