193 lines
5.7 KiB
TypeScript
193 lines
5.7 KiB
TypeScript
// 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<any, any>;
|
|
|
|
// /**
|
|
// * 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<T extends PgTable>({ // Adjusted for PgTable
|
|
// db,
|
|
// table,
|
|
// page = 1,
|
|
// limit = 10,
|
|
// whereClause,
|
|
// }: {
|
|
// db: DrizzleDB;
|
|
// table: PgTableWithColumns<any>;
|
|
// 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<any, any>;
|
|
|
|
/**
|
|
* 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<T extends PgTable>({
|
|
db,
|
|
table,
|
|
page = 1,
|
|
limit = 10,
|
|
filters, // Now using FilterCondition[]
|
|
}: {
|
|
db: DrizzleDB;
|
|
table: PgTableWithColumns<any>;
|
|
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,
|
|
};
|
|
} |