bindnode

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Mar 9, 2022 License: MIT Imports: 12 Imported by: 55

Documentation

Overview

Package bindnode provides a datamodel.Node implementation via Go reflection.

This package is EXPERIMENTAL; its behavior and API might change as it's still in development.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ProduceGoTypes added in v0.14.0

func ProduceGoTypes(w io.Writer, ts *schema.TypeSystem) error

ProduceGoTypes infers Go types from an IPLD schema in ts and writes their Go source code type declarations to w. Note that just the types are written, without a package declaration nor any imports.

This gives a good starting point when wanting to use bindnode with Go types, but users will generally want to own and modify the types afterward, so they can add documentation or tweak the types as needed.

func Prototype

func Prototype(ptrType interface{}, schemaType schema.Type) schema.TypedPrototype

Prototype implements a schema.TypedPrototype given a Go pointer type and an IPLD schema type. Note that the result is also a datamodel.NodePrototype.

If both the Go type and schema type are supplied, it is assumed that they are compatible with one another.

If either the Go type or schema type are nil, we infer the missing type from the other provided type. For example, we can infer an unnamed Go struct type for a schema struct type, and we can infer a schema Int type for a Go int64 type. The inferring logic is still a work in progress and subject to change. At this time, inferring IPLD Unions and Enums from Go types is not supported.

When supplying a non-nil ptrType, Prototype only obtains the Go pointer type from it, so its underlying value will typically be nil. For example:

proto := bindnode.Prototype((*goType)(nil), schemaType)
Example (OnlySchema)
ts, err := ipld.LoadSchemaBytes([]byte(`
		type Person struct {
			Name    String
			Age     optional Int
			Friends [String]
		}
	`))
if err != nil {
	panic(err)
}

schemaType := ts.TypeByName("Person")
proto := bindnode.Prototype(nil, schemaType)

node, err := qp.BuildMap(proto, -1, func(ma datamodel.MapAssembler) {
	qp.MapEntry(ma, "Name", qp.String("Michael"))
	qp.MapEntry(ma, "Friends", qp.List(-1, func(la datamodel.ListAssembler) {
		qp.ListEntry(la, qp.String("Sarah"))
		qp.ListEntry(la, qp.String("Alex"))
	}))
})
if err != nil {
	panic(err)
}

nodeRepr := node.(schema.TypedNode).Representation()
dagjson.Encode(nodeRepr, os.Stdout)
Output:

{"Friends":["Sarah","Alex"],"Name":"Michael"}
Example (Union)
ts, err := ipld.LoadSchemaBytes([]byte(`
		type StringOrInt union {
			| String "hasString"
			| Int    "hasInt"
		} representation keyed
	`))
if err != nil {
	panic(err)
}
schemaType := ts.TypeByName("StringOrInt")

type CustomIntType int64
type StringOrInt struct {
	String *string
	Int    *CustomIntType // We can use custom types, too.
}

proto := bindnode.Prototype((*StringOrInt)(nil), schemaType)

node, err := qp.BuildMap(proto.Representation(), -1, func(ma datamodel.MapAssembler) {
	qp.MapEntry(ma, "hasInt", qp.Int(123))
})
if err != nil {
	panic(err)
}

fmt.Print("Type level DAG-JSON: ")
dagjson.Encode(node, os.Stdout)
fmt.Println()

fmt.Print("Representation level DAG-JSON: ")
nodeRepr := node.(schema.TypedNode).Representation()
dagjson.Encode(nodeRepr, os.Stdout)
fmt.Println()

// Inspect what the underlying Go value contains.
union := bindnode.Unwrap(node).(*StringOrInt)
switch {
case union.String != nil:
	fmt.Printf("Go StringOrInt.String: %v\n", *union.String)
case union.Int != nil:
	fmt.Printf("Go StringOrInt.Int: %v\n", *union.Int)
}
Output:

Type level DAG-JSON: {"Int":123}
Representation level DAG-JSON: {"hasInt":123}
Go StringOrInt.Int: 123

func Unwrap

func Unwrap(node datamodel.Node) (ptrVal interface{})

Unwrap takes a datamodel.Node implemented by Prototype or Wrap, and returns a pointer to the inner Go value.

Unwrap returns nil if the node isn't implemented by this package.

func Wrap added in v0.11.0

func Wrap(ptrVal interface{}, schemaType schema.Type) schema.TypedNode

Wrap implements a schema.TypedNode given a non-nil pointer to a Go value and an IPLD schema type. Note that the result is also a datamodel.Node.

Wrap is meant to be used when one already has a Go value with data. As such, ptrVal must not be nil.

Similar to Prototype, if schemaType is non-nil it is assumed to be compatible with the Go type, and otherwise it's inferred from the Go type.

Example (NoSchema)
package main

import (
	"os"

	"github.com/ipld/go-ipld-prime/codec/dagjson"
	"github.com/ipld/go-ipld-prime/node/bindnode"
)

func main() {
	type Person struct {
		Name    string
		Age     int64 // TODO: optional to match other examples
		Friends []string
	}
	person := &Person{
		Name:    "Michael",
		Friends: []string{"Sarah", "Alex"},
	}
	node := bindnode.Wrap(person, nil)

	nodeRepr := node.Representation()
	dagjson.Encode(nodeRepr, os.Stdout)

}
Output:

{"Age":0,"Friends":["Sarah","Alex"],"Name":"Michael"}
Example (WithSchema)
ts, err := ipld.LoadSchemaBytes([]byte(`
		type Person struct {
			Name    String
			Age     optional Int
			Friends [String]
		}
	`))
if err != nil {
	panic(err)
}
schemaType := ts.TypeByName("Person")

type Person struct {
	Name    string
	Age     *int64 // optional
	Friends []string
}
person := &Person{
	Name:    "Michael",
	Friends: []string{"Sarah", "Alex"},
}
node := bindnode.Wrap(person, schemaType)

nodeRepr := node.Representation()
dagjson.Encode(nodeRepr, os.Stdout)
Output:

{"Friends":["Sarah","Alex"],"Name":"Michael"}

Types

This section is empty.

Jump to

Keyboard shortcuts

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