package main import ( "bufio" "flag" "fmt" "os" "strings" "g.arns.lt/zordsdavini/zordfsdb" ) var ( rootDir string executeCommand string lastPath string lastKey string ) func main() { flag.StringVar(&rootDir, "d", "./", "database root directory") flag.StringVar(&executeCommand, "e", "", "execute command") flag.Parse() db, err := zordfsdb.InitDB(rootDir) if err != nil { panic(err) } if len(executeCommand) > 0 { ExecuteCommand(db, executeCommand) } else { reader := bufio.NewReader(os.Stdin) fmt.Println("ZordFsDB Shell") fmt.Println("---------------------") fmt.Println("DB initialized at ", rootDir) fmt.Println("") fmt.Println("Copyright (c) 2024 zordsdavini@arns.lt under MIT license") fmt.Println("") fmt.Println("Type HELP to get list of commands or QUIT to get out") fmt.Println("") for { fmt.Print("zordfsdb> ") text, _ := reader.ReadString('\n') // convert CRLF to LF text = strings.Replace(text, "\n", "", -1) if strings.Compare("QUIT", strings.ToUpper(text)) == 0 || strings.Compare("\\Q", strings.ToUpper(text)) == 0 { fmt.Println("\nBye o/") break } if strings.Compare("HELP", strings.ToUpper(text)) == 0 || strings.Compare("\\H", strings.ToUpper(text)) == 0 { fmt.Println(` ZordFsDB shell supported commands: KEYS [path] - get list of existing properties/objects/lists GET [path] - get value of property INC [path] - increase abcex value in property DEC [path] - decrease abcex value in property NOW [path] - set value to datetime string in property DEL [path] - remove property/object/list (no confirmation) SAVE [path] [value] - set value to property CREATE [path] - create list/object in path (parent path should exist) ADD [path] - add abcex indexed object to list. Will return index INFO [path] - get all info about property/object/list TREE [path] - draw db part in path with values HELP - will print this help QUIT - exit the shell Last used path can be accessed by _ Last returned index (after ADD command) can be accessed by $ Short commands can be as: KEYS(\K), GET(\G), INC(\I), DEC(\D), NOW(\N), DEL(\R), SAVE(\S), CREATE(\C), ADD(\A), INFO(\?), TREE(\T), HELP(\H), QUIT(\Q) `) continue } ExecuteCommand(db, text) } } } func ExecuteCommand(db zordfsdb.DB, commands string) error { for _, command := range strings.Split(commands, ";") { command = strings.Trim(command, " ") parts := strings.Split(command, " ") if len(parts) > 1 { if lastPath != "" { if parts[1] == "_" { parts[1] = lastPath } else { parts[1] = strings.Replace(parts[1], "_.", lastPath+".", 1) } } if lastKey != "" { parts[1] = strings.Replace(parts[1], "$", lastKey, 1) } lastPath = parts[1] } switch strings.ToUpper(parts[0]) { case "KEYS": case "\\K": kpath := "." if !(len(parts) == 1 || len(parts[1]) == 0) { kpath = parts[1] } fmt.Printf("{%s} KEYS: ", kpath) fmt.Println(db.Keys(kpath)) fmt.Println("") break case "INFO": case "\\?": if len(parts) == 1 || len(parts[1]) == 0 { return fmt.Errorf("err format: INFO [path]\n") } node, ok := db.GetNode(parts[1]) if !ok { fmt.Println("No path found.") fmt.Println("") } else { fmt.Printf("{%s} INFO\n-----------------\n", parts[1]) ntype := "property" if node.List { ntype = "list" } else if node.Object { ntype = "object" } fmt.Println("type:", ntype) if ntype == "property" { fmt.Println("value:", node.Value) } else { fmt.Println("keys:", db.Keys(parts[1])) } fmt.Println("") } break case "TREE": case "\\T": if len(parts) == 1 || len(parts[1]) == 0 || parts[1] == "." { fmt.Printf("TREE\n-----------------\n\\\n") printNodeTree(&db, 1) fmt.Println("") break } node, ok := db.GetNode(parts[1]) if !ok { return fmt.Errorf("err format: TREE [path]\n") } else { fmt.Printf("{%s} TREE\n-----------------\n", parts[1]) if !node.List && !node.Object { fmt.Printf("%s: %s\n\n", node.Key, node.Value) break } fmt.Println(node.Key) printNodeTree(&node, 1) } fmt.Println("") break case "GET": case "\\G": if len(parts) == 1 || len(parts[1]) == 0 { return fmt.Errorf("err format: GET [path]\n") } value, ok := db.Get(parts[1]) if !ok { fmt.Println("No value found.") fmt.Println("") } else { fmt.Printf("{%s} VALUE: ", parts[1]) fmt.Println(value) fmt.Println("") } break case "INC": case "\\I": if len(parts) == 1 || len(parts[1]) == 0 { return fmt.Errorf("err format: INC [path]\n") } ok := db.Inc(parts[1]) if !ok { fmt.Println("No value found.") fmt.Println("") } else { fmt.Printf("{%s} INC OK\n", parts[1]) fmt.Println("") } break case "DEC": case "\\D": if len(parts) == 1 || len(parts[1]) == 0 { return fmt.Errorf("err format: DEC [path]\n") } ok := db.Dec(parts[1]) if !ok { fmt.Println("No value found.") fmt.Println("") } else { fmt.Printf("{%s} DEC OK\n", parts[1]) fmt.Println("") } break case "NOW": case "\\N": if len(parts) == 1 || len(parts[1]) == 0 { return fmt.Errorf("err format: NOW [path]\n") } ok := db.Now(parts[1]) if !ok { fmt.Println("No value found.") fmt.Println("") } else { fmt.Printf("{%s} NOW OK\n", parts[1]) fmt.Println("") } break case "DEL": case "\\R": if len(parts) == 1 || len(parts[1]) == 0 { return fmt.Errorf("err format: DEL [path]\n") } ok := db.Del(parts[1]) if !ok { fmt.Println("No value/object found.") fmt.Println("") } else { fmt.Printf("{%s} DELETED\n", parts[1]) fmt.Println("") } break case "SAVE": case "\\S": if len(parts) < 3 || len(parts[1]) == 0 { return fmt.Errorf("err format: SAVE [path] [value|long value]\n") } value := strings.Trim(strings.Join(parts[2:], " "), "\"") ok := db.Save(parts[1], value) if !ok { fmt.Println("No value found.") fmt.Println("") } else { fmt.Printf("{%s} SAVED\n", parts[1]) fmt.Println("") } db.Refresh() break case "CREATE": case "\\C": if len(parts) == 1 || len(parts[1]) == 0 { return fmt.Errorf("err format: CREATE [path]\n") } ok := db.CreateNode(parts[1]) if !ok { fmt.Println("No path found.") fmt.Println("") } else { fmt.Printf("{%s} CREATED\n", parts[1]) fmt.Println("") } break case "ADD": case "\\A": if len(parts) == 1 || len(parts[1]) == 0 { return fmt.Errorf("err format: ADD [path]\n") } id, err := db.AddObject(parts[1]) if err != nil { fmt.Println("No path found.") fmt.Println("") } else { fmt.Printf("{%s} ADDED with ID: %s\n", parts[1], id) fmt.Println("") lastKey = id } break default: fmt.Println("err[00] unknown command, try HELP") } } return nil } func printNodeTree(node zordfsdb.GetNodes, i int) { for key, child := range node.GetNodes() { j := i - 1 for j > 0 { fmt.Printf("│ ") j-- } fmt.Printf("├── %s", key) if !child.List && !child.Object { fmt.Printf(": %s\n", child.Value) } else { fmt.Println("") printNodeTree(&child, i+1) } } }