mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 09:02:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			228 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			228 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// GoToSocial
							 | 
						||
| 
								 | 
							
								// Copyright (C) GoToSocial Authors admin@gotosocial.org
							 | 
						||
| 
								 | 
							
								// SPDX-License-Identifier: AGPL-3.0-or-later
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This program is free software: you can redistribute it and/or modify
							 | 
						||
| 
								 | 
							
								// it under the terms of the GNU Affero General Public License as published by
							 | 
						||
| 
								 | 
							
								// the Free Software Foundation, either version 3 of the License, or
							 | 
						||
| 
								 | 
							
								// (at your option) any later version.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This program is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								// but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						||
| 
								 | 
							
								// GNU Affero General Public License for more details.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// You should have received a copy of the GNU Affero General Public License
							 | 
						||
| 
								 | 
							
								// along with this program.  If not, see <http://www.gnu.org/licenses/>.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package paging
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import "golang.org/x/exp/slices"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Pager provides a means of paging serialized IDs,
							 | 
						||
| 
								 | 
							
								// using the terminology of our API endpoint queries.
							 | 
						||
| 
								 | 
							
								type Pager struct {
							 | 
						||
| 
								 | 
							
									// SinceID will limit the returned
							 | 
						||
| 
								 | 
							
									// page of IDs to contain newer than
							 | 
						||
| 
								 | 
							
									// since ID (excluding it). Result
							 | 
						||
| 
								 | 
							
									// will be returned DESCENDING.
							 | 
						||
| 
								 | 
							
									SinceID string
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// MinID will limit the returned
							 | 
						||
| 
								 | 
							
									// page of IDs to contain newer than
							 | 
						||
| 
								 | 
							
									// min ID (excluding it). Result
							 | 
						||
| 
								 | 
							
									// will be returned ASCENDING.
							 | 
						||
| 
								 | 
							
									MinID string
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// MaxID will limit the returned
							 | 
						||
| 
								 | 
							
									// page of IDs to contain older
							 | 
						||
| 
								 | 
							
									// than (excluding) this max ID.
							 | 
						||
| 
								 | 
							
									MaxID string
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Limit will limit the returned
							 | 
						||
| 
								 | 
							
									// page of IDs to at most 'limit'.
							 | 
						||
| 
								 | 
							
									Limit int
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Page will page the given slice of GoToSocial IDs according
							 | 
						||
| 
								 | 
							
								// to the receiving Pager's SinceID, MinID, MaxID and Limits.
							 | 
						||
| 
								 | 
							
								// NOTE THE INPUT SLICE MUST BE SORTED IN ASCENDING ORDER
							 | 
						||
| 
								 | 
							
								// (I.E. OLDEST ITEMS AT LOWEST INDICES, NEWER AT HIGHER).
							 | 
						||
| 
								 | 
							
								func (p *Pager) PageAsc(ids []string) []string {
							 | 
						||
| 
								 | 
							
									if p == nil {
							 | 
						||
| 
								 | 
							
										// no paging.
							 | 
						||
| 
								 | 
							
										return ids
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var asc bool
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if p.SinceID != "" {
							 | 
						||
| 
								 | 
							
										// If a sinceID is given, we
							 | 
						||
| 
								 | 
							
										// page down i.e. descending.
							 | 
						||
| 
								 | 
							
										asc = false
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for i := 0; i < len(ids); i++ {
							 | 
						||
| 
								 | 
							
											if ids[i] == p.SinceID {
							 | 
						||
| 
								 | 
							
												// Hit the boundary.
							 | 
						||
| 
								 | 
							
												// Reslice to be:
							 | 
						||
| 
								 | 
							
												// "from here"
							 | 
						||
| 
								 | 
							
												ids = ids[i+1:]
							 | 
						||
| 
								 | 
							
												break
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else if p.MinID != "" {
							 | 
						||
| 
								 | 
							
										// We only support minID if
							 | 
						||
| 
								 | 
							
										// no sinceID is provided.
							 | 
						||
| 
								 | 
							
										//
							 | 
						||
| 
								 | 
							
										// If a minID is given, we
							 | 
						||
| 
								 | 
							
										// page up, i.e. ascending.
							 | 
						||
| 
								 | 
							
										asc = true
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for i := 0; i < len(ids); i++ {
							 | 
						||
| 
								 | 
							
											if ids[i] == p.MinID {
							 | 
						||
| 
								 | 
							
												// Hit the boundary.
							 | 
						||
| 
								 | 
							
												// Reslice to be:
							 | 
						||
| 
								 | 
							
												// "from here"
							 | 
						||
| 
								 | 
							
												ids = ids[i+1:]
							 | 
						||
| 
								 | 
							
												break
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if p.MaxID != "" {
							 | 
						||
| 
								 | 
							
										for i := 0; i < len(ids); i++ {
							 | 
						||
| 
								 | 
							
											if ids[i] == p.MaxID {
							 | 
						||
| 
								 | 
							
												// Hit the boundary.
							 | 
						||
| 
								 | 
							
												// Reslice to be:
							 | 
						||
| 
								 | 
							
												// "up to here"
							 | 
						||
| 
								 | 
							
												ids = ids[:i]
							 | 
						||
| 
								 | 
							
												break
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if !asc && len(ids) > 1 {
							 | 
						||
| 
								 | 
							
										var (
							 | 
						||
| 
								 | 
							
											// Start at front.
							 | 
						||
| 
								 | 
							
											i = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Start at back.
							 | 
						||
| 
								 | 
							
											j = len(ids) - 1
							 | 
						||
| 
								 | 
							
										)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Clone input IDs before
							 | 
						||
| 
								 | 
							
										// we perform modifications.
							 | 
						||
| 
								 | 
							
										ids = slices.Clone(ids)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for i < j {
							 | 
						||
| 
								 | 
							
											// Swap i,j index values in slice.
							 | 
						||
| 
								 | 
							
											ids[i], ids[j] = ids[j], ids[i]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// incr + decr,
							 | 
						||
| 
								 | 
							
											// looping until
							 | 
						||
| 
								 | 
							
											// they meet in
							 | 
						||
| 
								 | 
							
											// the middle.
							 | 
						||
| 
								 | 
							
											i++
							 | 
						||
| 
								 | 
							
											j--
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if p.Limit > 0 && p.Limit < len(ids) {
							 | 
						||
| 
								 | 
							
										// Reslice IDs to given limit.
							 | 
						||
| 
								 | 
							
										ids = ids[:p.Limit]
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ids
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Page will page the given slice of GoToSocial IDs according
							 | 
						||
| 
								 | 
							
								// to the receiving Pager's SinceID, MinID, MaxID and Limits.
							 | 
						||
| 
								 | 
							
								// NOTE THE INPUT SLICE MUST BE SORTED IN ASCENDING ORDER.
							 | 
						||
| 
								 | 
							
								// (I.E. NEWEST ITEMS AT LOWEST INDICES, OLDER AT HIGHER).
							 | 
						||
| 
								 | 
							
								func (p *Pager) PageDesc(ids []string) []string {
							 | 
						||
| 
								 | 
							
									if p == nil {
							 | 
						||
| 
								 | 
							
										// no paging.
							 | 
						||
| 
								 | 
							
										return ids
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var asc bool
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if p.MaxID != "" {
							 | 
						||
| 
								 | 
							
										for i := 0; i < len(ids); i++ {
							 | 
						||
| 
								 | 
							
											if ids[i] == p.MaxID {
							 | 
						||
| 
								 | 
							
												// Hit the boundary.
							 | 
						||
| 
								 | 
							
												// Reslice to be:
							 | 
						||
| 
								 | 
							
												// "from here"
							 | 
						||
| 
								 | 
							
												ids = ids[i+1:]
							 | 
						||
| 
								 | 
							
												break
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if p.SinceID != "" {
							 | 
						||
| 
								 | 
							
										// If a sinceID is given, we
							 | 
						||
| 
								 | 
							
										// page down i.e. descending.
							 | 
						||
| 
								 | 
							
										asc = false
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for i := 0; i < len(ids); i++ {
							 | 
						||
| 
								 | 
							
											if ids[i] == p.SinceID {
							 | 
						||
| 
								 | 
							
												// Hit the boundary.
							 | 
						||
| 
								 | 
							
												// Reslice to be:
							 | 
						||
| 
								 | 
							
												// "up to here"
							 | 
						||
| 
								 | 
							
												ids = ids[:i]
							 | 
						||
| 
								 | 
							
												break
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else if p.MinID != "" {
							 | 
						||
| 
								 | 
							
										// We only support minID if
							 | 
						||
| 
								 | 
							
										// no sinceID is provided.
							 | 
						||
| 
								 | 
							
										//
							 | 
						||
| 
								 | 
							
										// If a minID is given, we
							 | 
						||
| 
								 | 
							
										// page up, i.e. ascending.
							 | 
						||
| 
								 | 
							
										asc = true
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for i := 0; i < len(ids); i++ {
							 | 
						||
| 
								 | 
							
											if ids[i] == p.MinID {
							 | 
						||
| 
								 | 
							
												// Hit the boundary.
							 | 
						||
| 
								 | 
							
												// Reslice to be:
							 | 
						||
| 
								 | 
							
												// "up to here"
							 | 
						||
| 
								 | 
							
												ids = ids[:i]
							 | 
						||
| 
								 | 
							
												break
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if asc && len(ids) > 1 {
							 | 
						||
| 
								 | 
							
										var (
							 | 
						||
| 
								 | 
							
											// Start at front.
							 | 
						||
| 
								 | 
							
											i = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Start at back.
							 | 
						||
| 
								 | 
							
											j = len(ids) - 1
							 | 
						||
| 
								 | 
							
										)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Clone input IDs before
							 | 
						||
| 
								 | 
							
										// we perform modifications.
							 | 
						||
| 
								 | 
							
										ids = slices.Clone(ids)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for i < j {
							 | 
						||
| 
								 | 
							
											// Swap i,j index values in slice.
							 | 
						||
| 
								 | 
							
											ids[i], ids[j] = ids[j], ids[i]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// incr + decr,
							 | 
						||
| 
								 | 
							
											// looping until
							 | 
						||
| 
								 | 
							
											// they meet in
							 | 
						||
| 
								 | 
							
											// the middle.
							 | 
						||
| 
								 | 
							
											i++
							 | 
						||
| 
								 | 
							
											j--
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if p.Limit > 0 && p.Limit < len(ids) {
							 | 
						||
| 
								 | 
							
										// Reslice IDs to given limit.
							 | 
						||
| 
								 | 
							
										ids = ids[:p.Limit]
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ids
							 | 
						||
| 
								 | 
							
								}
							 |