Needs and ideas
In general small projects or small software, such as small programs such as clients, data persistence may be required. However, using general databases (Mysql) and other things is not suitable. Using embedded sqlite3 is a better method, but the sqlite3 library in Go is C language, and Cgo does not support cross-platform compilation. It is precisely because of this requirement that I thought of using json format to save data directly in a file.
What is the specific idea? In Go language, if you want to convert data into json format, there are two formats: struct and map. If you need to add, delete, search and modify functions at the same time, it is more appropriate to use map as the intermediate format. Next, we will implement it.
Query operation
The implementation of this operation is relatively simple. You can directly read out the data in the file and deserialize it using the json library. The code is as follows:
type Product struct { Name string `json:"name"` Num int `json:"num"` } func findAll() { ps := make([]Product, 0) data, err := ("./") if err != nil { (err) } // This parameter should be specified as the address of the variable err = (data, &ps) if err != nil { (err) } (ps) }
Add an action
Based on the added implementation of real query, we need to query the database in the file first and convert it into map format, then convert struct into map format (reflection is used here), merge map, json serialization, and finally save it in the file. The code is as follows:
func create() { fields := make([]map[string]interface{}, 0) p1 := &Product{ Name: "Blog", Num: 2, } _, _ = (p1) // Read the data in the file and save it in map format data, _ := ("./") err := (data, &fields) if err != nil { (err) } // Use reflection to convert struct to map tp := (p1).Elem() vp := (p1).Elem() field := make(map[string]interface{}, 0) for i := 0; i < (); i++ { field1 := (i) field2 := (i) key := ("json") field[key] = () } // Merge map fields = append(fields, field) // Write to the file out, _ := (fields) _ = ("./", out, 0755) }
Conditional query
Idea: Convert struct into map and query according to the input conditions. The query results are converted into struct. The code is as follows:
func FindOne() { product := &Product{} p1 := &Product{ Name: "John", Num: 23, } // Use reflection to convert struct to map tp := (p1).Elem() vp := (p1).Elem() field := make(map[string]interface{}, 0) for i := 0; i < (); i++ { field1 := (i) field2 := (i) key := ("json") switch () { case : field[key] = float64(().(int)) case reflect.Int8: field[key] = float64(().(int8)) case reflect.Int16: field[key] = float64(().(int16)) case reflect.Int32: field[key] = float64(().(int32)) case reflect.Int64: field[key] = float64(().(int64)) case : field[key] = float64(().(uint)) case reflect.Uint8: field[key] = float64(().(uint8)) case reflect.Uint16: field[key] = float64(().(uint16)) case reflect.Uint32: field[key] = float64(().(uint32)) case reflect.Uint64: field[key] = float64(().(uint64)) case reflect.Float32: field[key] = float64(().(float32)) case reflect.Float64: field[key] = () default: field[key] = () } } _, _ = (p1) // Read the data in the file and save it in map format // When data is converted into map, the unity of the numerical type becomes float64 data, _ := ("./") fields := make([]map[string]interface{}, 0) err := (data, &fields) if err != nil { (err) } // Query conditions columns := []string{"name", "num"} length := len(columns) for _, item := range fields { for i := 0; i < length; i++ { // The comparison here needs to be improved if item[columns[i]] != field[columns[i]] { break } if i == length-1 { field = item goto OVER } } } OVER: (field) out, _ := (field) _ = (out, &product) (product) }
Modify the operation
The modification operation is implemented based on the query operation. The modification operation requires an id value to determine the uniqueness of the element. The code is as follows:
func Update() { p1 := &Product{ Id: "2bbec87025968879c3c9682abe3bf730", Name: "John_e", Num: 100, } // Use reflection to convert struct to map tp := (p1).Elem() vp := (p1).Elem() field := make(map[string]interface{}, 0) for i := 0; i < (); i++ { field1 := (i) field2 := (i) key := ("json") switch () { case : field[key] = float64(().(int)) case reflect.Int8: field[key] = float64(().(int8)) case reflect.Int16: field[key] = float64(().(int16)) case reflect.Int32: field[key] = float64(().(int32)) case reflect.Int64: field[key] = float64(().(int64)) case : field[key] = float64(().(uint)) case reflect.Uint8: field[key] = float64(().(uint8)) case reflect.Uint16: field[key] = float64(().(uint16)) case reflect.Uint32: field[key] = float64(().(uint32)) case reflect.Uint64: field[key] = float64(().(uint64)) case reflect.Float32: field[key] = float64(().(float32)) case reflect.Float64: field[key] = () default: field[key] = () } } _, _ = (p1) // Read the data in the file and save it in map format // When data is converted into map, the unity of the numerical type becomes float64 data, _ := ("./") fields := make([]map[string]interface{}, 0) err := (data, &fields) if err != nil { (err) } // Modified conditions columns := []string{"name", "num"} for _, v := range fields { if v["_id"] == field["_id"] { for _, col := range columns { v[col] = field[col] } field = v } } out, _ := (fields, "", " ") _ = ("./", out, 0755) }
Delete operation
Finally, it is the deletion operation. This is a simple idea. Enter the unique id value, delete the corresponding field, and then save it to the file. The code is as follows:
func Delete() { p1 := &Product{ Id: "db43fa2d4f69cddce7494941cb36032b", Name: "John_e", Num: 100, } _, _ = (p1) // Read the data in the file and save it in map format // When data is converted into map, the unity of the numerical type becomes float64 data, _ := ("./") fields := make([]map[string]interface{}, 0) err := (data, &fields) if err != nil { (err) } length := len(fields) for index, field := range fields { if field["_id"] == { if index == length - 1 { fields = fields[0:index] } else { fields = append(fields[0:index], fields[index+1:]...) } } } out, _ := (fields, "", " ") _ = ("./", out, 0755) }
Full version
Finally, the full version of the code is attached:
package store import ( "bytes" "crypto/md5" "encoding/json" "errors" "fmt" "io/ioutil" "os" "path/filepath" "reflect" "strings" "time" ) type Store struct { Dir string } func NewStore(dir string) (*Store, error) { // .The beginning is a relative path, and the completion is a full path if (dir, ".") { pwd, _ := () dir = (pwd, dir) } store := &Store{Dir: dir} st, err := (dir) if err != nil { err = (dir, 0755) if err != nil { return nil, err } } else if st != nil && !() { return nil, ("file already exists") } return store, nil } // Create a json file corresponding to the structurefunc (s *Store) Sync(values ...interface{}) error { for _, v := range values { tb := parseTn(v) if tb == "" { return ("does not find store") } _path := (, tb) _, err := (_path) if err != nil { _ = (_path, []byte("[]"), 0755) } } return nil } // Delete allfunc (s *Store) Destroy() error { return () } func (s *Store) FindAll(v interface{}) error { _path, err := (v) if err != nil { return err } out, err := (_path) if err != nil { return err } err = (out, &v) return err } func (s *Store) FindOne(v interface{}, columns ...string) (interface{}, error) { _path, err := (v) if err != nil { return nil, err } data, err := (_path) if err != nil { return nil, err } fields := make([]map[string]interface{}, 0) err = (data, &fields) if err != nil { return nil, err } m := structToMap(v) length := len(columns) for _, item := range fields { for i := 0; i < length; i++ { // TODO The comparison here needs to be improved if item[columns[i]] != m[columns[i]] { break } if i == length-1 { m = item goto OVER } } } OVER: err = mapToStruct(m, &v) if err != nil { return nil, err } return v, nil } func (s *Store) Create(v interface{}) error { _path, err := (v) if err != nil { return err } data, err := (_path) if err != nil { return err } fields := make([]map[string]interface{}, 0) err = (data, &fields) if err != nil { return err } m := structToMap(v) m["_id"] = randId() fields = append(fields, m) err = (_path, fields) if err != nil { return err } err = mapToStruct(m, v) if err != nil { return err } return nil } func (s *Store) Update(v interface{}, columns ...string) error { _path, err := (v) if err != nil { return err } data, err := (_path) if err != nil { return err } fields := make([]map[string]interface{}, 0) err = (data, &fields) if err != nil { return err } m := structToMap(v) for _, v := range fields { if v["_id"] == m["_id"] { for _, col := range columns { v[col] = m[col] } m = v } } err = (_path, fields) if err != nil { return err } return nil } func (s *Store) Delete(v interface{}) error { _path, err := (v) if err != nil { return err } data, err := (_path) if err != nil { return err } fields := make([]map[string]interface{}, 0) err = (data, &fields) if err != nil { return err } m := structToMap(v) length := len(fields) for index, field := range fields { if field["_id"] == m["_id"] { if index == length-1 { fields = fields[0:index] } else { fields = append(fields[0:index], fields[index+1:]...) } } } err = (_path, fields) if err != nil { return err } return nil } func (s *Store) Clean(v interface{}) error { _path, err := (v) if err != nil { return err } return (_path) } func (s *Store) readAll(file string) ([]byte, error) { out, err := (file) if err != nil { return nil, err } return out, nil } func (s *Store) writeAll(file string, v interface{}) error { out, err := (v, "", " ") if err != nil { return err } err = (file, out, 0755) if err != nil { return err } return nil } func (s *Store) before(v interface{}) (string, error) { tb := parseTn(v) if tb == "" { return "", ("invalid table name") } _path := (, tb) _, err := (_path) if err != nil { return "", err } return _path, nil } func structToMap(v interface{}) map[string]interface{} { tp := (v).Elem() vp := (v).Elem() field := make(map[string]interface{}, 0) for i := 0; i < (); i++ { field1 := (i) field2 := (i) key := ("json") field[key] = () switch () { case : field[key] = float64(().(int)) case reflect.Int8: field[key] = float64(().(int8)) case reflect.Int16: field[key] = float64(().(int16)) case reflect.Int32: field[key] = float64(().(int32)) case reflect.Int64: field[key] = float64(().(int64)) case : field[key] = float64(().(uint)) case reflect.Uint8: field[key] = float64(().(uint8)) case reflect.Uint16: field[key] = float64(().(uint16)) case reflect.Uint32: field[key] = float64(().(uint32)) case reflect.Uint64: field[key] = float64(().(uint64)) case reflect.Float32: field[key] = float64(().(float32)) case reflect.Float64: field[key] = () default: field[key] = () } } return field } func mapToStruct(m map[string]interface{}, v interface{}) error { out, err := (m) if err != nil { return err } return (out, &v) } func toSnake(s string) string { out := {} bName := []byte(s) point := 0 for index, b := range bName { // No capitalization, no conversion required if b < 65 || b > 90 || index-point < 2 { (b) continue } // The first letter is uppercase, directly converted to lowercase if index == 0 { (b + 32) point = index } // Three consecutive capitalizations trigger conversion if index-point >= 2 { (95) (b + 32) point = index } } return () } func parseTn(v interface{}) string { var name string tp := (v).Elem() switch () { case : sp := ((), ".") name = sp[len(sp)-1] case : sp := ((), ".") name = sp[len(sp)-1] case : name = () } name = toSnake(name) return name + ".json" } func randId() string { return ("%x", ([]byte(().String()))) }
This is the article about this article about the implementation example of golang using json format to implement addition, deletion, and revision. For more related golang json addition, deletion, and revision, please search for my previous articles or continue to browse the related articles below. I hope everyone will support me in the future!