// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. package sqlstore import ( "database/sql" "errors" "strconv" sq "github.com/Masterminds/squirrel" "github.com/mattermost/focalboard/server/model" "github.com/mattermost/focalboard/server/services/store" ) var ErrInvalidCardLimitValue = errors.New("card limit value is invalid") // activeCardsQuery applies the necessary filters to the query for it // to fetch an active cards window if the cardLimit is set, or all the // active cards if it's 0. func (s *SQLStore) activeCardsQuery(builder sq.StatementBuilderType, selectStr string, cardLimit int) sq.SelectBuilder { query := builder. Select(selectStr). From(s.tablePrefix + "blocks b"). Join(s.tablePrefix + "boards bd on b.board_id=bd.id"). Where(sq.Eq{ "b.delete_at": 0, "b.type": model.TypeCard, "bd.is_template": false, }) if cardLimit != 0 { query = query. Limit(1). Offset(uint64(cardLimit - 1)) } return query } // getUsedCardsCount returns the amount of active cards in the server. func (s *SQLStore) getUsedCardsCount(db sq.BaseRunner) (int, error) { row := s.activeCardsQuery(s.getQueryBuilder(db), "count(b.id)", 0). QueryRow() var usedCards int err := row.Scan(&usedCards) if err != nil { return 0, err } return usedCards, nil } // getCardLimitTimestamp returns the timestamp value from the // system_settings table or zero if it doesn't exist. func (s *SQLStore) getCardLimitTimestamp(db sq.BaseRunner) (int64, error) { scanner := s.getQueryBuilder(db). Select("value"). From(s.tablePrefix + "system_settings"). Where(sq.Eq{"id": store.CardLimitTimestampSystemKey}). QueryRow() var result string err := scanner.Scan(&result) if errors.Is(sql.ErrNoRows, err) { return 0, nil } if err != nil { return 0, err } cardLimitTimestamp, err := strconv.Atoi(result) if err != nil { return 0, ErrInvalidCardLimitValue } return int64(cardLimitTimestamp), nil } // updateCardLimitTimestamp updates the card limit value in the // system_settings table with the timestamp of the nth last updated // card, being nth the value of the cardLimit parameter. If cardLimit // is zero, the timestamp will be set to zero. func (s *SQLStore) updateCardLimitTimestamp(db sq.BaseRunner, cardLimit int) (int64, error) { query := s.getQueryBuilder(db). Insert(s.tablePrefix+"system_settings"). Columns("id", "value") var value interface{} = 0 if cardLimit != 0 { value = s.activeCardsQuery(sq.StatementBuilder, "b.update_at", cardLimit). OrderBy("b.update_at DESC"). Prefix("COALESCE((").Suffix("), 0)") } query = query.Values(store.CardLimitTimestampSystemKey, value) if s.dbType == model.MysqlDBType { query = query.Suffix("ON DUPLICATE KEY UPDATE value = ?", value) } else { query = query.Suffix( `ON CONFLICT (id) DO UPDATE SET value = EXCLUDED.value`, ) } result, err := query.Exec() if err != nil { return 0, err } if _, err := result.RowsAffected(); err != nil { return 0, err } return s.getCardLimitTimestamp(db) }