LoginSignup
0
1

More than 3 years have passed since last update.

Go+Google Cloud Datastore

Posted at

Go の勉強がてら Google Cloud Datastore へ読み書きする簡単なプログラムを作成したため共有する。
Go は Java と比べてリフレクション周りが癖があって扱いにくかった。
あと、オーバーロードがないのが辛い。

ds.go
package ds

import (
    "context"
    "fmt"
    "reflect"

    "cloud.google.com/go/datastore"
)

type Entity interface {
    EntityKey() *datastore.Key
    SetEntityKey(key *datastore.Key)
    EntityKind() string
}

func NewClient(ctx context.Context) (*datastore.Client, error) {
    return NewClientWithProjectID(ctx, "your project id here.") // FIXME
}

func NewClientWithProjectID(ctx context.Context, projectID string) (*datastore.Client, error) {
    client, err := datastore.NewClient(ctx, projectID)

    return client, err
}

func GetEntity(ctx context.Context, entity Entity) error {
    client, err := NewClient(ctx)
    if err != nil {
        return err
    }

    defer client.Close()

    return GetEntityWithClient(ctx, client, entity)
}

func GetEntityWithClient(ctx context.Context, client *datastore.Client, entity Entity) error {
    entity.EntityKey().Kind = entity.EntityKind()

    if err := client.Get(ctx, entity.EntityKey(), entity); err != nil {
        return err
    }

    return nil
}

func GetEntities(ctx context.Context, q *datastore.Query, dst interface{}) error {
    client, err := NewClient(ctx)
    if err != nil {
        return err
    }

    defer client.Close()

    return GetEntitiesWithClient(ctx, client, q, dst)
}

func GetEntitiesWithClient(ctx context.Context, client *datastore.Client, q *datastore.Query, dst interface{}) error {
    keys, err := client.GetAll(ctx, q, dst)
    if err != nil {
        return err
    }

    slice := reflect.ValueOf(dst).Elem()

    if len(keys) != slice.Len() {
        return fmt.Errorf("failed to get entities: len(keys)=%d, slice.Len()=%d", len(keys), slice.Len())
    }

    for i, key := range keys {
        entity := slice.Index(i).Addr().Interface().(Entity)
        entity.SetEntityKey(key)
    }

    return nil
}

func PutEntity(ctx context.Context, entity Entity) error {
    client, err := NewClient(ctx)
    if err != nil {
        return err
    }

    defer client.Close()

    return PutEntityWithClient(ctx, client, entity)
}

func PutEntityWithClient(ctx context.Context, client *datastore.Client, entity Entity) error {
    entity.EntityKey().Kind = entity.EntityKind()

    key, err := client.Put(ctx, entity.EntityKey(), entity)
    if err != nil {
        return err
    }

    entity.SetEntityKey(key)

    return nil
}

func PutEntities(ctx context.Context, entities interface{}) error {
    client, err := NewClient(ctx)
    if err != nil {
        return err
    }

    defer client.Close()

    return PutEntitiesWithClient(ctx, client, entities)
}

func PutEntitiesWithClient(ctx context.Context, client *datastore.Client, entities interface{}) error {
    slice := reflect.ValueOf(entities)
    keys := make([]*datastore.Key, 0, slice.Len())
    for i := 0; i < slice.Len(); i++ {
        entity := slice.Index(i).Addr().Interface().(Entity)

        entity.EntityKey().Kind = entity.EntityKind()
        keys = append(keys, entity.EntityKey())
    }

    keys, err := client.PutMulti(ctx, keys, entities)
    if err != nil {
        return err
    }
    if len(keys) != slice.Len() {
        return fmt.Errorf("failed to put entities: len(keys)=%d, slice.Len()=%d", len(keys), slice.Len())
    }

    for i, key := range keys {
        entity := slice.Index(i).Addr().Interface().(Entity)

        entity.SetEntityKey(key)
    }

    return nil
}

func DeleteEntity(ctx context.Context, key *datastore.Key) error {
    client, err := NewClient(ctx)
    if err != nil {
        return err
    }

    defer client.Close()

    return DeleteEntityWithClient(ctx, client, key)
}

func DeleteEntityWithClient(ctx context.Context, client *datastore.Client, key *datastore.Key) error {
    if err := client.Delete(ctx, key); err != nil {
        return err
    }

    return nil
}

func DeleteEntities(ctx context.Context, keys []*datastore.Key) error {
    client, err := NewClient(ctx)
    if err != nil {
        return err
    }

    defer client.Close()

    return DeleteEntitiesWithClient(ctx, client, keys)
}

func DeleteEntitiesWithClient(ctx context.Context, client *datastore.Client, keys []*datastore.Key) error {
    if err := client.DeleteMulti(ctx, keys); err != nil {
        return err
    }

    return nil
}
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1