Skip to content

Commit d89b78f

Browse files
committed
todo CRUD done, testing left
1 parent 69274a7 commit d89b78f

3 files changed

Lines changed: 268 additions & 26 deletions

File tree

go/samples/http/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@ func runApp(todosController *todos.TodosController) {
8282
func runForMysql() *gosql.DB {
8383
connection := "root:password@/sqlcommenter_db"
8484
db := mysqldb.ConnectMySQL(connection)
85-
todosController := &todos.TodosController{DB: db, SQL: todos.MySQLQueries{}}
85+
todosController := &todos.TodosController{Engine: "mysql", DB: db, SQL: todos.MySQLQueries{}}
8686
runApp(todosController)
8787
return db
8888
}
8989

9090
func runForPg() *gosql.DB {
9191
connection := "postgres://dev:dev@localhost/sqlcommenter_db?sslmode=disable"
9292
db := pgdb.ConnectPG(connection)
93-
todosController := &todos.TodosController{DB: db, SQL: todos.PGQueries{}}
93+
todosController := &todos.TodosController{Engine: "pg", DB: db, SQL: todos.PGQueries{}}
9494
runApp(todosController)
9595
return db
9696
}
Lines changed: 225 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,256 @@
11
package todos
22

33
import (
4+
"context"
5+
"encoding/json"
6+
"log"
47
"net/http"
58

69
gosql "github.com/google/sqlcommenter/go/database/sql"
710
"github.com/julienschmidt/httprouter"
811
)
912

13+
type Todo struct {
14+
Id int `json:"id"`
15+
Task string `json:"task"`
16+
}
17+
18+
type TodoDTO struct {
19+
Task string `json:"task"`
20+
}
21+
1022
type TodosController struct {
11-
DB *gosql.DB
12-
SQL TodosQueries
23+
Engine string
24+
DB *gosql.DB
25+
SQL TodosQueries
1326
}
1427

1528
func (c *TodosController) CreateTodosTableIfNotExists() error {
1629
return nil
1730
}
1831

1932
func (c *TodosController) ActionList(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
33+
ctx := r.Context()
34+
35+
query := r.URL.Query()
36+
search := query.Get("search")
2037

38+
rows, err := c.DB.QueryContext(ctx, c.SQL.ListTodos(), search)
39+
if err != nil {
40+
writeServerErrorResponse(w, "query failed")
41+
return
42+
}
43+
defer rows.Close()
44+
45+
var todos []Todo
46+
for rows.Next() {
47+
var todo Todo
48+
if err := rows.Scan(&todo.Id, &todo.Task); err != nil {
49+
writeServerErrorResponse(w, "scan row failed")
50+
return
51+
}
52+
53+
todos = append(todos, todo)
54+
}
55+
56+
res := make(map[string]([]Todo))
57+
res["todos"] = todos
58+
writeJsonResponse(w, res)
2159
}
2260

2361
func (c *TodosController) ActionInsert(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
62+
ctx := r.Context()
63+
64+
var dto TodoDTO
65+
err := json.NewDecoder(r.Body).Decode(&dto)
66+
if err != nil {
67+
writeServerErrorResponse(w, "parsing body failed")
68+
return
69+
}
70+
71+
if c.Engine == "pg" {
72+
c.insertTodoPG(ctx, w, dto)
73+
} else if c.Engine == "mysql" {
74+
c.insertTodoMySQL(ctx, w, dto)
75+
} else {
76+
log.Fatalf("Invalid controller.Engine %v", c.Engine)
77+
}
78+
}
79+
80+
func (c *TodosController) insertTodoPG(ctx context.Context, w http.ResponseWriter, dto TodoDTO) {
81+
rows, err := c.DB.QueryContext(ctx, c.SQL.InsertTodo(), dto.Task)
82+
if err != nil {
83+
writeServerErrorResponse(w, "insert failed")
84+
return
85+
}
86+
87+
if rows.Next() {
88+
var todo Todo
89+
if err := rows.Scan(&todo.Id, &todo.Task); err != nil {
90+
writeServerErrorResponse(w, "scan row failed")
91+
return
92+
}
93+
94+
res := make(map[string]Todo)
95+
res["todo"] = todo
96+
writeJsonResponse(w, res)
97+
return
98+
} else {
99+
writeServerErrorResponse(w, "no record of inserted task")
100+
return
101+
}
102+
}
24103

104+
func (c *TodosController) insertTodoMySQL(ctx context.Context, w http.ResponseWriter, dto TodoDTO) {
105+
dbRes, err := c.DB.ExecContext(ctx, c.SQL.InsertTodo(), dto.Task)
106+
if err != nil {
107+
writeServerErrorResponse(w, "insert failed")
108+
return
109+
}
110+
111+
lId, err := dbRes.LastInsertId()
112+
if err != nil {
113+
writeServerErrorResponse(w, "cannot get insert-id")
114+
return
115+
}
116+
117+
rows, err := c.DB.QueryContext(ctx, c.SQL.TodoById(), lId)
118+
if err != nil {
119+
writeServerErrorResponse(w, "error in query")
120+
return
121+
}
122+
123+
if rows.Next() {
124+
var todo Todo
125+
if err := rows.Scan(&todo.Id, &todo.Task); err != nil {
126+
writeServerErrorResponse(w, "scan row failed")
127+
return
128+
}
129+
130+
res := make(map[string]Todo)
131+
res["todo"] = todo
132+
writeJsonResponse(w, res)
133+
return
134+
} else {
135+
writeServerErrorResponse(w, "no record of inserted task")
136+
return
137+
}
25138
}
26139

27140
func (c *TodosController) ActionUpdate(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
141+
ctx := r.Context()
142+
id := p.ByName("id")
143+
144+
var dto TodoDTO
145+
err := json.NewDecoder(r.Body).Decode(&dto)
146+
if err != nil {
147+
writeServerErrorResponse(w, "parsing body failed")
148+
return
149+
}
28150

151+
var todo Todo
152+
rows, err := c.DB.QueryContext(ctx, c.SQL.TodoById(), id)
153+
if err != nil {
154+
writeServerErrorResponse(w, "error in query")
155+
return
156+
}
157+
158+
if rows.Next() {
159+
if err := rows.Scan(&todo.Id, &todo.Task); err != nil {
160+
writeServerErrorResponse(w, "scan row failed")
161+
return
162+
}
163+
} else {
164+
writeNotFoundResponse(w)
165+
return
166+
}
167+
168+
_, err = c.DB.ExecContext(ctx, c.SQL.UpdateTodo(), dto.Task, todo.Id)
169+
if err != nil {
170+
writeServerErrorResponse(w, "update todo query failed")
171+
return
172+
}
173+
174+
todo.Task = dto.Task
175+
res := make(map[string]Todo)
176+
res["todo"] = todo
177+
writeJsonResponse(w, res)
29178
}
30179

31180
func (c *TodosController) ActionDelete(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
181+
ctx := r.Context()
182+
id := p.ByName("id")
183+
184+
var todo Todo
185+
rows, err := c.DB.QueryContext(ctx, c.SQL.TodoById(), id)
186+
if err != nil {
187+
writeServerErrorResponse(w, "error in query")
188+
return
189+
}
190+
191+
if rows.Next() {
192+
if err := rows.Scan(&todo.Id, &todo.Task); err != nil {
193+
writeServerErrorResponse(w, "scan row failed")
194+
return
195+
}
196+
} else {
197+
writeNotFoundResponse(w)
198+
return
199+
}
200+
201+
_, err = c.DB.ExecContext(ctx, c.SQL.DeleteTodo(), todo.Id)
202+
if err != nil {
203+
writeServerErrorResponse(w, "update todo query failed")
204+
return
205+
}
206+
207+
res := make(map[string]Todo)
208+
res["todo"] = todo
209+
writeJsonResponse(w, res)
210+
}
211+
212+
func writeJsonResponse(w http.ResponseWriter, res any) {
213+
w.WriteHeader(http.StatusOK)
214+
w.Header().Set("Content-Type", "application/json")
215+
216+
resJson, err := json.Marshal(res)
217+
if err != nil {
218+
log.Fatalf("error: json marshall: %v", res)
219+
}
220+
221+
w.Write(resJson)
222+
return
223+
}
224+
225+
func writeServerErrorResponse(w http.ResponseWriter, reason string) {
226+
w.WriteHeader(http.StatusInternalServerError)
227+
w.Header().Set("Content-Type", "application/json")
228+
229+
res := make(map[string]string)
230+
res["msg"] = "server error"
231+
res["reason"] = reason
232+
233+
resJson, err := json.Marshal(res)
234+
if err != nil {
235+
log.Fatalf("error: json marshall: %v", res)
236+
}
237+
238+
w.Write(resJson)
239+
return
240+
}
241+
242+
func writeNotFoundResponse(w http.ResponseWriter) {
243+
w.WriteHeader(http.StatusNotFound)
244+
w.Header().Set("Content-Type", "application/json")
245+
246+
res := make(map[string]string)
247+
res["msg"] = "not found"
248+
249+
resJson, err := json.Marshal(res)
250+
if err != nil {
251+
log.Fatalf("error: json marshall: %v", res)
252+
}
32253

254+
w.Write(resJson)
255+
return
33256
}

go/samples/http/todos/queries.go

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,69 @@ type MySQLQueries struct{}
55

66
type TodosQueries interface {
77
CreateTodosTableIfNotExists() string
8-
ListTodos(search string) string
9-
InsertTodo(task string) string
10-
UpdateTodo(id int, task string) string
11-
DeleteTodo(id int) string
8+
ListTodos() string
9+
InsertTodo() string
10+
UpdateTodo() string
11+
DeleteTodo() string
12+
TodoById() string
1213
}
1314

1415
// PGQueries impl
1516
func (sql PGQueries) CreateTodosTableIfNotExists() string {
16-
return ""
17+
return `CREATE TABLE IF NOT EXISTS todos(
18+
id SERIAL NOT NULL,
19+
task VARCHAR(1000) NOT NULL,
20+
21+
PRIMARY KEY(id)
22+
)`
23+
}
24+
25+
func (sql PGQueries) ListTodos() string {
26+
return "SELECT id, task FROM todos WHERE LOWER(task) LIKE $1 ORDER BY id DESC"
1727
}
1828

19-
func (sql PGQueries) ListTodos(search string) string {
20-
return ""
29+
func (sql PGQueries) InsertTodo() string {
30+
return "INSERT INTO todos (task) VALUES ($1) RETURNING id, task"
2131
}
2232

23-
func (sql PGQueries) InsertTodo(task string) string {
24-
return ""
33+
func (sql PGQueries) UpdateTodo() string {
34+
return "UPDATE todos SET task=$1 WHERE id=$2"
2535
}
2636

27-
func (sql PGQueries) UpdateTodo(id int, task string) string {
28-
return ""
37+
func (sql PGQueries) DeleteTodo() string {
38+
return "DELETE FROM todos WHERE id=$1"
2939
}
3040

31-
func (sql PGQueries) DeleteTodo(id int) string {
32-
return ""
41+
func (sql PGQueries) TodoById() string {
42+
return "SELECT id, task FROM todos WHERE id=$1"
3343
}
3444

3545
// MySQLQueries impl
3646
func (sql MySQLQueries) CreateTodosTableIfNotExists() string {
37-
return ""
47+
return `CREATE TABLE IF NOT EXISTS todos(
48+
id INT NOT NULL AUTO_INCREMENT,
49+
task VARCHAR(1000) NOT NULL
50+
51+
PRIMARY KEY(id)
52+
)`
53+
}
54+
55+
func (sql MySQLQueries) ListTodos() string {
56+
return "SELECT id, task FROM todos WHERE task LIKE ? ORDER BY id DESC"
3857
}
3958

40-
func (sql MySQLQueries) ListTodos(search string) string {
41-
return ""
59+
func (sql MySQLQueries) InsertTodo() string {
60+
return "INSERT INTO todos (task) VALUES (?)"
4261
}
4362

44-
func (sql MySQLQueries) InsertTodo(task string) string {
45-
return ""
63+
func (sql MySQLQueries) UpdateTodo() string {
64+
return "UPDATE todos SET task=? WHERE id=?"
4665
}
4766

48-
func (sql MySQLQueries) UpdateTodo(id int, task string) string {
49-
return ""
67+
func (sql MySQLQueries) DeleteTodo() string {
68+
return "DELETE FROM todos WHERE id=?"
5069
}
5170

52-
func (sql MySQLQueries) DeleteTodo(id int) string {
53-
return ""
71+
func (sql MySQLQueries) TodoById() string {
72+
return "SELECT id, task FROM todos WHERE id=?"
5473
}

0 commit comments

Comments
 (0)