TypeScript - Drizzle: تابع عمومی که کوئری انتخاب با صفحهبندی و تعداد کل ایجاد میکند
من نیاز دارم همان پرسوجو را دو بار برای صفحهبندی اجرا کنم:
- اولین پرس و جو: برای به دست آوردن تعداد کل ردیفها.
- پرس و جوی دوم: برای بازیابی دادههای صفحه فعلی، که شامل مرتبسازی دادهها و اعمال
limitوoffsetاست.
هستهٔ پرسوجو در هر دو مورد یکسان است، تنها در فیلدهایی که انتخاب میکنند و محدودیتهایی که اعمال میشود متفاوت است. برای جلوگیری از تکرار منطق پرسوجو، من یک تابع برای تولید آن ایجاد کردهام:
function query(fields: any): any {
return db
.select(fields)
.from(hotels)
.innerJoin(cities, eq(cities.id, hotels.city_id))
.where(eq(hotels.locale, 'cs'));
}
const total = await query({ count: count() });
const rows = await query({
id: hotels.id,
cityId: cities.id,
name: hotels.name,
})
.orderBy(hotels.id)
.limit(limit)
.offset(offset);
این روش کار میکند، اما من امنیت نوع (type safety) را از دست میدهم. هنوز نتوانستهام بفهمم چگونه تابع query را بهدرستی تایپ کنم. آیا کسی ایدهای دارد که چگونه این کار را عملی کنیم یا چگونه میتوان به این مشکل به شکل متفاوتی نزدیک شد؟
پاسخ شماره ۱
برای صفحهبندی:
withPagination<T extends PgSelect>(qb: T, page: number, pageSize: number) {
return qb.limit(pageSize).offset((page - 1) * pageSize);
}
برای شمارش:
async queryWithCount<T extends PgSelect>(qb: T): Promise<[Awaited<T>, number]> {
const result = await qb;
// @ts-ignore hack to override internals (not the ideal way)
qb.config.fields = { count: count() };
// @ts-ignore
qb.config.orderBy = [];
const [total] = await qb;
return [result, total.count];
}
در نهایت :
let qb = db
.select(fields)
.from(hotels)
.innerJoin(cities, eq(cities.id, hotels.city_id))
.where(eq(hotels.locale, 'cs'))
.orderBy(hotels.id)
.$dynamic();
qb = withPagination(qb, limit, offset);
const [rows, total] = await queryWithCount(qb);
پاسخ شماره ۲
من این کار را در C# و SQL Server انجام دادهام، بنابراین معتقدم همان اصول باید در اینجا هم اعمال شود.
اول، فقط ردیفها را بشمارید. میتوانید از هر روشی که بهترین میدانید استفاده کنید، مثل تابع شمارش در پایگاه داده.
ثانیاً، دادههای محدودی را که میخواهید دریافت کنید، اما یک پارامتر تنظیم کنید به طوری که همیشه افست را بگیرد. مثال: اگر ورودی ۱ باشد، سپس ۳۰ ردیف اول. اگر ورودی ۲ باشد، سپس ۳۰ ردیف بعدی. من این کار را با ایجاد یک رویه SQL انجام دادم.
سوم، آنها را در یک Tuple ترکیب کنید. من یک C# Tuple<long,List<Object>> ایجاد کردم و از آنچه که در مورد تایپاسکریپت مطالعه کردهام، باید به همان صورت کار کند. پارامتر اول تعداد کل ردیفها را داشت و پارامتر دوم دادههای ردیف را به صورت یک List داشت که یک مجموعه نوع ایمن از اشیاء است.
