// import { count, SQL } from "drizzle-orm"; // import { PgDatabase, PgTable, PgTableWithColumns } from "drizzle-orm/pg-core"; // // import { AnyTable } from 'drizzle-orm'; // // Adjust if you use SQLite or another database // type DrizzleDB = PgDatabase; // /** // * Generic pagination utility for Drizzle ORM. // * // * @template T - The Drizzle ORM schema table type. // * @param {DrizzleDB} db - The Drizzle ORM database instance. // * @param {T} table - The Drizzle ORM schema table to paginate. // * @param {number} page - The current page number (1-indexed). // * @param {number} limit - The number of items per page. // * @param {SQL | undefined} whereClause - Optional Drizzle SQL condition for filtering. // * @returns {Promise<{ data: T[], totalRecords: number, totalPages: number, currentPage: number, pageSize: number }>} // */ // export async function paginate({ // Adjusted for PgTable // db, // table, // page = 1, // limit = 10, // whereClause, // }: { // db: DrizzleDB; // table: PgTableWithColumns; // page: number; // limit: number; // whereClause?: SQL | undefined; // Add optional where clause for filtering // }): Promise<{ // data: (typeof table.$inferSelect)[]; // Use $inferSelect for proper type inference // totalRecords: number; // totalPages: number; // currentPage: number; // pageSize: number; // }> { // if (page < 1) page = 1; // if (limit < 1) limit = 10; // const offset = (page - 1) * limit; // // Build the query // let query = db.select().from(table).$dynamic(); // Use $dynamic to conditionally add clauses // if (whereClause) { // query = query.where(whereClause); // } // const dataPromise = query.limit(limit).offset(offset).execute(); // // Get the total count, potentially with the same where clause // let countQuery = db // .select({ // count: count(), // }) // .from(table) // .$dynamic(); // if (whereClause) { // countQuery = countQuery.where(whereClause); // } // const countPromise = countQuery.execute(); // const [data, [countResult]] = await Promise.all([dataPromise, countPromise]); // const totalRecords = countResult?.count || 0; // const totalPages = Math.ceil(totalRecords / limit); // return { // data: data, // totalRecords, // totalPages, // currentPage: page, // pageSize: limit, // }; // } import { and, count, SQL } from "drizzle-orm"; import { PgDatabase, PgTable, PgTableWithColumns } from "drizzle-orm/pg-core"; import { FilterCondition } from "../../lib/types"; type DrizzleDB = PgDatabase; /** * Generic pagination utility for Drizzle ORM. * * @template T - The Drizzle ORM schema table type. * @param {DrizzleDB} db - The Drizzle ORM database instance. * @param {T} table - The Drizzle ORM schema table to paginate. * @param {number} page - The current page number (1-indexed). * @param {number} limit - The number of items per page. * @param {FilterCondition[] | undefined} filters - An array of filter conditions, which can be single SQL expressions or nested 'and'/'or' groups. * @returns {Promise<{ data: T[], totalRecords: number, totalPages: number, currentPage: number, pageSize: number }>} */ export async function paginate({ db, table, page = 1, limit = 10, filters, // Now using FilterCondition[] }: { db: DrizzleDB; table: PgTableWithColumns; page?: number; limit?: number; filters?: FilterCondition[]; // Accepts the new structured filters }): Promise<{ data: (typeof table.$inferSelect)[]; totalRecords: number; totalPages: number; currentPage: number; pageSize: number; }> { if (page < 1) page = 1; if (limit < 1) limit = 10; const offset = (page - 1) * limit; // Helper function to process the nested filter conditions const buildWhereClause = (conditions?: FilterCondition[]): SQL | undefined => { if (!conditions || conditions.length === 0) { return undefined; } const builtConditions: SQL[] = []; for (const condition of conditions) { if (condition instanceof SQL) { builtConditions.push(condition); } else if ('and' in condition && Array.isArray(condition.and)) { const nestedAnd = buildWhereClause(condition.and); if (nestedAnd) { builtConditions.push(nestedAnd); } } else if ('or' in condition && Array.isArray(condition.or)) { const nestedOr = buildWhereClause(condition.or); if (nestedOr) { builtConditions.push(nestedOr); } } } // By default, if multiple top-level conditions are provided without an explicit operator, // we'll combine them with 'AND'. If you want a different default, adjust here. if (builtConditions.length === 1) { return builtConditions[0]; } else if (builtConditions.length > 1) { return and(...builtConditions); } return undefined; }; const finalWhereClause = buildWhereClause(filters); // Build the query let query = db.select().from(table).$dynamic(); if (finalWhereClause) { query = query.where(finalWhereClause); } const dataPromise = query.limit(limit).offset(offset).execute(); // Get the total count, potentially with the same where clause let countQuery = db .select({ count: count(), }) .from(table) .$dynamic(); if (finalWhereClause) { countQuery = countQuery.where(finalWhereClause); } const countPromise = countQuery.execute(); const [data, [countResult]] = await Promise.all([dataPromise, countPromise]); const totalRecords = countResult?.count || 0; const totalPages = Math.ceil(totalRecords / limit); return { data: data.reverse(), totalRecords, totalPages, currentPage: page, pageSize: limit, }; }