| Index: service/datastore/multiarg.go
|
| diff --git a/service/datastore/multiarg.go b/service/datastore/multiarg.go
|
| index ab335c9ef634ba1ab4fa5817ecf3b649231a229f..9250acec811a89efd4e626a7f4aeef5b8eb9e278 100644
|
| --- a/service/datastore/multiarg.go
|
| +++ b/service/datastore/multiarg.go
|
| @@ -20,155 +20,165 @@ type multiArgType struct {
|
| newElem func() reflect.Value
|
| }
|
|
|
| -func (mat *multiArgType) GetKeysPMs(aid, ns string, slice reflect.Value, meta bool) ([]*Key, []PropertyMap, error) {
|
| - retKey := make([]*Key, slice.Len())
|
| - retPM := make([]PropertyMap, slice.Len())
|
| - getter := mat.getPM
|
| - if meta {
|
| - getter = func(slot reflect.Value) (PropertyMap, error) {
|
| - return mat.getMetaPM(slot), nil
|
| - }
|
| - }
|
| - lme := errors.NewLazyMultiError(len(retKey))
|
| - for i := range retKey {
|
| - key, err := mat.getKey(aid, ns, slice.Index(i))
|
| - if !lme.Assign(i, err) {
|
| - retKey[i] = key
|
| - pm, err := getter(slice.Index(i))
|
| - if !lme.Assign(i, err) {
|
| - retPM[i] = pm
|
| - }
|
| - }
|
| - }
|
| - return retKey, retPM, lme.Get()
|
| -}
|
| -
|
| -// parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some
|
| +// parseArg checks that et is of type S, *S, I, P or *P, for some
|
| // struct type S, for some interface type I, or some non-interface non-pointer
|
| // type P such that P or *P implements PropertyLoadSaver.
|
| -func parseMultiArg(e reflect.Type) multiArgType {
|
| - if e.Kind() != reflect.Slice {
|
| - panic(fmt.Errorf("invalid argument type: expected slice, got %s", e))
|
| +//
|
| +// If et is a chan type that implements PropertyLoadSaver, new elements will be
|
| +// allocated with a buffer of 0.
|
| +//
|
| +// If keysOnly is true, a read-only key extraction multiArgType will be
|
| +// returned if et is a *Key.
|
| +func parseArg(et reflect.Type, keysOnly bool) *multiArgType {
|
| + if keysOnly && et == typeOfKey {
|
| + return multiArgTypeKeyExtraction()
|
| }
|
| - return parseArg(e.Elem(), true)
|
| -}
|
|
|
| -// parseArg checks that et is of type S, *S, I, P or *P, for some
|
| -// struct type S, for some interface type I, or some non-interface non-pointer
|
| -// type P such that P or *P implements PropertyLoadSaver.
|
| -func parseArg(et reflect.Type, multi bool) multiArgType {
|
| - if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
|
| + if et.Kind() == reflect.Interface {
|
| + return multiArgTypeInterface()
|
| + }
|
| +
|
| + // If a map/chan type implements an interface, its pointer is also considered
|
| + // to implement that interface.
|
| + //
|
| + // In this case, we have special pointer-to-map/chan logic in multiArgTypePLS.
|
| + if et.Implements(typeOfPropertyLoadSaver) {
|
| return multiArgTypePLS(et)
|
| }
|
| - if et.Implements(typeOfPropertyLoadSaver) && et.Kind() != reflect.Interface {
|
| - return multiArgTypePLSPtr(et.Elem())
|
| + if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
|
| + return multiArgTypePLSPtr(et)
|
| }
|
| +
|
| switch et.Kind() {
|
| - case reflect.Struct:
|
| - return multiArgTypeStruct(et)
|
| - case reflect.Interface:
|
| - return multiArgTypeInterface()
|
| case reflect.Ptr:
|
| - et = et.Elem()
|
| - if et.Kind() == reflect.Struct {
|
| + if et.Elem().Kind() == reflect.Struct {
|
| return multiArgTypeStructPtr(et)
|
| }
|
| +
|
| + case reflect.Struct:
|
| + return multiArgTypeStruct(et)
|
| }
|
| - if multi {
|
| - panic(fmt.Errorf("invalid argument type: []%s", et))
|
| +
|
| + return nil
|
| +}
|
| +
|
| +// parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some
|
| +// struct type S, for some interface type I, or some non-interface non-pointer
|
| +// type P such that P or *P implements PropertyLoadSaver.
|
| +func mustParseMultiArg(et reflect.Type) *multiArgType {
|
| + if et.Kind() != reflect.Slice {
|
| + panic(fmt.Errorf("invalid argument type: expected slice, got %s", et))
|
| }
|
| - panic(fmt.Errorf("invalid argument type: %s", et))
|
| + return mustParseArg(et.Elem())
|
| }
|
|
|
| -type newKeyFunc func(kind, sid string, iid int64, par Key) Key
|
| +func mustParseArg(et reflect.Type) *multiArgType {
|
| + if mat := parseArg(et, false); mat != nil {
|
| + return mat
|
| + }
|
| + panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-struct", et))
|
| +}
|
|
|
| -// multiArgTypePLS == []P
|
| -// *P implements PropertyLoadSaver
|
| -func multiArgTypePLS(et reflect.Type) multiArgType {
|
| +// multiArgTypePLS handles the case where et implements PropertyLoadSaver.
|
| +//
|
| +// This handles the special case of pointer-to-map and pointer-to-chan (
|
| +// see parseArg).
|
| +func multiArgTypePLS(et reflect.Type) *multiArgType {
|
| ret := multiArgType{
|
| getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
|
| - return newKeyObjErr(aid, ns, slot.Addr().Interface())
|
| + return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
|
| },
|
| getPM: func(slot reflect.Value) (PropertyMap, error) {
|
| - return slot.Addr().Interface().(PropertyLoadSaver).Save(true)
|
| + return slot.Interface().(PropertyLoadSaver).Save(true)
|
| },
|
| getMetaPM: func(slot reflect.Value) PropertyMap {
|
| - return getMGS(slot.Addr().Interface()).GetAllMeta()
|
| + return getMGS(slot.Interface()).GetAllMeta()
|
| },
|
| setPM: func(slot reflect.Value, pm PropertyMap) error {
|
| - return slot.Addr().Interface().(PropertyLoadSaver).Load(pm)
|
| + return slot.Interface().(PropertyLoadSaver).Load(pm)
|
| },
|
| setKey: func(slot reflect.Value, k *Key) {
|
| - PopulateKey(slot.Addr().Interface(), k)
|
| + PopulateKey(slot.Interface(), k)
|
| },
|
| }
|
| - if et.Kind() == reflect.Map {
|
| + switch et.Kind() {
|
| + case reflect.Map:
|
| ret.newElem = func() reflect.Value {
|
| - // Create a *map so that way slot.Addr() works above when this is
|
| - // called from Run(). Otherwise the map is 'unaddressable' according
|
| - // to reflect. ¯\_(ツ)_/¯
|
| - ptr := reflect.New(et)
|
| - ptr.Elem().Set(reflect.MakeMap(et))
|
| - return ptr.Elem()
|
| + return reflect.MakeMap(et)
|
| }
|
| - } else {
|
| +
|
| + case reflect.Chan:
|
| ret.newElem = func() reflect.Value {
|
| - return reflect.New(et).Elem()
|
| + return reflect.MakeChan(et, 0)
|
| + }
|
| +
|
| + case reflect.Ptr:
|
| + elem := et.Elem()
|
| + switch elem.Kind() {
|
| + case reflect.Map:
|
| + ret.newElem = func() reflect.Value {
|
| + ptr := reflect.New(elem)
|
| + ptr.Elem().Set(reflect.MakeMap(elem))
|
| + return ptr
|
| + }
|
| +
|
| + case reflect.Chan:
|
| + ret.newElem = func() reflect.Value {
|
| + ptr := reflect.New(elem)
|
| + ptr.Elem().Set(reflect.MakeChan(elem, 0))
|
| + return ptr
|
| + }
|
| + }
|
| + }
|
| +
|
| + if ret.newElem == nil {
|
| + ret.newElem = func() reflect.Value {
|
| + return reflect.New(et.Elem())
|
| }
|
| }
|
| - return ret
|
| + return &ret
|
| }
|
|
|
| -// multiArgTypePLSPtr == []*P
|
| -// *P implements PropertyLoadSaver
|
| -func multiArgTypePLSPtr(et reflect.Type) multiArgType {
|
| - ret := multiArgType{
|
| +// multiArgTypePLSPtr handles the case where et doesn't implement
|
| +// PropertyLoadSaver, but a pointer to et does.
|
| +func multiArgTypePLSPtr(et reflect.Type) *multiArgType {
|
| + return &multiArgType{
|
| getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
|
| - return newKeyObjErr(aid, ns, slot.Interface())
|
| + return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interface()))
|
| },
|
| getPM: func(slot reflect.Value) (PropertyMap, error) {
|
| - return slot.Interface().(PropertyLoadSaver).Save(true)
|
| + return slot.Addr().Interface().(PropertyLoadSaver).Save(true)
|
| },
|
| getMetaPM: func(slot reflect.Value) PropertyMap {
|
| - return getMGS(slot.Interface()).GetAllMeta()
|
| + return getMGS(slot.Addr().Interface()).GetAllMeta()
|
| },
|
| setPM: func(slot reflect.Value, pm PropertyMap) error {
|
| - return slot.Interface().(PropertyLoadSaver).Load(pm)
|
| + return slot.Addr().Interface().(PropertyLoadSaver).Load(pm)
|
| },
|
| setKey: func(slot reflect.Value, k *Key) {
|
| - PopulateKey(slot.Interface(), k)
|
| + PopulateKey(slot.Addr().Interface(), k)
|
| + },
|
| + newElem: func() reflect.Value {
|
| + return reflect.New(et).Elem()
|
| },
|
| }
|
| - if et.Kind() == reflect.Map {
|
| - ret.newElem = func() reflect.Value {
|
| - ptr := reflect.New(et)
|
| - ptr.Elem().Set(reflect.MakeMap(et))
|
| - return ptr
|
| - }
|
| - } else {
|
| - ret.newElem = func() reflect.Value { return reflect.New(et) }
|
| - }
|
| - return ret
|
| }
|
|
|
| // multiArgTypeStruct == []S
|
| -func multiArgTypeStruct(et reflect.Type) multiArgType {
|
| +func multiArgTypeStruct(et reflect.Type) *multiArgType {
|
| cdc := getCodec(et)
|
| toPLS := func(slot reflect.Value) *structPLS {
|
| return &structPLS{slot, cdc}
|
| }
|
| - return multiArgType{
|
| + return &multiArgType{
|
| getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
|
| - return newKeyObjErr(aid, ns, toPLS(slot))
|
| + return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interface()))
|
| },
|
| getPM: func(slot reflect.Value) (PropertyMap, error) {
|
| return toPLS(slot).Save(true)
|
| },
|
| getMetaPM: func(slot reflect.Value) PropertyMap {
|
| - if slot.Type().Implements(typeOfMGS) {
|
| - return slot.Interface().(MetaGetterSetter).GetAllMeta()
|
| - }
|
| - return toPLS(slot).GetAllMeta()
|
| + return getMGS(slot.Addr().Interface()).GetAllMeta()
|
| },
|
| setPM: func(slot reflect.Value, pm PropertyMap) error {
|
| return toPLS(slot).Load(pm)
|
| @@ -183,23 +193,20 @@ func multiArgTypeStruct(et reflect.Type) multiArgType {
|
| }
|
|
|
| // multiArgTypeStructPtr == []*S
|
| -func multiArgTypeStructPtr(et reflect.Type) multiArgType {
|
| - cdc := getCodec(et)
|
| +func multiArgTypeStructPtr(et reflect.Type) *multiArgType {
|
| + cdc := getCodec(et.Elem())
|
| toPLS := func(slot reflect.Value) *structPLS {
|
| return &structPLS{slot.Elem(), cdc}
|
| }
|
| - return multiArgType{
|
| + return &multiArgType{
|
| getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
|
| - return newKeyObjErr(aid, ns, toPLS(slot))
|
| + return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
|
| },
|
| getPM: func(slot reflect.Value) (PropertyMap, error) {
|
| return toPLS(slot).Save(true)
|
| },
|
| getMetaPM: func(slot reflect.Value) PropertyMap {
|
| - if slot.Elem().Type().Implements(typeOfMGS) {
|
| - return getMGS(slot.Interface()).GetAllMeta()
|
| - }
|
| - return toPLS(slot).GetAllMeta()
|
| + return getMGS(slot.Interface()).GetAllMeta()
|
| },
|
| setPM: func(slot reflect.Value, pm PropertyMap) error {
|
| return toPLS(slot).Load(pm)
|
| @@ -208,16 +215,16 @@ func multiArgTypeStructPtr(et reflect.Type) multiArgType {
|
| PopulateKey(toPLS(slot), k)
|
| },
|
| newElem: func() reflect.Value {
|
| - return reflect.New(et)
|
| + return reflect.New(et.Elem())
|
| },
|
| }
|
| }
|
|
|
| // multiArgTypeInterface == []I
|
| -func multiArgTypeInterface() multiArgType {
|
| - return multiArgType{
|
| +func multiArgTypeInterface() *multiArgType {
|
| + return &multiArgType{
|
| getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
|
| - return newKeyObjErr(aid, ns, slot.Elem().Interface())
|
| + return newKeyObjErr(aid, ns, getMGS(slot.Elem().Interface()))
|
| },
|
| getPM: func(slot reflect.Value) (PropertyMap, error) {
|
| return mkPLS(slot.Elem().Interface()).Save(true)
|
| @@ -234,24 +241,34 @@ func multiArgTypeInterface() multiArgType {
|
| }
|
| }
|
|
|
| -func newKeyObjErr(aid, ns string, src interface{}) (*Key, error) {
|
| - pls := getMGS(src)
|
| - if key, _ := GetMetaDefault(pls, "key", nil).(*Key); key != nil {
|
| +// multiArgTypeKeyExtraction == *Key
|
| +//
|
| +// This ONLY implements getKey.
|
| +func multiArgTypeKeyExtraction() *multiArgType {
|
| + return &multiArgType{
|
| + getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
|
| + return slot.Interface().(*Key), nil
|
| + },
|
| + }
|
| +}
|
| +
|
| +func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) {
|
| + if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil {
|
| return key, nil
|
| }
|
|
|
| // get kind
|
| - kind := GetMetaDefault(pls, "kind", "").(string)
|
| + kind := GetMetaDefault(mgs, "kind", "").(string)
|
| if kind == "" {
|
| - return nil, fmt.Errorf("unable to extract $kind from %T", src)
|
| + return nil, errors.New("unable to extract $kind")
|
| }
|
|
|
| // get id - allow both to be default for default keys
|
| - sid := GetMetaDefault(pls, "id", "").(string)
|
| - iid := GetMetaDefault(pls, "id", 0).(int64)
|
| + sid := GetMetaDefault(mgs, "id", "").(string)
|
| + iid := GetMetaDefault(mgs, "id", 0).(int64)
|
|
|
| // get parent
|
| - par, _ := GetMetaDefault(pls, "parent", nil).(*Key)
|
| + par, _ := GetMetaDefault(mgs, "parent", nil).(*Key)
|
|
|
| return NewKey(aid, ns, kind, sid, iid, par), nil
|
| }
|
| @@ -262,3 +279,270 @@ func mkPLS(o interface{}) PropertyLoadSaver {
|
| }
|
| return GetPLS(o)
|
| }
|
| +
|
| +func isOKSingleType(t reflect.Type, keysOnly bool) error {
|
| + switch {
|
| + case t == nil:
|
| + return errors.New("no type information")
|
| + case t.Implements(typeOfPropertyLoadSaver):
|
| + return nil
|
| + case !keysOnly && t == typeOfKey:
|
| + return errors.New("not user datatype")
|
| + case t.Kind() != reflect.Ptr:
|
| + return errors.New("not a pointer")
|
| + case t.Elem().Kind() != reflect.Struct:
|
| + return errors.New("does not point to a struct")
|
| + default:
|
| + return nil
|
| + }
|
| +}
|
| +
|
| +type metaMultiArgElement struct {
|
| + arg reflect.Value
|
| + mat *multiArgType
|
| + size int // size is -1 if this element is not a slice.
|
| +}
|
| +
|
| +type metaMultiArg struct {
|
| + elems []metaMultiArgElement
|
| + keysOnly bool
|
| +
|
| + count int // total number of elements, flattening slices
|
| +}
|
| +
|
| +func makeMetaMultiArg(args []interface{}, keysOnly bool) (*metaMultiArg, error) {
|
| + mma := metaMultiArg{
|
| + elems: make([]metaMultiArgElement, len(args)),
|
| + keysOnly: keysOnly,
|
| + }
|
| +
|
| + lme := errors.NewLazyMultiError(len(args))
|
| + for i, arg := range args {
|
| + if arg == nil {
|
| + lme.Assign(i, errors.New("cannot use nil as single argument"))
|
| + continue
|
| + }
|
| +
|
| + v := reflect.ValueOf(arg)
|
| + vt := v.Type()
|
| + mma.elems[i].arg = v
|
| +
|
| + // Try and treat the argument as a single-value first. This allows slices
|
| + // that implement PropertyLoadSaver to be properly treated as a single
|
| + // element.
|
| + var err error
|
| + isSlice := false
|
| + mat := parseArg(vt, keysOnly)
|
| + if mat == nil {
|
| + // If this is a slice, treat it as a slice of arg candidates.
|
| + if v.Kind() == reflect.Slice {
|
| + isSlice = true
|
| + mat = parseArg(vt.Elem(), keysOnly)
|
| + }
|
| + } else {
|
| + // Single types need to be able to be assigned to.
|
| + err = isOKSingleType(vt, keysOnly)
|
| + }
|
| + if mat == nil {
|
| + err = errors.New("not a PLS or pointer-to-struct")
|
| + }
|
| + if err != nil {
|
| + lme.Assign(i, fmt.Errorf("invalid input type (%T): %s", arg, err))
|
| + continue
|
| + }
|
| +
|
| + mma.elems[i].mat = mat
|
| + if isSlice {
|
| + l := v.Len()
|
| + mma.count += l
|
| + mma.elems[i].size = l
|
| + } else {
|
| + mma.count++
|
| + mma.elems[i].size = -1
|
| + }
|
| + }
|
| + if err := lme.Get(); err != nil {
|
| + return nil, err
|
| + }
|
| +
|
| + return &mma, nil
|
| +}
|
| +
|
| +func (mma *metaMultiArg) iterator(cb metaMultiArgIteratorCallback) *metaMultiArgIterator {
|
| + return &metaMultiArgIterator{
|
| + metaMultiArg: mma,
|
| + cb: cb,
|
| + }
|
| +}
|
| +
|
| +// getKeysPMs returns the
|
| +func (mma *metaMultiArg) getKeysPMs(aid, ns string, meta bool) ([]*Key, []PropertyMap, error) {
|
| + var et errorTracker
|
| + it := mma.iterator(et.init(mma))
|
| +
|
| + // Determine our flattened keys and property maps.
|
| + retKey := make([]*Key, mma.count)
|
| + var retPM []PropertyMap
|
| + if !mma.keysOnly {
|
| + retPM = make([]PropertyMap, mma.count)
|
| + }
|
| +
|
| + for i := 0; i < mma.count; i++ {
|
| + it.next(func(mat *multiArgType, slot reflect.Value) error {
|
| + key, err := mat.getKey(aid, ns, slot)
|
| + if err != nil {
|
| + return err
|
| + }
|
| + retKey[i] = key
|
| +
|
| + if !mma.keysOnly {
|
| + var pm PropertyMap
|
| + if meta {
|
| + pm = mat.getMetaPM(slot)
|
| + } else {
|
| + var err error
|
| + if pm, err = mat.getPM(slot); err != nil {
|
| + return err
|
| + }
|
| + }
|
| + retPM[i] = pm
|
| + }
|
| + return nil
|
| + })
|
| + }
|
| + return retKey, retPM, et.error()
|
| +}
|
| +
|
| +type metaMultiArgIterator struct {
|
| + *metaMultiArg
|
| +
|
| + cb metaMultiArgIteratorCallback
|
| +
|
| + index int // flattened index
|
| + elemIdx int // current index in slice
|
| + slotIdx int // current index within elemIdx element (0 if single)
|
| +}
|
| +
|
| +func (it *metaMultiArgIterator) next(fn func(*multiArgType, reflect.Value) error) {
|
| + if it.remaining() <= 0 {
|
| + panic("out of bounds")
|
| + }
|
| +
|
| + // Advance to the next populated element/slot.
|
| + elem := &it.elems[it.elemIdx]
|
| + if it.index > 0 {
|
| + for {
|
| + it.slotIdx++
|
| + if it.slotIdx >= elem.size {
|
| + it.elemIdx++
|
| + it.slotIdx = 0
|
| + elem = &it.elems[it.elemIdx]
|
| + }
|
| +
|
| + // We're done iterating, unless we're on a zero-sized slice element.
|
| + if elem.size != 0 {
|
| + break
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Get the current slot value.
|
| + slot := elem.arg
|
| + if elem.size >= 0 {
|
| + // slot is a slice type, get its member.
|
| + slot = slot.Index(it.slotIdx)
|
| + }
|
| +
|
| + // Execute our callback.
|
| + it.cb(it, fn(elem.mat, slot))
|
| +
|
| + // Advance our flattened index.
|
| + it.index++
|
| +}
|
| +
|
| +func (it *metaMultiArgIterator) remaining() int {
|
| + return it.count - it.index
|
| +}
|
| +
|
| +type metaMultiArgIteratorCallback func(*metaMultiArgIterator, error)
|
| +
|
| +type errorTracker struct {
|
| + elemErrors errors.MultiError
|
| +}
|
| +
|
| +func (et *errorTracker) init(mma *metaMultiArg) metaMultiArgIteratorCallback {
|
| + return et.trackError
|
| +}
|
| +
|
| +func (et *errorTracker) trackError(it *metaMultiArgIterator, err error) {
|
| + if err == nil {
|
| + return
|
| + }
|
| +
|
| + if et.elemErrors == nil {
|
| + et.elemErrors = make(errors.MultiError, len(it.elems))
|
| + }
|
| +
|
| + // If this is a single element, assign the error directly.
|
| + elem := it.elems[it.elemIdx]
|
| + if elem.size < 0 {
|
| + et.elemErrors[it.elemIdx] = err
|
| + } else {
|
| + // This is a slice element. Use a slice-sized MultiError for its element
|
| + // error slot, then add this error to the inner MultiError's slot index.
|
| + serr, ok := et.elemErrors[it.elemIdx].(errors.MultiError)
|
| + if !ok {
|
| + serr = make(errors.MultiError, elem.size)
|
| + et.elemErrors[it.elemIdx] = serr
|
| + }
|
| + serr[it.slotIdx] = err
|
| + }
|
| +}
|
| +
|
| +func (et *errorTracker) error() error {
|
| + if err := et.elemErrors; err != nil {
|
| + return err
|
| + }
|
| + return nil
|
| +}
|
| +
|
| +type boolTracker struct {
|
| + errorTracker
|
| +
|
| + res ExistsResult
|
| +}
|
| +
|
| +func (bt *boolTracker) init(mma *metaMultiArg) metaMultiArgIteratorCallback {
|
| + bt.errorTracker.init(mma)
|
| +
|
| + sizes := make([]int, len(mma.elems))
|
| + for i, e := range mma.elems {
|
| + if e.size < 0 {
|
| + sizes[i] = 1
|
| + } else {
|
| + sizes[i] = e.size
|
| + }
|
| + }
|
| +
|
| + bt.res.init(sizes...)
|
| + return bt.trackExistsResult
|
| +}
|
| +
|
| +func (bt *boolTracker) trackExistsResult(it *metaMultiArgIterator, err error) {
|
| + switch err {
|
| + case nil:
|
| + bt.res.set(it.elemIdx, it.slotIdx)
|
| +
|
| + case ErrNoSuchEntity:
|
| + break
|
| +
|
| + default:
|
| + // Pass through to track as MultiError.
|
| + bt.errorTracker.trackError(it, err)
|
| + }
|
| +}
|
| +
|
| +func (bt *boolTracker) result() *ExistsResult {
|
| + bt.res.updateSlices()
|
| + return &bt.res
|
| +}
|
|
|