goon チートシート

# はじめに

* Google Cloud Datastore に入れたデータを自動でキャッシュしてくれる [goon](https://github.com/mjibson/goon) というライブラリが便利
* 素の Datastore からの移行はそんなに大変ではなかったがすぐ忘れそうなので自分用にチートシートを作っておく
* 簡単な CRUD と ancestor key を使った親子関係の扱いについて記載している

# チートシート

## 単純な CRUD

### 比較用に Datastore の場合

```go

// 保存するデータの型
type MyStruct struct {
	ID int64 `datastore:"-"`
	Name string
}

// Datastore の kind
const MyStructKind string = "MyStruct"

// Datastore を操作するレポジトリ型
type MyStructRepository struct {
	ctx  context.Context
}

// レポジトリの作成
func NewMyStructRepository(ctx context.Context) *MyStructRepository {
	return &MyStructRepository{ctx: ctx, kind: MyStructKind}
}

// 1件取得
func (r *MyStructRepository) Find(id int64) (*MyStruct, error) {
	s := MyStruct{}
	e := datastore.Get(r.ctx, r.NewKey(id), &s)
	return &s, e
}

// 全件取得
func (r *CharacterTypeDatastoreRepository) FindAll() ([]MyStruct, error) {
	list := []MyStruct{}
	_, err := datastore.NewQuery(r.kind).GetAll(r.ctx, &list)
	return list, err
}

// 作成
func (r *MyStructRepository) Create(s *MyStruct) error {
	key := datastore.NewIncompleteKey(r.ctx, r.kind, nil)
	newKey, e := datastore.Put(r.ctx, key, s)
	if e != nil {
		return e
	}
	s.ID = newKey.IntID()
	return nil
}

// 更新
func (r *MyStructRepository) Update(s *MyStruct) error {
	_, e := datastore.Put(r.ctx, r.NewKey(s.ID), s)
	return e
}

// 削除
func (r *MyStructRepository) Delete(s *MyStruct) error {
	return datastore.Delete(r.ctx, r.NewKey(s.ID))
}

// Datastore のキーの作成
func (r *MyStructRepository) NewKey(id int64) *datastore.Key {
	return datastore.NewKey(r.ctx, r.kind, "", id, nil)
}

```


### goon の場合

```go

// 保存するデータの型
type MyStruct struct {
	ID int64 `datastore:"-" goon:"id"`
	Name string
}

// Datastore の kind
// goon ではデフォルトで reflect.Type.Name() が kind になる
// kind 名用のフィールドを作ってタグで指定すればデフォルトの kind 以外も使える
const MyStructKind string = "MyStruct"

// Datastore を操作するレポジトリ型
type MyStructDatastoreRepository struct {
	ctx  context.Context
}

// レポジトリの作成
func NewMyStructDatastoreRepository(ctx context.Context) *MyStructDatastoreRepository {
	return &MyStructDatastoreRepository{ctx: ctx}
}

// 1件検索
func (r *MyStructDatastoreRepository) Find(id int64) (*MyStruct, error) {
	g := goon.FromContext(r.ctx)
	s := &MyStruct{ID: id}
	e := g.Get(s)
	return s, e
}

// 全件検索
func (r *MyStructDatastoreRepository) FindAll() ([]MyStruct, error) {
	g := goon.FromContext(r.ctx)
	list := []MyStruct{}
	if _, err := g.GetAll(datastore.NewQuery(MyStructKind), &list); err != nil {
		return nil, err
	}
	return list, nil
}

// 作成
func (r *MyStructDatastoreRepository) Create(s *MyStruct) error {
	g := goon.FromContext(r.ctx)
	_, e := g.Put(s)
	return e
}

// 更新
func (r *MyStructDatastoreRepository) Update(s *MyStruct) error {
	g := goon.FromContext(r.ctx)
	_, e := g.Put(s)
	return e
}

// 削除
func (r *MyStructDatastoreRepository) Delete(s *MyStruct) error {
	g := goon.FromContext(r.ctx)
	key := datastore.NewKey(r.ctx, MyStructKind, "", s.ID, nil)
	return g.Delete(key)
}

```

## 親（Ancestor）を持つデータの登録と取得


```go

// 保存するデータの親の型
type ParentStruct struct {
	ID int64 `datastore:"-" goon:"id"`
}

// 保存するデータの型
type MyStruct struct {
	ID int64 `datastore:"-" goon:"id"`
	ParentKey *datastore.Key `datastore:"-" goon:"parent"` // Datastore 操作時に親の key を入れる
	ParentID int64 // 親の ID
}

const (
	ParentStructKind string = "ParentStruct"
	MyStructKind string = "MyStruct"
)

type MyStructDatastoreRepository struct {
	ctx context.Context
}

func NewMyStructDatastoreRepository(ctx context.Context) *MyStructDatastoreRepository {
	return &MyStructDatastoreRepository{ctx: ctx}
}

// Ancestor の ID で一覧取得
func (r *MyStructDatastoreRepository) FindAllByParentID(id int64) ([]MyStruct, error) {
	g := goon.FromContext(r.ctx)
	list := []MyStruct{}
	_, err := g.GetAll(datastore.NewQuery(MyStructKind).Ancestor(r.NewAncestorKey(id)), &list)
	return list, err
}

// 登録
func (r *MyStructDatastoreRepository) Create(d MyStruct) error {
	g := goon.FromContext(r.ctx)
	d.ParentKey = r.NewAncestorKey(d.ParentID)
	_, e := g.Put(&d)
	return e
}

// Ancestor key の作成
func (r *MyStructDatastoreRepository) NewAncestorKey(id int64) *datastore.Key {
	return datastore.NewKey(r.ctx, ParentStructKind, "", id, nil)
}

```