OSDN Git Service

cd34ecd9e67d1f2c2e223e3c2b1b78b51a30a2a5
[bytom/vapor.git] / vendor / github.com / go-kit / kit / examples / profilesvc / service.go
1 package profilesvc
2
3 import (
4         "context"
5         "errors"
6         "sync"
7 )
8
9 // Service is a simple CRUD interface for user profiles.
10 type Service interface {
11         PostProfile(ctx context.Context, p Profile) error
12         GetProfile(ctx context.Context, id string) (Profile, error)
13         PutProfile(ctx context.Context, id string, p Profile) error
14         PatchProfile(ctx context.Context, id string, p Profile) error
15         DeleteProfile(ctx context.Context, id string) error
16         GetAddresses(ctx context.Context, profileID string) ([]Address, error)
17         GetAddress(ctx context.Context, profileID string, addressID string) (Address, error)
18         PostAddress(ctx context.Context, profileID string, a Address) error
19         DeleteAddress(ctx context.Context, profileID string, addressID string) error
20 }
21
22 // Profile represents a single user profile.
23 // ID should be globally unique.
24 type Profile struct {
25         ID        string    `json:"id"`
26         Name      string    `json:"name,omitempty"`
27         Addresses []Address `json:"addresses,omitempty"`
28 }
29
30 // Address is a field of a user profile.
31 // ID should be unique within the profile (at a minimum).
32 type Address struct {
33         ID       string `json:"id"`
34         Location string `json:"location,omitempty"`
35 }
36
37 var (
38         ErrInconsistentIDs = errors.New("inconsistent IDs")
39         ErrAlreadyExists   = errors.New("already exists")
40         ErrNotFound        = errors.New("not found")
41 )
42
43 type inmemService struct {
44         mtx sync.RWMutex
45         m   map[string]Profile
46 }
47
48 func NewInmemService() Service {
49         return &inmemService{
50                 m: map[string]Profile{},
51         }
52 }
53
54 func (s *inmemService) PostProfile(ctx context.Context, p Profile) error {
55         s.mtx.Lock()
56         defer s.mtx.Unlock()
57         if _, ok := s.m[p.ID]; ok {
58                 return ErrAlreadyExists // POST = create, don't overwrite
59         }
60         s.m[p.ID] = p
61         return nil
62 }
63
64 func (s *inmemService) GetProfile(ctx context.Context, id string) (Profile, error) {
65         s.mtx.RLock()
66         defer s.mtx.RUnlock()
67         p, ok := s.m[id]
68         if !ok {
69                 return Profile{}, ErrNotFound
70         }
71         return p, nil
72 }
73
74 func (s *inmemService) PutProfile(ctx context.Context, id string, p Profile) error {
75         if id != p.ID {
76                 return ErrInconsistentIDs
77         }
78         s.mtx.Lock()
79         defer s.mtx.Unlock()
80         s.m[id] = p // PUT = create or update
81         return nil
82 }
83
84 func (s *inmemService) PatchProfile(ctx context.Context, id string, p Profile) error {
85         if p.ID != "" && id != p.ID {
86                 return ErrInconsistentIDs
87         }
88
89         s.mtx.Lock()
90         defer s.mtx.Unlock()
91
92         existing, ok := s.m[id]
93         if !ok {
94                 return ErrNotFound // PATCH = update existing, don't create
95         }
96
97         // We assume that it's not possible to PATCH the ID, and that it's not
98         // possible to PATCH any field to its zero value. That is, the zero value
99         // means not specified. The way around this is to use e.g. Name *string in
100         // the Profile definition. But since this is just a demonstrative example,
101         // I'm leaving that out.
102
103         if p.Name != "" {
104                 existing.Name = p.Name
105         }
106         if len(p.Addresses) > 0 {
107                 existing.Addresses = p.Addresses
108         }
109         s.m[id] = existing
110         return nil
111 }
112
113 func (s *inmemService) DeleteProfile(ctx context.Context, id string) error {
114         s.mtx.Lock()
115         defer s.mtx.Unlock()
116         if _, ok := s.m[id]; !ok {
117                 return ErrNotFound
118         }
119         delete(s.m, id)
120         return nil
121 }
122
123 func (s *inmemService) GetAddresses(ctx context.Context, profileID string) ([]Address, error) {
124         s.mtx.RLock()
125         defer s.mtx.RUnlock()
126         p, ok := s.m[profileID]
127         if !ok {
128                 return []Address{}, ErrNotFound
129         }
130         return p.Addresses, nil
131 }
132
133 func (s *inmemService) GetAddress(ctx context.Context, profileID string, addressID string) (Address, error) {
134         s.mtx.RLock()
135         defer s.mtx.RUnlock()
136         p, ok := s.m[profileID]
137         if !ok {
138                 return Address{}, ErrNotFound
139         }
140         for _, address := range p.Addresses {
141                 if address.ID == addressID {
142                         return address, nil
143                 }
144         }
145         return Address{}, ErrNotFound
146 }
147
148 func (s *inmemService) PostAddress(ctx context.Context, profileID string, a Address) error {
149         s.mtx.Lock()
150         defer s.mtx.Unlock()
151         p, ok := s.m[profileID]
152         if !ok {
153                 return ErrNotFound
154         }
155         for _, address := range p.Addresses {
156                 if address.ID == a.ID {
157                         return ErrAlreadyExists
158                 }
159         }
160         p.Addresses = append(p.Addresses, a)
161         s.m[profileID] = p
162         return nil
163 }
164
165 func (s *inmemService) DeleteAddress(ctx context.Context, profileID string, addressID string) error {
166         s.mtx.Lock()
167         defer s.mtx.Unlock()
168         p, ok := s.m[profileID]
169         if !ok {
170                 return ErrNotFound
171         }
172         newAddresses := make([]Address, 0, len(p.Addresses))
173         for _, address := range p.Addresses {
174                 if address.ID == addressID {
175                         continue // delete
176                 }
177                 newAddresses = append(newAddresses, address)
178         }
179         if len(newAddresses) == len(p.Addresses) {
180                 return ErrNotFound
181         }
182         p.Addresses = newAddresses
183         s.m[profileID] = p
184         return nil
185 }