code.vegaprotocol.io/vega@v0.79.0/datanode/entities/entities.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package entities 17 18 import "google.golang.org/protobuf/proto" 19 20 type Entities interface { 21 Market | Party | Trade | Order | MarketData | Reward | Candle | Deposit | 22 Withdrawal | Asset | OracleSpec | OracleData | Position | LiquidityProvision | Vote | 23 AccountBalance | Proposal | Delegation | Node | NetworkParameter | Checkpoint | 24 StakeLinking | NodeSignature | KeyRotation | ERC20MultiSigSignerAddedEvent | 25 ERC20MultiSigSignerRemovedEvent | EthereumKeyRotation | AggregatedBalance | AggregatedLedgerEntry | 26 ProtocolUpgradeProposal | CoreSnapshotData | EpochRewardSummary | SuccessorMarket | StopOrder | 27 LiquidityProvider | FundingPeriod | FundingPeriodDataPoint | ReferralSet | ReferralSetRefereeStats | 28 FlattenReferralSetStats | Team | TeamMember | TeamMemberHistory | FundingPayment | FlattenVolumeDiscountStats | 29 PaidLiquidityFeesStats | CurrentAndPreviousLiquidityProvisions | TransferDetails | Game | TeamsStatistics | TeamMembersStatistics | 30 PartyMarginMode | PartyProfile | GamePartyScore | GameTeamScore | AMMPool | FlattenVolumeRebateStats 31 } 32 33 type PagedEntity[T proto.Message] interface { 34 Entities | Transfer | MarginLevels 35 36 // ToProtoEdge may need some optional arguments in order to generate the proto, for example margin levels 37 // requires an account source. This is not ideal, but we can come back to this later if a better solution can be found. 38 ToProtoEdge(...any) (T, error) 39 Cursor() *Cursor 40 } 41 42 type ProtoEntity[T proto.Message] interface { 43 Entities | Account | NodeBasic 44 ToProto() T 45 } 46 47 func PageEntities[T proto.Message, U PagedEntity[T]](items []U, pagination CursorPagination) ([]U, PageInfo) { 48 var pagedItems []U 49 var limit int 50 var pageInfo PageInfo 51 52 if len(items) == 0 { 53 return pagedItems, pageInfo 54 } 55 56 if pagination.HasForward() && pagination.Forward.Limit != nil { 57 limit = int(*pagination.Forward.Limit) 58 switch len(items) { 59 case limit + 2: 60 pagedItems = items[1 : limit+1] 61 pageInfo.HasNextPage = true 62 pageInfo.HasPreviousPage = true 63 case limit + 1: 64 if !pagination.Forward.HasCursor() { 65 pagedItems = items[0:limit] 66 pageInfo.HasNextPage = true 67 pageInfo.HasPreviousPage = false 68 } else { 69 pagedItems = items[1:] 70 pageInfo.HasNextPage = false 71 pageInfo.HasPreviousPage = true 72 } 73 default: 74 // if the pagination for the first item is the same as the after pagination, then we have a previous page, and we shouldn't include it 75 if pagination.HasForward() && pagination.Forward.HasCursor() && pagination.Forward.Cursor.Value() == items[0].Cursor().Value() { 76 pagedItems = items[1:] 77 pageInfo.HasNextPage = false 78 pageInfo.HasPreviousPage = true 79 } else { 80 pagedItems = items 81 pageInfo.HasNextPage = false 82 pageInfo.HasPreviousPage = false 83 } 84 } 85 } else if pagination.HasBackward() && pagination.Backward.Limit != nil { 86 limit = int(*pagination.Backward.Limit) 87 switch len(items) { 88 case limit + 2: 89 pagedItems = ReverseSlice(items[1 : limit+1]) 90 pageInfo.HasNextPage = true 91 pageInfo.HasPreviousPage = true 92 case limit + 1: 93 if !pagination.Backward.HasCursor() { 94 pagedItems = ReverseSlice(items[0:limit]) 95 pageInfo.HasNextPage = false 96 pageInfo.HasPreviousPage = true 97 } else { 98 pagedItems = ReverseSlice(items[1:]) 99 pageInfo.HasNextPage = true 100 pageInfo.HasPreviousPage = false 101 } 102 default: 103 if pagination.HasBackward() && pagination.Backward.HasCursor() && pagination.Backward.Cursor.Value() == items[0].Cursor().Value() { 104 pagedItems = ReverseSlice(items[1:]) 105 pageInfo.HasNextPage = true 106 pageInfo.HasPreviousPage = false 107 } else { 108 pagedItems = ReverseSlice(items) 109 pageInfo.HasNextPage = false 110 pageInfo.HasPreviousPage = false 111 } 112 } 113 } else { 114 pagedItems = items 115 pageInfo.HasNextPage = false 116 pageInfo.HasPreviousPage = false 117 } 118 119 if len(pagedItems) > 0 { 120 startCursor := pagedItems[0].Cursor() 121 endCursor := pagedItems[len(pagedItems)-1].Cursor() 122 pageInfo.StartCursor = startCursor.Encode() 123 pageInfo.EndCursor = endCursor.Encode() 124 } 125 126 return pagedItems, pageInfo 127 } 128 129 func ReverseSlice[T any](input []T) (reversed []T) { 130 reversed = make([]T, len(input)) 131 copy(reversed, input) 132 for i, j := 0, len(input)-1; i < j; i, j = i+1, j-1 { 133 reversed[i], reversed[j] = input[j], input[i] 134 } 135 return 136 }