Skip to content

Commit 3a2f208

Browse files
sendable + general cleanup (linting)
1 parent 3e50cbd commit 3a2f208

15 files changed

+403
-517
lines changed

README.md

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ClickHouseNIO
22

3-
![Swift 5](https://img.shields.io/badge/Swift-5-orange.svg) ![SPM](https://img.shields.io/badge/SPM-compatible-green.svg) ![Platforms](https://img.shields.io/badge/Platforms-macOS%20Linux-green.svg) [![codebeat badge](https://codebeat.co/badges/d15d7e95-d3df-4f97-974c-c3a7d9c07a9e)](https://codebeat.co/projects/github-com-patrick-zippenfenig-clickhousenio-main) [![CircleCI](https://circleci.com/gh/patrick-zippenfenig/ClickHouseNIO/tree/main.svg?style=svg)](https://circleci.com/gh/patrick-zippenfenig/ClickHouseNIO/tree/main)
3+
![Swift 5](https://img.shields.io/badge/Swift-5-orange.svg) ![SPM](https://img.shields.io/badge/SPM-compatible-green.svg) ![Platforms](https://img.shields.io/badge/Platforms-macOS%20Linux-green.svg) [![codebeat badge](https://codebeat.co/badges/d15d7e95-d3df-4f97-974c-c3a7d9c07a9e)](https://codebeat.co/projects/github-com-patrick-zippenfenig-clickhousenio-main) [![CircleCI](https://circleci.com/gh/patrick-zippenfenig/ClickHouseNIO/tree/main.svg?style=svg)](https://circleci.com/gh/patrick-zippenfenig/ClickHouseNIO/tree/main)
44

55
High performance Swift [ClickHouse](https://clickhouse.tech) client based on [SwiftNIO 2](https://github.com/apple/swift-nio). It is inspired by the [ClickHouse source code](https://github.com/ClickHouse/ClickHouse/tree/master/src/Client) (C++), but written in pure Swift.
66

@@ -31,7 +31,7 @@ This client provides raw query capabilities. Connection pooling or relational ab
3131
$ swift build
3232
```
3333

34-
## Usage
34+
## Usage
3535

3636
1. Connect to a ClickHouseServer. The client requires a `eventLoop` which is usually provided by frameworks which use SwiftNIO. We also use `wait()` for simplicity, but it is discouraged for production code.
3737

@@ -40,13 +40,13 @@ import NIO
4040
import ClickHouseNIO
4141

4242
let config = try ClickHouseConfiguration(
43-
hostname: "localhost",
44-
port: 9000,
45-
user: "default",
46-
password: "admin",
43+
hostname: "localhost",
44+
port: 9000,
45+
user: "default",
46+
password: "admin",
4747
database: "default")
48-
49-
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
48+
49+
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
5050
let connection = try ClickHouseConnection.connect(configuration: config, on: eventLoopGroup.next()).wait()
5151
```
5252

@@ -81,7 +81,7 @@ let data = [
8181
try! connection.insert(into: "test", data: data).wait()
8282
````
8383

84-
5. Query data and cast is to the exptected array
84+
5. Query data and cast is to the expected array
8585

8686
```swift
8787
try! conn.connection.query(sql: "SELECT * FROM test").map { res in
@@ -104,10 +104,10 @@ For TLS encrypted connections to the ClickHouse server, a `tlsConfiguration` att
104104
let tls = TLSConfiguration.forClient(certificateVerification: .none)
105105

106106
let config = try ClickHouseConfiguration(
107-
hostname: "localhost",
108-
port: 9440,
109-
user: "default",
110-
password: "admin",
107+
hostname: "localhost",
108+
port: 9440,
109+
user: "default",
110+
password: "admin",
111111
database: "default",
112112
tlsConfiguration: tls)
113113
```
@@ -118,7 +118,7 @@ Because networks unreliable by nature, ClickHouseNIO uses different timeouts to
118118
```swift
119119

120120
let config = try ClickHouseConfiguration(
121-
hostname: "localhost",
121+
hostname: "localhost",
122122
...,
123123
connectTimeout: .seconds(10),
124124
readTimeout: .seconds(90),
@@ -127,9 +127,9 @@ let config = try ClickHouseConfiguration(
127127
```
128128

129129
All timeouts will close the connection. Different timeouts trigger different exceptions:
130-
- `connectTimeout` will throw `NIO.ChannelError.connectTimeout(TimeAmount)` if the connection to the ClickHouse server cannot be establised after this period of time.
131-
- `readTimeout`: If a query is running, and the ClickHouseNIO client does not receive any network package, the conncection is closed and throws `ClickHouseError.readTimeout`. This can happen, if the network connection is interrupted while waiting for a response. Usually, even while waiting for a query result, packages are exchanged very frequently.
132-
- `queryTimeout` is the total time after a query will be terminated and the connection is closed. Because ClickHouseNIO is also capable of queueing queries, this includes the time in the queue as well. On a very busy server, a long waiting time starts to close connections. If a connection is closed, all queries in the queue will return a failed future with the exception `ClickHouseError.queryTimeout`.
130+
- `connectTimeout` will throw `NIO.ChannelError.connectTimeout(TimeAmount)` if the connection to the ClickHouse server cannot be established after this period of time.
131+
- `readTimeout`: If a query is running, and the ClickHouseNIO client does not receive any network package, the connection is closed and throws `ClickHouseError.readTimeout`. This can happen, if the network connection is interrupted while waiting for a response. Usually, even while waiting for a query result, packages are exchanged very frequently.
132+
- `queryTimeout` is the total time after a query will be terminated and the connection is closed. Because ClickHouseNIO is also capable of queueing queries, this includes the time in the queue as well. On a very busy server, a long waiting time starts to close connections. If a connection is closed, all queries in the queue will return a failed future with the exception `ClickHouseError.queryTimeout`.
133133

134134
Timeouts can also be specified for a single query with `connection.command(sql: sql, timeout: .seconds(30))`, but keep in mind that this also includes queue time.
135135

Sources/ClickHouseNIO/ByteBufferExtensions.swift

+38-39
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extension ByteBuffer {
1313
mutating func writeClickHouseString(_ string: String) {
1414
// We have to access the buffer here directly, because we need to know the byte length
1515
if let written = string.utf8.withContiguousStorageIfAvailable({ utf8Bytes -> Int in
16-
// If it is a continous UTF8 string
16+
// If it is a continuous UTF8 string
1717
writeVarInt64(UInt64(utf8Bytes.count))
1818
return self.setBytes(utf8Bytes, at: writerIndex)
1919
}) {
@@ -27,50 +27,49 @@ extension ByteBuffer {
2727
}
2828
moveWriterIndex(forwardBy: written)
2929
}
30-
30+
3131
/// Write a string with a fixed length. Returns the number of bytes written.
3232
@discardableResult
3333
@inlinable
3434
public mutating func setString(_ string: String, at index: Int, maxLength length: Int) -> Int {
3535
if let written = string.utf8.withContiguousStorageIfAvailable({ utf8Bytes in
36-
// If it is a continous UTF8 string
36+
// If it is a continuous UTF8 string
3737
self.setBytes(utf8Bytes.prefix(length), at: writerIndex)
3838
}) {
3939
return written
4040
}
4141
var string = string
42-
let written = string.withUTF8 {
42+
return string.withUTF8 {
4343
self.setBytes($0.prefix(length), at: writerIndex)
4444
}
45-
return written
4645
}
47-
46+
4847
/// Write a fixed string and zero padd in case the string is too short
4948
mutating func writeClickHouseFixedString(_ string: String, length: Int) {
50-
// Carefull, needs to work with UTF8
49+
// Careful, needs to work with UTF8
5150
let written = setString(string, at: writerIndex, maxLength: length)
5251
if written < length {
5352
setRepeatingByte(0, count: length - written, at: writerIndex + written)
5453
}
5554
self.moveWriterIndex(forwardBy: length)
5655
}
57-
56+
5857
mutating func writeClickHouseStrings(_ strings: [String]) {
59-
let stringLen = strings.reduce(0, {$0 + $1.count})
58+
let stringLen = strings.reduce(0, { $0 + $1.count })
6059
let offsetLen = strings.count * MemoryLayout<Int>.size
6160
reserveCapacity(writableBytes + stringLen + offsetLen)
6261
for string in strings {
6362
writeClickHouseString(string)
6463
}
6564
}
66-
65+
6766
mutating func writeClickHouseFixedStrings(_ strings: [String], length: Int) {
6867
reserveCapacity(writableBytes + length * strings.count)
6968
for string in strings {
7069
writeClickHouseFixedString(string, length: length)
7170
}
7271
}
73-
72+
7473
mutating func readClickHouseString() -> String? {
7574
guard let length = readVarInt64() else {
7675
return nil
@@ -84,41 +83,41 @@ extension ByteBuffer {
8483
}
8584
return readString(length: Int(length))
8685
}
87-
86+
8887
/// Fancy click house coding...
8988
mutating func writeVarInt64(_ frm: UInt64) {
9089
var value = frm
9190
var byte: UInt8 = 0
9291
for _ in 0...8 {
9392
byte = UInt8(value & 0x7F)
94-
if (value > 0x7F) {
93+
if value > 0x7F {
9594
byte |= 0x80
9695
}
9796
writeInteger(byte)
9897
value >>= 7
99-
if (value == 0) {
98+
if value == 0 {
10099
break
101100
}
102101
}
103102
}
104-
103+
105104
mutating func readVarInt64() -> UInt64? {
106105
var value: UInt64 = 0
107106
for i: UInt8 in 0...8 {
108107
guard let byte: UInt8 = readInteger() else {
109108
return nil
110109
}
111110
value |= UInt64(byte & 0x7F) << UInt64(7 * i)
112-
if ((byte & 0x80) == 0) {
111+
if (byte & 0x80) == 0 {
113112
return value
114113
}
115114
}
116115
return nil
117116
}
118-
117+
119118
mutating func readClickHouseStrings(numRows: Int) -> [String]? {
120119
// TODO calculate the required bytes more efficiently
121-
120+
122121
var strings = [String]()
123122
strings.reserveCapacity(numRows)
124123
for _ in 0..<numRows {
@@ -129,7 +128,7 @@ extension ByteBuffer {
129128
}
130129
return strings
131130
}
132-
131+
133132
mutating func readIntegerArray<T: FixedWidthInteger>(numRows: Int) -> [T]? {
134133
guard readableBytes >= MemoryLayout<T>.size * numRows else {
135134
return nil
@@ -144,56 +143,54 @@ extension ByteBuffer {
144143
}
145144
return array
146145
}
147-
146+
148147
mutating func readOptionalIntegerArray<T: FixedWidthInteger>(numRows: Int) -> [T?]? {
149-
guard readableBytes >= (MemoryLayout<T>.size+1) * numRows else {
148+
guard readableBytes >= (MemoryLayout<T>.size + 1) * numRows else {
150149
return nil
151150
}
152-
var isnull = [Bool]()
153-
isnull.reserveCapacity(numRows)
151+
var isNull = [Bool]()
152+
isNull.reserveCapacity(numRows)
154153
for _ in 0..<numRows {
155154
guard let set: UInt8 = readInteger(endianness: .little) else {
156155
return nil
157156
}
158-
isnull.append(set == 1)
157+
isNull.append(set == 1)
159158
}
160-
159+
161160
var array = [T?]()
162161
array.reserveCapacity(numRows)
163162
for i in 0..<numRows {
164163
guard let value: T = readInteger(endianness: .little) else {
165164
return nil
166165
}
167-
if isnull[i] {
166+
if isNull[i] {
168167
array.append(nil)
169168
} else {
170169
array.append(value)
171170
}
172171
}
173172
return array
174173
}
175-
174+
176175
mutating func readUuidArray(numRows: Int, endianness: Endianness = .big) -> [UUID]? {
177176
guard readableBytes >= MemoryLayout<UUID>.size * numRows else {
178177
return nil
179178
}
180179
return [UUID](unsafeUninitializedCapacity: numRows) { (buffer, initializedCount) in
181-
let numBytes = readableBytesView.withUnsafeBytes({ $0.copyBytes(to: buffer)})
180+
let numBytes = readableBytesView.withUnsafeBytes({ $0.copyBytes(to: buffer) })
182181
assert(numBytes / MemoryLayout<UUID>.size == numRows)
183182
moveReaderIndex(forwardBy: numBytes)
184183
if endianness == .little {
185-
for (i,e) in buffer.enumerated() {
184+
for (i, e) in buffer.enumerated() {
186185
buffer[i] = e.swapBytes()
187186
}
188187
}
189188
initializedCount = numRows
190189
}
191190
}
192-
193-
/**
194-
Read bytes as a specific array type. The data type should be continuously stored in memory. E.g. Does not work with strings
195-
TODO: Ensure that this works for all types... endians might also be an issue
196-
*/
191+
192+
/// Read bytes as a specific array type. The data type should be continuously stored in memory. E.g. Does not work with strings
193+
/// TODO: Ensure that this works for all types... endians might also be an issue
197194
mutating func readUnsafeGenericArray<T>(numRows: Int) -> [T]? {
198195
guard readableBytes >= MemoryLayout<T>.size * numRows else {
199196
return nil
@@ -207,14 +204,14 @@ extension ByteBuffer {
207204
initializedCount = numRows
208205
}
209206
}
210-
207+
211208
mutating func writeIntegerArray<T: FixedWidthInteger>(_ array: [T]) {
212209
reserveCapacity(array.count * MemoryLayout<T>.size + writableBytes)
213210
for element in array {
214211
writeInteger(element, endianness: .little)
215212
}
216213
}
217-
214+
218215
mutating func writeOptionalIntegerArray<T: FixedWidthInteger>(_ array: [T?]) {
219216
reserveCapacity(array.count * (MemoryLayout<T>.size + 1) + writableBytes)
220217
// Frist write one array with 0/1 for nullable, then data
@@ -233,7 +230,7 @@ extension ByteBuffer {
233230
}
234231
}
235232
}
236-
233+
237234
/// Write UUID array for clickhouse
238235
mutating func writeUuidArray(_ array: [UUID], endianness: Endianness = .big) {
239236
reserveCapacity(array.count * MemoryLayout<UUID>.size + writableBytes)
@@ -256,8 +253,10 @@ extension UUID {
256253
/// Swap bytes before sending to clickhouse and after retrieval
257254
fileprivate func swapBytes() -> UUID {
258255
let bytes = self.uuid
259-
let b = (bytes.7, bytes.6, bytes.5, bytes.4, bytes.3, bytes.2, bytes.1, bytes.0,
260-
bytes.15, bytes.14, bytes.13, bytes.12, bytes.11, bytes.10, bytes.9, bytes.8)
256+
let b = (
257+
bytes.7, bytes.6, bytes.5, bytes.4, bytes.3, bytes.2, bytes.1, bytes.0,
258+
bytes.15, bytes.14, bytes.13, bytes.12, bytes.11, bytes.10, bytes.9, bytes.8
259+
)
261260
return UUID(uuid: b)
262261
}
263262
}

0 commit comments

Comments
 (0)