First implementation of datastore interface.
Define Subscriptions, and the SubscriptionChange type that can modify
Subscriptions.
Define the subscriptionStore, which describes how Subscriptions are to be
created, retrieved, updated, and deleted in/from the storage backend they're
stored in.
Create a Memstore implementation of the subscriptionStore, which stores all our
data in-memory, for use in testing.
Write tests to cover the subscriptionStore interface, testing the entire
Memstore. We'll plug future storage backends into these tests, to make sure they
all behave the same, and to exercise each storage backend without requiring a
suite of tests for each.
At this point, we have 100% test coverage and no complaints from golint or go
vet. I expect it's all downhill from here.
7 "code.secondbit.org/uuid.hg"
10 func stripeCustomerInMemstore(stripeCustomer string, m *Memstore) bool {
11 for _, sub := range m.subscriptions {
12 if sub.StripeCustomer == stripeCustomer {
19 func (m *Memstore) createSubscription(sub Subscription) error {
20 m.subscriptionLock.Lock()
21 defer m.subscriptionLock.Unlock()
23 if _, ok := m.subscriptions[sub.ID.String()]; ok {
24 return ErrSubscriptionAlreadyExists
26 if stripeCustomerInMemstore(sub.StripeCustomer, m) {
27 return ErrStripeCustomerAlreadyExists
29 m.subscriptions[sub.ID.String()] = sub
33 func (m *Memstore) updateSubscription(id uuid.ID, change SubscriptionChange) error {
35 return ErrSubscriptionChangeEmpty
38 m.subscriptionLock.Lock()
39 defer m.subscriptionLock.Unlock()
41 s, ok := m.subscriptions[id.String()]
43 return ErrSubscriptionNotFound
45 if change.StripeCustomer != nil {
46 if stripeCustomerInMemstore(*change.StripeCustomer, m) {
47 return ErrStripeCustomerAlreadyExists
51 m.subscriptions[id.String()] = s
55 func (m *Memstore) deleteSubscription(id uuid.ID) error {
56 m.subscriptionLock.Lock()
57 defer m.subscriptionLock.Unlock()
59 _, ok := m.subscriptions[id.String()]
61 return ErrSubscriptionNotFound
63 delete(m.subscriptions, id.String())
67 func (m *Memstore) listSubscriptionsLastChargedBefore(cutoff time.Time) ([]Subscription, error) {
68 m.subscriptionLock.RLock()
69 defer m.subscriptionLock.RUnlock()
71 var result []Subscription
72 for _, s := range m.subscriptions {
73 if cutoff.Before(s.LastCharged) {
76 result = append(result, s)
79 sorted := ByLastChargeDate(result)
81 result = []Subscription(sorted)
86 func (m *Memstore) getSubscriptions(ids []uuid.ID) (map[string]Subscription, error) {
88 return map[string]Subscription{}, ErrNoSubscriptionID
90 m.subscriptionLock.RLock()
91 defer m.subscriptionLock.RUnlock()
93 result := map[string]Subscription{}
95 for _, id := range ids {
96 s, ok := m.subscriptions[id.String()]
100 result[s.ID.String()] = s
105 func (m *Memstore) getSubscriptionByUser(id uuid.ID) (Subscription, error) {
106 m.subscriptionLock.RLock()
107 defer m.subscriptionLock.RUnlock()
109 for _, subscription := range m.subscriptions {
110 if subscription.UserID.Equal(id) {
111 return subscription, nil
115 return Subscription{}, ErrSubscriptionNotFound