github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/vfs/iter.go (about) 1 package vfs 2 3 import ( 4 "path" 5 6 "github.com/cozy/cozy-stack/pkg/consts" 7 "github.com/cozy/cozy-stack/pkg/couchdb" 8 "github.com/cozy/cozy-stack/pkg/couchdb/mango" 9 "github.com/cozy/cozy-stack/pkg/prefixer" 10 ) 11 12 const iterMaxFetchSize = 256 13 14 // iter is a struct allowing to iterate over the children of a 15 // directory. The iterator is not thread-safe. 16 type iter struct { 17 db prefixer.Prefixer 18 sel mango.Filter 19 opt *IteratorOptions 20 list []*DirOrFileDoc 21 path string 22 bookmark string 23 index int 24 done bool 25 } 26 27 // NewIterator return a new iterator. 28 func NewIterator(db prefixer.Prefixer, dir *DirDoc, opt *IteratorOptions) DirIterator { 29 if opt == nil { 30 opt = &IteratorOptions{ByFetch: iterMaxFetchSize} 31 } 32 if opt.ByFetch == 0 || opt.ByFetch > iterMaxFetchSize { 33 opt.ByFetch = iterMaxFetchSize 34 } 35 sel := mango.Equal("dir_id", dir.DocID) 36 if opt.AfterID == "" { 37 sel = mango.And(sel, mango.Exists("_id")) 38 } else { 39 sel = mango.And(sel, mango.Gt("_id", opt.AfterID)) 40 } 41 return &iter{ 42 db: db, 43 sel: sel, 44 opt: opt, 45 path: dir.Fullpath, 46 } 47 } 48 49 // Next should be called to get the next directory or file children of the 50 // parent directory. If the error is ErrIteratorDone 51 func (i *iter) Next() (*DirDoc, *FileDoc, error) { 52 if i.done { 53 return nil, nil, ErrIteratorDone 54 } 55 if i.index >= len(i.list) { 56 if err := i.fetch(); err != nil { 57 return nil, nil, err 58 } 59 } 60 d, f := i.list[i.index].Refine() 61 if f != nil { 62 f.fullpath = path.Join(i.path, f.DocName) 63 } 64 i.index++ 65 return d, f, nil 66 } 67 68 // fetch should be called when the index is out of the list boundary. 69 func (i *iter) fetch() error { 70 l := len(i.list) 71 if l > 0 && l < i.opt.ByFetch { 72 i.done = true 73 return ErrIteratorDone 74 } 75 76 i.index = 0 77 i.list = i.list[:0] 78 79 req := &couchdb.FindRequest{ 80 UseIndex: "dir-children", 81 Selector: i.sel, 82 Limit: i.opt.ByFetch, 83 Bookmark: i.bookmark, 84 } 85 resp, err := couchdb.FindDocsRaw(i.db, consts.Files, req, &i.list) 86 if err != nil { 87 return err 88 } 89 if len(i.list) == 0 { 90 return ErrIteratorDone 91 } 92 i.bookmark = resp.Bookmark 93 return nil 94 }