linked.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package pagination
  2. import (
  3. "fmt"
  4. "reflect"
  5. "devel.mephi.ru/iacherepanov/openstack-gophercloud"
  6. )
  7. // LinkedPageBase may be embedded to implement a page that provides navigational "Next" and "Previous" links within its result.
  8. type LinkedPageBase struct {
  9. PageResult
  10. // LinkPath lists the keys that should be traversed within a response to arrive at the "next" pointer.
  11. // If any link along the path is missing, an empty URL will be returned.
  12. // If any link results in an unexpected value type, an error will be returned.
  13. // When left as "nil", []string{"links", "next"} will be used as a default.
  14. LinkPath []string
  15. }
  16. // NextPageURL extracts the pagination structure from a JSON response and returns the "next" link, if one is present.
  17. // It assumes that the links are available in a "links" element of the top-level response object.
  18. // If this is not the case, override NextPageURL on your result type.
  19. func (current LinkedPageBase) NextPageURL() (string, error) {
  20. var path []string
  21. var key string
  22. if current.LinkPath == nil {
  23. path = []string{"links", "next"}
  24. } else {
  25. path = current.LinkPath
  26. }
  27. submap, ok := current.Body.(map[string]interface{})
  28. if !ok {
  29. err := gophercloud.ErrUnexpectedType{}
  30. err.Expected = "map[string]interface{}"
  31. err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body))
  32. return "", err
  33. }
  34. for {
  35. key, path = path[0], path[1:len(path)]
  36. value, ok := submap[key]
  37. if !ok {
  38. return "", nil
  39. }
  40. if len(path) > 0 {
  41. submap, ok = value.(map[string]interface{})
  42. if !ok {
  43. err := gophercloud.ErrUnexpectedType{}
  44. err.Expected = "map[string]interface{}"
  45. err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value))
  46. return "", err
  47. }
  48. } else {
  49. if value == nil {
  50. // Actual null element.
  51. return "", nil
  52. }
  53. url, ok := value.(string)
  54. if !ok {
  55. err := gophercloud.ErrUnexpectedType{}
  56. err.Expected = "string"
  57. err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value))
  58. return "", err
  59. }
  60. return url, nil
  61. }
  62. }
  63. }
  64. // IsEmpty satisifies the IsEmpty method of the Page interface
  65. func (current LinkedPageBase) IsEmpty() (bool, error) {
  66. if b, ok := current.Body.([]interface{}); ok {
  67. return len(b) == 0, nil
  68. }
  69. err := gophercloud.ErrUnexpectedType{}
  70. err.Expected = "[]interface{}"
  71. err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body))
  72. return true, err
  73. }
  74. // GetBody returns the linked page's body. This method is needed to satisfy the
  75. // Page interface.
  76. func (current LinkedPageBase) GetBody() interface{} {
  77. return current.Body
  78. }