blob: 35f3e6cea399591752fbe407c5b611a5f7de7397 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package memory
import (
"bytes"
"fmt"
"strings"
"time"
ds "github.com/luci/gae/service/datastore"
"github.com/luci/gae/service/datastore/serialize"
"github.com/luci/luci-go/common/cmpbin"
)
func init() {
serializationDeterministic = true
serialize.WritePropertyMapDeterministic = true
}
var nextMarker = "NEXT MARKER"
var Next = &nextMarker
// Use like:
// pmap(
// "prop", "val", 0, 100, Next,
// "other", "val", 0, 100, Next,
// )
//
func pmap(stuff ...interface{}) ds.PropertyMap {
ret := ds.PropertyMap{}
nom := func() interface{} {
if len(stuff) > 0 {
ret := stuff[0]
stuff = stuff[1:]
return ret
}
return nil
}
for len(stuff) > 0 {
pname := nom().(string)
if pname[0] == '$' || (strings.HasPrefix(pname, "__") && strings.HasSuffix(pname, "__")) {
for len(stuff) > 0 && stuff[0] != Next {
ret[pname] = append(ret[pname], propNI(nom()))
}
} else {
for len(stuff) > 0 && stuff[0] != Next {
ret[pname] = append(ret[pname], prop(nom()))
}
}
nom()
}
return ret
}
func nq(kindMaybe ...string) *ds.Query {
kind := "Foo"
if len(kindMaybe) == 1 {
kind = kindMaybe[0]
}
return ds.NewQuery(kind)
}
func indx(kind string, orders ...string) *ds.IndexDefinition {
ancestor := false
if kind[len(kind)-1] == '!' {
ancestor = true
kind = kind[:len(kind)-1]
}
ret := &ds.IndexDefinition{Kind: kind, Ancestor: ancestor}
for _, o := range orders {
col, err := ds.ParseIndexColumn(o)
if err != nil {
panic(err)
}
ret.SortBy = append(ret.SortBy, col)
}
return ret
}
var (
prop = ds.MkProperty
propNI = ds.MkPropertyNI
)
func key(elems ...interface{}) *ds.Key {
return ds.MakeKey("dev~app", "ns", elems...)
}
func die(err error) {
if err != nil {
panic(err)
}
}
// cat is a convenience method for concatenating anything with an underlying
// byte representation into a single []byte.
func cat(bytethings ...interface{}) []byte {
err := error(nil)
buf := &bytes.Buffer{}
for _, thing := range bytethings {
switch x := thing.(type) {
case int64:
_, err = cmpbin.WriteInt(buf, x)
case int:
_, err = cmpbin.WriteInt(buf, int64(x))
case uint64:
_, err = cmpbin.WriteUint(buf, x)
case uint:
_, err = cmpbin.WriteUint(buf, uint64(x))
case float64:
_, err = cmpbin.WriteFloat64(buf, x)
case byte:
err = buf.WriteByte(x)
case ds.PropertyType:
err = buf.WriteByte(byte(x))
case string:
_, err = cmpbin.WriteString(buf, x)
case []byte:
_, err = buf.Write(x)
case time.Time:
err = serialize.WriteTime(buf, x)
case *ds.Key:
err = serialize.WriteKey(buf, serialize.WithoutContext, x)
case *ds.IndexDefinition:
err = serialize.WriteIndexDefinition(buf, *x)
case ds.Property:
err = serialize.WriteProperty(buf, serialize.WithoutContext, x)
default:
panic(fmt.Errorf("I don't know how to deal with %T: %#v", thing, thing))
}
die(err)
}
ret := buf.Bytes()
if ret == nil {
ret = []byte{}
}
return ret
}
func icat(bytethings ...interface{}) []byte {
ret := cat(bytethings...)
for i := range ret {
ret[i] ^= 0xFF
}
return ret
}
func sat(bytethings ...interface{}) string {
return string(cat(bytethings...))
}