func (db DatastoreBacked) domainsForQuery(query *datastore.Query) (domains []string, err error) {
	c, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	client, datastoreErr := db.backend.NewClient(c, db.projectID)
	if datastoreErr != nil {
		return domains, datastoreErr
	}
	keys, err := client.GetAll(c, query.KeysOnly(), nil)
	if err != nil {
		return domains, err
	}
	for _, key := range keys {
		domain := key.Name
		domains = append(domains, domain)
	}
	return domains, nil
}
domainsForQuery returns the domains that match the given datastore query.
package database
import (
	"time"
	"golang.org/x/net/context"
	"cloud.google.com/go/datastore"
	"github.com/chromium/hstspreload.org/database/gcd"
)
const (
	localProjectID = "hstspreload-local"
	prodProjectID  = "hstspreload"
	batchSize = 450
	timeout   = 45 * time.Second
	domainStateKind = "DomainState"
)
type Database interface {
	PutStates([]DomainState, func(string, ...interface{})) error
	PutState(DomainState) error
	StateForDomain(string) (DomainState, error)
	AllDomainStates() ([]DomainState, error)
	StatesWithStatus(PreloadStatus) ([]DomainState, error)
}
type DatastoreBacked struct {
	backend   gcd.Backend
	projectID string
}
func TempLocalDatabase() (db DatastoreBacked, shutdown func() error, err error) {
	backend, shutdown, err := gcd.NewLocalBackend()
	return DatastoreBacked{backend, localProjectID}, shutdown, err
}
func ProdDatabase() (db DatastoreBacked) {
	return DatastoreBacked{gcd.NewProdBackend(), prodProjectID}
}
var blackholeLogf = func(format string, args ...interface{}) {}
func (db DatastoreBacked) PutStates(updates []DomainState, logf func(format string, args ...interface{})) error {
	if len(updates) == 0 {
		logf("No updates.\n")
		return nil
	}
	c, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	client, datastoreErr := db.backend.NewClient(c, db.projectID)
	if datastoreErr != nil {
		return datastoreErr
	}
	putMulti := func(keys []*datastore.Key, values []DomainState) error {
		logf("Updating %d entries...", len(keys))
		if _, err := client.PutMulti(c, keys, values); err != nil {
			logf(" failed.\n")
			return err
		}
		logf(" done.\n")
		return nil
	}
	var keys []*datastore.Key
	var values []DomainState
	for _, state := range updates {
		key := datastore.NameKey(domainStateKind, string(state.Name), nil)
		keys = append(keys, key)
		values = append(values, state)
		if len(keys) >= batchSize {
			if err := putMulti(keys, values); err != nil {
				return err
			}
			keys = keys[:0]
			values = values[:0]
		}
	}
	return putMulti(keys, values)
}
func (db DatastoreBacked) PutState(update DomainState) error {
	return db.PutStates([]DomainState{update}, blackholeLogf)
}
func (db DatastoreBacked) statesForQuery(query *datastore.Query) (states []DomainState, err error) {
	c, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	client, datastoreErr := db.backend.NewClient(c, db.projectID)
	if datastoreErr != nil {
		return states, datastoreErr
	}
	keys, err := client.GetAll(c, query, &states)
	if err != nil {
		return states, err
	}
	for i, key := range keys {
		state := states[i]
		state.Name = key.Name
		states[i] = state
	}
	return states, nil
}