@@ -90,6 +90,7 @@ export interface PaginateConfig<T> {
9090 origin ?: string
9191 ignoreSearchByInQueryParam ?: boolean
9292 ignoreSelectInQueryParam ?: boolean
93+ multiWordSearch ?: boolean
9394}
9495
9596export enum PaginationLimit {
@@ -352,31 +353,75 @@ export async function paginate<T extends ObjectLiteral>(
352353 if ( query . search && searchBy . length ) {
353354 queryBuilder . andWhere (
354355 new Brackets ( ( qb : SelectQueryBuilder < T > ) => {
355- for ( const column of searchBy ) {
356- const property = getPropertiesByColumnName ( column )
357- const { isVirtualProperty, query : virtualQuery } = extractVirtualProperty ( qb , property )
358- const isRelation = checkIsRelation ( qb , property . propertyPath )
359- const isEmbeded = checkIsEmbedded ( qb , property . propertyPath )
360- const alias = fixColumnAlias (
361- property ,
362- qb . alias ,
363- isRelation ,
364- isVirtualProperty ,
365- isEmbeded ,
366- virtualQuery
367- )
368-
369- const condition : WherePredicateOperator = {
370- operator : 'ilike' ,
371- parameters : [ alias , `:${ property . column } ` ] ,
356+ // Explicitly handle the default case - multiWordSearch defaults to false
357+ const useMultiWordSearch = config . multiWordSearch ?? false
358+ if ( ! useMultiWordSearch ) {
359+ // Strict search mode (default behavior)
360+ for ( const column of searchBy ) {
361+ const property = getPropertiesByColumnName ( column )
362+ const { isVirtualProperty, query : virtualQuery } = extractVirtualProperty ( qb , property )
363+ const isRelation = checkIsRelation ( qb , property . propertyPath )
364+ const isEmbedded = checkIsEmbedded ( qb , property . propertyPath )
365+ const alias = fixColumnAlias (
366+ property ,
367+ qb . alias ,
368+ isRelation ,
369+ isVirtualProperty ,
370+ isEmbedded ,
371+ virtualQuery
372+ )
373+
374+ const condition : WherePredicateOperator = {
375+ operator : 'ilike' ,
376+ parameters : [ alias , `:${ property . column } ` ] ,
377+ }
378+
379+ if ( [ 'postgres' , 'cockroachdb' ] . includes ( queryBuilder . connection . options . type ) ) {
380+ condition . parameters [ 0 ] = `CAST(${ condition . parameters [ 0 ] } AS text)`
381+ }
382+
383+ qb . orWhere ( qb [ 'createWhereConditionExpression' ] ( condition ) , {
384+ [ property . column ] : `%${ query . search } %` ,
385+ } )
372386 }
373-
374- if ( [ 'postgres' , 'cockroachdb' ] . includes ( queryBuilder . connection . options . type ) ) {
375- condition . parameters [ 0 ] = `CAST(${ condition . parameters [ 0 ] } AS text)`
376- }
377-
378- qb . orWhere ( qb [ 'createWhereConditionExpression' ] ( condition ) , {
379- [ property . column ] : `%${ query . search } %` ,
387+ } else {
388+ // Multi-word search mode
389+ const searchWords = query . search . split ( ' ' ) . filter ( ( word ) => word . length > 0 )
390+ searchWords . forEach ( ( searchWord , index ) => {
391+ qb . andWhere (
392+ new Brackets ( ( subQb : SelectQueryBuilder < T > ) => {
393+ for ( const column of searchBy ) {
394+ const property = getPropertiesByColumnName ( column )
395+ const { isVirtualProperty, query : virtualQuery } = extractVirtualProperty (
396+ subQb ,
397+ property
398+ )
399+ const isRelation = checkIsRelation ( subQb , property . propertyPath )
400+ const isEmbedded = checkIsEmbedded ( subQb , property . propertyPath )
401+ const alias = fixColumnAlias (
402+ property ,
403+ subQb . alias ,
404+ isRelation ,
405+ isVirtualProperty ,
406+ isEmbedded ,
407+ virtualQuery
408+ )
409+
410+ const condition : WherePredicateOperator = {
411+ operator : 'ilike' ,
412+ parameters : [ alias , `:${ property . column } _${ index } ` ] ,
413+ }
414+
415+ if ( [ 'postgres' , 'cockroachdb' ] . includes ( queryBuilder . connection . options . type ) ) {
416+ condition . parameters [ 0 ] = `CAST(${ condition . parameters [ 0 ] } AS text)`
417+ }
418+
419+ subQb . orWhere ( subQb [ 'createWhereConditionExpression' ] ( condition ) , {
420+ [ `${ property . column } _${ index } ` ] : `%${ searchWord } %` ,
421+ } )
422+ }
423+ } )
424+ )
380425 } )
381426 }
382427 } )
0 commit comments