133 lines
2.3 KiB
Go
133 lines
2.3 KiB
Go
|
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})
|
||
|
}
|
||
|
|