Documentation ¶
Overview ¶
Package retag provides an ability to change tags of structures' fields in runtime without copying of the data. It may be helpful in next cases:
- Automatic tags generation;
- Different views of the one data;
- Fixing of leaky abstractions with minimal boilerplate code when application has layers of abstractions and model is separated from storages and presentation layers.
Features:
- No memory allocations (for cached types);
- Fast converting (lookup in table and pointer creation for cached types).
The package requires go1.7+.
The package is still experimental and subject to change. The package can be broken by a next release of go.
Example (Snaker) ¶
type UserProfile struct { Id int64 `json:"_id"` Name string CardNumber string SupportNote string } profile := &UserProfile{ Id: 7, Name: "Duke Nukem", CardNumber: "4378 0990 7823 1019", SupportNote: "Strange customer", } userView := Convert(profile, Snaker("json")) b, _ := json.MarshalIndent(userView, "", " ") fmt.Println(string(b))
Output: { "_id": 7, "name": "Duke Nukem", "card_number": "4378 0990 7823 1019", "support_note": "Strange customer" }
Example (ViewOfData) ¶
type UserProfile struct { Id int64 `view:"-"` Name string `view:"*"` CardNumber string `view:"user"` SupportNote string `view:"support"` } profile := &UserProfile{ Id: 7, Name: "Duke Nukem", CardNumber: "4378 0990 7823 1019", SupportNote: "Strange customer", } userView := Convert(profile, NewView("json", "user")) supportView := Convert(profile, NewView("json", "support")) // Now profile, userView and supportView point // on the same memory but have different types // with different tags. b, _ := json.MarshalIndent(userView, "", " ") fmt.Println(string(b)) b, _ = json.MarshalIndent(supportView, "", " ") fmt.Println(string(b))
Output: { "Name": "Duke Nukem", "CardNumber": "4378 0990 7823 1019" } { "Name": "Duke Nukem", "SupportNote": "Strange customer" }
Index ¶
- func CamelToSnake(src string) string
- func Convert(p interface{}, maker TagMaker) interface{}
- func ConvertAny(p interface{}, maker TagMaker) interface{}
- func SetJSONTag(v interface{}, field, tagValue string, args ...string) interface{}
- type Cameler
- type Custom
- type JSONTagValue
- type JSONTagValues
- type Pascaler
- type Snaker
- type TagMaker
- Bugs
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CamelToSnake ¶
func Convert ¶
func Convert(p interface{}, maker TagMaker) interface{}
Convert converts the given interface p, to a runtime-generated type. The type is generated on base of source type by the next rules:
- Analogous type with custom tags is generated for structures. The tag for every field is generated by the maker;
- Type is replaced with a generated one if it has field, element or key of type which should be replaced with its own analogue or if it is structure.
- A type of private fields of structures is not modified.
Convert panics if argument p has a type different from a pointer to structure. The maker's underlying type should be comparable. In different case panic occurs.
Convert panics if the maker attempts to change a field tag of a structure with unexported fields because reflect package doesn't support creation of a structure type with private fields.
Convert puts generated types in a cache by a key (source type + maker) to speed up handling of types. See notes in description of TagMaker interface to avoid the tricky situation with the cache.
Convert doesn't support cyclic references because reflect package doesn't support generation of types with cyclic references. Passing cyclic structures to Convert will result in an infinite recursion.
Convert doesn't support any interfaces, functions, chan and unsafe pointers. Interfaces is not supported because they requires memory-copy operations in most cases. Passing structures that contains unsupported types to Convert will result in a panic.
Convert doesn't reconstruct methods for a structure type until go1.9 because it is not supported by reflect package. Convert can raise a panic since go1.9 if a structure derivative type has too much methods (more than 32).
BUG(yar): Convert panics on structure with a final zero-size field in go1.7. It is fixed in go1.8 (see github.com/golang/go/issues/18016).
func ConvertAny ¶
func ConvertAny(p interface{}, maker TagMaker) interface{}
ConvertAny is basically the same as Convert except it doesn't panic in case if struct field has empty interface type, it's just left unchanged
func SetJSONTag ¶
Types ¶
type JSONTagValue ¶
func NewJSONTagValue ¶
func NewJSONTagValue(field, tagValue string) JSONTagValue
type JSONTagValues ¶
type JSONTagValues []JSONTagValue
func NewJSONTagValues ¶
func NewJSONTagValues(field, tagValue string) *JSONTagValues
func (*JSONTagValues) Add ¶
func (f *JSONTagValues) Add(field, tagValue string)
type TagMaker ¶
type TagMaker interface { // MakeTag makes tag for the field the fieldIndex in the structureType. // Result should depends on constant parameters of creation of the TagMaker and parameters // passed to the MakeTag. The MakeTag should not produce side effects (like a pure function). MakeTag(structureType reflect.Type, fieldIndex int, path string) reflect.StructTag }
A TagMaker interface is used by the Convert function to generate tags for structures. A type that implements TagMaker should be comparable.
func NewView ¶
NewView creates TagMaker which makes tag for structure's field by the next rules:
- If field's tag contains value with key 'view' and the value matches with value passed in the 'name' parameter, the maker returns the key passed in the 'tag' parameter with its value (if presented) from field's tag or empty string;
- If field's tag contains value with key 'view' and the value doesn't match with value passed in the 'name' parameter, the maker returns `<tag>:"-"`;
- If field's tag doesn't contain 'view' section, the maker returns value of the original tag.
Section view may contain comma-separated list of views or '*'. '*' matches any view.
Examples for NewView("json", "admin"):
`` -> `` `xml:"name"` -> `xml:"name"` `view:"-"` -> `json:"-"` `view:"user"` -> `json:"-"` `view:"*"` -> `` `view:"admin"` -> `` `view:"user,admin"` -> `` `view:"admin" json:"Name,omitempty"` -> `json:"Name,omitempty"`
See package examples additionally.
Notes ¶
Bugs ¶
Convert panics on structure with a final zero-size field in go1.7. It is fixed in go1.8 (see github.com/golang/go/issues/18016).