github.com/go-kivik/kivik/v4@v4.3.2/x/fsdb/changes.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 // Changes feed support 14 // 15 // At present, this driver provides only rudimentary Changes feed support. It 16 // supports only one-off changes feeds (no continuous support), and this is 17 // implemented by scanning the database directory, and returning each document 18 // and its most recent revision only. 19 20 package fs 21 22 import ( 23 "context" 24 "io" 25 "os" 26 "strings" 27 28 "github.com/go-kivik/kivik/v4/driver" 29 "github.com/go-kivik/kivik/v4/x/fsdb/cdb/decode" 30 ) 31 32 type changes struct { 33 db *db 34 ctx context.Context 35 infos []os.FileInfo 36 } 37 38 var _ driver.Changes = &changes{} 39 40 func (c *changes) ETag() string { return "" } 41 func (c *changes) LastSeq() string { return "" } 42 func (c *changes) Pending() int64 { return 0 } 43 44 func ignoreDocID(name string) bool { 45 if name[0] != '_' { 46 return false 47 } 48 if strings.HasPrefix(name, "_design/") { 49 return false 50 } 51 if strings.HasPrefix(name, "_local/") { 52 return false 53 } 54 return true 55 } 56 57 func (c *changes) Next(ch *driver.Change) error { 58 for { 59 if len(c.infos) == 0 { 60 return io.EOF 61 } 62 candidate := c.infos[len(c.infos)-1] 63 c.infos = c.infos[:len(c.infos)-1] 64 if candidate.IsDir() { 65 continue 66 } 67 for _, ext := range decode.Extensions() { 68 if strings.HasSuffix(candidate.Name(), "."+ext) { 69 base := strings.TrimSuffix(candidate.Name(), "."+ext) 70 docid, err := filename2id(base) 71 if err != nil { 72 // ignore unrecognized files 73 continue 74 } 75 if ignoreDocID(docid) { 76 continue 77 } 78 rev, deleted, err := c.db.metadata(candidate.Name(), ext) 79 if err != nil { 80 return err 81 } 82 if rev == "" { 83 rev = "1-" 84 } 85 ch.ID = docid 86 ch.Deleted = deleted 87 ch.Changes = []string{rev} 88 return nil 89 } 90 } 91 } 92 } 93 94 func (c *changes) Close() error { 95 return nil 96 } 97 98 func (d *db) Changes(ctx context.Context, _ driver.Options) (driver.Changes, error) { 99 f, err := os.Open(d.path()) 100 if err != nil { 101 return nil, err 102 } 103 dir, err := f.Readdir(-1) 104 if err != nil { 105 return nil, err 106 } 107 return &changes{ 108 db: d, 109 ctx: ctx, 110 infos: dir, 111 }, nil 112 }