tyson

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2022 License: Apache-2.0 Imports: 0 Imported by: 0

README

deep-rent/tyson

Logo

Tyson is a tiny Go library that helps with navigating hierarchies of unknown or dynamic JSON structures parsed into map[string]any. It aims to hide the messy type and existence checks that usually occur when dealing with such structures.

Test Status Documentation Code Quality

Installation

Download the libary using go get:

go get github.com/deep-rent/tyson@latest

Add the following import to your project:

import (
    "github.com/deep-rent/tyson"
)

Usage

Start by parsing your JSON into tyson.Object. This type is simply an alias for map[string]any:

var o tyson.Object
_ = json.Unmarshal([]byte(`
{
    "obj": {
        "num": 42,
        "str": "abc"
    },
    "arr": [true, false]
}
`), &o)

Using the GetXXX() methods, you can fetch specific values from the wrapped structure in a type-safe manner. Getters are available for Go equivalents of all JSON types, including arrays. Each getter can take multiple keys to target nested values:

fmt.Printf("num: %d\n", o.GetInt("obj", "num").Value())
fmt.Printf("str: %q\n", o.GetString("obj", "str").Value())
fmt.Printf("arr: %v\n", o.GetBools("arr").Value())

Output:

num: 42
str: "abc"
arr: [true false]

Note that the getters don't directly return the target values but rather instances of the tyson.Node interface. This is important because the target value might be of an unexpected type, or might not exist at all. In that case, the returned node is Empty(), and a default value can be provided using Or() and OrGet():

xyz := o.Get("xyz")
str := o.GetString("obj", "num")

fmt.Printf(`key "xyz" does not exist: %t`+"\n", xyz.Empty())
fmt.Printf(`val "num" isn't a string: %t`+"\n", str.Empty())

fmt.Printf("xyz: %v\n", xyz.Or("def"))
fmt.Printf("str: %s\n", str.OrGet(func() string { return "def" }))

Output:

key "xyz" does not exist: true
val "num" isn't a string: true
xyz: def
str: def

Remarks

  • Parsing JSON into map[string]any is known to be slow. If you deal with large JSON objects, or target only a small subset of the entire structure, you should look for libraries that implement specialized parsers.
  • The GetInt and GetInts methods of Object require the target value to actually be an integral number. For example, 42 and 42.00 are valid integers, but 42.01 causes the getters to return an empty Node.

License

Licensed under the Apache 2.0 License. For the full copyright and licensing information, please view the LICENSE file that was distributed with this source code.

Documentation

Overview

Package tyson provides a wrapper for navigating hierarchies of unknown or dynamic JSON objects parsed into map[string]any. It aims to hide the messy type and existence checks that usually occur when dealing with such structures.

Example (Default_values)

This example explains how to return a default value for target values that either don't exist or have a wrong type.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/deep-rent/tyson"
)

func main() {
	var o tyson.Object
	_ = json.Unmarshal([]byte(`{ "num": 12.34 }`), &o)

	xyz := o.Get("xyz")
	str := o.GetString("num")

	fmt.Printf(`key "xyz" does not exist: %t`+"\n", xyz.Empty())
	fmt.Printf(`val "num" isn't a string: %t`+"\n", str.Empty())

	fmt.Printf("xyz: %v\n", xyz.Or("def"))
	fmt.Printf("str: %s\n", str.OrGet(func() string { return "def" }))

}
Output:

key "xyz" does not exist: true
val "num" isn't a string: true
xyz: def
str: def
Example (Type_getters)

This example showcases the retrieval of various types from a parsed JSON object.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/deep-rent/tyson"
)

func main() {
	var o tyson.Object
	_ = json.Unmarshal([]byte(`
	{
		"obj": {
			"num": 12.34,
			"int": 12345,
			"str": "abc"
		},
		"arr": [true, false]
	}
	`), &o)

	fmt.Printf("num: %.2f\n", o.GetFloat("obj", "num").Value())
	fmt.Printf("int: %d\n", o.GetInt("obj", "int").Value())
	fmt.Printf("str: %q\n", o.GetString("obj", "str").Value())
	fmt.Printf("arr: %v\n", o.GetBools("arr").Value())

}
Output:

num: 12.34
int: 12345
str: "abc"
arr: [true false]

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AsArray added in v1.1.0

func AsArray(v any) (w []any, ok bool)

func AsBool added in v1.1.0

func AsBool(v any) (w bool, ok bool)

func AsFloat added in v1.1.0

func AsFloat(v any) (w float64, ok bool)

func AsInt added in v1.1.0

func AsInt(v float64) (w int64, ok bool)

func AsString added in v1.1.0

func AsString(v any) (w string, ok bool)

Types

type Mapper

type Mapper[S any, T any] func(v S) (w T, ok bool)

A Mapper converts type S into type T. If the conversion succeeded, ok will be true; if not, ok will be false. This is essentially a generic abstraction of the "comma ok" idiom used in Go type casts.

func All

func All[S, T any](m Mapper[S, T]) Mapper[[]S, []T]

All "lifts" m to convert a slice of item type S into a slice of item type T. The resulting Mapper indicates ok if and only if m was successfully applied to each element of the input slice.

func And added in v1.3.0

func And[R, S, T any](m Mapper[R, S], n Mapper[S, T]) Mapper[R, T]

And returns a composed Mapper that first applies m and then n.

func One added in v1.2.0

func One[S, T any](mappers ...Mapper[S, T]) Mapper[S, T]

One returns a Mapper that applies the given mappers one after another until the first to succeed. It fails if none of the mappers succeed.

type Node

type Node[T any] interface {
	// Value returns the contained value if present, or else the
	// zero value of T.
	Value() T
	// Empty returns true if no value is present, otherwise false.
	Empty() bool
	// Or returns the contained value if present, otherwise v.
	Or(v T) T
	// OrGet returns the contained value if present, or else the
	// result produced by f.
	OrGet(f func() T) T
}

A Node is a container which may or may not contain a value of type T. If a value is present, Empty returns false and Value will return the value. Additional methods that depend on the presence or absence of a contained value are provided, such as Or which returns a default value if this Node is empty.

Use EmptyNode or ValueNode to create empty or nonempty Nodes respectively.

func EmptyNode

func EmptyNode[T any]() Node[T]

EmptyNode returns an empty Node of type T.

func Map

func Map[S, T any](n Node[S], m Mapper[S, T]) Node[T]

Map applies m to convert the value contained in n. If n is empty, the resulting Node will be empty as well.

func ValueNode

func ValueNode[T any](v T) Node[T]

ValueNode returns a nonempty Node containing v.

type Object

type Object map[string]any

An Object represents the result of parsing an unknown or dynamic JSON object. Provided getters can be used to navigate the object hierarchy in a type-safe manner.

func AsObject added in v1.1.0

func AsObject(v any) (w Object, ok bool)

func (Object) Get

func (o Object) Get(keys ...string) Node[any]

Get follows the given hierarchy of keys to locate a target value within the underlying JSON structure. The returned Node is empty if some key does not exist, or else contains the target value. If no key is passed, the returned Node contains this Object.

The following example fetches the nested value of "c" from the parsed JSON object:

var o tyson.Object
_ = json.Unmarshal([]byte(`{"a":{"b":{"c":"d"}}}`), &o)
fmt.Print(o.Get("a", "b", "c").Value()) // prints "d"

func (Object) GetArray

func (o Object) GetArray(keys ...string) Node[[]any]

GetArray follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON array. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetArrays

func (o Object) GetArrays(keys ...string) Node[[][]any]

GetArrays follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a two-dimensional JSON array. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetBool

func (o Object) GetBool(keys ...string) Node[bool]

GetBool follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON boolean. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetBools

func (o Object) GetBools(keys ...string) Node[[]bool]

GetBools follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON array of only booleans. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetFloat

func (o Object) GetFloat(keys ...string) Node[float64]

GetFloat follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON number. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetFloats

func (o Object) GetFloats(keys ...string) Node[[]float64]

GetFloats follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON array of only numbers. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetInt

func (o Object) GetInt(keys ...string) Node[int64]

GetInt follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not an integral JSON number. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetInts

func (o Object) GetInts(keys ...string) Node[[]int64]

GetInts follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON array of only integral numbers. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetObject

func (o Object) GetObject(keys ...string) Node[Object]

GetObject follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON object. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetObjects

func (o Object) GetObjects(keys ...string) Node[[]Object]

GetObjects follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON array of only objects. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetString

func (o Object) GetString(keys ...string) Node[string]

GetString follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON string. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) GetStrings

func (o Object) GetStrings(keys ...string) Node[[]string]

GetStrings follows the given hierarchy of keys to fetch a target value from the underlying JSON structure. The returned Node is empty if some key does not exist, or if the target value is not a JSON array of only strings. Otherwise, the returned Node contains the target value.

See Object.Get for an example on how to fetch nested JSON values.

func (Object) Has

func (o Object) Has(k string) bool

Has returns true if key k is present in this Object, otherwise false.

func (Object) Remove

func (o Object) Remove(k string)

Remove deletes the value with key k from this Object.

func (Object) Set

func (o Object) Set(k string, v any)

Set assigns value v to key k.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL