github.com/ipld/go-ipld-prime@v0.21.0/node/tests/schemaLinks.go (about)

     1  package tests
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"testing"
     7  
     8  	qt "github.com/frankban/quicktest"
     9  
    10  	"github.com/ipfs/go-cid"
    11  	"github.com/ipld/go-ipld-prime/codec/dagjson"
    12  	"github.com/ipld/go-ipld-prime/datamodel"
    13  	"github.com/ipld/go-ipld-prime/fluent"
    14  	"github.com/ipld/go-ipld-prime/linking"
    15  	cidlink "github.com/ipld/go-ipld-prime/linking/cid"
    16  	"github.com/ipld/go-ipld-prime/node/basicnode"
    17  	"github.com/ipld/go-ipld-prime/schema"
    18  	"github.com/ipld/go-ipld-prime/storage/memstore"
    19  	"github.com/ipld/go-ipld-prime/traversal"
    20  	"github.com/ipld/go-ipld-prime/traversal/selector"
    21  	"github.com/ipld/go-ipld-prime/traversal/selector/builder"
    22  )
    23  
    24  var store = memstore.Store{}
    25  
    26  func encode(n datamodel.Node) (datamodel.Node, datamodel.Link) {
    27  	lp := cidlink.LinkPrototype{Prefix: cid.Prefix{
    28  		Version:  1,
    29  		Codec:    0x0129,
    30  		MhType:   0x13,
    31  		MhLength: 4,
    32  	}}
    33  	lsys := cidlink.DefaultLinkSystem()
    34  	lsys.SetWriteStorage(&store)
    35  
    36  	lnk, err := lsys.Store(linking.LinkContext{}, lp, n)
    37  	if err != nil {
    38  		panic(err)
    39  	}
    40  	return n, lnk
    41  }
    42  
    43  func SchemaTestLinks(t *testing.T, engine Engine) {
    44  	ts := schema.TypeSystem{}
    45  	ts.Init()
    46  	ts.Accumulate(schema.SpawnInt("Int"))
    47  	ts.Accumulate(schema.SpawnString("String"))
    48  	ts.Accumulate(schema.SpawnList("ListOfStrings", "String", false))
    49  
    50  	ts.Accumulate(schema.SpawnLink("Link"))                                        // &Any
    51  	ts.Accumulate(schema.SpawnLinkReference("IntLink", "Int"))                     // &Int
    52  	ts.Accumulate(schema.SpawnLinkReference("StringLink", "String"))               // &String
    53  	ts.Accumulate(schema.SpawnLinkReference("ListOfStringsLink", "ListOfStrings")) // &ListOfStrings
    54  
    55  	ts.Accumulate(schema.SpawnStruct("LinkStruct",
    56  		[]schema.StructField{
    57  			schema.SpawnStructField("any", "Link", false, false),
    58  			schema.SpawnStructField("int", "IntLink", false, false),
    59  			schema.SpawnStructField("str", "StringLink", false, false),
    60  			schema.SpawnStructField("strlist", "ListOfStringsLink", false, false),
    61  		},
    62  		schema.SpawnStructRepresentationMap(map[string]string{}),
    63  	))
    64  
    65  	engine.Init(t, ts)
    66  
    67  	t.Run("typed linkage traversal", func(t *testing.T) {
    68  		_, intNodeLnk := func() (datamodel.Node, datamodel.Link) {
    69  			np := engine.PrototypeByName("Int")
    70  			nb := np.NewBuilder()
    71  			nb.AssignInt(101)
    72  			return encode(nb.Build())
    73  		}()
    74  		_, stringNodeLnk := encode(fluent.MustBuild(engine.PrototypeByName("String"), func(na fluent.NodeAssembler) {
    75  			na.AssignString("a string")
    76  		}))
    77  		_, listOfStringsNodeLnk := encode(fluent.MustBuildList(engine.PrototypeByName("ListOfStrings"), 3, func(la fluent.ListAssembler) {
    78  			la.AssembleValue().AssignString("s1")
    79  			la.AssembleValue().AssignString("s2")
    80  			la.AssembleValue().AssignString("s3")
    81  		}))
    82  		linkStructNode, _ := encode(fluent.MustBuildMap(engine.PrototypeByName("LinkStruct"), 4, func(ma fluent.MapAssembler) {
    83  			ma.AssembleEntry("any").AssignLink(stringNodeLnk)
    84  			ma.AssembleEntry("int").AssignLink(intNodeLnk)
    85  			ma.AssembleEntry("str").AssignLink(stringNodeLnk)
    86  			ma.AssembleEntry("strlist").AssignLink(listOfStringsNodeLnk)
    87  		}))
    88  
    89  		ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)
    90  		ss := ssb.ExploreRecursive(selector.RecursionLimitDepth(3), ssb.ExploreUnion(
    91  			ssb.Matcher(),
    92  			ssb.ExploreAll(ssb.ExploreRecursiveEdge()),
    93  		))
    94  		s, err := ss.Selector()
    95  		qt.Check(t, err, qt.IsNil)
    96  
    97  		var order int
    98  		lsys := cidlink.DefaultLinkSystem()
    99  		lsys.SetReadStorage(&store)
   100  		err = traversal.Progress{
   101  			Cfg: &traversal.Config{
   102  				LinkSystem: lsys,
   103  				LinkTargetNodePrototypeChooser: func(lnk datamodel.Link, lnkCtx linking.LinkContext) (datamodel.NodePrototype, error) {
   104  					if tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok {
   105  						return tlnkNd.LinkTargetNodePrototype(), nil
   106  					}
   107  					return basicnode.Prototype.Any, nil
   108  				},
   109  			},
   110  		}.WalkMatching(linkStructNode, s, func(prog traversal.Progress, n datamodel.Node) error {
   111  			buf := new(bytes.Buffer)
   112  			dagjson.Encode(n, buf)
   113  			fmt.Printf("Walked %d: %v\n", order, buf.String())
   114  			switch order {
   115  			case 0: // root
   116  				qt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName("LinkStruct"))
   117  			case 1: // from an &Any
   118  				qt.Check(t, n.Prototype(), qt.Equals, basicnode.Prototype__String{})
   119  			case 2: // &Int
   120  				qt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName("Int"))
   121  			case 3: // &String
   122  				qt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName("String"))
   123  			case 4: // &ListOfStrings
   124  				qt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName("ListOfStrings"))
   125  			case 5:
   126  				fallthrough
   127  			case 6:
   128  				fallthrough
   129  			case 7:
   130  				qt.Check(t, n.Prototype(), qt.Equals, engine.PrototypeByName("String"))
   131  			}
   132  			order++
   133  			return nil
   134  		})
   135  		qt.Check(t, err, qt.IsNil)
   136  		qt.Check(t, order, qt.Equals, 8)
   137  	})
   138  }