@@ -268,4 +268,105 @@ async def test_datetime_comparison_with_asyncpg(conn):
268268 # Should find User2 and User3 (created within last 15 minutes)
269269 assert len (rows ) == 2
270270 names = sorted ([row ['name' ] for row in rows ])
271- assert names == ['User2' , 'User3' ]
271+ assert names == ['User2' , 'User3' ]
272+
273+
274+ async def test_like_pattern_format_specs_with_postgres (conn ):
275+ """Test LIKE pattern format specs with PostgreSQL"""
276+ # Insert test data with special characters
277+ await conn .execute (
278+ "INSERT INTO test_users (name) VALUES ($1), ($2), ($3), ($4)" ,
279+ 'john_doe' , 'john%smith' , 'alice' , 'admin_50%'
280+ )
281+
282+ # Test contains pattern (%like%)
283+ search = "john"
284+ sql , params = tsql .render (
285+ t "SELECT name FROM test_users WHERE name LIKE {search:%like%} ORDER BY name" ,
286+ style = tsql .styles .NUMERIC_DOLLAR
287+ )
288+
289+ assert "ESCAPE '\\ '" in sql
290+ assert params == ['%john%' ]
291+
292+ rows = await conn .fetch (sql , * params )
293+
294+ # Should match both john_doe and john%smith
295+ assert len (rows ) == 2
296+ names = sorted ([row ['name' ] for row in rows ])
297+ assert names == ['john%smith' , 'john_doe' ]
298+
299+ # Test prefix pattern (like%)
300+ prefix = "admin"
301+ sql , params = tsql .render (
302+ t "SELECT name FROM test_users WHERE name LIKE {prefix:like%}" ,
303+ style = tsql .styles .NUMERIC_DOLLAR
304+ )
305+
306+ assert params == ['admin%' ]
307+
308+ rows = await conn .fetch (sql , * params )
309+
310+ # Should match admin_50%
311+ assert len (rows ) == 1
312+ assert rows [0 ]['name' ] == 'admin_50%'
313+
314+ # Test wildcard escaping - searching for literal underscore
315+ search = "john_"
316+ sql , params = tsql .render (
317+ t "SELECT name FROM test_users WHERE name LIKE {search:%like%}" ,
318+ style = tsql .styles .NUMERIC_DOLLAR
319+ )
320+
321+ # Should escape the underscore
322+ assert params == ['%john\\ _%' ]
323+
324+ rows = await conn .fetch (sql , * params )
325+
326+ # Should match only john_doe (literal underscore after "john")
327+ assert len (rows ) == 1
328+ assert rows [0 ]['name' ] == 'john_doe'
329+
330+ # Test wildcard escaping - searching for literal percent
331+ search = "50%"
332+ sql , params = tsql .render (
333+ t "SELECT name FROM test_users WHERE name LIKE {search:%like%}" ,
334+ style = tsql .styles .NUMERIC_DOLLAR
335+ )
336+
337+ # Should escape the percent
338+ assert params == ['%50\\ %%' ]
339+
340+ rows = await conn .fetch (sql , * params )
341+
342+ # Should match admin_50%
343+ assert len (rows ) == 1
344+ assert rows [0 ]['name' ] == 'admin_50%'
345+
346+ # Test suffix pattern (%like)
347+ suffix = "_doe"
348+ sql , params = tsql .render (
349+ t "SELECT name FROM test_users WHERE name LIKE {suffix:%like}" ,
350+ style = tsql .styles .NUMERIC_DOLLAR
351+ )
352+
353+ # Underscore should be escaped
354+ assert params == ['%\\ _doe' ]
355+
356+ rows = await conn .fetch (sql , * params )
357+
358+ # Should match john_doe
359+ assert len (rows ) == 1
360+ assert rows [0 ]['name' ] == 'john_doe'
361+
362+ # Test ILIKE (case-insensitive) works too
363+ search = "JOHN"
364+ sql , params = tsql .render (
365+ t "SELECT name FROM test_users WHERE name ILIKE {search:%like%}" ,
366+ style = tsql .styles .NUMERIC_DOLLAR
367+ )
368+
369+ rows = await conn .fetch (sql , * params )
370+
371+ # Should match both john_doe and john%smith (case-insensitive)
372+ assert len (rows ) == 2
0 commit comments