package query import ( "fmt" "net/url" ) // Map represents the encoding of Query maps. A Query map is a representation // of a mapping of arbitrary string keys to arbitrary values of a fixed type. // A Map differs from an Object in that the set of keys is not fixed, in that // the values must all be of the same type, and that map entries are ordered. // A serialized map might look like the following: // // MapName.entry.1.key=Foo // &MapName.entry.1.value=spam // &MapName.entry.2.key=Bar // &MapName.entry.2.value=eggs type Map struct { // The query values to add the map to. values url.Values // The map's prefix, which includes the names of all parent structures // and ends with the name of the object. For example, the prefix might be // "ParentStructure.MapName". This prefix will be used to form the full // keys for each key-value pair of the map. For example, a value might have // the key "ParentStructure.MapName.1.value". // // While this is currently represented as a string that gets added to, it // could also be represented as a stack that only gets condensed into a // string when a finalized key is created. This could potentially reduce // allocations. prefix string // Whether the map is flat or not. A map that is not flat will produce the // following entries to the url.Values for a given key-value pair: // MapName.entry.1.KeyLocationName=mykey // MapName.entry.1.ValueLocationName=myvalue // A map that is flat will produce the following: // MapName.1.KeyLocationName=mykey // MapName.1.ValueLocationName=myvalue flat bool // The location name of the key. In most cases this should be "key". keyLocationName string // The location name of the value. In most cases this should be "value". valueLocationName string // Elements are stored in values, so we keep track of the list size here. size int32 } func newMap(values url.Values, prefix string, flat bool, keyLocationName string, valueLocationName string) *Map { return &Map{ values: values, prefix: prefix, flat: flat, keyLocationName: keyLocationName, valueLocationName: valueLocationName, } } // Key adds the given named key to the Query map. // Returns a Value encoder that should be used to encode a Query value type. func (m *Map) Key(name string) Value { // Query lists start a 1, so adjust the size first m.size++ var key string var value string if m.flat { key = fmt.Sprintf("%s.%d.%s", m.prefix, m.size, m.keyLocationName) value = fmt.Sprintf("%s.%d.%s", m.prefix, m.size, m.valueLocationName) } else { key = fmt.Sprintf("%s.entry.%d.%s", m.prefix, m.size, m.keyLocationName) value = fmt.Sprintf("%s.entry.%d.%s", m.prefix, m.size, m.valueLocationName) } // The key can only be a string, so we just go ahead and set it here newValue(m.values, key, false).String(name) // Maps can't have flat members return newValue(m.values, value, false) }