gitlab.com/ignitionrobotics/web/ign-go@v1.0.0-rc4/repository/sql_repository.go (about)

     1  package repository
     2  
     3  import (
     4  	"github.com/jinzhu/gorm"
     5  	"gitlab.com/ignitionrobotics/web/ign-go/reflect"
     6  )
     7  
     8  // NewRepositorySQL initializes a new Repository implementation for SQL databases.
     9  func NewRepositorySQL(db *gorm.DB, entity Model) Repository {
    10  	return &repositorySQL{
    11  		DB:     db,
    12  		entity: entity,
    13  	}
    14  }
    15  
    16  // repositorySQL implements Repository using gorm to support SQL databases.
    17  type repositorySQL struct {
    18  	DB     *gorm.DB
    19  	entity Model
    20  }
    21  
    22  // Create inserts a single entry.
    23  //	entity: The entry to insert.
    24  func (r *repositorySQL) Create(entity Model) (Model, error) {
    25  	result, err := r.CreateBulk([]Model{entity})
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	return result[0], nil
    30  }
    31  
    32  // CreateBulk is a bulk operation to create multiple entries with a single operation.
    33  //	entities: should be a slice of the same data structure implementing Model.
    34  func (r *repositorySQL) CreateBulk(entities []Model) ([]Model, error) {
    35  	for _, entity := range entities {
    36  		err := r.DB.Model(r.Model()).Create(entity).Error
    37  		if err != nil {
    38  			return nil, err
    39  		}
    40  	}
    41  	return entities, nil
    42  }
    43  
    44  // Find filters entries and stores filtered entries in output.
    45  //	output: will contain the result of the query. It must be a pointer to a slice.
    46  //	offset: defines the number of results to skip before loading values to output.
    47  //	limit: defines the maximum number of entries to return. A nil value returns infinite results.
    48  // 	filters: filter entries by field value.
    49  func (r *repositorySQL) Find(output interface{}, offset, limit *int, filters ...Filter) error {
    50  	q := r.startQuery()
    51  	if limit != nil {
    52  		q = q.Limit(*limit)
    53  		if offset != nil {
    54  			q = q.Offset(*offset)
    55  		}
    56  	}
    57  
    58  	q = r.setQueryFilters(q, filters)
    59  	q = q.Find(output)
    60  	err := q.Error
    61  	if err != nil {
    62  		return err
    63  	}
    64  	return nil
    65  }
    66  
    67  // FindOne filters entries and stores the first filtered entry in output, it must be a pointer to
    68  // a data structure implementing Model.
    69  func (r *repositorySQL) FindOne(output Model, filters ...Filter) error {
    70  	if len(filters) == 0 {
    71  		return ErrNoFilter
    72  	}
    73  	q := r.startQuery()
    74  	q = r.setQueryFilters(q, filters)
    75  	q = q.First(output)
    76  	return q.Error
    77  }
    78  
    79  // Update updates all model entries that match the provided filters with the given data.
    80  //	data: must be a map[string]interface{}
    81  //  filters: filter entries that should be updated.
    82  func (r *repositorySQL) Update(data interface{}, filters ...Filter) error {
    83  	q := r.startQuery()
    84  	q = r.setQueryFilters(q, filters)
    85  	q = q.Update(data)
    86  	return q.Error
    87  }
    88  
    89  // Delete removes all the model entries that match filters.
    90  //  filters: filter entries that should be deleted.
    91  func (r *repositorySQL) Delete(filters ...Filter) error {
    92  	q := r.startQuery()
    93  	q = r.setQueryFilters(q, filters)
    94  	q = q.Delete(r.Model())
    95  	err := q.Error
    96  	if err != nil {
    97  		return err
    98  	}
    99  	return nil
   100  }
   101  
   102  // FirstOrCreate inserts a new entry if the given filters don't find any existing record.
   103  //	entity: must be a pointer to a Model implementation. Results will be saved in this argument if the record exists.
   104  func (r *repositorySQL) FirstOrCreate(entity Model, filters ...Filter) error {
   105  	q := r.startQuery()
   106  	q = r.setQueryFilters(q, filters)
   107  	return q.FirstOrCreate(entity).Error
   108  }
   109  
   110  // startQuery inits a gorm query for this repository's model. Multiple filters are ANDd together.
   111  func (r *repositorySQL) startQuery() *gorm.DB {
   112  	return r.DB.Model(r.Model())
   113  }
   114  
   115  // setQueryFilters applies the given filters to a gorm query.
   116  func (r *repositorySQL) setQueryFilters(q *gorm.DB, filters []Filter) *gorm.DB {
   117  	for _, f := range filters {
   118  		q = q.Where(f.Template, f.Values...)
   119  	}
   120  	return q
   121  }
   122  
   123  // Model returns this repository's model.
   124  func (r *repositorySQL) Model() Model {
   125  	return reflect.NewInstance(r.entity).(Model)
   126  }