Skip to content

Commit 2d93ec3

Browse files
authored
Merge pull request vapor#22 from vapor/cc-fixes
conditional conformance fixes
2 parents 25a0435 + a226381 commit 2d93ec3

File tree

4 files changed

+74
-28
lines changed

4 files changed

+74
-28
lines changed

Sources/PostgreSQL/Data/PostgreSQLArrayCustomConvertible.swift

+28-14
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import Foundation
22

33
/// Representable by a `T[]` column on the PostgreSQL database.
4-
public protocol PostgreSQLArrayCustomConvertible: PostgreSQLDataCustomConvertible, Codable {
4+
public protocol PostgreSQLArrayCustomConvertible: PostgreSQLDataCustomConvertible {
55
/// The associated array element type
6-
associatedtype PostgreSQLArrayElement: PostgreSQLDataCustomConvertible
6+
associatedtype PostgreSQLArrayElement // : PostgreSQLDataCustomConvertible
77

88
/// Convert an array of elements to self.
99
static func convertFromPostgreSQLArray(_ data: [PostgreSQLArrayElement]) -> Self
@@ -13,11 +13,6 @@ public protocol PostgreSQLArrayCustomConvertible: PostgreSQLDataCustomConvertibl
1313
}
1414

1515
extension PostgreSQLArrayCustomConvertible {
16-
/// See `PostgreSQLDataCustomConvertible.postgreSQLDataType`
17-
public static var postgreSQLDataType: PostgreSQLDataType {
18-
return PostgreSQLArrayElement.postgreSQLDataArrayType
19-
}
20-
2116
/// See `PostgreSQLDataCustomConvertible.convertFromPostgreSQLData(_:)`
2217
public static func convertFromPostgreSQLData(_ data: PostgreSQLData) throws -> Self {
2318
guard var value = data.data else {
@@ -35,8 +30,8 @@ extension PostgreSQLArrayCustomConvertible {
3530
let count = Int(value.extract(Int32.self).bigEndian)
3631
let subValue = value.extract(count: count)
3732
let psqlData = PostgreSQLData(type: metadata.type, format: data.format, data: subValue)
38-
let element = try PostgreSQLArrayElement.convertFromPostgreSQLData(psqlData)
39-
array.append(element)
33+
let element = try requirePostgreSQLDataCustomConvertible(PostgreSQLArrayElement.self).convertFromPostgreSQLData(psqlData)
34+
array.append(element as! PostgreSQLArrayElement)
4035
}
4136
} else {
4237
array = []
@@ -48,13 +43,13 @@ extension PostgreSQLArrayCustomConvertible {
4843
/// See `PostgreSQLDataCustomConvertible.convertToPostgreSQLData()`
4944
public func convertToPostgreSQLData() throws -> PostgreSQLData {
5045
let elements = try convertToPostgreSQLArray().map {
51-
try $0.convertToPostgreSQLData()
46+
try requirePostgreSQLDataCustomConvertible($0).convertToPostgreSQLData()
5247
}
5348

5449
var data = Data()
5550
data += Int32(1).data // non-null
5651
data += Int32(0).data // b
57-
data += PostgreSQLArrayElement.postgreSQLDataType.raw.data // type
52+
data += requirePostgreSQLDataCustomConvertible(PostgreSQLArrayElement.self).postgreSQLDataType.raw.data // type
5853
data += Int32(elements.count).data // length
5954
data += Int32(1).data // dimensions
6055

@@ -67,7 +62,7 @@ extension PostgreSQLArrayCustomConvertible {
6762
}
6863
}
6964

70-
return PostgreSQLData(type: PostgreSQLArrayElement.postgreSQLDataArrayType, format: .binary, data: data)
65+
return PostgreSQLData(type: requirePostgreSQLDataCustomConvertible(PostgreSQLArrayElement.self).postgreSQLDataArrayType, format: .binary, data: data)
7166
}
7267
}
7368

@@ -107,10 +102,15 @@ extension PostgreSQLArrayMetadata: CustomStringConvertible {
107102
}
108103
}
109104

110-
extension Array: PostgreSQLArrayCustomConvertible where Element: Codable, Element: PostgreSQLDataCustomConvertible {
105+
extension Array: PostgreSQLArrayCustomConvertible {
111106
/// See `PostgreSQLArrayCustomConvertible.postgreSQLDataArrayType`
112107
public static var postgreSQLDataArrayType: PostgreSQLDataType {
113-
return Element.postgreSQLDataArrayType
108+
fatalError("Multi-dimensional arrays are not yet supported.")
109+
}
110+
111+
/// See `PostgreSQLDataCustomConvertible.postgreSQLDataType`
112+
public static var postgreSQLDataType: PostgreSQLDataType {
113+
return requirePostgreSQLDataCustomConvertible(Element.self).postgreSQLDataArrayType
114114
}
115115

116116
/// See `PostgreSQLArrayCustomConvertible.PostgreSQLArrayElement`
@@ -126,3 +126,17 @@ extension Array: PostgreSQLArrayCustomConvertible where Element: Codable, Elemen
126126
return self
127127
}
128128
}
129+
130+
func requirePostgreSQLDataCustomConvertible<T>(_ type: T.Type) -> PostgreSQLDataCustomConvertible.Type {
131+
guard let custom = T.self as? PostgreSQLDataCustomConvertible.Type else {
132+
fatalError("`\(T.self)` does not conform to `PostgreSQLDataCustomConvertible`")
133+
}
134+
return custom
135+
}
136+
137+
func requirePostgreSQLDataCustomConvertible<T>(_ type: T) -> PostgreSQLDataCustomConvertible {
138+
guard let custom = type as? PostgreSQLDataCustomConvertible else {
139+
fatalError("`\(T.self)` does not conform to `PostgreSQLDataCustomConvertible`")
140+
}
141+
return custom
142+
}
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,32 @@
11
import Async
22
import Foundation
33

4-
extension OptionalType where Self.WrappedType: PostgreSQLDataCustomConvertible {
4+
extension OptionalType {
55
/// See `PostgreSQLDataCustomConvertible.convertFromPostgreSQLData(_:)`
66
public static func convertFromPostgreSQLData(_ data: PostgreSQLData) throws -> Self {
7-
let wrapped = try WrappedType.convertFromPostgreSQLData(data)
8-
return Self.makeOptionalType(wrapped)
7+
let wrapped = try requirePostgreSQLDataCustomConvertible(WrappedType.self).convertFromPostgreSQLData(data)
8+
return Self.makeOptionalType(wrapped as? WrappedType)
99
}
1010

1111
/// See `PostgreSQLDataCustomConvertible.convertToPostgreSQLData()`
1212
public func convertToPostgreSQLData() throws -> PostgreSQLData {
1313
if let wrapped = self.wrapped {
14-
return try wrapped.convertToPostgreSQLData()
14+
return try requirePostgreSQLDataCustomConvertible(wrapped).convertToPostgreSQLData()
1515
} else {
1616
return PostgreSQLData(type: .void, format: .binary, data: nil)
1717
}
1818
}
1919
}
2020

21-
extension Optional: PostgreSQLDataCustomConvertible where Wrapped: PostgreSQLDataCustomConvertible {
21+
extension Optional: PostgreSQLDataCustomConvertible {
2222
/// See `PostgreSQLDataCustomConvertible.postgreSQLDataType`
2323
public static var postgreSQLDataType: PostgreSQLDataType {
24-
return Wrapped.postgreSQLDataType
24+
return requirePostgreSQLDataCustomConvertible(Wrapped.self).postgreSQLDataType
2525
}
2626

2727

2828
/// See `PostgreSQLDataCustomConvertible.postgreSQLDataArrayType`
2929
public static var postgreSQLDataArrayType: PostgreSQLDataType {
30-
return Wrapped.postgreSQLDataArrayType
30+
return requirePostgreSQLDataCustomConvertible(Wrapped.self).postgreSQLDataArrayType
3131
}
3232
}
33-

Sources/PostgreSQL/Data/PostgreSQLJSONCustomConvertible.swift

+38-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import COperatingSystem
22
import Foundation
33

44
/// Representable by a `JSONB` column on the PostgreSQL database.
5-
public protocol PostgreSQLJSONCustomConvertible: PostgreSQLDataCustomConvertible, Codable { }
5+
public protocol PostgreSQLJSONCustomConvertible: PostgreSQLDataCustomConvertible { }
66

77
extension PostgreSQLJSONCustomConvertible {
88
/// See `PostgreSQLDataCustomConvertible.postgreSQLDataType`
@@ -17,22 +17,55 @@ extension PostgreSQLJSONCustomConvertible {
1717
throw PostgreSQLError(identifier: "data", reason: "Unable to decode PostgreSQL JSON from `null` data.", source: .capture())
1818
}
1919

20+
21+
guard let decodable = Self.self as? Decodable.Type else {
22+
fatalError("`\(Self.self)` is not `Decodable`.")
23+
}
24+
2025
switch data.type {
2126
case .jsonb:
2227
switch data.format {
23-
case .text: return try JSONDecoder().decode(Self.self, from: value)
28+
case .text:
29+
let decoder = try JSONDecoder().decode(DecoderUnwrapper.self, from: value).decoder
30+
return try decodable.init(from: decoder) as! Self
2431
case .binary:
2532
assert(value[0] == 0x01)
26-
return try JSONDecoder().decode(Self.self, from: value[1...])
33+
let decoder = try JSONDecoder().decode(DecoderUnwrapper.self, from: value[1...]).decoder
34+
return try decodable.init(from: decoder) as! Self
2735
}
2836
default: throw PostgreSQLError(identifier: "json", reason: "Could not decode \(Self.self) from data type: \(data.type).", source: .capture())
2937
}
3038
}
3139

3240
/// See `PostgreSQLDataCustomConvertible.convertToPostgreSQLData()`
3341
public func convertToPostgreSQLData() throws -> PostgreSQLData {
34-
return try PostgreSQLData(type: .jsonb, format: .text, data: JSONEncoder().encode(self))
42+
guard let encodable = self as? Encodable else {
43+
fatalError("`\(Self.self)` is not `Encodable`.")
44+
}
45+
return try PostgreSQLData(
46+
type: .jsonb,
47+
format: .text,
48+
data: JSONEncoder().encode(EncoderWrapper(encodable))
49+
)
50+
}
51+
}
52+
53+
extension Dictionary: PostgreSQLJSONCustomConvertible { }
54+
55+
fileprivate struct DecoderUnwrapper: Decodable {
56+
let decoder: Decoder
57+
init(from decoder: Decoder) {
58+
self.decoder = decoder
59+
}
60+
}
61+
62+
fileprivate struct EncoderWrapper: Encodable {
63+
var encodable: Encodable
64+
init(_ encodable: Encodable) {
65+
self.encodable = encodable
66+
}
67+
func encode(to encoder: Encoder) throws {
68+
try encodable.encode(to: encoder)
3569
}
3670
}
3771

38-
extension Dictionary: PostgreSQLJSONCustomConvertible where Key: Codable, Value: Codable { }

Tests/PostgreSQLTests/PostgreSQLConnectionTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class PostgreSQLConnectionTests: XCTestCase {
247247
}
248248

249249
func testStruct() throws {
250-
struct Hello: PostgreSQLJSONCustomConvertible {
250+
struct Hello: PostgreSQLJSONCustomConvertible, Codable {
251251
var message: String
252252
}
253253

0 commit comments

Comments
 (0)