Documentation
¶
Overview ¶
Example (Compared) ¶
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/LeGEC/ordmap"
)
func main() {
input := `{
"last_name": "Doe",
"first_name": "John",
"age": 42,
"skills": {
"go": 5,
"python": 3,
"ada": 2,
"rust": 1
}
}`
var std any
var oMap ordmap.Map[string, any]
var oAny ordmap.Any
_ = json.Unmarshal([]byte(input), &std)
_ = json.Unmarshal([]byte(input), &oMap)
_ = json.Unmarshal([]byte(input), &oAny)
var output = json.NewEncoder(os.Stdout)
output.SetIndent("", " ")
output.SetEscapeHTML(false)
fmt.Println("// standard 'any' object: order of keys is not preserved")
output.Encode(std)
fmt.Println()
fmt.Println("// ordmap.Map[string, any]: order of keys is preserved in the root object (last_name, first_name, age, skills),")
fmt.Println("// but with values of 'any' type, not in nested objects:")
fmt.Println("// inside 'skills' object: the order (go, python, ada, rust) is not preserved")
output.Encode(oMap)
fmt.Println()
fmt.Println("// ordmap.Any: order of keys is preserved everywhere")
output.Encode(oAny)
}
Output: // standard 'any' object: order of keys is not preserved { "age": 42, "first_name": "John", "last_name": "Doe", "skills": { "ada": 2, "go": 5, "python": 3, "rust": 1 } } // ordmap.Map[string, any]: order of keys is preserved in the root object (last_name, first_name, age, skills), // but with values of 'any' type, not in nested objects: // inside 'skills' object: the order (go, python, ada, rust) is not preserved { "last_name": "Doe", "first_name": "John", "age": 42, "skills": { "ada": 2, "go": 5, "python": 3, "rust": 1 } } // ordmap.Any: order of keys is preserved everywhere { "last_name": "Doe", "first_name": "John", "age": 42, "skills": { "go": 5, "python": 3, "ada": 2, "rust": 1 } }
Example (OpenapiUseCase) ¶
package main
import (
"bytes"
"encoding/json"
"fmt"
"os"
"github.com/LeGEC/ordmap"
)
func main() {
// a Schema declaration, to match a 'schema' entry in an OpenAPI document,
// limited to the fields visible in the example below (excerpt from the github openapi specification)
type Schema struct {
Ref string `yaml:"$ref,omitempty" json:"$ref,omitempty"`
AnyOf []*Schema `yaml:"anyOf,omitempty" json:"anyOf,omitempty"`
OneOf []*Schema `yaml:"oneOf,omitempty" json:"oneOf,omitempty"`
Title string `yaml:"title,omitempty" json:"title,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Type any `yaml:"type,omitempty" json:"type,omitempty"`
Enum []any `yaml:"enum,omitempty" json:"enum,omitempty"`
Default any `yaml:"default,omitempty" json:"default,omitempty"`
Format string `yaml:"format,omitempty" json:"format,omitempty"`
Items *Schema `yaml:"items,omitempty" json:"items,omitempty"`
// The 'example' field may hold any value, be it a simple scalar or a fully fledged object.
// Using 'ordpmap.Any' here allows to keep the original order if you are into unmarshalling/marshalling
// a schema, and want to have a stable value here
Example *ordmap.Any `yaml:"example,omitempty" json:"example,omitempty"`
Examples []*ordmap.Any `yaml:"examples,omitempty" json:"examples,omitempty"`
// keep Properties in same order as in the original schema
Properties *ordmap.Map[string, *Schema] `yaml:"properties,omitempty" json:"properties,omitempty"`
ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
Required []string `yaml:"required,omitempty" json:"required,omitempty"`
WriteOnly bool `yaml:"writeOnly,omitempty" json:"writeOnly,omitempty"`
}
type Components struct {
Schemas *ordmap.Map[string, *Schema] `yaml:"schemas,omitempty" json:"schemas,omitempty"`
// other fields ...
}
type Document struct {
Components *Components `yaml:"components,omitempty" json:"components,omitempty"`
// other fields ...
}
// file testdata/github.excerpt.3.14.json:
// excerpt from the github openapi specification at:
// https://raw.githubusercontent.com/github/rest-api-description/main/descriptions-next/ghes-3.14/ghes-3.14.2022-11-28.json
//
// you will note that the order of the "properties", for example, is preserved,
// as well as, in the "authentication-token" schema, the "examples" section for "properties.permissions"
inputFile := "testdata/github.excerpt.3.14.json"
input, err := os.ReadFile(inputFile)
var doc Document
err = json.Unmarshal(input, &doc)
if err != nil {
panic(err)
}
marshalled, err := json.MarshalIndent(doc, "", " ")
if err != nil {
panic(err)
}
if bytes.Equal(marshalled, input) {
fmt.Println("fields order from input is preserved")
} else {
fmt.Println("!!! fields order from input is not preserved")
}
}
Output: fields order from input is preserved
Index ¶
- type Any
- type Map
- func (m *Map[K, V]) Clear()
- func (m *Map[K, V]) Clone() *Map[K, V]
- func (m *Map[K, V]) Delete(key K) bool
- func (m *Map[K, V]) ForAll() iter.Seq2[K, V]
- func (m *Map[K, V]) Get(key K) V
- func (m *Map[K, V]) Get2(key K) (V, bool)
- func (m *Map[K, V]) Keys() []K
- func (m *Map[K, V]) Len() int
- func (m Map[K, V]) MarshalJSON() ([]byte, error)
- func (m Map[K, V]) MarshalYAML() (any, error)
- func (m *Map[K, V]) Set(key K, value V)
- func (m *Map[K, V]) UnmarshalJSON(p []byte) error
- func (m *Map[K, V]) UnmarshalYAML(value *yaml.Node) error
- func (m *Map[K, V]) Values() iter.Seq2[int, V]
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Any ¶
type Any struct {
// contains filtered or unexported fields
}
Any wraps an 'any' value.
Its purpose is to be used as the target for `json.Umarshal()` or `yaml.Unmarshal()`, and to create a go structure which keeps track of the order of the keys as they appeared in the initial document.
See the implementation of `Any.UnmarshalJSON()` and `Any.UnmarshalYAML()`
Example (Json) ¶
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/LeGEC/ordmap"
)
func main() {
input := `{
"last_name": "Doe",
"first_name": "John",
"age": 42,
"skills": {
"go": 5,
"python": 3,
"ada": 2,
"rust": 1
}
}`
var x ordmap.Any
_ = json.Unmarshal([]byte(input), &x)
// ordmap.Any: all objects, including nested, are unmarshalled as ordmap.Map,
// the order of keys is preserved everywhere
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
enc.Encode(x)
fmt.Println()
obj := x.V().(*ordmap.Map[string, any])
// the type for any json object is '*ordmap.Map[string, any]':
fmt.Printf("type for skills: %T\n", obj.Get("skills"))
// the type for other fields is the regular go type for generic unmarshalling
fmt.Printf("type for first_name: %T\n", obj.Get("first_name"))
}
Output: { "last_name": "Doe", "first_name": "John", "age": 42, "skills": { "go": 5, "python": 3, "ada": 2, "rust": 1 } } type for skills: *ordmap.Map[string,interface {}] type for first_name: string
Example (Yaml) ¶
input := ` last_name: Doe first_name: John age: 42 skills: go: 5 python: 3 ada: 2 rust: 1` var x ordmap.Any _ = yaml.Unmarshal([]byte(input), &x) // ordmap.Any: all objects, including nested, are unmarshalled as ordmap.Map, // the order of keys is preserved everywhere enc := yaml.NewEncoder(os.Stdout) enc.SetIndent(2) enc.Encode(x)
Output: last_name: Doe first_name: John age: 42 skills: go: 5 python: 3 ada: 2 rust: 1
func (Any) MarshalJSON ¶
func (Any) MarshalYAML ¶
func (*Any) UnmarshalJSON ¶
type Map ¶
type Map[K comparable, V any] struct { // contains filtered or unexported fields }
Map is a map which preserves the order in which the keys were inserted.
Its main feature is to implement the 4 following interfaces:
- `json.Marshaler` (from standard package `encoding/json`)
- `json.Unmarshaler` (from standard package `encoding/json`)
- `yaml.Marshaler` (from package `gopkg.in/yaml.v3`)
- `yaml.Unmarshaler` (from package `gopkg.in/yaml.v3`)
in a way that preserves the order of the keys in the source data.
Example (Json) ¶
package main
import (
"encoding/json"
"os"
"github.com/LeGEC/ordmap"
)
func main() {
input := `{
"last_name": "Doe",
"first_name": "John",
"age": 42,
"skills": {
"go": 5,
"python": 3,
"ada": 2,
"rust": 1
}
}`
var x ordmap.Map[string, any]
_ = json.Unmarshal([]byte(input), &x)
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
// ordmap.Map[string, any]: the order of the keys in the root object is preserved,
// but with values of type 'any', the order in nested objects is not preserved.
enc.Encode(x)
}
Output: { "last_name": "Doe", "first_name": "John", "age": 42, "skills": { "ada": 2, "go": 5, "python": 3, "rust": 1 } }
Example (Yaml) ¶
input := ` last_name: Doe first_name: John age: 42 skills: go: 5 python: 3 ada: 2 rust: 1` var x ordmap.Map[string, any] _ = yaml.Unmarshal([]byte(input), &x) enc := yaml.NewEncoder(os.Stdout) enc.SetIndent(2) // ordmap.Map[string, any]: the order of the keys in the root object is preserved, // but with an 'any' type as value, the order in nested objects is not preserved. enc.Encode(x)
Output: last_name: Doe first_name: John age: 42 skills: ada: 2 go: 5 python: 3 rust: 1
func (Map[K, V]) MarshalJSON ¶
func (Map[K, V]) MarshalYAML ¶
func (*Map[K, V]) UnmarshalJSON ¶
Click to show internal directories.
Click to hide internal directories.