diff --git a/go.mod b/go.mod index a97c8b7..762ed71 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module go.pkg.cx/leaf go 1.21 require ( - github.com/rs/zerolog v1.31.0 github.com/stretchr/testify v1.8.4 go.mongodb.org/mongo-driver v1.13.1 ) @@ -12,8 +11,6 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/klauspost/compress v1.13.6 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect @@ -22,7 +19,6 @@ require ( github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.12.0 // indirect golang.org/x/text v0.7.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index da95aed..0b7d3da 100644 --- a/go.sum +++ b/go.sum @@ -1,26 +1,15 @@ -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= -github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -52,10 +41,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/index.go b/index.go index 0553bc3..8d4418c 100644 --- a/index.go +++ b/index.go @@ -3,45 +3,49 @@ package leaf import ( "context" - "github.com/rs/zerolog" "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - driver "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) -func ensureIndexes(ctx context.Context, collection *driver.Collection, models []driver.IndexModel, createIndexes bool, logger *zerolog.Logger) error { +type IndexMessage struct { + Name string + Keys interface{} + Message string +} + +func ensureIndexes(ctx context.Context, collection *mongo.Collection, models []mongo.IndexModel, createIndexes bool) ([]IndexMessage, error) { existing, err := indexNames(ctx, collection) if err != nil { - return err + return []IndexMessage{}, err } - indexes := filterIndexes(models, existing, logger) + indexes, messages := filterIndexes(models, existing, []IndexMessage{}) if len(indexes) < 1 { - return nil + return messages, nil } if !createIndexes { for _, im := range indexes { - logger.Warn().Str("name", *im.Options.Name).Msg("index declared but not present") + messages = append(messages, IndexMessage{Name: *im.Options.Name, Message: "index declared but not present"}) } - return nil + return messages, nil } _, err = collection.Indexes().CreateMany(ctx, indexes) if err != nil { - return err + return messages, err } for _, im := range indexes { - logger.Info().Str("name", *im.Options.Name).Msg("index created") + messages = append(messages, IndexMessage{Name: *im.Options.Name, Keys: im.Keys, Message: "index created"}) } - return nil + return messages, nil } -func indexNames(ctx context.Context, collection *driver.Collection) (map[string]struct{}, error) { +func indexNames(ctx context.Context, collection *mongo.Collection) (map[string]struct{}, error) { cursor, err := collection.Indexes().List(ctx) if err != nil { return nil, err @@ -66,11 +70,11 @@ func indexNames(ctx context.Context, collection *driver.Collection) (map[string] return names, nil } -func filterIndexes(models []driver.IndexModel, names map[string]struct{}, logger *zerolog.Logger) []driver.IndexModel { - var filtered []driver.IndexModel +func filterIndexes(models []mongo.IndexModel, names map[string]struct{}, messages []IndexMessage) ([]mongo.IndexModel, []IndexMessage) { + var filtered []mongo.IndexModel for _, im := range models { if im.Options.Name == nil { - logger.Warn().Interface("keys", im.Keys).Msg("must specify index name explicitly") + messages = append(messages, IndexMessage{Keys: im.Keys, Message: "must specify index name explicitly"}) continue } @@ -79,17 +83,17 @@ func filterIndexes(models []driver.IndexModel, names map[string]struct{}, logger } } - return filtered + return filtered, messages } -func withTimestampIndexes(models []driver.IndexModel) []driver.IndexModel { - tsModels := []driver.IndexModel{ +func withTimestampIndexes(models []mongo.IndexModel) []mongo.IndexModel { + tsModels := []mongo.IndexModel{ { - Keys: bson.D{primitive.E{Key: "created_at", Value: 1}}, + Keys: bson.D{bson.E{Key: "created_at", Value: 1}}, Options: options.Index().SetName("created_at_1"), }, { - Keys: bson.D{primitive.E{Key: "updated_at", Value: 1}}, + Keys: bson.D{bson.E{Key: "updated_at", Value: 1}}, Options: options.Index().SetName("updated_at_1"), }, } diff --git a/index_test.go b/index_test.go new file mode 100644 index 0000000..e9ae2cd --- /dev/null +++ b/index_test.go @@ -0,0 +1,129 @@ +package leaf + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/integration/mtest" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func TestEnsureIndexes(t *testing.T) { + mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock)) + ctx := context.Background() + + mt.Run("error getting index names", func(mt *mtest.T) { + mt.AddMockResponses(bson.D{{Key: "ok", Value: 0}}) + _, err := ensureIndexes(ctx, mt.Coll, nil, false) + assert.Error(t, err) + }) + + mt.Run("no indexes to create", func(mt *mtest.T) { + mt.AddMockResponses(mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch)) + messages, err := ensureIndexes(ctx, mt.Coll, nil, false) + assert.NoError(t, err) + assert.Empty(t, messages) + }) + + mt.Run("createIndexes is false", func(mt *mtest.T) { + indexModel := mongo.IndexModel{ + Keys: bson.D{bson.E{Key: "test", Value: 1}}, + Options: options.Index().SetName("test_1"), + } + + mt.AddMockResponses(mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch)) + messages, err := ensureIndexes(ctx, mt.Coll, []mongo.IndexModel{indexModel}, false) + assert.NoError(t, err) + assert.Equal(t, 1, len(messages)) + assert.Equal(t, "test_1", messages[0].Name) + assert.Equal(t, "index declared but not present", messages[0].Message) + }) + + mt.Run("createIndexes is true", func(mt *mtest.T) { + indexModel := mongo.IndexModel{ + Keys: bson.D{bson.E{Key: "test", Value: 1}}, + Options: options.Index().SetName("test_1"), + } + + mt.AddMockResponses(mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch)) + mt.AddMockResponses(mtest.CreateSuccessResponse(bson.E{Key: "ok", Value: 1})) + messages, err := ensureIndexes(ctx, mt.Coll, []mongo.IndexModel{indexModel}, true) + assert.NoError(t, err) + assert.Equal(t, 1, len(messages)) + assert.Equal(t, "test_1", messages[0].Name) + assert.Equal(t, "index created", messages[0].Message) + }) +} + +func TestIndexNames(t *testing.T) { + mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock)) + ctx := context.Background() + + mt.Run("test index names", func(mt *mtest.T) { + collection := mt.Coll + + indexModel := mongo.IndexModel{ + Keys: bson.D{bson.E{Key: "test", Value: 1}}, + Options: options.Index().SetName("test_1"), + } + + indexReposne := bson.D{ + {Key: "v", Value: 2}, + {Key: "key", Value: bson.M{"test": 1}}, + {Key: "name", Value: "test_1"}, + } + + mt.AddMockResponses(mtest.CreateSuccessResponse(bson.E{Key: "ok", Value: 1})) + _, err := collection.Indexes().CreateOne(ctx, indexModel) + assert.NoError(t, err) + + mt.AddMockResponses(mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch, indexReposne)) + names, err := indexNames(ctx, collection) + assert.NoError(t, err) + assert.Contains(t, names, "test_1") + }) +} + +func TestFilterIndexes(t *testing.T) { + models := []mongo.IndexModel{ + { + Keys: bson.D{bson.E{Key: "test1", Value: 1}}, + Options: options.Index().SetName("test_1"), + }, + { + Keys: bson.D{bson.E{Key: "test2", Value: 1}}, + Options: options.Index(), + }, + { + Keys: bson.D{bson.E{Key: "test3", Value: 1}}, + Options: options.Index().SetName("test_3"), + }, + } + + names := map[string]struct{}{"test_1": {}} + filtered, messages := filterIndexes(models, names, []IndexMessage{}) + + assert.Equal(t, 1, len(filtered)) + assert.Equal(t, "test_3", *filtered[0].Options.Name) + assert.Equal(t, 1, len(messages)) + assert.Equal(t, "must specify index name explicitly", messages[0].Message) +} + +func TestWithTimestampIndexes(t *testing.T) { + models := []mongo.IndexModel{ + { + Keys: bson.D{bson.E{Key: "test1", Value: 1}}, + Options: options.Index().SetName("test_1"), + }, + } + + result := withTimestampIndexes(models) + + assert.Equal(t, 3, len(result)) + assert.Equal(t, "test_1", *result[0].Options.Name) + assert.Equal(t, "created_at_1", *result[1].Options.Name) + assert.Equal(t, "updated_at_1", *result[2].Options.Name) +} diff --git a/repository.go b/repository.go index cd9400a..da13544 100644 --- a/repository.go +++ b/repository.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "github.com/rs/zerolog" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" driver "go.mongodb.org/mongo-driver/mongo" @@ -109,8 +108,8 @@ func (s *Repository[T]) CountDocuments(ctx context.Context, filter interface{}, return int(count), err } -func (s *Repository[T]) EnsureIndexes(ctx context.Context, createIndexes bool, logger *zerolog.Logger) error { - return ensureIndexes(ctx, s.collection, s.indexes, createIndexes, logger) +func (s *Repository[T]) EnsureIndexes(ctx context.Context, createIndexes bool) ([]IndexMessage, error) { + return ensureIndexes(ctx, s.collection, s.indexes, createIndexes) } func repositoryError(collection *driver.Collection, op string, err error) error {