github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/query/queryhistory/history.go (about) 1 package queryhistory 2 3 import ( 4 "encoding/json" 5 "io" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/turbot/steampipe/pkg/constants" 11 "github.com/turbot/steampipe/pkg/filepaths" 12 ) 13 14 // QueryHistory :: struct for working with history in the interactive mode 15 type QueryHistory struct { 16 history []string 17 } 18 19 // New creates a new QueryHistory object 20 func New() (*QueryHistory, error) { 21 history := &QueryHistory{history: []string{}} 22 err := history.load() 23 if err != nil { 24 return nil, err 25 } 26 return history, nil 27 } 28 29 // Push adds a string to the history queue trimming to maxHistorySize if necessary 30 func (q *QueryHistory) Push(query string) { 31 if len(strings.TrimSpace(query)) == 0 { 32 // do not store a blank query 33 return 34 } 35 36 // do a strict compare to see if we have this same exact query as the most recent history item 37 if lastElement := q.Peek(); lastElement != nil && (*lastElement) == query { 38 return 39 } 40 41 // limit the history length to HistorySize 42 historyLength := len(q.history) 43 if historyLength >= constants.HistorySize { 44 q.history = q.history[historyLength-constants.HistorySize+1:] 45 } 46 47 // append the new entry 48 q.history = append(q.history, query) 49 } 50 51 // Peek returns the last element of the history stack. 52 // returns nil if there is no history 53 func (q *QueryHistory) Peek() *string { 54 if len(q.history) == 0 { 55 return nil 56 } 57 return &q.history[len(q.history)-1] 58 } 59 60 // Persist writes the history to the filesystem 61 func (q *QueryHistory) Persist() error { 62 var file *os.File 63 var err error 64 defer func() { 65 file.Close() 66 }() 67 path := filepath.Join(filepaths.EnsureInternalDir(), constants.HistoryFile) 68 file, err = os.Create(path) 69 if err != nil { 70 return err 71 } 72 73 jsonEncoder := json.NewEncoder(file) 74 75 // disable indentation 76 jsonEncoder.SetIndent("", "") 77 78 return jsonEncoder.Encode(q.history) 79 } 80 81 // Get returns the full history 82 func (q *QueryHistory) Get() []string { 83 return q.history 84 } 85 86 // loads up the history from the file where it is persisted 87 func (q *QueryHistory) load() error { 88 path := filepath.Join(filepaths.EnsureInternalDir(), constants.HistoryFile) 89 file, err := os.Open(path) 90 if err != nil { 91 // ignore not exists errors 92 if os.IsNotExist(err) { 93 return nil 94 } 95 return err 96 97 } 98 defer file.Close() 99 100 decoder := json.NewDecoder(file) 101 err = decoder.Decode(&q.history) 102 // ignore EOF (caused by empty file) 103 if err == io.EOF { 104 return nil 105 } 106 return err 107 }