|
1 | 1 | # Swift Cassandra Client |
2 | 2 |
|
3 | | -CassandraClient is a Cassandra client in Swift. The client is based on [Datastax Cassandra C++ Driver](https://github.com/datastax/cpp-driver) wrapping it with Swift friendly APIs and data structures. |
| 3 | +CassandraClient is a Cassandra client in Swift. The client is based on [DataStax Cassandra C++ Driver](https://github.com/datastax/cpp-driver), |
| 4 | +wrapping it with Swift friendly APIs and data structures. |
4 | 5 |
|
5 | | -CassandraClient API currently exposes [SwiftNIO](https://github.com/apple/swift-nio) based futures to simplify integration with SwiftNIO based servers. Swift concurrency based API is also available in Swift 5.5 and newer. |
| 6 | +CassandraClient API currently exposes [SwiftNIO](https://github.com/apple/swift-nio) based futures to |
| 7 | +simplify integration with SwiftNIO based servers. Swift concurrency based API is also available in Swift 5.5 and newer. |
6 | 8 |
|
7 | 9 | ## Usage |
8 | 10 |
|
| 11 | +### Swift concurrency based API |
| 12 | + |
9 | 13 | #### Creating a client instance |
10 | 14 |
|
11 | 15 | ```swift |
12 | | - let configuration = CassandraClient.Configuration(...) |
13 | | - let cassandraClient = CassandraClient(configuration: configuration) |
| 16 | +var configuration = CassandraClient.Configuration(...) |
| 17 | +let cassandraClient = CassandraClient(configuration: configuration) |
14 | 18 | ``` |
15 | 19 |
|
16 | | -The client has a default session established (lazily) so that it can be used directly to perform queries on the configured keyspace: |
| 20 | +The client has a default session established (lazily) so that it can be used directly to perform |
| 21 | +queries on the configured keyspace: |
17 | 22 |
|
18 | 23 | ```swift |
19 | | - cassandraClient.query(...) |
| 24 | +let result = try await cassandraClient.query(...) |
20 | 25 | ``` |
21 | 26 |
|
22 | | -The client must be explicitly shut down when no longer needed. |
| 27 | +The client must be explicitly shut down when no longer needed: |
23 | 28 |
|
24 | 29 | ```swift |
25 | | - cassandraClient.shutdown() |
| 30 | +try cassandraClient.shutdown() |
26 | 31 | ``` |
27 | 32 |
|
28 | 33 | #### Creating a session for a different keyspace |
29 | 34 |
|
30 | 35 | ```swift |
31 | | - let session = cassandraClient.makeSession(keyspace: "the_keyspace") |
32 | | - session.query(...) |
| 36 | +let session = cassandraClient.makeSession(keyspace: <KEYSPACE>) |
| 37 | +let result = try await session.query(...) |
33 | 38 | ``` |
34 | 39 |
|
35 | | -The session must be explicitly shut down when no longer needed. |
| 40 | +The session must be explicitly shut down when no longer needed: |
36 | 41 |
|
37 | 42 | ```swift |
38 | | - session.shutdown() |
| 43 | +try session.shutdown() |
39 | 44 | ``` |
40 | 45 |
|
41 | | -You can also create a session and pass in a closure, which will automatically release the resource when the closure exists: |
| 46 | +You can also create a session and pass in a closure, which will automatically release the resource when the closure exits: |
42 | 47 |
|
43 | 48 | ```swift |
44 | | - cassandraClient.withSession(keyspace: "<keyspace>") { session in |
45 | | - session.query(...) |
46 | | - } |
| 49 | +try await cassandraClient.withSession(keyspace: <KEYSPACE>) { session in |
| 50 | + ... |
| 51 | +} |
47 | 52 | ``` |
48 | 53 |
|
49 | | -#### Running result-less commands, e.g. insert, update, delete or DDL |
| 54 | +#### Running result-less commands (e.g. insert, update, delete or DDL) |
50 | 55 |
|
51 | 56 | ```swift |
52 | | - cassandraClient.run("create table ...") |
| 57 | +try await cassandraClient.run("create table ...") |
53 | 58 | ``` |
54 | 59 |
|
55 | | -Or at a session level |
| 60 | +Or at session level: |
56 | 61 |
|
57 | 62 | ```swift |
58 | | - session.run("create table ...") |
| 63 | +try await session.run("create table ...") |
59 | 64 | ``` |
60 | 65 |
|
61 | | -#### Running queries returning small data-sets that fit in-memory |
| 66 | +#### Running queries returning small datasets that fit in memory |
62 | 67 |
|
63 | | -Returning a model object, having `Model: Codable` |
| 68 | +Returning a model object, having `Model: Codable`: |
64 | 69 |
|
65 | 70 | ```swift |
66 | | - cassandraClient.query("select * from table ...").map { (result: [Model]) in |
67 | | - ... |
68 | | - } |
69 | | - |
70 | | - let result: [Model] = try await cassandraClient.query("select * from table ...") |
| 71 | +let result: [Model] = try await cassandraClient.query("select * from table ...") |
71 | 72 | ``` |
72 | 73 |
|
73 | 74 | ```swift |
74 | | - session.query("select * from table ...").map { (result: [Model]) in |
75 | | - ... |
76 | | - } |
| 75 | +let result: [Model] = try await session.query("select * from table ...") |
| 76 | +``` |
77 | 77 |
|
78 | | - let result: [Model] = try await session.query("select * from table ...") |
| 78 | +Or using free-form transformations on the row: |
| 79 | + |
| 80 | +```swift |
| 81 | +let values = try await cassandraClient.query("select * from table ...") { row in |
| 82 | + row.column(<COLUMN_NAME>).int32 |
| 83 | +} |
79 | 84 | ``` |
80 | 85 |
|
81 | | -Or using free-form transformations on the row |
| 86 | +```swift |
| 87 | +let values = try await session.query("select * from table ...") { row in |
| 88 | + row.column(<COLUMN_NAME>).int32 |
| 89 | +} |
| 90 | +``` |
| 91 | + |
| 92 | +#### Running queries returning large datasets that do not fit in memory |
82 | 93 |
|
83 | 94 | ```swift |
84 | | - cassandraClient.query("select * from table ...") { row in |
85 | | - row.column("column_name").int32 |
86 | | - }.map { value in |
87 | | - ... |
88 | | - } |
| 95 | +// `rows` is a sequence that one needs to iterate on |
| 96 | +let rows: Rows = try await cassandraClient.query("select * from table ...") |
89 | 97 | ``` |
90 | 98 |
|
91 | 99 | ```swift |
92 | | - session.query("select * from table ...") { row in |
93 | | - row.column("column_name").int32 |
94 | | - }.map { value in |
95 | | - ... |
96 | | - } |
| 100 | +// `rows` is a sequence that one needs to iterate on |
| 101 | +let rows: Rows = try await session.query("select * from table ...") |
| 102 | +``` |
| 103 | + |
| 104 | +### SwiftNIO future based API |
| 105 | + |
| 106 | +#### Creating a client instance |
| 107 | + |
| 108 | +```swift |
| 109 | +var configuration = CassandraClient.Configuration(...) |
| 110 | +let cassandraClient = CassandraClient(configuration: configuration) |
| 111 | +``` |
| 112 | + |
| 113 | +The client has a default session established (lazily) so that it can be used directly to perform |
| 114 | +queries on the configured keyspace: |
| 115 | + |
| 116 | +```swift |
| 117 | +let resultFuture = cassandraClient.query(...) |
| 118 | +``` |
| 119 | + |
| 120 | +The client must be explicitly shut down when no longer needed: |
| 121 | + |
| 122 | +```swift |
| 123 | +try cassandraClient.shutdown() |
| 124 | +``` |
| 125 | + |
| 126 | +#### Creating a session for a different keyspace |
| 127 | + |
| 128 | +```swift |
| 129 | +let session = cassandraClient.makeSession(keyspace: <KEYSPACE>) |
| 130 | +let resultFuture = session.query(...) |
| 131 | +``` |
| 132 | + |
| 133 | +The session must be explicitly shut down when no longer needed: |
| 134 | + |
| 135 | +```swift |
| 136 | +try session.shutdown() |
| 137 | +``` |
| 138 | + |
| 139 | +You can also create a session and pass in a closure, which will automatically release the resource when the closure exits: |
| 140 | + |
| 141 | +```swift |
| 142 | +try cassandraClient.withSession(keyspace: <KEYSPACE>) { session in |
| 143 | + ... |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | +#### Running result-less commands (e.g. insert, update, delete or DDL) |
| 148 | + |
| 149 | +```swift |
| 150 | +let voidFuture = cassandraClient.run("create table ...") |
| 151 | +``` |
| 152 | + |
| 153 | +Or at session level: |
| 154 | + |
| 155 | +```swift |
| 156 | +let voidFuture = session.run("create table ...") |
97 | 157 | ``` |
98 | 158 |
|
99 | | -#### Running queries returning large data-sets that do not fit in-memory |
| 159 | +#### Running queries returning small datasets that fit in memory |
| 160 | + |
| 161 | +Returning a model object, having `Model: Codable`: |
100 | 162 |
|
101 | 163 | ```swift |
102 | | - cassandraClient.query("select * from table ...").map { (rows: Rows) in |
103 | | - // rows is a sequence that one needs to iterate on |
104 | | - rows.map { row in |
105 | | - ... |
106 | | - } |
| 164 | +cassandraClient.query("select * from table ...").map { result: [Model] in |
| 165 | + ... |
| 166 | +} |
| 167 | +``` |
| 168 | + |
| 169 | +```swift |
| 170 | +session.query("select * from table ...").map { result: [Model] in |
| 171 | + ... |
| 172 | +} |
| 173 | +``` |
| 174 | + |
| 175 | +Or using free-form transformations on the row: |
| 176 | + |
| 177 | +```swift |
| 178 | +cassandraClient.query("select * from table ...") { row in |
| 179 | + row.column(<COLUMN_NAME>).int32 |
| 180 | +}.map { value in |
| 181 | + ... |
| 182 | +} |
| 183 | +``` |
| 184 | + |
| 185 | +```swift |
| 186 | +session.query("select * from table ...") { row in |
| 187 | + row.column(<COLUMN_NAME>).int32 |
| 188 | +}.map { value in |
| 189 | + ... |
| 190 | +} |
| 191 | +``` |
| 192 | + |
| 193 | +#### Running queries returning large datasets that do not fit in memory |
| 194 | + |
| 195 | +```swift |
| 196 | +cassandraClient.query("select * from table ...").map { rows: Rows in |
| 197 | + // `rows` is a sequence that one needs to iterate on |
| 198 | + rows.map { row in |
| 199 | + ... |
107 | 200 | } |
| 201 | +} |
108 | 202 | ``` |
109 | 203 |
|
110 | 204 | ```swift |
111 | | - session.query("select * from table ...").map { (rows: Rows) in |
112 | | - // rows is a sequence that one needs to iterate on |
113 | | - rows.map { row in |
114 | | - ... |
115 | | - } |
| 205 | +session.query("select * from table ...").map { rows: Rows in |
| 206 | + // `rows` is a sequence that one needs to iterate on |
| 207 | + rows.map { row in |
| 208 | + ... |
116 | 209 | } |
| 210 | +} |
117 | 211 | ``` |
118 | 212 |
|
119 | 213 | ## DataStax Driver and libuv |
120 | 214 |
|
121 | | -The library depends on [the DataStax driver](https://github.com/datastax/cpp-driver) and [libuv](https://github.com/libuv/libuv), which are included as git submodules. Both of them have source files that are excluded in `Package.swift`. |
| 215 | +The library depends on [the DataStax driver](https://github.com/datastax/cpp-driver) and |
| 216 | +[libuv](https://github.com/libuv/libuv), which are included as git submodules. Both of them |
| 217 | +have source files that are excluded in `Package.swift`. |
122 | 218 |
|
123 | 219 | ### DataStax driver |
124 | 220 |
|
125 | | -The git submodule is under `Sources/CDataStaxDriver/datastax-cpp-driver`. To update, do `git fetch` then checkout the desired [tag/release](https://github.com/datastax/cpp-driver/releases). The driver's config files are located in `Sources/CDataStaxDriver/extras`. |
| 221 | +The git submodule is under `Sources/CDataStaxDriver/datastax-cpp-driver`. To update, |
| 222 | +do `git fetch` then checkout the desired [tag/release](https://github.com/datastax/cpp-driver/releases). The |
| 223 | +driver's config files are located in `Sources/CDataStaxDriver/extras`. |
126 | 224 |
|
127 | 225 | ### libuv |
128 | 226 |
|
129 | | -The git submodule is under `Sources/Clibuv/libuv`. To update, do `git fetch` then checkout the desired [tag/release](https://github.com/libuv/libuv/releases). Note that `include` and `uv.h` in `Sources/Clibuv` are symlinked to the corresponding directory/file in `Sources/Clibuv/libuv`. |
| 227 | +The git submodule is under `Sources/Clibuv/libuv`. To update, do `git fetch` then checkout |
| 228 | +the desired [tag/release](https://github.com/libuv/libuv/releases). Note that `include` |
| 229 | +and `uv.h` in `Sources/Clibuv` are symlinked to the corresponding directory/file in `Sources/Clibuv/libuv`. |
130 | 230 |
|
131 | 231 | ## Development Setup |
132 | 232 |
|
|
0 commit comments