github.com/huaweicloud/golangsdk@v0.0.0-20210831081626-d823fe11ceba/pagination/linked.go (about) 1 package pagination 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/huaweicloud/golangsdk" 8 ) 9 10 // LinkedPageBase may be embedded to implement a page that provides navigational "Next" and "Previous" links within its result. 11 type LinkedPageBase struct { 12 PageResult 13 14 // LinkPath lists the keys that should be traversed within a response to arrive at the "next" pointer. 15 // If any link along the path is missing, an empty URL will be returned. 16 // If any link results in an unexpected value type, an error will be returned. 17 // When left as "nil", []string{"links", "next"} will be used as a default. 18 LinkPath []string 19 } 20 21 // NextPageURL extracts the pagination structure from a JSON response and returns the "next" link, if one is present. 22 // It assumes that the links are available in a "links" element of the top-level response object. 23 // If this is not the case, override NextPageURL on your result type. 24 func (current LinkedPageBase) NextPageURL() (string, error) { 25 var path []string 26 var key string 27 28 if current.LinkPath == nil { 29 path = []string{"links", "next"} 30 } else { 31 path = current.LinkPath 32 } 33 34 submap, ok := current.Body.(map[string]interface{}) 35 if !ok { 36 err := golangsdk.ErrUnexpectedType{} 37 err.Expected = "map[string]interface{}" 38 err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) 39 return "", err 40 } 41 42 for { 43 key, path = path[0], path[1:] 44 45 value, ok := submap[key] 46 if !ok { 47 return "", nil 48 } 49 50 if len(path) > 0 { 51 submap, ok = value.(map[string]interface{}) 52 if !ok { 53 err := golangsdk.ErrUnexpectedType{} 54 err.Expected = "map[string]interface{}" 55 err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value)) 56 return "", err 57 } 58 } else { 59 if value == nil { 60 // Actual null element. 61 return "", nil 62 } 63 64 url, ok := value.(string) 65 if !ok { 66 err := golangsdk.ErrUnexpectedType{} 67 err.Expected = "string" 68 err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value)) 69 return "", err 70 } 71 72 return url, nil 73 } 74 } 75 } 76 77 // IsEmpty satisifies the IsEmpty method of the Page interface 78 func (current LinkedPageBase) IsEmpty() (bool, error) { 79 if b, ok := current.Body.([]interface{}); ok { 80 return len(b) == 0, nil 81 } 82 err := golangsdk.ErrUnexpectedType{} 83 err.Expected = "[]interface{}" 84 err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) 85 return true, err 86 } 87 88 // GetBody returns the linked page's body. This method is needed to satisfy the 89 // Page interface. 90 func (current LinkedPageBase) GetBody() interface{} { 91 return current.Body 92 } 93 94 // WrapNextPageURL function use makerID to warp next page url,it returns the full url for request. 95 func (current LinkedPageBase) WrapNextPageURL(markerID string) (string, error) { 96 limit := current.URL.Query().Get("limit") 97 98 if limit == "" { 99 return "", nil 100 } 101 102 q := current.URL.Query() 103 104 q.Set("marker", markerID) 105 current.URL.RawQuery = q.Encode() 106 return current.URL.String(), nil 107 }