Created
June 4, 2021 02:47
-
-
Save xkisu/ad6391368a90c94e09bd5e06e49369ae to your computer and use it in GitHub Desktop.
Golang Postgres Query Builder for GraphQL Relay-style Cursor-Based Pagination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package filters | |
import ( | |
"fmt" | |
sq "github.com/Masterminds/squirrel" | |
) | |
// Pagination provides parameters for a pagination filter. | |
type Pagination struct { | |
// First specifies a count of the first items to retrieve. | |
First int `json:"first"` | |
// Last | |
Last int `json:"last"` | |
// Before specifies a cursor to select items from before. | |
Before string `json:"before"` | |
// After specifies a cursor to select items after. | |
After string `json:"after"` | |
// NOTES: | |
// When before: cursor is used, the edge closest to cursor must come last in the result edges. | |
// @see https://relay.dev/graphql/connections.htm#sec-Edge-order | |
// | |
// When after: cursor is used, the edge closest to cursor must come first in the result edges. | |
// @see https://relay.dev/graphql/connections.htm#sec-Edge-order | |
} | |
// Apply pagination clauses to the specified query builder. | |
func (p Pagination) Apply (builder sq.SelectBuilder) (sq.SelectBuilder, error) { | |
if p.Before != "" && p.After != "" { | |
return sq.SelectBuilder{}, fmt.Errorf("pagniation before and after cannot both be specified") | |
} | |
if p.Before != "" { | |
builder = builder.Where(sq.Lt{ | |
"id": p.Before, | |
}) | |
} else if p.After != "" { | |
builder = builder.Where(sq.Gt{ | |
"id": p.After, | |
}) | |
} | |
if p.First > 0 || p.Last > 0 { | |
if p.First > 0 { | |
builder = builder.OrderBy("id DESC", "created_at DESC"). | |
Limit(uint64(p.First) + 1) | |
} else if p.Last > 0 { | |
builder = builder.OrderBy("id ASC", "created_at ASC"). | |
Limit(uint64(p.Last) + 1) | |
} else { | |
builder = builder.OrderBy("id DESC", "created_at DESC"). | |
Limit(25) | |
} | |
} | |
return builder, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment