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  }