diff --git a/interfaces/14-io-reader/_database_save.go b/interfaces/14-io-reader/_database_save.go deleted file mode 100644 index 01a4fd6..0000000 --- a/interfaces/14-io-reader/_database_save.go +++ /dev/null @@ -1,133 +0,0 @@ -// 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 deleted file mode 100644 index 076c5fb..0000000 --- a/interfaces/14-io-reader/_main_save.go +++ /dev/null @@ -1,40 +0,0 @@ -// 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 fc2b822..9c0dc30 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" "io/ioutil" "reflect" ) @@ -19,27 +20,17 @@ type database struct { 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) +// load the list by decoding the data from any data source. +func (db *database) load(r io.Reader) error { + // ReadAll reads from `r` entirely into memory. + // `data` contains the entire data in memory. + data, err := ioutil.ReadAll(r) if err != nil { return err } return json.Unmarshal(data, db) } -// #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 - func (db *database) MarshalJSON() ([]byte, error) { type encodable struct { Type string @@ -49,9 +40,6 @@ func (db *database) MarshalJSON() ([]byte, error) { 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}) } @@ -87,16 +75,9 @@ func (db *database) newItem(data []byte, typ string) (item, error) { 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) diff --git a/interfaces/14-io-reader/main.go b/interfaces/14-io-reader/main.go index 800bb6d..023bea7 100644 --- a/interfaces/14-io-reader/main.go +++ b/interfaces/14-io-reader/main.go @@ -9,22 +9,10 @@ package main import ( "fmt" + "net/http" ) 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") - - fmt.Print(store) - /* store := list{ &book{product{"moby dick", 10}, toTimestamp(118281600)}, @@ -48,4 +36,32 @@ func main() { // store.discount(.5) // fmt.Print(store) */ + + 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)) + + // load from a file + // f, _ := os.Open("database.json") + // db.load(f) + // f.Close() + + // load from a string + // const data = `[ + // { "Type": "book", "Item": { "Title": "1984", "Price": 8, "Published": -649641600 } }, + // { "Type": "game", "Item": { "Title": "paperboy", "Price": 20 } }]` + // r := strings.NewReader(data) + // db.load(r) + + // load from a web server + res, _ := http.Get("https://inancgumus.github.io/x/database.json") + db.load(res.Body) + res.Body.Close() + + fmt.Print(store) }