update redis docs

This commit is contained in:
tanner0101 2018-08-17 16:16:01 -04:00
parent 16483f71bc
commit 025b1c7db2
7 changed files with 142 additions and 214 deletions

View File

@ -1,100 +0,0 @@
# Redis basic usage
To interact with Redis, you first need to construct a Redis client.
The Redis library primarily supports TCP sockets.
This requires a hostname, port and worker. The eventloop will be used for Redis' Socket. The hostname and port have a default. The hostname is defaulted to `localhost`, and the port to Redis' default port `6379`.
```swift
let client = try RedisClient.connect(on: worker) // Future<RedisClient>
```
The `connect` method will return a future containing the TCP based Redis Client.
## Redis Data Types
Redis has 6 data types:
- null
- Int
- Error
- Array
- Basic String (used for command names and basic replies only)
- Bulk String (used for Strings and binary data blobs)
You can instantiate one from the static functions and variables on `RedisData`.
```swift
let null = RedisData.null
let helloWorld = RedisData.bulkString("Hello World")
let three = RedisData.integer(3)
let oneThroughTen = RedisData.array([
.integer(1),
.integer(2),
.integer(3),
.integer(4),
.integer(5),
.integer(6),
.integer(7),
.integer(8),
.integer(9),
.integer(10)
])
```
The above is the explicit way of defining Redis Types. You can also use literals in most scenarios:
```swift
let array = RedisData.array([
[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
],
"Hello World",
"One",
"Two",
.null,
.null,
"test"
])
```
## CRUD using Redis
From here on it is assumed that your client has been successfully created and is available in the variable `client` as a `RedisClient`.
### Creating a record
Creating a record is done using a `RedisData` for a value and a key.
```swift
client.set("world", forKey: "hello")
```
This returns a future that'll indicate successful or unsuccessful insertion.
### Reading a record
Reading a record is similar, only you'll get a warning if you don't use the returned future.
The `Future<RedisData>` for the key "hello" will be "world" if you created the record as shown above.
```swift
let futureRecord = client.getData(forKey: "hello") // Future<RedisData>
```
### Deleting a record
Deleting a record is similar but allows querying the keys, too.
```swift
client.delete(keys: ["hello"])
```
Where the above command will remove the key "hello", the next command will delete **all** keys from the Redis database.
```swift
client.delete(keys: ["*"])
```

View File

@ -1,17 +0,0 @@
# Custom commands
Many commands are not (yet) implemented by the driver using a convenience function. This does not mean the feature/command is not usable.
[(Almost) all functions listed here](https://redis.io/commands) work out of the box using custom commands.
## Usage
The Redis client has a `run` function that allows you to run these commands.
The following code demonstrates a "custom" implementation for [GET](https://redis.io/commands/get).
```swift
let future = client.run(command: "GET", arguments: ["my-key"]) // Future<RedisData>
```
This future will contain the result as specified in the article on the redis command page or an error.

View File

@ -1,36 +1,68 @@
!!! warning
Redis 3.0 is still in beta. Some documentation may be missing or out of date.
# Getting Started with Redis
# Redis
Redis ([vapor/redis](https://github.com/vapor/redis)) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO.
Redis is a Redis client library that can communicate with a Redis database.
You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's `KeyedCache` interface.
### What is Redis?
Let's take a look at how you can get started using Redis.
Redis is an in-memory data store used as a database, cache and message broker. It supports most common data structures. Redis is most commonly used for caching data such as sessions and notifications (between multiple servers).
## Package
Redis works as a key-value store, but allows querying the keys, unlike most databases.
## With and without Vapor
To include it in your package, add the following to your `Package.swift` file.
The first step to using Redis is adding it as a dependency to your project in your SPM package manifest file.
```swift
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "Project",
name: "MyApp",
dependencies: [
...
.package(url: "https://github.com/vapor/redis.git", .upToNextMajor(from: "3.0.0")),
/// Any other dependencies ...
// ⚡Non-blocking, event-driven Redis client.
.package(url: "https://github.com/vapor/redis.git", from: "3.0.0"),
],
targets: [
.target(name: "Project", dependencies: ["Redis", ... ])
.target(name: "App", dependencies: ["Redis", ...]),
.target(name: "Run", dependencies: ["App"]),
.testTarget(name: "AppTests", dependencies: ["App"]),
]
)
```
If this is your first time adding a dependency, you should read our introduction to [Package.swift](../getting-started/spm.md).
## Provider
Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in [`configure.swift`](../getting-started/structure.md#configureswift).
```swift
import Redis
// register Redis provider
try services.register(RedisProvider())
```
That's it for basic setup. The next step is to create a Redis connection and send a command.
## Command
First, create a new connection to your Redis database. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. See [DatabaseKit &rarr; Overview](../database-kit/overview.md) for more information.
```swift
router.get("redis") { req -> Future<String> in
return req.withNewConnection(to: .redis) { redis in
// use redis connection
}
}
```
Once you have a connection, you can use it to send a command. Let's send the `"INFO"` command which should return information about our Redis server.
```swift
// send INFO command to redis
return redis.command("INFO")
// map the resulting RedisData to a String
.map { $0.string ?? "" }
```
Run your app and query `GET /redis`. You should see information about your Redis server printed as output. Congratulations!
Use `import Redis` to access Redis' APIs.

View File

@ -0,0 +1,92 @@
# Using Redis
Redis ([vapor/redis](https://github.com/vapor/redis)) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO.
You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's `KeyedCache` interface.
## Redis Commands
Let's take a look at how to send and recieve data using Redis commands.
### Connection
The first thing you will need to send a Redis command is a connection. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection.
For this example, we will use the `withNewConnection(to:)` method to create a new connection to Redis.
```swift
router.get("redis") { req -> Future<String> in
return req.withNewConnection(to: .redis) { redis in
// use redis connection
}
}
```
See [DatabaseKit &rarr; Overview](../database-kit/overview.md) for more information.
### Available Commands
See [`RedisClient`](https://api.vapor.codes/redis/latest/Redis/Classes/RedisClient.html) for a list of all available commands. Here we'll take a look at some common commands.
#### Get / Set
Redis's `GET` and `SET` commands allow you to store and later retrieve data from the server. You can pass any `Codable` type as the value to this command.
```swift
router.get("set") { req -> Future<HTTPStatus> in
// create a new redis connection
return req.withNewConnection(to: .redis) { redis in
// save a new key/value pair to the cache
return redis.set("hello", to: "world")
// convert void future to HTTPStatus.ok
.transform(to: .ok)
}
}
router.get("get") { req -> Future<String> in
// create a new redis connection
return req.withNewConnection(to: .redis) { redis in
// fetch the key/value pair from the cache, decoding a String
return redis.get("hello", as: String.self)
// handle nil case
.map { $0 ?? "" }
}
}
```
#### Delete
Redis's `DELETE` command allows you to clear a previously stored key/value pair.
```swift
router.get("del") { req -> Future<HTTPStatus> in
// create a new redis connection
return req.withNewConnection(to: .redis) { redis in
// fetch the key/value pair from the cache, decoding a String
return redis.delete("hello")
// convert void future to HTTPStatus.ok
.transform(to: .ok)
}
}
```
See [`RedisClient`](https://api.vapor.codes/redis/latest/Redis/Classes/RedisClient.html) for a list of all available commands.
## Keyed Cache
You can also use Redis as the backend to Vapor's [`KeyedCache`](https://api.vapor.codes/database-kit/latest/DatabaseKit/Protocols/KeyedCache.html) protocol.
```swift
router.get("set") { req -> Future<HTTPStatus> in
let string = try req.query.get(String.self, at: "string")
return try req.keyedCache(for: .redis).set("string", to: string)
.transform(to: .ok)
}
router.get("get") { req -> Future<String> in
return try req.keyedCache(for: .redis).get("string", as: String.self)
.unwrap(or: Abort(.badRequest, reason: "No string set yet."))
}
```
See [DatabaseKit &rarr; Overview](../database-kit/overview/#keyed-cache) for more information.

View File

@ -1,18 +0,0 @@
# Pipelining
Pipelining is used for sending multiple commands at once. The performance advantages become apparent when sending a large number of queries. Redis' pipelining cuts down latency by reducing the RTT (Round Trip Time) between the client and server. Pipelining also reduces the amount of IO operations Redis has to perform, this increases the amount of queries per second Redis can handle.
### Use cases
Sometimes multiple commands need to be executed at once. Instead of sending those commands individually in a loop, pipelining allows the commands to be batched and sent in one request. A common scenario might be needing to set a key and increment a count, pipelining those commands would be ideal.
### Enqueuing Commands
```swift
let pipeline = connection.makePipeline()
let result = try pipeline
.enqueue(command: "SET", arguments: ["KEY", "VALUE"])
.enqueue(command: "INCR", arguments: ["COUNT"])
.execute() // Future<[RedisData]>
```
Note: Commands will not be executed until execute is called.

View File

@ -1,58 +0,0 @@
# Publish & Subscribe
Redis' Publish and Subscribe model is really useful for notifications.
### Use cases
Pub/sub is used for notifying subscribers of an event.
A simple and common event for example would be a chat message.
A channel consists of a name and group of listeners. Think of it as being `[String: [Listener]]`.
When you send a notification to a channel you need to provide a payload.
Each listener will get a notification consisting of this payload.
Channels must be a string. For chat groups, for example, you could use the database identifier.
### Publishing
You cannot get a list of listeners, but sending a payload will emit the amount of listeners that received the notification.
Sending (publishing) an event is done like so:
```swift
// Any redis data
let notification: RedisData = "My-Notification"
client.publish(notification, to: "my-channel")
```
If you want access to the listener count:
```swift
let notifiedCount = client.publish(notification, to: "my-channel") // Future<Int>
```
### Subscribing
To subscribe for notifications you're rendering an entire Redis Client useless in exchange for listening to events.
A single client can listen to one or more channels, which is provided using a set of unique channel names. The result of subscribing is a `SubscriptionStream`.
```swift
let notifications = client.subscribe(to: ["some-notification-channel", "other-notification-channel"])
```
If you try to use the client after subscribing, all operations will fail. These errors are usually emitted through the Future.
This stream will receive messages asynchronously from the point of `draining`. This works like any other async stream.
Notifications consist of the channel and payload.
```swift
notifications.drain { notification in
print(notification.channel)
let payload = notification.payload
// TODO: Process the payload
}
```

View File

@ -74,10 +74,7 @@ pages:
- 'Getting Started': 'postgresql/getting-started.md'
- 'Redis':
- 'Getting Started': 'redis/getting-started.md'
- 'Basics': 'redis/basics.md'
- 'Custom commands': 'redis/custom-commands.md'
- 'Publish and Subscribe': 'redis/pub-sub.md'
- 'Pipeline': 'redis/pipeline.md'
- 'Overview': 'redis/overview.md'
- 'Routing':
- 'Getting Started': 'routing/getting-started.md'
- 'Overview': 'routing/overview.md'