MM-19336 Migrated GetMembersByIds and GetMembersByChannelIds to Squirrel (#19728)

* Ported GetMembersByIds and GetMembersByChannelIds to Squirrel

* Added checks for empty ID lists

* Updated GetAllChannelMembersById to use Squirrel

* Added a method to get the query placeholder directly

* Migrated UpdateMultipleMembers to use a Squirrel query

* Migrated UpdateMultipleMembers to Squirrel

* Initialize a prepared query builder for channelMembersForTeamWithSchemeSelectQuery

* Migrated GetMembersForUser to Squirrel

* Slight improvement for constructMySQLJSONArgs

* Migrated UpdateMemberNotifyProps to Squirrel

* Migrated GetMembers to Squirrel

* Migrated GetMember to Squirrel

* Avoid shadowing err

* Don't set query builder on copy of SqlChannelStore

* Fixed typo in error message

* Fixed missing elipsis

* Shorter SQL generation for GetAllChannelMembersById

* Don't unnecessarily copy the reference

* Use a function to generate the ChannelMember map

* Avoid shadowing err

* Don't use IN for matching multiple possible values

* Initialize the members lists

* Remove check for empty channelIDs list

* Fixed test and removed check for empty list

* Use err2 rather than eerr

Co-authored-by: Tim Scheuermann <tim@plusmid.dev>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Tim Scheuermann
2022-03-10 20:57:09 +01:00
коммит произвёл GitHub
родитель f5b6e09965
Коммит caa30c9bc4
5 изменённых файлов: 215 добавлений и 121 удалений

Просмотреть файл

@@ -35,6 +35,9 @@ const (
type SqlChannelStore struct { type SqlChannelStore struct {
*SqlStore *SqlStore
metrics einterfaces.MetricsInterface metrics einterfaces.MetricsInterface
// prepared query builders for use in multiple methods
channelMembersForTeamWithSchemeSelectQuery sq.SelectBuilder
} }
type channelMember struct { type channelMember struct {
@@ -53,21 +56,21 @@ type channelMember struct {
MsgCountRoot int64 MsgCountRoot int64
} }
func NewChannelMemberFromModel(cm *model.ChannelMember) *channelMember { func NewMapFromChannelMemberModel(cm *model.ChannelMember) map[string]interface{} {
return &channelMember{ return map[string]interface{}{
ChannelId: cm.ChannelId, "ChannelId": cm.ChannelId,
UserId: cm.UserId, "UserId": cm.UserId,
Roles: cm.ExplicitRoles, "Roles": cm.ExplicitRoles,
LastViewedAt: cm.LastViewedAt, "LastViewedAt": cm.LastViewedAt,
MsgCount: cm.MsgCount, "MsgCount": cm.MsgCount,
MentionCount: cm.MentionCount, "MentionCount": cm.MentionCount,
MentionCountRoot: cm.MentionCountRoot, "MentionCountRoot": cm.MentionCountRoot,
MsgCountRoot: cm.MsgCountRoot, "MsgCountRoot": cm.MsgCountRoot,
NotifyProps: cm.NotifyProps, "NotifyProps": cm.NotifyProps,
LastUpdateAt: cm.LastUpdateAt, "LastUpdateAt": cm.LastUpdateAt,
SchemeGuest: sql.NullBool{Valid: true, Bool: cm.SchemeGuest}, "SchemeGuest": sql.NullBool{Valid: true, Bool: cm.SchemeGuest},
SchemeUser: sql.NullBool{Valid: true, Bool: cm.SchemeUser}, "SchemeUser": sql.NullBool{Valid: true, Bool: cm.SchemeUser},
SchemeAdmin: sql.NullBool{Valid: true, Bool: cm.SchemeAdmin}, "SchemeAdmin": sql.NullBool{Valid: true, Bool: cm.SchemeAdmin},
} }
} }
@@ -454,10 +457,32 @@ func (s SqlChannelStore) ClearCaches() {
} }
func newSqlChannelStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) store.ChannelStore { func newSqlChannelStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) store.ChannelStore {
return &SqlChannelStore{ s := &SqlChannelStore{
SqlStore: sqlStore, SqlStore: sqlStore,
metrics: metrics, metrics: metrics,
} }
s.initializeQueries()
return s
}
func (s *SqlChannelStore) initializeQueries() {
s.channelMembersForTeamWithSchemeSelectQuery = s.getQueryBuilder().
Select(
"ChannelMembers.*",
"TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole",
"TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole",
"TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole",
"ChannelScheme.DefaultChannelGuestRole ChannelSchemeDefaultGuestRole",
"ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole",
"ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole",
).
From("ChannelMembers").
InnerJoin("Channels ON ChannelMembers.ChannelId = Channels.Id").
LeftJoin("Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id").
LeftJoin("Teams ON Channels.TeamId = Teams.Id").
LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id")
} }
func (s SqlChannelStore) upsertPublicChannelT(transaction *sqlxTxWrapper, channel *model.Channel) error { func (s SqlChannelStore) upsertPublicChannelT(transaction *sqlxTxWrapper, channel *model.Channel) error {
@@ -1136,15 +1161,22 @@ func (s SqlChannelStore) GetChannelsByUser(userId string, includeDeleted bool, l
} }
func (s SqlChannelStore) GetAllChannelMembersById(channelID string) ([]string, error) { func (s SqlChannelStore) GetAllChannelMembersById(channelID string) ([]string, error) {
sql, args, err := s.channelMembersForTeamWithSchemeSelectQuery.Where(sq.Eq{
"ChannelId": channelID,
}).ToSql()
if err != nil {
return nil, errors.Wrap(err, "GetAllChannelMembersById_ToSql")
}
dbMembers := channelMemberWithSchemeRolesList{} dbMembers := channelMemberWithSchemeRolesList{}
err := s.GetReplicaX().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelId = ?", channelID) err = s.GetReplicaX().Select(&dbMembers, sql, args...)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelID=%s", channelID) return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelID=%s", channelID)
} }
res := make([]string, 0, len(dbMembers)) res := make([]string, len(dbMembers))
for _, member := range dbMembers.ToModel() { for i, member := range dbMembers.ToModel() {
res = append(res, member.UserId) res[i] = member.UserId
} }
return res, nil return res, nil
@@ -1558,27 +1590,6 @@ func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int, userId
return channels, nil return channels, nil
} }
var channelMembersForTeamWithSchemeSelectQuery = `
SELECT
ChannelMembers.*,
TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole,
TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole,
TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole,
ChannelScheme.DefaultChannelGuestRole ChannelSchemeDefaultGuestRole,
ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole,
ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole
FROM
ChannelMembers
INNER JOIN
Channels ON ChannelMembers.ChannelId = Channels.Id
LEFT JOIN
Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id
LEFT JOIN
Teams ON Channels.TeamId = Teams.Id
LEFT JOIN
Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id
`
var channelMembersWithSchemeSelectQuery = ` var channelMembersWithSchemeSelectQuery = `
SELECT SELECT
ChannelMembers.*, ChannelMembers.*,
@@ -1792,25 +1803,35 @@ func (s SqlChannelStore) UpdateMultipleMembers(members []*model.ChannelMember) (
updatedMembers := []*model.ChannelMember{} updatedMembers := []*model.ChannelMember{}
for _, member := range members { for _, member := range members {
if _, err := transaction.NamedExec(`UPDATE ChannelMembers update := s.getQueryBuilder().
SET Roles=:Roles, Update("ChannelMembers").
LastViewedAt=:LastViewedAt, SetMap(NewMapFromChannelMemberModel(member)).
MsgCount=:MsgCount, Where(sq.Eq{
MentionCount=:MentionCount, "ChannelId": member.ChannelId,
NotifyProps=:NotifyProps, "UserId": member.UserId,
LastUpdateAt=:LastUpdateAt, })
SchemeUser=:SchemeUser,
SchemeAdmin=:SchemeAdmin, sqlUpdate, args, err := update.ToSql()
SchemeGuest=:SchemeGuest, if err != nil {
MentionCountRoot=:MentionCountRoot, return nil, errors.Wrapf(err, "UpdateMultipleMembers_Update_ToSql ChannelID=%s UserID=%s", member.ChannelId, member.UserId)
MsgCountRoot=:MsgCountRoot }
WHERE ChannelId=:ChannelId AND UserId=:UserId`, NewChannelMemberFromModel(member)); err != nil {
if _, err = transaction.Exec(sqlUpdate, args...); err != nil {
return nil, errors.Wrap(err, "failed to update ChannelMember") return nil, errors.Wrap(err, "failed to update ChannelMember")
} }
sqlSelect, args, err := s.channelMembersForTeamWithSchemeSelectQuery.
Where(sq.Eq{
"ChannelMembers.ChannelId": member.ChannelId,
"ChannelMembers.UserId": member.UserId,
}).ToSql()
if err != nil {
return nil, errors.Wrapf(err, "UpdateMultipleMembers_Select_ToSql ChannelID=%s UserID=%s", member.ChannelId, member.UserId)
}
// TODO: Get this out of the transaction when is possible // TODO: Get this out of the transaction when is possible
var dbMember channelMemberWithSchemeRoles var dbMember channelMemberWithSchemeRoles
if err := transaction.Get(&dbMember, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = ? AND ChannelMembers.UserId = ?", member.ChannelId, member.UserId); err != nil { if err := transaction.Get(&dbMember, sqlSelect, args...); err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", member.ChannelId, member.UserId)) return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", member.ChannelId, member.UserId))
} }
@@ -1841,31 +1862,57 @@ func (s SqlChannelStore) UpdateMemberNotifyProps(channelID, userID string, props
defer finalizeTransactionX(tx) defer finalizeTransactionX(tx)
if s.DriverName() == model.DatabaseDriverPostgres { if s.DriverName() == model.DatabaseDriverPostgres {
_, err = tx.Exec(`UPDATE channelmembers sql, args, err2 := s.getQueryBuilder().
SET notifyprops = notifyprops || ?::jsonb Update("channelmembers").
WHERE userid=? AND channelid=?`, model.MapToJSON(props), userID, channelID) Set("notifyprops", sq.Expr("notifyprops || ?::jsonb", model.MapToJSON(props))).
} else { Where(sq.Eq{
"userid": userID,
"channelid": channelID,
}).ToSql()
if err2 != nil {
return nil, errors.Wrapf(err, "UpdateMemberNotifyProps_Update_Postgres_ToSql channelID=%s and userID=%s", channelID, userID)
}
_, err = tx.Exec(sql, args...)
} else if len(props) > 0 {
// It's difficult to construct a SQL query for MySQL // It's difficult to construct a SQL query for MySQL
// to handle a case of empty map. So we just ignore it. // to handle a case of empty map. So we just ignore it.
if len(props) > 0 {
// unpack the keys and values to pass to MySQL.
args, argString := constructMySQLJSONArgs(props)
args = append(args, userID, channelID)
// Example: UPDATE ChannelMembers // unpack the keys and values to pass to MySQL.
// SET NotifyProps = JSON_SET(NotifyProps, '$.mark_unread', '"yes"' [, ...]) jsonArgs, jsonSQL := constructMySQLJSONArgs(props)
// WHERE ... jsonExpr := sq.Expr(fmt.Sprintf("JSON_SET(NotifyProps, %s)", jsonSQL), jsonArgs...)
_, err = tx.Exec(`UPDATE ChannelMembers
SET NotifyProps = JSON_SET(NotifyProps, `+argString+`) // Example: UPDATE ChannelMembers
WHERE UserId=? AND ChannelId=?`, args...) // SET NotifyProps = JSON_SET(NotifyProps, '$.mark_unread', '"yes"' [, ...])
// WHERE ...
sql, args, err2 := s.getQueryBuilder().
Update("ChannelMembers").
Set("NotifyProps", jsonExpr).
Where(sq.Eq{
"UserId": userID,
"ChannelId": channelID,
}).ToSql()
if err2 != nil {
return nil, errors.Wrapf(err, "UpdateMemberNotifyProps_Update_MySQL_ToSql channelID=%s and userID=%s", channelID, userID)
} }
_, err = tx.Exec(sql, args...)
} }
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to update ChannelMember with channelID=%s and userID=%s", channelID, userID) return nil, errors.Wrapf(err, "failed to update ChannelMember with channelID=%s and userID=%s", channelID, userID)
} }
selectSQL, args, err := s.channelMembersForTeamWithSchemeSelectQuery.
Where(sq.Eq{
"ChannelMembers.ChannelId": channelID,
"ChannelMembers.UserId": userID,
}).ToSql()
if err != nil {
return nil, errors.Wrapf(err, "UpdateMemberNotifyProps_Select_ToSql channelID=%s and userID=%s", channelID, userID)
}
var dbMember channelMemberWithSchemeRoles var dbMember channelMemberWithSchemeRoles
if err2 := tx.Get(&dbMember, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = ? AND ChannelMembers.UserId = ?", channelID, userID); err2 != nil { if err2 := tx.Get(&dbMember, selectSQL, args...); err2 != nil {
if err2 == sql.ErrNoRows { if err2 == sql.ErrNoRows {
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelID, userID)) return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelID, userID))
} }
@@ -1879,11 +1926,22 @@ func (s SqlChannelStore) UpdateMemberNotifyProps(channelID, userID string, props
return dbMember.ToModel(), err return dbMember.ToModel(), err
} }
func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) (model.ChannelMembers, error) { func (s SqlChannelStore) GetMembers(channelID string, offset, limit int) (model.ChannelMembers, error) {
dbMembers := channelMemberWithSchemeRolesList{} sql, args, err := s.channelMembersForTeamWithSchemeSelectQuery.
err := s.GetReplicaX().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelId = ? LIMIT ? OFFSET ?", channelId, limit, offset) Where(sq.Eq{
"ChannelId": channelID,
}).
Limit(uint64(limit)).
Offset(uint64(offset)).
ToSql()
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelId=%s", channelId) return nil, errors.Wrapf(err, "GetMember_ToSql ChannelID=%s", channelID)
}
dbMembers := channelMemberWithSchemeRolesList{}
err = s.GetReplicaX().Select(&dbMembers, sql, args...)
if err != nil {
return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelId=%s", channelID)
} }
return dbMembers.ToModel(), nil return dbMembers.ToModel(), nil
@@ -1908,14 +1966,23 @@ func (s SqlChannelStore) GetChannelMembersTimezones(channelId string) ([]model.S
return dbMembersTimezone, nil return dbMembersTimezone, nil
} }
func (s SqlChannelStore) GetMember(ctx context.Context, channelId string, userId string) (*model.ChannelMember, error) { func (s SqlChannelStore) GetMember(ctx context.Context, channelID string, userID string) (*model.ChannelMember, error) {
selectSQL, args, err := s.channelMembersForTeamWithSchemeSelectQuery.
Where(sq.Eq{
"ChannelMembers.ChannelId": channelID,
"ChannelMembers.UserId": userID,
}).ToSql()
if err != nil {
return nil, errors.Wrapf(err, "GetMember_ToSql ChannelID=%s UserID=%s", channelID, userID)
}
var dbMember channelMemberWithSchemeRoles var dbMember channelMemberWithSchemeRoles
if err := s.DBXFromContext(ctx).Get(&dbMember, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = ? AND ChannelMembers.UserId = ?", channelId, userId); err != nil { if err := s.DBXFromContext(ctx).Get(&dbMember, selectSQL, args...); err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelId, userId)) return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelID, userID))
} }
return nil, errors.Wrapf(err, "failed to get ChannelMember with channelId=%s and userId=%s", channelId, userId) return nil, errors.Wrapf(err, "failed to get ChannelMember with channelId=%s and userId=%s", channelID, userID)
} }
return dbMember.ToModel(), nil return dbMember.ToModel(), nil
@@ -2695,11 +2762,24 @@ func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType mo
return v, nil return v, nil
} }
func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) (model.ChannelMembers, error) { func (s SqlChannelStore) GetMembersForUser(teamID string, userID string) (model.ChannelMembers, error) {
dbMembers := channelMemberWithSchemeRolesList{} sql, args, err := s.channelMembersForTeamWithSchemeSelectQuery.
err := s.GetReplicaX().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = ? AND (Teams.Id = ? OR Teams.Id = '' OR Teams.Id IS NULL)", userId, teamId) Where(sq.And{
sq.Eq{"ChannelMembers.UserId": userID},
sq.Or{
sq.Eq{"Teams.Id": teamID},
sq.Eq{"Teams.Id": ""},
sq.Eq{"Teams.Id": nil},
},
}).ToSql()
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to find ChannelMembers data with teamId=%s and userId=%s", teamId, userId) return nil, errors.Wrapf(err, "GetMembersForUser_ToSql teamID=%s userID=%s", teamID, userID)
}
dbMembers := channelMemberWithSchemeRolesList{}
err = s.GetReplicaX().Select(&dbMembers, sql, args...)
if err != nil {
return nil, errors.Wrapf(err, "failed to find ChannelMembers data with teamId=%s and userId=%s", teamID, userID)
} }
return dbMembers.ToModel(), nil return dbMembers.ToModel(), nil
@@ -3545,29 +3625,43 @@ func (s SqlChannelStore) SearchGroupChannels(userId, term string) (model.Channel
return groupChannels, nil return groupChannels, nil
} }
// TODO: rewrite in squirrel (https://github.com/mattermost/mattermost-server/issues/19336) func (s SqlChannelStore) GetMembersByIds(channelID string, userIDs []string) (model.ChannelMembers, error) {
func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) (model.ChannelMembers, error) { query := s.channelMembersForTeamWithSchemeSelectQuery.Where(
var dbMembers channelMemberWithSchemeRolesList sq.Eq{
"ChannelMembers.ChannelId": channelID,
"ChannelMembers.UserId": userIDs,
},
)
keys, props := MapStringsToQueryParams(userIds, "User") sql, args, err := query.ToSql()
props["ChannelId"] = channelId if err != nil {
return nil, errors.Wrap(err, "GetMembersByIds_ToSql")
}
if _, err := s.GetReplica().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId IN "+keys, props); err != nil { dbMembers := channelMemberWithSchemeRolesList{}
return nil, errors.Wrapf(err, "failed to find ChannelMembers with channelId=%s and userId in %v", channelId, userIds) if err := s.GetReplicaX().Select(&dbMembers, sql, args...); err != nil {
return nil, errors.Wrapf(err, "failed to find ChannelMembers with channelId=%s and userId in %v", channelID, userIDs)
} }
return dbMembers.ToModel(), nil return dbMembers.ToModel(), nil
} }
// TODO: rewrite in squirrel (https://github.com/mattermost/mattermost-server/issues/19336) func (s SqlChannelStore) GetMembersByChannelIds(channelIDs []string, userID string) (model.ChannelMembers, error) {
func (s SqlChannelStore) GetMembersByChannelIds(channelIds []string, userId string) (model.ChannelMembers, error) { query := s.channelMembersForTeamWithSchemeSelectQuery.Where(
var dbMembers channelMemberWithSchemeRolesList sq.Eq{
"ChannelMembers.ChannelId": channelIDs,
"ChannelMembers.UserId": userID,
},
)
keys, props := MapStringsToQueryParams(channelIds, "Channel") sql, args, err := query.ToSql()
props["UserId"] = userId if err != nil {
return nil, errors.Wrap(err, "GetMembersByChannelIds_ToSql")
}
if _, err := s.GetReplica().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId AND ChannelMembers.ChannelId IN "+keys, props); err != nil { dbMembers := channelMemberWithSchemeRolesList{}
return nil, errors.Wrapf(err, "failed to find ChannelMembers with userId=%s and channelId in %v", userId, channelIds) if err := s.GetReplicaX().Select(&dbMembers, sql, args...); err != nil {
return nil, errors.Wrapf(err, "failed to find ChannelMembers with userId=%s and channelId in %v", userID, channelIDs)
} }
return dbMembers.ToModel(), nil return dbMembers.ToModel(), nil

Просмотреть файл

@@ -41,12 +41,12 @@ func TestChannelSearchQuerySQLInjection(t *testing.T) {
} }
func TestChannelStoreInternalDataTypes(t *testing.T) { func TestChannelStoreInternalDataTypes(t *testing.T) {
t.Run("NewChannelMemberFromModel", func(t *testing.T) { testNewChannelMemberFromModel(t) }) t.Run("NewMapFromChannelMemberModel", func(t *testing.T) { testNewMapFromChannelMemberModel(t) })
t.Run("ChannelMemberWithSchemeRolesToModel", func(t *testing.T) { testChannelMemberWithSchemeRolesToModel(t) }) t.Run("ChannelMemberWithSchemeRolesToModel", func(t *testing.T) { testChannelMemberWithSchemeRolesToModel(t) })
t.Run("AllChannelMemberProcess", func(t *testing.T) { testAllChannelMemberProcess(t) }) t.Run("AllChannelMemberProcess", func(t *testing.T) { testAllChannelMemberProcess(t) })
} }
func testNewChannelMemberFromModel(t *testing.T) { func testNewMapFromChannelMemberModel(t *testing.T) {
m := model.ChannelMember{ m := model.ChannelMember{
ChannelId: model.NewId(), ChannelId: model.NewId(),
UserId: model.NewId(), UserId: model.NewId(),
@@ -62,23 +62,20 @@ func testNewChannelMemberFromModel(t *testing.T) {
ExplicitRoles: "custom_role", ExplicitRoles: "custom_role",
} }
db := NewChannelMemberFromModel(&m) db := NewMapFromChannelMemberModel(&m)
assert.Equal(t, m.ChannelId, db.ChannelId) assert.Equal(t, m.ChannelId, db["ChannelId"])
assert.Equal(t, m.UserId, db.UserId) assert.Equal(t, m.UserId, db["UserId"])
assert.Equal(t, m.LastViewedAt, db.LastViewedAt) assert.Equal(t, m.LastViewedAt, db["LastViewedAt"])
assert.Equal(t, m.MsgCount, db.MsgCount) assert.Equal(t, m.MsgCount, db["MsgCount"])
assert.Equal(t, m.MentionCount, db.MentionCount) assert.Equal(t, m.MentionCount, db["MentionCount"])
assert.Equal(t, int64(0), m.MentionCountRoot) assert.Equal(t, int64(0), m.MentionCountRoot)
assert.Equal(t, m.NotifyProps, db.NotifyProps) assert.Equal(t, m.NotifyProps, db["NotifyProps"])
assert.Equal(t, m.LastUpdateAt, db.LastUpdateAt) assert.Equal(t, m.LastUpdateAt, db["LastUpdateAt"])
assert.Equal(t, true, db.SchemeGuest.Valid) assert.Equal(t, sql.NullBool{Bool: false, Valid: true}, db["SchemeGuest"])
assert.Equal(t, true, db.SchemeUser.Valid) assert.Equal(t, sql.NullBool{Bool: true, Valid: true}, db["SchemeUser"])
assert.Equal(t, true, db.SchemeAdmin.Valid) assert.Equal(t, sql.NullBool{Bool: true, Valid: true}, db["SchemeAdmin"])
assert.Equal(t, m.SchemeGuest, db.SchemeGuest.Bool) assert.Equal(t, m.ExplicitRoles, db["Roles"])
assert.Equal(t, m.SchemeUser, db.SchemeUser.Bool)
assert.Equal(t, m.SchemeAdmin, db.SchemeAdmin.Bool)
assert.Equal(t, m.ExplicitRoles, db.Roles)
} }
func testChannelMemberWithSchemeRolesToModel(t *testing.T) { func testChannelMemberWithSchemeRolesToModel(t *testing.T) {

Просмотреть файл

@@ -961,11 +961,14 @@ func (ss *SqlStore) DropAllTables() {
} }
func (ss *SqlStore) getQueryBuilder() sq.StatementBuilderType { func (ss *SqlStore) getQueryBuilder() sq.StatementBuilderType {
builder := sq.StatementBuilder.PlaceholderFormat(sq.Question) return sq.StatementBuilder.PlaceholderFormat(ss.getQueryPlaceholder())
}
func (ss *SqlStore) getQueryPlaceholder() sq.PlaceholderFormat {
if ss.DriverName() == model.DatabaseDriverPostgres { if ss.DriverName() == model.DatabaseDriverPostgres {
builder = builder.PlaceholderFormat(sq.Dollar) return sq.Dollar
} }
return builder return sq.Question
} }
// getSubQueryBuilder is necessary to generate the SQL query and args to pass to sub-queries because squirrel does not support WHERE clause in sub-queries. // getSubQueryBuilder is necessary to generate the SQL query and args to pass to sub-queries because squirrel does not support WHERE clause in sub-queries.

Просмотреть файл

@@ -113,14 +113,13 @@ func constructMySQLJSONArgs(props map[string]string) ([]interface{}, string) {
// Unpack the keys and values to pass to MySQL. // Unpack the keys and values to pass to MySQL.
args := make([]interface{}, 0, len(props)) args := make([]interface{}, 0, len(props))
for k, v := range props { for k, v := range props {
args = append(args, "$."+k) args = append(args, "$."+k, v)
args = append(args, v)
} }
// We calculate the number of ? to set in the query string. // We calculate the number of ? to set in the query string.
argString := strings.Repeat("?, ", len(props)*2) argString := strings.Repeat("?, ", len(props)*2)
// Strip off the trailing comma. // Strip off the trailing comma.
argString = strings.TrimSuffix(strings.TrimSpace(argString), ",") argString = strings.TrimSuffix(argString, ", ")
return args, argString return args, argString
} }

Просмотреть файл

@@ -6321,8 +6321,9 @@ func testChannelStoreGetMembersByIds(t *testing.T, ss store.Store) {
require.NoError(t, nErr, nErr) require.NoError(t, nErr, nErr)
require.Len(t, members, 2, "return wrong number of results") require.Len(t, members, 2, "return wrong number of results")
_, nErr = ss.Channel().GetMembersByIds(m1.ChannelId, []string{}) members, nErr = ss.Channel().GetMembersByIds(m1.ChannelId, []string{})
require.Error(t, nErr, "empty user ids - should have failed") require.NoError(t, nErr)
require.Len(t, members, 0)
} }
func testChannelStoreGetMembersByChannelIds(t *testing.T, ss store.Store) { func testChannelStoreGetMembersByChannelIds(t *testing.T, ss store.Store) {