func (r KeyRange) keySetProto() (*sppb.KeySet, error) {
	rp, err := r.proto()
	if err != nil {
		return nil, err
	}
	return &sppb.KeySet{Ranges: []*sppb.KeyRange{rp}}, nil
}
keySetProto lets a KeyRange act as a KeySet.
package spanner
import (
	"bytes"
	"fmt"
	"time"
	"google.golang.org/grpc/codes"
	"cloud.google.com/go/civil"
	proto3 "github.com/golang/protobuf/ptypes/struct"
	sppb "google.golang.org/genproto/googleapis/spanner/v1"
)
type Key []interface{}
func errInvdKeyPartType(part interface{}) error {
	return spannerErrorf(codes.InvalidArgument, "key part has unsupported type %T", part)
}
func keyPartValue(part interface{}) (pb *proto3.Value, err error) {
	switch v := part.(type) {
	case int:
		pb, _, err = encodeValue(int64(v))
	case int8:
		pb, _, err = encodeValue(int64(v))
	case int16:
		pb, _, err = encodeValue(int64(v))
	case int32:
		pb, _, err = encodeValue(int64(v))
	case uint8:
		pb, _, err = encodeValue(int64(v))
	case uint16:
		pb, _, err = encodeValue(int64(v))
	case uint32:
		pb, _, err = encodeValue(int64(v))
	case float32:
		pb, _, err = encodeValue(float64(v))
	case int64, float64, NullInt64, NullFloat64, bool, NullBool, []byte, string, NullString, time.Time, civil.Date, NullTime, NullDate:
		pb, _, err = encodeValue(v)
	default:
		return nil, errInvdKeyPartType(v)
	}
	return pb, err
}
func (key Key) proto() (*proto3.ListValue, error) {
	lv := &proto3.ListValue{}
	lv.Values = make([]*proto3.Value, 0, len(key))
	for _, part := range key {
		v, err := keyPartValue(part)
		if err != nil {
			return nil, err
		}
		lv.Values = append(lv.Values, v)
	}
	return lv, nil
}
func (key Key) keySetProto() (*sppb.KeySet, error) {
	kp, err := key.proto()
	if err != nil {
		return nil, err
	}
	return &sppb.KeySet{Keys: []*proto3.ListValue{kp}}, nil
}
func (key Key) String() string {
	b := &bytes.Buffer{}
	fmt.Fprint(b, "(")
	for i, part := range []interface{}(key) {
		if i != 0 {
			fmt.Fprint(b, ",")
		}
		switch v := part.(type) {
		case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, float32, float64, bool:
			fmt.Fprintf(b, "%v", v)
		case string:
			fmt.Fprintf(b, "%q", v)
		case []byte:
			if v != nil {
				fmt.Fprintf(b, "%q", v)
			} else {
				fmt.Fprint(b, "<null>")
			}
		case NullInt64, NullFloat64, NullBool, NullString, NullTime, NullDate:
			fmt.Fprintf(b, "%s", v)
		case civil.Date:
			fmt.Fprintf(b, "%q", v)
		case time.Time:
			fmt.Fprintf(b, "%q", v.Format(time.RFC3339Nano))
		default:
			fmt.Fprintf(b, "%v", v)
		}
	}
	fmt.Fprint(b, ")")
	return b.String()
}
func (key Key) AsPrefix() KeyRange {
	return KeyRange{
		Start: key,
		End:   key,
		Kind:  ClosedClosed,
	}
}
type KeyRangeKind int
const (
	ClosedOpen KeyRangeKind = iota
	ClosedClosed
	OpenClosed
	OpenOpen
)
type KeyRange struct {
	Start, End Key
	Kind KeyRangeKind
}
func (r KeyRange) String() string {
	var left, right string
	switch r.Kind {
	case ClosedClosed:
		left, right = "[", "]"
	case ClosedOpen:
		left, right = "[", ")"
	case OpenClosed:
		left, right = "(", "]"
	case OpenOpen:
		left, right = "(", ")"
	default:
		left, right = "?", "?"
	}
	return fmt.Sprintf("%s%s,%s%s", left, r.Start, r.End, right)
}
func (r KeyRange) proto() (*sppb.KeyRange, error) {
	var err error
	var start, end *proto3.ListValue
	pb := &sppb.KeyRange{}
	if start, err = r.Start.proto(); err != nil {
		return nil, err
	}
	if end, err = r.End.proto(); err != nil {
		return nil, err
	}
	if r.Kind == ClosedClosed || r.Kind == ClosedOpen {
		pb.StartKeyType = &sppb.KeyRange_StartClosed{StartClosed: start}
	} else {
		pb.StartKeyType = &sppb.KeyRange_StartOpen{StartOpen: start}
	}
	if r.Kind == ClosedClosed || r.Kind == OpenClosed {
		pb.EndKeyType = &sppb.KeyRange_EndClosed{EndClosed: end}
	} else {
		pb.EndKeyType = &sppb.KeyRange_EndOpen{EndOpen: end}
	}
	return pb, nil
}