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 }