From 423d084defec3f80b368ce80d9ea4975b6e339da Mon Sep 17 00:00:00 2001 From: manelcecs Date: Thu, 11 Jul 2024 09:57:18 +0200 Subject: [PATCH] Add 'distinct' clause --- src/db/util/raw-model.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/db/util/raw-model.ts b/src/db/util/raw-model.ts index 780f8e2c..ef66daa7 100644 --- a/src/db/util/raw-model.ts +++ b/src/db/util/raw-model.ts @@ -46,6 +46,16 @@ export type FindFn = ( */ skipValidation?: boolean; trx?: Knex.Transaction; + /** + * Uses `DISTINCT ON`, which is a feature unique to PostgreSQL. + * + * Keeps only the first row of each set of rows where the given (set of) column(s) is unique. + * Note that the “first row” of each set is unpredictable unless `ORDER BY` is used to + * ensure that the desired row appears first. If ordering is used, there is an important + * constraint, because the first expression of `ORDER BY` must be present **somewhere** in + * `DISTINCT ON` expressions. But, not all expressions of `ORDER BY` need to be in `DISTINCT ON`. + */ + distinct?: Array>; } & AdditionalArgs ) => Promise>>; @@ -161,6 +171,7 @@ export const defineRawModel = orderBy, skipValidation = false, trx, + distinct, } = {}) => { const builder = trx ? masterTable().transacting(trx) : replicaTable(); const query = builder.where(prepareCondition(where ?? {})).select('*'); @@ -180,6 +191,18 @@ export const defineRawModel = query.orderBy(orderBy); } + if (distinct && distinct.length >= 1) { + if ( + (orderBy?.length ?? 0) >= 1 && + orderBy?.at(0)?.column !== distinct.at(0) + ) { + throw new Error( + 'SELECT DISTINCT ON expressions must match initial ORDER BY expression' + ); + } + query.distinctOn(distinct); + } + const res = await query; if (skipValidation) {