From 60cf74352f13874a7d07c609c03b1c763af19cea Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Thu, 3 May 2018 14:00:26 +0100 Subject: MM-10140: API Implementation for Schemes related Endpoints (#8615) * Implement basic scheme CRUD endpoints. * Get All Schemes (Paged) Endpoint and store plumbing. * Add get teams/channels for schemes. * Fix unit tests. * Review fixes. * More review fixes. --- store/layered_store.go | 6 +++ store/layered_store_supplier.go | 1 + store/local_cache_supplier_schemes.go | 4 ++ store/redis_supplier_schemes.go | 5 ++ store/sqlstore/channel_store.go | 2 +- store/sqlstore/scheme_supplier.go | 19 +++++++ store/store.go | 1 + store/storetest/channel_store.go | 6 +-- store/storetest/mocks/LayeredStoreDatabaseLayer.go | 23 ++++++++ store/storetest/mocks/LayeredStoreSupplier.go | 23 ++++++++ store/storetest/mocks/SchemeStore.go | 16 ++++++ store/storetest/mocks/SqlStore.go | 14 +++++ store/storetest/scheme_store.go | 61 ++++++++++++++++++++++ 13 files changed, 177 insertions(+), 4 deletions(-) (limited to 'store') diff --git a/store/layered_store.go b/store/layered_store.go index 603976fc0..cbabe9d22 100644 --- a/store/layered_store.go +++ b/store/layered_store.go @@ -292,3 +292,9 @@ func (s *LayeredSchemeStore) Delete(schemeId string) StoreChannel { return supplier.SchemeDelete(s.TmpContext, schemeId) }) } + +func (s *LayeredSchemeStore) GetAllPage(scope string, offset int, limit int) StoreChannel { + return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { + return supplier.SchemeGetAllPage(s.TmpContext, scope, offset, limit) + }) +} diff --git a/store/layered_store_supplier.go b/store/layered_store_supplier.go index 04fa26fd3..4f57004bb 100644 --- a/store/layered_store_supplier.go +++ b/store/layered_store_supplier.go @@ -42,4 +42,5 @@ type LayeredStoreSupplier interface { SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemeGet(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult SchemeDelete(ctx context.Context, schemeId string, hints ...LayeredStoreHint) *LayeredStoreSupplierResult + SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) *LayeredStoreSupplierResult } diff --git a/store/local_cache_supplier_schemes.go b/store/local_cache_supplier_schemes.go index 2a8f73a71..809c60510 100644 --- a/store/local_cache_supplier_schemes.go +++ b/store/local_cache_supplier_schemes.go @@ -42,3 +42,7 @@ func (s *LocalCacheSupplier) SchemeDelete(ctx context.Context, schemeId string, return s.Next().SchemeDelete(ctx, schemeId, hints...) } + +func (s *LocalCacheSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + return s.Next().SchemeGetAllPage(ctx, scope, offset, limit, hints...) +} diff --git a/store/redis_supplier_schemes.go b/store/redis_supplier_schemes.go index 4c05e9329..3bd747044 100644 --- a/store/redis_supplier_schemes.go +++ b/store/redis_supplier_schemes.go @@ -23,3 +23,8 @@ func (s *RedisSupplier) SchemeDelete(ctx context.Context, schemeId string, hints // TODO: Redis caching. return s.Next().SchemeDelete(ctx, schemeId, hints...) } + +func (s *RedisSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + // TODO: Redis caching. + return s.Next().SchemeGetAllPage(ctx, scope, offset, limit, hints...) +} diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go index b12c553a4..beef1be80 100644 --- a/store/sqlstore/channel_store.go +++ b/store/sqlstore/channel_store.go @@ -1730,7 +1730,7 @@ func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) sto func (s SqlChannelStore) GetChannelsByScheme(schemeId string, offset int, limit int) store.StoreChannel { return store.Do(func(result *store.StoreResult) { - var channels []*model.Channel + var channels model.ChannelList _, err := s.GetReplica().Select(&channels, "SELECT * FROM Channels WHERE SchemeId = :SchemeId ORDER BY DisplayName LIMIT :Limit OFFSET :Offset", map[string]interface{}{"SchemeId": schemeId, "Offset": offset, "Limit": limit}) if err != nil { result.Err = model.NewAppError("SqlChannelStore.GetChannelsByScheme", "store.sql_channel.get_by_scheme.app_error", nil, "schemeId="+schemeId+" "+err.Error(), http.StatusInternalServerError) diff --git a/store/sqlstore/scheme_supplier.go b/store/sqlstore/scheme_supplier.go index 278d1a3c4..448e5a92f 100644 --- a/store/sqlstore/scheme_supplier.go +++ b/store/sqlstore/scheme_supplier.go @@ -270,3 +270,22 @@ func (s *SqlSupplier) SchemeDelete(ctx context.Context, schemeId string, hints . return result } + +func (s *SqlSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + result := store.NewSupplierResult() + + var schemes []*model.Scheme + + scopeClause := "" + if len(scope) > 0 { + scopeClause = " AND Scope=:Scope " + } + + if _, err := s.GetReplica().Select(&schemes, "SELECT * from Schemes WHERE DeleteAt = 0 "+scopeClause+" ORDER BY CreateAt DESC LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Limit": limit, "Offset": offset, "Scope": scope}); err != nil { + result.Err = model.NewAppError("SqlSchemeStore.Get", "store.sql_scheme.get.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + result.Data = schemes + + return result +} diff --git a/store/store.go b/store/store.go index 1085198bd..dd149fbe9 100644 --- a/store/store.go +++ b/store/store.go @@ -485,5 +485,6 @@ type RoleStore interface { type SchemeStore interface { Save(scheme *model.Scheme) StoreChannel Get(schemeId string) StoreChannel + GetAllPage(scope string, offset int, limit int) StoreChannel Delete(schemeId string) StoreChannel } diff --git a/store/storetest/channel_store.go b/store/storetest/channel_store.go index 7427c816c..d90a0ae1e 100644 --- a/store/storetest/channel_store.go +++ b/store/storetest/channel_store.go @@ -2239,18 +2239,18 @@ func testChannelStoreGetChannelsByScheme(t *testing.T, ss store.Store) { // Get the channels by a valid Scheme ID. res1 := <-ss.Channel().GetChannelsByScheme(s1.Id, 0, 100) assert.Nil(t, res1.Err) - d1 := res1.Data.([]*model.Channel) + d1 := res1.Data.(model.ChannelList) assert.Len(t, d1, 2) // Get the channels by a valid Scheme ID where there aren't any matching Channel. res2 := <-ss.Channel().GetChannelsByScheme(s2.Id, 0, 100) assert.Nil(t, res2.Err) - d2 := res2.Data.([]*model.Channel) + d2 := res2.Data.(model.ChannelList) assert.Len(t, d2, 0) // Get the channels by an invalid Scheme ID. res3 := <-ss.Channel().GetChannelsByScheme(model.NewId(), 0, 100) assert.Nil(t, res3.Err) - d3 := res3.Data.([]*model.Channel) + d3 := res3.Data.(model.ChannelList) assert.Len(t, d3, 0) } diff --git a/store/storetest/mocks/LayeredStoreDatabaseLayer.go b/store/storetest/mocks/LayeredStoreDatabaseLayer.go index 6f6776b47..a505b6434 100644 --- a/store/storetest/mocks/LayeredStoreDatabaseLayer.go +++ b/store/storetest/mocks/LayeredStoreDatabaseLayer.go @@ -632,6 +632,29 @@ func (_m *LayeredStoreDatabaseLayer) SchemeGet(ctx context.Context, schemeId str return r0 } +// SchemeGetAllPage provides a mock function with given fields: ctx, scope, offset, limit, hints +func (_m *LayeredStoreDatabaseLayer) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, scope, offset, limit) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, string, int, int, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, scope, offset, limit, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + // SchemeSave provides a mock function with given fields: ctx, scheme, hints func (_m *LayeredStoreDatabaseLayer) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) diff --git a/store/storetest/mocks/LayeredStoreSupplier.go b/store/storetest/mocks/LayeredStoreSupplier.go index 8e1920d17..18dbe3af1 100644 --- a/store/storetest/mocks/LayeredStoreSupplier.go +++ b/store/storetest/mocks/LayeredStoreSupplier.go @@ -329,6 +329,29 @@ func (_m *LayeredStoreSupplier) SchemeGet(ctx context.Context, schemeId string, return r0 } +// SchemeGetAllPage provides a mock function with given fields: ctx, scope, offset, limit, hints +func (_m *LayeredStoreSupplier) SchemeGetAllPage(ctx context.Context, scope string, offset int, limit int, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, scope, offset, limit) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, string, int, int, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, scope, offset, limit, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + // SchemeSave provides a mock function with given fields: ctx, scheme, hints func (_m *LayeredStoreSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) diff --git a/store/storetest/mocks/SchemeStore.go b/store/storetest/mocks/SchemeStore.go index 00eeb0573..2868521b3 100644 --- a/store/storetest/mocks/SchemeStore.go +++ b/store/storetest/mocks/SchemeStore.go @@ -45,6 +45,22 @@ func (_m *SchemeStore) Get(schemeId string) store.StoreChannel { return r0 } +// GetAllPage provides a mock function with given fields: scope, offset, limit +func (_m *SchemeStore) GetAllPage(scope string, offset int, limit int) store.StoreChannel { + ret := _m.Called(scope, offset, limit) + + var r0 store.StoreChannel + if rf, ok := ret.Get(0).(func(string, int, int) store.StoreChannel); ok { + r0 = rf(scope, offset, limit) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(store.StoreChannel) + } + } + + return r0 +} + // Save provides a mock function with given fields: scheme func (_m *SchemeStore) Save(scheme *model.Scheme) store.StoreChannel { ret := _m.Called(scheme) diff --git a/store/storetest/mocks/SqlStore.go b/store/storetest/mocks/SqlStore.go index baf112e87..021baa7d3 100644 --- a/store/storetest/mocks/SqlStore.go +++ b/store/storetest/mocks/SqlStore.go @@ -143,6 +143,20 @@ func (_m *SqlStore) CreateColumnIfNotExists(tableName string, columnName string, return r0 } +// CreateColumnIfNotExistsNoDefault provides a mock function with given fields: tableName, columnName, mySqlColType, postgresColType +func (_m *SqlStore) CreateColumnIfNotExistsNoDefault(tableName string, columnName string, mySqlColType string, postgresColType string) bool { + ret := _m.Called(tableName, columnName, mySqlColType, postgresColType) + + var r0 bool + if rf, ok := ret.Get(0).(func(string, string, string, string) bool); ok { + r0 = rf(tableName, columnName, mySqlColType, postgresColType) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + // CreateCompositeIndexIfNotExists provides a mock function with given fields: indexName, tableName, columnNames func (_m *SqlStore) CreateCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool { ret := _m.Called(indexName, tableName, columnNames) diff --git a/store/storetest/scheme_store.go b/store/storetest/scheme_store.go index 45d136d3e..c0cbe5deb 100644 --- a/store/storetest/scheme_store.go +++ b/store/storetest/scheme_store.go @@ -17,6 +17,7 @@ func TestSchemeStore(t *testing.T, ss store.Store) { t.Run("Save", func(t *testing.T) { testSchemeStoreSave(t, ss) }) t.Run("Get", func(t *testing.T) { testSchemeStoreGet(t, ss) }) + t.Run("GetAllPage", func(t *testing.T) { testSchemeStoreGetAllPage(t, ss) }) t.Run("Delete", func(t *testing.T) { testSchemeStoreDelete(t, ss) }) } @@ -171,6 +172,66 @@ func testSchemeStoreGet(t *testing.T, ss store.Store) { assert.NotNil(t, res3.Err) } +func testSchemeStoreGetAllPage(t *testing.T, ss store.Store) { + // Save a scheme to test with. + schemes := []*model.Scheme{ + { + Name: model.NewId(), + Description: model.NewId(), + Scope: model.SCHEME_SCOPE_TEAM, + }, + { + Name: model.NewId(), + Description: model.NewId(), + Scope: model.SCHEME_SCOPE_CHANNEL, + }, + { + Name: model.NewId(), + Description: model.NewId(), + Scope: model.SCHEME_SCOPE_TEAM, + }, + { + Name: model.NewId(), + Description: model.NewId(), + Scope: model.SCHEME_SCOPE_CHANNEL, + }, + } + + for _, scheme := range schemes { + store.Must(ss.Scheme().Save(scheme)) + } + + r1 := <-ss.Scheme().GetAllPage("", 0, 2) + assert.Nil(t, r1.Err) + s1 := r1.Data.([]*model.Scheme) + assert.Len(t, s1, 2) + + r2 := <-ss.Scheme().GetAllPage("", 2, 2) + assert.Nil(t, r2.Err) + s2 := r2.Data.([]*model.Scheme) + assert.Len(t, s2, 2) + assert.NotEqual(t, s1[0].Name, s2[0].Name) + assert.NotEqual(t, s1[0].Name, s2[1].Name) + assert.NotEqual(t, s1[1].Name, s2[0].Name) + assert.NotEqual(t, s1[1].Name, s2[1].Name) + + r3 := <-ss.Scheme().GetAllPage("team", 0, 1000) + assert.Nil(t, r3.Err) + s3 := r3.Data.([]*model.Scheme) + assert.NotZero(t, len(s3)) + for _, s := range s3 { + assert.Equal(t, "team", s.Scope) + } + + r4 := <-ss.Scheme().GetAllPage("channel", 0, 1000) + assert.Nil(t, r4.Err) + s4 := r4.Data.([]*model.Scheme) + assert.NotZero(t, len(s4)) + for _, s := range s4 { + assert.Equal(t, "channel", s.Scope) + } +} + func testSchemeStoreDelete(t *testing.T, ss store.Store) { // Save a new scheme. s1 := &model.Scheme{ -- cgit v1.2.3-1-g7c22