data

package
v0.0.0-...-e4ad722 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2021 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ScopeActivation     = "activation"
	ScopeAuthentication = "authentication"
)

Define constants for the token scope. For now we just define the scope "activation" but we'll add additional scope later in the book.

Variables

View Source
var (
	ErrRecordNotFound = errors.New("record not found")
	ErrEditConflict   = errors.New("edit conflict")
)
View Source
var AnonymousUser = &User{}

Declare a new AnonymousUser variable.

View Source
var (
	ErrDuplicateEmail = errors.New("duplicate email")
)

Define a custom ErrDuplicateEmail error.

View Source
var ErrInvalidRuntimeFormat = errors.New("invalid runtime format")

Define an error that out UnmarshalJSON() method can return if we are unable to parse or convert the JSON string successfully.

Functions

func ValidateEmail

func ValidateEmail(v *validator.Validator, email string)

func ValidateFilters

func ValidateFilters(v *validator.Validator, f Filters)

func ValidateMovie

func ValidateMovie(v *validator.Validator, movie *Movie)

func ValidatePasswordPlaintext

func ValidatePasswordPlaintext(v *validator.Validator, password string)

func ValidateTokenPlaintext

func ValidateTokenPlaintext(v *validator.Validator, tokenPlaintext string)

Check that the plaintext token has been provided and it exactly 52 bytes long.

func ValidateUser

func ValidateUser(v *validator.Validator, user *User)

Types

type Filters

type Filters struct {
	Page     int
	PageSize int
	Sort     string
	// Add a SortSafelist field to hold the supported sort values.
	SortSafelist []string
}

type Metadata

type Metadata struct {
	CurrentPage  int `json:"current_page,omitempty"`
	PageSize     int `json:"page_size,omitempty"`
	FirstPage    int `json:"first_page,omitempty"`
	LastPage     int `json:"last_page,omitempty"`
	TotalRecords int `json:"total_records,omitempty"`
}

Define a new Metadata struct for holding the pagination metadata.

type Models

type Models struct {
	Movies      MovieModel
	Users       UserModel
	Tokens      TokenModel
	Permissions PermissionModel
}

Create a Models struct which wraps the MovieModel. We'll add other models to this, like a UserModel and PermissionModel.

func NewModels

func NewModels(db *sql.DB) Models

For ease of use, we also add a New() method which returns a Models struct containing the initialized MovieModel.

type Movie

type Movie struct {
	ID        int64     `json:"id"`
	CreatedAt time.Time `json:"-"` // Timestamp for when the movie is added to our database
	Title     string    `json:"title"`
	Year      int32     `json:"year,omitempty"`
	Runtime   Runtime   `json:"runtime,omitempty"` // Movie runtime in minutes
	Genres    []string  `json:"genres,omitempty"`  // Slice of genres for the movie, romance, comedy, etc.
	Version   int32     `json:"version"`           // The version number will be incremented each time the information is updated.
}

type MovieModel

type MovieModel struct {
	DB *sql.DB
}

Define a MovieModel struct type which wraps a sql.DB connection pool.

func (MovieModel) Delete

func (m MovieModel) Delete(id int64) error

Delete a specific record from the movies table.

func (MovieModel) Get

func (m MovieModel) Get(id int64) (*Movie, error)

Get a specific record from the movies table.

func (MovieModel) GetAll

func (m MovieModel) GetAll(title string, genres []string, filters Filters) ([]*Movie, Metadata, error)

func (MovieModel) Insert

func (m MovieModel) Insert(movie *Movie) error

Insert a new record in the movies table. The Insert() method accepts a pointer to a movie struct, which should contain the data for the new record.

func (MovieModel) Update

func (m MovieModel) Update(movie *Movie) error

Update a specific record in the movies table.

type PermissionModel

type PermissionModel struct {
	DB *sql.DB
}

func (PermissionModel) AddForUser

func (m PermissionModel) AddForUser(userID int64, codes ...string) error

Add the provided permission codes for a specific user. Notice that we are using a variadic parameter for the codes so that we can assign multiple permissions in a single call.

func (*PermissionModel) GetAllForUser

func (m *PermissionModel) GetAllForUser(userID int64) (Permissions, error)

type Permissions

type Permissions []string

Define a Permissions slice, which we will use to hold the permission codes like "movie:read" and "movie:write" for a single user.

func (Permissions) Include

func (p Permissions) Include(code string) bool

Add a helper method to check whether the Permissions slice contains a specific permission code.

type Runtime

type Runtime int32

Declare a custom Runtime type.

func (Runtime) MarshalJSON

func (r Runtime) MarshalJSON() ([]byte, error)

Implement a MarshalJSON() method on the Runtime type so that it statisfies the json.Marshaler interface.

func (*Runtime) UnmarshalJSON

func (r *Runtime) UnmarshalJSON(jsonValue []byte) error

Note that because UnmarshalJSON() needs to modify the receiver (our Runtime type), we must use a pointer receiver for this to work correctly. Otherwise, we will only be modifying a copy (which is then discarded when this method is returned).

type Token

type Token struct {
	Plaintext string    `json:"token"`
	Hash      []byte    `json:"-"`
	UserID    int64     `json:"-"`
	Expiry    time.Time `json:"expiry"`
	Scope     string    `json:"-"`
}

Add struct tag to control how the struct appears when encoded to JSON.

type TokenModel

type TokenModel struct {
	DB *sql.DB
}

Define the TokenModel type.

func (TokenModel) DeleteAllForUser

func (m TokenModel) DeleteAllForUser(scope string, userID int64) error

DeleteAllForUser() deletes all tokens for a specific user and scope.

func (TokenModel) Insert

func (m TokenModel) Insert(token *Token) error

Insert() adds the data for a specific token to the token table.

func (*TokenModel) New

func (m *TokenModel) New(userID int64, ttl time.Duration, scope string) (*Token, error)

The New() method is a shortcut which creates a new TOken struct and then inserts the data in the tokens table.

type User

type User struct {
	ID        int64     `json:"id"`
	CreatedAt time.Time `json:"created_at"`
	Name      string    `json:"name"`
	Email     string    `json:"email"`
	Password  password  `json:"-"`
	Activated bool      `json:"activated"`
	Version   string    `json:"-"`
}

Define a User struct to represent an individual user. Importantly, notice how we are using the json:"-" struct tag to prevent the Password and Version fields appearing in any output when we encode it to JSON. Also notice that the Password field uses the custom password type defined below.

func (*User) IsAnonymous

func (u *User) IsAnonymous() bool

Check if a User instance is the AnonymousUser.

type UserModel

type UserModel struct {
	DB *sql.DB
}

Create a UserModel struct which wraps the connection pool.

func (UserModel) GetByEmail

func (m UserModel) GetByEmail(email string) (*User, error)

Retrieve the User details from the database based on the user's email address. Because we have a UNIQUE constraint on the email column, this query will only return one record (or none at all, in which case we return a ErrRecordNotFound error).

func (UserModel) GetForToken

func (m UserModel) GetForToken(tokenScope, tokenPlaintext string) (*User, error)

func (UserModel) Insert

func (m UserModel) Insert(user *User) error

Insert a new record in the database for the user. Note that the id, created_at and version fields are all automatically generated by our database, so we use the RETURNING clause to read them into the User struct after the insert, in the same way that we did when creating a movie.

func (UserModel) Update

func (m UserModel) Update(user *User) error

Update the details for a specific user. Notice that we check against the version field to help prevent any race conditions during the request cycle, just like we did when updating a movie. And we also check for a violation of the "users_email_key" constraint when performing the udpate, just like we did when inserting the user record originally.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL