fix(table): escape LIKE wildcards in $contains filter values (#3949)

The $contains filter operator builds an ILIKE pattern but does not
escape LIKE wildcard characters (%, _) in user-provided values.

This causes incorrect, over-broad query results when the search value
contains these characters. For example, filtering with
{ name: { $contains: "100%" } } matches any row where name
contains "100" followed by anything, not just the literal "100%".

Escape %, _, and \ in the value before interpolating into the ILIKE
pattern so that they match literally.

Co-authored-by: Waleed <walif6@gmail.com>
Co-authored-by: lawrence3699 <lawrence3699@users.noreply.github.com>
This commit is contained in:
chaoliang yan
2026-04-08 01:49:43 +10:00
committed by GitHub
parent f46886e6cf
commit d5bea5f266

View File

@@ -322,10 +322,15 @@ function buildComparisonClause(
return sql`(${sql.raw(`${tableName}.data->>'${escapedField}'`)})::numeric ${sql.raw(operator)} ${value}`
}
/** Escapes LIKE/ILIKE wildcard characters so they match literally */
function escapeLikePattern(value: string): string {
return value.replace(/[\\%_]/g, '\\$&')
}
/** Builds case-insensitive pattern match: `data->>'field' ILIKE '%value%'` */
function buildContainsClause(tableName: string, field: string, value: string): SQL {
const escapedField = field.replace(/'/g, "''")
return sql`${sql.raw(`${tableName}.data->>'${escapedField}'`)} ILIKE ${`%${value}%`}`
return sql`${sql.raw(`${tableName}.data->>'${escapedField}'`)} ILIKE ${`%${escapeLikePattern(value)}%`}`
}
/**