func ExampleScanSlice() { c, err := dial() if err != nil { panic(err) } defer c.Close() c.Send("HMSET", "album:1", "title", "Red", "rating", 5) c.Send("HMSET", "album:2", "title", "Earthbound", "rating", 1) c.Send("HMSET", "album:3", "title", "Beat", "rating", 4) c.Send("LPUSH", "albums", "1") c.Send("LPUSH", "albums", "2") c.Send("LPUSH", "albums", "3") values, err := redis.Values(c.Do("SORT", "albums", "BY", "album:*->rating", "GET", "album:*->title", "GET", "album:*->rating")) if err != nil { panic(err) } var albums []struct { Title string Rating int } if err := redis.ScanSlice(values, &albums); err != nil { panic(err) } fmt.Printf("%v\n", albums) // Output: // [{Earthbound 1} {Beat 4} {Red 5}] }
func TestBlankCommmand(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() for _, cmd := range testCommands { if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil { t.Fatalf("Send(%v) returned error %v", cmd.args, err) } } reply, err := redis.Values(c.Do("")) if err != nil { t.Fatalf("Do() returned error %v", err) } if len(reply) != len(testCommands) { t.Fatalf("len(reply)=%d, want %d", len(reply), len(testCommands)) } for i, cmd := range testCommands { actual := reply[i] if !reflect.DeepEqual(actual, cmd.expected) { t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected) } } }
func ExampleArgs() { c, err := dial() if err != nil { panic(err) } defer c.Close() var p1, p2 struct { Title string `redis:"title"` Author string `redis:"author"` Body string `redis:"body"` } p1.Title = "Example" p1.Author = "Gary" p1.Body = "Hello" if _, err := c.Do("HMSET", redis.Args{}.Add("id1").AddFlat(&p1)...); err != nil { panic(err) } m := map[string]string{ "title": "Example2", "author": "Steve", "body": "Map", } if _, err := c.Do("HMSET", redis.Args{}.Add("id2").AddFlat(m)...); err != nil { panic(err) } for _, id := range []string{"id1", "id2"} { v, err := redis.Values(c.Do("HGETALL", id)) if err != nil { panic(err) } if err := redis.ScanStruct(v, &p2); err != nil { panic(err) } fmt.Printf("%+v\n", p2) } // Output: // {Title:Example Author:Gary Body:Hello} // {Title:Example2 Author:Steve Body:Map} }
func sliceOfChannelIDs(result interface{}, prefix string, err error) ([]ChannelID, error) { values, err := redis.Values(result, err) if err != nil { return nil, err } channels := make([]ChannelID, len(values)) for i := 0; i < len(values); i += 1 { value, okValue := values[i].([]byte) if !okValue { return nil, errors.New("error getting ChannelID value") } chID := ChannelID(value) channels[i] = chID } return channels, nil }
func mapStringByte(result interface{}, err error) (map[string][]byte, error) { values, err := redis.Values(result, err) if err != nil { return nil, err } if len(values)%2 != 0 { return nil, errors.New("mapStringByte expects even number of values result") } m := make(map[string][]byte, len(values)/2) for i := 0; i < len(values); i += 2 { key, okKey := values[i].([]byte) value, okValue := values[i+1].([]byte) if !okKey || !okValue { return nil, errors.New("ScanMap key not a bulk string value") } m[string(key)] = value } return m, nil }
func sliceOfMessages(result interface{}, err error) ([]Message, error) { values, err := redis.Values(result, err) if err != nil { return nil, err } msgs := make([]Message, len(values)) for i := 0; i < len(values); i += 1 { value, okValue := values[i].([]byte) if !okValue { return nil, errors.New("error getting Message value") } var m Message err = json.Unmarshal(value, &m) if err != nil { return nil, errors.New("can not unmarshal value to Message") } msgs[i] = m } return msgs, nil }
func ExampleScan() { c, err := dial() if err != nil { panic(err) } defer c.Close() c.Send("HMSET", "album:1", "title", "Red", "rating", 5) c.Send("HMSET", "album:2", "title", "Earthbound", "rating", 1) c.Send("HMSET", "album:3", "title", "Beat") c.Send("LPUSH", "albums", "1") c.Send("LPUSH", "albums", "2") c.Send("LPUSH", "albums", "3") values, err := redis.Values(c.Do("SORT", "albums", "BY", "album:*->rating", "GET", "album:*->title", "GET", "album:*->rating")) if err != nil { panic(err) } for len(values) > 0 { var title string rating := -1 // initialize to illegal value to detect nil. values, err = redis.Scan(values, &title, &rating) if err != nil { panic(err) } if rating == -1 { fmt.Println(title, "not-rated") } else { fmt.Println(title, rating) } } // Output: // Beat not-rated // Earthbound 1 // Red 5 }
func mapStringClientInfo(result interface{}, err error) (map[ConnID]ClientInfo, error) { values, err := redis.Values(result, err) if err != nil { return nil, err } if len(values)%2 != 0 { return nil, errors.New("mapStringClientInfo expects even number of values result") } m := make(map[ConnID]ClientInfo, len(values)/2) for i := 0; i < len(values); i += 2 { key, okKey := values[i].([]byte) value, okValue := values[i+1].([]byte) if !okKey || !okValue { return nil, errors.New("ScanMap key not a bulk string value") } var f ClientInfo err = json.Unmarshal(value, &f) if err != nil { return nil, errors.New("can not unmarshal value to ClientInfo") } m[ConnID(key)] = f } return m, nil }
// TextExecError tests handling of errors in a transaction. See // http://redis.io/topics/transactions for information on how Redis handles // errors in a transaction. func TestExecError(t *testing.T) { c, err := redistest.Dial() if err != nil { t.Fatalf("error connection to database, %v", err) } defer c.Close() // Execute commands that fail before EXEC is called. c.Do("ZADD", "k0", 0, 0) c.Send("MULTI") c.Send("NOTACOMMAND", "k0", 0, 0) c.Send("ZINCRBY", "k0", 0, 0) v, err := c.Do("EXEC") if err == nil { t.Fatalf("EXEC returned values %v, expected error", v) } // Execute commands that fail after EXEC is called. The first command // returns an error. c.Do("ZADD", "k1", 0, 0) c.Send("MULTI") c.Send("HSET", "k1", 0, 0) c.Send("ZINCRBY", "k1", 0, 0) v, err = c.Do("EXEC") if err != nil { t.Fatalf("EXEC returned error %v", err) } vs, err := redis.Values(v, nil) if err != nil { t.Fatalf("Values(v) returned error %v", err) } if len(vs) != 2 { t.Fatalf("len(vs) == %d, want 2", len(vs)) } if _, ok := vs[0].(error); !ok { t.Fatalf("first result is type %T, expected error", vs[0]) } if _, ok := vs[1].([]byte); !ok { t.Fatalf("second result is type %T, expected []byte", vs[2]) } // Execute commands that fail after EXEC is called. The second command // returns an error. c.Do("ZADD", "k2", 0, 0) c.Send("MULTI") c.Send("ZINCRBY", "k2", 0, 0) c.Send("HSET", "k2", 0, 0) v, err = c.Do("EXEC") if err != nil { t.Fatalf("EXEC returned error %v", err) } vs, err = redis.Values(v, nil) if err != nil { t.Fatalf("Values(v) returned error %v", err) } if len(vs) != 2 { t.Fatalf("len(vs) == %d, want 2", len(vs)) } if _, ok := vs[0].([]byte); !ok { t.Fatalf("first result is type %T, expected []byte", vs[0]) } if _, ok := vs[1].(error); !ok { t.Fatalf("second result is type %T, expected error", vs[2]) } }
func (e *RedisEngine) initializeApi() { e.Lock() e.inAPI = true e.Unlock() conn := e.pool.Get() defer conn.Close() defer func() { e.Lock() e.inAPI = false e.Unlock() }() e.app.RLock() apiKey := e.app.config.ChannelPrefix + "." + "api" e.app.RUnlock() done := make(chan struct{}) bodies := make(chan []byte, 256) defer close(done) go func() { for { select { case body, ok := <-bodies: if !ok { return } var req redisApiRequest err := json.Unmarshal(body, &req) if err != nil { logger.ERROR.Println(err) continue } for _, command := range req.Data { _, err := e.app.apiCmd(command) if err != nil { logger.ERROR.Println(err) } } case <-done: return } } }() for { reply, err := conn.Do("BLPOP", apiKey, 0) if err != nil { logger.ERROR.Println(err) return } values, err := redis.Values(reply, nil) if err != nil { logger.ERROR.Println(err) return } if len(values) != 2 { logger.ERROR.Println("Wrong reply from Redis in BLPOP - expecting 2 values") continue } body, okValue := values[1].([]byte) if !okValue { logger.ERROR.Println("Wrong reply from Redis in BLPOP - can not value convert to bytes") continue } bodies <- body } }
func (e *RedisEngine) runAPI() { conn := e.pool.Get() defer conn.Close() e.app.RLock() apiKey := e.app.config.ChannelPrefix + "." + "api" e.app.RUnlock() done := make(chan struct{}) defer close(done) popParams := []interface{}{apiKey} workQueues := make(map[string]chan []byte) workQueues[apiKey] = make(chan []byte, 256) for i := 0; i < e.numApiShards; i++ { queueKey := fmt.Sprintf("%s.%d", apiKey, i) popParams = append(popParams, queueKey) workQueues[queueKey] = make(chan []byte, 256) } // Add timeout param popParams = append(popParams, 0) // Start a worker for each queue for name, ch := range workQueues { go func(name string, in <-chan []byte) { logger.INFO.Printf("Starting worker for API queue %s", name) for { select { case body, ok := <-in: if !ok { return } var req redisAPIRequest err := json.Unmarshal(body, &req) if err != nil { logger.ERROR.Println(err) continue } for _, command := range req.Data { _, err := e.app.apiCmd(command) if err != nil { logger.ERROR.Println(err) } } case <-done: return } } }(name, ch) } for { reply, err := conn.Do("BLPOP", popParams...) if err != nil { logger.ERROR.Println(err) return } values, err := redis.Values(reply, nil) if err != nil { logger.ERROR.Println(err) return } if len(values) != 2 { logger.ERROR.Println("Wrong reply from Redis in BLPOP - expecting 2 values") continue } queue, okQ := values[0].([]byte) body, okVal := values[1].([]byte) if !okQ || !okVal { logger.ERROR.Println("Wrong reply from Redis in BLPOP - can not convert value") continue } // Pick worker based on queue q, ok := workQueues[string(queue)] if !ok { logger.ERROR.Println("Got message from a queue we didn't even know about!") continue } q <- body } }
ve(redis.Ints(nil, nil)), ve([]int(nil), redis.ErrNil), }, { "strings([v1, v2])", ve(redis.Strings([]interface{}{[]byte("v1"), []byte("v2")}, nil)), ve([]string{"v1", "v2"}, nil), }, { "strings(nil)", ve(redis.Strings(nil, nil)), ve([]string(nil), redis.ErrNil), }, { "values([v1, v2])", ve(redis.Values([]interface{}{[]byte("v1"), []byte("v2")}, nil)), ve([]interface{}{[]byte("v1"), []byte("v2")}, nil), }, { "values(nil)", ve(redis.Values(nil, nil)), ve([]interface{}(nil), redis.ErrNil), }, { "float64(1.0)", ve(redis.Float64([]byte("1.0"), nil)), ve(float64(1.0), nil), }, { "float64(nil)", ve(redis.Float64(nil, nil)),