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  }