finalize: io reader lecture
This commit is contained in:
		| @@ -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 |  | ||||||
| } |  | ||||||
| @@ -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) |  | ||||||
| } |  | ||||||
| @@ -10,6 +10,7 @@ package main | |||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| ) | ) | ||||||
| @@ -19,27 +20,17 @@ type database struct { | |||||||
| 	types map[string]item // the registry of the types | 	types map[string]item // the registry of the types | ||||||
| } | } | ||||||
|  |  | ||||||
| // load the list by decoding the data from a json file. | // load the list by decoding the data from any data source. | ||||||
| func (db *database) load(path string) error { // #v1 | func (db *database) load(r io.Reader) error { | ||||||
| 	data, err := ioutil.ReadFile(path) | 	// ReadAll reads from `r` entirely into memory. | ||||||
|  | 	// `data` contains the entire data in memory. | ||||||
|  | 	data, err := ioutil.ReadAll(r) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return json.Unmarshal(data, db) | 	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) { | func (db *database) MarshalJSON() ([]byte, error) { | ||||||
| 	type encodable struct { | 	type encodable struct { | ||||||
| 		Type string | 		Type string | ||||||
| @@ -49,9 +40,6 @@ func (db *database) MarshalJSON() ([]byte, error) { | |||||||
| 	var e []encodable | 	var e []encodable | ||||||
|  |  | ||||||
| 	for _, it := range *db.list { | 	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() | 		t := reflect.TypeOf(it).Elem().Name() | ||||||
| 		e = append(e, encodable{t, it}) | 		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) | 		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) | 	t := reflect.TypeOf(it) | ||||||
|  |  | ||||||
| 	// get the pointer type's element type like book, game, etc... |  | ||||||
| 	e := t.Elem() | 	e := t.Elem() | ||||||
|  |  | ||||||
| 	// create a new pointer value of the type like new(book), new(game), etc... |  | ||||||
| 	v := reflect.New(e) | 	v := reflect.New(e) | ||||||
|  |  | ||||||
| 	// get the interface value and cast it to the item type |  | ||||||
| 	it = v.Interface().(item) | 	it = v.Interface().(item) | ||||||
|  |  | ||||||
| 	return it, json.Unmarshal(data, &it) | 	return it, json.Unmarshal(data, &it) | ||||||
|   | |||||||
| @@ -9,22 +9,10 @@ package main | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"net/http" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func main() { | 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{ | 		store := list{ | ||||||
| 			&book{product{"moby dick", 10}, toTimestamp(118281600)}, | 			&book{product{"moby dick", 10}, toTimestamp(118281600)}, | ||||||
| @@ -48,4 +36,32 @@ func main() { | |||||||
| 		// store.discount(.5) | 		// store.discount(.5) | ||||||
| 		// fmt.Print(store) | 		// 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) | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user