github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/mongo/utils/data_cleansing.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package utils 5 6 import "strings" 7 8 // EscapeKeys is used to escape bad keys in a map. A statusDoc without 9 // escaped keys is broken. 10 func EscapeKeys(input map[string]interface{}) map[string]interface{} { 11 return mapKeys(escapeReplacer.Replace, input) 12 } 13 14 // UnescapeKeys is used to restore escaped keys from a map to their 15 // original values. 16 func UnescapeKeys(input map[string]interface{}) map[string]interface{} { 17 return mapKeys(unescapeReplacer.Replace, input) 18 } 19 20 // EscapeKey escapes a string to be safe to store in Mongo as a document key. 21 func EscapeKey(s string) string { 22 return escapeReplacer.Replace(s) 23 } 24 25 // UnescapeKey restores escaped characters from a key to their 26 // original values. 27 func UnescapeKey(s string) string { 28 return unescapeReplacer.Replace(s) 29 } 30 31 // See: http://docs.mongodb.org/manual/faq/developers/#faq-dollar-sign-escaping 32 // for why we're using those replacements. 33 const ( 34 fullWidthDot = "\uff0e" 35 fullWidthDollar = "\uff04" 36 ) 37 38 var ( 39 escapeReplacer = strings.NewReplacer(".", fullWidthDot, "$", fullWidthDollar) 40 unescapeReplacer = strings.NewReplacer(fullWidthDot, ".", fullWidthDollar, "$") 41 ) 42 43 // mapKeys returns a copy of the supplied map, with all nested map[string]interface{} 44 // keys transformed by f. All other types are ignored. 45 func mapKeys(f func(string) string, input map[string]interface{}) map[string]interface{} { 46 result := make(map[string]interface{}) 47 for key, value := range input { 48 if submap, ok := value.(map[string]interface{}); ok { 49 value = mapKeys(f, submap) 50 } 51 result[f(key)] = value 52 } 53 return result 54 }