From 11292174066ce0624d117fdb9d8a557c15b951b3 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 31 May 2024 19:25:39 +0200 Subject: [PATCH] feat(examples): add upgrade pattern d example (#2151) Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../upgrade_d/README.md | 9 ++++ .../upgrade_d/v1/v1.gno | 34 +++++++++++++ .../upgrade_d/v1/z_filetest.gno | 18 +++++++ .../upgrade_d/v2/v2.gno | 51 +++++++++++++++++++ .../upgrade_d/v2/z_filetest.gno | 22 ++++++++ 5 files changed, 134 insertions(+) create mode 100644 examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/README.md create mode 100644 examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1/v1.gno create mode 100644 examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1/z_filetest.gno create mode 100644 examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno create mode 100644 examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/z_filetest.gno diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/README.md b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/README.md new file mode 100644 index 00000000000..fa73113ef3b --- /dev/null +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/README.md @@ -0,0 +1,9 @@ +# Lazy Migration Example + +This example demonstrates lazy migrations from v1 to v2 of a data structure in Gno. + +## Notes + +Uses AVL trees, but storage can vary since public Get functions are used. + +v1 can be made pausable and readonly during migration. diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1/v1.gno b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1/v1.gno new file mode 100644 index 00000000000..3a2b1388fda --- /dev/null +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1/v1.gno @@ -0,0 +1,34 @@ +package v1 + +import ( + "strconv" + + "gno.land/p/demo/avl" +) + +var myTree avl.Tree + +type MyStruct struct { + FieldA string + FieldB int +} + +func (s *MyStruct) String() string { + if s == nil { + return "nil" + } + return "v1:" + s.FieldA + ":" + strconv.Itoa(s.FieldB) +} + +func Get(key string) *MyStruct { + ret, ok := myTree.Get(key) + if !ok { + return nil + } + return ret.(*MyStruct) +} + +func init() { + myTree.Set("a", &MyStruct{FieldA: "a", FieldB: 1}) + myTree.Set("b", &MyStruct{FieldA: "b", FieldB: 2}) +} diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1/z_filetest.gno b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1/z_filetest.gno new file mode 100644 index 00000000000..8f7537b04eb --- /dev/null +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1/z_filetest.gno @@ -0,0 +1,18 @@ +package main + +import ( + "fmt" + + "gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1" +) + +func main() { + println("a", v1.Get("a")) + println("b", v1.Get("b")) + println("c", v1.Get("c")) +} + +// Output: +// a v1:a:1 +// b v1:b:2 +// c nil diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno new file mode 100644 index 00000000000..a31219cd4d0 --- /dev/null +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/v2.gno @@ -0,0 +1,51 @@ +package v1 + +import ( + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" + "gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v1" +) + +var myTree avl.Tree + +// MyStruct represents the structure with fields that may have been migrated from v1. +type MyStruct struct { + FieldA string // Appending "imported-from-v1" if migrating from v1. + FieldB uint64 // Switching from int to uint64 and multiplying by 1000 if migrating from v1. + FieldC bool // Adding a boolean field which is true by default for v1 objects. +} + +// String returns a string representation of MyStruct. +func (s *MyStruct) String() string { + if s == nil { + return "nil" + } + return ufmt.Sprintf("v2:%s:%d:%t", s.FieldA, s.FieldB, s.FieldC) +} + +// Get retrieves a MyStruct from the tree by key. If the key does not exist in the current version, +// it attempts to retrieve and migrate the structure from v1. +func Get(key string) *MyStruct { + ret, ok := myTree.Get(key) + if !ok { + v1Struct := v1.Get(key) + if v1Struct == nil { + return nil + } + // Lazy migration code: convert v1 structure to v2 structure. + v2Struct := &MyStruct{ + FieldA: v1Struct.FieldA + "-imported-from-v1", + FieldB: uint64(v1Struct.FieldB * 1000), + FieldC: true, + } + myTree.Set(key, v2Struct) + return v2Struct + } + return ret.(*MyStruct) +} + +// init initializes the tree with some default values. +func init() { + myTree.Set("c", &MyStruct{FieldA: "c", FieldB: 3, FieldC: true}) + myTree.Set("d", &MyStruct{FieldA: "d", FieldB: 4, FieldC: false}) +} diff --git a/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/z_filetest.gno b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/z_filetest.gno new file mode 100644 index 00000000000..961c7a13208 --- /dev/null +++ b/examples/gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2/z_filetest.gno @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + + "gno.land/r/x/manfred_upgrade_patterns/upgrade_d/v2" +) + +func main() { + println("a", v1.Get("a")) + println("b", v1.Get("b")) + println("c", v1.Get("c")) + println("d", v1.Get("d")) + println("e", v1.Get("e")) +} + +// Output: +// a v2:a-imported-from-v1:1000:true +// b v2:b-imported-from-v1:2000:true +// c v2:c:3:true +// d v2:d:4:false +// e nil