map.go (2951B)
1 package query 2 3 import ( 4 "fmt" 5 "net/url" 6 ) 7 8 // Map represents the encoding of Query maps. A Query map is a representation 9 // of a mapping of arbitrary string keys to arbitrary values of a fixed type. 10 // A Map differs from an Object in that the set of keys is not fixed, in that 11 // the values must all be of the same type, and that map entries are ordered. 12 // A serialized map might look like the following: 13 // 14 // MapName.entry.1.key=Foo 15 // &MapName.entry.1.value=spam 16 // &MapName.entry.2.key=Bar 17 // &MapName.entry.2.value=eggs 18 type Map struct { 19 // The query values to add the map to. 20 values url.Values 21 // The map's prefix, which includes the names of all parent structures 22 // and ends with the name of the object. For example, the prefix might be 23 // "ParentStructure.MapName". This prefix will be used to form the full 24 // keys for each key-value pair of the map. For example, a value might have 25 // the key "ParentStructure.MapName.1.value". 26 // 27 // While this is currently represented as a string that gets added to, it 28 // could also be represented as a stack that only gets condensed into a 29 // string when a finalized key is created. This could potentially reduce 30 // allocations. 31 prefix string 32 // Whether the map is flat or not. A map that is not flat will produce the 33 // following entries to the url.Values for a given key-value pair: 34 // MapName.entry.1.KeyLocationName=mykey 35 // MapName.entry.1.ValueLocationName=myvalue 36 // A map that is flat will produce the following: 37 // MapName.1.KeyLocationName=mykey 38 // MapName.1.ValueLocationName=myvalue 39 flat bool 40 // The location name of the key. In most cases this should be "key". 41 keyLocationName string 42 // The location name of the value. In most cases this should be "value". 43 valueLocationName string 44 // Elements are stored in values, so we keep track of the list size here. 45 size int32 46 } 47 48 func newMap(values url.Values, prefix string, flat bool, keyLocationName string, valueLocationName string) *Map { 49 return &Map{ 50 values: values, 51 prefix: prefix, 52 flat: flat, 53 keyLocationName: keyLocationName, 54 valueLocationName: valueLocationName, 55 } 56 } 57 58 // Key adds the given named key to the Query map. 59 // Returns a Value encoder that should be used to encode a Query value type. 60 func (m *Map) Key(name string) Value { 61 // Query lists start a 1, so adjust the size first 62 m.size++ 63 var key string 64 var value string 65 if m.flat { 66 key = fmt.Sprintf("%s.%d.%s", m.prefix, m.size, m.keyLocationName) 67 value = fmt.Sprintf("%s.%d.%s", m.prefix, m.size, m.valueLocationName) 68 } else { 69 key = fmt.Sprintf("%s.entry.%d.%s", m.prefix, m.size, m.keyLocationName) 70 value = fmt.Sprintf("%s.entry.%d.%s", m.prefix, m.size, m.valueLocationName) 71 } 72 73 // The key can only be a string, so we just go ahead and set it here 74 newValue(m.values, key, false).String(name) 75 76 // Maps can't have flat members 77 return newValue(m.values, value, false) 78 }