2019-01-02 06:33:26 -05:00
|
|
|
// Copyright 2019 The Hugo Authors. All rights reserved.
|
2014-01-27 17:16:28 -05:00
|
|
|
//
|
2015-11-23 22:16:36 -05:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
2014-01-27 17:16:28 -05:00
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
2015-11-23 22:16:36 -05:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2014-01-27 17:16:28 -05:00
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
package page
|
2014-01-27 17:16:28 -05:00
|
|
|
|
|
|
|
import (
|
2023-02-11 10:20:24 -05:00
|
|
|
"context"
|
2017-02-19 02:50:08 -05:00
|
|
|
"sort"
|
2018-03-15 04:37:30 -04:00
|
|
|
|
2020-06-15 10:33:09 -04:00
|
|
|
"github.com/gohugoio/hugo/common/collections"
|
2022-04-10 14:30:52 -04:00
|
|
|
"github.com/gohugoio/hugo/langs"
|
2020-06-15 10:33:09 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
"github.com/gohugoio/hugo/resources/resource"
|
|
|
|
|
2019-08-01 04:19:19 -04:00
|
|
|
"github.com/gohugoio/hugo/compare"
|
2018-03-15 04:37:30 -04:00
|
|
|
"github.com/spf13/cast"
|
2014-01-27 17:16:28 -05:00
|
|
|
)
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
var spc = newPageCache()
|
|
|
|
|
2014-01-27 17:16:28 -05:00
|
|
|
/*
|
|
|
|
* Implementation of a custom sorter for Pages
|
|
|
|
*/
|
|
|
|
|
2016-03-24 22:12:03 -04:00
|
|
|
// A pageSorter implements the sort interface for Pages
|
|
|
|
type pageSorter struct {
|
2014-01-29 17:50:31 -05:00
|
|
|
pages Pages
|
2016-03-24 22:12:03 -04:00
|
|
|
by pageBy
|
2014-01-27 17:16:28 -05:00
|
|
|
}
|
|
|
|
|
2016-03-24 22:12:03 -04:00
|
|
|
// pageBy is a closure used in the Sort.Less method.
|
2019-01-02 06:33:26 -05:00
|
|
|
type pageBy func(p1, p2 Page) bool
|
2014-01-27 17:16:28 -05:00
|
|
|
|
2020-06-15 10:33:09 -04:00
|
|
|
func getOrdinals(p1, p2 Page) (int, int) {
|
|
|
|
p1o, ok1 := p1.(collections.Order)
|
|
|
|
if !ok1 {
|
|
|
|
return -1, -1
|
|
|
|
}
|
|
|
|
p2o, ok2 := p2.(collections.Order)
|
|
|
|
if !ok2 {
|
|
|
|
return -1, -1
|
|
|
|
}
|
|
|
|
|
|
|
|
return p1o.Ordinal(), p2o.Ordinal()
|
|
|
|
}
|
|
|
|
|
2016-03-23 12:12:47 -04:00
|
|
|
// Sort stable sorts the pages given the receiver's sort order.
|
2016-03-24 22:12:03 -04:00
|
|
|
func (by pageBy) Sort(pages Pages) {
|
|
|
|
ps := &pageSorter{
|
2014-01-29 17:50:31 -05:00
|
|
|
pages: pages,
|
|
|
|
by: by, // The Sort method's receiver is the function (closure) that defines the sort order.
|
|
|
|
}
|
2014-09-09 05:59:47 -04:00
|
|
|
sort.Stable(ps)
|
2014-01-27 17:16:28 -05:00
|
|
|
}
|
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
var (
|
|
|
|
|
|
|
|
// DefaultPageSort is the default sort func for pages in Hugo:
|
2020-06-15 10:33:09 -04:00
|
|
|
// Order by Ordinal, Weight, Date, LinkTitle and then full file path.
|
2019-10-11 07:55:46 -04:00
|
|
|
DefaultPageSort = func(p1, p2 Page) bool {
|
2020-06-15 10:33:09 -04:00
|
|
|
o1, o2 := getOrdinals(p1, p2)
|
|
|
|
if o1 != o2 && o1 != -1 && o2 != -1 {
|
|
|
|
return o1 < o2
|
|
|
|
}
|
2019-10-11 07:55:46 -04:00
|
|
|
if p1.Weight() == p2.Weight() {
|
|
|
|
if p1.Date().Unix() == p2.Date().Unix() {
|
2022-04-10 14:30:52 -04:00
|
|
|
c := collatorStringCompare(func(p Page) string { return p.LinkTitle() }, p1, p2)
|
2019-10-11 07:55:46 -04:00
|
|
|
if c == 0 {
|
|
|
|
if p1.File().IsZero() || p2.File().IsZero() {
|
|
|
|
return p1.File().IsZero()
|
|
|
|
}
|
|
|
|
return compare.LessStrings(p1.File().Filename(), p2.File().Filename())
|
2019-01-02 06:33:26 -05:00
|
|
|
}
|
2019-10-11 07:55:46 -04:00
|
|
|
return c < 0
|
2015-09-29 23:43:11 -04:00
|
|
|
}
|
2019-10-11 07:55:46 -04:00
|
|
|
return p1.Date().Unix() > p2.Date().Unix()
|
2015-07-25 10:34:35 -04:00
|
|
|
}
|
2016-11-06 09:38:52 -05:00
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
if p2.Weight() == 0 {
|
|
|
|
return true
|
|
|
|
}
|
2016-11-06 09:38:52 -05:00
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
if p1.Weight() == 0 {
|
|
|
|
return false
|
|
|
|
}
|
2016-11-06 09:38:52 -05:00
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
return p1.Weight() < p2.Weight()
|
|
|
|
}
|
2014-01-27 17:16:28 -05:00
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
lessPageLanguage = func(p1, p2 Page) bool {
|
|
|
|
if p1.Language().Weight == p2.Language().Weight {
|
|
|
|
if p1.Date().Unix() == p2.Date().Unix() {
|
|
|
|
c := compare.Strings(p1.LinkTitle(), p2.LinkTitle())
|
|
|
|
if c == 0 {
|
|
|
|
if !p1.File().IsZero() && !p2.File().IsZero() {
|
|
|
|
return compare.LessStrings(p1.File().Filename(), p2.File().Filename())
|
|
|
|
}
|
2019-01-02 06:33:26 -05:00
|
|
|
}
|
2019-10-11 07:55:46 -04:00
|
|
|
return c < 0
|
2016-07-25 16:22:09 -04:00
|
|
|
}
|
2019-10-11 07:55:46 -04:00
|
|
|
return p1.Date().Unix() > p2.Date().Unix()
|
2016-07-25 16:22:09 -04:00
|
|
|
}
|
2019-10-11 07:55:46 -04:00
|
|
|
|
|
|
|
if p2.Language().Weight == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if p1.Language().Weight == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return p1.Language().Weight < p2.Language().Weight
|
2016-07-25 16:22:09 -04:00
|
|
|
}
|
2016-11-06 09:38:52 -05:00
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
lessPageTitle = func(p1, p2 Page) bool {
|
2022-04-10 14:30:52 -04:00
|
|
|
return collatorStringCompare(func(p Page) string { return p.Title() }, p1, p2) < 0
|
2016-11-06 09:38:52 -05:00
|
|
|
}
|
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
lessPageLinkTitle = func(p1, p2 Page) bool {
|
2022-04-10 14:30:52 -04:00
|
|
|
return collatorStringCompare(func(p Page) string { return p.LinkTitle() }, p1, p2) < 0
|
2016-11-06 09:38:52 -05:00
|
|
|
}
|
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
lessPageDate = func(p1, p2 Page) bool {
|
|
|
|
return p1.Date().Unix() < p2.Date().Unix()
|
|
|
|
}
|
|
|
|
|
|
|
|
lessPagePubDate = func(p1, p2 Page) bool {
|
|
|
|
return p1.PublishDate().Unix() < p2.PublishDate().Unix()
|
|
|
|
}
|
|
|
|
)
|
2016-07-25 16:22:09 -04:00
|
|
|
|
2016-03-24 22:12:03 -04:00
|
|
|
func (ps *pageSorter) Len() int { return len(ps.pages) }
|
|
|
|
func (ps *pageSorter) Swap(i, j int) { ps.pages[i], ps.pages[j] = ps.pages[j], ps.pages[i] }
|
2014-01-27 17:16:28 -05:00
|
|
|
|
|
|
|
// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
|
2016-03-24 22:12:03 -04:00
|
|
|
func (ps *pageSorter) Less(i, j int) bool { return ps.by(ps.pages[i], ps.pages[j]) }
|
2014-01-27 17:16:28 -05:00
|
|
|
|
2016-03-23 12:11:29 -04:00
|
|
|
// Limit limits the number of pages returned to n.
|
2014-01-27 17:16:28 -05:00
|
|
|
func (p Pages) Limit(n int) Pages {
|
2016-02-06 16:10:36 -05:00
|
|
|
if len(p) > n {
|
2014-01-29 17:50:31 -05:00
|
|
|
return p[0:n]
|
|
|
|
}
|
2015-03-07 06:53:20 -05:00
|
|
|
return p
|
2014-01-27 17:16:28 -05:00
|
|
|
}
|
|
|
|
|
2022-04-10 14:30:52 -04:00
|
|
|
var collatorStringSort = func(getString func(Page) string) func(p Pages) {
|
|
|
|
return func(p Pages) {
|
|
|
|
if len(p) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Pages may be a mix of multiple languages, so we need to use the language
|
|
|
|
// for the currently rendered Site.
|
|
|
|
currentSite := p[0].Site().Current()
|
|
|
|
coll := langs.GetCollator(currentSite.Language())
|
|
|
|
coll.Lock()
|
|
|
|
defer coll.Unlock()
|
|
|
|
|
|
|
|
sort.SliceStable(p, func(i, j int) bool {
|
|
|
|
return coll.CompareStrings(getString(p[i]), getString(p[j])) < 0
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var collatorStringCompare = func(getString func(Page) string, p1, p2 Page) int {
|
|
|
|
currentSite := p1.Site().Current()
|
|
|
|
coll := langs.GetCollator(currentSite.Language())
|
|
|
|
coll.Lock()
|
|
|
|
c := coll.CompareStrings(getString(p1), getString(p2))
|
|
|
|
coll.Unlock()
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
var collatorStringLess = func(p Page) (less func(s1, s2 string) bool, close func()) {
|
|
|
|
currentSite := p.Site().Current()
|
|
|
|
coll := langs.GetCollator(currentSite.Language())
|
|
|
|
coll.Lock()
|
|
|
|
return func(s1, s2 string) bool {
|
|
|
|
return coll.CompareStrings(s1, s2) < 1
|
|
|
|
},
|
|
|
|
func() {
|
|
|
|
coll.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
// ByWeight sorts the Pages by weight and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2015-07-20 19:29:22 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
2014-01-27 17:16:28 -05:00
|
|
|
func (p Pages) ByWeight() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByWeight"
|
2019-01-02 06:33:26 -05:00
|
|
|
pages, _ := spc.get(key, pageBy(DefaultPageSort).Sort, p)
|
2015-07-20 19:29:22 -04:00
|
|
|
return pages
|
2014-01-27 17:16:28 -05:00
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
// SortByDefault sorts pages by the default sort.
|
|
|
|
func SortByDefault(pages Pages) {
|
|
|
|
pageBy(DefaultPageSort).Sort(pages)
|
|
|
|
}
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
// ByTitle sorts the Pages by title and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2015-07-20 19:29:22 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
2014-03-05 01:29:57 -05:00
|
|
|
func (p Pages) ByTitle() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByTitle"
|
2015-07-20 19:29:22 -04:00
|
|
|
|
2022-04-10 14:30:52 -04:00
|
|
|
pages, _ := spc.get(key, collatorStringSort(func(p Page) string { return p.Title() }), p)
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
return pages
|
2014-03-05 01:29:57 -05:00
|
|
|
}
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
// ByLinkTitle sorts the Pages by link title and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2015-07-20 19:29:22 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
2014-03-05 01:29:57 -05:00
|
|
|
func (p Pages) ByLinkTitle() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByLinkTitle"
|
2015-07-20 19:29:22 -04:00
|
|
|
|
2022-04-10 14:30:52 -04:00
|
|
|
pages, _ := spc.get(key, collatorStringSort(func(p Page) string { return p.LinkTitle() }), p)
|
2015-07-20 19:29:22 -04:00
|
|
|
|
|
|
|
return pages
|
2014-03-05 01:29:57 -05:00
|
|
|
}
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
// ByDate sorts the Pages by date and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2015-07-20 19:29:22 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
2014-01-27 17:16:28 -05:00
|
|
|
func (p Pages) ByDate() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByDate"
|
2015-07-20 19:29:22 -04:00
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
pages, _ := spc.get(key, pageBy(lessPageDate).Sort, p)
|
2015-07-20 19:29:22 -04:00
|
|
|
|
|
|
|
return pages
|
2014-01-27 17:16:28 -05:00
|
|
|
}
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
// ByPublishDate sorts the Pages by publish date and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2015-07-20 19:29:22 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
2014-10-17 11:10:19 -04:00
|
|
|
func (p Pages) ByPublishDate() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByPublishDate"
|
2015-07-20 19:29:22 -04:00
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
pages, _ := spc.get(key, pageBy(lessPagePubDate).Sort, p)
|
2015-07-20 19:29:22 -04:00
|
|
|
|
|
|
|
return pages
|
2014-10-17 11:10:19 -04:00
|
|
|
}
|
|
|
|
|
2016-05-11 10:08:48 -04:00
|
|
|
// ByExpiryDate sorts the Pages by publish date and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2016-05-11 10:08:48 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
|
|
|
func (p Pages) ByExpiryDate() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByExpiryDate"
|
2016-05-11 10:08:48 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
expDate := func(p1, p2 Page) bool {
|
|
|
|
return p1.ExpiryDate().Unix() < p2.ExpiryDate().Unix()
|
2016-05-11 10:08:48 -04:00
|
|
|
}
|
|
|
|
|
2018-03-15 04:37:30 -04:00
|
|
|
pages, _ := spc.get(key, pageBy(expDate).Sort, p)
|
2016-05-11 10:08:48 -04:00
|
|
|
|
|
|
|
return pages
|
|
|
|
}
|
|
|
|
|
2016-04-22 14:43:00 -04:00
|
|
|
// ByLastmod sorts the Pages by the last modification date and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2016-04-22 14:43:00 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
|
|
|
func (p Pages) ByLastmod() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByLastmod"
|
2016-04-22 14:43:00 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
date := func(p1, p2 Page) bool {
|
|
|
|
return p1.Lastmod().Unix() < p2.Lastmod().Unix()
|
2016-04-22 14:43:00 -04:00
|
|
|
}
|
|
|
|
|
2018-03-15 04:37:30 -04:00
|
|
|
pages, _ := spc.get(key, pageBy(date).Sort, p)
|
2016-04-22 14:43:00 -04:00
|
|
|
|
|
|
|
return pages
|
|
|
|
}
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
// ByLength sorts the Pages by length and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2015-07-20 19:29:22 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
2023-02-11 10:20:24 -05:00
|
|
|
func (p Pages) ByLength(ctx context.Context) Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByLength"
|
2015-07-20 19:29:22 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
length := func(p1, p2 Page) bool {
|
|
|
|
p1l, ok1 := p1.(resource.LengthProvider)
|
|
|
|
p2l, ok2 := p2.(resource.LengthProvider)
|
|
|
|
|
|
|
|
if !ok1 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if !ok2 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-02-11 10:20:24 -05:00
|
|
|
return p1l.Len(ctx) < p2l.Len(ctx)
|
2014-01-29 17:50:31 -05:00
|
|
|
}
|
2014-01-27 17:16:28 -05:00
|
|
|
|
2018-03-15 04:37:30 -04:00
|
|
|
pages, _ := spc.get(key, pageBy(length).Sort, p)
|
2015-07-20 19:29:22 -04:00
|
|
|
|
|
|
|
return pages
|
2014-01-27 17:16:28 -05:00
|
|
|
}
|
|
|
|
|
2016-07-25 16:22:09 -04:00
|
|
|
// ByLanguage sorts the Pages by the language's Weight.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2016-07-25 16:22:09 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
|
|
|
func (p Pages) ByLanguage() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.ByLanguage"
|
2016-07-25 16:22:09 -04:00
|
|
|
|
2019-10-11 07:55:46 -04:00
|
|
|
pages, _ := spc.get(key, pageBy(lessPageLanguage).Sort, p)
|
2016-07-25 16:22:09 -04:00
|
|
|
|
|
|
|
return pages
|
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
// SortByLanguage sorts the pages by language.
|
|
|
|
func SortByLanguage(pages Pages) {
|
2019-10-11 07:55:46 -04:00
|
|
|
pageBy(lessPageLanguage).Sort(pages)
|
2019-01-02 06:33:26 -05:00
|
|
|
}
|
|
|
|
|
2015-07-20 19:29:22 -04:00
|
|
|
// Reverse reverses the order in Pages and returns a copy.
|
|
|
|
//
|
2017-02-09 04:48:07 -05:00
|
|
|
// Adjacent invocations on the same receiver will return a cached result.
|
2015-07-20 19:29:22 -04:00
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
2014-01-27 17:16:28 -05:00
|
|
|
func (p Pages) Reverse() Pages {
|
2018-09-21 08:13:45 -04:00
|
|
|
const key = "pageSort.Reverse"
|
2015-07-20 19:29:22 -04:00
|
|
|
|
|
|
|
reverseFunc := func(pages Pages) {
|
|
|
|
for i, j := 0, len(pages)-1; i < j; i, j = i+1, j-1 {
|
|
|
|
pages[i], pages[j] = pages[j], pages[i]
|
|
|
|
}
|
2014-01-29 17:50:31 -05:00
|
|
|
}
|
2014-01-27 17:16:28 -05:00
|
|
|
|
2018-03-15 04:37:30 -04:00
|
|
|
pages, _ := spc.get(key, reverseFunc, p)
|
2015-07-20 19:29:22 -04:00
|
|
|
|
|
|
|
return pages
|
2014-01-27 17:16:28 -05:00
|
|
|
}
|
2017-02-10 08:01:25 -05:00
|
|
|
|
2018-09-21 08:13:45 -04:00
|
|
|
// ByParam sorts the pages according to the given page Params key.
|
|
|
|
//
|
|
|
|
// Adjacent invocations on the same receiver with the same paramsKey will return a cached result.
|
|
|
|
//
|
|
|
|
// This may safely be executed in parallel.
|
2022-03-17 17:03:27 -04:00
|
|
|
func (p Pages) ByParam(paramsKey any) Pages {
|
2022-04-10 14:30:52 -04:00
|
|
|
if len(p) < 2 {
|
|
|
|
return p
|
|
|
|
}
|
2017-02-10 08:01:25 -05:00
|
|
|
paramsKeyStr := cast.ToString(paramsKey)
|
|
|
|
key := "pageSort.ByParam." + paramsKeyStr
|
|
|
|
|
2022-04-10 14:30:52 -04:00
|
|
|
stringLess, close := collatorStringLess(p[0])
|
|
|
|
defer close()
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
paramsKeyComparator := func(p1, p2 Page) bool {
|
2017-02-10 08:01:25 -05:00
|
|
|
v1, _ := p1.Param(paramsKeyStr)
|
|
|
|
v2, _ := p2.Param(paramsKeyStr)
|
|
|
|
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
if v1 == nil {
|
2017-02-10 08:01:25 -05:00
|
|
|
return false
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if v2 == nil {
|
2017-02-10 08:01:25 -05:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2022-03-17 17:03:27 -04:00
|
|
|
isNumeric := func(v any) bool {
|
Support numeric sort in ByParam
With this commit ByParam takes into account a type of a value under a
key. If both values are numeric then they're coerced into float64 and
then get compared.
If any value isn't numeric, for example it's nil or string, then both
values coerced into string and get compared as strings
(lexicographicaly)
Nil values are always sent to the end.
Numeric values confirm to any type listed below:
uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64
Closes #5305
2019-01-15 07:41:54 -05:00
|
|
|
switch v.(type) {
|
|
|
|
case uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64:
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if isNumeric(v1) && isNumeric(v2) {
|
|
|
|
return cast.ToFloat64(v1) < cast.ToFloat64(v2)
|
|
|
|
}
|
|
|
|
|
|
|
|
s1 := cast.ToString(v1)
|
|
|
|
s2 := cast.ToString(v2)
|
|
|
|
|
2022-04-10 14:30:52 -04:00
|
|
|
return stringLess(s1, s2)
|
|
|
|
|
2017-02-10 08:01:25 -05:00
|
|
|
}
|
|
|
|
|
2018-03-15 04:37:30 -04:00
|
|
|
pages, _ := spc.get(key, pageBy(paramsKeyComparator).Sort, p)
|
2017-02-10 08:01:25 -05:00
|
|
|
|
|
|
|
return pages
|
|
|
|
}
|