diff --git a/cli/completer.go b/cli/completer.go index 1b17342..270a940 100644 --- a/cli/completer.go +++ b/cli/completer.go @@ -31,9 +31,11 @@ func cmdCompleter(d prompt.Document, cmd string) []prompt.Suggest { {Text: "ttl", Description: "ttl command"}, {Text: "show", Description: "show info"}, {Text: "keys", Description: "iterate keys"}, + {Text: "search", Description: "search for string in all values"}, {Text: "use", Description: "change db"}, {Text: "exit", Description: "exit buntdb shell client"}, {Text: "drop", Description: "drop the index"}, + {Text: "help", Description: "show available commands"}, } tx, _ := db.GetCurrentTransaction() if tx == nil { diff --git a/cli/executor.go b/cli/executor.go index 21db9d3..a99c039 100644 --- a/cli/executor.go +++ b/cli/executor.go @@ -7,7 +7,7 @@ import ( "strings" ) -type transactionRequireType int64 +type transactionRequireType uint8 const ( noNeed transactionRequireType = iota @@ -38,10 +38,12 @@ func BuntdbExecutor(s string) { } grammar := NewGrammar() + k := kong.Must( grammar, kong.Exit(grammar.ExitWrapper), ) + ctx, err := k.Parse(args) if grammar.Exit { return diff --git a/cli/grammar.go b/cli/grammar.go index fe41ead..93d5fc2 100644 --- a/cli/grammar.go +++ b/cli/grammar.go @@ -6,6 +6,7 @@ import ( "github.com/alecthomas/kong" "github.com/tidwall/buntdb" "os" + "strings" "time" ) @@ -103,6 +104,47 @@ func (k KeysGrammar) Run(ctx *kong.Context, tx *buntdb.Tx) error { }) } +type SearchGrammar struct { + Pattern string `arg:"" help:"the match pattern "` + Delete bool `optional:"" short:"c" help:"delete all keys found (DANGEROUS)"` +} + +func (s SearchGrammar) Run(ctx *kong.Context, tx *buntdb.Tx) error { + var keys []string + err := tx.AscendKeys("*", func(key, value string) bool { + if strings.Contains(value, s.Pattern) { + keys = append(keys, key) + fmt.Fprintf(ctx.Stdout, "%v : %v\n", key, value) + } + return true + }) + + if err != nil { + return err + } + + if !s.Delete { + return nil + } + + fmt.Fprintf(ctx.Stdout, "\n-------------------\n\nFound %d keys, written above. \nSleeping 10 seconds before we delete.\n", len(keys)) + for n := 0; n != 10; n++ { + time.Sleep(1 * time.Second) + fmt.Fprintf(ctx.Stdout, ".") + } + + for i, k := range keys { + if i == 0 { + fmt.Fprint(ctx.Stdout, "\n") + } + _, err := tx.Delete(k) + if err == nil { + fmt.Fprintf(ctx.Stdout, "Deleted: %v\n", k) + } + } + return nil +} + type UseGrammar struct { Path string `arg:"" help:"the new db path"` Create bool `optional:"" short:"c" help:"create new db if path doesn't exist'"` @@ -215,6 +257,18 @@ func (s *DropIndexGrammar) Run(ctx *kong.Context, tx *buntdb.Tx) error { return tx.DropIndex(s.Name) } +type HelpGrammar struct { + // +} + +func (h *HelpGrammar) Run(ctx *kong.Context) (err error) { + commands := "get\nset\ndel\nttl\nrbegin (begin a readonly transaction)\nrwbegin (begin a read/write transaction)\ncommit\nrollback\nshow\nkeys\nsearch\nuse\nshrink" + _, err = fmt.Fprintln(ctx.Stdout, + "Commands available:\n----------\n"+commands+"\n----------\nFor more help, try running a command with the -h switch.", + ) + return +} + type Grammar struct { Get GetGrammar `cmd:"" help:"get a value from key, return the value if key exists, or if non-exists."` Set SetGrammar `cmd:"" help:"set a key-value [ttl], return the old value, or if old value doesn't exist."` @@ -230,6 +284,8 @@ type Grammar struct { Shrink ShrinkGrammar `cmd:"" help:"run database shrink command"` Save SaveGrammar `cmd:"" help:"save the db to file"` Drop DropGrammar `cmd:"" help:"drop command"` + Search SearchGrammar `cmd:"" help:"Search for a string contained in any values"` + Help HelpGrammar `cmd:""` Exit bool `kong:"-"` }