This commit is contained in:
GenZmeY 2021-03-21 14:03:35 +03:00
parent 6142ac93b9
commit e90f4a1291
3 changed files with 62 additions and 32 deletions

View File

@ -3,14 +3,16 @@ package model
import ( import (
"errors" "errors"
"fmt"
"net/http" "net/http"
"strconv"
"github.com/manyminds/api2go" "github.com/manyminds/api2go"
"github.com/manyminds/api2go/jsonapi" "github.com/manyminds/api2go/jsonapi"
) )
type Car struct { type Car struct {
ID string `json:"-"` ID uint64 `json:"-"`
Brand string `json:"brand"` Brand string `json:"brand"`
Model string `json:"model"` Model string `json:"model"`
Price uint64 `json:"price"` Price uint64 `json:"price"`
@ -70,12 +72,16 @@ func newVerifyError(title string, detail string, pointer string) api2go.Error {
// GetID to satisfy jsonapi.MarshalIdentifier interface // GetID to satisfy jsonapi.MarshalIdentifier interface
func (c Car) GetID() string { func (c Car) GetID() string {
return c.ID return fmt.Sprintf("%d", c.ID)
} }
// SetID to satisfy jsonapi.UnmarshalIdentifier interface // SetID to satisfy jsonapi.UnmarshalIdentifier interface
func (c *Car) SetID(id string) error { func (c *Car) SetID(id string) error {
c.ID = id intID, err := strconv.ParseUint(id, 10, 64)
if err != nil {
return err
}
c.ID = intID
return nil return nil
} }

View File

@ -3,7 +3,7 @@ package resource
import ( import (
"errors" "errors"
"net/http" "net/http"
"sort" _ "sort"
"strconv" "strconv"
"go-jsonapi-example/internal/model" "go-jsonapi-example/internal/model"
@ -19,17 +19,11 @@ type CarResource struct {
// FindAll to satisfy api2go data source interface // FindAll to satisfy api2go data source interface
func (s CarResource) FindAll(r api2go.Request) (api2go.Responder, error) { func (s CarResource) FindAll(r api2go.Request) (api2go.Responder, error) {
cars := s.CarStorage.GetAll() return &Response{Res: s.CarStorage.GetAll()}, nil
result := make([]model.Car, 0, len(cars))
for _, car := range cars {
result = append(result, *car)
}
return &Response{Res: result}, nil
} }
// PaginatedFindAll can be used to load cars in chunks // PaginatedFindAll can be used to load cars in chunks
/*
func (s CarResource) PaginatedFindAll(r api2go.Request) (uint, api2go.Responder, error) { func (s CarResource) PaginatedFindAll(r api2go.Request) (uint, api2go.Responder, error) {
var ( var (
result []model.Car result []model.Car
@ -104,10 +98,15 @@ func (s CarResource) PaginatedFindAll(r api2go.Request) (uint, api2go.Responder,
return uint(len(cars)), &Response{Res: result}, nil return uint(len(cars)), &Response{Res: result}, nil
} }
*/
// FindOne to satisfy `api2go.DataSource` interface // FindOne to satisfy `api2go.DataSource` interface
func (s CarResource) FindOne(ID string, r api2go.Request) (api2go.Responder, error) { func (s CarResource) FindOne(ID string, r api2go.Request) (api2go.Responder, error) {
car, err := s.CarStorage.GetOne(ID) intID, err := strconv.ParseUint(ID, 10, 64)
if err != nil {
return &Response{}, api2go.NewHTTPError(err, err.Error(), http.StatusNotFound)
}
car, err := s.CarStorage.GetOne(intID)
if err != nil { if err != nil {
return &Response{}, api2go.NewHTTPError(err, err.Error(), http.StatusNotFound) return &Response{}, api2go.NewHTTPError(err, err.Error(), http.StatusNotFound)
} }
@ -133,7 +132,10 @@ func (s CarResource) Create(obj interface{}, r api2go.Request) (api2go.Responder
// Delete to satisfy `api2go.DataSource` interface // Delete to satisfy `api2go.DataSource` interface
func (s CarResource) Delete(id string, r api2go.Request) (api2go.Responder, error) { func (s CarResource) Delete(id string, r api2go.Request) (api2go.Responder, error) {
err := s.CarStorage.Delete(id) intID, err := strconv.ParseUint(id, 10, 64)
if err == nil {
err = s.CarStorage.Delete(intID)
}
return &Response{Code: http.StatusNoContent}, err return &Response{Code: http.StatusNoContent}, err
} }

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"sync"
"go-jsonapi-example/internal/model" "go-jsonapi-example/internal/model"
@ -11,36 +12,55 @@ import (
) )
type CarStorage struct { type CarStorage struct {
cars map[string]*model.Car mutex sync.RWMutex
idCount int cars map[uint64]*model.Car
idCount uint64
} }
type Cars []model.Car
func (c Cars) Len() int { return len(c) }
func (c Cars) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c Cars) Less(i, j int) bool { return c[i].ID < c[j].ID }
func NewCarStorage() *CarStorage { func NewCarStorage() *CarStorage {
return &CarStorage{make(map[string]*model.Car), 1} return &CarStorage{cars: make(map[uint64]*model.Car), idCount: 1}
} }
func (s CarStorage) GetAll() map[string]*model.Car { func (s CarStorage) GetAll() Cars {
return s.cars s.mutex.RLock()
} defer s.mutex.RUnlock()
result := make(Cars, 0, len(s.cars))
func (s CarStorage) GetOne(id string) (model.Car, error) { for _, car := range s.cars {
user, ok := s.cars[id] result = append(result, *car)
if ok {
return *user, nil
} }
return result
}
func (s CarStorage) GetOne(id uint64) (model.Car, error) {
s.mutex.RLock()
car, ok := s.cars[id]
if ok {
defer s.mutex.RUnlock()
return *car, nil
}
s.mutex.RUnlock()
errMessage := fmt.Sprintf("Car for id %s not found", id) errMessage := fmt.Sprintf("Car for id %s not found", id)
return model.Car{}, api2go.NewHTTPError(errors.New(errMessage), errMessage, http.StatusNotFound) return model.Car{}, api2go.NewHTTPError(errors.New(errMessage), errMessage, http.StatusNotFound)
} }
func (s *CarStorage) Insert(c model.Car) string { func (s *CarStorage) Insert(c model.Car) uint64 {
id := fmt.Sprintf("%d", s.idCount) s.mutex.Lock()
c.ID = id defer s.mutex.Unlock()
s.cars[id] = &c c.ID = s.idCount
s.cars[s.idCount] = &c
s.idCount++ s.idCount++
return id return c.ID
} }
func (s *CarStorage) Delete(id string) error { func (s *CarStorage) Delete(id uint64) error {
s.mutex.Lock()
defer s.mutex.Unlock()
_, exists := s.cars[id] _, exists := s.cars[id]
if !exists { if !exists {
return fmt.Errorf("Car with id %s does not exist", id) return fmt.Errorf("Car with id %s does not exist", id)
@ -51,6 +71,8 @@ func (s *CarStorage) Delete(id string) error {
} }
func (s *CarStorage) Update(c model.Car) error { func (s *CarStorage) Update(c model.Car) error {
s.mutex.Lock()
defer s.mutex.Unlock()
_, exists := s.cars[c.ID] _, exists := s.cars[c.ID]
if !exists { if !exists {
return fmt.Errorf("Car with id %s does not exist", c.ID) return fmt.Errorf("Car with id %s does not exist", c.ID)