diff --git a/Sources/PostgresNIO/Data/PostgresDataType.swift b/Sources/PostgresNIO/Data/PostgresDataType.swift index f3ab4dca..c3e4e747 100644 --- a/Sources/PostgresNIO/Data/PostgresDataType.swift +++ b/Sources/PostgresNIO/Data/PostgresDataType.swift @@ -113,12 +113,14 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri /// `774` public static let macaddr8 = PostgresDataType(774) /// `775` - public static let macaddr8Aray = PostgresDataType(775) + @available(*, deprecated, renamed: "macaddr8Array") + public static let macaddr8Aray = Self.macaddr8Array + public static let macaddr8Array = PostgresDataType(775) /// `790` public static let money = PostgresDataType(790) /// `791` @available(*, deprecated, renamed: "moneyArray") - public static let _money = PostgresDataType(791) + public static let _money = Self.moneyArray public static let moneyArray = PostgresDataType(791) /// `829` public static let macaddr = PostgresDataType(829) @@ -192,6 +194,10 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri public static let timestamp = PostgresDataType(1114) /// `1115` _timestamp public static let timestampArray = PostgresDataType(1115) + /// `1182` + public static let dateArray = PostgresDataType(1182) + /// `1183` + public static let timeArray = PostgresDataType(1183) /// `1184` public static let timestamptz = PostgresDataType(1184) /// `1185` @@ -446,7 +452,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .circle: return "CIRCLE" case .circleArray: return "CIRCLE[]" case .macaddr8: return "MACADDR8" - case .macaddr8Aray: return "MACADDR8[]" + case .macaddr8Array: return "MACADDR8[]" case .money: return "MONEY" case .moneyArray: return "MONEY[]" case .macaddr: return "MACADDR" @@ -485,6 +491,8 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .time: return "TIME" case .timestamp: return "TIMESTAMP" case .timestampArray: return "TIMESTAMP[]" + case .dateArray: return "DATE[]" + case .timeArray: return "TIME[]" case .timestamptz: return "TIMESTAMPTZ" case .timestamptzArray: return "TIMESTAMPTZ[]" case .interval: return "INTERVAL" @@ -596,7 +604,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .line: return .lineArray case .cidr: return .cidrArray case .circle: return .circleArray - case .macaddr8Aray: return .macaddr8 + case .macaddr8: return .macaddr8Array case .money: return .moneyArray case .int2vector: return .int2vectorArray case .regproc: return .regprocArray @@ -613,6 +621,9 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .aclitem: return .aclitemArray case .macaddr: return .macaddrArray case .inet: return .inetArray + case .timestamp: return .timestampArray + case .date: return .dateArray + case .time: return .timeArray case .timestamptz: return .timestamptzArray case .interval: return .intervalArray case .numeric: return .numericArray @@ -635,6 +646,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .regdictionary: return .regdictionaryArray case .numrange: return .numrangeArray case .tsrange: return .tsrangeArray + case .tstzrange: return .tstzrangeArray case .daterange: return .daterangeArray case .jsonpath: return .jsonpathArray case .regnamespace: return .regnamespaceArray @@ -643,7 +655,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .int4multirange: return .int4multirangeArray case .tsmultirange: return .tsmultirangeArray case .tstzmultirange: return .tstzmultirangeArray - case .datemultirange: return .datemultirange + case .datemultirange: return .datemultirangeArray case .int8multirange: return .int8multirangeArray case .bool: return .boolArray case .bytea: return .byteaArray @@ -677,7 +689,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .lineArray: return .line case .cidrArray: return .cidr case .circleArray: return .circle - case .macaddr8: return .macaddr8Aray + case .macaddr8Array: return .macaddr8 case .moneyArray: return .money case .int2vectorArray: return .int2vector case .regprocArray: return .regproc @@ -694,6 +706,9 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .aclitemArray: return .aclitem case .macaddrArray: return .macaddr case .inetArray: return .inet + case .timestampArray: return .timestamp + case .dateArray: return .date + case .timeArray: return .time case .timestamptzArray: return .timestamptz case .intervalArray: return .interval case .numericArray: return .numeric @@ -716,6 +731,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .regdictionaryArray: return .regdictionary case .numrangeArray: return .numrange case .tsrangeArray: return .tsrange + case .tstzrangeArray: return .tstzrange case .daterangeArray: return .daterange case .jsonpathArray: return .jsonpath case .regnamespaceArray: return .regnamespace @@ -724,7 +740,7 @@ public struct PostgresDataType: RawRepresentable, Sendable, Hashable, CustomStri case .int4multirangeArray: return .int4multirange case .tsmultirangeArray: return .tsmultirange case .tstzmultirangeArray: return .tstzmultirange - case .datemultirange: return .datemultirange + case .datemultirangeArray: return .datemultirange case .int8multirangeArray: return .int8multirange case .boolArray: return .bool case .byteaArray: return .bytea diff --git a/Sources/PostgresNIO/New/Data/Array+PostgresCodable.swift b/Sources/PostgresNIO/New/Data/Array+PostgresCodable.swift index d605a6c1..ddab0fff 100644 --- a/Sources/PostgresNIO/New/Data/Array+PostgresCodable.swift +++ b/Sources/PostgresNIO/New/Data/Array+PostgresCodable.swift @@ -1,4 +1,5 @@ import NIOCore +import struct Foundation.Date import struct Foundation.UUID // MARK: Protocols @@ -85,6 +86,12 @@ extension UUID: PostgresArrayEncodable { public static var psqlArrayType: PostgresDataType { .uuidArray } } +extension Date: PostgresArrayDecodable {} + +extension Date: PostgresArrayEncodable { + public static var psqlArrayType: PostgresDataType { .timestamptzArray } +} + extension Range: PostgresArrayDecodable where Bound: PostgresRangeArrayDecodable {} extension Range: PostgresArrayEncodable where Bound: PostgresRangeArrayEncodable { diff --git a/Tests/IntegrationTests/PostgresNIOTests.swift b/Tests/IntegrationTests/PostgresNIOTests.swift index ea4d8d05..de6aaf73 100644 --- a/Tests/IntegrationTests/PostgresNIOTests.swift +++ b/Tests/IntegrationTests/PostgresNIOTests.swift @@ -783,6 +783,44 @@ final class PostgresNIOTests: XCTestCase { XCTAssertEqual(row?[data: "array"].array(of: Int64?.self), [1, nil, 3]) } + @available(*, deprecated, message: "Testing deprecated functionality") + func testDateArraySerialize() { + var conn: PostgresConnection? + XCTAssertNoThrow(conn = try PostgresConnection.test(on: eventLoop).wait()) + defer { XCTAssertNoThrow( try conn?.close().wait() ) } + let date1 = Date(timeIntervalSince1970: 1704088800), + date2 = Date(timeIntervalSince1970: 1706767200), + date3 = Date(timeIntervalSince1970: 1709272800) + var rows: PostgresQueryResult? + XCTAssertNoThrow(rows = try conn?.query(""" + select + $1::timestamptz[] as array + """, [ + PostgresData(array: [date1, date2, date3]) + ]).wait()) + let row = rows?.first?.makeRandomAccess() + XCTAssertEqual(row?[data: "array"].array(of: Date.self), [date1, date2, date3]) + } + + @available(*, deprecated, message: "Testing deprecated functionality") + func testDateArraySerializeAsPostgresDate() { + var conn: PostgresConnection? + XCTAssertNoThrow(conn = try PostgresConnection.test(on: eventLoop).wait()) + defer { XCTAssertNoThrow(try conn?.close().wait()) } + let date1 = Date(timeIntervalSince1970: 1704088800),//8766 + date2 = Date(timeIntervalSince1970: 1706767200),//8797 + date3 = Date(timeIntervalSince1970: 1709272800) //8826 + var data = PostgresData(array: [date1, date2, date3].map { Int32(($0.timeIntervalSince1970 - 946_684_800) / 86_400).postgresData }, elementType: .date) + data.type = .dateArray // N.B.: `.date` format is an Int32 count of days since psqlStartDate + var rows: PostgresQueryResult? + XCTAssertNoThrow(rows = try conn?.query("select $1::date[] as array", [data]).wait()) + let row = rows?.first?.makeRandomAccess() + XCTAssertEqual( + row?[data: "array"].array(of: Date.self)?.map { Int32((($0.timeIntervalSince1970 - 946_684_800) / 86_400).rounded(.toNearestOrAwayFromZero)) }, + [date1, date2, date3].map { Int32((($0.timeIntervalSince1970 - 946_684_800) / 86_400).rounded(.toNearestOrAwayFromZero)) } + ) + } + // https://github.com/vapor/postgres-nio/issues/143 func testEmptyStringFromNonNullColumn() { var conn: PostgresConnection? diff --git a/Tests/PostgresNIOTests/New/Data/Array+PSQLCodableTests.swift b/Tests/PostgresNIOTests/New/Data/Array+PSQLCodableTests.swift index 79d47c30..bfffef52 100644 --- a/Tests/PostgresNIOTests/New/Data/Array+PSQLCodableTests.swift +++ b/Tests/PostgresNIOTests/New/Data/Array+PSQLCodableTests.swift @@ -56,6 +56,10 @@ class Array_PSQLCodableTests: XCTestCase { XCTAssertEqual(UUID.psqlType, .uuid) XCTAssertEqual([UUID].psqlType, .uuidArray) + XCTAssertEqual(Date.psqlArrayType, .timestamptzArray) + XCTAssertEqual(Date.psqlType, .timestamptz) + XCTAssertEqual([Date].psqlType, .timestamptzArray) + XCTAssertEqual(Range.psqlArrayType, .int4RangeArray) XCTAssertEqual(Range.psqlType, .int4Range) XCTAssertEqual([Range].psqlType, .int4RangeArray)