golangでRedisの参照と更新をする
golangを勉強することにしました。頑張るぞ
初回は A Tour of Go すら読んでいない状態で、勢いと感性のままにRedis Access をするCLI を作ります。
Redigoを選んだのは、Redis公式でrecommendされていたからです 🙃
main
package main import ( "encoding/json" "flag" "fmt" "github.com/gomodule/redigo/redis" "io/ioutil" "os" "redis-cli/entity" ) func main() { // parameterを受け取る var ( t = flag.String("t", "", doc()) u = flag.Bool("u", false, "update mode enabled?") ) flag.Parse() fmt.Printf("type: %s\n", *t) fmt.Printf("update: %t\n", *u) // entityType object et := entity.NewEntityType(*t) // entityType validation err := et.ValidateEntityType() if err != nil { fmt.Println(err.Error()) os.Exit(1) } // json file read && unmarshal raw, err := ioutil.ReadFile(et.JsonFilePath()) if err != nil { fmt.Println(err.Error()) os.Exit(1) } ec := unmarshal(raw, *et) // redis connect conn, err := redis.Dial("tcp", os.Getenv("REDIS_HOST")) if err != nil { fmt.Println(err.Error()) os.Exit(1) } defer conn.Close() // 更新前の情報を取得して出力する for _, e := range ec { fmt.Println("HGETALL Key:", e.Key()) val, _ := redis.StringMap(conn.Do("HGETALL", e.Key())) if val != nil { fmt.Println("Value:", val) } // 更新モードではない場合次へ if !*u { continue } // set value if update mode true fmt.Println("Set Value") // interfaceでポリモーフィズム的なことをする for k, v := range e.Values() { // skip empty value if len(v) == 0 { continue } fmt.Println("[HSET]", "SubKey:", k, "Value:", v) r, err := conn.Do("HSET", e.Key(), k, v) if err != nil { fmt.Println(err.Error()) os.Exit(1) } if r == 1 { fmt.Println("set new sub key:", k) } } fmt.Println("") } fmt.Println("Script end successfully.") } func unmarshal(raw []byte, t entity.Type) []entity.IEntity { switch t.V { case "book": var ec entity.BookCollection if err := json.Unmarshal(raw, &ec); err != nil { fmt.Println(err.Error()) os.Exit(1) } return ec.Collection() case "publisher": var ec entity.PublisherCollection if err := json.Unmarshal(raw, &ec); err != nil { fmt.Println(err.Error()) os.Exit(1) } return ec.Collection() default: panic("error") } } func doc() string { return ` set redis table type book publisher ` }
Entity
- Book と Publisher を用意
- InterfaceにIEntityを用意
package entity type IEntity interface { // keyを返す Key() string // HSETするvaluesをmapで返す Values() map[string]string }
package entity import "strconv" type BookCollection struct { Books []Book `json:"books"` } type Book struct { Isbn string `json:"isbn"` Price string `json:"price"` PublisherCode string `json:"publisherCode"` Authors []Author `json:"authors"` } type Author struct { Name string `json:"name"` } func (b Book) Key() string { return b.Isbn } func (b Book) Values() map[string]string { m := map[string]string{ "price": b.Price, "publisherCode": b.PublisherCode, } // authorは複数所持 for i, a := range b.Authors { m["author_"+strconv.Itoa(i)] = a.Name } return m } // object arrayをinterface arrayにして返す func (bc BookCollection) Collection() []IEntity { var entities []IEntity for _, b := range bc.Books { // objectをInterfaceにする var e IEntity = b entities = append(entities, e) } return entities }
package entity type PublisherCollection struct { Publishers []Publisher `json:"publishers"` } type Publisher struct { PublisherCode string `json:"publisherCode"` Name string `json:"name"` } func (p Publisher) Key() string { return p.PublisherCode } func (p Publisher) Values() map[string]string { return map[string]string{ "Name": p.Name, } } func (pc PublisherCollection) Collection() []IEntity { var entities []IEntity for _, p := range pc.Publishers { var e IEntity = p entities = append(entities, e) } return entities }
package entity import "errors" type Type struct { V string } func NewEntityType(v string) *Type { return &Type{V: v} } func (t Type) JsonFilePath() string { switch t.V { case "book": return "./json/book.json" case "publisher": return "./json/publisher.json" default: panic("error") } } func (t Type) ValidateEntityType() error { switch t.V { case "book", "publisher": return nil default: return errors.New("error") } }
json
book.json
{ "books" :[ { "isbn": "4000000000", "price": "1000", "publisherCode": "1000", "authors": [ { "name": "foo" } ] } ] }
まとめ
自分が正しい方向に進んでいるのかよくわからなくなったので基礎から勉強することにします 😑
目標はgoroutineを使いこなせるようになることです!