library for working amorphous data (as when you decode json into an interface{})

Introduction

Decoding json into an interface{} produces an hierarchical arrangement of four data types: float64, string are 'primative types' and form 'leaf nodes' in the hierarchy, []interface, and map[string]interface{} are compound types and compose layers of the hierarchy around the primative and compound types.

This hierarchical arrangement has no name that I've been able to find, so I label it Amorph which is short for Amorphic. The four types listed above will be referred to as the A4 types.

The json aspect of this README is only an example of where the data might come from, Amorphs can be constructed in other ways as well.

Other types are handled in a limited, and not efficient manner. This of course could be addressed, but would require the reflect package, which this library only uses as a last resort.

Value Proposition

amorph provides a Diff function that diffs two Amorphs and produces a Patch. A Patch can be applied to an Amorph and a new Amorph reflecting the differences is produced. Patches can be both forward and reverse applied.

The Walker provides a means to iterate over an Amorph and provides functions needed to fully manipulate it.

Amorphs also work with gojq which allows sophisticated queries to be run on an Amorph and producing results that are Amorphs as well.

Amorph Creation

Literal Amorph:

simpleLiteralAmorph := []interface{}{3.14159}

A more sophisticated literal Amorph:

literalAmorph := []interface{}{
	"123",
	"456",
	[]interface{}{
		"string", 88, "test",
	},
	map[string]interface{}{
		"dooo": "foo",
		"farp": "bar",
		"flam": "baz",
	},
}

Create an Amorph from json in a file:

	amorphFromFile, err := amorph.NewAmorphFromFile("test.json")

Create an Amorph from a json string:

amorphExample0, err := amorph.NewAmorphFromString(`{
	"employee":{ 
		"name":"John", 
		"age":30, 
		"city":"New York", 
		"country": "USA",
		"burgers": [ "memphis", "johnny cash", "roy orbison", "burford"]
	}
}`)

Create an Amorph from json coming in on an io.Reader:

rdr := bytes.NewReader(
	[]byte(`{
		"employee":{ 
			"name":"John", 
			"age":30, 
			"city":"New York", 
			"country": "USA",
			"burgers": [ "memphis", "johnny cash", "roy orbison", "burford"]
		}
	}`),
)
amorphExample1, err := amorph.NewAmorphFromReader(rdr)

DeepCopy - Create an Amorph from any arbitrary data object:

amorph.DeepCopy encodes the input in json and then decodes it into an interface{}. The output will include only A4 types.

copyOfInputAmorph := amorph.DeepCopy(inputAmorph)

Amorph DeepEqual

Compares two Amorphs, returns true or false. While 'walking' the data structure, any data type found one of the A4 types results in a call to reflect.DeepEqual.

// data0 and data1 are from above examples
eq := amorph.DeepEqual(inputAmorph0, inputAmorph1)

Amorph Diff function

As an example, you have two Amorphs that represent 'before' and 'after' conditions.

amorph.Diff() generates a Patch containing their differences.

patch, err := amorph.Diff(before, after)

Applying the patch in the forward direction to 'before' will produce 'after'.

Applying the patch in the reverse direction to 'after' will produce 'before'.

Patch ApplyFwd and ApplyRev

The patch methods ApplyFwd and ApplyRev take an Amorph as input and generate a new Amorph as output. The output Amorph will contain the input Amorph with the differences from the Patch applied.

result, err := amorph.ApplyFwd(patch, before)

// amorph.DeepEqual(after, result) will be true

A patch can also be reverse applied:

result, err := amorph.ApplyRev(patch, after)

// amorph.DeepEqual(before, result) will be true

Walker behavior

Walk Function

amorph.Walk iterates over an Amorph and calls the user supplied function at every node in the Amorph.

The user supplied function receives an iterator of type WalkIterator.

err = amorph.Walk(adata0, func(iter amorph.WalkIter) error {
	top := iter.Top()
	key := top.Key()
	rval := top.Value()

	switch trval := rval.(type) {
	case nil:
		fmt.Println("key ", key, ", trval = ", trval, " nil ")
	case []interface{}:
		fmt.Println(key, " slice ") // , value)
	case map[string]interface{}:
		fmt.Println(key, " map ") // , value)
	case string:
		fmt.Println(key, ",", trval, " string ") // , value)
	case float64:
		fmt.Println(key, ",", trval, "  float64 ") // , value)
	default:
		fmt.Println("other type: ", rval)
	}
	return nil
})

WalkIterator

WalkIterator is a stack that describes the path from the top of the Amorph down the node being 'visited'. It contains all of the map keys and slice indexes down to the visited node.

Internally the WalkIterator is implemented as a slice of WalkPos elements (described below).

Len

Len() returns the length of the WalkIterator

Top

Top() returns the top WalkPos element of the WalkIterator. top := iter.Top()

panics if the len of the iterator is zero.

Pop

Pop() returns a copy of a WalkIterator with the top WalkIterator removed.

newiter := iter.Pop()

Copy

Copy() returns a copy of a WalkIterator.

newiter := iter.Copy()

WalkPos

WalkPos the the type of the elements in WalkIter

Key and Value

If WalkPos refers to a slice, the value returned from Key() can be type asserted to int.

If WalkPos refers to a map, the value returned from Key() can be type asserted to string.

If WalkPos refers to anything else, do not use Key(), it will return nil.

Key() and Value() allow you to access the key and value for that element.

Dereference

If the WalkPos points to a slice:

val := wp.Dereference(idx)

it returns the value at idx in the slice.

If the WalkPos points to a map:

val := wp.Dereference(key)

it returns the value associate with key in the map.

panics if called on an unsupported type. The type can be determined from the iterator.

Rereference

If the WalkPos points to a slice:

wp.Rereference(idx, value)

sets the value at idx in the slice.

If the WalkPos points to a map:

wp.Rereference(key, value)

sets the value associate with key in the map.

panics if called on an unsupported type. The type can be determined from the iterator.

Delete

If the WalkPos points to a map:

wp.Delete(key)

deletes the key from the map.

panics if called on an unsupported type. The type can be determined from the iterator.

Owner
Chuck Luciano
Professional software developer since dinosaurs roamed the earth. Expert amateur photographer, my lovely wife is video producer, and I help with that too.
Chuck Luciano
Similar Resources

converts text-formats from one to another, it is very useful if you want to re-format a json file to yaml, toml to yaml, csv to yaml, ... etc

re-txt reformates a text file from a structure to another, i.e: convert from json to yaml, toml to json, ... etc Supported Source Formats json yaml hc

Sep 23, 2022

Simple json based db, if you call db xd.

Golang-json-db Simple json based db, if you call db xd. Basics //First of all you have to config main json file then config backup json file. Backup i

Sep 27, 2021

A simple Go package to Query over JSON/YAML/XML/CSV Data

A simple Go package to Query over JSON/YAML/XML/CSV Data

A simple Go package to Query over JSON Data. It provides simple, elegant and fast ODM like API to access, query JSON document Installation Install the

Dec 27, 2022

Kazaam was created with the goal of supporting easy and fast transformations of JSON data with Golang

kazaam Description Kazaam was created with the goal of supporting easy and fast transformations of JSON data with Golang. This functionality provides

Sep 17, 2021

A tool to aggregate and mine data from JSON reports of Go tests.

teststat A tool to aggregate and mine data from JSON reports of Go tests. Why? Mature Go projects often have a lot of tests, and not all of them are i

Sep 15, 2022

Jsonmask use for mask sensitive data from json format

Jsonmask use for mask sensitive data from json format Installation go get -u github.com/rkritchat/jsonmask Code example package main import ( "fmt"

Sep 16, 2022

Senml-go - a Golang module for the JSON-based SenML sensor data format

ThingWave SenML module for Golang This is a Golang module for the JSON-based Sen

Jan 2, 2022

A blazingly fast JSON serializing & deserializing library

A blazingly fast JSON serializing & deserializing library

Sonic A blazingly fast JSON serializing & deserializing library, accelerated by JIT(just-in-time compiling) and SIMD(single-instruction-multi-data). B

Jan 5, 2023

A library to query the godoc.org JSON API.

gopkg This repository provides minimal Go package that makes queries against the godoc.org JSON API. Since that site has mostly been subsumed by pkg.g

Dec 2, 2022
Related tags
This is an experimental package for working with JSON-LD documents in Go

JSON-LD ?? Simple JSON-LD in Go This is an experimental package for working with JSON-LD documents in Go. Experimental, Pre-Alpha Quality Please do no

Jul 6, 2022
An example of how to parse json data using go....a typical step for preparing data prior to uploading to a db.

JSON parser using GO An example of parsing json data in go, when you already know the schema of the data Example input: { "num_listings":"36",

Jan 12, 2022
JSON diff library for Go based on RFC6902 (JSON Patch)

jsondiff jsondiff is a Go package for computing the diff between two JSON documents as a series of RFC6902 (JSON Patch) operations, which is particula

Dec 4, 2022
Gron transforms JSON into discrete assignments to make it easier to grep

gron Make JSON greppable! gron transforms JSON into discrete assignments to make it easier to grep for what you want and see the absolute 'path' to it

Nov 4, 2021
Devto-json2md - Convert the dev.to blog JSON export into Markdown files

devto-json2md Convert dev.to blog JSON export into Markdown files Features Exports Markdown compatible files using Hugo-compatible front-matter fields

Jan 8, 2022
Get JSON values quickly - JSON parser for Go
Get JSON values quickly - JSON parser for Go

get json values quickly GJSON is a Go package that provides a fast and simple way to get values from a json document. It has features such as one line

Dec 28, 2022
Fast JSON encoder/decoder compatible with encoding/json for Go
Fast JSON encoder/decoder compatible with encoding/json for Go

Fast JSON encoder/decoder compatible with encoding/json for Go

Jan 6, 2023
Package json implements encoding and decoding of JSON as defined in RFC 7159

Package json implements encoding and decoding of JSON as defined in RFC 7159. The mapping between JSON and Go values is described in the documentation for the Marshal and Unmarshal functions

Jun 26, 2022
Json-go - CLI to convert JSON to go and vice versa
Json-go - CLI to convert JSON to go and vice versa

Json To Go Struct CLI Install Go version 1.17 go install github.com/samit22/js

Jul 29, 2022
JSON Spanner - A Go package that provides a fast and simple way to filter or transform a json document

JSON SPANNER JSON Spanner is a Go package that provides a fast and simple way to

Sep 14, 2022