package adapter import ( "errors" "slices" "github.com/uptrace/bun" ) func appendODSetClauses(q *bun.InsertQuery) *bun.InsertQuery { return q.Set("rank_att = EXCLUDED.rank_att"). Set("score_att = EXCLUDED.score_att"). Set("rank_def = EXCLUDED.rank_def"). Set("score_def = EXCLUDED.score_def"). Set("rank_sup = EXCLUDED.rank_sup"). Set("score_sup = EXCLUDED.score_sup"). Set("rank_total = EXCLUDED.rank_total"). Set("score_total = EXCLUDED.score_total") } func separateListResultAndNext[T any](res []T, limit int) ([]T, T) { var next T if len(res) > limit { next = res[limit] res = res[:limit] } return res, next } type sortDirection uint8 var errInvalidSortDirection = errors.New("invalid sort direction") const ( sortDirectionASC sortDirection = iota + 1 sortDirectionDESC ) func (sd sortDirection) Bun() bun.Safe { return bun.Safe(sd.String()) } func (sd sortDirection) String() string { switch sd { case sortDirectionASC: return "ASC" case sortDirectionDESC: return "DESC" default: return "unknown" } } type cursorPaginationApplierDataElement struct { unique bool column bun.Safe direction sortDirection value any } type cursorPaginationApplier struct { data []cursorPaginationApplierDataElement } var errCursorNoUniqueFieldUsedForSorting = errors.New("cursor - no unique field used for sorting") func (a cursorPaginationApplier) apply(q *bun.SelectQuery) *bun.SelectQuery { if len(a.data) == 0 { return q } uniqueIndex := slices.IndexFunc(a.data, func(element cursorPaginationApplierDataElement) bool { return element.unique }) if uniqueIndex < 0 { return q.Err(errCursorNoUniqueFieldUsedForSorting) } return q.WhereGroup(" AND ", func(q *bun.SelectQuery) *bun.SelectQuery { dataLen := len(a.data) // based on https://github.com/prisma/prisma/issues/19159#issuecomment-1713389245 return q.WhereGroup(" OR ", func(q *bun.SelectQuery) *bun.SelectQuery { for i := range dataLen { q.WhereGroup(" OR ", func(q *bun.SelectQuery) *bun.SelectQuery { current := a.data[i] for j := range i { prev := a.data[j] q = q.Where("? = ?", prev.column, prev.value) } column := current.column greaterSymbol := bun.Safe(">") lessSymbol := bun.Safe("<") if i == dataLen-1 { greaterSymbol = ">=" lessSymbol = "<=" } switch current.direction { case sortDirectionASC: q = q.Where("? ? ?", column, greaterSymbol, current.value) case sortDirectionDESC: q = q.Where("? ? ?", column, lessSymbol, current.value) default: return q.Err(errInvalidSortDirection) } return q }) } return q }) }) }