github.com/storacha/go-ucanto@v0.7.2/core/receipt/datamodel/receipt.go (about)

     1  package datamodel
     2  
     3  import (
     4  	"bytes"
     5  	_ "embed"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/ipld/go-ipld-prime"
    10  	"github.com/ipld/go-ipld-prime/datamodel"
    11  	"github.com/ipld/go-ipld-prime/schema"
    12  	schemadmt "github.com/ipld/go-ipld-prime/schema/dmt"
    13  	schemadsl "github.com/ipld/go-ipld-prime/schema/dsl"
    14  )
    15  
    16  //go:embed receipt.ipldsch
    17  var receipt []byte
    18  
    19  //go:embed anyresult.ipldsch
    20  var anyResultSchema []byte
    21  
    22  var anyReceiptTs *schema.TypeSystem
    23  
    24  func init() {
    25  	ts, err := NewReceiptModelType(anyResultSchema)
    26  	if err != nil {
    27  		panic(fmt.Errorf("failed to load IPLD schema: %w", err))
    28  	}
    29  	anyReceiptTs = ts.TypeSystem()
    30  }
    31  
    32  func TypeSystem() *schema.TypeSystem {
    33  	return anyReceiptTs
    34  }
    35  
    36  type ReceiptModel[O any, X any] struct {
    37  	Ocm OutcomeModel[O, X]
    38  	Sig []byte
    39  }
    40  
    41  type OutcomeModel[O any, X any] struct {
    42  	Ran  ipld.Link
    43  	Out  ResultModel[O, X]
    44  	Fx   EffectsModel
    45  	Meta MetaModel
    46  	Iss  *string
    47  	Prf  []ipld.Link
    48  }
    49  
    50  type EffectsModel struct {
    51  	Fork []ipld.Link
    52  	Join ipld.Link
    53  }
    54  
    55  type MetaModel struct {
    56  	Keys   []string
    57  	Values map[string]datamodel.Node
    58  }
    59  
    60  type ResultModel[O any, X any] struct {
    61  	Ok    *O
    62  	Error *X
    63  }
    64  
    65  // NewReceiptModelType creates a new schema.Type for a Receipt. You must
    66  // provide the schema containing a Result type, which is a keyed union. e.g.
    67  //
    68  //	type Result union {
    69  //	  | Ok "ok"
    70  //	  | Err "error"
    71  //	} representation keyed
    72  //
    73  //	type Ok struct {
    74  //	  status String (rename "Status")
    75  //	}
    76  //
    77  //	type Err struct {
    78  //	  message String (rename "Message")
    79  //	}
    80  func NewReceiptModelType(resultschema []byte) (schema.Type, error) {
    81  	sch := bytes.Join([][]byte{resultschema, receipt}, []byte("\n"))
    82  	ts, err := ipld.LoadSchemaBytes(sch)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	return ts.TypeByName("Receipt"), nil
    87  }
    88  
    89  func NewReceiptModelFromTypes(successType schema.Type, errType schema.Type) (schema.Type, error) {
    90  	ts := new(schema.TypeSystem)
    91  	ts.Init()
    92  	schema.SpawnDefaultBasicTypes(ts)
    93  	schema.MergeTypeSystem(ts, successType.TypeSystem(), true)
    94  	schema.MergeTypeSystem(ts, errType.TypeSystem(), true)
    95  	ts.Accumulate(schema.SpawnUnion("Result", []schema.TypeName{successType.Name(), errType.Name()}, schema.SpawnUnionRepresentationKeyed(map[string]schema.TypeName{"ok": successType.Name(), "error": errType.Name()})))
    96  	sch, err := schemadsl.Parse("", bytes.NewReader(receipt))
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	schemadmt.SpawnSchemaTypes(ts, sch)
   101  	if errs := ts.ValidateGraph(); errs != nil {
   102  		return nil, errors.Join(errs...)
   103  	}
   104  	return ts.TypeByName("Receipt"), nil
   105  }