gifs/api
2014-08-27
Child:96aac3ae74e6
gifs/api/memstore.go
Spike out functionality and tests. Create our interfaces around storing data and retrieving it. Create an in-memory implementation of our interfaces, for testing and rapid dev purposes. Begin sketching out what our unit tests look like. Create our Google Cloud Storage datastore implementation. Sketch out an idea for a usage collection process to keep track of which users are actually using stuff.
| paddy@0 | 1 package api |
| paddy@0 | 2 |
| paddy@0 | 3 import ( |
| paddy@0 | 4 "time" |
| paddy@0 | 5 |
| paddy@0 | 6 "secondbit.org/uuid" |
| paddy@0 | 7 ) |
| paddy@0 | 8 |
| paddy@0 | 9 type Memstore struct { |
| paddy@0 | 10 collections map[string]Collection |
| paddy@0 | 11 domains map[string]Domain |
| paddy@0 | 12 items map[string]Item |
| paddy@0 | 13 users map[string]User |
| paddy@0 | 14 logins map[string]Login |
| paddy@0 | 15 } |
| paddy@0 | 16 |
| paddy@0 | 17 func NewMemstore() Memstore { |
| paddy@0 | 18 return Memstore{ |
| paddy@0 | 19 collections: map[string]Collection{}, |
| paddy@0 | 20 domains: map[string]Domain{}, |
| paddy@0 | 21 items: map[string]Item{}, |
| paddy@0 | 22 users: map[string]User{}, |
| paddy@0 | 23 logins: map[string]Login{}, |
| paddy@0 | 24 } |
| paddy@0 | 25 } |
| paddy@0 | 26 |
| paddy@0 | 27 func (m Memstore) CreateCollection(c Collection) error { |
| paddy@0 | 28 m.collections[c.ID.String()] = c |
| paddy@0 | 29 return nil |
| paddy@0 | 30 } |
| paddy@0 | 31 |
| paddy@0 | 32 func (m Memstore) UpdateCollection(c Collection) error { |
| paddy@0 | 33 if _, ok := m.collections[c.ID.String()]; !ok { |
| paddy@0 | 34 return CollectionNotFoundError |
| paddy@0 | 35 } |
| paddy@0 | 36 m.collections[c.ID.String()] = c |
| paddy@0 | 37 return nil |
| paddy@0 | 38 } |
| paddy@0 | 39 |
| paddy@0 | 40 func (m Memstore) GetCollectionByDomain(domain string) (Collection, error) { |
| paddy@0 | 41 d, ok := m.domains[domain] |
| paddy@0 | 42 if !ok { |
| paddy@0 | 43 return Collection{}, CollectionNotFoundError |
| paddy@0 | 44 } |
| paddy@0 | 45 return m.GetCollectionByID(d.CollectionID) |
| paddy@0 | 46 } |
| paddy@0 | 47 |
| paddy@0 | 48 func (m Memstore) GetCollectionByID(id uuid.ID) (Collection, error) { |
| paddy@0 | 49 if c, ok := m.collections[id.String()]; ok { |
| paddy@0 | 50 return c, nil |
| paddy@0 | 51 } |
| paddy@0 | 52 return Collection{}, CollectionNotFoundError |
| paddy@0 | 53 } |
| paddy@0 | 54 |
| paddy@0 | 55 func (m Memstore) GetCollectionsByUser(id uuid.ID) ([]Collection, error) { |
| paddy@0 | 56 collections := []Collection{} |
| paddy@0 | 57 for _, c := range m.collections { |
| paddy@0 | 58 if c.Owner.Equal(id) { |
| paddy@0 | 59 collections = append(collections, c) |
| paddy@0 | 60 } |
| paddy@0 | 61 } |
| paddy@0 | 62 return collections, nil |
| paddy@0 | 63 } |
| paddy@0 | 64 |
| paddy@0 | 65 func (m Memstore) AddDomainToCollection(id uuid.ID, domain string) error { |
| paddy@0 | 66 if _, ok := m.domains[domain]; ok { |
| paddy@0 | 67 return DomainAlreadyExistsError |
| paddy@0 | 68 } |
| paddy@0 | 69 m.domains[domain] = Domain{ |
| paddy@0 | 70 Domain: domain, |
| paddy@0 | 71 CollectionID: id, |
| paddy@0 | 72 Created: time.Now(), |
| paddy@0 | 73 } |
| paddy@0 | 74 return nil |
| paddy@0 | 75 } |
| paddy@0 | 76 |
| paddy@0 | 77 func (m Memstore) RemoveDomainFromCollection(id uuid.ID, domain string) error { |
| paddy@0 | 78 if _, ok := m.domains[domain]; !ok { |
| paddy@0 | 79 return DomainNotFoundError |
| paddy@0 | 80 } |
| paddy@0 | 81 delete(m.domains, domain) |
| paddy@0 | 82 return nil |
| paddy@0 | 83 } |
| paddy@0 | 84 |
| paddy@0 | 85 func (m Memstore) GetDomainsByCollection(id uuid.ID) ([]Domain, error) { |
| paddy@0 | 86 domains := []Domain{} |
| paddy@0 | 87 for _, d := range m.domains { |
| paddy@0 | 88 if d.CollectionID.Equal(id) { |
| paddy@0 | 89 domains = append(domains, d) |
| paddy@0 | 90 } |
| paddy@0 | 91 } |
| paddy@0 | 92 return domains, nil |
| paddy@0 | 93 } |
| paddy@0 | 94 |
| paddy@0 | 95 func (m Memstore) DeleteCollection(c Collection) error { |
| paddy@0 | 96 if _, ok := m.collections[c.ID.String()]; !ok { |
| paddy@0 | 97 return CollectionNotFoundError |
| paddy@0 | 98 } |
| paddy@0 | 99 delete(m.collections, c.ID.String()) |
| paddy@0 | 100 return nil |
| paddy@0 | 101 } |
| paddy@0 | 102 |
| paddy@0 | 103 func (m Memstore) GetItemsByCollectionDomain(domain string, num, offset int) ([]Item, error) { |
| paddy@0 | 104 collection, err := m.GetCollectionByDomain(domain) |
| paddy@0 | 105 if err != nil { |
| paddy@0 | 106 return []Item{}, err |
| paddy@0 | 107 } |
| paddy@0 | 108 return m.GetItemsByCollectionID(collection.ID, num, offset) |
| paddy@0 | 109 } |
| paddy@0 | 110 |
| paddy@0 | 111 func (m Memstore) GetItemsByCollectionID(id uuid.ID, num, offset int) ([]Item, error) { |
| paddy@0 | 112 if _, ok := m.collections[id.String()]; !ok { |
| paddy@0 | 113 return []Item{}, CollectionNotFoundError |
| paddy@0 | 114 } |
| paddy@0 | 115 items := []Item{} |
| paddy@0 | 116 for _, item := range m.items { |
| paddy@0 | 117 if item.CollectionID.Equal(id) { |
| paddy@0 | 118 items = append(items, item) |
| paddy@0 | 119 } |
| paddy@0 | 120 } |
| paddy@0 | 121 if len(items) < offset { |
| paddy@0 | 122 return []Item{}, nil |
| paddy@0 | 123 } |
| paddy@0 | 124 end := offset + num |
| paddy@0 | 125 if len(items) < end { |
| paddy@0 | 126 end = len(items) |
| paddy@0 | 127 } |
| paddy@0 | 128 return items[offset:end], nil |
| paddy@0 | 129 } |
| paddy@0 | 130 |
| paddy@0 | 131 func (m Memstore) AddItemToCollection(id uuid.ID, item Item) error { |
| paddy@0 | 132 if _, ok := m.collections[id.String()]; !ok { |
| paddy@0 | 133 return CollectionNotFoundError |
| paddy@0 | 134 } |
| paddy@0 | 135 if _, ok := m.items[id.String()+"/"+item.Name]; ok { |
| paddy@0 | 136 return ItemAlreadyExistsError |
| paddy@0 | 137 } |
| paddy@0 | 138 item.CollectionID = id |
| paddy@0 | 139 m.items[id.String()+"/"+item.Name] = item |
| paddy@0 | 140 return nil |
| paddy@0 | 141 } |
| paddy@0 | 142 |
| paddy@0 | 143 func (m Memstore) GetItemByName(collectionID uuid.ID, name string) (Item, error) { |
| paddy@0 | 144 if _, ok := m.collections[collectionID.String()]; !ok { |
| paddy@0 | 145 return Item{}, CollectionNotFoundError |
| paddy@0 | 146 } |
| paddy@0 | 147 if item, ok := m.items[collectionID.String()+"/"+name]; ok { |
| paddy@0 | 148 return item, nil |
| paddy@0 | 149 } |
| paddy@0 | 150 return Item{}, ItemNotFoundError |
| paddy@0 | 151 } |
| paddy@0 | 152 |
| paddy@0 | 153 func (m Memstore) DeleteItem(item Item) error { |
| paddy@0 | 154 if _, ok := m.items[item.CollectionID.String()+"/"+item.Name]; !ok { |
| paddy@0 | 155 return ItemNotFoundError |
| paddy@0 | 156 } |
| paddy@0 | 157 delete(m.items, item.CollectionID.String()+"/"+item.Name) |
| paddy@0 | 158 return nil |
| paddy@0 | 159 } |
| paddy@0 | 160 |
| paddy@0 | 161 func (m Memstore) GetUserByID(id uuid.ID) (User, error) { |
| paddy@0 | 162 if u, ok := m.users[id.String()]; ok { |
| paddy@0 | 163 return u, nil |
| paddy@0 | 164 } |
| paddy@0 | 165 return User{}, UserNotFoundError |
| paddy@0 | 166 } |
| paddy@0 | 167 |
| paddy@0 | 168 func (m Memstore) GetUserByLogin(loginType, value, passphrase string) (User, error) { |
| paddy@0 | 169 login, ok := m.logins[loginType+":"+value] |
| paddy@0 | 170 if !ok { |
| paddy@0 | 171 return User{}, UserNotFoundError |
| paddy@0 | 172 } |
| paddy@0 | 173 user, err := m.GetUserByID(login.UserID) |
| paddy@0 | 174 if err != nil { |
| paddy@0 | 175 return user, err |
| paddy@0 | 176 } |
| paddy@0 | 177 if user.Passphrase != passphrase { |
| paddy@0 | 178 return User{}, UserNotFoundError |
| paddy@0 | 179 } |
| paddy@0 | 180 return user, nil |
| paddy@0 | 181 } |
| paddy@0 | 182 |
| paddy@0 | 183 func (m Memstore) CreateUser(u User) error { |
| paddy@0 | 184 m.users[u.ID.String()] = u |
| paddy@0 | 185 return nil |
| paddy@0 | 186 } |
| paddy@0 | 187 |
| paddy@0 | 188 func (m Memstore) AddLoginToUser(login Login, user uuid.ID) error { |
| paddy@0 | 189 if _, ok := m.logins[login.Type+":"+login.Value]; ok { |
| paddy@0 | 190 return LoginAlreadyExistsError |
| paddy@0 | 191 } |
| paddy@0 | 192 m.logins[login.Type+":"+login.Value] = login |
| paddy@0 | 193 return nil |
| paddy@0 | 194 } |
| paddy@0 | 195 |
| paddy@0 | 196 func (m Memstore) RemoveLoginFromUser(loginType, value string, user uuid.ID) error { |
| paddy@0 | 197 if _, ok := m.logins[loginType+":"+value]; !ok { |
| paddy@0 | 198 return LoginNotFoundError |
| paddy@0 | 199 } |
| paddy@0 | 200 delete(m.logins, loginType+":"+value) |
| paddy@0 | 201 return nil |
| paddy@0 | 202 } |
| paddy@0 | 203 |
| paddy@0 | 204 func (m Memstore) GetLoginsByUser(user uuid.ID) ([]Login, error) { |
| paddy@0 | 205 logins := []Login{} |
| paddy@0 | 206 for _, login := range m.logins { |
| paddy@0 | 207 if login.UserID.Equal(user) { |
| paddy@0 | 208 logins = append(logins, login) |
| paddy@0 | 209 } |
| paddy@0 | 210 } |
| paddy@0 | 211 return logins, nil |
| paddy@0 | 212 } |
| paddy@0 | 213 |
| paddy@0 | 214 func (m Memstore) UpdateUser(u User) error { |
| paddy@0 | 215 if _, ok := m.users[u.ID.String()]; !ok { |
| paddy@0 | 216 return UserNotFoundError |
| paddy@0 | 217 } |
| paddy@0 | 218 m.users[u.ID.String()] = u |
| paddy@0 | 219 return nil |
| paddy@0 | 220 } |
| paddy@0 | 221 |
| paddy@0 | 222 func (m Memstore) DeleteUser(u User) error { |
| paddy@0 | 223 if _, ok := m.users[u.ID.String()]; !ok { |
| paddy@0 | 224 return UserNotFoundError |
| paddy@0 | 225 } |
| paddy@0 | 226 delete(m.users, u.ID.String()) |
| paddy@0 | 227 return nil |
| paddy@0 | 228 } |