package persist import ( "encoding/json" "fmt" "os" "io" ) import "snamellit.com/play/todo/internal/model" var EMPTY_TODO = model.Todo{Id: 0, Title: "", Completed: false} var maxId int = 0 var todos model.Todos type eventType string const ( ADDED eventType = "ADDED" DELETED eventType = "DELETED" CHANGED eventType = "CHANGED" ) type event struct { Kind eventType Todo model.Todo } func readTodos() (model.Todos, error) { f, err := os.OpenFile("todo_events.txt", os.O_RDONLY|os.O_CREATE, 0644) defer f.Close() if err != nil { return nil, err } dec := json.NewDecoder(f) todos = make(model.Todos) for { var e event err = dec.Decode(&e) if err != nil { if err == io.EOF { break } return nil, err } fmt.Println("Read event", e) id := e.Todo.Id if id > maxId { maxId = id } applyEvent(e.Kind, e.Todo) } return todos, nil } func applyEvent(kind eventType, todo model.Todo) error { id := todo.Id switch t := kind; t { case ADDED: fmt.Println("apply add ", todo) todos[id] = todo case CHANGED: fmt.Println("apply change ", todo) todos[id] = todo case DELETED: fmt.Println("apply delete ", todo) delete(todos, id) default: return fmt.Errorf("Unknown event type %s", t) } return nil } func addEvent(kind eventType, todo model.Todo) error { err := applyEvent(kind, todo) if err != nil { return err } f, err := os.OpenFile("todo_events.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) defer f.Close() if err != nil { return err } fmt.Println("Write todo", todo) enc := json.NewEncoder(f) e := event{Kind: kind, Todo: todo} fmt.Println("Write event", e) err = enc.Encode(e) if err != nil { return err } return nil } func GetTodos() (model.Todos, error) { if len(todos) == 0 { return readTodos() } return todos, nil } func GetTodoById(id int) (model.Todo, error) { todo, present := todos[id] if !present { return EMPTY_TODO, fmt.Errorf("Todo with id %d not found", id) } return todo, nil } func SetTodo(todo model.Todo) error { fmt.Println("SetTodo", todo) todos[todo.Id] = todo return addEvent(CHANGED, todo) } func AddTodo(title string) error { fmt.Println("AddTodo", title) maxId++; todo := model.Todo{Id: maxId, Title: title, Completed: false} return addEvent(ADDED, todo) } func DeleteTodoById(id int) error { delete(todos, id) return addEvent(DELETED, model.Todo{Id: id}) }