From 4dadfb5cfd9cdafd924ee81047b51e9f72aa3209 Mon Sep 17 00:00:00 2001 From: Inanc Gumus Date: Sun, 8 Sep 2019 11:47:13 +0300 Subject: [PATCH] add: db.load and save --- interfaces/14-io-reader/_database_save.go | 133 ++++++++++++++++++++++ interfaces/14-io-reader/_main_save.go | 40 +++++++ interfaces/14-io-reader/database.go | 39 ++----- interfaces/14-io-reader/database.json | 2 +- interfaces/14-io-reader/main.go | 12 +- 5 files changed, 184 insertions(+), 42 deletions(-) create mode 100644 interfaces/14-io-reader/_database_save.go create mode 100644 interfaces/14-io-reader/_main_save.go diff --git a/interfaces/14-io-reader/_database_save.go b/interfaces/14-io-reader/_database_save.go new file mode 100644 index 0000000..01a4fd6 --- /dev/null +++ b/interfaces/14-io-reader/_database_save.go @@ -0,0 +1,133 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "reflect" +) + +type database struct { + list *list + types map[string]item // the registry of the types +} + +// load the list by decoding the data from a json file. +func (db *database) load(path string) error { // #v1 + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + return json.Unmarshal(data, db) +} + +// save the list by encoding the data to a json file. +func (db *database) save(path string) error { // #v1 + out, err := json.MarshalIndent(db, "", "\t") + if err != nil { + return err + } + return ioutil.WriteFile(path, out, 0644) +} + +// #v2 +// func (db *database) load(r io.Reader) error { +// data, err := ioutil.ReadAll(r) +// if err != nil { +// return err +// } +// return json.Unmarshal(data, db) +// } + +// #v3 +// TODO: use decoder + +// #v2 +// func (db *database) save(w io.Writer) error { +// data, err := json.MarshalIndent(db, "", "\t") +// if err != nil { +// return err +// } + +// _, err = io.Copy(w, bytes.NewReader(data)) +// return err +// } + +// #v3 +// TODO: use encoder + +func (db *database) MarshalJSON() ([]byte, error) { + type encodable struct { + Type string + Item item + } + + var e []encodable + + for _, it := range *db.list { + // TypeOf -> finds the dynamic type of "it" + // Elem -> returns the element type of the pointer + // Name -> returns the type name as string + t := reflect.TypeOf(it).Elem().Name() + e = append(e, encodable{t, it}) + } + + return json.Marshal(e) +} + +func (db *database) UnmarshalJSON(data []byte) error { + var decodables []struct { + Type string + Item json.RawMessage + } + + if err := json.Unmarshal(data, &decodables); err != nil { + return err + } + + for _, d := range decodables { + it, err := db.newItem(d.Item, d.Type) + if err != nil { + return err + } + + *db.list = append(*db.list, it) + } + + return nil +} + +func (db *database) newItem(data []byte, typ string) (item, error) { + it, ok := db.types[typ] + if !ok { + return nil, fmt.Errorf("newItem: type (%q) does not exist", typ) + } + + // get the dynamic type inside "it" like *book, *game, etc.. + t := reflect.TypeOf(it) + + // get the pointer type's element type like book, game, etc... + e := t.Elem() + + // create a new pointer value of the type like new(book), new(game), etc... + v := reflect.New(e) + + // get the interface value and cast it to the item type + it = v.Interface().(item) + + return it, json.Unmarshal(data, &it) +} + +func (db *database) register(typ string, it item) { + if db.types == nil { + db.types = make(map[string]item) + } + db.types[typ] = it +} diff --git a/interfaces/14-io-reader/_main_save.go b/interfaces/14-io-reader/_main_save.go new file mode 100644 index 0000000..076c5fb --- /dev/null +++ b/interfaces/14-io-reader/_main_save.go @@ -0,0 +1,40 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" +) + +func main() { + var store list + + db := database{list: &store} + + // db.register("book", new(book)) + // db.register("book", new(book)) + // db.register("game", new(game)) + // db.register("puzzle", new(puzzle)) + // db.register("toy", new(toy)) + + // db.load("database.json") + + store = list{ + &book{product{"moby dick", 10}, toTimestamp(118281600)}, + &book{product{"odyssey", 15}, toTimestamp("733622400")}, + &book{product{"hobbit", 25}, unknown}, + &puzzle{product{"rubik's cube", 5}}, + &game{product{"minecraft", 20}}, + &game{product{"tetris", 5}}, + &toy{product{"yoda", 150}}, + } + + db.save("database.json") + + fmt.Print(store) +} diff --git a/interfaces/14-io-reader/database.go b/interfaces/14-io-reader/database.go index 7f964d1..fc2b822 100644 --- a/interfaces/14-io-reader/database.go +++ b/interfaces/14-io-reader/database.go @@ -10,6 +10,7 @@ package main import ( "encoding/json" "fmt" + "io/ioutil" "reflect" ) @@ -18,14 +19,14 @@ type database struct { types map[string]item // the registry of the types } -// #v1 -// func (db *database) load(path string) error { -// data, err := ioutil.ReadFile(path) -// if err != nil { -// return err -// } -// return json.Unmarshal(data, db) -// } +// load the list by decoding the data from a json file. +func (db *database) load(path string) error { // #v1 + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + return json.Unmarshal(data, db) +} // #v2 // func (db *database) load(r io.Reader) error { @@ -39,28 +40,6 @@ type database struct { // #v3 // TODO: use decoder -// #v1 -// func (db *database) save(path string) error { -// data, err := json.MarshalIndent(db, "", "\t") -// if err != nil { -// return err -// } -// return ioutil.WriteFile(path, data, 0644) -// } - -// #v2 -// func (db *database) save(w io.Writer) error { -// data, err := json.MarshalIndent(db, "", "\t") -// if err != nil { -// return err -// } -// -// return io.Copy(w, bytes.NewReader(data)) -// } - -// #v3 -// TODO: use encoder - func (db *database) MarshalJSON() ([]byte, error) { type encodable struct { Type string diff --git a/interfaces/14-io-reader/database.json b/interfaces/14-io-reader/database.json index cccab62..5c9516c 100644 --- a/interfaces/14-io-reader/database.json +++ b/interfaces/14-io-reader/database.json @@ -51,4 +51,4 @@ "Price": 150 } } -] +] \ No newline at end of file diff --git a/interfaces/14-io-reader/main.go b/interfaces/14-io-reader/main.go index 9629cc7..800bb6d 100644 --- a/interfaces/14-io-reader/main.go +++ b/interfaces/14-io-reader/main.go @@ -8,18 +8,10 @@ package main import ( - "encoding/json" "fmt" - "io/ioutil" - "log" ) func main() { - data, err := ioutil.ReadFile("database.json") - if err != nil { - log.Fatalln(err) - } - var store list db := database{list: &store} @@ -29,9 +21,7 @@ func main() { db.register("puzzle", new(puzzle)) db.register("toy", new(toy)) - if err := json.Unmarshal(data, &db); err != nil { - log.Fatalln(err) - } + db.load("database.json") fmt.Print(store)