Skip to content

Commit

Permalink
Plays with sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
tjayrush committed Nov 28, 2024
1 parent 2c96cee commit ba60560
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 71 deletions.
2 changes: 1 addition & 1 deletion sdk
Submodule sdk updated 5 files
+0 −36 abis.go
+0 −43 chunks.go
+0 −19 names.go
+162 −0 sorts.go
+0 −18 status.go
98 changes: 98 additions & 0 deletions src/apps/chifra/pkg/types/types_chain_sort.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package types

type ChainField string

// Fields in the Chain struct available for sorting.
const (
ChainChain ChainField = "chain"
ChainChainId ChainField = "chainId"
ChainIpfsGateway ChainField = "ipfsGateway"
ChainLocalExplorer ChainField = "localExplorer"
ChainRemoteExplorer ChainField = "remoteExplorer"
ChainRpcProvider ChainField = "rpcProvider"
ChainSymbol ChainField = "symbol"
)

// IsValidChainField returns true if the given field is a valid sortable Chain field.
func IsValidChainField(field string) bool {
switch field {
case "chain", "chainId", "ipfsGateway", "localExplorer", "remoteExplorer", "rpcProvider", "symbol":
return true
}
return false
}

// ChainBy returns a comparison function for sorting Chain instances by the given field.
// These comparison functions may be strung together by the CmdChains function.
func ChainBy(field ChainField, order SortOrder) func(p1, p2 Chain) bool {
switch field {
case ChainChain: // string
return func(p1, p2 Chain) bool {
if order == Ascending {
return p1.Chain < p2.Chain
}
return p1.Chain > p2.Chain
}
case ChainChainId: // uint64
return func(p1, p2 Chain) bool {
if order == Ascending {
return p1.ChainId < p2.ChainId
}
return p1.ChainId > p2.ChainId
}
case ChainIpfsGateway: // string
return func(p1, p2 Chain) bool {
if order == Ascending {
return p1.IpfsGateway < p2.IpfsGateway
}
return p1.IpfsGateway > p2.IpfsGateway
}
case ChainLocalExplorer: // string
return func(p1, p2 Chain) bool {
if order == Ascending {
return p1.LocalExplorer < p2.LocalExplorer
}
return p1.LocalExplorer > p2.LocalExplorer
}
case ChainRemoteExplorer: // string
return func(p1, p2 Chain) bool {
if order == Ascending {
return p1.RemoteExplorer < p2.RemoteExplorer
}
return p1.RemoteExplorer > p2.RemoteExplorer
}
case ChainRpcProvider: // string
return func(p1, p2 Chain) bool {
if order == Ascending {
return p1.RpcProvider < p2.RpcProvider
}
return p1.RpcProvider > p2.RpcProvider
}
case ChainSymbol: // string
return func(p1, p2 Chain) bool {
if order == Ascending {
return p1.Symbol < p2.Symbol
}
return p1.Symbol > p2.Symbol
}

}
panic("Should not happen in ChainBy")
}

// ChainCmp accepts a slice and variadic comparison functions and returns a functions
// that can be used to sort the slice.
func ChainCmp(slice []Chain, orders ...func(p1, p2 Chain) bool) func(i, j int) bool {
return func(i, j int) bool {
p1, p2 := slice[i], slice[j]
for _, order := range orders {
if order(p1, p2) {
return true
}
if order(p2, p1) {
return false
}
}
return false
}
}
99 changes: 99 additions & 0 deletions src/apps/chifra/pkg/types/types_monitor_sort.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package types

type MonitorField string

// Fields in the Monitor struct available for sorting.
const (
MonitorAddress MonitorField = "address"
MonitorDeleted MonitorField = "deleted"
MonitorFileSize MonitorField = "fileSize"
MonitorIsEmpty MonitorField = "isEmpty"
MonitorIsStaged MonitorField = "isStaged"
MonitorLastScanned MonitorField = "lastScanned"
MonitorNRecords MonitorField = "nRecords"
)

// IsValidMonitorField returns true if the given field is a valid sortable Monitor field.
func IsValidMonitorField(field string) bool {
switch field {
case "address", "deleted", "fileSize", "isEmpty", "isStaged", "lastScanned", "nRecords":
return true
}
return false
}

// MonitorBy returns a comparison function for sorting Monitor instances by the given field.
// These comparison functions may be strung together by the CmdMonitors function.
func MonitorBy(field MonitorField, order SortOrder) func(p1, p2 Monitor) bool {
switch field {
case MonitorAddress: // address
return func(p1, p2 Monitor) bool {
cmp := p1.Address.Cmp(p2.Address.Address)
if order == Ascending {
return cmp == -1
}
return cmp == 1
}
case MonitorDeleted: // bool
return func(p1, p2 Monitor) bool {
if order == Ascending {
return !p1.Deleted && p2.Deleted
}
return p1.Deleted && !p2.Deleted
}
case MonitorFileSize: // int64
return func(p1, p2 Monitor) bool {
if order == Ascending {
return p1.FileSize < p2.FileSize
}
return p1.FileSize > p2.FileSize
}
case MonitorIsEmpty: // bool
return func(p1, p2 Monitor) bool {
if order == Ascending {
return !p1.IsEmpty && p2.IsEmpty
}
return p1.IsEmpty && !p2.IsEmpty
}
case MonitorIsStaged: // bool
return func(p1, p2 Monitor) bool {
if order == Ascending {
return !p1.IsStaged && p2.IsStaged
}
return p1.IsStaged && !p2.IsStaged
}
case MonitorLastScanned: // uint32
return func(p1, p2 Monitor) bool {
if order == Ascending {
return p1.LastScanned < p2.LastScanned
}
return p1.LastScanned > p2.LastScanned
}
case MonitorNRecords: // int64
return func(p1, p2 Monitor) bool {
if order == Ascending {
return p1.NRecords < p2.NRecords
}
return p1.NRecords > p2.NRecords
}

}
panic("Should not happen in MonitorBy")
}

// MonitorCmp accepts a slice and variadic comparison functions and returns a functions
// that can be used to sort the slice.
func MonitorCmp(slice []Monitor, orders ...func(p1, p2 Monitor) bool) func(i, j int) bool {
return func(i, j int) bool {
p1, p2 := slice[i], slice[j]
for _, order := range orders {
if order(p1, p2) {
return true
}
if order(p2, p1) {
return false
}
}
return false
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name ,type ,strDefault ,attributes ,docOrder ,description
chain ,string , , , 1 ,the common name of the chain
chainId ,uint64 , , , 2 ,the chain id as reported by the RPC
symbol ,string , , , 3 ,the symbol of the base currency on the chain
rpcProvider ,string ,http://localhost:8545 , , 4 ,a valid RPC provider for the chain
remoteExplorer ,string ,http://etherscan.io , , 5 ,a remote explorer for the chain such as Etherscan
localExplorer ,string ,http://localhost:1234 , , 6 ,the local explorer for the chain (typically TrueBlocks Explorer)
ipfsGateway ,string ,http://gateway.ipfs.io/ipfs , , 7 ,an IPFS gateway for pinning the index if enabled
chain ,string , ,sorts , 1 ,the common name of the chain
chainId ,uint64 , ,sorts , 2 ,the chain id as reported by the RPC
symbol ,string , ,sorts , 3 ,the symbol of the base currency on the chain
rpcProvider ,string ,http://localhost:8545 ,sorts , 4 ,a valid RPC provider for the chain
remoteExplorer ,string ,http://etherscan.io ,sorts , 5 ,a remote explorer for the chain such as Etherscan
localExplorer ,string ,http://localhost:1234 ,sorts , 6 ,the local explorer for the chain (typically TrueBlocks Explorer)
ipfsGateway ,string ,http://gateway.ipfs.io/ipfs ,sorts , 7 ,an IPFS gateway for pinning the index if enabled
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name ,type ,strDefault ,attributes ,upgrades ,docOrder ,description
address ,address , , , , 1 ,the address of this monitor
deleted ,bool , , , , 8 ,`true` if this monitor has been deleted&#44; `false` otherwise
isEmpty ,bool , , ,>3.1.2:bool , 6 ,`true` if the monitor has no appearances&#44; `false` otherwise
isStaged ,bool , , ,>3.1.2:bool , 7 ,`true` if the monitor file in on the stage&#44; `false` otherwise
fileSize ,int64 , , , , 4 ,the size of this monitor on disc
lastScanned ,uint32 , , , , 5 ,the last scanned block number
nRecords ,int64 , , , , 3 ,the number of appearances for this monitor
address ,address , ,sorts , , 1 ,the address of this monitor
deleted ,bool , ,sorts , , 8 ,`true` if this monitor has been deleted&#44; `false` otherwise
isEmpty ,bool , ,sorts ,>3.1.2:bool , 6 ,`true` if the monitor has no appearances&#44; `false` otherwise
isStaged ,bool , ,sorts ,>3.1.2:bool , 7 ,`true` if the monitor file in on the stage&#44; `false` otherwise
fileSize ,int64 , ,sorts , , 4 ,the size of this monitor on disc
lastScanned ,uint32 , ,sorts , , 5 ,the last scanned block number
nRecords ,int64 , ,sorts , , 3 ,the number of appearances for this monitor
name ,string , , , , 2 ,the name of this monitor (if any)
8 changes: 4 additions & 4 deletions src/dev_tools/goMaker/templates/cmd-line-options.csv
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ num,folder,group,route,tool,longName,hotKey,def_val,attributes,handler,option_ty
14170,apps,Accounts,monitors,acctExport,n4,,,,,note,,,,,,Addresses provided on the command line are ignored in `--watch` mode.
14180,apps,Accounts,monitors,acctExport,n5,,,,,note,,,,,,Providing the value `existing` to the `--watchlist` monitors all existing monitor files (see --list).
#
15000,tools,Accounts,names,ethNames,,,,visible|docs|sorts=name,,command,,,Manage names,[flags] <term> [term...],default|,Query addresses or names of well-known accounts.
15000,tools,Accounts,names,ethNames,,,,visible|docs,,command,,,Manage names,[flags] <term> [term...],default|,Query addresses or names of well-known accounts.
15020,tools,Accounts,names,ethNames,terms,,,required|visible|docs,4,positional,list<string>,name,,,,a space separated list of one or more search terms
15030,tools,Accounts,names,ethNames,expand,e,,visible|docs,,switch,<boolean>,,,,,expand search to include all fields (search name&#44; address&#44; and symbol otherwise)
15040,tools,Accounts,names,ethNames,match_case,m,,visible|docs,,switch,<boolean>,,,,,do case-sensitive search
Expand All @@ -102,7 +102,7 @@ num,folder,group,route,tool,longName,hotKey,def_val,attributes,handler,option_ty
15190,tools,Accounts,names,ethNames,n1,,,,,note,,,,,,The tool will accept up to three terms&#44; each of which must match against any field in the database.
15200,tools,Accounts,names,ethNames,n2,,,,,note,,,,,,The `--match_case` option enables case sensitive matching.
#
16000,tools,Accounts,abis,grabABI,,,,visible|docs|sorts=function:abi,,command,,,Manage Abi files,[flags] <address> [address...],default|caching|names|,Fetches the ABI for a smart contract.
16000,tools,Accounts,abis,grabABI,,,,visible|docs,,command,,,Manage Abi files,[flags] <address> [address...],default|caching|names|,Fetches the ABI for a smart contract.
16020,tools,Accounts,abis,grabABI,addrs,,,required|visible|docs,5,positional,list<addr>,function,,,,a list of one or more smart contracts whose ABIs to display
16030,tools,Accounts,abis,grabABI,known,k,,visible|docs,,switch,<boolean>,,,,,load common 'known' ABIs from cache
16040,tools,Accounts,abis,grabABI,proxy_for,r,,visible|docs,,flag,<address>,,,,,redirects the query to this implementation
Expand Down Expand Up @@ -239,7 +239,7 @@ num,folder,group,route,tool,longName,hotKey,def_val,attributes,handler,option_ty
42030,apps,Admin,config,config,paths,a,,visible|docs,1,switch,<boolean>,cacheItem,,,,show the configuration paths for the system
42040,apps,Admin,config,config,dump,d,,visible|docs,2,switch,<boolean>,config,,,,dump the configuration to stdout
#
43000,apps,Admin,status,cacheStatus,,,,visible|docs|sorts=cacheItem,,command,,,Get status on caches,<mode> [mode...] [flags],default|,Report on the state of the internal binary caches.
43000,apps,Admin,status,cacheStatus,,,,visible|docs,,command,,,Get status on caches,<mode> [mode...] [flags],default|,Report on the state of the internal binary caches.
43020,apps,Admin,status,cacheStatus,modes,,,visible|docs,2,positional,list<enum[index|blooms|blocks|transactions|traces|logs|statements|results|state|tokens|monitors|names|abis|slurps|staging|unripe|maps|some*|all]>,status,,,,the (optional) name of the binary cache to report on&#44; terse otherwise
43030,apps,Admin,status,cacheStatus,diagnose,d,,visible|docs,1,switch,<boolean>,status,,,,same as the default but with additional diagnostics
43040,apps,Admin,status,cacheStatus,first_record,c,,visible|docs,,flag,<uint64>,,,,,the first record to process
Expand Down Expand Up @@ -279,7 +279,7 @@ num,folder,group,route,tool,longName,hotKey,def_val,attributes,handler,option_ty
45150,apps,Admin,scrape,blockScrape,n2,,,,,note,,,,,,This command requires your RPC to provide trace data. See the README for more information.
45150,apps,Admin,scrape,blockScrape,n3,,,,,note,,,,,,The --notify option requires proper configuration. Additionally&#44; IPFS must be running locally. See the README.md file.
#
46000,apps,Admin,chunks,chunkMan,,,,visible|docs|sorts=chunkStats:chunkRecord,,command,,,Manage chunks,<mode> [flags] [blocks...] [address...],default|,Manage&#44; investigate&#44; and display the Unchained Index.
46000,apps,Admin,chunks,chunkMan,,,,visible|docs,,command,,,Manage chunks,<mode> [flags] [blocks...] [address...],default|,Manage&#44; investigate&#44; and display the Unchained Index.
46020,apps,Admin,chunks,chunkMan,mode,,,required|visible|docs,9,positional,enum[manifest|index|blooms|pins|addresses|appearances|stats],mode,,,,the type of data to process
46030,apps,Admin,chunks,chunkMan,blocks,,,visible|docs,,positional,list<blknum>,,,,,an optional list of blocks to intersect with chunk ranges
46040,apps,Admin,chunks,chunkMan,check,c,,visible|docs,1,switch,<boolean>,,,,,check the manifest&#44; index&#44; or blooms for internal consistency
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package sdk

// EXISTING_CODE
// EXISTING_CODE

type SortOrder = types.SortOrder

const (
Asc SortOrder = types.Ascending
Dec SortOrder = types.Descending
)

type SortSpec struct {
Fields []string `json:"fields"`
Order []SortOrder `json:"orders"`
}

{{range .Structures}}
{{ if .HasSorts }}{{.Sorts2}}{{end}}
{{end}}

// EXISTING_CODE
// EXISTING_CODE
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ func (opts {{toProper .Route}}Options) String() string {

{{if .HasSdkEndpoints}}{{.SdkEndpoints}}{{end}}

{{.Enums2}}{{if .HasSorts}}{{.Sorts2}}{{end}}
{{.Enums2}}
// EXISTING_CODE
// EXISTING_CODE
3 changes: 0 additions & 3 deletions src/dev_tools/goMaker/types/types_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,6 @@ func (c *Command) Clean() {
c.Aliases = append(c.Aliases, op.Description)
} else if op.OptionType == "command" {
c.Description = op.Description
if c.HasSorts() {
c.Sorts = getSorts(op.Attributes)
}
} else if op.OptionType == "group" {
// c.Description = op.Description
} else {
Expand Down
63 changes: 15 additions & 48 deletions src/dev_tools/goMaker/types/types_sorts.go
Original file line number Diff line number Diff line change
@@ -1,64 +1,31 @@
package types

import (
"sort"
"strings"
)

func (c *Command) HasSorts() bool {
for _, prod := range c.Productions {
if prod.HasSorts() {
return true
}
}
return strings.Contains(c.Attributes, "sorts=")
// Sorts2 for tag {{.Sorts2}}
func (s *Structure) Sorts2() string {
tmplName := "sortCode"
tmpl := `
func Sort{{toPlural .Class}}({{toLowerPlural .Class}} []types.{{.Class}}, sortSpec SortSpec) error {
if len(sortSpec.Fields) != len(sortSpec.Order) {
return fmt.Errorf("fields and order must have the same length")
}
func getSorts(attributes string) []string {
parts := strings.Split(attributes, "=")
if len(parts) < 2 {
return []string{}
}
parts = strings.Split(parts[1], ":")
ret := []string{}
for _, part := range parts {
ret = append(ret, FirstUpper(part))
sorts := make([]func(p1, p2 types.{{.Class}}) bool, len(sortSpec.Fields))
for i, field := range sortSpec.Fields {
if !types.IsValid{{.Class}}Field(field) {
return fmt.Errorf("%s is not an {{.Class}} sort field", field)
}
sort.Strings(ret)
return ret
sorts[i] = types.{{.Class}}By(types.{{.Class}}Field(field), types.SortOrder(sortSpec.Order[i]))
}
type Sort struct {
Type string
}

// Sorts2 for tag {{.Sorts2}}
func (c *Command) Sorts2() string {
ret := ""
for _, sort := range c.Sorts {
tmplName := "sortCode"
tmpl := `
func Sort{{toPlural .Type}}({{toLowerPlural .Type}} []types.{{.Type}}, sortSpec SortSpec) error {
if len(sortSpec.Fields) != len(sortSpec.Order) {
return fmt.Errorf("fields and order must have the same length")
}
sorts := make([]func(p1, p2 types.{{.Type}}) bool, len(sortSpec.Fields))
for i, field := range sortSpec.Fields {
if !types.IsValid{{.Type}}Field(field) {
return fmt.Errorf("%s is not an {{.Type}} sort field", field)
}
sorts[i] = types.{{.Type}}By(types.{{.Type}}Field(field), types.SortOrder(sortSpec.Order[i]))
}
sort.Slice({{toLowerPlural .Type}}, types.{{.Type}}Cmp({{toLowerPlural .Type}}, sorts...))
return nil
sort.Slice({{toLowerPlural .Class}}, types.{{.Class}}Cmp({{toLowerPlural .Class}}, sorts...))
return nil
}
`
ss := Sort{Type: sort}
ret += executeTemplate(ss, "sort", tmplName, tmpl)
}
return ret
return executeTemplate(*s, "sort", tmplName, tmpl)
}

func (m *Member) IsSortable() bool {
Expand Down

0 comments on commit ba60560

Please sign in to comment.