accessors.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package objx
  2. import (
  3. "regexp"
  4. "strconv"
  5. "strings"
  6. )
  7. // arrayAccesRegexString is the regex used to extract the array number
  8. // from the access path
  9. const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
  10. // arrayAccesRegex is the compiled arrayAccesRegexString
  11. var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
  12. // Get gets the value using the specified selector and
  13. // returns it inside a new Obj object.
  14. //
  15. // If it cannot find the value, Get will return a nil
  16. // value inside an instance of Obj.
  17. //
  18. // Get can only operate directly on map[string]interface{} and []interface.
  19. //
  20. // Example
  21. //
  22. // To access the title of the third chapter of the second book, do:
  23. //
  24. // o.Get("books[1].chapters[2].title")
  25. func (m Map) Get(selector string) *Value {
  26. rawObj := access(m, selector, nil, false)
  27. return &Value{data: rawObj}
  28. }
  29. // Set sets the value using the specified selector and
  30. // returns the object on which Set was called.
  31. //
  32. // Set can only operate directly on map[string]interface{} and []interface
  33. //
  34. // Example
  35. //
  36. // To set the title of the third chapter of the second book, do:
  37. //
  38. // o.Set("books[1].chapters[2].title","Time to Go")
  39. func (m Map) Set(selector string, value interface{}) Map {
  40. access(m, selector, value, true)
  41. return m
  42. }
  43. // access accesses the object using the selector and performs the
  44. // appropriate action.
  45. func access(current, selector, value interface{}, isSet bool) interface{} {
  46. switch selector.(type) {
  47. case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
  48. if array, ok := current.([]interface{}); ok {
  49. index := intFromInterface(selector)
  50. if index >= len(array) {
  51. return nil
  52. }
  53. return array[index]
  54. }
  55. return nil
  56. case string:
  57. selStr := selector.(string)
  58. selSegs := strings.SplitN(selStr, PathSeparator, 2)
  59. thisSel := selSegs[0]
  60. index := -1
  61. var err error
  62. if strings.Contains(thisSel, "[") {
  63. arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
  64. if len(arrayMatches) > 0 {
  65. // Get the key into the map
  66. thisSel = arrayMatches[1]
  67. // Get the index into the array at the key
  68. index, err = strconv.Atoi(arrayMatches[2])
  69. if err != nil {
  70. // This should never happen. If it does, something has gone
  71. // seriously wrong. Panic.
  72. panic("objx: Array index is not an integer. Must use array[int].")
  73. }
  74. }
  75. }
  76. if curMap, ok := current.(Map); ok {
  77. current = map[string]interface{}(curMap)
  78. }
  79. // get the object in question
  80. switch current.(type) {
  81. case map[string]interface{}:
  82. curMSI := current.(map[string]interface{})
  83. if len(selSegs) <= 1 && isSet {
  84. curMSI[thisSel] = value
  85. return nil
  86. }
  87. current = curMSI[thisSel]
  88. default:
  89. current = nil
  90. }
  91. // do we need to access the item of an array?
  92. if index > -1 {
  93. if array, ok := current.([]interface{}); ok {
  94. if index < len(array) {
  95. current = array[index]
  96. } else {
  97. current = nil
  98. }
  99. }
  100. }
  101. if len(selSegs) > 1 {
  102. current = access(current, selSegs[1], value, isSet)
  103. }
  104. }
  105. return current
  106. }
  107. // intFromInterface converts an interface object to the largest
  108. // representation of an unsigned integer using a type switch and
  109. // assertions
  110. func intFromInterface(selector interface{}) int {
  111. var value int
  112. switch selector.(type) {
  113. case int:
  114. value = selector.(int)
  115. case int8:
  116. value = int(selector.(int8))
  117. case int16:
  118. value = int(selector.(int16))
  119. case int32:
  120. value = int(selector.(int32))
  121. case int64:
  122. value = int(selector.(int64))
  123. case uint:
  124. value = int(selector.(uint))
  125. case uint8:
  126. value = int(selector.(uint8))
  127. case uint16:
  128. value = int(selector.(uint16))
  129. case uint32:
  130. value = int(selector.(uint32))
  131. case uint64:
  132. value = int(selector.(uint64))
  133. default:
  134. return 0
  135. }
  136. return value
  137. }