From 0a38ec08388c9d2716f9e41185af0bcfb0ed7f8d Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 5 Mar 2026 00:12:15 +0100 Subject: [PATCH] fix: use ParadeDB v2 fuzzy prefix matching for search (#2346) Switch from legacy @@@ paradedb.match() to v2 ||| operator with ::pdb.fuzzy(1, t) cast. This enables prefix matching so 'landing' matches 'landingpages', and adds single-character typo tolerance. --- pkg/db/helpers.go | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/pkg/db/helpers.go b/pkg/db/helpers.go index 915acba5f..77aeb5947 100644 --- a/pkg/db/helpers.go +++ b/pkg/db/helpers.go @@ -52,25 +52,18 @@ func MultiFieldSearch(fields []string, search string) builder.Cond { // for non-ParadeDB queries and the id field for ParadeDB queries. func MultiFieldSearchWithTableAlias(fields []string, search, tableAlias string) builder.Cond { if Type() == schemas.POSTGRES && paradedbInstalled { - if len(fields) == 1 { - // Single field search - use optimized match function - return builder.Expr("id @@@ paradedb.match(?, ?)", fields[0], search) - } - // Multi-field search - use disjunction_max for optimal performance - fieldMatches := make([]string, len(fields)) - args := make([]interface{}, len(fields)*2) + conditions := make([]builder.Cond, len(fields)) for i, field := range fields { - fieldMatches[i] = "paradedb.match(?, ?)" - args[i*2] = field - args[i*2+1] = search + fieldName := field + if tableAlias != "" { + fieldName = tableAlias + "." + field + } + conditions[i] = builder.Expr(fieldName+" ||| ?::pdb.fuzzy(1, t)", search) } - - idField := "`id`" - if tableAlias != "" { - idField = "`" + tableAlias + "`.`id`" + if len(conditions) == 1 { + return conditions[0] } - - return builder.Expr(idField+" @@@ paradedb.disjunction_max(ARRAY["+strings.Join(fieldMatches, ", ")+"])", args...) + return builder.Or(conditions...) } // For non-PostgreSQL databases, use ILIKE on all fields