Skip to content

Commit

Permalink
Update README (#12)
Browse files Browse the repository at this point in the history
Add async/await examples
  • Loading branch information
yim-lee authored Dec 21, 2022
1 parent 4150253 commit c714635
Showing 1 changed file with 156 additions and 56 deletions.
212 changes: 156 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,132 +1,232 @@
# Swift Cassandra Client

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.
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.

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.
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.

## Usage

### Swift concurrency based API

#### Creating a client instance

```swift
let configuration = CassandraClient.Configuration(...)
let cassandraClient = CassandraClient(configuration: configuration)
var configuration = CassandraClient.Configuration(...)
let cassandraClient = CassandraClient(configuration: configuration)
```

The client has a default session established (lazily) so that it can be used directly to perform queries on the configured keyspace:
The client has a default session established (lazily) so that it can be used directly to perform
queries on the configured keyspace:

```swift
cassandraClient.query(...)
let result = try await cassandraClient.query(...)
```

The client must be explicitly shut down when no longer needed.
The client must be explicitly shut down when no longer needed:

```swift
cassandraClient.shutdown()
try cassandraClient.shutdown()
```

#### Creating a session for a different keyspace

```swift
let session = cassandraClient.makeSession(keyspace: "the_keyspace")
session.query(...)
let session = cassandraClient.makeSession(keyspace: <KEYSPACE>)
let result = try await session.query(...)
```

The session must be explicitly shut down when no longer needed.
The session must be explicitly shut down when no longer needed:

```swift
session.shutdown()
try session.shutdown()
```

You can also create a session and pass in a closure, which will automatically release the resource when the closure exists:
You can also create a session and pass in a closure, which will automatically release the resource when the closure exits:

```swift
cassandraClient.withSession(keyspace: "<keyspace>") { session in
session.query(...)
}
try await cassandraClient.withSession(keyspace: <KEYSPACE>) { session in
...
}
```

#### Running result-less commands, e.g. insert, update, delete or DDL
#### Running result-less commands (e.g. insert, update, delete or DDL)

```swift
cassandraClient.run("create table ...")
try await cassandraClient.run("create table ...")
```

Or at a session level
Or at session level:

```swift
session.run("create table ...")
try await session.run("create table ...")
```

#### Running queries returning small data-sets that fit in-memory
#### Running queries returning small datasets that fit in memory

Returning a model object, having `Model: Codable`
Returning a model object, having `Model: Codable`:

```swift
cassandraClient.query("select * from table ...").map { (result: [Model]) in
...
}

let result: [Model] = try await cassandraClient.query("select * from table ...")
let result: [Model] = try await cassandraClient.query("select * from table ...")
```

```swift
session.query("select * from table ...").map { (result: [Model]) in
...
}
let result: [Model] = try await session.query("select * from table ...")
```

let result: [Model] = try await session.query("select * from table ...")
Or using free-form transformations on the row:

```swift
let values = try await cassandraClient.query("select * from table ...") { row in
row.column(<COLUMN_NAME>).int32
}
```

Or using free-form transformations on the row
```swift
let values = try await session.query("select * from table ...") { row in
row.column(<COLUMN_NAME>).int32
}
```

#### Running queries returning large datasets that do not fit in memory

```swift
cassandraClient.query("select * from table ...") { row in
row.column("column_name").int32
}.map { value in
...
}
// `rows` is a sequence that one needs to iterate on
let rows: Rows = try await cassandraClient.query("select * from table ...")
```

```swift
session.query("select * from table ...") { row in
row.column("column_name").int32
}.map { value in
...
}
// `rows` is a sequence that one needs to iterate on
let rows: Rows = try await session.query("select * from table ...")
```

### SwiftNIO future based API

#### Creating a client instance

```swift
var configuration = CassandraClient.Configuration(...)
let cassandraClient = CassandraClient(configuration: configuration)
```

The client has a default session established (lazily) so that it can be used directly to perform
queries on the configured keyspace:

```swift
let resultFuture = cassandraClient.query(...)
```

The client must be explicitly shut down when no longer needed:

```swift
try cassandraClient.shutdown()
```

#### Creating a session for a different keyspace

```swift
let session = cassandraClient.makeSession(keyspace: <KEYSPACE>)
let resultFuture = session.query(...)
```

The session must be explicitly shut down when no longer needed:

```swift
try session.shutdown()
```

You can also create a session and pass in a closure, which will automatically release the resource when the closure exits:

```swift
try cassandraClient.withSession(keyspace: <KEYSPACE>) { session in
...
}
```

#### Running result-less commands (e.g. insert, update, delete or DDL)

```swift
let voidFuture = cassandraClient.run("create table ...")
```

Or at session level:

```swift
let voidFuture = session.run("create table ...")
```

#### Running queries returning large data-sets that do not fit in-memory
#### Running queries returning small datasets that fit in memory

Returning a model object, having `Model: Codable`:

```swift
cassandraClient.query("select * from table ...").map { (rows: Rows) in
// rows is a sequence that one needs to iterate on
rows.map { row in
...
}
cassandraClient.query("select * from table ...").map { result: [Model] in
...
}
```

```swift
session.query("select * from table ...").map { result: [Model] in
...
}
```

Or using free-form transformations on the row:

```swift
cassandraClient.query("select * from table ...") { row in
row.column(<COLUMN_NAME>).int32
}.map { value in
...
}
```

```swift
session.query("select * from table ...") { row in
row.column(<COLUMN_NAME>).int32
}.map { value in
...
}
```

#### Running queries returning large datasets that do not fit in memory

```swift
cassandraClient.query("select * from table ...").map { rows: Rows in
// `rows` is a sequence that one needs to iterate on
rows.map { row in
...
}
}
```

```swift
session.query("select * from table ...").map { (rows: Rows) in
// rows is a sequence that one needs to iterate on
rows.map { row in
...
}
session.query("select * from table ...").map { rows: Rows in
// `rows` is a sequence that one needs to iterate on
rows.map { row in
...
}
}
```

## DataStax Driver and libuv

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`.
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`.

### DataStax driver

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`.
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`.

### libuv

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`.
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`.

## Development Setup

Expand Down

0 comments on commit c714635

Please sign in to comment.