github.com/mattermost/mattermost-server/v5@v5.39.3/store/sqlstore/group_store.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"database/sql"
     8  	"fmt"
     9  	"strings"
    10  
    11  	sq "github.com/Masterminds/squirrel"
    12  	"github.com/pkg/errors"
    13  
    14  	"github.com/mattermost/mattermost-server/v5/model"
    15  	"github.com/mattermost/mattermost-server/v5/store"
    16  )
    17  
    18  type selectType int
    19  
    20  const (
    21  	selectGroups selectType = iota
    22  	selectCountGroups
    23  )
    24  
    25  type groupTeam struct {
    26  	model.GroupSyncable
    27  	TeamId string `db:"TeamId"`
    28  }
    29  
    30  type groupChannel struct {
    31  	model.GroupSyncable
    32  	ChannelId string `db:"ChannelId"`
    33  }
    34  
    35  type groupTeamJoin struct {
    36  	groupTeam
    37  	TeamDisplayName string `db:"TeamDisplayName"`
    38  	TeamType        string `db:"TeamType"`
    39  }
    40  
    41  type groupChannelJoin struct {
    42  	groupChannel
    43  	ChannelDisplayName string `db:"ChannelDisplayName"`
    44  	TeamDisplayName    string `db:"TeamDisplayName"`
    45  	TeamType           string `db:"TeamType"`
    46  	ChannelType        string `db:"ChannelType"`
    47  	TeamID             string `db:"TeamId"`
    48  }
    49  
    50  type SqlGroupStore struct {
    51  	*SqlStore
    52  }
    53  
    54  func newSqlGroupStore(sqlStore *SqlStore) store.GroupStore {
    55  	s := &SqlGroupStore{SqlStore: sqlStore}
    56  	for _, db := range sqlStore.GetAllConns() {
    57  		groups := db.AddTableWithName(model.Group{}, "UserGroups").SetKeys(false, "Id")
    58  		groups.ColMap("Id").SetMaxSize(26)
    59  		groups.ColMap("Name").SetMaxSize(model.GroupNameMaxLength).SetUnique(true)
    60  		groups.ColMap("DisplayName").SetMaxSize(model.GroupDisplayNameMaxLength)
    61  		groups.ColMap("Description").SetMaxSize(model.GroupDescriptionMaxLength)
    62  		groups.ColMap("Source").SetMaxSize(model.GroupSourceMaxLength)
    63  		groups.ColMap("RemoteId").SetMaxSize(model.GroupRemoteIDMaxLength)
    64  		groups.SetUniqueTogether("Source", "RemoteId")
    65  
    66  		groupMembers := db.AddTableWithName(model.GroupMember{}, "GroupMembers").SetKeys(false, "GroupId", "UserId")
    67  		groupMembers.ColMap("GroupId").SetMaxSize(26)
    68  		groupMembers.ColMap("UserId").SetMaxSize(26)
    69  
    70  		groupTeams := db.AddTableWithName(groupTeam{}, "GroupTeams").SetKeys(false, "GroupId", "TeamId")
    71  		groupTeams.ColMap("GroupId").SetMaxSize(26)
    72  		groupTeams.ColMap("TeamId").SetMaxSize(26)
    73  
    74  		groupChannels := db.AddTableWithName(groupChannel{}, "GroupChannels").SetKeys(false, "GroupId", "ChannelId")
    75  		groupChannels.ColMap("GroupId").SetMaxSize(26)
    76  		groupChannels.ColMap("ChannelId").SetMaxSize(26)
    77  	}
    78  	return s
    79  }
    80  
    81  func (s *SqlGroupStore) createIndexesIfNotExists() {
    82  	s.CreateIndexIfNotExists("idx_groupmembers_create_at", "GroupMembers", "CreateAt")
    83  	s.CreateIndexIfNotExists("idx_usergroups_remote_id", "UserGroups", "RemoteId")
    84  	s.CreateIndexIfNotExists("idx_usergroups_delete_at", "UserGroups", "DeleteAt")
    85  	s.CreateIndexIfNotExists("idx_groupteams_teamid", "GroupTeams", "TeamId")
    86  	s.CreateIndexIfNotExists("idx_groupchannels_channelid", "GroupChannels", "ChannelId")
    87  	s.CreateColumnIfNotExistsNoDefault("Channels", "GroupConstrained", "tinyint(1)", "boolean")
    88  	s.CreateColumnIfNotExistsNoDefault("Teams", "GroupConstrained", "tinyint(1)", "boolean")
    89  	s.CreateIndexIfNotExists("idx_groupteams_schemeadmin", "GroupTeams", "SchemeAdmin")
    90  	s.CreateIndexIfNotExists("idx_groupchannels_schemeadmin", "GroupChannels", "SchemeAdmin")
    91  }
    92  
    93  func (s *SqlGroupStore) Create(group *model.Group) (*model.Group, error) {
    94  	if group.Id != "" {
    95  		return nil, store.NewErrInvalidInput("Group", "id", group.Id)
    96  	}
    97  
    98  	if err := group.IsValidForCreate(); err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	group.Id = model.NewId()
   103  	group.CreateAt = model.GetMillis()
   104  	group.UpdateAt = group.CreateAt
   105  
   106  	if err := s.GetMaster().Insert(group); err != nil {
   107  		if IsUniqueConstraintError(err, []string{"Name", "groups_name_key"}) {
   108  			return nil, errors.Wrapf(err, "Group with name %s already exists", *group.Name)
   109  		}
   110  		return nil, errors.Wrap(err, "failed to save Group")
   111  	}
   112  
   113  	return group, nil
   114  }
   115  
   116  func (s *SqlGroupStore) Get(groupId string) (*model.Group, error) {
   117  	var group *model.Group
   118  	if err := s.GetReplica().SelectOne(&group, "SELECT * from UserGroups WHERE Id = :Id", map[string]interface{}{"Id": groupId}); err != nil {
   119  		if err == sql.ErrNoRows {
   120  			return nil, store.NewErrNotFound("Group", groupId)
   121  		}
   122  		return nil, errors.Wrapf(err, "failed to get Group with id=%s", groupId)
   123  	}
   124  
   125  	return group, nil
   126  }
   127  
   128  func (s *SqlGroupStore) GetByName(name string, opts model.GroupSearchOpts) (*model.Group, error) {
   129  	var group *model.Group
   130  	query := s.getQueryBuilder().Select("*").From("UserGroups").Where(sq.Eq{"Name": name})
   131  	if opts.FilterAllowReference {
   132  		query = query.Where("AllowReference = true")
   133  	}
   134  
   135  	queryString, args, err := query.ToSql()
   136  
   137  	if err != nil {
   138  		return nil, errors.Wrap(err, "get_by_name_tosql")
   139  	}
   140  	if err := s.GetReplica().SelectOne(&group, queryString, args...); err != nil {
   141  		if err == sql.ErrNoRows {
   142  			return nil, store.NewErrNotFound("Group", fmt.Sprintf("name=%s", name))
   143  		}
   144  		return nil, errors.Wrapf(err, "failed to get Group with name=%s", name)
   145  	}
   146  
   147  	return group, nil
   148  }
   149  
   150  func (s *SqlGroupStore) GetByIDs(groupIDs []string) ([]*model.Group, error) {
   151  	var groups []*model.Group
   152  	query := s.getQueryBuilder().Select("*").From("UserGroups").Where(sq.Eq{"Id": groupIDs})
   153  	queryString, args, err := query.ToSql()
   154  	if err != nil {
   155  		return nil, errors.Wrap(err, "get_by_ids_tosql")
   156  	}
   157  	if _, err := s.GetReplica().Select(&groups, queryString, args...); err != nil {
   158  		return nil, errors.Wrap(err, "failed to find Groups by ids")
   159  	}
   160  	return groups, nil
   161  }
   162  
   163  func (s *SqlGroupStore) GetByRemoteID(remoteID string, groupSource model.GroupSource) (*model.Group, error) {
   164  	var group *model.Group
   165  	if err := s.GetReplica().SelectOne(&group, "SELECT * from UserGroups WHERE RemoteId = :RemoteId AND Source = :Source", map[string]interface{}{"RemoteId": remoteID, "Source": groupSource}); err != nil {
   166  		if err == sql.ErrNoRows {
   167  			return nil, store.NewErrNotFound("Group", fmt.Sprintf("remoteId=%s", remoteID))
   168  		}
   169  		return nil, errors.Wrapf(err, "failed to get Group with remoteId=%s", remoteID)
   170  	}
   171  
   172  	return group, nil
   173  }
   174  
   175  func (s *SqlGroupStore) GetAllBySource(groupSource model.GroupSource) ([]*model.Group, error) {
   176  	var groups []*model.Group
   177  
   178  	if _, err := s.GetReplica().Select(&groups, "SELECT * from UserGroups WHERE DeleteAt = 0 AND Source = :Source", map[string]interface{}{"Source": groupSource}); err != nil {
   179  		return nil, errors.Wrapf(err, "failed to find Groups by groupSource=%v", groupSource)
   180  	}
   181  
   182  	return groups, nil
   183  }
   184  
   185  func (s *SqlGroupStore) GetByUser(userId string) ([]*model.Group, error) {
   186  	var groups []*model.Group
   187  
   188  	query := `
   189  		SELECT
   190  			UserGroups.*
   191  		FROM
   192  			GroupMembers
   193  			JOIN UserGroups ON UserGroups.Id = GroupMembers.GroupId
   194  		WHERE
   195  			GroupMembers.DeleteAt = 0
   196  			AND UserId = :UserId`
   197  
   198  	if _, err := s.GetReplica().Select(&groups, query, map[string]interface{}{"UserId": userId}); err != nil {
   199  		return nil, errors.Wrapf(err, "failed to find Groups with userId=%s", userId)
   200  	}
   201  
   202  	return groups, nil
   203  }
   204  
   205  func (s *SqlGroupStore) Update(group *model.Group) (*model.Group, error) {
   206  	var retrievedGroup *model.Group
   207  	if err := s.GetReplica().SelectOne(&retrievedGroup, "SELECT * FROM UserGroups WHERE Id = :Id", map[string]interface{}{"Id": group.Id}); err != nil {
   208  		if err == sql.ErrNoRows {
   209  			return nil, store.NewErrNotFound("Group", group.Id)
   210  		}
   211  		return nil, errors.Wrapf(err, "failed to get Group with id=%s", group.Id)
   212  	}
   213  
   214  	// If updating DeleteAt it can only be to 0
   215  	if group.DeleteAt != retrievedGroup.DeleteAt && group.DeleteAt != 0 {
   216  		return nil, errors.New("DeleteAt should be 0 when updating")
   217  	}
   218  
   219  	// Reset these properties, don't update them based on input
   220  	group.CreateAt = retrievedGroup.CreateAt
   221  	group.UpdateAt = model.GetMillis()
   222  
   223  	if err := group.IsValidForUpdate(); err != nil {
   224  		return nil, err
   225  	}
   226  
   227  	rowsChanged, err := s.GetMaster().Update(group)
   228  	if err != nil {
   229  		if IsUniqueConstraintError(err, []string{"Name", "groups_name_key"}) {
   230  			return nil, errors.Wrapf(err, "Group with name %s already exists", *group.Name)
   231  		}
   232  		return nil, errors.Wrap(err, "failed to update Group")
   233  	}
   234  	if rowsChanged > 1 {
   235  		return nil, errors.Wrapf(err, "multiple Groups were update: %d", rowsChanged)
   236  	}
   237  
   238  	return group, nil
   239  }
   240  
   241  func (s *SqlGroupStore) Delete(groupID string) (*model.Group, error) {
   242  	var group *model.Group
   243  	if err := s.GetReplica().SelectOne(&group, "SELECT * from UserGroups WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": groupID}); err != nil {
   244  		if err == sql.ErrNoRows {
   245  			return nil, store.NewErrNotFound("Group", groupID)
   246  		}
   247  		return nil, errors.Wrapf(err, "failed to get Group with id=%s", groupID)
   248  	}
   249  
   250  	time := model.GetMillis()
   251  	group.DeleteAt = time
   252  	group.UpdateAt = time
   253  
   254  	if _, err := s.GetMaster().Update(group); err != nil {
   255  		return nil, errors.Wrapf(err, "failed to update Group with id=%s", groupID)
   256  	}
   257  
   258  	return group, nil
   259  }
   260  
   261  func (s *SqlGroupStore) GetMemberUsers(groupID string) ([]*model.User, error) {
   262  	var groupMembers []*model.User
   263  
   264  	query := `
   265  		SELECT
   266  			Users.*
   267  		FROM
   268  			GroupMembers
   269  			JOIN Users ON Users.Id = GroupMembers.UserId
   270  		WHERE
   271  			GroupMembers.DeleteAt = 0
   272  			AND Users.DeleteAt = 0
   273  			AND GroupId = :GroupId`
   274  
   275  	if _, err := s.GetReplica().Select(&groupMembers, query, map[string]interface{}{"GroupId": groupID}); err != nil {
   276  		return nil, errors.Wrapf(err, "failed to find member Users for Group with id=%s", groupID)
   277  	}
   278  
   279  	return groupMembers, nil
   280  }
   281  
   282  func (s *SqlGroupStore) GetMemberUsersPage(groupID string, page int, perPage int) ([]*model.User, error) {
   283  	var groupMembers []*model.User
   284  
   285  	query := `
   286  		SELECT
   287  			Users.*
   288  		FROM
   289  			GroupMembers
   290  			JOIN Users ON Users.Id = GroupMembers.UserId
   291  		WHERE
   292  			GroupMembers.DeleteAt = 0
   293  			AND Users.DeleteAt = 0
   294  			AND GroupId = :GroupId
   295  		ORDER BY
   296  			GroupMembers.CreateAt DESC
   297  		LIMIT
   298  			:Limit
   299  		OFFSET
   300  			:Offset`
   301  
   302  	if _, err := s.GetReplica().Select(&groupMembers, query, map[string]interface{}{"GroupId": groupID, "Limit": perPage, "Offset": page * perPage}); err != nil {
   303  		return nil, errors.Wrapf(err, "failed to find member Users for Group with id=%s", groupID)
   304  	}
   305  
   306  	return groupMembers, nil
   307  }
   308  
   309  func (s *SqlGroupStore) GetMemberCount(groupID string) (int64, error) {
   310  	query := `
   311  		SELECT
   312  			count(*)
   313  		FROM
   314  			GroupMembers
   315  			JOIN Users ON Users.Id = GroupMembers.UserId
   316  		WHERE
   317  			GroupMembers.GroupId = :GroupId
   318  			AND Users.DeleteAt = 0`
   319  
   320  	count, err := s.GetReplica().SelectInt(query, map[string]interface{}{"GroupId": groupID})
   321  	if err != nil {
   322  		return int64(0), errors.Wrapf(err, "failed to count member Users for Group with id=%s", groupID)
   323  	}
   324  
   325  	return count, nil
   326  }
   327  
   328  func (s *SqlGroupStore) GetMemberUsersInTeam(groupID string, teamID string) ([]*model.User, error) {
   329  	var groupMembers []*model.User
   330  
   331  	query := `
   332  		SELECT
   333  			Users.*
   334  		FROM
   335  			GroupMembers
   336  			JOIN Users ON Users.Id = GroupMembers.UserId
   337  		WHERE
   338  			GroupId = :GroupId
   339  			AND GroupMembers.UserId IN (
   340  				SELECT TeamMembers.UserId
   341  				FROM TeamMembers
   342  				JOIN Teams ON Teams.Id = :TeamId
   343  				WHERE TeamMembers.TeamId = Teams.Id
   344  				AND TeamMembers.DeleteAt = 0
   345  			)
   346  			AND GroupMembers.DeleteAt = 0
   347  			AND Users.DeleteAt = 0
   348  		`
   349  
   350  	if _, err := s.GetReplica().Select(&groupMembers, query, map[string]interface{}{"GroupId": groupID, "TeamId": teamID}); err != nil {
   351  		return nil, errors.Wrapf(err, "failed to member Users for groupId=%s and teamId=%s", groupID, teamID)
   352  	}
   353  
   354  	return groupMembers, nil
   355  }
   356  
   357  func (s *SqlGroupStore) GetMemberUsersNotInChannel(groupID string, channelID string) ([]*model.User, error) {
   358  	var groupMembers []*model.User
   359  
   360  	query := `
   361  		SELECT
   362  			Users.*
   363  		FROM
   364  			GroupMembers
   365  			JOIN Users ON Users.Id = GroupMembers.UserId
   366  		WHERE
   367  			GroupId = :GroupId
   368  			AND GroupMembers.UserId NOT IN (
   369  				SELECT ChannelMembers.UserId
   370  				FROM ChannelMembers
   371  				WHERE ChannelMembers.ChannelId = :ChannelId
   372  			)
   373  			AND GroupMembers.UserId IN (
   374  				SELECT TeamMembers.UserId
   375  				FROM TeamMembers
   376  				JOIN Channels ON Channels.Id = :ChannelId
   377  				JOIN Teams ON Teams.Id = Channels.TeamId
   378  				WHERE TeamMembers.TeamId = Teams.Id
   379  				AND TeamMembers.DeleteAt = 0
   380  			)
   381  			AND GroupMembers.DeleteAt = 0
   382  			AND Users.DeleteAt = 0
   383  		`
   384  
   385  	if _, err := s.GetReplica().Select(&groupMembers, query, map[string]interface{}{"GroupId": groupID, "ChannelId": channelID}); err != nil {
   386  		return nil, errors.Wrapf(err, "failed to member Users for groupId=%s and channelId!=%s", groupID, channelID)
   387  	}
   388  
   389  	return groupMembers, nil
   390  }
   391  
   392  func (s *SqlGroupStore) UpsertMember(groupID string, userID string) (*model.GroupMember, error) {
   393  	member := &model.GroupMember{
   394  		GroupId:  groupID,
   395  		UserId:   userID,
   396  		CreateAt: model.GetMillis(),
   397  		DeleteAt: 0,
   398  	}
   399  
   400  	if err := member.IsValid(); err != nil {
   401  		return nil, err
   402  	}
   403  
   404  	var retrievedGroup *model.Group
   405  	if err := s.GetReplica().SelectOne(&retrievedGroup, "SELECT * FROM UserGroups WHERE Id = :Id", map[string]interface{}{"Id": groupID}); err != nil {
   406  		return nil, errors.Wrapf(err, "failed to get UserGroup with groupId=%s and userId=%s", groupID, userID)
   407  	}
   408  
   409  	query := s.getQueryBuilder().
   410  		Insert("GroupMembers").
   411  		Columns("GroupId", "UserId", "CreateAt", "DeleteAt").
   412  		Values(member.GroupId, member.UserId, member.CreateAt, member.DeleteAt)
   413  
   414  	if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
   415  		query = query.SuffixExpr(sq.Expr("ON DUPLICATE KEY UPDATE CreateAt = ?, DeleteAt = ?", member.CreateAt, member.DeleteAt))
   416  	} else if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   417  		query = query.SuffixExpr(sq.Expr("ON CONFLICT (groupid, userid) DO UPDATE SET CreateAt = ?, DeleteAt = ?", member.CreateAt, member.DeleteAt))
   418  	}
   419  
   420  	queryString, args, err := query.ToSql()
   421  	if err != nil {
   422  		return nil, errors.Wrap(err, "failed to generate sqlquery")
   423  	}
   424  
   425  	if _, err = s.GetMaster().Exec(queryString, args...); err != nil {
   426  		return nil, errors.Wrap(err, "failed to save GroupMember")
   427  	}
   428  	return member, nil
   429  }
   430  
   431  func (s *SqlGroupStore) DeleteMember(groupID string, userID string) (*model.GroupMember, error) {
   432  	var retrievedMember *model.GroupMember
   433  	if err := s.GetReplica().SelectOne(&retrievedMember, "SELECT * FROM GroupMembers WHERE GroupId = :GroupId AND UserId = :UserId AND DeleteAt = 0", map[string]interface{}{"GroupId": groupID, "UserId": userID}); err != nil {
   434  		if err == sql.ErrNoRows {
   435  			return nil, store.NewErrNotFound("GroupMember", fmt.Sprintf("groupId=%s, userId=%s", groupID, userID))
   436  		}
   437  		return nil, errors.Wrapf(err, "failed to get GroupMember with groupId=%s and userId=%s", groupID, userID)
   438  	}
   439  
   440  	retrievedMember.DeleteAt = model.GetMillis()
   441  
   442  	if _, err := s.GetMaster().Update(retrievedMember); err != nil {
   443  		return nil, errors.Wrapf(err, "failed to update GroupMember with groupId=%s and userId=%s", groupID, userID)
   444  	}
   445  
   446  	return retrievedMember, nil
   447  }
   448  
   449  func (s *SqlGroupStore) PermanentDeleteMembersByUser(userId string) error {
   450  	if _, err := s.GetMaster().Exec("DELETE FROM GroupMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
   451  		return errors.Wrapf(err, "failed to permanent delete GroupMember with userId=%s", userId)
   452  	}
   453  	return nil
   454  }
   455  
   456  func (s *SqlGroupStore) CreateGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, error) {
   457  	if err := groupSyncable.IsValid(); err != nil {
   458  		return nil, err
   459  	}
   460  
   461  	// Reset values that shouldn't be updatable by parameter
   462  	groupSyncable.DeleteAt = 0
   463  	groupSyncable.CreateAt = model.GetMillis()
   464  	groupSyncable.UpdateAt = groupSyncable.CreateAt
   465  
   466  	var insertErr error
   467  
   468  	switch groupSyncable.Type {
   469  	case model.GroupSyncableTypeTeam:
   470  		if _, err := s.Team().Get(groupSyncable.SyncableId); err != nil {
   471  			return nil, err
   472  		}
   473  
   474  		insertErr = s.GetMaster().Insert(groupSyncableToGroupTeam(groupSyncable))
   475  	case model.GroupSyncableTypeChannel:
   476  		var channel *model.Channel
   477  		channel, err := s.Channel().Get(groupSyncable.SyncableId, false)
   478  		if err != nil {
   479  			return nil, err
   480  		}
   481  		insertErr = s.GetMaster().Insert(groupSyncableToGroupChannel(groupSyncable))
   482  		groupSyncable.TeamID = channel.TeamId
   483  	default:
   484  		return nil, fmt.Errorf("invalid GroupSyncableType: %s", groupSyncable.Type)
   485  	}
   486  
   487  	if insertErr != nil {
   488  		return nil, errors.Wrap(insertErr, "unable to insert GroupSyncable")
   489  	}
   490  
   491  	return groupSyncable, nil
   492  }
   493  
   494  func (s *SqlGroupStore) GetGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, error) {
   495  	groupSyncable, err := s.getGroupSyncable(groupID, syncableID, syncableType)
   496  	if err != nil {
   497  		if err == sql.ErrNoRows {
   498  			return nil, store.NewErrNotFound("GroupSyncable", fmt.Sprintf("groupId=%s, syncableId=%s, syncableType=%s", groupID, syncableID, syncableType))
   499  		}
   500  		return nil, errors.Wrapf(err, "failed to find GroupSyncable with groupId=%s, syncableId=%s, syncableType=%s", groupID, syncableID, syncableType)
   501  	}
   502  
   503  	return groupSyncable, nil
   504  }
   505  
   506  func (s *SqlGroupStore) getGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, error) {
   507  	var err error
   508  	var result interface{}
   509  
   510  	switch syncableType {
   511  	case model.GroupSyncableTypeTeam:
   512  		result, err = s.GetReplica().Get(groupTeam{}, groupID, syncableID)
   513  	case model.GroupSyncableTypeChannel:
   514  		result, err = s.GetReplica().Get(groupChannel{}, groupID, syncableID)
   515  	}
   516  
   517  	if err != nil {
   518  		return nil, err
   519  	}
   520  
   521  	if result == nil {
   522  		return nil, sql.ErrNoRows
   523  	}
   524  
   525  	groupSyncable := model.GroupSyncable{}
   526  	switch syncableType {
   527  	case model.GroupSyncableTypeTeam:
   528  		groupTeam := result.(*groupTeam)
   529  		groupSyncable.SyncableId = groupTeam.TeamId
   530  		groupSyncable.GroupId = groupTeam.GroupId
   531  		groupSyncable.AutoAdd = groupTeam.AutoAdd
   532  		groupSyncable.CreateAt = groupTeam.CreateAt
   533  		groupSyncable.DeleteAt = groupTeam.DeleteAt
   534  		groupSyncable.UpdateAt = groupTeam.UpdateAt
   535  		groupSyncable.Type = syncableType
   536  	case model.GroupSyncableTypeChannel:
   537  		groupChannel := result.(*groupChannel)
   538  		groupSyncable.SyncableId = groupChannel.ChannelId
   539  		groupSyncable.GroupId = groupChannel.GroupId
   540  		groupSyncable.AutoAdd = groupChannel.AutoAdd
   541  		groupSyncable.CreateAt = groupChannel.CreateAt
   542  		groupSyncable.DeleteAt = groupChannel.DeleteAt
   543  		groupSyncable.UpdateAt = groupChannel.UpdateAt
   544  		groupSyncable.Type = syncableType
   545  	default:
   546  		return nil, fmt.Errorf("unable to convert syncableType: %s", syncableType.String())
   547  	}
   548  
   549  	return &groupSyncable, nil
   550  }
   551  
   552  func (s *SqlGroupStore) GetAllGroupSyncablesByGroupId(groupID string, syncableType model.GroupSyncableType) ([]*model.GroupSyncable, error) {
   553  	args := map[string]interface{}{"GroupId": groupID}
   554  
   555  	groupSyncables := []*model.GroupSyncable{}
   556  
   557  	switch syncableType {
   558  	case model.GroupSyncableTypeTeam:
   559  		sqlQuery := `
   560  			SELECT
   561  				GroupTeams.*,
   562  				Teams.DisplayName AS TeamDisplayName,
   563  				Teams.Type AS TeamType
   564  			FROM
   565  				GroupTeams
   566  				JOIN Teams ON Teams.Id = GroupTeams.TeamId
   567  			WHERE
   568  				GroupId = :GroupId AND GroupTeams.DeleteAt = 0`
   569  
   570  		results := []*groupTeamJoin{}
   571  		_, err := s.GetReplica().Select(&results, sqlQuery, args)
   572  		if err != nil {
   573  			return nil, errors.Wrapf(err, "failed to find GroupTeams with groupId=%s", groupID)
   574  		}
   575  		for _, result := range results {
   576  			groupSyncable := &model.GroupSyncable{
   577  				SyncableId:      result.TeamId,
   578  				GroupId:         result.GroupId,
   579  				AutoAdd:         result.AutoAdd,
   580  				CreateAt:        result.CreateAt,
   581  				DeleteAt:        result.DeleteAt,
   582  				UpdateAt:        result.UpdateAt,
   583  				Type:            syncableType,
   584  				TeamDisplayName: result.TeamDisplayName,
   585  				TeamType:        result.TeamType,
   586  				SchemeAdmin:     result.SchemeAdmin,
   587  			}
   588  			groupSyncables = append(groupSyncables, groupSyncable)
   589  		}
   590  	case model.GroupSyncableTypeChannel:
   591  		sqlQuery := `
   592  			SELECT
   593  				GroupChannels.*,
   594  				Channels.DisplayName AS ChannelDisplayName,
   595  				Teams.DisplayName AS TeamDisplayName,
   596  				Channels.Type As ChannelType,
   597  				Teams.Type As TeamType,
   598  				Teams.Id AS TeamId
   599  			FROM
   600  				GroupChannels
   601  				JOIN Channels ON Channels.Id = GroupChannels.ChannelId
   602  				JOIN Teams ON Teams.Id = Channels.TeamId
   603  			WHERE
   604  				GroupId = :GroupId AND GroupChannels.DeleteAt = 0`
   605  
   606  		results := []*groupChannelJoin{}
   607  		_, err := s.GetReplica().Select(&results, sqlQuery, args)
   608  		if err != nil {
   609  			return nil, errors.Wrapf(err, "failed to find GroupChannels with groupId=%s", groupID)
   610  		}
   611  		for _, result := range results {
   612  			groupSyncable := &model.GroupSyncable{
   613  				SyncableId:         result.ChannelId,
   614  				GroupId:            result.GroupId,
   615  				AutoAdd:            result.AutoAdd,
   616  				CreateAt:           result.CreateAt,
   617  				DeleteAt:           result.DeleteAt,
   618  				UpdateAt:           result.UpdateAt,
   619  				Type:               syncableType,
   620  				ChannelDisplayName: result.ChannelDisplayName,
   621  				ChannelType:        result.ChannelType,
   622  				TeamDisplayName:    result.TeamDisplayName,
   623  				TeamType:           result.TeamType,
   624  				TeamID:             result.TeamID,
   625  				SchemeAdmin:        result.SchemeAdmin,
   626  			}
   627  			groupSyncables = append(groupSyncables, groupSyncable)
   628  		}
   629  	}
   630  
   631  	return groupSyncables, nil
   632  }
   633  
   634  func (s *SqlGroupStore) UpdateGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, error) {
   635  	retrievedGroupSyncable, err := s.getGroupSyncable(groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type)
   636  	if err != nil {
   637  		if err == sql.ErrNoRows {
   638  			return nil, errors.Wrap(store.NewErrNotFound("GroupSyncable", fmt.Sprintf("groupId=%s, syncableId=%s, syncableType=%s", groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type)), "GroupSyncable not found")
   639  		}
   640  		return nil, errors.Wrapf(err, "failed to find GroupSyncable with groupId=%s, syncableId=%s, syncableType=%s", groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type)
   641  	}
   642  
   643  	if err := groupSyncable.IsValid(); err != nil {
   644  		return nil, err
   645  	}
   646  
   647  	// If updating DeleteAt it can only be to 0
   648  	if groupSyncable.DeleteAt != retrievedGroupSyncable.DeleteAt && groupSyncable.DeleteAt != 0 {
   649  		return nil, errors.New("DeleteAt should be 0 when updating")
   650  	}
   651  
   652  	// Reset these properties, don't update them based on input
   653  	groupSyncable.CreateAt = retrievedGroupSyncable.CreateAt
   654  	groupSyncable.UpdateAt = model.GetMillis()
   655  
   656  	switch groupSyncable.Type {
   657  	case model.GroupSyncableTypeTeam:
   658  		_, err = s.GetMaster().Update(groupSyncableToGroupTeam(groupSyncable))
   659  	case model.GroupSyncableTypeChannel:
   660  		// We need to get the TeamId so redux can manage channels when teams are unlinked
   661  		var channel *model.Channel
   662  		channel, channelErr := s.Channel().Get(groupSyncable.SyncableId, false)
   663  		if channelErr != nil {
   664  			return nil, channelErr
   665  		}
   666  
   667  		_, err = s.GetMaster().Update(groupSyncableToGroupChannel(groupSyncable))
   668  
   669  		groupSyncable.TeamID = channel.TeamId
   670  	default:
   671  		return nil, fmt.Errorf("invalid GroupSyncableType: %s", groupSyncable.Type)
   672  	}
   673  
   674  	if err != nil {
   675  		return nil, errors.Wrap(err, "failed to update GroupSyncable")
   676  	}
   677  
   678  	return groupSyncable, nil
   679  }
   680  
   681  func (s *SqlGroupStore) DeleteGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, error) {
   682  	groupSyncable, err := s.getGroupSyncable(groupID, syncableID, syncableType)
   683  	if err != nil {
   684  		if err == sql.ErrNoRows {
   685  			return nil, store.NewErrNotFound("GroupSyncable", fmt.Sprintf("groupId=%s, syncableId=%s, syncableType=%s", groupID, syncableID, syncableType))
   686  		}
   687  		return nil, errors.Wrapf(err, "failed to find GroupSyncable with groupId=%s, syncableId=%s, syncableType=%s", groupID, syncableID, syncableType)
   688  	}
   689  
   690  	if groupSyncable.DeleteAt != 0 {
   691  		return nil, store.NewErrInvalidInput("GroupSyncable", "<groupId, syncableId, syncableType>", fmt.Sprintf("<%s, %s, %s>", groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type))
   692  	}
   693  
   694  	time := model.GetMillis()
   695  	groupSyncable.DeleteAt = time
   696  	groupSyncable.UpdateAt = time
   697  
   698  	switch groupSyncable.Type {
   699  	case model.GroupSyncableTypeTeam:
   700  		_, err = s.GetMaster().Update(groupSyncableToGroupTeam(groupSyncable))
   701  	case model.GroupSyncableTypeChannel:
   702  		_, err = s.GetMaster().Update(groupSyncableToGroupChannel(groupSyncable))
   703  	default:
   704  		return nil, fmt.Errorf("invalid GroupSyncableType: %s", groupSyncable.Type)
   705  	}
   706  
   707  	if err != nil {
   708  		return nil, errors.Wrap(err, "failed to update GroupSyncable")
   709  	}
   710  
   711  	return groupSyncable, nil
   712  }
   713  
   714  func (s *SqlGroupStore) TeamMembersToAdd(since int64, teamID *string, includeRemovedMembers bool) ([]*model.UserTeamIDPair, error) {
   715  	builder := s.getQueryBuilder().Select("GroupMembers.UserId", "GroupTeams.TeamId").
   716  		From("GroupMembers").
   717  		Join("GroupTeams ON GroupTeams.GroupId = GroupMembers.GroupId").
   718  		Join("UserGroups ON UserGroups.Id = GroupMembers.GroupId").
   719  		Join("Teams ON Teams.Id = GroupTeams.TeamId").
   720  		Where(sq.Eq{
   721  			"UserGroups.DeleteAt":   0,
   722  			"GroupTeams.DeleteAt":   0,
   723  			"GroupTeams.AutoAdd":    true,
   724  			"GroupMembers.DeleteAt": 0,
   725  			"Teams.DeleteAt":        0,
   726  		})
   727  
   728  	if !includeRemovedMembers {
   729  		builder = builder.
   730  			JoinClause("LEFT OUTER JOIN TeamMembers ON TeamMembers.TeamId = GroupTeams.TeamId AND TeamMembers.UserId = GroupMembers.UserId").
   731  			Where(sq.Eq{"TeamMembers.UserId": nil}).
   732  			Where(sq.Or{
   733  				sq.GtOrEq{"GroupMembers.CreateAt": since},
   734  				sq.GtOrEq{"GroupTeams.UpdateAt": since},
   735  			})
   736  	}
   737  	if teamID != nil {
   738  		builder = builder.Where(sq.Eq{"Teams.Id": *teamID})
   739  	}
   740  
   741  	query, params, err := builder.ToSql()
   742  	if err != nil {
   743  		return nil, errors.Wrap(err, "team_members_to_add_tosql")
   744  	}
   745  
   746  	var teamMembers []*model.UserTeamIDPair
   747  
   748  	_, err = s.GetMaster().Select(&teamMembers, query, params...)
   749  	if err != nil {
   750  		return nil, errors.Wrap(err, "failed to find UserTeamIDPairs")
   751  	}
   752  
   753  	return teamMembers, nil
   754  }
   755  
   756  func (s *SqlGroupStore) ChannelMembersToAdd(since int64, channelID *string, includeRemovedMembers bool) ([]*model.UserChannelIDPair, error) {
   757  	builder := s.getQueryBuilder().Select("GroupMembers.UserId", "GroupChannels.ChannelId").
   758  		From("GroupMembers").
   759  		Join("GroupChannels ON GroupChannels.GroupId = GroupMembers.GroupId").
   760  		Join("UserGroups ON UserGroups.Id = GroupMembers.GroupId").
   761  		Join("Channels ON Channels.Id = GroupChannels.ChannelId").
   762  		Where(sq.Eq{
   763  			"UserGroups.DeleteAt":    0,
   764  			"GroupChannels.DeleteAt": 0,
   765  			"GroupChannels.AutoAdd":  true,
   766  			"GroupMembers.DeleteAt":  0,
   767  			"Channels.DeleteAt":      0,
   768  		})
   769  
   770  	if !includeRemovedMembers {
   771  		builder = builder.
   772  			JoinClause("LEFT OUTER JOIN ChannelMemberHistory ON ChannelMemberHistory.ChannelId = GroupChannels.ChannelId AND ChannelMemberHistory.UserId = GroupMembers.UserId").
   773  			Where(sq.Eq{
   774  				"ChannelMemberHistory.UserId":    nil,
   775  				"ChannelMemberHistory.LeaveTime": nil,
   776  			}).
   777  			Where(sq.Or{
   778  				sq.GtOrEq{"GroupMembers.CreateAt": since},
   779  				sq.GtOrEq{"GroupChannels.UpdateAt": since},
   780  			})
   781  	}
   782  	if channelID != nil {
   783  		builder = builder.Where(sq.Eq{"Channels.Id": *channelID})
   784  	}
   785  
   786  	query, params, err := builder.ToSql()
   787  	if err != nil {
   788  		return nil, errors.Wrap(err, "channel_members_to_add_tosql")
   789  	}
   790  
   791  	var channelMembers []*model.UserChannelIDPair
   792  
   793  	_, err = s.GetMaster().Select(&channelMembers, query, params...)
   794  	if err != nil {
   795  		return nil, errors.Wrap(err, "failed to find UserChannelIDPairs")
   796  	}
   797  
   798  	return channelMembers, nil
   799  }
   800  
   801  func groupSyncableToGroupTeam(groupSyncable *model.GroupSyncable) *groupTeam {
   802  	return &groupTeam{
   803  		GroupSyncable: *groupSyncable,
   804  		TeamId:        groupSyncable.SyncableId,
   805  	}
   806  }
   807  
   808  func groupSyncableToGroupChannel(groupSyncable *model.GroupSyncable) *groupChannel {
   809  	return &groupChannel{
   810  		GroupSyncable: *groupSyncable,
   811  		ChannelId:     groupSyncable.SyncableId,
   812  	}
   813  }
   814  
   815  func (s *SqlGroupStore) TeamMembersToRemove(teamID *string) ([]*model.TeamMember, error) {
   816  	whereStmt := `
   817  		(TeamMembers.TeamId,
   818  			TeamMembers.UserId)
   819  		NOT IN (
   820  			SELECT
   821  				Teams.Id AS TeamId,
   822  				GroupMembers.UserId
   823  			FROM
   824  				Teams
   825  				JOIN GroupTeams ON GroupTeams.TeamId = Teams.Id
   826  				JOIN UserGroups ON UserGroups.Id = GroupTeams.GroupId
   827  				JOIN GroupMembers ON GroupMembers.GroupId = UserGroups.Id
   828  			WHERE
   829  				Teams.GroupConstrained = TRUE
   830  				AND GroupTeams.DeleteAt = 0
   831  				AND UserGroups.DeleteAt = 0
   832  				AND Teams.DeleteAt = 0
   833  				AND GroupMembers.DeleteAt = 0
   834  			GROUP BY
   835  				Teams.Id,
   836  				GroupMembers.UserId)`
   837  
   838  	builder := s.getQueryBuilder().Select(
   839  		"TeamMembers.TeamId",
   840  		"TeamMembers.UserId",
   841  		"TeamMembers.Roles",
   842  		"TeamMembers.DeleteAt",
   843  		"TeamMembers.SchemeUser",
   844  		"TeamMembers.SchemeAdmin",
   845  		"(TeamMembers.SchemeGuest IS NOT NULL AND TeamMembers.SchemeGuest) AS SchemeGuest",
   846  	).
   847  		From("TeamMembers").
   848  		Join("Teams ON Teams.Id = TeamMembers.TeamId").
   849  		LeftJoin("Bots ON Bots.UserId = TeamMembers.UserId").
   850  		Where(sq.Eq{"TeamMembers.DeleteAt": 0, "Teams.DeleteAt": 0, "Teams.GroupConstrained": true, "Bots.UserId": nil}).
   851  		Where(whereStmt)
   852  
   853  	if teamID != nil {
   854  		builder = builder.Where(sq.Eq{"TeamMembers.TeamId": *teamID})
   855  	}
   856  
   857  	query, params, err := builder.ToSql()
   858  	if err != nil {
   859  		return nil, errors.Wrap(err, "team_members_to_remove_tosql")
   860  	}
   861  
   862  	var teamMembers []*model.TeamMember
   863  
   864  	_, err = s.GetReplica().Select(&teamMembers, query, params...)
   865  	if err != nil {
   866  		return nil, errors.Wrap(err, "failed to find TeamMembers")
   867  	}
   868  
   869  	return teamMembers, nil
   870  }
   871  
   872  func (s *SqlGroupStore) CountGroupsByChannel(channelId string, opts model.GroupSearchOpts) (int64, error) {
   873  	countQuery := s.groupsBySyncableBaseQuery(model.GroupSyncableTypeChannel, selectCountGroups, channelId, opts)
   874  
   875  	countQueryString, args, err := countQuery.ToSql()
   876  	if err != nil {
   877  		return int64(0), errors.Wrap(err, "count_groups_by_channel_tosql")
   878  	}
   879  
   880  	count, err := s.GetReplica().SelectInt(countQueryString, args...)
   881  	if err != nil {
   882  		return int64(0), errors.Wrapf(err, "failed to count Groups by channel with channelId=%s", channelId)
   883  	}
   884  
   885  	return count, nil
   886  }
   887  
   888  func (s *SqlGroupStore) GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, error) {
   889  	query := s.groupsBySyncableBaseQuery(model.GroupSyncableTypeChannel, selectGroups, channelId, opts)
   890  
   891  	if opts.PageOpts != nil {
   892  		offset := uint64(opts.PageOpts.Page * opts.PageOpts.PerPage)
   893  		query = query.OrderBy("ug.DisplayName").Limit(uint64(opts.PageOpts.PerPage)).Offset(offset)
   894  	}
   895  
   896  	queryString, args, err := query.ToSql()
   897  	if err != nil {
   898  		return nil, errors.Wrap(err, "get_groups_by_channel_tosql")
   899  	}
   900  
   901  	var groups []*model.GroupWithSchemeAdmin
   902  
   903  	_, err = s.GetReplica().Select(&groups, queryString, args...)
   904  	if err != nil {
   905  		return nil, errors.Wrapf(err, "failed to find Groups with channelId=%s", channelId)
   906  	}
   907  
   908  	return groups, nil
   909  }
   910  
   911  func (s *SqlGroupStore) ChannelMembersToRemove(channelID *string) ([]*model.ChannelMember, error) {
   912  	whereStmt := `
   913  		(ChannelMembers.ChannelId,
   914  			ChannelMembers.UserId)
   915  		NOT IN (
   916  			SELECT
   917  				Channels.Id AS ChannelId,
   918  				GroupMembers.UserId
   919  			FROM
   920  				Channels
   921  				JOIN GroupChannels ON GroupChannels.ChannelId = Channels.Id
   922  				JOIN UserGroups ON UserGroups.Id = GroupChannels.GroupId
   923  				JOIN GroupMembers ON GroupMembers.GroupId = UserGroups.Id
   924  			WHERE
   925  				Channels.GroupConstrained = TRUE
   926  				AND GroupChannels.DeleteAt = 0
   927  				AND UserGroups.DeleteAt = 0
   928  				AND Channels.DeleteAt = 0
   929  				AND GroupMembers.DeleteAt = 0
   930  			GROUP BY
   931  				Channels.Id,
   932  				GroupMembers.UserId)`
   933  
   934  	builder := s.getQueryBuilder().Select(
   935  		"ChannelMembers.ChannelId",
   936  		"ChannelMembers.UserId",
   937  		"ChannelMembers.LastViewedAt",
   938  		"ChannelMembers.MsgCount",
   939  		"ChannelMembers.MsgCountRoot",
   940  		"ChannelMembers.MentionCount",
   941  		"ChannelMembers.MentionCountRoot",
   942  		"ChannelMembers.NotifyProps",
   943  		"ChannelMembers.LastUpdateAt",
   944  		"ChannelMembers.LastUpdateAt",
   945  		"ChannelMembers.SchemeUser",
   946  		"ChannelMembers.SchemeAdmin",
   947  		"(ChannelMembers.SchemeGuest IS NOT NULL AND ChannelMembers.SchemeGuest) AS SchemeGuest",
   948  	).
   949  		From("ChannelMembers").
   950  		Join("Channels ON Channels.Id = ChannelMembers.ChannelId").
   951  		LeftJoin("Bots ON Bots.UserId = ChannelMembers.UserId").
   952  		Where(sq.Eq{"Channels.DeleteAt": 0, "Channels.GroupConstrained": true, "Bots.UserId": nil}).
   953  		Where(whereStmt)
   954  
   955  	if channelID != nil {
   956  		builder = builder.Where(sq.Eq{"ChannelMembers.ChannelId": *channelID})
   957  	}
   958  
   959  	query, params, err := builder.ToSql()
   960  	if err != nil {
   961  		return nil, errors.Wrap(err, "channel_members_to_remove_tosql")
   962  	}
   963  
   964  	var channelMembers []*model.ChannelMember
   965  
   966  	_, err = s.GetReplica().Select(&channelMembers, query, params...)
   967  	if err != nil {
   968  		return nil, errors.Wrap(err, "failed to find ChannelMembers")
   969  	}
   970  
   971  	return channelMembers, nil
   972  }
   973  
   974  func (s *SqlGroupStore) groupsBySyncableBaseQuery(st model.GroupSyncableType, t selectType, syncableID string, opts model.GroupSearchOpts) sq.SelectBuilder {
   975  	selectStrs := map[selectType]string{
   976  		selectGroups:      "ug.*, gs.SchemeAdmin AS SyncableSchemeAdmin",
   977  		selectCountGroups: "COUNT(*)",
   978  	}
   979  
   980  	var table string
   981  	var idCol string
   982  	if st == model.GroupSyncableTypeTeam {
   983  		table = "GroupTeams"
   984  		idCol = "TeamId"
   985  	} else {
   986  		table = "GroupChannels"
   987  		idCol = "ChannelId"
   988  	}
   989  
   990  	query := s.getQueryBuilder().
   991  		Select(selectStrs[t]).
   992  		From(fmt.Sprintf("%s gs", table)).
   993  		LeftJoin("UserGroups ug ON gs.GroupId = ug.Id").
   994  		Where(fmt.Sprintf("ug.DeleteAt = 0 AND gs.%s = ? AND gs.DeleteAt = 0", idCol), syncableID)
   995  
   996  	if opts.IncludeMemberCount && t == selectGroups {
   997  		query = s.getQueryBuilder().
   998  			Select(fmt.Sprintf("ug.*, coalesce(Members.MemberCount, 0) AS MemberCount, Group%ss.SchemeAdmin AS SyncableSchemeAdmin", st)).
   999  			From("UserGroups ug").
  1000  			LeftJoin("(SELECT GroupMembers.GroupId, COUNT(*) AS MemberCount FROM GroupMembers LEFT JOIN Users ON Users.Id = GroupMembers.UserId WHERE GroupMembers.DeleteAt = 0 AND Users.DeleteAt = 0 GROUP BY GroupId) AS Members ON Members.GroupId = ug.Id").
  1001  			LeftJoin(fmt.Sprintf("%[1]s ON %[1]s.GroupId = ug.Id", table)).
  1002  			Where(fmt.Sprintf("ug.DeleteAt = 0 AND %[1]s.DeleteAt = 0 AND %[1]s.%[2]s = ?", table, idCol), syncableID).
  1003  			OrderBy("ug.DisplayName")
  1004  	}
  1005  
  1006  	if opts.FilterAllowReference && t == selectGroups {
  1007  		query = query.Where("ug.AllowReference = true")
  1008  	}
  1009  
  1010  	if opts.Q != "" {
  1011  		pattern := fmt.Sprintf("%%%s%%", sanitizeSearchTerm(opts.Q, "\\"))
  1012  		operatorKeyword := "ILIKE"
  1013  		if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
  1014  			operatorKeyword = "LIKE"
  1015  		}
  1016  		query = query.Where(fmt.Sprintf("(ug.Name %[1]s ? OR ug.DisplayName %[1]s ?)", operatorKeyword), pattern, pattern)
  1017  	}
  1018  
  1019  	return query
  1020  }
  1021  
  1022  func (s *SqlGroupStore) getGroupsAssociatedToChannelsByTeam(teamID string, opts model.GroupSearchOpts) sq.SelectBuilder {
  1023  	query := s.getQueryBuilder().
  1024  		Select("gc.ChannelId, ug.*, gc.SchemeAdmin AS SyncableSchemeAdmin").
  1025  		From("UserGroups ug").
  1026  		LeftJoin(`
  1027  			(SELECT
  1028  				GroupChannels.GroupId, GroupChannels.ChannelId, GroupChannels.DeleteAt, GroupChannels.SchemeAdmin
  1029  			FROM
  1030  				GroupChannels
  1031  			LEFT JOIN
  1032  				Channels ON (Channels.Id = GroupChannels.ChannelId)
  1033  			WHERE
  1034  				GroupChannels.DeleteAt = 0
  1035  				AND Channels.DeleteAt = 0
  1036  				AND Channels.TeamId = ?) AS gc ON gc.GroupId = ug.Id`, teamID).
  1037  		Where("ug.DeleteAt = 0 AND gc.DeleteAt = 0").
  1038  		OrderBy("ug.DisplayName")
  1039  
  1040  	if opts.IncludeMemberCount {
  1041  		query = s.getQueryBuilder().
  1042  			Select("gc.ChannelId, ug.*, coalesce(Members.MemberCount, 0) AS MemberCount, gc.SchemeAdmin AS SyncableSchemeAdmin").
  1043  			From("UserGroups ug").
  1044  			LeftJoin(`
  1045  				(SELECT
  1046  					GroupChannels.ChannelId, GroupChannels.DeleteAt, GroupChannels.GroupId, GroupChannels.SchemeAdmin
  1047  				FROM
  1048  					GroupChannels
  1049  				LEFT JOIN
  1050  					Channels ON (Channels.Id = GroupChannels.ChannelId)
  1051  				WHERE
  1052  					GroupChannels.DeleteAt = 0
  1053  					AND Channels.DeleteAt = 0
  1054  					AND Channels.TeamId = ?) AS gc ON gc.GroupId = ug.Id`, teamID).
  1055  			LeftJoin(`(
  1056  				SELECT
  1057  					GroupMembers.GroupId, COUNT(*) AS MemberCount
  1058  				FROM
  1059  					GroupMembers
  1060  				LEFT JOIN
  1061  					Users ON Users.Id = GroupMembers.UserId
  1062  				WHERE
  1063  					GroupMembers.DeleteAt = 0
  1064  					AND Users.DeleteAt = 0
  1065  				GROUP BY GroupId) AS Members
  1066  			ON Members.GroupId = ug.Id`).
  1067  			Where("ug.DeleteAt = 0 AND gc.DeleteAt = 0").
  1068  			OrderBy("ug.DisplayName")
  1069  	}
  1070  
  1071  	if opts.FilterAllowReference {
  1072  		query = query.Where("ug.AllowReference = true")
  1073  	}
  1074  
  1075  	if opts.Q != "" {
  1076  		pattern := fmt.Sprintf("%%%s%%", sanitizeSearchTerm(opts.Q, "\\"))
  1077  		operatorKeyword := "ILIKE"
  1078  		if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
  1079  			operatorKeyword = "LIKE"
  1080  		}
  1081  		query = query.Where(fmt.Sprintf("(ug.Name %[1]s ? OR ug.DisplayName %[1]s ?)", operatorKeyword), pattern, pattern)
  1082  	}
  1083  
  1084  	return query
  1085  }
  1086  
  1087  func (s *SqlGroupStore) CountGroupsByTeam(teamId string, opts model.GroupSearchOpts) (int64, error) {
  1088  	countQuery := s.groupsBySyncableBaseQuery(model.GroupSyncableTypeTeam, selectCountGroups, teamId, opts)
  1089  
  1090  	countQueryString, args, err := countQuery.ToSql()
  1091  	if err != nil {
  1092  		return int64(0), errors.Wrap(err, "count_groups_by_team_tosql")
  1093  	}
  1094  
  1095  	count, err := s.GetReplica().SelectInt(countQueryString, args...)
  1096  	if err != nil {
  1097  		return int64(0), errors.Wrapf(err, "failed to count Groups with teamId=%s", teamId)
  1098  	}
  1099  
  1100  	return count, nil
  1101  }
  1102  
  1103  func (s *SqlGroupStore) GetGroupsByTeam(teamId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, error) {
  1104  	query := s.groupsBySyncableBaseQuery(model.GroupSyncableTypeTeam, selectGroups, teamId, opts)
  1105  
  1106  	if opts.PageOpts != nil {
  1107  		offset := uint64(opts.PageOpts.Page * opts.PageOpts.PerPage)
  1108  		query = query.OrderBy("ug.DisplayName").Limit(uint64(opts.PageOpts.PerPage)).Offset(offset)
  1109  	}
  1110  
  1111  	queryString, args, err := query.ToSql()
  1112  	if err != nil {
  1113  		return nil, errors.Wrap(err, "get_groups_by_team_tosql")
  1114  	}
  1115  
  1116  	var groups []*model.GroupWithSchemeAdmin
  1117  
  1118  	_, err = s.GetReplica().Select(&groups, queryString, args...)
  1119  	if err != nil {
  1120  		return nil, errors.Wrapf(err, "failed to find Groups with teamId=%s", teamId)
  1121  	}
  1122  
  1123  	return groups, nil
  1124  }
  1125  
  1126  func (s *SqlGroupStore) GetGroupsAssociatedToChannelsByTeam(teamId string, opts model.GroupSearchOpts) (map[string][]*model.GroupWithSchemeAdmin, error) {
  1127  	query := s.getGroupsAssociatedToChannelsByTeam(teamId, opts)
  1128  
  1129  	if opts.PageOpts != nil {
  1130  		offset := uint64(opts.PageOpts.Page * opts.PageOpts.PerPage)
  1131  		query = query.OrderBy("ug.DisplayName").Limit(uint64(opts.PageOpts.PerPage)).Offset(offset)
  1132  	}
  1133  
  1134  	queryString, args, err := query.ToSql()
  1135  	if err != nil {
  1136  		return nil, errors.Wrap(err, "get_groups_associated_to_channel_by_team_tosql")
  1137  	}
  1138  
  1139  	var tgroups []*model.GroupsAssociatedToChannelWithSchemeAdmin
  1140  
  1141  	_, err = s.GetReplica().Select(&tgroups, queryString, args...)
  1142  	if err != nil {
  1143  		return nil, errors.Wrapf(err, "failed to find Groups with teamId=%s", teamId)
  1144  	}
  1145  
  1146  	groups := map[string][]*model.GroupWithSchemeAdmin{}
  1147  	for _, tgroup := range tgroups {
  1148  		var group = model.GroupWithSchemeAdmin{}
  1149  		group.Group = tgroup.Group
  1150  		group.SchemeAdmin = tgroup.SchemeAdmin
  1151  
  1152  		if val, ok := groups[tgroup.ChannelId]; ok {
  1153  			groups[tgroup.ChannelId] = append(val, &group)
  1154  		} else {
  1155  			groups[tgroup.ChannelId] = []*model.GroupWithSchemeAdmin{&group}
  1156  		}
  1157  	}
  1158  
  1159  	return groups, nil
  1160  }
  1161  
  1162  func (s *SqlGroupStore) GetGroups(page, perPage int, opts model.GroupSearchOpts) ([]*model.Group, error) {
  1163  	var groups []*model.Group
  1164  
  1165  	groupsQuery := s.getQueryBuilder().Select("g.*")
  1166  
  1167  	if opts.IncludeMemberCount {
  1168  		groupsQuery = s.getQueryBuilder().
  1169  			Select("g.*, coalesce(Members.MemberCount, 0) AS MemberCount").
  1170  			LeftJoin("(SELECT GroupMembers.GroupId, COUNT(*) AS MemberCount FROM GroupMembers LEFT JOIN Users ON Users.Id = GroupMembers.UserId WHERE GroupMembers.DeleteAt = 0 AND Users.DeleteAt = 0 GROUP BY GroupId) AS Members ON Members.GroupId = g.Id")
  1171  	}
  1172  
  1173  	groupsQuery = groupsQuery.
  1174  		From("UserGroups g").
  1175  		OrderBy("g.DisplayName")
  1176  
  1177  	if opts.Since > 0 {
  1178  		groupsQuery = groupsQuery.Where(sq.Gt{
  1179  			"g.UpdateAt": opts.Since,
  1180  		})
  1181  	} else {
  1182  		groupsQuery = groupsQuery.Where("g.DeleteAt = 0")
  1183  	}
  1184  
  1185  	if perPage != 0 {
  1186  		groupsQuery = groupsQuery.
  1187  			Limit(uint64(perPage)).
  1188  			Offset(uint64(page * perPage))
  1189  	}
  1190  
  1191  	if opts.FilterAllowReference {
  1192  		groupsQuery = groupsQuery.Where("g.AllowReference = true")
  1193  	}
  1194  
  1195  	if opts.Q != "" {
  1196  		pattern := fmt.Sprintf("%%%s%%", sanitizeSearchTerm(opts.Q, "\\"))
  1197  		operatorKeyword := "ILIKE"
  1198  		if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
  1199  			operatorKeyword = "LIKE"
  1200  		}
  1201  		groupsQuery = groupsQuery.Where(fmt.Sprintf("(g.Name %[1]s ? OR g.DisplayName %[1]s ?)", operatorKeyword), pattern, pattern)
  1202  	}
  1203  
  1204  	if len(opts.NotAssociatedToTeam) == 26 {
  1205  		groupsQuery = groupsQuery.Where(`
  1206  			g.Id NOT IN (
  1207  				SELECT
  1208  					Id
  1209  				FROM
  1210  					UserGroups
  1211  					JOIN GroupTeams ON GroupTeams.GroupId = UserGroups.Id
  1212  				WHERE
  1213  					GroupTeams.DeleteAt = 0
  1214  					AND UserGroups.DeleteAt = 0
  1215  					AND GroupTeams.TeamId = ?
  1216  			)
  1217  		`, opts.NotAssociatedToTeam)
  1218  	}
  1219  
  1220  	if len(opts.NotAssociatedToChannel) == 26 {
  1221  		groupsQuery = groupsQuery.Where(`
  1222  			g.Id NOT IN (
  1223  				SELECT
  1224  					Id
  1225  				FROM
  1226  					UserGroups
  1227  					JOIN GroupChannels ON GroupChannels.GroupId = UserGroups.Id
  1228  				WHERE
  1229  					GroupChannels.DeleteAt = 0
  1230  					AND UserGroups.DeleteAt = 0
  1231  					AND GroupChannels.ChannelId = ?
  1232  			)
  1233  		`, opts.NotAssociatedToChannel)
  1234  	}
  1235  
  1236  	if opts.FilterParentTeamPermitted && len(opts.NotAssociatedToChannel) == 26 {
  1237  		groupsQuery = groupsQuery.Where(`
  1238  			CASE
  1239  			WHEN (
  1240  				SELECT
  1241  					Teams.GroupConstrained
  1242  				FROM
  1243  					Teams
  1244  					JOIN Channels ON Channels.TeamId = Teams.Id
  1245  				WHERE
  1246  					Channels.Id = ?
  1247  			) THEN g.Id IN (
  1248  				SELECT
  1249  					GroupId
  1250  				FROM
  1251  					GroupTeams
  1252  				WHERE
  1253  					GroupTeams.DeleteAt = 0
  1254  					AND GroupTeams.TeamId = (
  1255  						SELECT
  1256  							TeamId
  1257  						FROM
  1258  							Channels
  1259  						WHERE
  1260  							Id = ?
  1261  					)
  1262  			)
  1263  			ELSE TRUE
  1264  		END
  1265  		`, opts.NotAssociatedToChannel, opts.NotAssociatedToChannel)
  1266  	}
  1267  
  1268  	queryString, args, err := groupsQuery.ToSql()
  1269  	if err != nil {
  1270  		return nil, errors.Wrap(err, "get_groups_tosql")
  1271  	}
  1272  
  1273  	if _, err = s.GetReplica().Select(&groups, queryString, args...); err != nil {
  1274  		return nil, errors.Wrap(err, "failed to find Groups")
  1275  	}
  1276  
  1277  	return groups, nil
  1278  }
  1279  
  1280  func (s *SqlGroupStore) teamMembersMinusGroupMembersQuery(teamID string, groupIDs []string, isCount bool) sq.SelectBuilder {
  1281  	var selectStr string
  1282  
  1283  	if isCount {
  1284  		selectStr = "count(DISTINCT Users.Id)"
  1285  	} else {
  1286  		tmpl := "Users.*, coalesce(TeamMembers.SchemeGuest, false), TeamMembers.SchemeAdmin, TeamMembers.SchemeUser, %s AS GroupIDs"
  1287  		if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
  1288  			selectStr = fmt.Sprintf(tmpl, "group_concat(UserGroups.Id)")
  1289  		} else {
  1290  			selectStr = fmt.Sprintf(tmpl, "string_agg(UserGroups.Id, ',')")
  1291  		}
  1292  	}
  1293  
  1294  	subQuery := s.getQueryBuilder().Select("GroupMembers.UserId").
  1295  		From("GroupMembers").
  1296  		Join("UserGroups ON UserGroups.Id = GroupMembers.GroupId").
  1297  		Where("GroupMembers.DeleteAt = 0").
  1298  		Where(fmt.Sprintf("GroupMembers.GroupId IN ('%s')", strings.Join(groupIDs, "', '")))
  1299  
  1300  	query, _ := subQuery.MustSql()
  1301  
  1302  	builder := s.getQueryBuilder().Select(selectStr).
  1303  		From("TeamMembers").
  1304  		Join("Teams ON Teams.Id = TeamMembers.TeamId").
  1305  		Join("Users ON Users.Id = TeamMembers.UserId").
  1306  		LeftJoin("Bots ON Bots.UserId = TeamMembers.UserId").
  1307  		LeftJoin("GroupMembers ON GroupMembers.UserId = Users.Id").
  1308  		LeftJoin("UserGroups ON UserGroups.Id = GroupMembers.GroupId").
  1309  		Where("TeamMembers.DeleteAt = 0").
  1310  		Where("Teams.DeleteAt = 0").
  1311  		Where("Users.DeleteAt = 0").
  1312  		Where("Bots.UserId IS NULL").
  1313  		Where("Teams.Id = ?", teamID).
  1314  		Where(fmt.Sprintf("Users.Id NOT IN (%s)", query))
  1315  
  1316  	if !isCount {
  1317  		builder = builder.GroupBy("Users.Id, TeamMembers.SchemeGuest, TeamMembers.SchemeAdmin, TeamMembers.SchemeUser")
  1318  	}
  1319  
  1320  	return builder
  1321  }
  1322  
  1323  // TeamMembersMinusGroupMembers returns the set of users on the given team minus the set of users in the given
  1324  // groups.
  1325  func (s *SqlGroupStore) TeamMembersMinusGroupMembers(teamID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, error) {
  1326  	query := s.teamMembersMinusGroupMembersQuery(teamID, groupIDs, false)
  1327  	query = query.OrderBy("Users.Username ASC").Limit(uint64(perPage)).Offset(uint64(page * perPage))
  1328  
  1329  	queryString, args, err := query.ToSql()
  1330  	if err != nil {
  1331  		return nil, errors.Wrap(err, "team_members_minus_group_members")
  1332  	}
  1333  
  1334  	var users []*model.UserWithGroups
  1335  	if _, err = s.GetReplica().Select(&users, queryString, args...); err != nil {
  1336  		return nil, errors.Wrap(err, "failed to find UserWithGroups")
  1337  	}
  1338  
  1339  	return users, nil
  1340  }
  1341  
  1342  // CountTeamMembersMinusGroupMembers returns the count of the set of users on the given team minus the set of users
  1343  // in the given groups.
  1344  func (s *SqlGroupStore) CountTeamMembersMinusGroupMembers(teamID string, groupIDs []string) (int64, error) {
  1345  	queryString, args, err := s.teamMembersMinusGroupMembersQuery(teamID, groupIDs, true).ToSql()
  1346  	if err != nil {
  1347  		return 0, errors.Wrap(err, "count_team_members_minus_group_members_tosql")
  1348  	}
  1349  
  1350  	var count int64
  1351  	if count, err = s.GetReplica().SelectInt(queryString, args...); err != nil {
  1352  		return 0, errors.Wrap(err, "failed to count TeamMembers minus GroupMembers")
  1353  	}
  1354  
  1355  	return count, nil
  1356  }
  1357  
  1358  func (s *SqlGroupStore) channelMembersMinusGroupMembersQuery(channelID string, groupIDs []string, isCount bool) sq.SelectBuilder {
  1359  	var selectStr string
  1360  
  1361  	if isCount {
  1362  		selectStr = "count(DISTINCT Users.Id)"
  1363  	} else {
  1364  		tmpl := "Users.*, coalesce(ChannelMembers.SchemeGuest, false), ChannelMembers.SchemeAdmin, ChannelMembers.SchemeUser, %s AS GroupIDs"
  1365  		if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
  1366  			selectStr = fmt.Sprintf(tmpl, "group_concat(UserGroups.Id)")
  1367  		} else {
  1368  			selectStr = fmt.Sprintf(tmpl, "string_agg(UserGroups.Id, ',')")
  1369  		}
  1370  	}
  1371  
  1372  	subQuery := s.getQueryBuilder().Select("GroupMembers.UserId").
  1373  		From("GroupMembers").
  1374  		Join("UserGroups ON UserGroups.Id = GroupMembers.GroupId").
  1375  		Where("GroupMembers.DeleteAt = 0").
  1376  		Where(fmt.Sprintf("GroupMembers.GroupId IN ('%s')", strings.Join(groupIDs, "', '")))
  1377  
  1378  	query, _ := subQuery.MustSql()
  1379  
  1380  	builder := s.getQueryBuilder().Select(selectStr).
  1381  		From("ChannelMembers").
  1382  		Join("Channels ON Channels.Id = ChannelMembers.ChannelId").
  1383  		Join("Users ON Users.Id = ChannelMembers.UserId").
  1384  		LeftJoin("Bots ON Bots.UserId = ChannelMembers.UserId").
  1385  		LeftJoin("GroupMembers ON GroupMembers.UserId = Users.Id").
  1386  		LeftJoin("UserGroups ON UserGroups.Id = GroupMembers.GroupId").
  1387  		Where("Channels.DeleteAt = 0").
  1388  		Where("Users.DeleteAt = 0").
  1389  		Where("Bots.UserId IS NULL").
  1390  		Where("Channels.Id = ?", channelID).
  1391  		Where(fmt.Sprintf("Users.Id NOT IN (%s)", query))
  1392  
  1393  	if !isCount {
  1394  		builder = builder.GroupBy("Users.Id, ChannelMembers.SchemeGuest, ChannelMembers.SchemeAdmin, ChannelMembers.SchemeUser")
  1395  	}
  1396  
  1397  	return builder
  1398  }
  1399  
  1400  // ChannelMembersMinusGroupMembers returns the set of users in the given channel minus the set of users in the given
  1401  // groups.
  1402  func (s *SqlGroupStore) ChannelMembersMinusGroupMembers(channelID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, error) {
  1403  	query := s.channelMembersMinusGroupMembersQuery(channelID, groupIDs, false)
  1404  	query = query.OrderBy("Users.Username ASC").Limit(uint64(perPage)).Offset(uint64(page * perPage))
  1405  
  1406  	queryString, args, err := query.ToSql()
  1407  	if err != nil {
  1408  		return nil, errors.Wrap(err, "channel_members_minus_group_members_tosql")
  1409  	}
  1410  
  1411  	var users []*model.UserWithGroups
  1412  	if _, err = s.GetReplica().Select(&users, queryString, args...); err != nil {
  1413  		return nil, errors.Wrap(err, "failed to find UserWithGroups")
  1414  	}
  1415  
  1416  	return users, nil
  1417  }
  1418  
  1419  // CountChannelMembersMinusGroupMembers returns the count of the set of users in the given channel minus the set of users
  1420  // in the given groups.
  1421  func (s *SqlGroupStore) CountChannelMembersMinusGroupMembers(channelID string, groupIDs []string) (int64, error) {
  1422  	queryString, args, err := s.channelMembersMinusGroupMembersQuery(channelID, groupIDs, true).ToSql()
  1423  	if err != nil {
  1424  		return 0, errors.Wrap(err, "count_channel_members_minus_group_members_tosql")
  1425  	}
  1426  
  1427  	var count int64
  1428  	if count, err = s.GetReplica().SelectInt(queryString, args...); err != nil {
  1429  		return 0, errors.Wrap(err, "failed to count ChannelMembers")
  1430  	}
  1431  
  1432  	return count, nil
  1433  }
  1434  
  1435  func (s *SqlGroupStore) AdminRoleGroupsForSyncableMember(userID, syncableID string, syncableType model.GroupSyncableType) ([]string, error) {
  1436  	var groupIds []string
  1437  
  1438  	query := fmt.Sprintf(`
  1439  		SELECT
  1440  			GroupMembers.GroupId
  1441  		FROM
  1442  			GroupMembers
  1443  		INNER JOIN
  1444  			Group%[1]ss ON Group%[1]ss.GroupId = GroupMembers.GroupId
  1445  		WHERE
  1446  			GroupMembers.UserId = :UserId
  1447  			AND GroupMembers.DeleteAt = 0
  1448  			AND %[1]sId = :%[1]sId
  1449  			AND Group%[1]ss.DeleteAt = 0
  1450  			AND Group%[1]ss.SchemeAdmin = TRUE`, syncableType)
  1451  
  1452  	_, err := s.GetReplica().Select(&groupIds, query, map[string]interface{}{"UserId": userID, fmt.Sprintf("%sId", syncableType): syncableID})
  1453  	if err != nil {
  1454  		return nil, errors.Wrap(err, "failed to find Group ids")
  1455  	}
  1456  
  1457  	return groupIds, nil
  1458  }
  1459  
  1460  func (s *SqlGroupStore) PermittedSyncableAdmins(syncableID string, syncableType model.GroupSyncableType) ([]string, error) {
  1461  	builder := s.getQueryBuilder().Select("UserId").
  1462  		From(fmt.Sprintf("Group%ss", syncableType)).
  1463  		Join(fmt.Sprintf("GroupMembers ON GroupMembers.GroupId = Group%ss.GroupId AND Group%[1]ss.SchemeAdmin = TRUE AND GroupMembers.DeleteAt = 0", syncableType.String())).Where(fmt.Sprintf("Group%[1]ss.%[1]sId = ?", syncableType.String()), syncableID)
  1464  
  1465  	query, args, err := builder.ToSql()
  1466  	if err != nil {
  1467  		return nil, errors.Wrap(err, "permitted_syncable_admins_tosql")
  1468  	}
  1469  
  1470  	var userIDs []string
  1471  	if _, err = s.GetMaster().Select(&userIDs, query, args...); err != nil {
  1472  		return nil, errors.Wrapf(err, "failed to find User ids")
  1473  	}
  1474  
  1475  	return userIDs, nil
  1476  }
  1477  
  1478  func (s *SqlGroupStore) GroupCount() (int64, error) {
  1479  	return s.countTable("UserGroups")
  1480  }
  1481  
  1482  func (s *SqlGroupStore) GroupTeamCount() (int64, error) {
  1483  	return s.countTable("GroupTeams")
  1484  }
  1485  
  1486  func (s *SqlGroupStore) GroupChannelCount() (int64, error) {
  1487  	return s.countTable("GroupChannels")
  1488  }
  1489  
  1490  func (s *SqlGroupStore) GroupMemberCount() (int64, error) {
  1491  	return s.countTable("GroupMembers")
  1492  }
  1493  
  1494  func (s *SqlGroupStore) DistinctGroupMemberCount() (int64, error) {
  1495  	return s.countTableWithSelectAndWhere("COUNT(DISTINCT UserId)", "GroupMembers", nil)
  1496  }
  1497  
  1498  func (s *SqlGroupStore) GroupCountWithAllowReference() (int64, error) {
  1499  	return s.countTableWithSelectAndWhere("COUNT(*)", "UserGroups", sq.Eq{"AllowReference": true, "DeleteAt": 0})
  1500  }
  1501  
  1502  func (s *SqlGroupStore) countTable(tableName string) (int64, error) {
  1503  	return s.countTableWithSelectAndWhere("COUNT(*)", tableName, nil)
  1504  }
  1505  
  1506  func (s *SqlGroupStore) countTableWithSelectAndWhere(selectStr, tableName string, whereStmt map[string]interface{}) (int64, error) {
  1507  	if whereStmt == nil {
  1508  		whereStmt = sq.Eq{"DeleteAt": 0}
  1509  	}
  1510  
  1511  	query := s.getQueryBuilder().Select(selectStr).From(tableName).Where(whereStmt)
  1512  
  1513  	sql, args, err := query.ToSql()
  1514  	if err != nil {
  1515  		return 0, errors.Wrap(err, "count_table_with_select_and_where_tosql")
  1516  	}
  1517  
  1518  	count, err := s.GetReplica().SelectInt(sql, args...)
  1519  	if err != nil {
  1520  		return 0, errors.Wrapf(err, "failed to count from table %s", tableName)
  1521  	}
  1522  
  1523  	return count, nil
  1524  }