From 9f65427f30859f6153575d3f3f32efff83624b28 Mon Sep 17 00:00:00 2001 From: David Dworken Date: Sun, 2 Jun 2024 10:51:08 -0700 Subject: [PATCH] Add unfinished code for full text search using sqlite --- client/cmd/query.go | 3 ++- client/cmd/status.go | 3 +++ client/hctx/hctx.go | 28 +++++++++++++++++++++++++++- client/lib/lib.go | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/client/cmd/query.go b/client/cmd/query.go index c56bf3e..cfa6f76 100644 --- a/client/cmd/query.go +++ b/client/cmd/query.go @@ -37,7 +37,8 @@ var queryCmd = &cobra.Command{ DisableFlagParsing: true, Run: func(cmd *cobra.Command, args []string) { ctx := hctx.MakeContext() - lib.CheckFatalError(lib.ProcessDeletionRequests(ctx)) + fmt.Println("DDWORKENDEBUG: 1") + // lib.CheckFatalError(lib.ProcessDeletionRequests(ctx)) query(ctx, strings.Join(args, " ")) }, } diff --git a/client/cmd/status.go b/client/cmd/status.go index ce3541d..82ca459 100644 --- a/client/cmd/status.go +++ b/client/cmd/status.go @@ -25,6 +25,9 @@ var statusCmd = &cobra.Command{ printOnlineStatus(config) } fmt.Printf("Commit Hash: %s\n", lib.GitCommit) + results, err := lib.Search(ctx, hctx.GetDb(ctx), "foo", 10) + lib.CheckFatalError(err) + fmt.Printf("results=%#v\n", results) }, } diff --git a/client/hctx/hctx.go b/client/hctx/hctx.go index 1e9ab7a..487d990 100644 --- a/client/hctx/hctx.go +++ b/client/hctx/hctx.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "path" + "strings" "sync" "time" @@ -82,7 +83,7 @@ func OpenLocalSqliteDb() (*gorm.DB, error) { newLogger := logger.New( GetLogger().WithField("fromSQL", true), logger.Config{ - SlowThreshold: 100 * time.Millisecond, + SlowThreshold: time.Nanosecond, LogLevel: logger.Warn, IgnoreRecordNotFoundError: false, Colorful: false, @@ -107,9 +108,34 @@ func OpenLocalSqliteDb() (*gorm.DB, error) { db.Exec("CREATE INDEX IF NOT EXISTS start_time_index ON history_entries(start_time)") db.Exec("CREATE INDEX IF NOT EXISTS end_time_index ON history_entries(end_time)") db.Exec("CREATE INDEX IF NOT EXISTS entry_id_index ON history_entries(entry_id)") + /* + local_username, hostname, command, current_working_directory, exit_code, start_time, end_time, device_id, home_directory, entry_id, custom_columns + */ + queries := []string{ + "DROP TABLE ft", + "CREATE VIRTUAL TABLE ft USING fts5(local_username, hostname, command, current_working_directory, home_directory, custom_columns, content='history_entries')", + "INSERT INTO ft(ft) VALUES('rebuild')", + `SELECT * FROM ft WHERE (command MATCH "foo" OR local_username MATCH "foo" OR current_working_directory MATCH "foo")`, + } + for _, query := range queries { + danger(query, db.Exec(query)) + + } + fmt.Println("Done with FTS setup!") return db, nil } +func danger(query string, res *gorm.DB) { + fmt.Printf("Executing query=%q\n", query) + err := res.Error + if err != nil { + if strings.Contains(err.Error(), "no such table: ") && strings.Contains(query, "DROP TABLE ") { + return + } + panic(err) + } +} + type hishtoryContextKey string const ( diff --git a/client/lib/lib.go b/client/lib/lib.go index c90e0ed..ecd3316 100644 --- a/client/lib/lib.go +++ b/client/lib/lib.go @@ -745,8 +745,44 @@ func where(tx *gorm.DB, s string, v1 any, v2 any) *gorm.DB { panic(fmt.Sprintf("Impossible state: v1=%#v, v2=%#v", v1, v2)) } +func isSimpleQuery(tokens []string) bool { + for _, token := range tokens { + if strings.HasPrefix(token, "-") || containsUnescaped(token, ":") { + return false + } + } + return true +} + +func makeFtsQuery(ctx context.Context, db *gorm.DB, tokens []string) (*gorm.DB, error) { + fmt.Printf("makeFtsQuery: tokens=%#v\n", tokens) + + // tx := db.Exec("SELECT * FROM ft") + // for _, token := range tokens { + // tx = tx.Where("(command MATCH ? OR local_username MATCH ? OR current_working_directory MATCH ?)", token, token, token) + // } + // return tx, nil + query := "SELECT * FROM ft WHERE " + isFirst := true + args := []any{} + for _, token := range tokens { + if !isFirst { + query += " OR " + } + query += fmt.Sprintf("(command MATCH %q OR local_username MATCH %q OR current_working_directory MATCH %q)", token, token, token) + args = append(args, token, token, token) + isFirst = false + } + fmt.Printf("makeFtsQuery: %s\n", query) + return db.Exec(query), nil +} + func MakeWhereQueryFromSearch(ctx context.Context, db *gorm.DB, query string) (*gorm.DB, error) { tokens := tokenize(query) + if isSimpleQuery(tokens) { + fmt.Println("Calling makeFtsQuery") + return makeFtsQuery(ctx, db, tokens) + } tx := db.Model(&data.HistoryEntry{}).Where("true") for _, token := range tokens { if strings.HasPrefix(token, "-") { @@ -823,6 +859,7 @@ func retryingSearch(ctx context.Context, db *gorm.DB, query string, limit int, c } func parseNonAtomizedToken(token string) (string, any, any, any, error) { + // TODO: We probably should find a way to support searching based on custom columns here wildcardedToken := "%" + unescape(token) + "%" return "(command LIKE ? OR hostname LIKE ? OR current_working_directory LIKE ?)", wildcardedToken, wildcardedToken, wildcardedToken, nil }