github.com/hoffie/larasync@v0.0.0-20151025221940-0384d2bddcef/repository/tracker/databaseNib.go (about) 1 package tracker 2 3 import ( 4 "errors" 5 "os" 6 "strings" 7 8 "github.com/jinzhu/gorm" 9 10 // Needed for sqlite gorm support. 11 _ "github.com/mattn/go-sqlite3" 12 ) 13 14 // NIBLookup struct is used to represent entries in the database. 15 type NIBLookup struct { 16 ID int64 17 NIBID string `sql:"size:256;unique" gorm:"column:nib_id"` 18 Path string `sql:"size:4096;unique"` 19 } 20 21 // TableName returns the name of the SQLite NIB table. 22 func (n NIBLookup) TableName() string { 23 return "nib_lookups" 24 } 25 26 // NewDatabaseNIBTracker initializes a new object which uses a database 27 // to track NIB changes and implements the NIBTracker repository. 28 func NewDatabaseNIBTracker(dbLocation string, repositoryPath string) (NIBTracker, error) { 29 nibTracker := &DatabaseNIBTracker{ 30 dbLocation: dbLocation, 31 repositoryPath: repositoryPath, 32 } 33 _, statErr := os.Stat(dbLocation) 34 35 db, err := gorm.Open("sqlite3", nibTracker.dbLocation) 36 nibTracker.db = &db 37 if err == nil && os.IsNotExist(statErr) { 38 err = nibTracker.createDb() 39 } 40 41 return nibTracker, err 42 } 43 44 // DatabaseNIBTracker implements the NIBTracker interface and utilizes 45 // a sqlite database backend for persistence. 46 type DatabaseNIBTracker struct { 47 dbLocation string 48 db *gorm.DB 49 repositoryPath string 50 } 51 52 // createDb initializes the tables in the database structure. 53 func (d *DatabaseNIBTracker) createDb() error { 54 db := d.db.CreateTable(&NIBLookup{}) 55 return db.Error 56 } 57 58 // Add registers the given nibID for the given path. 59 func (d *DatabaseNIBTracker) Add(path string, nibID string) error { 60 if len(path) > MaxPathSize { 61 return errors.New("Path longer than maximal allowed path.") 62 } 63 tx := d.db.Begin() 64 res, err := d.getLookup(path, tx) 65 66 var db *gorm.DB 67 if err == nil && res != nil { 68 res.NIBID = nibID 69 db = tx.Save(res) 70 } else { 71 res = &NIBLookup{ 72 NIBID: nibID, 73 Path: path, 74 } 75 db = tx.Create(res) 76 } 77 78 tx.Commit() 79 return db.Error 80 } 81 82 // whereFor returns a where statement which requests entries from the database 83 // for the passed path. 84 func (d *DatabaseNIBTracker) whereFor(path string, db *gorm.DB) *gorm.DB { 85 return db.Where(map[string]interface{}{"path": path}) 86 } 87 88 // lookupToNIB converts the lookup nib to a search response. 89 func (d *DatabaseNIBTracker) lookupToNIB(nibLookup *NIBLookup) *NIBSearchResponse { 90 return &NIBSearchResponse{ 91 NIBID: nibLookup.NIBID, 92 Path: nibLookup.Path, 93 repositoryPath: d.repositoryPath, 94 } 95 } 96 97 // get returns the database object for the given path. 98 func (d *DatabaseNIBTracker) getLookup(path string, db *gorm.DB) (*NIBLookup, error) { 99 stmt := d.whereFor(path, db) 100 data := &NIBLookup{} 101 res := stmt.First(data) 102 if res.Error != nil { 103 return nil, res.Error 104 } 105 return data, nil 106 } 107 108 // Get returns the nibID for the given path. 109 func (d *DatabaseNIBTracker) Get(path string) (*NIBSearchResponse, error) { 110 data, err := d.getLookup(path, d.db) 111 if err != nil { 112 return nil, err 113 } 114 115 return d.lookupToNIB(data), err 116 } 117 118 // SearchPrefix returns all nibIDs with the given path. 119 // The map being returned has the paths 120 func (d *DatabaseNIBTracker) SearchPrefix(prefix string) ([]*NIBSearchResponse, error) { 121 var resp []NIBLookup 122 123 prefix = strings.TrimSuffix(prefix, "/") 124 directoryPrefix := prefix + "/" 125 db := d.db.Where("path LIKE ? or path = ?", directoryPrefix+"%", prefix).Find(&resp) 126 127 searchResponse := []*NIBSearchResponse{} 128 for _, item := range resp { 129 searchResponse = append(searchResponse, d.lookupToNIB(&item)) 130 } 131 132 return searchResponse, db.Error 133 } 134 135 // Remove removes the given path from being tracked. 136 func (d *DatabaseNIBTracker) Remove(path string) error { 137 tx := d.db.Begin() 138 db := d.whereFor(path, tx).Delete(NIBLookup{}) 139 if db.Error != nil { 140 tx.Rollback() 141 } else if db.Error == nil && db.RowsAffected < 1 { 142 tx.Rollback() 143 return errors.New("Entry not found") 144 } else { 145 tx.Commit() 146 } 147 return db.Error 148 }