package persistence import ( "strings" . "github.com/Masterminds/squirrel" "github.com/deluan/navidrome/log" "github.com/kennygrant/sanitize" ) const searchTable = "search" func (r sqlRepository) index(id string, text ...string) error { sanitizedText := strings.Builder{} for _, txt := range text { sanitizedText.WriteString(strings.TrimSpace(sanitize.Accents(strings.ToLower(txt))) + " ") } values := map[string]interface{}{ "id": id, "item_type": r.tableName, "full_text": strings.TrimSpace(sanitizedText.String()), } update := Update(searchTable).Where(Eq{"id": id}).SetMap(values) count, err := r.executeSQL(update) if err != nil { return err } if count > 0 { return nil } insert := Insert(searchTable).SetMap(values) _, err = r.executeSQL(insert) return err } func (r sqlRepository) doSearch(q string, offset, size int, results interface{}, orderBys ...string) error { q = strings.TrimSpace(sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))) if len(q) < 2 { return nil } sq := r.newSelectWithAnnotation(r.tableName + ".id").Columns("*") sq = sq.Limit(uint64(size)).Offset(uint64(offset)) if len(orderBys) > 0 { sq = sq.OrderBy(orderBys...) } sq = sq.Join("search").Where("search.id = " + r.tableName + ".id") parts := strings.Split(q, " ") for _, part := range parts { sq = sq.Where(Or{ Like{"full_text": part + "%"}, Like{"full_text": "%" + part + "%"}, }) } err := r.queryAll(sq, results) return err } func (r sqlRepository) cleanSearchIndex() error { del := Delete(searchTable).Where(Eq{"item_type": r.tableName}).Where("id not in (select id from " + r.tableName + ")") c, err := r.executeSQL(del) if err != nil { return err } if c > 0 { log.Debug(r.ctx, "Clean-up search index", "table", r.tableName, "totalDeleted", c) } return nil }