Skip to content

Commit 859ff81

Browse files
committed
string numeric support
1 parent 7b3b23a commit 859ff81

12 files changed

+97
-98
lines changed

Sources/PostgreSQL/Base/PostgreSQLData.swift

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@ public enum PostgreSQLData {
66
case data(Data)
77
case date(Date)
88

9+
case bool(Bool)
10+
911
case int8(Int8)
1012
case int16(Int16)
1113
case int32(Int32)
1214
case int64(Int64)
1315

14-
case uint8(UInt8)
15-
case uint16(UInt16)
16-
case uint32(UInt32)
17-
case uint64(UInt64)
18-
1916
case float(Float)
2017
case double(Double)
2118

@@ -44,12 +41,6 @@ extension PostgreSQLData {
4441
case .int64(let i):
4542
guard i <= Int64(Int.max) else { return nil }
4643
return Int(i)
47-
case .uint8(let ui): return Int(ui)
48-
case .uint16(let ui): return Int(ui)
49-
case .uint32(let ui): return Int(ui)
50-
case .uint64(let ui):
51-
guard ui <= UInt64(Int.max) else { return nil }
52-
return Int(ui)
5344
case .string(let s): return Int(s)
5445
default: return nil
5546
}
@@ -88,10 +79,6 @@ extension PostgreSQLData: Equatable {
8879
case (.int16(let a), .int16(let b)): return a == b
8980
case (.int32(let a), .int32(let b)): return a == b
9081
case (.int64(let a), .int64(let b)): return a == b
91-
case (.uint8(let a), .uint8(let b)): return a == b
92-
case (.uint16(let a), .uint16(let b)): return a == b
93-
case (.uint32(let a), .uint32(let b)): return a == b
94-
case (.uint64(let a), .uint64(let b)): return a == b
9582
case (.float(let a), .float(let b)): return a == b
9683
case (.double(let a), .double(let b)): return a == b
9784
case (.point(let a), .point(let b)): return a == b
@@ -116,13 +103,10 @@ extension PostgreSQLData: CustomStringConvertible {
116103
case .int16(let val): return "\(val) (int16)"
117104
case .int32(let val): return "\(val) (int32)"
118105
case .int64(let val): return "\(val) (int64)"
119-
case .uint8(let val): return "\(val) (uint8)"
120-
case .uint16(let val): return "\(val) (uint16)"
121-
case .uint32(let val): return "\(val) (uint32)"
122-
case .uint64(let val): return "\(val) (uint64)"
123106
case .float(let val): return "\(val) (float)"
124107
case .double(let val): return "\(val) (double)"
125108
case .point(let x, let y): return "(\(x), \(y))"
109+
case .bool(let bool): return bool.description
126110
case .null: return "null"
127111
}
128112
}

Sources/PostgreSQL/Base/PostgreSQLDataType+Parse.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ extension PostgreSQLDataType {
1616
case .int8: return .int64(data.makeFixedWidthInteger())
1717
case .oid, .regproc, .int4: return .int32(data.makeFixedWidthInteger())
1818
case .int2: return .int16(data.makeFixedWidthInteger())
19-
case .bool, .char: return .uint8(data.makeFixedWidthInteger())
19+
case .bool, .char: return .int8(data.makeFixedWidthInteger())
2020
case .bytea: return .data(data)
2121
case .void: return .null
2222
case .float4: return .float(data.makeFloatingPoint())
@@ -31,14 +31,14 @@ extension PostgreSQLDataType {
3131
/// Parses this column to the specified data type assuming text format.
3232
private func parseText(from data: Data) throws -> PostgreSQLData {
3333
switch self {
34-
case .bool: return try .uint8(data.makeString() == "t" ? 1 : 0)
35-
case .text, .name, .varchar, .bpchar: return try .string(data.makeString())
34+
case .bool: return try .int8(data.makeString() == "t" ? 1 : 0)
35+
case .text, .name, .varchar, .bpchar,.numeric: return try .string(data.makeString())
3636
case .int8: return try Int64(data.makeString()).flatMap { .int64($0) } ?? .null
3737
case .oid, .regproc, .int4: return try Int32(data.makeString()).flatMap { .int32($0) } ?? .null
3838
case .int2: return try Int16(data.makeString()).flatMap { .int16($0) } ?? .null
39-
case .char: return .uint8(data[0])
39+
case .char: return .int8(Int8(bitPattern: data[0]))
4040
case .float4: return try Float(data.makeString()).flatMap { .float($0) } ?? .null
41-
case .numeric, .float8: return try Double(data.makeString()).flatMap { .double($0) } ?? .null
41+
case .float8: return try Double(data.makeString()).flatMap { .double($0) } ?? .null
4242
case .bytea: return try .data(Data(hexString: data[2...].makeString()))
4343
case .timestamp: return try .date(data.makeString().parseDate(format: "yyyy-MM-dd HH:mm:ss"))
4444
case .date: return try .date(data.makeString().parseDate(format: "yyyy-MM-dd"))

Sources/PostgreSQL/Base/PostgreSQLDataType+Serialize.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ extension PostgreSQLData {
1414
let serialized: Data?
1515
switch self {
1616
case .date(let date): serialized = Data(date.description.utf8)
17-
case .string, .null, .int8, .int16, .int32, .int64, .uint8, .uint16, .uint32, .uint64, .double, .float, .data, .point:
17+
case .string, .null, .int8, .int16, .int32, .int64, .double, .float, .data, .point, .bool:
1818
fatalError("Unsupported serialize text: \(self)")
1919
}
2020
return serialized
@@ -30,14 +30,13 @@ extension PostgreSQLData {
3030
case .int16(let int): serialized = Data(int.bytes)
3131
case .int32(let int): serialized = Data(int.bytes)
3232
case .int64(let int): serialized = Data(int.bytes)
33-
case .uint8(let int): serialized = Data(int.bytes)
34-
case .uint16(let int): serialized = Data(int.bytes)
35-
case .uint32(let int): serialized = Data(int.bytes)
36-
case .uint64(let int): serialized = Data(int.bytes)
3733
case .double(let double): serialized = Data(double.bytes)
3834
case .float(let float): serialized = Data(float.bytes)
3935
case .data(let data): serialized = data
4036
case .point(let x, let y): serialized = Data(x.bytes) + Data(y.bytes)
37+
case .bool(let bool):
38+
let int: Int8 = bool ? 1 : 0
39+
serialized = Data(int.bytes)
4140
case .date:
4241
fatalError("Unsupported serialize binary: \(self)")
4342
}

Sources/PostgreSQL/Base/PostgreSQLDataType.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,13 @@ extension PostgreSQLDataType {
3131
/// Converts the supplied `PostgreSQLData` to the best matching `PostgreSQLDataType`
3232
static func type(forData data: PostgreSQLData) -> PostgreSQLDataType {
3333
switch data {
34+
case .bool: return .bool
3435
case .int8: return .char
3536
case .int16: return .int2
3637
case .int32: return .int4
3738
case .int64: return .int8
38-
case .uint64: return .int8
39-
case .uint8: return .bool
40-
case .uint16: return .int2
41-
case .uint32: return .int4
4239
case .null: return .void
43-
case .string: return .varchar
40+
case .string: return .text
4441
case .double: return .float8
4542
case .float: return .float4
4643
case .data: return .bytea

Sources/PostgreSQL/Base/PostgreSQLMessage.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import Bits
33
/// A frontend or backend PostgreSQL message.
44
enum PostgreSQLMessage {
55
case startupMessage(PostgreSQLStartupMessage)
6-
case errorResponse(PostgreSQLErrorResponse)
6+
/// Identifies the message as an error.
7+
case error(PostgreSQLDiagnosticResponse)
8+
/// Identifies the message as a notice.
9+
case notice(PostgreSQLDiagnosticResponse)
710
case authenticationRequest(PostgreSQLAuthenticationRequest)
811
case parameterStatus(PostgreSQLParameterStatus)
912
case backendKeyData(PostgreSQLBackendKeyData)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Async
2+
3+
extension PostgreSQLClient {
4+
/// Authenticates the `PostgreSQLClient` using a username with no password.
5+
public func authenticate(username: String) -> Future<Void> {
6+
let startup = PostgreSQLStartupMessage.versionThree(parameters: ["user": username])
7+
return send([.startupMessage(startup)]).transform(to: ())
8+
}
9+
}

Sources/PostgreSQL/Client/PostgreSQLClient+ParamaterizedQuery.swift

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,14 @@ extension PostgreSQLClient {
2929
let describe = PostgreSQLDescribeRequest(type: .statement, name: "")
3030
var currentRow: PostgreSQLRowDescription?
3131
var currentParameters: PostgreSQLParameterDescription?
32-
return queueStream.enqueue([
32+
return send([
3333
.parse(parse), .describe(describe), .sync
3434
]) { message in
3535
switch message {
36-
case .errorResponse(let e): throw e
37-
case .parseComplete: return false
38-
case .rowDescription(let row):
39-
currentRow = row
40-
return false
41-
case .parameterDescription(let parameters):
42-
currentParameters = parameters
43-
return false
44-
case .noData: return false
45-
case .readyForQuery: return true
36+
case .parseComplete: break
37+
case .rowDescription(let row): currentRow = row
38+
case .parameterDescription(let parameters): currentParameters = parameters
39+
case .noData: break
4640
default: fatalError("Unexpected message during PostgreSQLParseRequest: \(message)")
4741
}
4842
}.flatMap(to: Void.self) {
@@ -63,20 +57,17 @@ extension PostgreSQLClient {
6357
portalName: "",
6458
maxRows: 0
6559
)
66-
return self.queueStream.enqueue([
60+
return self.send([
6761
.bind(bind), .execute(execute), .sync
6862
]) { message in
6963
switch message {
70-
case .errorResponse(let e): throw e
71-
case .bindComplete: return false
64+
case .bindComplete: break
7265
case .dataRow(let data):
7366
let row = currentRow !! "Unexpected PostgreSQLDataRow without preceding PostgreSQLRowDescription."
7467
let parsed = try row.parse(data: data, formats: _resultFormats)
7568
onRow(parsed)
76-
return false
77-
case .close: return false
78-
case .noData: return false
79-
case .readyForQuery: return true
69+
case .close: break
70+
case .noData: break
8071
default: fatalError("Unexpected message during PostgreSQLParseRequest: \(message)")
8172
}
8273
}

Sources/PostgreSQL/Client/PostgreSQLClient+Query.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ extension PostgreSQLClient {
66
var rows: [[String: PostgreSQLData]] = []
77
return query(string) { row in
88
rows.append(row)
9-
}.map(to: [[String: PostgreSQLData]].self) {
10-
return rows
9+
}.map(to: [[String: PostgreSQLData]].self) {
10+
return rows
1111
}
1212
}
1313

@@ -16,7 +16,7 @@ extension PostgreSQLClient {
1616
public func query(_ string: String, onRow: @escaping ([String: PostgreSQLData]) -> ()) -> Future<Void> {
1717
var currentRow: PostgreSQLRowDescription?
1818
let query = PostgreSQLQuery(query: string)
19-
return queueStream.enqueue([.query(query)]) { message in
19+
return send([.query(query)]) { message in
2020
switch message {
2121
case .rowDescription(let row):
2222
currentRow = row
@@ -25,11 +25,8 @@ extension PostgreSQLClient {
2525
let parsed = try row.parse(data: data, formats: row.fields.map { $0.formatCode })
2626
onRow(parsed)
2727
case .close: break // query over, waiting for `readyForQuery`
28-
case .readyForQuery: return true
29-
case .errorResponse(let e): throw e
3028
default: fatalError("Unexpected message during PostgreSQLQuery: \(message)")
3129
}
32-
return false // more messages, please
3330
}
3431
}
3532
}

Sources/PostgreSQL/Client/PostgreSQLClient.swift

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Async
33
/// A PostgreSQL frontend client.
44
public final class PostgreSQLClient {
55
/// Handles enqueued redis commands and responses.
6-
internal let queueStream: AsymmetricQueueStream<PostgreSQLMessage, PostgreSQLMessage>
6+
private let queueStream: AsymmetricQueueStream<PostgreSQLMessage, PostgreSQLMessage>
77

88
/// Creates a new Redis client on the provided data source and sink.
99
init<Stream>(stream: Stream, on worker: Worker) where Stream: ByteStream {
@@ -21,24 +21,29 @@ public final class PostgreSQLClient {
2121
}
2222

2323
/// Sends `PostgreSQLMessage` to the server.
24-
func send(_ message: PostgreSQLMessage) -> Future<[PostgreSQLMessage]> {
25-
var responses: [PostgreSQLMessage] = []
26-
return queueStream.enqueue([message]) { message in
27-
responses.append(message)
24+
func send(_ message: [PostgreSQLMessage], onResponse: @escaping (PostgreSQLMessage) throws -> ()) -> Future<Void> {
25+
return queueStream.enqueue(message) { message in
2826
switch message {
2927
case .readyForQuery: return true
30-
case .errorResponse(let e): throw e
31-
default: return false
28+
case .error(let e): throw e
29+
case .notice(let n):
30+
print(n)
31+
return false
32+
default:
33+
try onResponse(message)
34+
return false // request until ready for query
3235
}
33-
}.map(to: [PostgreSQLMessage].self) {
34-
return responses
3536
}
3637
}
3738

38-
/// Authenticates the `PostgreSQLClient` using a username with no password.
39-
public func authenticate(username: String) -> Future<Void> {
40-
let startup = PostgreSQLStartupMessage.versionThree(parameters: ["user": username])
41-
return send(.startupMessage(startup)).transform(to: ())
39+
/// Sends `PostgreSQLMessage` to the server.
40+
func send(_ message: [PostgreSQLMessage]) -> Future<[PostgreSQLMessage]> {
41+
var responses: [PostgreSQLMessage] = []
42+
return send(message) { response in
43+
responses.append(response)
44+
}.map(to: [PostgreSQLMessage].self) {
45+
return responses
46+
}
4247
}
4348
}
4449

Sources/PostgreSQL/Coders/PostgreSQLMessageDecoder.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ final class PostgreSQLMessageDecoder {
2020

2121
let message: PostgreSQLMessage
2222
switch type {
23-
case .E: message = try .errorResponse(decoder.decode())
23+
case .E: message = try .error(decoder.decode())
24+
case .N: message = try .notice(decoder.decode())
2425
case .R: message = try .authenticationRequest(decoder.decode())
2526
case .S: message = try .parameterStatus(decoder.decode())
2627
case .K: message = try .backendKeyData(decoder.decode())

0 commit comments

Comments
 (0)