// GetTodosByUser は特定のユーザーに関連するTodoリストを取得します。
func (u *User) GetTodosByUser() (todos []Todo, err error) {
// SQLコマンドを定義します。?はプレースホルダーで、後で実際の値に置き換えます。
cmd := `select id, content, user_id, created_at from todos where user_id = ?`
// データベースから結果セットを取得します。
rows, err := Db.Query(cmd, u.ID)
if err != nil {
// エラーが発生した場合はログに記録して、エラーを返します。
log.Fatalln(err)
return nil, err
}
defer rows.Close()
// 結果セットからTodoを取得します。
for rows.Next() {
// 新しいTodoオブジェクトを作成します。
var todo Todo
// 現在の行のカラムの値を、Todoオブジェクトの各フィールドにスキャンします。
err = rows.Scan(
&todo.ID, // IDカラムをtodoのIDフィールドにスキャン
&todo.Content, // contentカラムをtodoのContentフィールドにスキャン
&todo.UserID, // user_idカラムをtodoのUserIDフィールドにスキャン
&todo.CreatedAt, // created_atカラムをtodoのCreatedAtフィールドにスキャン
)
if err != nil {
// エラーが発生した場合はログに記録して、エラーを返します。
log.Fatalln(err)
return nil, err
}
// スキャンしたTodoをtodosスライスに追加します。
todos = append(todos, todo)
}
// Todoのリストとエラーを返します。
return todos, nil
}
このコードでは、GetTodosByUser関数は指定されたユーザーID(u.ID)に関連するTodoリストをデータベースから取得します。SQLクエリを実行する際には、ユーザーIDがプレースホルダーとして使われ、その後でu.IDの実際の値に置き換えられます。
結果セットからTodoを取得する際には、rows.Next関数を使って次の行があるか確認し、rows.Scan関数を使用して各カラムの値をTodoのフィールドにスキャンしています。エラーが発生した場合には、エラーをログに記録して、そのまま返します。
注意すべき点として、このコードではrows.Close()を必ず実行しています。rowsは結果セットを表すオブジェクトであり、処理が終了した後には必ずクローズする必要があります。これをdeferを使って行っています。
ここでいう「スキャン(Scan)」は、データベースの結果セットから取得した行の各カラムの値を、Go言語の変数に割り当てる作業を指します。結果セットから取得した1つの行のデータを、対応するGoの変数にコピーすることを「スキャン」と呼びます。
データベースの結果セットは、複数の行と列から構成されるテーブルのようなデータの集まりです。この結果セットを1行ずつ順番に取り出し、各行の値をGoの変数に割り当てることで、データを取り出しています。
具体的にこのコードでは、rows.Scanメソッドを使って結果セットの現在の行の各カラムの値を、新しく作成したTodo構造体のフィールドに順番にコピーしています。例えば、&todo.IDはTodo構造体のIDフィールドへ、&todo.ContentはContentフィールドへ、それぞれ値をコピーしています。
このようにして、データベースから取得したTodoの情報をGoのTodo構造体に取り込んでいます。そして、todosスライスにそれぞれのTodo構造体を追加して、最終的に指定されたユーザーに関連するTodoのリストを作成しています。