Users: NullTime, removing transaction from insert.
This commit is contained in:
		
							parent
							
								
									950b15a117
								
							
						
					
					
						commit
						f912a434b5
					
				
					 4 changed files with 12 additions and 42 deletions
				
			
		|  | @ -2,11 +2,9 @@ package datastore | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"math/rand" |  | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/jmoiron/modl" |  | ||||||
| 	"github.com/thermokarst/bactdb/models" | 	"github.com/thermokarst/bactdb/models" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -30,46 +28,16 @@ func (s *usersStore) Get(id int64) (*models.User, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *usersStore) Create(user *models.User) (bool, error) { | func (s *usersStore) Create(user *models.User) (bool, error) { | ||||||
| 	retries := 3 |  | ||||||
| 	var wantRetry bool |  | ||||||
| 	currentTime := time.Now() | 	currentTime := time.Now() | ||||||
| 	user.CreatedAt = currentTime | 	user.CreatedAt = currentTime | ||||||
| 	user.UpdatedAt = currentTime | 	user.UpdatedAt = currentTime | ||||||
| 
 | 	fmt.Println(user) | ||||||
| retry: | 	if err := s.dbh.Insert(user); err != nil { | ||||||
| 	retries-- | 		if strings.Contains(err.Error(), `violates unique constraint "username_idx"`) { | ||||||
| 	wantRetry = false | 			return false, err | ||||||
| 	if retries == 0 { | 		} | ||||||
| 		return false, fmt.Errorf("failed to create user with username %q after retrying", user.UserName) |  | ||||||
| 	} | 	} | ||||||
| 
 | 	return true, nil | ||||||
| 	var created bool |  | ||||||
| 	err := transact(s.dbh, func(tx modl.SqlExecutor) error { |  | ||||||
| 		var existing []*models.User |  | ||||||
| 		if err := tx.Select(&existing, `SELECT * FROM users WHERE username=$1 LIMIT 1;`, user.UserName); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		if len(existing) > 0 { |  | ||||||
| 			*user = *existing[0] |  | ||||||
| 			return nil |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if err := tx.Insert(user); err != nil { |  | ||||||
| 			if strings.Contains(err.Error(), `violates unique constraint "username_idx"`) { |  | ||||||
| 				time.Sleep(time.Duration(rand.Intn(75)) * time.Millisecond) |  | ||||||
| 				wantRetry = true |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		created = true |  | ||||||
| 		return nil |  | ||||||
| 	}) |  | ||||||
| 	if wantRetry { |  | ||||||
| 		goto retry |  | ||||||
| 	} |  | ||||||
| 	return created, err |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *usersStore) List(opt *models.UserListOptions) ([]*models.User, error) { | func (s *usersStore) List(opt *models.UserListOptions) ([]*models.User, error) { | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ func TestUsersStore_Get_db(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) | 	normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) | ||||||
|  | 	normalizeTime(&user.CreatedAt, &user.UpdatedAt, &user.DeletedAt) | ||||||
| 	if !reflect.DeepEqual(user, want) { | 	if !reflect.DeepEqual(user, want) { | ||||||
| 		t.Errorf("got user %+v, want %+v", user, want) | 		t.Errorf("got user %+v, want %+v", user, want) | ||||||
| 	} | 	} | ||||||
|  | @ -77,8 +78,9 @@ func TestUsersStore_List_db(t *testing.T) { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, u := range want { | 	for i := range want { | ||||||
| 		normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt) | 		normalizeTime(&want[i].CreatedAt, &want[i].UpdatedAt, &want[i].DeletedAt) | ||||||
|  | 		normalizeTime(&users[i].CreatedAt, &users[i].UpdatedAt, &users[i].DeletedAt) | ||||||
| 	} | 	} | ||||||
| 	if !reflect.DeepEqual(users, want) { | 	if !reflect.DeepEqual(users, want) { | ||||||
| 		t.Errorf("got users %+v, want %+v", users, want) | 		t.Errorf("got users %+v, want %+v", users, want) | ||||||
|  |  | ||||||
|  | @ -15,7 +15,7 @@ type User struct { | ||||||
| 	UserName  string    `json:"userName"` | 	UserName  string    `json:"userName"` | ||||||
| 	CreatedAt time.Time `db:"created_at" json:"createdAt"` | 	CreatedAt time.Time `db:"created_at" json:"createdAt"` | ||||||
| 	UpdatedAt time.Time `db:"updated_at" json:"updatedAt"` | 	UpdatedAt time.Time `db:"updated_at" json:"updatedAt"` | ||||||
| 	DeletedAt time.Time `db:"deleted_at" json:"deletedAt"` | 	DeletedAt NullTime  `db:"deleted_at" json:"deletedAt"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewUser() *User { | func NewUser() *User { | ||||||
|  |  | ||||||
|  | @ -54,7 +54,7 @@ func TestUsersService_Create(t *testing.T) { | ||||||
| 	mux.HandleFunc(urlPath(t, router.CreateUser, nil), func(w http.ResponseWriter, r *http.Request) { | 	mux.HandleFunc(urlPath(t, router.CreateUser, nil), func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		called = true | 		called = true | ||||||
| 		testMethod(t, r, "POST") | 		testMethod(t, r, "POST") | ||||||
| 		testBody(t, r, `{"id":1,"userName":"Test User","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":"0001-01-01T00:00:00Z"}`+"\n") | 		testBody(t, r, `{"id":1,"userName":"Test User","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||||
| 
 | 
 | ||||||
| 		w.WriteHeader(http.StatusCreated) | 		w.WriteHeader(http.StatusCreated) | ||||||
| 		writeJSON(w, want) | 		writeJSON(w, want) | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Matthew Dillon
						Matthew Dillon