# redis

> Redis client — connect and run key/value, list, hash, and pub/sub commands over integer handles.

# redis

The `redis` module is a Redis client. You connect once to get an integer handle, then pass that handle to every command. Import it with `import redis`.

## Connection

`redis.connect` returns an `int` handle on success, or `-1` if the URL is invalid or the connection/ping fails. Pass the handle to every other call.

| Function | Signature | Description |
| --- | --- | --- |
| `connect` | `redis.connect(url: string) → int` | connect via a `redis://` or `rediss://` URL; returns a handle or `-1` |
| `close` | `redis.close(handle: int) → bool` | close the connection; true if the handle existed |
| `ping` | `redis.ping(handle: int) → bool` | true if the server responds to PING |

## Key/value

| Function | Signature | Description |
| --- | --- | --- |
| `set` | `redis.set(handle: int, key: string, val: any, ttlMs?: int) → bool` | set a key; `ttlMs` ≤ 0 or omitted means no expiry |
| `get` | `redis.get(handle: int, key: string) → string` | get a value; void if the key is missing |
| `del` | `redis.del(handle: int, key: string) → bool` | delete a key; true if a key was removed |
| `exists` | `redis.exists(handle: int, key: string) → bool` | true if the key exists |
| `expire` | `redis.expire(handle: int, key: string, ttlMs: int) → bool` | set a TTL in milliseconds |
| `ttl` | `redis.ttl(handle: int, key: string) → int` | remaining TTL in ms; `-1` no expiry, `-2` missing |
| `incr` | `redis.incr(handle: int, key: string) → int` | increment and return the new value |
| `decr` | `redis.decr(handle: int, key: string) → int` | decrement and return the new value |
| `keys` | `redis.keys(handle: int, pattern: string) → string[]` | keys matching the glob pattern |

## Lists

| Function | Signature | Description |
| --- | --- | --- |
| `lpush` | `redis.lpush(handle: int, key: string, val: any) → int` | push to the head; returns new length (`-1` on error) |
| `rpush` | `redis.rpush(handle: int, key: string, val: any) → int` | push to the tail; returns new length (`-1` on error) |
| `lpop` | `redis.lpop(handle: int, key: string) → string` | pop from the head; void if empty/missing |
| `rpop` | `redis.rpop(handle: int, key: string) → string` | pop from the tail; void if empty/missing |
| `lrange` | `redis.lrange(handle: int, key: string, start: int, stop: int) → string[]` | elements in the index range |
| `llen` | `redis.llen(handle: int, key: string) → int` | list length |

## Hashes

| Function | Signature | Description |
| --- | --- | --- |
| `hset` | `redis.hset(handle: int, key: string, field: string, val: any) → bool` | set a field; true if it was a new field |
| `hget` | `redis.hget(handle: int, key: string, field: string) → string` | get a field; void if missing |
| `hgetall` | `redis.hgetall(handle: int, key: string) → object` | all fields as an object (string values) |
| `hdel` | `redis.hdel(handle: int, key: string, field: string) → bool` | delete a field |

## Pub/Sub

| Function | Signature | Description |
| --- | --- | --- |
| `publish` | `redis.publish(handle: int, channel: string, msg: string) → int` | publish a message; returns subscribers reached (`-1` on error) |

## Example

```goost
import redis

let db = redis.connect("redis://localhost:6379")
if db < 0 {
    println("could not connect")
    return
}

// Key/value with a 60s TTL
redis.set(db, "session:42", "active", 60000)
println("session: " + redis.get(db, "session:42"))

// A counter
redis.incr(db, "visits")
println("visits: " + toString(redis.incr(db, "visits")))

// A list
redis.rpush(db, "queue", "job-1")
redis.rpush(db, "queue", "job-2")
println("next: " + redis.lpop(db, "queue"))

// Publish to a channel
redis.publish(db, "events", "user-signup")

redis.close(db)
```