| 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 |
| } |