diff --git a/README.md b/README.md index 029581bb..525203e8 100644 --- a/README.md +++ b/README.md @@ -20,215 +20,123 @@ Install: go get github.com/vmihailenco/redis -Getting Client instance ------------------------ +Getting started +--------------- -Example 1: +Let's start with connecting to Redis: - import "github.com/vmihailenco/redis" + password := "" // no password set + db := -1 // use default DB + client := redis.NewTCPClient("localhost:6379", password, db) + defer client.Close() +Then we can start sending commands: - address := "localhost:6379" - password := "secret" - db := 0 - redisClient := redis.NewTCPClient(address, password, db) + if err := client.Set("foo", "bar"); err != nil { panic(err) } -Example 2: + get := client.Get("foo") + if err := get.Err(); err != nil { panic(err) } + fmt.Println(get.Val()) - import "github.com/vmihailenco/redis" +We can also pipeline two commands together: - - openConn := func() (net.Conn, error) { - fmt.Println("Connecting...") - return net.Dial("tcp", ":6379") + var set *redis.StatusReq + var get *redis.StringReq + reqs, err := client.Pipelined(func(c *redis.PipelineClient)) { + set = c.Set("key1", "hello1") + get = c.Get("key2") } + if err != nil { panic(err) } + if err := set.Err(); err != nil { panic(err) } + if err := get.Err(); err != nil { panic(err) } + fmt.Println(get.Val()) + fmt.Println(reqs[0] == set) + fmt.Println(reqs[1] == get) - closeConn := func(conn net.Conn) error { - fmt.Println("Disconnecting...") - return nil - } +or: - initConn := func(client *redis.Client) error { - auth := client.Auth("key") - if err := auth.Err(); err != nil { - return err - } - - ping := client.Ping() - if err := ping.Err(); err != nil { - return err - } - - return nil - } - - redisClient := redis.NewClient(openConn, closeConn, initConn) - -Both `closeConn` and `initConn` functions can be `nil`. - -Running commands ----------------- - - set := redisClient.Set("key", "hello") - if err := set.Err(); err != nil { - panic(err) - } - ok := set.Val() - - get := redisClient.Get("key") - if err := get.Err(); err != nil && err != redis.Nil { - panic(err) - } - val := get.Val() - -Pipelining ----------- - -Client has ability to run commands in batches: - - reqs, err := redisClient.Pipelined(func(c *redis.PipelineClient) { - c.Set("key1", "hello1") // queue command SET - c.Set("key2", "hello2") // queue command SET - }) - if err != nil { - panic(err) - } - for _, req := range reqs { - // ... - } - -Or: - - pipeline, err := redisClient.PipelineClient() + pipeline, err := client.PipelineClient() if err != nil { panic(err) } defer pipeline.Close() - setReq := pipeline.Set("key1", "hello1") // queue command SET - getReq := pipeline.Get("key2") // queue command GET + set := pipeline.Set("key1", "hello1") + get := pipline.Get("key2") - reqs, err := pipeline.RunQueued() // run queued commands - if err != nil { - panic(err) - } - for _, req := range reqs { - // ... - } + reqs, err := pipeline.RunQueued() + if err != nil { panic(err) } - if err := setReq.Err(); err != nil { - panic(err - } + if err := set.Err(); err != nil { panic(err) } + if err := get.Err(); err != nil { panic(err) } + fmt.Println(get.Val()) + fmt.Println(reqs[0] == set) + fmt.Println(reqs[1] == get) - if err := getReq.Err(); err != nil && err != redis.Nil { - panic(err) - } +We can also send several commands in transaction: -Multi/Exec ----------- - -Example: - - func transaction(multi *redis.MultiClient) ([]redis.Req, error) { - get := multiClient.Get("key") + func incrKeyInTransaction(multi *redis.MultiClient) ([]redis.Req, error) { + get := multi.Get("key") if err := get.Err(); err != nil { panic(err) } - reqs, err = multiClient.Exec(func() { - multi.Set("key", get.Val() + "1") - }) - if err == redis.Nil { - return transaction() - } + val, err := strconv.ParseInt(get.Val(), 10, 64) + if err != nil { panic(err) } + reqs, err = multi.Exec(func() { + multi.Set("key", val + 1) + }) + // Transaction failed. Repeat. + if err == redis.Nil { + return incrKeyInTransaction(multi) + } return reqs, err } - multiClient, err := redisClient.MultiClient() - if err != nil { - panic(err) - } - defer multiClient.Close() + multi, err := client.MultiClient() + if err != nil { panic(err) } + defer multi.Close() - watch := multiClient.Watch("key") - if err := watch.Err(); err != nil { - panic(err) - } + watch := multi.Watch("key") + if err := watch.Err(); err != nil { panic(err) } - reqs, err := transaction(multiClient) - if err != nil { - panic(err) - } + reqs, err := incrKeyInTransaction(multi) + if err != nil { panic(err) } for _, req := range reqs { // ... } -Pub/sub -------- +To subscribe to the channel: -Publish: - - pub := redisClient.Publish("mychannel", "hello") - if err := pub.Err(); err != nil { - panic(err) - } - -Subscribe: - - pubsub, err := redisClient.PubSubClient() - if err != nil { - panic(err) - } + pubsub, err := client.PubSubClient() + if err != nil { panic(err) } defer pubsub.Close() ch, err := pubsub.Subscribe("mychannel") - if err != nil { - panic(err) - } + if err != nil { panic(err) } go func() { for msg := range ch { - if msg.Err != nil { - panic(err) - } + if err := msg.Err; err != nil { panic(err) } message := msg.Message } } -Thread safety -------------- +You can also write custom commands: -Commands are thread safe. Following code is correct: - - for i := 0; i < 1000; i++ { - go func() { - redisClient.Incr("key") - }() - } - -Custom commands ---------------- - -Example: - - func Get(client *redis.Client, key string) *redis.BulkReq { - req := redis.NewBulkReq("GET", key) + func Get(client *redis.Client, key string) *redis.StringReq { + req := redis.NewStringReq("GET", key) client.Process(req) return req } get := Get(redisClient, "key") - if err := get.Err(); err != nil && err != redis.Nil { - panic(err) - } + if err := get.Err(); err != nil && err != redis.Nil { panic(err) } -Connection pool ---------------- +Client uses connection pool to send commands. You can change maximum number of connections with: -Client uses connection pool with default capacity of 10 connections. To change pool capacity: - - redisClient.ConnPool.(*redis.MultiConnPool).MaxCap = 1 + client.ConnPool.(*redis.MultiConnPool).MaxCap = 1 Look and feel ------------- diff --git a/doc.go b/doc.go new file mode 100644 index 00000000..f73ffdc7 --- /dev/null +++ b/doc.go @@ -0,0 +1,123 @@ +// Copyright 2012 The Redis Client Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package github.com/vmihailenco/redis implements a Redis client. + +Let's start with connecting to Redis: + + password := "" // no password set + db := -1 // use default DB + client := redis.NewTCPClient("localhost:6379", password, db) + defer client.Close() + +Then we can start sending commands: + + if err := client.Set("foo", "bar"); err != nil { panic(err) } + + get := client.Get("foo") + if err := get.Err(); err != nil { panic(err) } + fmt.Println(get.Val()) + +We can also pipeline two commands together: + + var set *redis.StatusReq + var get *redis.StringReq + reqs, err := client.Pipelined(func(c *redis.PipelineClient)) { + set = c.Set("key1", "hello1") + get = c.Get("key2") + } + if err != nil { panic(err) } + if err := set.Err(); err != nil { panic(err) } + if err := get.Err(); err != nil { panic(err) } + fmt.Println(get.Val()) + fmt.Println(reqs[0] == set) + fmt.Println(reqs[1] == get) + +or: + + pipeline, err := client.PipelineClient() + if err != nil { + panic(err) + } + defer pipeline.Close() + + set := pipeline.Set("key1", "hello1") + get := pipline.Get("key2") + + reqs, err := pipeline.RunQueued() + if err != nil { panic(err) } + + if err := set.Err(); err != nil { panic(err) } + if err := get.Err(); err != nil { panic(err) } + fmt.Println(get.Val()) + fmt.Println(reqs[0] == set) + fmt.Println(reqs[1] == get) + +We can also send several commands in transaction: + + func incrKeyInTransaction(multi *redis.MultiClient) ([]redis.Req, error) { + get := multi.Get("key") + if err := get.Err(); err != nil { + panic(err) + } + + val, err := strconv.ParseInt(get.Val(), 10, 64) + if err != nil { panic(err) } + + reqs, err = multi.Exec(func() { + multi.Set("key", val + 1) + }) + // Transaction failed. Repeat. + if err == redis.Nil { + return incrKeyInTransaction(multi) + } + return reqs, err + } + + multi, err := client.MultiClient() + if err != nil { panic(err) } + defer multi.Close() + + watch := multi.Watch("key") + if err := watch.Err(); err != nil { panic(err) } + + reqs, err := incrKeyInTransaction(multi) + if err != nil { panic(err) } + for _, req := range reqs { + // ... + } + +To subscribe to the channel: + + pubsub, err := client.PubSubClient() + if err != nil { panic(err) } + defer pubsub.Close() + + ch, err := pubsub.Subscribe("mychannel") + if err != nil { panic(err) } + + go func() { + for msg := range ch { + if err := msg.Err; err != nil { panic(err) } + message := msg.Message + } + } + +You can also write custom commands: + + func Get(client *redis.Client, key string) *redis.StringReq { + req := redis.NewStringReq("GET", key) + client.Process(req) + return req + } + + get := Get(redisClient, "key") + if err := get.Err(); err != nil && err != redis.Nil { panic(err) } + +Client uses connection pool to send commands. You can change maximum number of connections with: + + client.ConnPool.(*redis.MultiConnPool).MaxCap = 1 +*/ +package redis