package pagination import ( "fmt" "reflect" "github.com/gophercloud/gophercloud" ) // LinkedPageBase may be embedded to implement a page that provides navigational "Next" and "Previous" links within its result. type LinkedPageBase struct { PageResult // LinkPath lists the keys that should be traversed within a response to arrive at the "next" pointer. // If any link along the path is missing, an empty URL will be returned. // If any link results in an unexpected value type, an error will be returned. // When left as "nil", []string{"links", "next"} will be used as a default. LinkPath []string } // NextPageURL extracts the pagination structure from a JSON response and returns the "next" link, if one is present. // It assumes that the links are available in a "links" element of the top-level response object. // If this is not the case, override NextPageURL on your result type. func (current LinkedPageBase) NextPageURL() (string, error) { var path []string var key string if current.LinkPath == nil { path = []string{"links", "next"} } else { path = current.LinkPath } submap, ok := current.Body.(map[string]interface{}) if !ok { err := gophercloud.ErrUnexpectedType{} err.Expected = "map[string]interface{}" err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) return "", err } for { key, path = path[0], path[1:len(path)] value, ok := submap[key] if !ok { return "", nil } if len(path) > 0 { submap, ok = value.(map[string]interface{}) if !ok { err := gophercloud.ErrUnexpectedType{} err.Expected = "map[string]interface{}" err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value)) return "", err } } else { if value == nil { // Actual null element. return "", nil } url, ok := value.(string) if !ok { err := gophercloud.ErrUnexpectedType{} err.Expected = "string" err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value)) return "", err } return url, nil } } } // IsEmpty satisifies the IsEmpty method of the Page interface func (current LinkedPageBase) IsEmpty() (bool, error) { if b, ok := current.Body.([]interface{}); ok { return len(b) == 0, nil } err := gophercloud.ErrUnexpectedType{} err.Expected = "[]interface{}" err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) return true, err } // GetBody returns the linked page's body. This method is needed to satisfy the // Page interface. func (current LinkedPageBase) GetBody() interface{} { return current.Body }