Problem: Build a Flexible Product Query Builder

Medium
30 min
Extend a query builder to support optional filters in a fluent, composable way.

Problem statement

You’re building a product search API for a marketplace. Currently, the backend utilizes fragile object literals to construct search queries with optional filters, such as category, price range, and tags. You’ve been asked to design a ProductQueryBuilder that lets developers fluently compose flexible search conditions, with a .build() method that outputs a clean query object.

Goal

Implement a ProductQueryBuilder with these chainable methods:

  • .inCategory(category: string)

  • .withMinPrice(min: number)

  • .withMaxPrice(max: number)

  • .withTags(tags: string[])

  • .build(): Returns a query object with shape: { category?: string, price?: { min?: number, max?: number }, tags?: string[] }

If no filters were set, return an empty object.

Constraints

  • Do not return undefined keys—only include fields that were explicitly set.

  • Use a fluent API—no configuration objects or constructor arguments.

  • Keep internal state encapsulated and immutable from outside.

Sample output

The examples below illustrate what the output should look like:

// Category and tag filter
const query1 = new ProductQueryBuilder()
.inCategory('books')
.withTags(['fiction', 'bestseller'])
.build();
console.log(query1);
/* Expected output:
{ category: 'books', tags: [ 'fiction', 'bestseller' ] } */
// Price range only
const query2 = new ProductQueryBuilder()
.withMinPrice(10)
.withMaxPrice(50)
.build();
console.log(query2);
/* Expected output:
{ price: { min: 10, max: 50 } } */
// All filters
const query3 = new ProductQueryBuilder()
.inCategory('electronics')
.withMinPrice(100)
.withMaxPrice(500)
.withTags(['gaming', '4k'])
.build();
console.log(query3);
/* Expected output:
{ category: 'electronics',
price: { min: 100, max: 500 },
tags: [ 'gaming', '4k' ] } */
// No filters
const query4 = new ProductQueryBuilder().build();
console.log(query4);
/* Expected output:
{} */

Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.

Problem: Build a Flexible Product Query Builder

Medium
30 min
Extend a query builder to support optional filters in a fluent, composable way.

Problem statement

You’re building a product search API for a marketplace. Currently, the backend utilizes fragile object literals to construct search queries with optional filters, such as category, price range, and tags. You’ve been asked to design a ProductQueryBuilder that lets developers fluently compose flexible search conditions, with a .build() method that outputs a clean query object.

Goal

Implement a ProductQueryBuilder with these chainable methods:

  • .inCategory(category: string)

  • .withMinPrice(min: number)

  • .withMaxPrice(max: number)

  • .withTags(tags: string[])

  • .build(): Returns a query object with shape: { category?: string, price?: { min?: number, max?: number }, tags?: string[] }

If no filters were set, return an empty object.

Constraints

  • Do not return undefined keys—only include fields that were explicitly set.

  • Use a fluent API—no configuration objects or constructor arguments.

  • Keep internal state encapsulated and immutable from outside.

Sample output

The examples below illustrate what the output should look like:

// Category and tag filter
const query1 = new ProductQueryBuilder()
.inCategory('books')
.withTags(['fiction', 'bestseller'])
.build();
console.log(query1);
/* Expected output:
{ category: 'books', tags: [ 'fiction', 'bestseller' ] } */
// Price range only
const query2 = new ProductQueryBuilder()
.withMinPrice(10)
.withMaxPrice(50)
.build();
console.log(query2);
/* Expected output:
{ price: { min: 10, max: 50 } } */
// All filters
const query3 = new ProductQueryBuilder()
.inCategory('electronics')
.withMinPrice(100)
.withMaxPrice(500)
.withTags(['gaming', '4k'])
.build();
console.log(query3);
/* Expected output:
{ category: 'electronics',
price: { min: 100, max: 500 },
tags: [ 'gaming', '4k' ] } */
// No filters
const query4 = new ProductQueryBuilder().build();
console.log(query4);
/* Expected output:
{} */

Good luck trying the problem! If you’re unsure how to proceed, check the “Solution” tab above.

Node.js
class ProductQueryBuilder {
// implement methods here
}
// Example usage:
// Category and tag filter
const query1 = new ProductQueryBuilder()
.inCategory('books')
.withTags(['fiction', 'bestseller'])
.build();
console.log(query1);
/* Expected output:
{ category: 'books', tags: [ 'fiction', 'bestseller' ] } */
// Price range only
const query2 = new ProductQueryBuilder()
.withMinPrice(10)
.withMaxPrice(50)
.build();
console.log(query2);
/* Expected output:
{ price: { min: 10, max: 50 } } */
// All filters
const query3 = new ProductQueryBuilder()
.inCategory('electronics')
.withMinPrice(100)
.withMaxPrice(500)
.withTags(['gaming', '4k'])
.build();
console.log(query3);
/* Expected output:
{ category: 'electronics',
price: { min: 100, max: 500 },
tags: [ 'gaming', '4k' ] } */
// No filters
const query4 = new ProductQueryBuilder().build();
console.log(query4);
/* Expected output:
{} */