Skip to content
Permalink
Fetching contributors…
Cannot retrieve contributors at this time
115 lines (101 sloc) 2.64 KB
package user
import (
"errors"
"sync"
"time"
)
// IDGenerator would be our user ID generator
// but here we keep the order of users by their IDs
// so we will use numbers that can be easly written
// to the browser to get results back from the REST API.
// var IDGenerator = func() string {
// return uuid.NewV4().String()
// }
// DataSource is our data store example.
type DataSource struct {
Users map[int64]Model
mu sync.RWMutex
}
// NewDataSource returns a new user data source.
func NewDataSource() *DataSource {
return &DataSource{
Users: make(map[int64]Model),
}
}
// GetBy receives a query function
// which is fired for every single user model inside
// our imaginary database.
// When that function returns true then it stops the iteration.
//
// It returns the query's return last known boolean value
// and the last known user model
// to help callers to reduce the loc.
//
// But be carefully, the caller should always check for the "found"
// because it may be false but the user model has actually real data inside it.
//
// It's actually a simple but very clever prototype function
// I'm think of and using everywhere since then,
// hope you find it very useful too.
func (d *DataSource) GetBy(query func(Model) bool) (user Model, found bool) {
d.mu.RLock()
for _, user = range d.Users {
found = query(user)
if found {
break
}
}
d.mu.RUnlock()
return
}
// GetByID returns a user model based on its ID.
func (d *DataSource) GetByID(id int64) (Model, bool) {
return d.GetBy(func(u Model) bool {
return u.ID == id
})
}
// GetByUsername returns a user model based on the Username.
func (d *DataSource) GetByUsername(username string) (Model, bool) {
return d.GetBy(func(u Model) bool {
return u.Username == username
})
}
func (d *DataSource) getLastID() (lastID int64) {
d.mu.RLock()
for id := range d.Users {
if id > lastID {
lastID = id
}
}
d.mu.RUnlock()
return lastID
}
// InsertOrUpdate adds or updates a user to the (memory) storage.
func (d *DataSource) InsertOrUpdate(user Model) (Model, error) {
// no matter what we will update the password hash
// for both update and insert actions.
hashedPassword, err := GeneratePassword(user.password)
if err != nil {
return user, err
}
user.HashedPassword = hashedPassword
// update
if id := user.ID; id > 0 {
_, found := d.GetByID(id)
if !found {
return user, errors.New("ID should be zero or a valid one that maps to an existing User")
}
d.mu.Lock()
d.Users[id] = user
d.mu.Unlock()
return user, nil
}
// insert
id := d.getLastID() + 1
user.ID = id
d.mu.Lock()
user.CreatedAt = time.Now()
d.Users[id] = user
d.mu.Unlock()
return user, nil
}
You can’t perform that action at this time.