기본 구조는 아래와 같습니다.
이번에는 sqlliteHandler.go 파일을 마무리하고 디비파일 위치와 이름을 파라미터로 처리하게 변경하였음.
그래서 테스트시에는 test.db 를 사용하고 실제 운영시에는 todo.db 를 사용하게 처리 가능하였음.
./model/sqlliteHandler.go - 완료
package model
import (
"database/sql"
"time"
_ "github.com/mattn/go-sqlite3"
)
type sqliteHandler struct {
db *sql.DB
}
func (s *sqliteHandler) GetTodos() []*Todo {
todos := []*Todo{}
sql_string := "SELECT id, name, completed, createdAt From todos"
rows, err := s.db.Query(sql_string)
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
var todo Todo
rows.Scan(&todo.ID, &todo.Name, &todo.Completed, &todo.CreatedAt)
todos = append(todos, &todo)
}
return todos
}
func (s *sqliteHandler) AddTodo(name string) *Todo {
sql_string := "INSERT INTO todos (name, completed, createdAt) VALUES(?,?,datetime('now'))"
stmt, err := s.db.Prepare(sql_string)
if err != nil {
panic(err)
}
result, err := stmt.Exec(name, false)
if err != nil {
panic(err)
}
id, _ := result.LastInsertId()
var todo Todo
todo.ID = int(id)
todo.Name = name
todo.Completed = false
todo.CreatedAt = time.Now()
return &todo
}
func (s *sqliteHandler) RemoveTodo(id int) bool {
sql_string := "DELETE FROM todos WHERE id = ?"
stmt, err := s.db.Prepare(sql_string)
if err != nil {
panic(err)
}
result, err := stmt.Exec(id)
if err != nil {
panic(err)
}
cnt, _ := result.RowsAffected()
return cnt > 0
}
func (s *sqliteHandler) CompleteTodo(id int, complete bool) bool {
sql_string := "UPDATE todos SET completed = ? WHERE id = ?"
stmt, err := s.db.Prepare(sql_string)
if err != nil {
panic(err)
}
result, err := stmt.Exec(complete, id)
if err != nil {
panic(err)
}
cnt, _ := result.RowsAffected()
return cnt > 0
}
func (s *sqliteHandler) Close() {
s.db.Close()
}
func newSqliteHandler(filepath string) DBHandler {
database, err := sql.Open("sqlite3", filepath)
if err != nil {
panic(err)
}
statement, _ := database.Prepare(
`CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
completed BOOLEAN,
createdAt DATETIME
)`)
statement.Exec()
return &sqliteHandler{db: database}
// return &sqliteHandler{}
}
./model/model.go 및 관련 파일 수정 - filepath 를 main.go 에서 설정가능하게 모두 수정함.
// sqliteHandler.go 파일의 파라미터 추가
func newSqliteHandler(filepath string) DBHandler {
database, err := sql.Open("sqlite3", filepath)
// sqliteHandler.go 파일의 파라미터 추가로 상위 파일인 model.go 파일수정.
func NewDBHandler(filepath string) DBHandler {
return newSqliteHandler(filepath)
}
// 관련하여 app.go 파일도 수정
func MakeNewHandler(filepath string) *AppHandler {
mux := mux.NewRouter()
a := &AppHandler{
Handler: mux,
db: model.NewDBHandler(filepath),
}
// 최상위 호출파일인 main.go 수정
func main() {
mux := myapp.MakeNewHandler("./todo.db")
defer mux.Close()
test result
PS D:\workspace\GO\tuckersGo\goWeb\web19-todo_sqlite\myapp>
PS D:\workspace\GO\tuckersGo\goWeb\web19-todo_sqlite\myapp> go test
2021/11/19 14:03:52 app_test.go / add result > {1 Test todo false 2021-11-19 14:03:52.6294806 +0100 CET} 1
2021/11/19 14:03:52 app_test.go / add result > {2 Test todo2 false 2021-11-19 14:03:52.6647899 +0100 CET} 2
2021/11/19 14:03:52 after getting whole data > {1 Test todo false 2021-11-19 13:03:52 +0000 UTC}
2021/11/19 14:03:52 after getting whole data > {2 Test todo2 false 2021-11-19 13:03:52 +0000 UTC}
2021/11/19 14:03:52 after complete for > {1 Test todo false 2021-11-19 13:03:52 +0000 UTC}
2021/11/19 14:03:52 after complete for > {2 Test todo2 true 2021-11-19 13:03:52 +0000 UTC}
2021/11/19 14:03:52 delete id1: 1
2021/11/19 14:03:52 after delete for > {2 Test todo2 true 2021-11-19 13:03:52 +0000 UTC}
PASS
ok GO/tuckersGo/goWeb/web18-todo_sqlite/myapp 0.387s
PS D:\workspace\GO\tuckersGo\goWeb\web19-todo_sqlite\myapp>
참고로 app_test.go 파일은 아래 부분을 수정함.
테스트용 db 를 별도로 생성한 이유는 테스트시 insert 된 내용이 중복으로 db 에 저장되므로 검증시 오류로 인식함.
func TestTodos(t *testing.T) {
os.Remove("./test.db") // insert 결과가 계속 저장되어 삭제하고 테스트를 시작함
assert := assert.New(t)
appH := MakeNewHandler("./test.db") // 테스트용 db를 별도로 생성, 위치는 ./myapp/test.db
defer appH.Close() // 자동종료 추가
이제는 아래의 호출자에 따라서 SQLite3 또는 메모리상의 map 구조로 데이터를 저장가능하게 되었음.
그러나, sqlite3는 서버를 재실행해도 기존 todo lists 가 저장되어 있는 반면, map 구조는 서버를 재실행시 todo lists 가 초기화 되어 이전 리스트가 사라지는 차이점이 있음.
// sqlite3 로 처리한 경우
func NewDBHandler(filepath string) DBHandler {
return newSqliteHandler(filepath)
}
// map 으로 처리한 경우
func NewDBHandler(filepath string) DBHandler {
return newMemoryHandler()
}
sqlite DB browser 는 다음 툴로 확인 가능함 ==> [DB Browser for SQLite (sqlitebrowser.org)]
참고자료 [유투브 링크]
- 패키지 설치 및 컴파일 오류 대처
1. sqlite3를 사용하기 위해서는 tdm-gcc를 설치해야 함 - 관련 설명은 아래 링크 참고
[https://www.youtube.com/watch?v=UVhprQ5CYh4&list=PLy-g2fnSzUTDALoERcKDniql16SAaQYHF&index=19]
2. go get github.com/mattn/go-sqlite3 패키지 설치
tdm-gcc 설치 후, MinGW prompt 상에서 "go get github.com/mattn/go-sqlite3" 을 실행해야 함.
[MinGW prompt 실행화면]
Setting up environment for using MinGW with GCC from C:\TDM-GCC-64\.
C:\TDM-GCC-64>go get github.com/mattn/go-sqlite3
go: downloading github.com/mattn/go-sqlite3 v1.14.9
C:\TDM-GCC-64>
3. 강좌에서는 1,2 번만 처리하는데, 나는 오류가 발생하여 아래와 같이 추가 처리함.
(tdm-gcc 설치후 해당 프롬프트에서 "go get github.com/mattn/go-sqlite3" 명령어 처리)
/* 오류 내용은 아래와 같음.
PS D:\workspace\GO\tuckersGo\goWeb\web19-todo_sqlite\myapp> go test
..\model\sqlliteHandler.go:6:2: no required module provides package github.com/mattn/go-sqlite3; to add it:
go get github.com/mattn/go-sqlite3
PS D:\workspace\GO\tuckersGo\goWeb\web19-todo_sqlite\myapp>
*/
PS D:\workspace\GO\tuckersGo\goWeb\web19-todo_sqlite\myapp> go get github.com/mattn/go-sqlite3
go get: added github.com/mattn/go-sqlite3 v1.14.9
PS D:\workspace\GO\tuckersGo\goWeb\web19-todo_sqlite\myapp>
'GO lang > web' 카테고리의 다른 글
[GO] Todo list - session 별 데이터 관리 (0) | 2021.11.23 |
---|---|
[GO] Todo list - Google Oauth2 (0) | 2021.11.23 |
[GO] Todo list - interface 구현2 (0) | 2021.11.18 |
[GO] Todo list - interface 구현1 (0) | 2021.11.18 |
[GO] Todo list - refactoring(구조변경) (0) | 2021.11.17 |