Skip to content

Commit 64dbcd1

Browse files
committed
support encoding empty arrays, fixes vapor#80
1 parent c0d2fc7 commit 64dbcd1

7 files changed

+91
-101
lines changed

Sources/PostgreSQL/Codable/PostgreSQLQueryEncoder.swift

-96
This file was deleted.

Sources/PostgreSQL/Codable/PostgreSQLValueEncoder.swift

+27-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,23 @@ public struct PostgreSQLDataEncoder {
2626
if let data = encoder.data {
2727
return data
2828
} else {
29-
let type = encoder.array.first?.type ?? .null
29+
let type: PostgreSQLDataFormat
30+
if let present = encoder.array.first?.type {
31+
type = present
32+
} else if
33+
let array = Swift.type(of: encodable) as? AnyArray.Type,
34+
let psql = array.anyElementType as? PostgreSQLDataTypeStaticRepresentable.Type
35+
{
36+
if let format = psql.postgreSQLDataType.dataFormat {
37+
type = format
38+
} else {
39+
WARNING("Could not determine PostgreSQL array data type: \(psql.postgreSQLDataType)")
40+
type = .null
41+
}
42+
} else {
43+
WARNING("Could not determine PostgreSQL array data type: \(Swift.type(of: encodable))")
44+
type = .null
45+
}
3046
// encode array
3147
var data = Data()
3248
data += Data.of(Int32(1).bigEndian) // non-null
@@ -179,3 +195,13 @@ public struct PostgreSQLDataEncoder {
179195
}
180196
}
181197
}
198+
199+
protocol AnyArray {
200+
static var anyElementType: Any.Type { get }
201+
}
202+
203+
extension Array: AnyArray {
204+
static var anyElementType: Any.Type {
205+
return Element.self
206+
}
207+
}

Sources/PostgreSQL/Column/PostgreSQLDataTypeCode.swift

+24
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,30 @@ extension PostgreSQLDataFormat {
127127
case .float8: return ._float8
128128
case .uuid: return ._uuid
129129
case .jsonb: return ._jsonb
130+
case .text: return ._text
131+
default: return nil
132+
}
133+
}
134+
}
135+
136+
extension PostgreSQLDataType {
137+
internal var dataFormat: PostgreSQLDataFormat? {
138+
switch primitive {
139+
case .bigint, .bigserial: return .int8
140+
case .bit, .char: return .char
141+
case .boolean: return .bool
142+
case .bytea: return .bytea
143+
case .date: return .date
144+
case .doublePrecision: return .float8
145+
case .integer, .serial: return .int4
146+
case .json: return .json
147+
case .jsonb: return .jsonb
148+
case .numeric: return .numeric
149+
case .smallint, .smallserial: return .int2
150+
case .text: return .text
151+
case .time: return .time
152+
case .timestamptz: return .timestamptz
153+
case .uuid: return .uuid
130154
default: return nil
131155
}
132156
}

Sources/PostgreSQL/Data/PostgreSQLData.swift

+9
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ extension PostgreSQLData: CustomStringConvertible {
8888
case .int4: override = data.as(Int32.self, default: 0).bigEndian.description
8989
case .int2: override = data.as(Int16.self, default: 0).bigEndian.description
9090
case .uuid: override = UUID.init(uuid: data.as(uuid_t.self, default: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))).description
91+
case ._text:
92+
let strings = try? PostgreSQLDataDecoder().decode([String].self, from: self)
93+
override = strings?.description
94+
case ._int4:
95+
let ints = try? PostgreSQLDataDecoder().decode([Int32].self, from: self)
96+
override = ints?.description
97+
case ._int8:
98+
let ints = try? PostgreSQLDataDecoder().decode([Int64].self, from: self)
99+
override = ints?.description
91100
default: break
92101
}
93102

Sources/PostgreSQL/SQL/PostgreSQLQuery+DataType.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -338,15 +338,15 @@ public struct PostgreSQLDataType: SQLDataType, Equatable {
338338
return .init(dataType.primitive, isArray: true)
339339
}
340340

341-
private let primitive: Primitive
342-
private let isArray: Bool
341+
let primitive: Primitive
342+
let isArray: Bool
343343

344344
private init(_ primitive: Primitive, isArray: Bool = false) {
345345
self.primitive = primitive
346346
self.isArray = isArray
347347
}
348348

349-
private enum Primitive {
349+
enum Primitive {
350350
/// signed eight-byte integer
351351
case bigint
352352

Sources/PostgreSQL/SQL/PostgreSQLUpsert.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
public struct PostgreSQLUpsert {
1+
public struct PostgreSQLUpsert: SQLSerializable {
22
/// See `SQLUpsert`.
33
public typealias Identifier = PostgreSQLIdentifier
44

Tests/PostgreSQLTests/PostgreSQLConnectionTests.swift

+27
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,32 @@ class PostgreSQLConnectionTests: XCTestCase {
491491
default: XCTFail("invalid row count")
492492
}
493493
}
494+
495+
// https://github.com/vapor/postgresql/issues/80
496+
func testEmptyArray() throws {
497+
do {
498+
var messages: [String] = []
499+
let a = try PostgreSQLDataEncoder().encode(messages)
500+
print(a)
501+
messages.append("hello")
502+
let b = try PostgreSQLDataEncoder().encode(messages)
503+
print(b)
504+
messages.append("world")
505+
let c = try PostgreSQLDataEncoder().encode(messages)
506+
print(c)
507+
}
508+
do {
509+
var messages: [Int] = []
510+
let a = try PostgreSQLDataEncoder().encode(messages)
511+
print(a)
512+
messages.append(42)
513+
let b = try PostgreSQLDataEncoder().encode(messages)
514+
print(b)
515+
messages.append(1337)
516+
let c = try PostgreSQLDataEncoder().encode(messages)
517+
print(c)
518+
}
519+
}
494520

495521
static var allTests = [
496522
("testBenchmark", testBenchmark),
@@ -511,6 +537,7 @@ class PostgreSQLConnectionTests: XCTestCase {
511537
("testSum", testSum),
512538
("testOrderBy", testOrderBy),
513539
("testInvalidDate", testInvalidDate),
540+
("testEmptyArray", testEmptyArray),
514541
]
515542
}
516543

0 commit comments

Comments
 (0)