// 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 }
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 }
// 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 }