11import Product from "../models/product.model.js" ;
22import HttpException from "../utils/exceptions/http.exception.js" ;
3+ import { tokenize , buildLookaheadRegex } from "../utils/regex.util.js" ;
34
45// GET /api/collections/:name
56export const getCollectionProducts = async ( req , res , next ) => {
67 try {
78 const name = ( req . params ?. name || "" ) . toString ( ) . trim ( ) ;
8- // empty or invalid just returns empty results per spec
99 if ( ! name ) {
1010 return res . status ( 200 ) . json ( { collections : name , products : [ ] } ) ;
1111 }
1212
13- // Normalize input into a regex that is:
14- // - case-insensitive
15- // - tolerant of hyphens vs spaces vs multiple separators
16- // Escape regex special chars, then allow separators between words
17- const escapeRegex = ( s = "" ) => s . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, "\\$&" ) ;
18- const safe = escapeRegex ( name ) ;
19- // replace runs of hyphens / spaces / underscores with a pattern that matches any of them
20- const tolerant = safe . replace ( / [ - _ \s ] + / g, "[-_\\s]*" ) ;
21- const pattern = new RegExp ( `^${ tolerant } $` , "i" ) ;
13+ // try exact slug match first (fast, indexable if you add normalizedCollections)
14+ const slug = name . toLowerCase ( ) ;
15+ let products = await Product . find ( { collections : slug } ) ;
16+ if ( products && products . length ) {
17+ return res . status ( 200 ) . json ( { collections : name , products } ) ;
18+ }
19+
20+ // fallback: tokenize and build safe lookahead regex
21+ const tokens = tokenize ( name ) ;
22+ // safety limits
23+ if ( tokens . length === 0 ) {
24+ return res . status ( 200 ) . json ( { collections : name , products : [ ] } ) ;
25+ }
26+ if ( tokens . length > 6 || tokens . some ( t => t . length > 40 ) ) {
27+ return res . status ( 400 ) . json ( { collections : name , products : [ ] , message : "Query too complex" } ) ;
28+ }
2229
23- // Match any array element using $elemMatch + $regex
24- const products = await Product . find ( {
30+ const pattern = buildLookaheadRegex ( tokens ) ;
31+
32+ products = await Product . find ( {
2533 collections : { $elemMatch : { $regex : pattern } } ,
2634 } ) ;
2735
@@ -30,7 +38,4 @@ export const getCollectionProducts = async (req, res, next) => {
3038 console . error ( 'Collection controller error (getCollectionProducts):' , err ) ;
3139 next ( new HttpException ( 500 , "Failed to fetch collections products" ) ) ;
3240 }
33- }
34-
35-
36-
41+ }
0 commit comments