Model validation, initial cut

Fixes #11.
This commit is contained in:
Matthew Dillon 2015-10-13 15:28:44 -07:00
parent a678eb4017
commit ae17363f8b
12 changed files with 162 additions and 52 deletions

View file

@ -38,6 +38,24 @@ func (c *CharacteristicBase) DeleteError() error {
return errors.ErrCharacteristicNotDeleted
}
func (c *CharacteristicBase) validate() types.ValidationError {
cv := make(types.ValidationError, 0)
if c.CharacteristicName == "" {
cv["Name"] = []string{helpers.MustProvideAValue}
}
if c.CharacteristicTypeID == 0 {
cv["Characteristic Type"] = []string{helpers.MustProvideAValue}
}
if len(cv) > 0 {
return cv
}
return nil
}
// CharacteristicBase is what the DB expects for write operations
type CharacteristicBase struct {
ID int64 `json:"id,omitempty"`

View file

@ -1,16 +1,24 @@
package models
import "github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/jmoiron/modl"
import (
"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/jmoiron/modl"
"github.com/thermokarst/bactdb/types"
)
type base interface {
PreInsert(modl.SqlExecutor) error
PreUpdate(modl.SqlExecutor) error
UpdateError() error
DeleteError() error
validate() types.ValidationError
}
// Create will create a new DB record of a model.
func Create(b base) error {
if err := b.validate(); err != nil {
return err
}
if err := DBH.Insert(b); err != nil {
return nil
}
@ -19,6 +27,10 @@ func Create(b base) error {
// Update runs a DB update on a model.
func Update(b base) error {
if err := b.validate(); err != nil {
return err
}
count, err := DBH.Update(b)
if err != nil {
return err
@ -26,6 +38,7 @@ func Update(b base) error {
if count != 1 {
return b.UpdateError()
}
return nil
}
@ -38,5 +51,6 @@ func Delete(b base) error {
if count != 1 {
return b.DeleteError()
}
return nil
}

View file

@ -39,6 +39,24 @@ func (m *MeasurementBase) DeleteError() error {
return errors.ErrMeasurementNotDeleted
}
func (m *MeasurementBase) validate() types.ValidationError {
mv := make(types.ValidationError, 0)
if m.StrainID == 0 {
mv["Strain"] = []string{helpers.MustProvideAValue}
}
if m.CharacteristicID == 0 {
mv["Characteristic"] = []string{helpers.MustProvideAValue}
}
if len(mv) > 0 {
return mv
}
return nil
}
// MeasurementBase is what the DB expects for write operations
// There are three types of supported measurements: fixed-text, free-text,
// & numerical. The table has a constraint that will allow at most one

View file

@ -39,6 +39,24 @@ func (s *SpeciesBase) DeleteError() error {
return errors.ErrSpeciesNotDeleted
}
func (s *SpeciesBase) validate() types.ValidationError {
sv := make(types.ValidationError, 0)
if s.GenusID == 0 {
sv["Genus"] = []string{helpers.MustProvideAValue}
}
if s.SpeciesName == "" {
sv["Species"] = []string{helpers.MustProvideAValue}
}
if len(sv) > 0 {
return sv
}
return nil
}
// SpeciesBase is what the DB expects for write operations.
type SpeciesBase struct {
ID int64 `db:"id" json:"id"`

View file

@ -39,6 +39,24 @@ func (s *StrainBase) DeleteError() error {
return errors.ErrStrainNotDeleted
}
func (s *StrainBase) validate() types.ValidationError {
sv := make(types.ValidationError, 0)
if s.SpeciesID == 0 {
sv["Species"] = []string{helpers.MustProvideAValue}
}
if s.StrainName == "" {
sv["Name"] = []string{helpers.MustProvideAValue}
}
if len(sv) > 0 {
return sv
}
return nil
}
// StrainBase is what the DB expects for write operations.
type StrainBase struct {
ID int64 `db:"id" json:"id"`

View file

@ -2,7 +2,6 @@ package models
import (
"database/sql"
"encoding/json"
"regexp"
"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/jmoiron/modl"
@ -40,6 +39,33 @@ func (u *UserBase) DeleteError() error {
return errors.ErrUserNotDeleted
}
func (u *UserBase) validate() types.ValidationError {
uv := make(types.ValidationError, 0)
if u.Name == "" {
uv["Name"] = []string{helpers.MustProvideAValue}
}
if u.Email == "" {
uv["Email"] = []string{helpers.MustProvideAValue}
}
regex, _ := regexp.Compile(`(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})`)
if u.Email != "" && !regex.MatchString(u.Email) {
uv["Email"] = []string{"Must provide a valid email address"}
}
if len(u.Password) < 8 {
uv["Password"] = []string{"Password must be at least 8 characters"}
}
if len(uv) > 0 {
return uv
}
return nil
}
// UserBase is what the DB expects to see for write operations.
type UserBase struct {
ID int64 `json:"id,omitempty"`
@ -68,17 +94,6 @@ type UserValidation struct {
Role []string `json:"role,omitempty"`
}
// Error returns the JSON-encoded error response for any validation errors.
func (uv UserValidation) Error() string {
errs, err := json.Marshal(struct {
UserValidation `json:"errors"`
}{uv})
if err != nil {
return err.Error()
}
return string(errs)
}
// Users are multiple user entities.
type Users []*User
@ -87,38 +102,6 @@ type UserMeta struct {
CanAdd bool `json:"canAdd"`
}
// Validate validates a user record.
func (u *User) Validate() error {
var uv UserValidation
validationError := false
if u.Name == "" {
uv.Name = append(uv.Name, helpers.MustProvideAValue)
validationError = true
}
if u.Email == "" {
uv.Email = append(uv.Email, helpers.MustProvideAValue)
validationError = true
}
regex, _ := regexp.Compile(`(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})`)
if u.Email != "" && !regex.MatchString(u.Email) {
uv.Email = append(uv.Email, "Must provide a valid email address")
validationError = true
}
if len(u.Password) < 8 {
uv.Password = append(uv.Password, "Password must be at least 8 characters")
validationError = true
}
if validationError {
return uv
}
return nil
}
// DbAuthenticate authenticates a user.
// For thermokarst/jwt: authentication callback
func DbAuthenticate(email string, password string) error {