GoでgRPCサーバーを立ててみる３（repository.goの実装）

お疲れ様です。

今日は「repository.goの実装」について部分いたします。

articleサービスにおいてDBとやり取りをするrepository.goの実装を行なっていきます。

今回は簡易的なデータベースとしてsqlite3を使用するので、以下のパッケージをインストールしておきましょう。

```terminal
go get github.com/mattn/go-sqlite3
```

インストールできたら、忘れずにimportしておきます。

```article/repository/repository.go
package repository

import (
	_ "github.com/mattn/go-sqlite3"
)

```

articleサービスでは、以下のようなarticlesテーブルにデータを格納していきます。

|    id    |   author	      |     title                 |     content      |
|:----------:|:---------------:|:------------------------:|:------------------------:|
| INTEGER   | STRING        | STRING      |STRING     |

このテーブルとデータをやり取りする５つの処理を実装していきます。

```article/repository/repository.go
type Repository interface {
　　InsertArticle(ctx context.Context, input *pb.ArticleInput) (int64, error)
　　SelectArticleByID(ctx context.Context, id int64) (*pb.Article, error)
　　UpdateArticle(ctx context.Context, id int64, input *pb.ArticleInput) error
　　DeleteArticle(ctx context.Context, id int64) error
　　SelectAllArticles() (*sql.Rows, error)
}

type sqliteRepo struct {
	db *sql.DB
}

func NewsqliteRepo() (Repository, error) {
	db, err := sql.Open("sqlite3", "./article/article.sql")
	if err != nil {
		return nil, err
	}

	// articlesテーブルを作成
	cmd := `CREATE TABLE IF NOT EXISTS articles(
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		author STRING,
		title STRING,
		content STRING)`

	_, err = db.Exec(cmd)
	if err != nil {
		return nil, err
	}
	return &sqliteRepo{db}, nil
}

func (r *sqliteRepo) InsertArticle(ctx context.Context, input *pb.ArticleInput) (int64, error) {
	// DBに記事をINERT
}

func (r *sqliteRepo) SelectArticleByID(ctx context.Context, id int64) (*pb.Article, error) {
	// DBからIDに基づいて記事をSELECT
}

func (r *sqliteRepo) UpdateArticle(ctx context.Context, id int64, input *pb.ArticleInput) error {
	//　DB内の記事をUPDATE
}

func (r *sqliteRepo) DeleteArticle(ctx context.Context, id int64) error {
	// DB内の記事をDELETE
}

func (r *sqliteRepo) SelectAllArticles() (*sql.Rows, error) {
	// articlesテーブルの記事を全取得
}
```

## InsertArticle

```article/repository/repository.go
func (r *sqliteRepo) InsertArticle(ctx context.Context, input *pb.ArticleInput) (int64, error) {
	// Inputの内容(Author, Title, Content)をarticlesテーブルにINSERT
	cmd := "INSERT INTO articles(author, title, content) VALUES (?, ?, ?)"
	result, err := r.db.Exec(cmd, input.Author, input.Title, input.Content)
	if err != nil {
		return 0, err
	}
	
	// INSERTした記事のIDを取得
	id, err := result.LastInsertId()
	if err != nil {
		return 0, err
	}
	
	// INSERTした記事のIDを返す
	return id, nil
}
```

## SelectArticleByID

```article/repository/repository.go
func (r *sqliteRepo) SelectArticleByID(ctx context.Context, id int64) (*pb.Article, error) {
	// 該当IDの記事をSELECT
	cmd := "SELECT * FROM articles WHERE id = ?"
	row := r.db.QueryRow(cmd, id)
	var a pb.Article

	// SELECTした記事の内容を読み取る
	err := row.Scan(&a.Id, &a.Author, &a.Title, &a.Content)
	if err != nil {
		return nil, err
	}

	// SELECTした記事を返す
	return &pb.Article{
		Id:      a.Id,
		Author:  a.Author,
		Title:   a.Title,
		Content: a.Content,
	}, nil
}
```

## UpdateArticle

```article/repository/repository.go
func (r *sqliteRepo) UpdateArticle(ctx context.Context, id int64, input *pb.ArticleInput) (*pb.Article, error) {
	// 該当IDのAuthor, Title, ContentをUPDATE
	cmd := "UPDATE articles SET author = ?, title = ?, content = ? WHERE id = ?"
	_, err := r.db.Exec(cmd, input.Author, input.Title, input.Content, id)
	if err != nil {
		return err
	}

	// errorがなければ返り値なし
	return nil
}
```

## DeleteArticle

```article/repository/repository.go
func (r *sqliteRepo) DeleteArticle(ctx context.Context, id int64) error {
	// 該当IDの記事をDELETE
	cmd := "DELETE FROM articles WHERE id = ?"
	_, err := r.db.Exec(cmd, id)
	if err != nil {
		return err
	}

	// errorがなければ返り値なし
	return nil
}
```

## SelectAllArticles

```article/repository/repository.go
func (r *sqliteRepo) SelectAllArticles() (*sql.Rows, error) {
	// articlesテーブルの記事を全取得
	cmd := "SELECT * FROM articles"
	rows, err := r.db.Query(cmd)
	if err != nil {
		return nil, err
	}

	// 全取得した記事を*sql.Rowsの形で返す
	return rows, nil
}
```

これで、repositoryの実装ができました！

今日は以上です。

次は「service.goの実装」についてです。

ありがとうございました。

よろしくお願いいたします。