// subtreeByPath retrieves a subdirectories of a given directory.
// It is relying on an indexed string property "Dir"
// containing a string representation of the full path.
//
// It might be fast for deep, uncached directory subtree,
// that have been saved in nested manner.
//
// However, it might not find recently added directories.
// Upon finding nothing, it therefore returns the
// "warning" fsi.EmptyQueryResult
//
// The func could easily be enhanced chunked scanning.
//
// It is currently used by ReadDir and by the test package.
// It is public for the test package.
func (fs *dsFileSys) SubtreeByPath(name string, onlyDirectChildren bool) ([]DsDir, error) {

	dir, bname := fs.SplitX(name)
	name = dir + common.Filify(bname)
	if !strings.HasSuffix(name, sep) {
		name += sep
	}

	var q *datastore.Query

	if onlyDirectChildren {
		q = datastore.NewQuery(tdir).
			Filter("Dir=", name).
			Order("Dir")
		//  Limit(4)
	} else {
		pathInc := IncrementString(name)
		q = datastore.NewQuery(tdir).
			Filter("Dir>=", name).
			Filter("Dir<", pathInc).
			Order("Dir")
	}

	// log.Printf("%v", q)

	var children []DsDir
	keys, err := q.GetAll(fs.Ctx(), &children)
	if err != nil {
		aelog.Errorf(fs.Ctx(), "Error getting all children of %v => %v", dir+bname, err)
		return children, err
	}

	if len(children) < 1 {
		return children, fsi.EmptyQueryResult
	}

	// Very evil: We filter out root node, since it's
	// has the same dir as the level-1 directories.
	keyRoot := datastore.NewKey(fs.Ctx(), tdir, fs.RootDir(), 0, nil)
	idxRoot := -1

	for i := 0; i < len(children); i++ {
		children[i].fSys = fs
		children[i].Key = keys[i]
		if keys[i].Equal(keyRoot) {
			// log.Printf("root idx %v", i)
			idxRoot = i
		}
	}

	if idxRoot > -1 {
		children = append(children[:idxRoot], children[idxRoot+1:]...)
	}

	return children, nil

}
Exemple #2
0
func fillKeyQuery(c context.Context, q *datastore.Query, results interface{}) error {
	keys, err := q.GetAll(c, results)
	if err == nil {
		rslice := reflect.ValueOf(results).Elem()
		for i := range keys {
			if k, ok := rslice.Index(i).Interface().(Keyable); ok {
				k.setKey(keys[i])
			} else if k, ok := rslice.Index(i).Addr().Interface().(Keyable); ok {
				k.setKey(keys[i])
			} else {
				log.Infof(c, "Warning: %v is not Keyable", rslice.Index(i).Interface())
			}
		}
	} else {
		log.Errorf(c, "Error executing query: %v", err)
	}
	return err
}
func (cdb ComplaintDB) getComplaintsByQueryFromDatastore(q *datastore.Query) ([]*datastore.Key, []types.Complaint, error) {

	cdb.Debugf("gCBQFD_200", "getComplaintsByQueryFromDatastore")

	var data = []types.Complaint{}

	cdb.Debugf("gCBQFD_201", "calling GetAll() ...")
	keys, err := q.GetAll(cdb.Ctx(), &data)
	cdb.Debugf("gCBQFD_202", "... call done (n=%d)", len(keys))

	// We tolerate missing fields, because the DB is full of old objects with dead fields
	if err != nil {
		if mismatchErr, ok := err.(*datastore.ErrFieldMismatch); ok {
			_ = mismatchErr
			// cdb.Debugf("gCBQFD_203", "missing field: %v", mismatchErr)
		} else {
			return nil, nil, fmt.Errorf("gCBQFD: %v", err)
		}
	}

	return keys, data, nil
}
Exemple #4
0
// GetAll runs the query and returns all the keys that match the query, as well
// as appending the values to dst, setting the goon key fields of dst, and
// caching the returned data in local memory.
//
// For "keys-only" queries dst can be nil, however if it is not, then GetAll
// appends zero value structs to dst, only setting the goon key fields.
// No data is cached with "keys-only" queries.
//
// See: https://developers.google.com/appengine/docs/go/datastore/reference#Query.GetAll
func (g *Goon) GetAll(q *datastore.Query, dst interface{}) ([]*datastore.Key, error) {
	v := reflect.ValueOf(dst)
	vLenBefore := 0

	if dst != nil {
		if v.Kind() != reflect.Ptr {
			return nil, fmt.Errorf("goon: Expected dst to be a pointer to a slice or nil, got instead: %v", v.Kind())
		}

		v = v.Elem()
		if v.Kind() != reflect.Slice {
			return nil, fmt.Errorf("goon: Expected dst to be a pointer to a slice or nil, got instead: %v", v.Kind())
		}

		vLenBefore = v.Len()
	}

	keys, err := q.GetAll(g.Context, dst)
	if err != nil {
		g.error(err)
		return nil, err
	}
	if dst == nil || len(keys) == 0 {
		return keys, nil
	}

	keysOnly := ((v.Len() - vLenBefore) != len(keys))
	updateCache := !g.inTransaction && !keysOnly

	// If this is a keys-only query, we need to fill the slice with zero value elements
	if keysOnly {
		elemType := v.Type().Elem()
		ptr := false
		if elemType.Kind() == reflect.Ptr {
			elemType = elemType.Elem()
			ptr = true
		}

		if elemType.Kind() != reflect.Struct {
			return keys, fmt.Errorf("goon: Expected struct, got instead: %v", elemType.Kind())
		}

		for i := 0; i < len(keys); i++ {
			ev := reflect.New(elemType)
			if !ptr {
				ev = ev.Elem()
			}

			v.Set(reflect.Append(v, ev))
		}
	}

	if updateCache {
		g.cacheLock.Lock()
		defer g.cacheLock.Unlock()
	}

	for i, k := range keys {
		var e interface{}
		vi := v.Index(vLenBefore + i)
		if vi.Kind() == reflect.Ptr {
			e = vi.Interface()
		} else {
			e = vi.Addr().Interface()
		}

		if err := g.setStructKey(e, k); err != nil {
			return nil, err
		}

		if updateCache {
			// Cache lock is handled before the for loop
			g.cache[memkey(k)] = e
		}
	}

	return keys, nil
}