Skip to content

Commit 5dd8a15

Browse files
authored
billing: add db migrations (#437)
Signed-off-by: Sander Pick <sanderpick@gmail.com>
1 parent 5072d0a commit 5dd8a15

File tree

4 files changed

+145
-2
lines changed

4 files changed

+145
-2
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package migrations
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
logging "github.com/ipfs/go-log"
8+
migrate "github.com/xakep666/mongo-migrate"
9+
"go.mongodb.org/mongo-driver/bson"
10+
"go.mongodb.org/mongo-driver/mongo"
11+
"go.mongodb.org/mongo-driver/mongo/options"
12+
)
13+
14+
var (
15+
log = logging.Logger("migrations")
16+
migrateTimeout = time.Hour
17+
)
18+
19+
var m001 = migrate.Migration{
20+
Version: 1,
21+
Description: "make customer_id index sparse",
22+
Up: func(db *mongo.Database) error {
23+
log.Info("migrating 001 up")
24+
ctx, cancel := context.WithTimeout(context.Background(), migrateTimeout)
25+
defer cancel()
26+
count, err := db.Collection("customers").CountDocuments(ctx, bson.M{})
27+
if err != nil {
28+
return err
29+
}
30+
if count == 0 {
31+
return nil // namespace doesn't exist
32+
}
33+
_, err = db.Collection("customers").Indexes().DropOne(ctx, "customer_id_1")
34+
if err != nil {
35+
return err
36+
}
37+
_, err = db.Collection("customers").Indexes().CreateOne(ctx, mongo.IndexModel{
38+
Keys: bson.D{{"customer_id", 1}},
39+
Options: options.Index().SetUnique(true).SetSparse(true),
40+
})
41+
return err
42+
},
43+
Down: func(db *mongo.Database) error {
44+
log.Info("migrating 001 down")
45+
ctx, cancel := context.WithTimeout(context.Background(), migrateTimeout)
46+
defer cancel()
47+
count, err := db.Collection("customers").CountDocuments(ctx, bson.M{})
48+
if err != nil {
49+
return err
50+
}
51+
if count == 0 {
52+
return nil // namespace doesn't exist
53+
}
54+
_, err = db.Collection("customers").Indexes().DropOne(ctx, "customer_id_1")
55+
if err != nil {
56+
return err
57+
}
58+
_, err = db.Collection("customers").Indexes().CreateOne(ctx, mongo.IndexModel{
59+
Keys: bson.D{{"customer_id", 1}},
60+
Options: options.Index().SetUnique(true),
61+
})
62+
return err
63+
},
64+
}
65+
66+
func Migrate(db *mongo.Database) error {
67+
m := migrate.NewMigrate(
68+
db,
69+
m001,
70+
)
71+
return m.Up(migrate.AllAvailable)
72+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package migrations
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
migrate "github.com/xakep666/mongo-migrate"
9+
"go.mongodb.org/mongo-driver/bson"
10+
"go.mongodb.org/mongo-driver/mongo"
11+
"go.mongodb.org/mongo-driver/mongo/options"
12+
)
13+
14+
// Test make customer_id index sparse
15+
func TestMigrations_m001(t *testing.T) {
16+
ctx := context.Background()
17+
db := setup(t, ctx)
18+
19+
// Preload collection
20+
_, err := db.Collection("customers").Indexes().CreateOne(ctx, mongo.IndexModel{
21+
Keys: bson.D{{"customer_id", 1}},
22+
Options: options.Index().SetUnique(true),
23+
})
24+
require.NoError(t, err)
25+
_, err = db.Collection("customers").InsertMany(ctx, []interface{}{
26+
bson.M{"customer_id": "one"},
27+
bson.M{"customer_id": "two"},
28+
bson.M{"customer_id": "three"},
29+
})
30+
require.NoError(t, err)
31+
32+
// Test that nil customer_id causes duplicate key error
33+
docs := []interface{}{
34+
bson.M{"foo": 1}, // nil customer_id
35+
bson.M{"bar": 1}, // nil customer_id
36+
}
37+
_, err = db.Collection("customers").InsertMany(ctx, docs)
38+
require.Error(t, err) // Duplicate key error
39+
40+
// Run up
41+
err = migrate.NewMigrate(db, m001).Up(migrate.AllAvailable)
42+
require.NoError(t, err)
43+
44+
// No duplicate key error this time
45+
_, err = db.Collection("customers").InsertMany(ctx, docs)
46+
require.NoError(t, err)
47+
48+
// Clean up
49+
_, err = db.Collection("customers").DeleteMany(ctx, bson.M{})
50+
require.NoError(t, err)
51+
52+
// Run down
53+
err = migrate.NewMigrate(db, m001).Down(migrate.AllAvailable)
54+
require.NoError(t, err)
55+
}
56+
57+
func setup(t *testing.T, ctx context.Context) *mongo.Database {
58+
uri := "mongodb://127.0.0.1:27017"
59+
client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
60+
require.NoError(t, err)
61+
db := client.Database("test_billing_migrations")
62+
t.Cleanup(func() {
63+
err := db.Drop(ctx)
64+
require.NoError(t, err)
65+
})
66+
return db
67+
}

api/billingd/service/service.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/textileio/go-threads/util"
2121
"github.com/textileio/textile/v2/api/billingd/common"
2222
"github.com/textileio/textile/v2/api/billingd/gateway"
23+
"github.com/textileio/textile/v2/api/billingd/migrations"
2324
pb "github.com/textileio/textile/v2/api/billingd/pb"
2425
mdb "github.com/textileio/textile/v2/mongodb"
2526
"go.mongodb.org/mongo-driver/bson"
@@ -235,13 +236,16 @@ func NewService(ctx context.Context, config Config) (*Service, error) {
235236
return nil, err
236237
}
237238
db := client.Database(config.DBName)
239+
if err = migrations.Migrate(db); err != nil {
240+
return nil, err
241+
}
238242

239243
pdb := db.Collection("products")
240244
cdb := db.Collection("customers")
241245
indexes, err := cdb.Indexes().CreateMany(ctx, []mongo.IndexModel{
242246
{
243247
Keys: bson.D{{"customer_id", 1}},
244-
Options: options.Index().SetUnique(true),
248+
Options: options.Index().SetUnique(true).SetSparse(true),
245249
},
246250
{
247251
Keys: bson.D{{"parent_key", 1}, {"created_at", 1}},

mongodb/migrations/migrations_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func setup(t *testing.T, ctx context.Context) *mongo.Database {
141141
uri := "mongodb://127.0.0.1:27017"
142142
client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
143143
require.NoError(t, err)
144-
db := client.Database("test_migrations")
144+
db := client.Database("test_textile_migrations")
145145
t.Cleanup(func() {
146146
err := db.Drop(ctx)
147147
require.NoError(t, err)

0 commit comments

Comments
 (0)