Skip to content

Commit 2feccba

Browse files
committed
Fix pagination to use indexed_at for chronological order
- Order by indexed_at DESC instead of uri for proper time ordering - Use indexed_at timestamp as cursor instead of URI - Load more now shows older posts in correct chronological order
1 parent 2dca380 commit 2feccba

2 files changed

Lines changed: 24 additions & 19 deletions

File tree

internal/database/repositories/records.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -242,21 +242,23 @@ func (r *RecordsRepository) GetByCollection(ctx context.Context, collection stri
242242
}
243243

244244
// GetByCollectionWithCursor retrieves records for a specific collection with cursor-based pagination.
245-
// The cursor is the URI of the last record from the previous page.
246-
func (r *RecordsRepository) GetByCollectionWithCursor(ctx context.Context, collection string, limit int, afterURI string) ([]*Record, error) {
245+
// The cursor is the indexed_at timestamp of the last record from the previous page.
246+
// Records are ordered by indexed_at DESC (newest first) for chronological feed display.
247+
func (r *RecordsRepository) GetByCollectionWithCursor(ctx context.Context, collection string, limit int, afterTimestamp string) ([]*Record, error) {
247248
var sqlStr string
248249
var args []any
249250

250-
if afterURI == "" {
251-
// No cursor - get first page
252-
sqlStr = fmt.Sprintf("SELECT %s FROM record WHERE collection = %s ORDER BY uri DESC LIMIT %d",
251+
if afterTimestamp == "" {
252+
// No cursor - get first page, ordered by indexed_at DESC (newest first)
253+
sqlStr = fmt.Sprintf("SELECT %s FROM record WHERE collection = %s ORDER BY indexed_at DESC, uri DESC LIMIT %d",
253254
r.recordColumns(), r.db.Placeholder(1), limit)
254255
args = []any{collection}
255256
} else {
256-
// With cursor - get records after the cursor (URI is used for stable ordering)
257-
sqlStr = fmt.Sprintf("SELECT %s FROM record WHERE collection = %s AND uri < %s ORDER BY uri DESC LIMIT %d",
257+
// With cursor - get records older than the cursor timestamp
258+
// Using indexed_at < cursor for "load more" (older posts)
259+
sqlStr = fmt.Sprintf("SELECT %s FROM record WHERE collection = %s AND indexed_at < %s ORDER BY indexed_at DESC, uri DESC LIMIT %d",
258260
r.recordColumns(), r.db.Placeholder(1), r.db.Placeholder(2), limit)
259-
args = []any{collection, afterURI}
261+
args = []any{collection, afterTimestamp}
260262
}
261263

262264
rows, err := r.db.DB().QueryContext(ctx, sqlStr, args...)

internal/graphql/schema/builder.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -321,18 +321,18 @@ func (b *Builder) createGenericRecordsResolver() graphql.FieldResolveFn {
321321
}
322322
after, _ := p.Args["after"].(string)
323323

324-
// Decode cursor to URI if provided
325-
var afterURI string
324+
// Decode cursor to timestamp if provided
325+
var afterTimestamp string
326326
if after != "" {
327327
var err error
328-
afterURI, err = decodeCursor(after)
328+
afterTimestamp, err = decodeCursor(after)
329329
if err != nil {
330330
return nil, fmt.Errorf("invalid cursor: %w", err)
331331
}
332332
}
333333

334-
// Query database with cursor
335-
records, err := repos.Records.GetByCollectionWithCursor(p.Context, collection, first+1, afterURI)
334+
// Query database with cursor (ordered by indexed_at DESC)
335+
records, err := repos.Records.GetByCollectionWithCursor(p.Context, collection, first+1, afterTimestamp)
336336
if err != nil {
337337
return nil, fmt.Errorf("failed to query records: %w", err)
338338
}
@@ -354,7 +354,8 @@ func (b *Builder) createGenericRecordsResolver() graphql.FieldResolveFn {
354354
value = map[string]interface{}{"raw": rec.JSON}
355355
}
356356

357-
cursor := encodeCursor(rec.URI)
357+
// Use indexed_at as cursor for chronological pagination
358+
cursor := encodeCursor(rec.IndexedAt.Format("2006-01-02 15:04:05"))
358359
if startCursor == "" {
359360
startCursor = cursor
360361
}
@@ -404,18 +405,19 @@ func (b *Builder) createCollectionResolver(lexiconID string) graphql.FieldResolv
404405
first = 20
405406
}
406407

407-
// Decode cursor to URI if provided
408-
var afterURI string
408+
// Decode cursor to timestamp if provided
409+
var afterTimestamp string
409410
if after != "" {
410411
var err error
411-
afterURI, err = decodeCursor(after)
412+
afterTimestamp, err = decodeCursor(after)
412413
if err != nil {
413414
return nil, fmt.Errorf("invalid cursor: %w", err)
414415
}
415416
}
416417

417418
// Query database with cursor (fetch one extra to determine hasNextPage)
418-
records, err := repos.Records.GetByCollectionWithCursor(p.Context, lexiconID, first+1, afterURI)
419+
// Ordered by indexed_at DESC for chronological display
420+
records, err := repos.Records.GetByCollectionWithCursor(p.Context, lexiconID, first+1, afterTimestamp)
419421
if err != nil {
420422
return nil, fmt.Errorf("failed to query records: %w", err)
421423
}
@@ -441,7 +443,8 @@ func (b *Builder) createCollectionResolver(lexiconID string) graphql.FieldResolv
441443
data["uri"] = rec.URI
442444
data["cid"] = rec.CID
443445

444-
cursor := encodeCursor(rec.URI)
446+
// Use indexed_at as cursor for chronological pagination
447+
cursor := encodeCursor(rec.IndexedAt.Format("2006-01-02 15:04:05"))
445448
if startCursor == "" {
446449
startCursor = cursor
447450
}

0 commit comments

Comments
 (0)