From 02b13f0549851f1aa111ef28259f5ddf067c6e1a Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 5 Sep 2026 02:19:30 -0400 Subject: [PATCH] fix(pglite): count through a subquery and drop the rowid pagination trick A count built from a sorted builder failed with 'column must appear in the GROUP BY clause' (the library list); counting the ids in a subquery makes the carried ORDER BY harmless. optimizePagination relied on SQLite's rowid and is now a no-op. --- persistence/sql_base_repository.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/persistence/sql_base_repository.go b/persistence/sql_base_repository.go index c81be22c4..36ea8c2a4 100644 --- a/persistence/sql_base_repository.go +++ b/persistence/sql_base_repository.go @@ -457,14 +457,8 @@ func (r sqlRepository) queryAllSlice(sq SelectBuilder, response any) error { // optimizePagination uses a less inefficient pagination, by not using OFFSET. // See https://gist.github.com/ssokolow/262503 -func (r sqlRepository) optimizePagination(sq SelectBuilder, options model.QueryOptions) SelectBuilder { - if options.Offset > conf.Server.DevOffsetOptimize { - sq = sq.RemoveOffset() - rowidSq := sq.RemoveColumns().Columns(r.tableName + ".rowid") - rowidSq = rowidSq.Limit(uint64(options.Offset)) - rowidSql, args, _ := rowidSq.ToSql() - sq = sq.Where(r.tableName+".rowid not in ("+rowidSql+")", args...) - } +func (r sqlRepository) optimizePagination(sq SelectBuilder, _ model.QueryOptions) SelectBuilder { + // The SQLite rowid trick for deep offsets does not apply to PostgreSQL; plain OFFSET is used. return sq } @@ -535,11 +529,14 @@ func (r sqlRepository) classifyOwnedWriteMiss(id string) error { } func (r sqlRepository) count(countQuery SelectBuilder, options ...model.QueryOptions) (int64, error) { - countQuery = countQuery. - RemoveColumns().Columns("count(distinct " + r.tableName + ".id) as count"). + // Counted through a subquery so a sort carried by the builder (PostgreSQL rejects ORDER BY on + // a column that is neither grouped nor aggregated) stays harmless. + inner := countQuery. + RemoveColumns().Columns(r.tableName + ".id"). RemoveOffset().RemoveLimit(). From(r.tableName) - countQuery = r.applyFilters(countQuery, options...) + inner = r.applyFilters(inner, options...) + countQuery = Select("count(distinct t.id) as count").FromSelect(inner, "t") var res struct{ Count int64 } err := r.queryOne(countQuery, &res) return res.Count, err