DB 의 스키마를 정의하고, Go 서버와 연결까지 마무리 하였으니 이제 model 의 주 기능인 DB 에 접속하여 자료를 query 문을 사용하여 제어하는 부분을 구현한다.
model 기능은 sqliteHandler.go 파일에서 담당한다.
DB 에서 자료를 가져오는 GetTodos() 메서드 코드를 작성했다.
func (s *sqliteHandler) GetTodos() []*Todo {
todos := []*Todo{}
rows, err := s.db.Query("SELECT id, name, completed, createdAt FROM todos")
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
}

db.Query 메서드를 사용해서 쿼리를 한다. 첫 번째 인자에 쿼리문을 넣어주면 된다. 검색된 자료를 sql.Rows 타입의 포인터로 반환한다.
rows도 파일 DB 연결이 이루어진 것이기에 Close 로 닫아야 하며, Iterator 타입이기 때문에 for 문 안에서 Next() 를 이용해서 각 원소에 접근 가능하다. Todo 인스턴스를 생성해서 값을 채우고 todos 배열에 append 해줌으로써 모든 원소의 값을 저장할 수 있다.
이어서 DB 에 자료를 추가하는 AddTodo() 메서드를 만들었다.
func (s *sqliteHandler) AddTodo(name string) *Todo {
statement, err := s.db.Prepare("INSERT INTO todos (name, completed, createdAt) VALUES (?, ?, datetime('now'))")
if err != nil {
panic(err)
}
result, err := statement.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
}
이전에 학습하였듯이 db.Prepare 에 쿼리를 넣으면 statement 와 err 를 반환한다.
쿼리문을 살펴보면 node.js 의 시퀄라이저와 매우 비슷하다는 것을 알 수 있다. ‘?’ 에는 statement.Exec() 을 할 때 인자로 넣어주는 값이 들어간다. dateTime(’now’) 는 SQLite 내장 함수로 현재 시간을 createdAt 에 넣어준다.
go test 를 해보면 여기까지는 문제없이 테스트 코드가 통과되는 것을 확인할 수 있다.
주의할 점은 이제 테스트를 하더라도 DB 파일에 자료가 저장되기 때문에 다시 테스트를 하면 자료가 저장된 갯수라든가 이런 부분에서 기존에 2 로 지정해둔 값에 오류가 생긴다.
app_test.go 파일의 TestTodos() 함수 앞 부분을 아래와 같이 수정했다.
func TestTodos(t *testing.T) {
os.Remove("./test.db")
assert := assert.New(t)
// 테스트 서버 open
appHandler := MakeHandler()
defer appHandler.Close()
ts := httptest.NewServer(appHandler)
defer ts.Close()