[MM-39636] Migrate from gorp to sqlx in store/sqlstore/retention_policy_store.go (#18994)
* Migrate Save from gorp to sqlx * Migrate checkTeamsExist from gorp to sqlx * Migrate checkChannelsExist from gorp to sqlx * Migrate Patch from gorp to sqlx * Migrate buildGetPoliciesQuery from gorp to sqlx * Migrate Get from gorp to sqlx * Change buildGetPolicyQuery return values * Migrate GetAll from gorp to sqlx * Migrate GetCount from gorp to sqlx * Migrate Delete from gorp to sqlx * Migrate GetChannels from gorp to sqlx * Migrate GetChannelsCount from gorp to sqlx * Migrate AddChannels from gorp to sqlx * Migrate RemoveChannels from gorp to sqlx * Migrate GetTeams from gorp to sqlx * Migrate GetTeamsCount from gorp to sqlx * Migrate AddTeams from gorp to sqlx * Migrate RemoveTeams from gorp to sqlx * Migrate DeleteOrphanedRows from gorp to sqlx * Migrate GetTeamPoliciesForUser from gorp to sqlx * Migrate GetTeamPoliciesCountForUser from gorp to sqlx * Migrate GetChannelPoliciesForUser from gorp to sqlx * Migrate GetChannelPoliciesCountForUser from gorp to sqlx * Migrate Delete from gorp to sqlx * Add mapper tag function before saving a record Summary: Since there is a db tag in this model for the ID column, I set a mapper in this transaction to lowercase all mapping columns before saving the record. * Use quoted identifiers when selecting Id * Address PR comments, replace variable declarations for their short hand syntax * Enhance subquery implementation Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
@@ -5,13 +5,13 @@ package sqlstore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/lib/pq"
|
||||
"github.com/mattermost/gorp"
|
||||
"github.com/mattermost/mattermost-server/v6/einterfaces"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/store"
|
||||
@@ -59,7 +59,7 @@ func (s *SqlRetentionPolicyStore) createIndexesIfNotExists() {
|
||||
|
||||
// executePossiblyEmptyQuery only executes the query if it is non-empty. This helps avoid
|
||||
// having to check for MySQL, which, unlike Postgres, does not allow empty queries.
|
||||
func executePossiblyEmptyQuery(txn *gorp.Transaction, query string, args ...interface{}) (sql.Result, error) {
|
||||
func executePossiblyEmptyQuery(txn *sqlxTxWrapper, query string, args ...interface{}) (sql.Result, error) {
|
||||
if query == "" {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -100,13 +100,16 @@ func (s *SqlRetentionPolicyStore) Save(policy *model.RetentionPolicyWithTeamAndC
|
||||
return nil, err
|
||||
}
|
||||
|
||||
policySelectQuery, policySelectProps := s.buildGetPolicyQuery(policy.ID)
|
||||
|
||||
txn, err := s.GetMaster().Begin()
|
||||
queryString, args, err := s.buildGetPolicyQuery(policy.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer finalizeTransaction(txn)
|
||||
|
||||
txn, err := s.GetMasterX().Beginx()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer finalizeTransactionX(txn)
|
||||
// Create a new policy in RetentionPolicies
|
||||
if _, err = txn.Exec(policyInsertQuery, policyInsertArgs...); err != nil {
|
||||
return nil, err
|
||||
@@ -121,7 +124,8 @@ func (s *SqlRetentionPolicyStore) Save(policy *model.RetentionPolicyWithTeamAndC
|
||||
}
|
||||
// Select the new policy (with team/channel counts) which we just created
|
||||
var newPolicy model.RetentionPolicyWithTeamAndChannelCounts
|
||||
if err = txn.SelectOne(&newPolicy, policySelectQuery, policySelectProps); err != nil {
|
||||
|
||||
if err = txn.Get(&newPolicy, queryString, args...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = txn.Commit(); err != nil {
|
||||
@@ -140,8 +144,8 @@ func (s *SqlRetentionPolicyStore) checkTeamsExist(teamIDs []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var rows []*string
|
||||
_, err = s.GetReplica().Select(&rows, teamsSelectQuery, teamsSelectArgs...)
|
||||
rows := []*string{}
|
||||
err = s.GetReplicaX().Select(&rows, teamsSelectQuery, teamsSelectArgs...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -171,8 +175,8 @@ func (s *SqlRetentionPolicyStore) checkChannelsExist(channelIDs []string) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var rows []*string
|
||||
_, err = s.GetReplica().Select(&rows, channelsSelectQuery, channelsSelectArgs...)
|
||||
rows := []*string{}
|
||||
err = s.GetReplicaX().Select(&rows, channelsSelectQuery, channelsSelectArgs...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -291,13 +295,16 @@ func (s *SqlRetentionPolicyStore) Patch(patch *model.RetentionPolicyWithTeamAndC
|
||||
}
|
||||
}
|
||||
|
||||
policySelectQuery, policySelectProps := s.buildGetPolicyQuery(patch.ID)
|
||||
|
||||
txn, err := s.GetMaster().Begin()
|
||||
queryString, args, err := s.buildGetPolicyQuery(patch.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer finalizeTransaction(txn)
|
||||
|
||||
txn, err := s.GetMasterX().Beginx()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer finalizeTransactionX(txn)
|
||||
// Update the fields of the policy in RetentionPolicies
|
||||
if _, err = executePossiblyEmptyQuery(txn, policyUpdateQuery, policyUpdateArgs...); err != nil {
|
||||
return nil, err
|
||||
@@ -320,7 +327,7 @@ func (s *SqlRetentionPolicyStore) Patch(patch *model.RetentionPolicyWithTeamAndC
|
||||
}
|
||||
// Select the policy which we just updated
|
||||
var newPolicy model.RetentionPolicyWithTeamAndChannelCounts
|
||||
if err = txn.SelectOne(&newPolicy, policySelectQuery, policySelectProps); err != nil {
|
||||
if err = txn.Get(&newPolicy, queryString, args...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = txn.Commit(); err != nil {
|
||||
@@ -329,118 +336,179 @@ func (s *SqlRetentionPolicyStore) Patch(patch *model.RetentionPolicyWithTeamAndC
|
||||
return &newPolicy, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) buildGetPolicyQuery(id string) (query string, props map[string]interface{}) {
|
||||
func (s *SqlRetentionPolicyStore) buildGetPolicyQuery(id string) (string, []interface{}, error) {
|
||||
return s.buildGetPoliciesQuery(id, 0, 1)
|
||||
}
|
||||
|
||||
// buildGetPoliciesQuery builds a query to select information for the policy with the specified
|
||||
// ID, or, if `id` is the empty string, from all policies. The results returned will be sorted by
|
||||
// policy display name and ID.
|
||||
func (s *SqlRetentionPolicyStore) buildGetPoliciesQuery(id string, offset, limit int) (query string, props map[string]interface{}) {
|
||||
props = map[string]interface{}{"Offset": offset, "Limit": limit}
|
||||
whereIdEqualsPolicyId := ""
|
||||
func (s *SqlRetentionPolicyStore) buildGetPoliciesQuery(id string, offset, limit int) (string, []interface{}, error) {
|
||||
rpcSubQuery := s.getQueryBuilder().
|
||||
Select("RetentionPolicies.Id, COUNT(RetentionPoliciesChannels.ChannelId) AS Count").
|
||||
From("RetentionPolicies").
|
||||
LeftJoin("RetentionPoliciesChannels ON RetentionPolicies.Id = RetentionPoliciesChannels.PolicyId").
|
||||
GroupBy("RetentionPolicies.Id").
|
||||
OrderBy("RetentionPolicies.DisplayName, RetentionPolicies.Id").
|
||||
Limit(uint64(limit)).
|
||||
Offset(uint64(offset))
|
||||
|
||||
if id != "" {
|
||||
whereIdEqualsPolicyId = "WHERE RetentionPolicies.Id = :PolicyId"
|
||||
props["PolicyId"] = id
|
||||
rpcSubQuery = rpcSubQuery.Where(sq.Eq{"RetentionPolicies.Id": id})
|
||||
}
|
||||
query = `
|
||||
SELECT RetentionPolicies.Id,
|
||||
RetentionPolicies.DisplayName,
|
||||
RetentionPolicies.PostDuration,
|
||||
A.Count AS ChannelCount,
|
||||
B.Count AS TeamCount
|
||||
FROM RetentionPolicies
|
||||
INNER JOIN (
|
||||
SELECT RetentionPolicies.Id,
|
||||
COUNT(RetentionPoliciesChannels.ChannelId) AS Count
|
||||
FROM RetentionPolicies
|
||||
LEFT JOIN RetentionPoliciesChannels ON RetentionPolicies.Id = RetentionPoliciesChannels.PolicyId
|
||||
` + whereIdEqualsPolicyId + `
|
||||
GROUP BY RetentionPolicies.Id
|
||||
ORDER BY RetentionPolicies.DisplayName, RetentionPolicies.Id
|
||||
LIMIT :Limit
|
||||
OFFSET :Offset
|
||||
) AS A ON RetentionPolicies.Id = A.Id
|
||||
INNER JOIN (
|
||||
SELECT RetentionPolicies.Id,
|
||||
COUNT(RetentionPoliciesTeams.TeamId) AS Count
|
||||
FROM RetentionPolicies
|
||||
LEFT JOIN RetentionPoliciesTeams ON RetentionPolicies.Id = RetentionPoliciesTeams.PolicyId
|
||||
` + whereIdEqualsPolicyId + `
|
||||
GROUP BY RetentionPolicies.Id
|
||||
ORDER BY RetentionPolicies.DisplayName, RetentionPolicies.Id
|
||||
LIMIT :Limit
|
||||
OFFSET :Offset
|
||||
) AS B ON RetentionPolicies.Id = B.Id
|
||||
ORDER BY RetentionPolicies.DisplayName, RetentionPolicies.Id`
|
||||
return
|
||||
|
||||
rpcSubQueryString, args, err := rpcSubQuery.ToSql()
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "retention_policies_tosql")
|
||||
}
|
||||
|
||||
rptSubQuery := s.getQueryBuilder().
|
||||
Select("RetentionPolicies.Id, COUNT(RetentionPoliciesTeams.TeamId) AS Count").
|
||||
From("RetentionPolicies").
|
||||
LeftJoin("RetentionPoliciesTeams ON RetentionPolicies.Id = RetentionPoliciesTeams.PolicyId").
|
||||
GroupBy("RetentionPolicies.Id").
|
||||
OrderBy("RetentionPolicies.DisplayName, RetentionPolicies.Id").
|
||||
Limit(uint64(limit)).
|
||||
Offset(uint64(offset))
|
||||
|
||||
if id != "" {
|
||||
rptSubQuery = rptSubQuery.Where(sq.Eq{"RetentionPolicies.Id": id})
|
||||
}
|
||||
|
||||
rptSubQueryString, _, err := rptSubQuery.ToSql()
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "retention_policies_tosql")
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select(`
|
||||
RetentionPolicies.Id as "Id",
|
||||
RetentionPolicies.DisplayName,
|
||||
RetentionPolicies.PostDuration,
|
||||
A.Count AS ChannelCount,
|
||||
B.Count AS TeamCount
|
||||
`).
|
||||
From("RetentionPolicies").
|
||||
InnerJoin(`(` + rpcSubQueryString + `) AS A ON RetentionPolicies.Id = A.Id`).
|
||||
InnerJoin(`(` + rptSubQueryString + `) AS B ON RetentionPolicies.Id = B.Id`).
|
||||
OrderBy("RetentionPolicies.DisplayName, RetentionPolicies.Id")
|
||||
|
||||
queryString, _, err := query.ToSql()
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "retention_policies_tosql")
|
||||
}
|
||||
|
||||
// MySQL does not support positional params, so we add one param for each WHERE clause.
|
||||
if s.DriverName() == model.DatabaseDriverMysql {
|
||||
args = append(args, args...)
|
||||
}
|
||||
|
||||
return queryString, args, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) Get(id string) (*model.RetentionPolicyWithTeamAndChannelCounts, error) {
|
||||
query, props := s.buildGetPolicyQuery(id)
|
||||
queryString, args, err := s.buildGetPolicyQuery(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var policy model.RetentionPolicyWithTeamAndChannelCounts
|
||||
if err := s.GetReplica().SelectOne(&policy, query, props); err != nil {
|
||||
if err := s.GetReplicaX().Get(&policy, queryString, args...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &policy, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetAll(offset, limit int) (policies []*model.RetentionPolicyWithTeamAndChannelCounts, err error) {
|
||||
query, props := s.buildGetPoliciesQuery("", offset, limit)
|
||||
_, err = s.GetReplica().Select(&policies, query, props)
|
||||
queryString, args, err := s.buildGetPoliciesQuery("", offset, limit)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = s.GetReplicaX().Select(&policies, queryString, args...)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetCount() (int64, error) {
|
||||
return s.GetReplica().SelectInt("SELECT COUNT(*) FROM RetentionPolicies")
|
||||
var count int64
|
||||
err := s.GetReplicaX().Get(&count, "SELECT COUNT(*) FROM RetentionPolicies")
|
||||
if err != nil {
|
||||
return count, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) Delete(id string) error {
|
||||
builder := s.getQueryBuilder().
|
||||
query := s.getQueryBuilder().
|
||||
Delete("RetentionPolicies").
|
||||
Where(sq.Eq{"Id": id})
|
||||
result, err := builder.RunWith(s.GetMaster()).Exec()
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "retention_policies_tosql")
|
||||
}
|
||||
numRowsAffected, err := result.RowsAffected()
|
||||
|
||||
sqlResult, err := s.GetMasterX().Exec(queryString, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "failed to permanent delete retention policy with id=%s", id)
|
||||
}
|
||||
|
||||
numRowsAffected, err := sqlResult.RowsAffected()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to get rows affected")
|
||||
} else if numRowsAffected == 0 {
|
||||
return errors.New("policy not found")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetChannels(policyId string, offset, limit int) (channels model.ChannelListWithTeamData, err error) {
|
||||
const query = `
|
||||
SELECT Channels.*,
|
||||
Teams.DisplayName AS TeamDisplayName,
|
||||
Teams.Name AS TeamName,
|
||||
Teams.UpdateAt AS TeamUpdateAt
|
||||
FROM RetentionPoliciesChannels
|
||||
INNER JOIN Channels ON RetentionPoliciesChannels.ChannelId = Channels.Id
|
||||
INNER JOIN Teams ON Channels.TeamId = Teams.Id
|
||||
WHERE RetentionPoliciesChannels.PolicyId = :PolicyId
|
||||
ORDER BY Channels.DisplayName, Channels.Id
|
||||
LIMIT :Limit
|
||||
OFFSET :Offset`
|
||||
props := map[string]interface{}{"PolicyId": policyId, "Limit": limit, "Offset": offset}
|
||||
_, err = s.GetReplica().Select(&channels, query, props)
|
||||
func (s *SqlRetentionPolicyStore) GetChannels(policyId string, offset, limit int) (model.ChannelListWithTeamData, error) {
|
||||
query := s.getQueryBuilder().Select(`Channels.*, Teams.DisplayName AS TeamDisplayName,
|
||||
Teams.Name AS TeamName,Teams.UpdateAt AS TeamUpdateAt`).
|
||||
From("RetentionPoliciesChannels").
|
||||
InnerJoin("Channels ON RetentionPoliciesChannels.ChannelId = Channels.Id").
|
||||
InnerJoin("Teams ON Channels.TeamId = Teams.Id").
|
||||
Where(sq.Eq{"RetentionPoliciesChannels.PolicyId": policyId}).
|
||||
OrderBy("Channels.DisplayName, Channels.Id").
|
||||
Limit(uint64(limit)).
|
||||
Offset(uint64(offset))
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "retention_policies_channels_tosql")
|
||||
}
|
||||
|
||||
channels := model.ChannelListWithTeamData{}
|
||||
if err := s.GetReplicaX().Select(&channels, queryString, args...); err != nil {
|
||||
return channels, errors.Wrap(err, "failed to find RetentionPoliciesChannels")
|
||||
}
|
||||
|
||||
for _, channel := range channels {
|
||||
channel.PolicyID = model.NewString(policyId)
|
||||
}
|
||||
return
|
||||
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetChannelsCount(policyId string) (int64, error) {
|
||||
const query = `
|
||||
SELECT COUNT(*)
|
||||
FROM RetentionPolicies
|
||||
INNER JOIN RetentionPoliciesChannels ON RetentionPolicies.Id = RetentionPoliciesChannels.PolicyId
|
||||
WHERE RetentionPolicies.Id = :PolicyId`
|
||||
props := map[string]interface{}{"PolicyId": policyId}
|
||||
return s.GetReplica().SelectInt(query, props)
|
||||
query := s.getQueryBuilder().
|
||||
Select("Count(*)").
|
||||
From("RetentionPolicies").
|
||||
InnerJoin("RetentionPoliciesChannels ON RetentionPolicies.Id = RetentionPoliciesChannels.PolicyId").
|
||||
Where(sq.Eq{"RetentionPolicies.Id": policyId})
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "retention_policies_tosql")
|
||||
}
|
||||
|
||||
var count int64
|
||||
if err := s.GetReplicaX().Get(&count, queryString, args...); err != nil {
|
||||
return 0, errors.Wrap(err, "failed to count RetentionPolicies")
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) AddChannels(policyId string, channelIds []string) error {
|
||||
@@ -450,13 +518,20 @@ func (s *SqlRetentionPolicyStore) AddChannels(policyId string, channelIds []stri
|
||||
if err := s.checkChannelsExist(channelIds); err != nil {
|
||||
return err
|
||||
}
|
||||
builder := s.getQueryBuilder().
|
||||
query := s.getQueryBuilder().
|
||||
Insert("RetentionPoliciesChannels").
|
||||
Columns("policyId", "channelId")
|
||||
|
||||
for _, channelId := range channelIds {
|
||||
builder = builder.Values(policyId, channelId)
|
||||
query = query.Values(policyId, channelId)
|
||||
}
|
||||
_, err := builder.RunWith(s.GetMaster()).Exec()
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "retention_policies_channels_tosql")
|
||||
}
|
||||
|
||||
_, err = s.GetMasterX().Exec(queryString, args...)
|
||||
if err != nil {
|
||||
switch dbErr := err.(type) {
|
||||
case *pq.Error:
|
||||
@@ -469,47 +544,74 @@ func (s *SqlRetentionPolicyStore) AddChannels(policyId string, channelIds []stri
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) RemoveChannels(policyId string, channelIds []string) error {
|
||||
if len(channelIds) == 0 {
|
||||
return nil
|
||||
}
|
||||
builder := s.getQueryBuilder().
|
||||
query := s.getQueryBuilder().
|
||||
Delete("RetentionPoliciesChannels").
|
||||
Where(sq.And{
|
||||
sq.Eq{"PolicyId": policyId},
|
||||
sq.Eq{"ChannelId": channelIds},
|
||||
})
|
||||
_, err := builder.RunWith(s.GetMaster()).Exec()
|
||||
return err
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "retention_policies_channels_tosql")
|
||||
}
|
||||
|
||||
if _, err := s.GetMasterX().Exec(queryString, args...); err != nil {
|
||||
return errors.Wrapf(err, "failed to permanent delete retention policy channels with policyid=%s", policyId)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetTeams(policyId string, offset, limit int) (teams []*model.Team, err error) {
|
||||
const query = `
|
||||
SELECT Teams.* FROM RetentionPoliciesTeams
|
||||
INNER JOIN Teams ON RetentionPoliciesTeams.TeamId = Teams.Id
|
||||
WHERE RetentionPoliciesTeams.PolicyId = :PolicyId
|
||||
ORDER BY Teams.DisplayName, Teams.Id
|
||||
LIMIT :Limit
|
||||
OFFSET :Offset`
|
||||
props := map[string]interface{}{"PolicyId": policyId, "Limit": limit, "Offset": offset}
|
||||
_, err = s.GetReplica().Select(&teams, query, props)
|
||||
for _, team := range teams {
|
||||
team.PolicyID = &policyId
|
||||
func (s *SqlRetentionPolicyStore) GetTeams(policyId string, offset, limit int) ([]*model.Team, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("Teams.*").
|
||||
From("RetentionPoliciesTeams").
|
||||
InnerJoin("Teams ON RetentionPoliciesTeams.TeamId = Teams.Id").
|
||||
Where(sq.Eq{"RetentionPoliciesTeams.PolicyId": policyId}).
|
||||
OrderBy("Teams.DisplayName, Teams.Id").
|
||||
Limit(uint64(limit)).
|
||||
Offset(uint64(offset))
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "retention_policies_teams_tosql")
|
||||
}
|
||||
return
|
||||
|
||||
teams := []*model.Team{}
|
||||
if err = s.GetReplicaX().Select(&teams, queryString, args...); err != nil {
|
||||
return teams, errors.Wrap(err, "failed to find Teams")
|
||||
}
|
||||
|
||||
return teams, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetTeamsCount(policyId string) (int64, error) {
|
||||
const query = `
|
||||
SELECT COUNT(*)
|
||||
FROM RetentionPolicies
|
||||
INNER JOIN RetentionPoliciesTeams ON RetentionPolicies.Id = RetentionPoliciesTeams.PolicyId
|
||||
WHERE RetentionPolicies.Id = :PolicyId`
|
||||
props := map[string]interface{}{"PolicyId": policyId}
|
||||
return s.GetReplica().SelectInt(query, props)
|
||||
query := s.getQueryBuilder().
|
||||
Select("Count(*)").
|
||||
From("RetentionPolicies").
|
||||
InnerJoin("RetentionPoliciesTeams ON RetentionPolicies.Id = RetentionPoliciesTeams.PolicyId").
|
||||
Where(sq.Eq{"RetentionPolicies.Id": policyId})
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "retention_policies_tosql")
|
||||
}
|
||||
|
||||
var count int64
|
||||
if err := s.GetReplicaX().Get(&count, queryString, args...); err != nil {
|
||||
return 0, errors.Wrap(err, "failed to count RetentionPolicies")
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) AddTeams(policyId string, teamIds []string) error {
|
||||
@@ -519,54 +621,87 @@ func (s *SqlRetentionPolicyStore) AddTeams(policyId string, teamIds []string) er
|
||||
if err := s.checkTeamsExist(teamIds); err != nil {
|
||||
return err
|
||||
}
|
||||
builder := s.getQueryBuilder().
|
||||
query := s.getQueryBuilder().
|
||||
Insert("RetentionPoliciesTeams").
|
||||
Columns("PolicyId", "TeamId")
|
||||
for _, teamId := range teamIds {
|
||||
builder = builder.Values(policyId, teamId)
|
||||
query = query.Values(policyId, teamId)
|
||||
}
|
||||
_, err := builder.RunWith(s.GetMaster()).Exec()
|
||||
return err
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "retention_policies_teams_tosql")
|
||||
}
|
||||
|
||||
if _, err := s.GetMasterX().Exec(queryString, args...); err != nil {
|
||||
return errors.Wrap(err, "failed to insert retention policies teams")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) RemoveTeams(policyId string, teamIds []string) error {
|
||||
if len(teamIds) == 0 {
|
||||
return nil
|
||||
}
|
||||
builder := s.getQueryBuilder().
|
||||
query := s.getQueryBuilder().
|
||||
Delete("RetentionPoliciesTeams").
|
||||
Where(sq.And{
|
||||
sq.Eq{"PolicyId": policyId},
|
||||
sq.Eq{"TeamId": teamIds},
|
||||
})
|
||||
_, err := builder.RunWith(s.GetMaster()).Exec()
|
||||
return err
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "retention_policies_teams_tosql")
|
||||
}
|
||||
|
||||
if _, err := s.GetMasterX().Exec(queryString, args...); err != nil {
|
||||
return errors.Wrapf(err, "unable to permanent delete retention policies teams with policyid=%s", policyId)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func subQueryIN(property string, query sq.SelectBuilder) sq.Sqlizer {
|
||||
queryString, args, _ := query.ToSql()
|
||||
subQuery := fmt.Sprintf("%s IN (SELECT * FROM (%s) AS A)", property, queryString)
|
||||
return sq.Expr(subQuery, args...)
|
||||
}
|
||||
|
||||
// DeleteOrphanedRows removes entries from RetentionPoliciesChannels and RetentionPoliciesTeams
|
||||
// where a channel or team no longer exists.
|
||||
func (s *SqlRetentionPolicyStore) DeleteOrphanedRows(limit int) (deleted int64, err error) {
|
||||
// We need the extra level of nesting to deal with MySQL's locking
|
||||
const rpcDeleteQuery = `
|
||||
DELETE FROM RetentionPoliciesChannels WHERE ChannelId IN (
|
||||
SELECT * FROM (
|
||||
SELECT ChannelId FROM RetentionPoliciesChannels
|
||||
LEFT JOIN Channels ON RetentionPoliciesChannels.ChannelId = Channels.Id
|
||||
WHERE Channels.Id IS NULL
|
||||
LIMIT :Limit
|
||||
) AS A
|
||||
)`
|
||||
const rptDeleteQuery = `
|
||||
DELETE FROM RetentionPoliciesTeams WHERE TeamId IN (
|
||||
SELECT * FROM (
|
||||
SELECT TeamId FROM RetentionPoliciesTeams
|
||||
LEFT JOIN Teams ON RetentionPoliciesTeams.TeamId = Teams.Id
|
||||
WHERE Teams.Id IS NULL
|
||||
LIMIT :Limit
|
||||
) AS A
|
||||
)`
|
||||
props := map[string]interface{}{"Limit": limit}
|
||||
result, err := s.GetMaster().Exec(rpcDeleteQuery, props)
|
||||
rpcSubQuery := sq.Select("ChannelId").
|
||||
From("RetentionPoliciesChannels").
|
||||
LeftJoin("Channels ON RetentionPoliciesChannels.ChannelId = Channels.Id").
|
||||
Where("Channels.Id IS NULL").
|
||||
Limit(uint64(limit))
|
||||
|
||||
rpcDeleteQuery, rpcArgs, err := s.getQueryBuilder().
|
||||
Delete("RetentionPoliciesChannels").
|
||||
Where(subQueryIN("ChannelId", rpcSubQuery)).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return int64(0), errors.Wrap(err, "retention_policies_channels_tosql")
|
||||
}
|
||||
|
||||
rptSubQuery := sq.Select("TeamId").
|
||||
From("RetentionPoliciesTeams").
|
||||
LeftJoin("Teams ON RetentionPoliciesTeams.TeamId = Teams.Id").
|
||||
Where("Teams.Id IS NULL").
|
||||
Limit(uint64(limit))
|
||||
|
||||
rptDeleteQuery, rptArgs, err := s.getQueryBuilder().
|
||||
Delete("RetentionPoliciesTeams").
|
||||
Where(subQueryIN("TeamId", rptSubQuery)).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return int64(0), errors.Wrap(err, "retention_policies_teams_tosql")
|
||||
}
|
||||
|
||||
result, err := s.GetMasterX().Exec(rpcDeleteQuery, rpcArgs...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -574,7 +709,7 @@ func (s *SqlRetentionPolicyStore) DeleteOrphanedRows(limit int) (deleted int64,
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
result, err = s.GetMaster().Exec(rptDeleteQuery, props)
|
||||
result, err = s.GetMasterX().Exec(rptDeleteQuery, rptArgs...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -586,70 +721,124 @@ func (s *SqlRetentionPolicyStore) DeleteOrphanedRows(limit int) (deleted int64,
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetTeamPoliciesForUser(userID string, offset, limit int) (policies []*model.RetentionPolicyForTeam, err error) {
|
||||
const query = `
|
||||
SELECT Teams.Id, RetentionPolicies.PostDuration
|
||||
FROM Users
|
||||
INNER JOIN TeamMembers ON Users.Id = TeamMembers.UserId
|
||||
INNER JOIN Teams ON TeamMembers.TeamId = Teams.Id
|
||||
INNER JOIN RetentionPoliciesTeams ON Teams.Id = RetentionPoliciesTeams.TeamId
|
||||
INNER JOIN RetentionPolicies ON RetentionPoliciesTeams.PolicyId = RetentionPolicies.Id
|
||||
WHERE Users.Id = :UserId
|
||||
AND TeamMembers.DeleteAt = 0
|
||||
AND Teams.DeleteAt = 0
|
||||
ORDER BY Teams.Id
|
||||
LIMIT :Limit
|
||||
OFFSET :Offset`
|
||||
props := map[string]interface{}{"UserId": userID, "Limit": limit, "Offset": offset}
|
||||
_, err = s.GetReplica().Select(&policies, query, props)
|
||||
return
|
||||
func (s *SqlRetentionPolicyStore) GetTeamPoliciesForUser(userID string, offset, limit int) ([]*model.RetentionPolicyForTeam, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select(`Teams.Id AS "Id", RetentionPolicies.PostDuration`).
|
||||
From("Users").
|
||||
InnerJoin("TeamMembers ON Users.Id = TeamMembers.UserId").
|
||||
InnerJoin("Teams ON TeamMembers.TeamId = Teams.Id").
|
||||
InnerJoin("RetentionPoliciesTeams ON Teams.Id = RetentionPoliciesTeams.TeamId").
|
||||
InnerJoin("RetentionPolicies ON RetentionPoliciesTeams.PolicyId = RetentionPolicies.Id").
|
||||
Where(
|
||||
sq.And{
|
||||
sq.Eq{"Users.Id": userID},
|
||||
sq.Eq{"TeamMembers.DeleteAt": 0},
|
||||
sq.Eq{"Teams.DeleteAt": 0},
|
||||
},
|
||||
).
|
||||
OrderBy("Teams.Id").
|
||||
Limit(uint64(limit)).
|
||||
Offset(uint64(offset))
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "team_policies_for_user_tosql")
|
||||
}
|
||||
|
||||
policies := []*model.RetentionPolicyForTeam{}
|
||||
if err := s.GetReplicaX().Select(&policies, queryString, args...); err != nil {
|
||||
return policies, errors.Wrap(err, "failed to find Users")
|
||||
}
|
||||
|
||||
return policies, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetTeamPoliciesCountForUser(userID string) (int64, error) {
|
||||
const query = `
|
||||
SELECT COUNT(*)
|
||||
FROM Users
|
||||
INNER JOIN TeamMembers ON Users.Id = TeamMembers.UserId
|
||||
INNER JOIN Teams ON TeamMembers.TeamId = Teams.Id
|
||||
INNER JOIN RetentionPoliciesTeams ON Teams.Id = RetentionPoliciesTeams.TeamId
|
||||
INNER JOIN RetentionPolicies ON RetentionPoliciesTeams.PolicyId = RetentionPolicies.Id
|
||||
WHERE Users.Id = :UserId
|
||||
AND TeamMembers.DeleteAt = 0
|
||||
AND Teams.DeleteAt = 0`
|
||||
props := map[string]interface{}{"UserId": userID}
|
||||
return s.GetReplica().SelectInt(query, props)
|
||||
query := s.getQueryBuilder().
|
||||
Select("Count(*)").
|
||||
From("Users").
|
||||
InnerJoin("TeamMembers ON Users.Id = TeamMembers.UserId").
|
||||
InnerJoin("Teams ON TeamMembers.TeamId = Teams.Id").
|
||||
InnerJoin("RetentionPoliciesTeams ON Teams.Id = RetentionPoliciesTeams.TeamId").
|
||||
InnerJoin("RetentionPolicies ON RetentionPoliciesTeams.PolicyId = RetentionPolicies.Id").
|
||||
Where(
|
||||
sq.And{
|
||||
sq.Eq{"Users.Id": userID},
|
||||
sq.Eq{"TeamMembers.DeleteAt": 0},
|
||||
sq.Eq{"Teams.DeleteAt": 0},
|
||||
},
|
||||
)
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "team_policies_count_for_user_tosql")
|
||||
}
|
||||
|
||||
var count int64
|
||||
if err := s.GetReplicaX().Get(&count, queryString, args...); err != nil {
|
||||
return 0, errors.Wrap(err, "failed to count TeamPoliciesCountForUser")
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetChannelPoliciesForUser(userID string, offset, limit int) (policies []*model.RetentionPolicyForChannel, err error) {
|
||||
const query = `
|
||||
SELECT Channels.Id, RetentionPolicies.PostDuration
|
||||
FROM Users
|
||||
INNER JOIN ChannelMembers ON Users.Id = ChannelMembers.UserId
|
||||
INNER JOIN Channels ON ChannelMembers.ChannelId = Channels.Id
|
||||
INNER JOIN RetentionPoliciesChannels ON Channels.Id = RetentionPoliciesChannels.ChannelId
|
||||
INNER JOIN RetentionPolicies ON RetentionPoliciesChannels.PolicyId = RetentionPolicies.Id
|
||||
WHERE Users.Id = :UserId
|
||||
AND Channels.DeleteAt = 0
|
||||
ORDER BY Channels.Id
|
||||
LIMIT :Limit
|
||||
OFFSET :Offset`
|
||||
props := map[string]interface{}{"UserId": userID, "Limit": limit, "Offset": offset}
|
||||
_, err = s.GetReplica().Select(&policies, query, props)
|
||||
return
|
||||
func (s *SqlRetentionPolicyStore) GetChannelPoliciesForUser(userID string, offset, limit int) ([]*model.RetentionPolicyForChannel, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select(`Channels.Id as "Id", RetentionPolicies.PostDuration`).
|
||||
From("Users").
|
||||
InnerJoin("ChannelMembers ON Users.Id = ChannelMembers.UserId").
|
||||
InnerJoin("Channels ON ChannelMembers.ChannelId = Channels.Id").
|
||||
InnerJoin("RetentionPoliciesChannels ON Channels.Id = RetentionPoliciesChannels.ChannelId").
|
||||
InnerJoin("RetentionPolicies ON RetentionPoliciesChannels.PolicyId = RetentionPolicies.Id").
|
||||
Where(
|
||||
sq.And{
|
||||
sq.Eq{"Users.Id": userID},
|
||||
sq.Eq{"Channels.DeleteAt": 0},
|
||||
},
|
||||
).
|
||||
OrderBy("Channels.Id").
|
||||
Limit(uint64(limit)).
|
||||
Offset(uint64(offset))
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "channel_policies_for_user_tosql")
|
||||
}
|
||||
|
||||
policies := []*model.RetentionPolicyForChannel{}
|
||||
if err := s.GetReplicaX().Select(&policies, queryString, args...); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find Users")
|
||||
}
|
||||
|
||||
return policies, nil
|
||||
}
|
||||
|
||||
func (s *SqlRetentionPolicyStore) GetChannelPoliciesCountForUser(userID string) (int64, error) {
|
||||
const query = `
|
||||
SELECT COUNT(*)
|
||||
FROM Users
|
||||
INNER JOIN ChannelMembers ON Users.Id = ChannelMembers.UserId
|
||||
INNER JOIN Channels ON ChannelMembers.ChannelId = Channels.Id
|
||||
INNER JOIN RetentionPoliciesChannels ON Channels.Id = RetentionPoliciesChannels.ChannelId
|
||||
INNER JOIN RetentionPolicies ON RetentionPoliciesChannels.PolicyId = RetentionPolicies.Id
|
||||
WHERE Users.Id = :UserId
|
||||
AND Channels.DeleteAt = 0`
|
||||
props := map[string]interface{}{"UserId": userID}
|
||||
return s.GetReplica().SelectInt(query, props)
|
||||
query := s.getQueryBuilder().
|
||||
Select("Count(*)").
|
||||
From("Users").
|
||||
InnerJoin("ChannelMembers ON Users.Id = ChannelMembers.UserId").
|
||||
InnerJoin("Channels ON ChannelMembers.ChannelId = Channels.Id").
|
||||
InnerJoin("RetentionPoliciesChannels ON Channels.Id = RetentionPoliciesChannels.ChannelId").
|
||||
InnerJoin("RetentionPolicies ON RetentionPoliciesChannels.PolicyId = RetentionPolicies.Id").
|
||||
Where(
|
||||
sq.And{
|
||||
sq.Eq{"Users.Id": userID},
|
||||
sq.Eq{"Channels.DeleteAt": 0},
|
||||
},
|
||||
)
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "channel_policies_count_users_tosql")
|
||||
}
|
||||
|
||||
var count int64
|
||||
if err := s.GetReplicaX().Get(&count, queryString, args...); err != nil {
|
||||
return 0, errors.Wrap(err, "failed to count ChannelPoliciesCountForUser")
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// RetentionPolicyBatchDeletionInfo gives information on how to delete records
|
||||
@@ -811,7 +1000,7 @@ func genericRetentionPoliciesDeletion(
|
||||
` + query + `
|
||||
) AS A ON ` + joinClause
|
||||
}
|
||||
result, err := s.GetMaster().Exec(query, args...)
|
||||
result, err := s.GetMasterX().Exec(query, args...)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to delete "+r.Table)
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user