Skip to content

Commit b6496eb

Browse files
authored
Fix multiple array type mapping mistakes and add missing date and time array types (#463)
* Add missing definitions for Postgres type OIDs 1182 and 1183 (_date and _time), fix typos in the `macaddr8Array` and `datemultirange` types, and add missing array mappings for `timestamp` and `tstzrange`. * Add PostgresArrayCodable conformance for Date * Add tests for date arrays. * Fix test to account for rounding error in conversion to days during Postgres encoding
1 parent dc9caf8 commit b6496eb

File tree

4 files changed

+72
-7
lines changed

4 files changed

+72
-7
lines changed

Sources/PostgresNIO/Data/PostgresDataType.swift

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,14 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
113113
/// `774`
114114
public static let macaddr8 = PostgresDataType(774)
115115
/// `775`
116-
public static let macaddr8Aray = PostgresDataType(775)
116+
@available(*, deprecated, renamed: "macaddr8Array")
117+
public static let macaddr8Aray = Self.macaddr8Array
118+
public static let macaddr8Array = PostgresDataType(775)
117119
/// `790`
118120
public static let money = PostgresDataType(790)
119121
/// `791`
120122
@available(*, deprecated, renamed: "moneyArray")
121-
public static let _money = PostgresDataType(791)
123+
public static let _money = Self.moneyArray
122124
public static let moneyArray = PostgresDataType(791)
123125
/// `829`
124126
public static let macaddr = PostgresDataType(829)
@@ -192,6 +194,10 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
192194
public static let timestamp = PostgresDataType(1114)
193195
/// `1115` _timestamp
194196
public static let timestampArray = PostgresDataType(1115)
197+
/// `1182`
198+
public static let dateArray = PostgresDataType(1182)
199+
/// `1183`
200+
public static let timeArray = PostgresDataType(1183)
195201
/// `1184`
196202
public static let timestamptz = PostgresDataType(1184)
197203
/// `1185`
@@ -446,7 +452,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
446452
case .circle: return "CIRCLE"
447453
case .circleArray: return "CIRCLE[]"
448454
case .macaddr8: return "MACADDR8"
449-
case .macaddr8Aray: return "MACADDR8[]"
455+
case .macaddr8Array: return "MACADDR8[]"
450456
case .money: return "MONEY"
451457
case .moneyArray: return "MONEY[]"
452458
case .macaddr: return "MACADDR"
@@ -485,6 +491,8 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
485491
case .time: return "TIME"
486492
case .timestamp: return "TIMESTAMP"
487493
case .timestampArray: return "TIMESTAMP[]"
494+
case .dateArray: return "DATE[]"
495+
case .timeArray: return "TIME[]"
488496
case .timestamptz: return "TIMESTAMPTZ"
489497
case .timestamptzArray: return "TIMESTAMPTZ[]"
490498
case .interval: return "INTERVAL"
@@ -596,7 +604,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
596604
case .line: return .lineArray
597605
case .cidr: return .cidrArray
598606
case .circle: return .circleArray
599-
case .macaddr8Aray: return .macaddr8
607+
case .macaddr8: return .macaddr8Array
600608
case .money: return .moneyArray
601609
case .int2vector: return .int2vectorArray
602610
case .regproc: return .regprocArray
@@ -613,6 +621,9 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
613621
case .aclitem: return .aclitemArray
614622
case .macaddr: return .macaddrArray
615623
case .inet: return .inetArray
624+
case .timestamp: return .timestampArray
625+
case .date: return .dateArray
626+
case .time: return .timeArray
616627
case .timestamptz: return .timestamptzArray
617628
case .interval: return .intervalArray
618629
case .numeric: return .numericArray
@@ -635,6 +646,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
635646
case .regdictionary: return .regdictionaryArray
636647
case .numrange: return .numrangeArray
637648
case .tsrange: return .tsrangeArray
649+
case .tstzrange: return .tstzrangeArray
638650
case .daterange: return .daterangeArray
639651
case .jsonpath: return .jsonpathArray
640652
case .regnamespace: return .regnamespaceArray
@@ -643,7 +655,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
643655
case .int4multirange: return .int4multirangeArray
644656
case .tsmultirange: return .tsmultirangeArray
645657
case .tstzmultirange: return .tstzmultirangeArray
646-
case .datemultirange: return .datemultirange
658+
case .datemultirange: return .datemultirangeArray
647659
case .int8multirange: return .int8multirangeArray
648660
case .bool: return .boolArray
649661
case .bytea: return .byteaArray
@@ -677,7 +689,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
677689
case .lineArray: return .line
678690
case .cidrArray: return .cidr
679691
case .circleArray: return .circle
680-
case .macaddr8: return .macaddr8Aray
692+
case .macaddr8Array: return .macaddr8
681693
case .moneyArray: return .money
682694
case .int2vectorArray: return .int2vector
683695
case .regprocArray: return .regproc
@@ -694,6 +706,9 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
694706
case .aclitemArray: return .aclitem
695707
case .macaddrArray: return .macaddr
696708
case .inetArray: return .inet
709+
case .timestampArray: return .timestamp
710+
case .dateArray: return .date
711+
case .timeArray: return .time
697712
case .timestamptzArray: return .timestamptz
698713
case .intervalArray: return .interval
699714
case .numericArray: return .numeric
@@ -716,6 +731,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
716731
case .regdictionaryArray: return .regdictionary
717732
case .numrangeArray: return .numrange
718733
case .tsrangeArray: return .tsrange
734+
case .tstzrangeArray: return .tstzrange
719735
case .daterangeArray: return .daterange
720736
case .jsonpathArray: return .jsonpath
721737
case .regnamespaceArray: return .regnamespace
@@ -724,7 +740,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri
724740
case .int4multirangeArray: return .int4multirange
725741
case .tsmultirangeArray: return .tsmultirange
726742
case .tstzmultirangeArray: return .tstzmultirange
727-
case .datemultirange: return .datemultirange
743+
case .datemultirangeArray: return .datemultirange
728744
case .int8multirangeArray: return .int8multirange
729745
case .boolArray: return .bool
730746
case .byteaArray: return .bytea

Sources/PostgresNIO/New/Data/Array+PostgresCodable.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import NIOCore
2+
import struct Foundation.Date
23
import struct Foundation.UUID
34

45
// MARK: Protocols
@@ -85,6 +86,12 @@ extension UUID: PostgresArrayEncodable {
8586
public static var psqlArrayType: PostgresDataType { .uuidArray }
8687
}
8788

89+
extension Date: PostgresArrayDecodable {}
90+
91+
extension Date: PostgresArrayEncodable {
92+
public static var psqlArrayType: PostgresDataType { .timestamptzArray }
93+
}
94+
8895
extension Range: PostgresArrayDecodable where Bound: PostgresRangeArrayDecodable {}
8996

9097
extension Range: PostgresArrayEncodable where Bound: PostgresRangeArrayEncodable {

Tests/IntegrationTests/PostgresNIOTests.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,44 @@ final class PostgresNIOTests: XCTestCase {
783783
XCTAssertEqual(row?[data: "array"].array(of: Int64?.self), [1, nil, 3])
784784
}
785785

786+
@available(*, deprecated, message: "Testing deprecated functionality")
787+
func testDateArraySerialize() {
788+
var conn: PostgresConnection?
789+
XCTAssertNoThrow(conn = try PostgresConnection.test(on: eventLoop).wait())
790+
defer { XCTAssertNoThrow( try conn?.close().wait() ) }
791+
let date1 = Date(timeIntervalSince1970: 1704088800),
792+
date2 = Date(timeIntervalSince1970: 1706767200),
793+
date3 = Date(timeIntervalSince1970: 1709272800)
794+
var rows: PostgresQueryResult?
795+
XCTAssertNoThrow(rows = try conn?.query("""
796+
select
797+
$1::timestamptz[] as array
798+
""", [
799+
PostgresData(array: [date1, date2, date3])
800+
]).wait())
801+
let row = rows?.first?.makeRandomAccess()
802+
XCTAssertEqual(row?[data: "array"].array(of: Date.self), [date1, date2, date3])
803+
}
804+
805+
@available(*, deprecated, message: "Testing deprecated functionality")
806+
func testDateArraySerializeAsPostgresDate() {
807+
var conn: PostgresConnection?
808+
XCTAssertNoThrow(conn = try PostgresConnection.test(on: eventLoop).wait())
809+
defer { XCTAssertNoThrow(try conn?.close().wait()) }
810+
let date1 = Date(timeIntervalSince1970: 1704088800),//8766
811+
date2 = Date(timeIntervalSince1970: 1706767200),//8797
812+
date3 = Date(timeIntervalSince1970: 1709272800) //8826
813+
var data = PostgresData(array: [date1, date2, date3].map { Int32(($0.timeIntervalSince1970 - 946_684_800) / 86_400).postgresData }, elementType: .date)
814+
data.type = .dateArray // N.B.: `.date` format is an Int32 count of days since psqlStartDate
815+
var rows: PostgresQueryResult?
816+
XCTAssertNoThrow(rows = try conn?.query("select $1::date[] as array", [data]).wait())
817+
let row = rows?.first?.makeRandomAccess()
818+
XCTAssertEqual(
819+
row?[data: "array"].array(of: Date.self)?.map { Int32((($0.timeIntervalSince1970 - 946_684_800) / 86_400).rounded(.toNearestOrAwayFromZero)) },
820+
[date1, date2, date3].map { Int32((($0.timeIntervalSince1970 - 946_684_800) / 86_400).rounded(.toNearestOrAwayFromZero)) }
821+
)
822+
}
823+
786824
// https://github.com/vapor/postgres-nio/issues/143
787825
func testEmptyStringFromNonNullColumn() {
788826
var conn: PostgresConnection?

Tests/PostgresNIOTests/New/Data/Array+PSQLCodableTests.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ class Array_PSQLCodableTests: XCTestCase {
5656
XCTAssertEqual(UUID.psqlType, .uuid)
5757
XCTAssertEqual([UUID].psqlType, .uuidArray)
5858

59+
XCTAssertEqual(Date.psqlArrayType, .timestamptzArray)
60+
XCTAssertEqual(Date.psqlType, .timestamptz)
61+
XCTAssertEqual([Date].psqlType, .timestamptzArray)
62+
5963
XCTAssertEqual(Range<Int32>.psqlArrayType, .int4RangeArray)
6064
XCTAssertEqual(Range<Int32>.psqlType, .int4Range)
6165
XCTAssertEqual([Range<Int32>].psqlType, .int4RangeArray)

0 commit comments

Comments
 (0)