기본적으로 Drizzle의 모든 쿼리 빌더는 가능한 한 SQL을 따르려고 하기 때문에, 대부분의 메서드를 한 번만 호출할 수 있습니다.
예를 들어, SELECT 문에는 WHERE 절이 하나만 있을 수 있으므로 .where()를 한 번만 호출할 수 있습니다:
const query = db .select() .from(users) .where(eq(users.id, 1)) .where(eq(users.name, 'John')); // ❌ Type error - where() can only be invoked once
이전 ORM 버전에서는 이러한 제한이 구현되지 않았을 때, 이 예제는 많은 사용자들에게 혼란의 원인이었습니다. 사용자들은 쿼리 빌더가 여러 .where() 호출을 단일 조건으로 “병합”할 것으로 예상했기 때문입니다.
이 동작은 기존 쿼리 빌딩, 즉 전체 쿼리를 한 번에 생성할 때 유용합니다.
그러나 동적으로 쿼리를 빌드하려고 할 때, 즉 쿼리 빌더를 받아서 향상시키는 공유 함수가 있는 경우 문제가 됩니다.
이 문제를 해결하기 위해 Drizzle은 쿼리 빌더를 위한 특별한 ‘dynamic’ 모드를 제공하며, 이는 메서드를 한 번만 호출해야 하는 제한을 제거합니다.
이를 활성화하려면 쿼리 빌더에서 .$dynamic()을 호출해야 합니다.
제공된 페이지 번호와 선택적 페이지 크기를 기반으로 쿼리에 LIMIT과 OFFSET 절을 추가하는 간단한 withPagination 함수를 구현하여 작동 방식을 살펴보겠습니다:
function withPagination<T extends PgSelect>( qb: T, page: number = 1, pageSize: number = 10,) { return qb.limit(pageSize).offset((page - 1) * pageSize);}const query = db.select().from(users).where(eq(users.id, 1));withPagination(query, 1); // ❌ Type error - the query builder is not in dynamic modeconst dynamicQuery = query.$dynamic();withPagination(dynamicQuery, 1); // ✅ OK
withPagination 함수는 제네릭이므로, 내부에서 쿼리 빌더의 결과 타입을 수정할 수 있습니다. 예를 들어 조인을 추가할 수 있습니다: