func realMain() int { var optr, optn bool flag.BoolVar(&optr, "r", false, "") flag.BoolVar(&optr, "read", false, "") flag.BoolVar(&optn, "n", false, "") flag.BoolVar(&optn, "new", false, "") flag.Usage = printUsage flag.Parse() if len(flag.Args()) == 0 { flag.Usage() return 0 } if len(flag.Args()) != 1 { fmt.Fprintf(os.Stderr, "Error: illegal argument.\n") flag.Usage() return 1 } path := flag.Arg(0) if optn { // only create new database if _, err := os.Stat(path); err == nil { fmt.Fprintf(os.Stderr, "Error: '%s' is already exists.\n", path) return 1 } ds, err := bucketstore.Open(path, 0600, nil) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v", err) return 1 } ds.Close() return 0 } // setup datastore options options := bucketstore.NewOptions() if optr { options.ReadOnly = true } // setup shell sh := shell.NewShell() sh.Path = path sh.Options = options if err := sh.Run(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) return 1 } return 0 }
func (sh *Shell) Run() error { // if the stdin is pipe, runs as a non-interactive mode if stat, _ := sh.Stdin.Stat(); (stat.Mode() & os.ModeCharDevice) == 0 { scanner := bufio.NewScanner(sh.Stdin) for scanner.Scan() { if err := sh.ExecCommand(scanner.Text()); err != nil { return err } } if err := scanner.Err(); err != nil { return err } return nil } // the following code runs on interactive mode if _, err := os.Stat(sh.Path); err != nil { // file not found. fmt.Printf("Database file '%s' was not found.\n", sh.Path) fmt.Print("Do you create initial database file? [y|N]: ") reader := bufio.NewReader(os.Stdin) if str, err := reader.ReadString('\n'); err == nil { str = strings.TrimRight(str, "\r\n") if str != "y" { return fmt.Errorf("the database has not been created.") } } // create new database. ds, err := bucketstore.Open(sh.Path, 0600, sh.Options) if err != nil { return err } ds.Close() } fmt.Println("Welcome to Bucketstore client. (hit ^D to exit)") fmt.Println("You can see the help by typing 'help' command.") fd := int(sh.Stdin.Fd()) oldState, err := terminal.MakeRaw(fd) if err != nil { return err } defer terminal.Restore(fd, oldState) term := terminal.NewTerminal(&shell{r: sh.Stdin, w: sh.Stdout}, "["+filepath.Base(sh.Path)+"]> ") if term == nil { return fmt.Errorf("could not create terminal") } for { line, err := term.ReadLine() if err != nil { break } if err := sh.ExecCommand(line); err != nil { return err } if sh.exit { break } } return nil }
func main() { // open database db, err := bucketstore.Open("my.db", 0600, nil) if err != nil { panic(err) } defer db.Close() bucket := db.Bucket("MyBucket") // put key/value item err = bucket.PutRaw([]byte("user001"), []byte(`{"name": "kohkimakimoto", "age": 36}`)) if err != nil { panic(err) } // get value v, err := bucket.GetRaw([]byte("user001")) if err != nil { panic(err) } fmt.Println(string(v)) // {"age":36,"name":"kohkimakimoto"} err = bucket.Delete([]byte("user001")) if err != nil { panic(err) } // put data err = bucket.PutRaw([]byte("user001"), []byte(`{"name": "hoge", "age": 20}`)) if err != nil { panic(err) } err = bucket.PutRaw([]byte("user002"), []byte(`{"name": "foo", "age": 31}`)) if err != nil { panic(err) } err = bucket.PutRaw([]byte("user003"), []byte(`{"name": "bar", "age": 18}`)) if err != nil { panic(err) } err = bucket.PutRaw([]byte("user004"), []byte(`{"name": "aaa", "age": 40}`)) if err != nil { panic(err) } err = bucket.PutRaw([]byte("user005"), []byte(`{"name": "xxx", "age": 41}`)) if err != nil { panic(err) } err = bucket.PutRaw([]byte("user006"), []byte(`{"name": "ccc", "age": 50}`)) if err != nil { panic(err) } // query q := bucket.Query() q.Filter = &bucketstore.PropValueRangeFilter{ Property: "age", Min: 20, Max: 40, } items, err := q.AsList() if err != nil { panic(err) } for _, item := range items { fmt.Println(string(item.Key), string(item.Value)) } // user001 {"age":20,"name":"hoge"} // user002 {"age":31,"name":"foo"} // user004 {"age":40,"name":"aaa"} }
func (sh *Shell) ExecCommand(line string) error { // in order to prevent locking the database, get a new datastore instance by each commands. ds, err := bucketstore.Open(sh.Path, 0600, sh.Options) if err != nil { return err } sh.DB = ds defer func() { ds.Close() sh.DB = nil }() tokens, err := Tokenize(line) if err != nil { sh.outputError(fmt.Sprintf("%v", err), false) return nil } if len(tokens) == 0 { return nil } // parse global options var pretty bool var removedIndexes = []int{} for i, token := range tokens { if token.DataType == DataTypeTerm && strings.HasPrefix(token.Buf, "-") { switch token.Buf { case "-p": pretty = true removedIndexes = append(removedIndexes, i) } } } // remove global options from tokens for i, idx := range removedIndexes { removedI := idx - i tokens = append(tokens[:removedI], tokens[removedI+1:]...) } defer func() { if err := recover(); err != nil { sh.outputError(fmt.Sprintf("%v", err), pretty) } }() if len(tokens) >= 1 { if tokens[0].DataType != DataTypeTerm { sh.outputError("syntax error: it is not a valid command.", pretty) return nil } if fn, ok := Cmds[tokens[0].Buf]; ok { res, err := fn(sh, tokens[1:]) if err != nil { sh.outputError(fmt.Sprintf("%v", err), pretty) } if res != nil { sh.output(res, pretty) } } else { sh.outputError(fmt.Sprintf("unknown command: %s", tokens[0].Buf), pretty) } } return nil }