diff --git a/go/catalogue/kept_form.go b/go/catalogue/kept_form.go index a07f315a..6ab5ccc4 100644 --- a/go/catalogue/kept_form.go +++ b/go/catalogue/kept_form.go @@ -1,6 +1,8 @@ package catalogue import ( + "bytes" + "encoding/json" "fmt" "sort" ) @@ -17,9 +19,39 @@ import ( type KeptLayout struct { // Form is the form of the kept data's layout, 0 where none is said. Form int `json:"form,omitempty"` - // CatchUp is the module's own tool a restore of this kept data is followed by, named by the manifest that raised its - // form; empty where none is. - CatchUp string `json:"catch-up,omitempty"` + // CatchUp is the module's own tool a restore of this kept data is followed by, with its arguments, named by the + // manifest that raised its form; nil where none is (design 47 G §631). + CatchUp *CatchUp `json:"catch-up,omitempty"` +} + +// CatchUp is a manifest's `catch-up`: the tool and the arguments it is called with (design 47 G §631). +type CatchUp struct { + Tool string `json:"tool"` + Arguments map[string]any `json:"arguments,omitempty"` +} + +// UnmarshalJSON reads the object {tool, arguments} whole, and a string of before G as {tool, arguments: {}}. +func (c *CatchUp) UnmarshalJSON(raw []byte) error { + trimmed := bytes.TrimSpace(raw) + if len(trimmed) > 0 && trimmed[0] == '"' { + var tool string + if err := json.Unmarshal(trimmed, &tool); err != nil { + return err + } + *c = CatchUp{Tool: tool} + return nil + } + var full struct { + Tool string `json:"tool"` + Arguments map[string]any `json:"arguments"` + } + dec := json.NewDecoder(bytes.NewReader(trimmed)) + dec.DisallowUnknownFields() + if err := dec.Decode(&full); err != nil { + return fmt.Errorf("a catch-up is {tool, arguments}: %w", typedUnknown(err)) + } + *c = CatchUp{Tool: full.Tool, Arguments: full.Arguments} + return nil } // refuse is the one reading of a layout's form every kept kind's decoder calls: a form is a whole number from 0, and one diff --git a/go/catalogue/kept_form_test.go b/go/catalogue/kept_form_test.go index 88a29602..0787b165 100644 --- a/go/catalogue/kept_form_test.go +++ b/go/catalogue/kept_form_test.go @@ -13,8 +13,8 @@ func TestAKeptDataSaysItsFormAndItsCatchUp(t *testing.T) { m, err := decodeForTest([]byte(`{"module":"x","version":"1","tools":["x_take_in"], "state": ["seen", {"name":"modules","history":20,"form":1,"catch-up":"x_take_in"}], "logs": [{"name":"acts","form":2}], - "streams": [{"name":"forge","events":["merged"],"form":1,"catch-up":"x_take_in"}], - "objects": [{"name":"revisions","max-mib":64,"form":1,"catch-up":"x_take_in"}], + "streams": [{"name":"forge","events":["merged"],"form":1,"catch-up":{"tool":"x_take_in","arguments":{"all":true}}}], + "objects": [{"name":"revisions","max-mib":64,"form":1,"catch-up":{"tool":"x_take_in","arguments":{"all":true}}}], "requires": [ {"name":"records","storage":"ledger","template":"ledger","form":3,"catch-up":"x_take_in"}, {"name":"holds","storage":"key-value","template":"state"}, @@ -27,13 +27,13 @@ func TestAKeptDataSaysItsFormAndItsCatchUp(t *testing.T) { want := []KeptDeclared{ {"acts", KeptKindLog, KeptLayout{Form: 2}}, {"blobs", KeptKindObjects, KeptLayout{Form: 4}}, - {"forge", KeptKindStream, KeptLayout{1, "x_take_in"}}, + {"forge", KeptKindStream, KeptLayout{1, &CatchUp{Tool: "x_take_in", Arguments: map[string]any{"all": true}}}}, {"history", KeptKindLog, KeptLayout{Form: 1}}, {"holds", KeptKindState, KeptLayout{}}, {"marks", KeptKindStream, KeptLayout{}}, - {"modules", KeptKindState, KeptLayout{1, "x_take_in"}}, - {"records", KeptKindLedger, KeptLayout{3, "x_take_in"}}, - {"revisions", KeptKindObjects, KeptLayout{1, "x_take_in"}}, + {"modules", KeptKindState, KeptLayout{1, &CatchUp{Tool: "x_take_in"}}}, + {"records", KeptKindLedger, KeptLayout{3, &CatchUp{Tool: "x_take_in"}}}, + {"revisions", KeptKindObjects, KeptLayout{1, &CatchUp{Tool: "x_take_in", Arguments: map[string]any{"all": true}}}}, {"seen", KeptKindState, KeptLayout{}}, } if got := KeptDeclarations(m); !reflect.DeepEqual(got, want) { @@ -60,7 +60,7 @@ func TestAKeptDataSaysItsFormAndItsCatchUp(t *testing.T) { } changes := FormChanges(running, applied) wantChanges := []FormChange{ - {Name: "acts", Kind: KeptKindLog, Running: &KeptLayout{}, Applied: &KeptLayout{1, "x_take_in"}}, + {Name: "acts", Kind: KeptKindLog, Running: &KeptLayout{}, Applied: &KeptLayout{1, &CatchUp{Tool: "x_take_in"}}}, {Name: "fresh", Kind: KeptKindState, Applied: &KeptLayout{}}, {Name: "modules", Kind: KeptKindState, Running: &KeptLayout{}}, }