Dynamic 'where' statements in Drizzle

July 17, 2024 3 minute read

Drizzle has quickly become my go-to ORM for Node.js applications. It offers a lot of flexibility and functionality while providing a great developer experience.

Recently, while working on Queuebase, I had a need for being able to append where clauses dynamically to my queries. Thankfully, because Drizzle is just TypeScript, this was a really simple thing to implement. Today, I’ll be showing you how to create dynamic where statements in Drizzle.

The Problem

Let’s say we have a product model in our database, and we want to fetch all products that have a price greater than 100. This is simple enough to do with a where clause.

const products = await db
  .select()
  .from(product)
  .where(gte(product.price, 100));

Now let’s say we want to fetch all products that have a price greater than 100, but only if they have a category of “electronics”. This is also simple to do, we just need to add a and call to our query.

const products = await db
  .select()
  .from(product)
  .where(and(
    gte(product.price, 100), 
    eq(product.category, 'electronics')
));

This works, but it’s a bit verbose. This query assumes that we always want to filter by price and category. If we want to add more filters, we’ll need to add more and calls. And what if these filters are optional? We may not always want to filter by category, or have a start and stop price range.

Dynamically appending ‘where’ conditions

The solution here is to create an array of conditions. Then, we can pass our array to the where clause.

function getProducts(filters?: ProductFilters) {
  // Placeholder condition incase we don't have any filters
  const where = [eq(1, 1)];

  if (filters?.category) {
    where.push(eq(product.category, filters.category));
  }

  if (filters?.priceRange?.start) {
    where.push(gte(product.price, filters.priceRange.start));
  }

  if (filters?.priceRange?.stop) {
    where.push(lte(product.price, filters.priceRange.stop));
  }

  const products = await db
    .select()
    .from(product)
    .where(and(...where));
}

Now, if we have no filters, we’ll get all products. If we have a category filter, we’ll get all products where the category matches. If we have a price range filter, we’ll get all products where the price is between the start and stop values. With this setup, we are now able to dynamically build our where clause and expand on it in the future if needed.

Resources

#drizzle
#typescript
#node

Newsletter

Brock's Bytes

Every Sunday, I share an exclusive email newsletter sharing my journey. If you're inesterest in code, technology, business, etc. this is the newsletter for you. Sign up now and join a growing community of readers!