Add unfinished code for full text search using sqlite

This commit is contained in:
David Dworken 2024-06-02 10:51:08 -07:00
parent 110eb38127
commit 9f65427f30
No known key found for this signature in database
4 changed files with 69 additions and 2 deletions

View File

@ -37,7 +37,8 @@ var queryCmd = &cobra.Command{
DisableFlagParsing: true, DisableFlagParsing: true,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
ctx := hctx.MakeContext() ctx := hctx.MakeContext()
lib.CheckFatalError(lib.ProcessDeletionRequests(ctx)) fmt.Println("DDWORKENDEBUG: 1")
// lib.CheckFatalError(lib.ProcessDeletionRequests(ctx))
query(ctx, strings.Join(args, " ")) query(ctx, strings.Join(args, " "))
}, },
} }

View File

@ -25,6 +25,9 @@ var statusCmd = &cobra.Command{
printOnlineStatus(config) printOnlineStatus(config)
} }
fmt.Printf("Commit Hash: %s\n", lib.GitCommit) 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)
}, },
} }

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"os" "os"
"path" "path"
"strings"
"sync" "sync"
"time" "time"
@ -82,7 +83,7 @@ func OpenLocalSqliteDb() (*gorm.DB, error) {
newLogger := logger.New( newLogger := logger.New(
GetLogger().WithField("fromSQL", true), GetLogger().WithField("fromSQL", true),
logger.Config{ logger.Config{
SlowThreshold: 100 * time.Millisecond, SlowThreshold: time.Nanosecond,
LogLevel: logger.Warn, LogLevel: logger.Warn,
IgnoreRecordNotFoundError: false, IgnoreRecordNotFoundError: false,
Colorful: 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 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 end_time_index ON history_entries(end_time)")
db.Exec("CREATE INDEX IF NOT EXISTS entry_id_index ON history_entries(entry_id)") 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 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 type hishtoryContextKey string
const ( const (

View File

@ -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)) 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) { func MakeWhereQueryFromSearch(ctx context.Context, db *gorm.DB, query string) (*gorm.DB, error) {
tokens := tokenize(query) tokens := tokenize(query)
if isSimpleQuery(tokens) {
fmt.Println("Calling makeFtsQuery")
return makeFtsQuery(ctx, db, tokens)
}
tx := db.Model(&data.HistoryEntry{}).Where("true") tx := db.Model(&data.HistoryEntry{}).Where("true")
for _, token := range tokens { for _, token := range tokens {
if strings.HasPrefix(token, "-") { 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) { 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) + "%" wildcardedToken := "%" + unescape(token) + "%"
return "(command LIKE ? OR hostname LIKE ? OR current_working_directory LIKE ?)", wildcardedToken, wildcardedToken, wildcardedToken, nil return "(command LIKE ? OR hostname LIKE ? OR current_working_directory LIKE ?)", wildcardedToken, wildcardedToken, wildcardedToken, nil
} }