linkingExamples_test.go 6.12 KB
Newer Older
Eric Myhre's avatar
Eric Myhre committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
package ipld_test

import (
	"fmt"

	"github.com/ipfs/go-cid"

	"github.com/ipld/go-ipld-prime"
	_ "github.com/ipld/go-ipld-prime/codec/dagcbor"
	"github.com/ipld/go-ipld-prime/fluent"
	cidlink "github.com/ipld/go-ipld-prime/linking/cid"
	basicnode "github.com/ipld/go-ipld-prime/node/basic"
	"github.com/ipld/go-ipld-prime/storage"
)

// storage is a map where we'll store serialized IPLD data.
//
18 19
// ExampleLinkSystem_Store will put data into this;
// ExampleLinkSystem_Load will read out from it.
Eric Myhre's avatar
Eric Myhre committed
20 21 22 23 24 25 26 27
//
// In a real program, you'll probably make functions to load and store from disk,
// or some network storage, or... whatever you want, really :)
var store = storage.Memory{}

// TODO: These examples are really heavy on CIDs and the multicodec and multihash magic tables.
// It would be good to have examples that create and use less magical LinkSystem constructions, too.

28
func ExampleLinkSystem_Store() {
Eric Myhre's avatar
Eric Myhre committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
	// Creating a Link is done by choosing a concrete link implementation (typically, CID),
	//  getting a LinkSystem that knows how to work with that, and then using the LinkSystem methods.

	// Let's get a LinkSystem.  We're going to be working with CID links,
	//  so let's get the default LinkSystem that's ready to work with those.
	lsys := cidlink.DefaultLinkSystem()

	// We want to store the serialized data somewhere.
	//  We'll use an in-memory store for this.  (It's a package scoped variable.)
	//  You can use any kind of storage system here;
	//   you just need a function that conforms to the ipld.BlockWriteOpener interface.
	lsys.StorageWriteOpener = (&store).OpenWrite

	// To create any links, first we need a LinkPrototype.
	// This gathers together any parameters that might be needed when making a link.
	// (For CIDs, the version, the codec, and the multihash type are all parameters we'll need.)
	// Often, you can probably make this a constant for your whole application.
	lp := cidlink.LinkPrototype{cid.Prefix{
		Version:  1,    // Usually '1'.
		Codec:    0x71, // 0x71 means "dag-cbor" -- See the multicodecs table: https://github.com/multiformats/multicodec/
49 50
		MhType:   0x13, // 0x20 means "sha2-512" -- See the multicodecs table: https://github.com/multiformats/multicodec/
		MhLength: 64,   // sha2-512 hash has a 64-byte sum.
Eric Myhre's avatar
Eric Myhre committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
	}}

	// And we need some data to link to!  Here's a quick piece of example data:
	n := fluent.MustBuildMap(basicnode.Prototype.Map, 1, func(na fluent.MapAssembler) {
		na.AssembleEntry("hello").AssignString("world")
	})

	// Before we use the LinkService, NOTE:
	//  There's a side-effecting import at the top of the file.  It's for the dag-cbor codec.
	//  The CID LinkSystem defaults use a global registry called the multicodec table;
	//  and the multicodec table is populated in part by the dag-cbor package when it's first imported.
	// You'll need that side-effecting import, too, to copy this example.
	//  It can happen anywhere in your program; once, in any package, is enough.
	//  If you don't have this import, the codec will not be registered in the multicodec registry,
	//  and when you use the LinkSystem we got from the cidlink package, it will return an error of type ErrLinkingSetup.
	// If you initialize a custom LinkSystem, you can control this more directly;
	//  these registry systems are only here as defaults.

	// Now: time to apply the LinkSystem, and do the actual store operation!
	lnk, err := lsys.Store(
		ipld.LinkContext{}, // The zero value is fine.  Configure it it you want cancellability or other features.
		lp,                 // The LinkPrototype says what codec and hashing to use.
		n,                  // And here's our data.
	)
	if err != nil {
		panic(err)
	}

	// That's it!  We got a link.
	fmt.Printf("link: %s\n", lnk)
	fmt.Printf("concrete type: `%T`\n", lnk)

	// Remember: the serialized data was also stored to the 'store' variable as a side-effect.
	//  (We set this up back when we customized the LinkSystem.)
	//  We'll pick this data back up again in the example for loading.

	// Output:
88
	// link: bafyrgqhai26anf3i7pips7q22coa4sz2fr4gk4q4sqdtymvvjyginfzaqewveaeqdh524nsktaq43j65v22xxrybrtertmcfxufdam3da3hbk
Eric Myhre's avatar
Eric Myhre committed
89 90 91
	// concrete type: `cidlink.Link`
}

92 93
func ExampleLinkSystem_Load() {
	// Let's say we want to load this link (it's the same one we created in ExampleLinkSystem_Store).
94
	cid, _ := cid.Decode("bafyrgqhai26anf3i7pips7q22coa4sz2fr4gk4q4sqdtymvvjyginfzaqewveaeqdh524nsktaq43j65v22xxrybrtertmcfxufdam3da3hbk")
Eric Myhre's avatar
Eric Myhre committed
95 96 97 98
	lnk := cidlink.Link{cid}

	// Let's get a LinkSystem.  We're going to be working with CID links,
	//  so let's get the default LinkSystem that's ready to work with those.
99
	// (This is the same as we did in ExampleLinkSystem_Store.)
Eric Myhre's avatar
Eric Myhre committed
100 101 102 103
	lsys := cidlink.DefaultLinkSystem()

	// We need somewhere to go looking for any of the data we might want to load!
	//  We'll use an in-memory store for this.  (It's a package scoped variable.)
104
	//   (This particular memory store was filled with the data we'll load earlier, during ExampleLinkSystem_Store.)
Eric Myhre's avatar
Eric Myhre committed
105 106 107 108 109 110 111 112 113 114 115
	//  You can use any kind of storage system here;
	//   you just need a function that conforms to the ipld.BlockReadOpener interface.
	lsys.StorageReadOpener = (&store).OpenRead

	// We'll need to decide what in-memory implementation of ipld.Node we want to use.
	//  Here, we'll use the "basicnode" implementation.  This is a good getting-started choice.
	//   But you could also use other implementations, or even a code-generated type with special features!
	np := basicnode.Prototype.Any

	// Before we use the LinkService, NOTE:
	//  There's a side-effecting import at the top of the file.  It's for the dag-cbor codec.
116
	//  See the comments in ExampleLinkSystem_Store for more discussion of this and why it's important.
Eric Myhre's avatar
Eric Myhre committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133

	// Apply the LinkSystem, and ask it to load our link!
	n, err := lsys.Load(
		ipld.LinkContext{}, // The zero value is fine.  Configure it it you want cancellability or other features.
		lnk,                // The Link we want to load!
		np,                 // The NodePrototype says what kind of Node we want as a result.
	)
	if err != nil {
		panic(err)
	}

	// Tada!  We have the data as node that we can traverse and use as desired.
	fmt.Printf("we loaded a %s with %d entries\n", n.Kind(), n.Length())

	// Output:
	// we loaded a map with 1 entries
}