typescript - Drizzle: funcție generică care creează interogare select cu paginare și număr total


Trebuie să rulez aceeași interogare de două ori pentru paginare:

  • Prima interogare: pentru a obține numărul total de rânduri.
  • A doua interogare: Pentru a obține datele pentru pagina curentă, ceea ce implică ordonarea datelor și aplicarea limit și offset.

Nucleul interogării este identic în ambele cazuri, diferențându-se doar prin câmpurile pe care le selectează și prin limita aplicată. Pentru a evita repetarea logicii interogării, am creat o funcție pentru a o genera:

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);

Această abordare funcționează, dar pierd siguranța tipului. Nu am descoperit cum să tipizez corect funcția query. Are cineva idei despre cum să facem să funcționeze acest lucru sau cum să abordăm această problemă diferit?

Răspuns #1

Pentru paginare:

withPagination<T extends PgSelect>(qb: T, page: number, pageSize: number) {
    return qb.limit(pageSize).offset((page - 1) * pageSize);
}

Pentru numărătoare:

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];
}

În sfârșit :

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);

Răspunsul #2

Am făcut asta în C# și SQL Server, așa că cred că aceleași principii ar trebui să se aplice și aici.

Mai întâi, doar numără rândurile. Poți folosi orice metodă consideri că este cea mai bună, cum ar fi funcția de numărare din baza de date.

În al doilea rând, obțineți datele limitate pe care le doriți, dar setați un parametru astfel încât să obțină întotdeauna decalajul. Ex: dacă inputul este 1, atunci primele 30 de rânduri. Dacă inputul este 2, atunci următoarele 30 de rânduri. Am realizat acest lucru creând o procedură SQL.

În al treilea rând, combină-le într-un Tuple. Am creat un C# Tuple<long,List<Object>> și din ceea ce am studiat despre TypeScript ar trebui să funcționeze la fel. Primul parametru avea numărul total de rânduri și al doilea parametru avea datele rândurilor sub forma unei liste, care este o colecție de obiecte sigură din punct de vedere al tipurilor.