"`
+// With an email and password - Discord will sign in with the provided
+// credentials.
+// With an email, password and auth token - Discord will verify the auth
+// token, if it is invalid it will sign in with the provided
+// credentials. This is the Discord recommended way to sign in.
//
// NOTE: While email/pass authentication is supported by DiscordGo it is
// HIGHLY DISCOURAGED by Discord. Please only use email/pass to obtain a token
@@ -153,3 +154,7 @@ func CheckRetry(_ context.Context, resp *http.Response, err error) (bool, error)
func StrID(id int64) string {
return strconv.FormatInt(id, 10)
}
+
+func ParseID(s string) (int64, error) {
+ return strconv.ParseInt(s, 10, 64)
+}
diff --git a/moderation/assets/moderation.html b/moderation/assets/moderation.html
index 254ed506d0..e1b10bbb56 100644
--- a/moderation/assets/moderation.html
+++ b/moderation/assets/moderation.html
@@ -218,7 +218,7 @@ Delete ALL server warnings?
-
@@ -300,7 +300,7 @@ Delete ALL server warnings?
-
@@ -423,7 +423,7 @@ Delete ALL server warnings?
-
diff --git a/moderation/commands.go b/moderation/commands.go
index 60f5230b11..b5457d19f9 100644
--- a/moderation/commands.go
+++ b/moderation/commands.go
@@ -1,6 +1,8 @@
package moderation
import (
+ "context"
+ "database/sql"
"fmt"
"regexp"
"strconv"
@@ -19,12 +21,13 @@ import (
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/lib/dstate"
"github.com/botlabs-gg/yagpdb/v2/logs"
+ "github.com/botlabs-gg/yagpdb/v2/moderation/models"
"github.com/botlabs-gg/yagpdb/v2/web"
- "github.com/jinzhu/gorm"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
)
func MBaseCmd(cmdData *dcmd.Data, targetID int64) (config *Config, targetUser *discordgo.User, err error) {
- config, err = GetConfig(cmdData.GuildData.GS.ID)
+ config, err = GetCachedConfigOrDefault(cmdData.GuildData.GS.ID)
if err != nil {
return nil, nil, errors.WithMessage(err, "GetConfig")
}
@@ -337,7 +340,7 @@ var ModerationCommands = []*commands.YAGCommand{
return nil, err
}
- if config.MuteRole == "" {
+ if config.MuteRole == 0 {
return fmt.Sprintf("No mute role selected. Select one at <%s/moderation>", web.ManageServerURL(parsed.GuildData)), nil
}
@@ -396,7 +399,7 @@ var ModerationCommands = []*commands.YAGCommand{
return nil, err
}
- if config.MuteRole == "" {
+ if config.MuteRole == 0 {
return "No mute role set up, assign a mute role in the control panel", nil
}
@@ -562,7 +565,7 @@ var ModerationCommands = []*commands.YAGCommand{
logLink := CreateLogs(parsed.GuildData.GS.ID, parsed.GuildData.CS.ID, parsed.Author)
- channelID := config.IntReportChannel()
+ channelID := config.ReportChannel
if channelID == 0 {
return "No report channel set up", nil
}
@@ -776,11 +779,11 @@ var ModerationCommands = []*commands.YAGCommand{
return nil, err
}
- if config.ActionChannel == "" {
+ if config.ActionChannel == 0 {
return "No mod log channel set up", nil
}
- msg, err := common.BotSession.ChannelMessage(config.IntActionChannel(), parsed.Args[0].Int64())
+ msg, err := common.BotSession.ChannelMessage(config.ActionChannel, parsed.Args[0].Int64())
if err != nil {
return nil, err
}
@@ -795,7 +798,7 @@ var ModerationCommands = []*commands.YAGCommand{
embed := msg.Embeds[0]
updateEmbedReason(parsed.Author, parsed.Args[1].Str(), embed)
- _, err = common.BotSession.ChannelMessageEditEmbed(config.IntActionChannel(), msg.ID, embed)
+ _, err = common.BotSession.ChannelMessageEditEmbed(config.ActionChannel, msg.ID, embed)
if err != nil {
return nil, err
}
@@ -874,19 +877,23 @@ var ModerationCommands = []*commands.YAGCommand{
}
if parsed.Switches["id"].Value != nil {
- var warn []*WarningModel
- err = common.GORM.Where("guild_id = ? AND id = ?", parsed.GuildData.GS.ID, parsed.Switches["id"].Int()).First(&warn).Error
- if err != nil && err != gorm.ErrRecordNotFound {
+ id := parsed.Switches["id"].Int()
+ warning, err := models.ModerationWarnings(
+ models.ModerationWarningWhere.ID.EQ(id),
+ // don't display warnings from other servers, even if ID is correct
+ models.ModerationWarningWhere.GuildID.EQ(parsed.GuildData.GS.ID),
+ ).OneG(parsed.Context())
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return fmt.Sprintf("Could not find warning with ID `%d`", id), nil
+ }
return nil, err
}
- if len(warn) == 0 {
- return fmt.Sprintf("Warning with given id : `%d` does not exist.", parsed.Switches["id"].Int()), nil
- }
return &discordgo.MessageEmbed{
- Title: fmt.Sprintf("Warning#%d - User : %s", warn[0].ID, warn[0].UserID),
- Description: fmt.Sprintf(" - **Reason** : %s", warn[0].CreatedAt.Unix(), warn[0].Message),
- Footer: &discordgo.MessageEmbedFooter{Text: fmt.Sprintf("By: %s (%13s)", warn[0].AuthorUsernameDiscrim, warn[0].AuthorID)},
+ Title: fmt.Sprintf("Warning#%d - User : %s", warning.ID, warning.UserID),
+ Description: fmt.Sprintf(" - **Reason** : %s", warning.CreatedAt.Unix(), warning.Message),
+ Footer: &discordgo.MessageEmbedFooter{Text: fmt.Sprintf("By: %s (%13s)", warning.AuthorUsernameDiscrim, warning.AuthorID)},
}, nil
}
page := parsed.Args[1].Int()
@@ -924,11 +931,18 @@ var ModerationCommands = []*commands.YAGCommand{
return nil, err
}
- rows := common.GORM.Model(WarningModel{}).Where("guild_id = ? AND id = ?", parsed.GuildData.GS.ID, parsed.Args[0].Int()).Update(
- "message", fmt.Sprintf("%s (updated by %s (%d))", parsed.Args[1].Str(), parsed.Author.String(), parsed.Author.ID)).RowsAffected
-
- if rows < 1 {
- return "Failed updating, most likely couldn't find the warning", nil
+ warningID := parsed.Args[0].Int()
+ updatedMessage := fmt.Sprintf("%s (updated by %s (%d))", parsed.Args[1].Str(), parsed.Author.String(), parsed.Author.ID)
+ numUpdated, err := models.ModerationWarnings(
+ models.ModerationWarningWhere.ID.EQ(warningID),
+ // don't edit warnings from other servers, even if ID is correct
+ models.ModerationWarningWhere.GuildID.EQ(parsed.GuildData.GS.ID),
+ ).UpdateAllG(parsed.Context(), models.M{"message": updatedMessage})
+ if err != nil {
+ return "Failed editing warning", err
+ }
+ if numUpdated == 0 {
+ return fmt.Sprintf("Could not find warning with ID `%d`", warningID), nil
}
return "👌", nil
@@ -959,9 +973,17 @@ var ModerationCommands = []*commands.YAGCommand{
return nil, err
}
- rows := common.GORM.Where("guild_id = ? AND id = ?", parsed.GuildData.GS.ID, parsed.Args[0].Int()).Delete(WarningModel{}).RowsAffected
- if rows < 1 {
- return "Failed deleting, most likely couldn't find the warning", nil
+ warningID := parsed.Args[0].Int()
+ numDeleted, err := models.ModerationWarnings(
+ models.ModerationWarningWhere.ID.EQ(warningID),
+ // don't delete warnings from other servers, even if ID is correct
+ models.ModerationWarningWhere.GuildID.EQ(parsed.GuildData.GS.ID),
+ ).DeleteAllG(parsed.Context())
+ if err != nil {
+ return "Failed deleting warning", err
+ }
+ if numDeleted == 0 {
+ return fmt.Sprintf("Could not find warning with ID `%d`", warningID), nil
}
return "👌", nil
@@ -993,15 +1015,21 @@ var ModerationCommands = []*commands.YAGCommand{
return nil, err
}
- rows := common.GORM.Where("guild_id = ? AND user_id = ?", parsed.GuildData.GS.ID, target.ID).Delete(WarningModel{}).RowsAffected
+ numDeleted, err := models.ModerationWarnings(
+ models.ModerationWarningWhere.GuildID.EQ(parsed.GuildData.GS.ID),
+ models.ModerationWarningWhere.UserID.EQ(discordgo.StrID(target.ID)),
+ ).DeleteAllG(parsed.Context())
+ if err != nil {
+ return "Failed deleting warnings", err
+ }
reason := parsed.Args[1].Str()
err = CreateModlogEmbed(config, parsed.Author, MAClearWarnings, target, reason, "")
if err != nil {
- return "failed sending modlog", err
+ return "Failed sending modlog", err
}
- return fmt.Sprintf("Deleted %d warnings.", rows), nil
+ return fmt.Sprintf("Deleted %d warnings.", numDeleted), nil
},
},
{
@@ -1061,8 +1089,11 @@ var ModerationCommands = []*commands.YAGCommand{
out += fmt.Sprintf("#%02d: %4d - %d\n", v.Rank, v.WarnCount, v.UserID)
}
}
- var count int
- common.GORM.Table("moderation_warnings").Where("guild_id = ?", parsed.GuildData.GS.ID).Count(&count)
+
+ count, err := models.ModerationWarnings(models.ModerationWarningWhere.GuildID.EQ(parsed.GuildData.GS.ID)).CountG(context.Background())
+ if err != nil {
+ return nil, err
+ }
out += "```\n" + fmt.Sprintf("Total Server Warnings: `%d`", count)
@@ -1139,7 +1170,7 @@ var ModerationCommands = []*commands.YAGCommand{
action := MAGiveRole
action.Prefix = "Gave the role " + role.Name + " to "
- if config.GiveRoleCmdModlog && config.IntActionChannel() != 0 {
+ if config.GiveRoleCmdModlog && config.ActionChannel != 0 {
if dur > 0 {
action.Footer = "Duration: " + common.HumanizeDuration(common.DurationPrecisionMinutes, dur)
}
@@ -1200,7 +1231,7 @@ var ModerationCommands = []*commands.YAGCommand{
action := MARemoveRole
action.Prefix = "Removed the role " + role.Name + " from "
- if config.GiveRoleCmdModlog && config.IntActionChannel() != 0 {
+ if config.GiveRoleCmdModlog && config.ActionChannel != 0 {
CreateModlogEmbed(config, parsed.Author, action, target, "", "")
}
@@ -1343,7 +1374,6 @@ func FindRole(gs *dstate.GuildSet, roleS string) *discordgo.Role {
}
func PaginateWarnings(parsed *dcmd.Data) func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
-
return func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
var err error
@@ -1351,14 +1381,24 @@ func PaginateWarnings(parsed *dcmd.Data) func(p *paginatedmessages.PaginatedMess
userID := parsed.Args[0].Int64()
limit := 6
- var result []*WarningModel
- var count int
- err = common.GORM.Table("moderation_warnings").Where("user_id = ? AND guild_id = ?", userID, parsed.GuildData.GS.ID).Count(&count).Error
- if err != nil && err != gorm.ErrRecordNotFound {
+ userIDStr := discordgo.StrID(userID)
+ count, err := models.ModerationWarnings(
+ models.ModerationWarningWhere.UserID.EQ(userIDStr),
+ models.ModerationWarningWhere.GuildID.EQ(parsed.GuildData.GS.ID),
+ ).CountG(parsed.Context())
+ if err != nil {
return nil, err
}
- err = common.GORM.Where("user_id = ? AND guild_id = ?", userID, parsed.GuildData.GS.ID).Order("id desc").Offset(skip).Limit(limit).Find(&result).Error
- if err != nil && err != gorm.ErrRecordNotFound {
+
+ result, err := models.ModerationWarnings(
+ models.ModerationWarningWhere.UserID.EQ(userIDStr),
+ models.ModerationWarningWhere.GuildID.EQ(parsed.GuildData.GS.ID),
+
+ qm.OrderBy("id desc"),
+ qm.Offset(skip),
+ qm.Limit(limit),
+ ).AllG(parsed.Context())
+ if err != nil {
return nil, err
}
@@ -1383,8 +1423,8 @@ func PaginateWarnings(parsed *dcmd.Data) func(p *paginatedmessages.PaginatedMess
}
entry_formatted += "\n"
purgedWarnLogs := logs.ConfEnableMessageLogPurge.GetBool() && entry.CreatedAt.Before(time.Now().AddDate(0, 0, -30))
- if entry.LogsLink != "" && !purgedWarnLogs {
- entry_formatted += fmt.Sprintf("> logs: [`link`](%s)\n", entry.LogsLink)
+ if entry.LogsLink.String != "" && !purgedWarnLogs {
+ entry_formatted += fmt.Sprintf("> logs: [`link`](%s)\n", entry.LogsLink.String)
}
if len([]rune(currentField.Value+entry_formatted)) > 1023 {
currentField = &discordgo.MessageEmbedField{
diff --git a/moderation/config.go b/moderation/config.go
new file mode 100644
index 0000000000..70cdb25ccf
--- /dev/null
+++ b/moderation/config.go
@@ -0,0 +1,205 @@
+package moderation
+
+import (
+ "time"
+
+ "github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
+ "github.com/botlabs-gg/yagpdb/v2/moderation/models"
+ "github.com/volatiletech/null/v8"
+ "github.com/volatiletech/sqlboiler/v4/types"
+)
+
+// For legacy reasons, many columns in the database schema are marked as
+// nullable when they should really be non-nullable, meaning working with
+// models.ModerationConfig directly is much more annoying than it should be. We
+// therefore wrap it in a Config (which has proper types) and convert to/from
+// only when strictly required.
+
+type Config struct {
+ GuildID int64
+ CreatedAt time.Time
+ UpdatedAt time.Time
+
+ // Kick
+ KickEnabled bool
+ KickCmdRoles types.Int64Array `valid:"role,true"`
+ DeleteMessagesOnKick bool
+ KickReasonOptional bool
+ KickMessage string `valid:"template,5000"`
+
+ // Ban
+ BanEnabled bool
+ BanCmdRoles types.Int64Array `valid:"role,true"`
+ BanReasonOptional bool
+ BanMessage string `valid:"template,5000"`
+ DefaultBanDeleteDays null.Int64 `valid:"0,7"`
+
+ // Timeout
+ TimeoutEnabled bool
+ TimeoutCmdRoles types.Int64Array `valid:"role,true"`
+ TimeoutReasonOptional bool
+ TimeoutRemoveReasonOptional bool
+ TimeoutMessage string `valid:"template,5000"`
+ DefaultTimeoutDuration null.Int64 `valid:"1,40320"`
+
+ // Mute/unmute
+ MuteEnabled bool
+ MuteCmdRoles types.Int64Array `valid:"role,true"`
+ MuteRole int64 `valid:"role,true"`
+ MuteDisallowReactionAdd bool
+ MuteReasonOptional bool
+ UnmuteReasonOptional bool
+ MuteManageRole bool
+ MuteRemoveRoles types.Int64Array `valid:"role,true"`
+ MuteIgnoreChannels types.Int64Array `valid:"channel,true"`
+ MuteMessage string `valid:"template,5000"`
+ UnmuteMessage string `valid:"template,5000"`
+ DefaultMuteDuration null.Int64 `valid:"0,"`
+
+ // Warn
+ WarnCommandsEnabled bool
+ WarnCmdRoles types.Int64Array `valid:"role,true"`
+ WarnIncludeChannelLogs bool
+ WarnSendToModlog bool
+ WarnMessage string `valid:"template,5000"`
+
+ // Misc
+ CleanEnabled bool
+ ReportEnabled bool
+ ActionChannel int64 `valid:"channel,true"`
+ ReportChannel int64 `valid:"channel,true"`
+ ErrorChannel int64 `valid:"channel,true"`
+ LogUnbans bool
+ LogBans bool
+ LogKicks bool
+ LogTimeouts bool
+
+ GiveRoleCmdEnabled bool
+ GiveRoleCmdModlog bool
+ GiveRoleCmdRoles types.Int64Array `valid:"role,true"`
+}
+
+func (c *Config) ToModel() *models.ModerationConfig {
+ return &models.ModerationConfig{
+ GuildID: c.GuildID,
+ CreatedAt: c.CreatedAt,
+ UpdatedAt: c.UpdatedAt,
+
+ KickEnabled: null.BoolFrom(c.KickEnabled),
+ KickCmdRoles: c.KickCmdRoles,
+ DeleteMessagesOnKick: null.BoolFrom(c.DeleteMessagesOnKick),
+ KickReasonOptional: null.BoolFrom(c.KickReasonOptional),
+ KickMessage: null.StringFrom(c.KickMessage),
+
+ BanEnabled: null.BoolFrom(c.BanEnabled),
+ BanCmdRoles: c.BanCmdRoles,
+ BanReasonOptional: null.BoolFrom(c.BanReasonOptional),
+ BanMessage: null.StringFrom(c.BanMessage),
+ DefaultBanDeleteDays: c.DefaultBanDeleteDays,
+
+ TimeoutEnabled: null.BoolFrom(c.TimeoutEnabled),
+ TimeoutCmdRoles: c.TimeoutCmdRoles,
+ TimeoutReasonOptional: null.BoolFrom(c.TimeoutReasonOptional),
+ TimeoutRemoveReasonOptional: null.BoolFrom(c.TimeoutRemoveReasonOptional),
+ TimeoutMessage: null.StringFrom(c.TimeoutMessage),
+ DefaultTimeoutDuration: c.DefaultTimeoutDuration,
+
+ MuteEnabled: null.BoolFrom(c.MuteEnabled),
+ MuteCmdRoles: c.MuteCmdRoles,
+ MuteRole: null.StringFrom(discordgo.StrID(c.MuteRole)),
+ MuteDisallowReactionAdd: null.BoolFrom(c.MuteDisallowReactionAdd),
+ MuteReasonOptional: null.BoolFrom(c.MuteReasonOptional),
+ UnmuteReasonOptional: null.BoolFrom(c.UnmuteReasonOptional),
+ MuteManageRole: null.BoolFrom(c.MuteManageRole),
+ MuteRemoveRoles: c.MuteRemoveRoles,
+ MuteIgnoreChannels: c.MuteIgnoreChannels,
+ MuteMessage: null.StringFrom(c.MuteMessage),
+ UnmuteMessage: null.StringFrom(c.UnmuteMessage),
+ DefaultMuteDuration: c.DefaultMuteDuration,
+
+ WarnCommandsEnabled: null.BoolFrom(c.WarnCommandsEnabled),
+ WarnCmdRoles: c.WarnCmdRoles,
+ WarnIncludeChannelLogs: null.BoolFrom(c.WarnIncludeChannelLogs),
+ WarnSendToModlog: null.BoolFrom(c.WarnSendToModlog),
+ WarnMessage: null.StringFrom(c.WarnMessage),
+
+ CleanEnabled: null.BoolFrom(c.CleanEnabled),
+ ReportEnabled: null.BoolFrom(c.ReportEnabled),
+ ActionChannel: null.StringFrom(discordgo.StrID(c.ActionChannel)),
+ ReportChannel: null.StringFrom(discordgo.StrID(c.ReportChannel)),
+ ErrorChannel: null.StringFrom(discordgo.StrID(c.ErrorChannel)),
+ LogUnbans: null.BoolFrom(c.LogUnbans),
+ LogBans: null.BoolFrom(c.LogBans),
+ LogKicks: null.BoolFrom(c.LogKicks),
+ LogTimeouts: null.BoolFrom(c.LogTimeouts),
+
+ GiveRoleCmdEnabled: null.BoolFrom(c.GiveRoleCmdEnabled),
+ GiveRoleCmdModlog: null.BoolFrom(c.GiveRoleCmdModlog),
+ GiveRoleCmdRoles: c.GiveRoleCmdRoles,
+ }
+}
+
+func configFromModel(model *models.ModerationConfig) *Config {
+ muteRole, _ := discordgo.ParseID(model.MuteRole.String)
+ actionChannel, _ := discordgo.ParseID(model.ActionChannel.String)
+ reportChannel, _ := discordgo.ParseID(model.ReportChannel.String)
+ errorChannel, _ := discordgo.ParseID(model.ErrorChannel.String)
+
+ return &Config{
+ GuildID: model.GuildID,
+ CreatedAt: model.CreatedAt,
+ UpdatedAt: model.UpdatedAt,
+
+ KickEnabled: model.KickEnabled.Bool,
+ KickCmdRoles: model.KickCmdRoles,
+ DeleteMessagesOnKick: model.DeleteMessagesOnKick.Bool,
+ KickReasonOptional: model.KickReasonOptional.Bool,
+ KickMessage: model.KickMessage.String,
+
+ BanEnabled: model.BanEnabled.Bool,
+ BanCmdRoles: model.BanCmdRoles,
+ BanReasonOptional: model.BanReasonOptional.Bool,
+ BanMessage: model.BanMessage.String,
+ DefaultBanDeleteDays: model.DefaultBanDeleteDays,
+
+ TimeoutEnabled: model.TimeoutEnabled.Bool,
+ TimeoutCmdRoles: model.TimeoutCmdRoles,
+ TimeoutReasonOptional: model.TimeoutReasonOptional.Bool,
+ TimeoutRemoveReasonOptional: model.TimeoutRemoveReasonOptional.Bool,
+ TimeoutMessage: model.TimeoutMessage.String,
+ DefaultTimeoutDuration: model.DefaultTimeoutDuration,
+
+ MuteEnabled: model.MuteEnabled.Bool,
+ MuteCmdRoles: model.MuteCmdRoles,
+ MuteRole: muteRole,
+ MuteDisallowReactionAdd: model.MuteDisallowReactionAdd.Bool,
+ MuteReasonOptional: model.MuteReasonOptional.Bool,
+ UnmuteReasonOptional: model.UnmuteReasonOptional.Bool,
+ MuteManageRole: model.MuteManageRole.Bool,
+ MuteRemoveRoles: model.MuteRemoveRoles,
+ MuteIgnoreChannels: model.MuteIgnoreChannels,
+ MuteMessage: model.MuteMessage.String,
+ UnmuteMessage: model.UnmuteMessage.String,
+ DefaultMuteDuration: model.DefaultMuteDuration,
+
+ WarnCommandsEnabled: model.WarnCommandsEnabled.Bool,
+ WarnCmdRoles: model.WarnCmdRoles,
+ WarnIncludeChannelLogs: model.WarnIncludeChannelLogs.Bool,
+ WarnSendToModlog: model.WarnSendToModlog.Bool,
+ WarnMessage: model.WarnMessage.String,
+
+ CleanEnabled: model.CleanEnabled.Bool,
+ ReportEnabled: model.ReportEnabled.Bool,
+ ActionChannel: actionChannel,
+ ReportChannel: reportChannel,
+ ErrorChannel: errorChannel,
+ LogUnbans: model.LogUnbans.Bool,
+ LogBans: model.LogBans.Bool,
+ LogKicks: model.LogKicks.Bool,
+ LogTimeouts: model.LogTimeouts.Bool,
+
+ GiveRoleCmdEnabled: model.GiveRoleCmdEnabled.Bool,
+ GiveRoleCmdModlog: model.GiveRoleCmdModlog.Bool,
+ GiveRoleCmdRoles: model.GiveRoleCmdRoles,
+ }
+}
diff --git a/moderation/models.go b/moderation/models.go
deleted file mode 100644
index 3356f46cb7..0000000000
--- a/moderation/models.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package moderation
-
-import (
- "context"
- "database/sql"
- "strconv"
- "time"
-
- "github.com/botlabs-gg/yagpdb/v2/common"
- "github.com/botlabs-gg/yagpdb/v2/common/configstore"
- "github.com/botlabs-gg/yagpdb/v2/common/featureflags"
- "github.com/botlabs-gg/yagpdb/v2/common/pubsub"
- "github.com/lib/pq"
-)
-
-type Config struct {
- configstore.GuildConfigModel
-
- // Kick command
- KickEnabled bool
- KickCmdRoles pq.Int64Array `gorm:"type:bigint[]" valid:"role,true"`
- DeleteMessagesOnKick bool
- KickReasonOptional bool
- KickMessage string `valid:"template,5000"`
-
- // Ban
- BanEnabled bool
- BanCmdRoles pq.Int64Array `gorm:"type:bigint[]" valid:"role,true"`
- BanReasonOptional bool
- BanMessage string `valid:"template,5000"`
- DefaultBanDeleteDays sql.NullInt64 `gorm:"default:1" valid:"0,7"`
-
- // Timeout
- TimeoutEnabled bool
- TimeoutCmdRoles pq.Int64Array `gorm:"type:bigint[]" valid:"role,true"`
- TimeoutReasonOptional bool
- TimeoutRemoveReasonOptional bool
- TimeoutMessage string `valid:"template,5000"`
- DefaultTimeoutDuration sql.NullInt64 `gorm:"default:10" valid:"1,40320"`
-
- // Mute/unmute
- MuteEnabled bool
- MuteCmdRoles pq.Int64Array `gorm:"type:bigint[]" valid:"role,true"`
- MuteRole string `valid:"role,true"`
- MuteDisallowReactionAdd bool
- MuteReasonOptional bool
- UnmuteReasonOptional bool
- MuteManageRole bool
- MuteRemoveRoles pq.Int64Array `gorm:"type:bigint[]" valid:"role,true"`
- MuteIgnoreChannels pq.Int64Array `gorm:"type:bigint[]" valid:"channel,true"`
- MuteMessage string `valid:"template,5000"`
- UnmuteMessage string `valid:"template,5000"`
- DefaultMuteDuration sql.NullInt64 `gorm:"default:10" valid:"0,"`
-
- // Warn
- WarnCommandsEnabled bool
- WarnCmdRoles pq.Int64Array `gorm:"type:bigint[]" valid:"role,true"`
- WarnIncludeChannelLogs bool
- WarnSendToModlog bool
- WarnMessage string `valid:"template,5000"`
-
- // Misc
- CleanEnabled bool
- ReportEnabled bool
- ActionChannel string `valid:"channel,true"`
- ReportChannel string `valid:"channel,true"`
- ErrorChannel string `valid:"channel,true"`
- LogUnbans bool
- LogBans bool
- LogKicks bool `gorm:"default:true"`
- LogTimeouts bool
-
- GiveRoleCmdEnabled bool
- GiveRoleCmdModlog bool
- GiveRoleCmdRoles pq.Int64Array `gorm:"type:bigint[]" valid:"role,true"`
-}
-
-func (c *Config) IntMuteRole() (r int64) {
- r, _ = strconv.ParseInt(c.MuteRole, 10, 64)
- return
-}
-
-func (c *Config) IntActionChannel() (r int64) {
- r, _ = strconv.ParseInt(c.ActionChannel, 10, 64)
- return
-}
-
-func (c *Config) IntReportChannel() (r int64) {
- r, _ = strconv.ParseInt(c.ReportChannel, 10, 64)
- return
-}
-
-func (c *Config) IntErrorChannel() (r int64) {
- r, _ = strconv.ParseInt(c.ErrorChannel, 10, 64)
- return
-}
-
-func (c *Config) GetName() string {
- return "moderation"
-}
-
-func (c *Config) TableName() string {
- return "moderation_configs"
-}
-
-func (c *Config) Save(guildID int64) error {
- c.GuildID = guildID
- err := configstore.SQL.SetGuildConfig(context.Background(), c)
- if err != nil {
- return err
- }
-
- if err = featureflags.UpdatePluginFeatureFlags(guildID, &Plugin{}); err != nil {
- return err
- }
-
- pubsub.Publish("mod_refresh_mute_override", guildID, nil)
- return err
-}
-
-type WarningModel struct {
- common.SmallModel
- GuildID int64 `gorm:"index"`
- UserID string
- AuthorID string
-
- // Username and discrim for author incase he/she leaves
- AuthorUsernameDiscrim string
-
- Message string
- LogsLink string
-}
-
-func (w *WarningModel) TableName() string {
- return "moderation_warnings"
-}
-
-type MuteModel struct {
- common.SmallModel
-
- ExpiresAt time.Time
-
- GuildID int64 `gorm:"index"`
- UserID int64
-
- AuthorID int64
- Reason string
-
- RemovedRoles pq.Int64Array `gorm:"type:bigint[]"`
-}
-
-func (m *MuteModel) TableName() string {
- return "muted_users"
-}
diff --git a/moderation/models/boil_queries.go b/moderation/models/boil_queries.go
new file mode 100644
index 0000000000..20c2563fdb
--- /dev/null
+++ b/moderation/models/boil_queries.go
@@ -0,0 +1,38 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "regexp"
+
+ "github.com/volatiletech/sqlboiler/v4/drivers"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+)
+
+var dialect = drivers.Dialect{
+ LQ: 0x22,
+ RQ: 0x22,
+
+ UseIndexPlaceholders: true,
+ UseLastInsertID: false,
+ UseSchema: false,
+ UseDefaultKeyword: true,
+ UseAutoColumns: false,
+ UseTopClause: false,
+ UseOutputClause: false,
+ UseCaseWhenExistsClause: false,
+}
+
+// This is a dummy variable to prevent unused regexp import error
+var _ = ®exp.Regexp{}
+
+// NewQuery initializes a new Query using the passed in QueryMods
+func NewQuery(mods ...qm.QueryMod) *queries.Query {
+ q := &queries.Query{}
+ queries.SetDialect(q, &dialect)
+ qm.Apply(q, mods...)
+
+ return q
+}
diff --git a/moderation/models/boil_table_names.go b/moderation/models/boil_table_names.go
new file mode 100644
index 0000000000..cf4e74f5e2
--- /dev/null
+++ b/moderation/models/boil_table_names.go
@@ -0,0 +1,14 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+var TableNames = struct {
+ ModerationConfigs string
+ ModerationWarnings string
+ MutedUsers string
+}{
+ ModerationConfigs: "moderation_configs",
+ ModerationWarnings: "moderation_warnings",
+ MutedUsers: "muted_users",
+}
diff --git a/moderation/models/boil_types.go b/moderation/models/boil_types.go
new file mode 100644
index 0000000000..02a6fdfdc5
--- /dev/null
+++ b/moderation/models/boil_types.go
@@ -0,0 +1,52 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "strconv"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/strmangle"
+)
+
+// M type is for providing columns and column values to UpdateAll.
+type M map[string]interface{}
+
+// ErrSyncFail occurs during insert when the record could not be retrieved in
+// order to populate default value information. This usually happens when LastInsertId
+// fails or there was a primary key configuration that was not resolvable.
+var ErrSyncFail = errors.New("models: failed to synchronize data after insert")
+
+type insertCache struct {
+ query string
+ retQuery string
+ valueMapping []uint64
+ retMapping []uint64
+}
+
+type updateCache struct {
+ query string
+ valueMapping []uint64
+}
+
+func makeCacheKey(cols boil.Columns, nzDefaults []string) string {
+ buf := strmangle.GetBuffer()
+
+ buf.WriteString(strconv.Itoa(cols.Kind))
+ for _, w := range cols.Cols {
+ buf.WriteString(w)
+ }
+
+ if len(nzDefaults) != 0 {
+ buf.WriteByte('.')
+ }
+ for _, nz := range nzDefaults {
+ buf.WriteString(nz)
+ }
+
+ str := buf.String()
+ strmangle.PutBuffer(buf)
+ return str
+}
diff --git a/moderation/models/boil_view_names.go b/moderation/models/boil_view_names.go
new file mode 100644
index 0000000000..01504d82bf
--- /dev/null
+++ b/moderation/models/boil_view_names.go
@@ -0,0 +1,7 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+var ViewNames = struct {
+}{}
diff --git a/moderation/models/moderation_configs.go b/moderation/models/moderation_configs.go
new file mode 100644
index 0000000000..84032cff8f
--- /dev/null
+++ b/moderation/models/moderation_configs.go
@@ -0,0 +1,1293 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/null/v8"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+ "github.com/volatiletech/sqlboiler/v4/queries/qmhelper"
+ "github.com/volatiletech/sqlboiler/v4/types"
+ "github.com/volatiletech/strmangle"
+)
+
+// ModerationConfig is an object representing the database table.
+type ModerationConfig struct {
+ GuildID int64 `boil:"guild_id" json:"guild_id" toml:"guild_id" yaml:"guild_id"`
+ CreatedAt time.Time `boil:"created_at" json:"created_at" toml:"created_at" yaml:"created_at"`
+ UpdatedAt time.Time `boil:"updated_at" json:"updated_at" toml:"updated_at" yaml:"updated_at"`
+ KickEnabled null.Bool `boil:"kick_enabled" json:"kick_enabled,omitempty" toml:"kick_enabled" yaml:"kick_enabled,omitempty"`
+ KickCmdRoles types.Int64Array `boil:"kick_cmd_roles" json:"kick_cmd_roles,omitempty" toml:"kick_cmd_roles" yaml:"kick_cmd_roles,omitempty"`
+ DeleteMessagesOnKick null.Bool `boil:"delete_messages_on_kick" json:"delete_messages_on_kick,omitempty" toml:"delete_messages_on_kick" yaml:"delete_messages_on_kick,omitempty"`
+ KickReasonOptional null.Bool `boil:"kick_reason_optional" json:"kick_reason_optional,omitempty" toml:"kick_reason_optional" yaml:"kick_reason_optional,omitempty"`
+ KickMessage null.String `boil:"kick_message" json:"kick_message,omitempty" toml:"kick_message" yaml:"kick_message,omitempty"`
+ BanEnabled null.Bool `boil:"ban_enabled" json:"ban_enabled,omitempty" toml:"ban_enabled" yaml:"ban_enabled,omitempty"`
+ BanCmdRoles types.Int64Array `boil:"ban_cmd_roles" json:"ban_cmd_roles,omitempty" toml:"ban_cmd_roles" yaml:"ban_cmd_roles,omitempty"`
+ BanReasonOptional null.Bool `boil:"ban_reason_optional" json:"ban_reason_optional,omitempty" toml:"ban_reason_optional" yaml:"ban_reason_optional,omitempty"`
+ BanMessage null.String `boil:"ban_message" json:"ban_message,omitempty" toml:"ban_message" yaml:"ban_message,omitempty"`
+ DefaultBanDeleteDays null.Int64 `boil:"default_ban_delete_days" json:"default_ban_delete_days,omitempty" toml:"default_ban_delete_days" yaml:"default_ban_delete_days,omitempty"`
+ TimeoutEnabled null.Bool `boil:"timeout_enabled" json:"timeout_enabled,omitempty" toml:"timeout_enabled" yaml:"timeout_enabled,omitempty"`
+ TimeoutCmdRoles types.Int64Array `boil:"timeout_cmd_roles" json:"timeout_cmd_roles,omitempty" toml:"timeout_cmd_roles" yaml:"timeout_cmd_roles,omitempty"`
+ TimeoutReasonOptional null.Bool `boil:"timeout_reason_optional" json:"timeout_reason_optional,omitempty" toml:"timeout_reason_optional" yaml:"timeout_reason_optional,omitempty"`
+ TimeoutRemoveReasonOptional null.Bool `boil:"timeout_remove_reason_optional" json:"timeout_remove_reason_optional,omitempty" toml:"timeout_remove_reason_optional" yaml:"timeout_remove_reason_optional,omitempty"`
+ TimeoutMessage null.String `boil:"timeout_message" json:"timeout_message,omitempty" toml:"timeout_message" yaml:"timeout_message,omitempty"`
+ DefaultTimeoutDuration null.Int64 `boil:"default_timeout_duration" json:"default_timeout_duration,omitempty" toml:"default_timeout_duration" yaml:"default_timeout_duration,omitempty"`
+ MuteEnabled null.Bool `boil:"mute_enabled" json:"mute_enabled,omitempty" toml:"mute_enabled" yaml:"mute_enabled,omitempty"`
+ MuteCmdRoles types.Int64Array `boil:"mute_cmd_roles" json:"mute_cmd_roles,omitempty" toml:"mute_cmd_roles" yaml:"mute_cmd_roles,omitempty"`
+ MuteRole null.String `boil:"mute_role" json:"mute_role,omitempty" toml:"mute_role" yaml:"mute_role,omitempty"`
+ MuteDisallowReactionAdd null.Bool `boil:"mute_disallow_reaction_add" json:"mute_disallow_reaction_add,omitempty" toml:"mute_disallow_reaction_add" yaml:"mute_disallow_reaction_add,omitempty"`
+ MuteReasonOptional null.Bool `boil:"mute_reason_optional" json:"mute_reason_optional,omitempty" toml:"mute_reason_optional" yaml:"mute_reason_optional,omitempty"`
+ UnmuteReasonOptional null.Bool `boil:"unmute_reason_optional" json:"unmute_reason_optional,omitempty" toml:"unmute_reason_optional" yaml:"unmute_reason_optional,omitempty"`
+ MuteManageRole null.Bool `boil:"mute_manage_role" json:"mute_manage_role,omitempty" toml:"mute_manage_role" yaml:"mute_manage_role,omitempty"`
+ MuteRemoveRoles types.Int64Array `boil:"mute_remove_roles" json:"mute_remove_roles,omitempty" toml:"mute_remove_roles" yaml:"mute_remove_roles,omitempty"`
+ MuteIgnoreChannels types.Int64Array `boil:"mute_ignore_channels" json:"mute_ignore_channels,omitempty" toml:"mute_ignore_channels" yaml:"mute_ignore_channels,omitempty"`
+ MuteMessage null.String `boil:"mute_message" json:"mute_message,omitempty" toml:"mute_message" yaml:"mute_message,omitempty"`
+ UnmuteMessage null.String `boil:"unmute_message" json:"unmute_message,omitempty" toml:"unmute_message" yaml:"unmute_message,omitempty"`
+ DefaultMuteDuration null.Int64 `boil:"default_mute_duration" json:"default_mute_duration,omitempty" toml:"default_mute_duration" yaml:"default_mute_duration,omitempty"`
+ WarnCommandsEnabled null.Bool `boil:"warn_commands_enabled" json:"warn_commands_enabled,omitempty" toml:"warn_commands_enabled" yaml:"warn_commands_enabled,omitempty"`
+ WarnCmdRoles types.Int64Array `boil:"warn_cmd_roles" json:"warn_cmd_roles,omitempty" toml:"warn_cmd_roles" yaml:"warn_cmd_roles,omitempty"`
+ WarnIncludeChannelLogs null.Bool `boil:"warn_include_channel_logs" json:"warn_include_channel_logs,omitempty" toml:"warn_include_channel_logs" yaml:"warn_include_channel_logs,omitempty"`
+ WarnSendToModlog null.Bool `boil:"warn_send_to_modlog" json:"warn_send_to_modlog,omitempty" toml:"warn_send_to_modlog" yaml:"warn_send_to_modlog,omitempty"`
+ WarnMessage null.String `boil:"warn_message" json:"warn_message,omitempty" toml:"warn_message" yaml:"warn_message,omitempty"`
+ CleanEnabled null.Bool `boil:"clean_enabled" json:"clean_enabled,omitempty" toml:"clean_enabled" yaml:"clean_enabled,omitempty"`
+ ReportEnabled null.Bool `boil:"report_enabled" json:"report_enabled,omitempty" toml:"report_enabled" yaml:"report_enabled,omitempty"`
+ ActionChannel null.String `boil:"action_channel" json:"action_channel,omitempty" toml:"action_channel" yaml:"action_channel,omitempty"`
+ ReportChannel null.String `boil:"report_channel" json:"report_channel,omitempty" toml:"report_channel" yaml:"report_channel,omitempty"`
+ ErrorChannel null.String `boil:"error_channel" json:"error_channel,omitempty" toml:"error_channel" yaml:"error_channel,omitempty"`
+ LogUnbans null.Bool `boil:"log_unbans" json:"log_unbans,omitempty" toml:"log_unbans" yaml:"log_unbans,omitempty"`
+ LogBans null.Bool `boil:"log_bans" json:"log_bans,omitempty" toml:"log_bans" yaml:"log_bans,omitempty"`
+ LogKicks null.Bool `boil:"log_kicks" json:"log_kicks,omitempty" toml:"log_kicks" yaml:"log_kicks,omitempty"`
+ LogTimeouts null.Bool `boil:"log_timeouts" json:"log_timeouts,omitempty" toml:"log_timeouts" yaml:"log_timeouts,omitempty"`
+ GiveRoleCmdEnabled null.Bool `boil:"give_role_cmd_enabled" json:"give_role_cmd_enabled,omitempty" toml:"give_role_cmd_enabled" yaml:"give_role_cmd_enabled,omitempty"`
+ GiveRoleCmdModlog null.Bool `boil:"give_role_cmd_modlog" json:"give_role_cmd_modlog,omitempty" toml:"give_role_cmd_modlog" yaml:"give_role_cmd_modlog,omitempty"`
+ GiveRoleCmdRoles types.Int64Array `boil:"give_role_cmd_roles" json:"give_role_cmd_roles,omitempty" toml:"give_role_cmd_roles" yaml:"give_role_cmd_roles,omitempty"`
+
+ R *moderationConfigR `boil:"-" json:"-" toml:"-" yaml:"-"`
+ L moderationConfigL `boil:"-" json:"-" toml:"-" yaml:"-"`
+}
+
+var ModerationConfigColumns = struct {
+ GuildID string
+ CreatedAt string
+ UpdatedAt string
+ KickEnabled string
+ KickCmdRoles string
+ DeleteMessagesOnKick string
+ KickReasonOptional string
+ KickMessage string
+ BanEnabled string
+ BanCmdRoles string
+ BanReasonOptional string
+ BanMessage string
+ DefaultBanDeleteDays string
+ TimeoutEnabled string
+ TimeoutCmdRoles string
+ TimeoutReasonOptional string
+ TimeoutRemoveReasonOptional string
+ TimeoutMessage string
+ DefaultTimeoutDuration string
+ MuteEnabled string
+ MuteCmdRoles string
+ MuteRole string
+ MuteDisallowReactionAdd string
+ MuteReasonOptional string
+ UnmuteReasonOptional string
+ MuteManageRole string
+ MuteRemoveRoles string
+ MuteIgnoreChannels string
+ MuteMessage string
+ UnmuteMessage string
+ DefaultMuteDuration string
+ WarnCommandsEnabled string
+ WarnCmdRoles string
+ WarnIncludeChannelLogs string
+ WarnSendToModlog string
+ WarnMessage string
+ CleanEnabled string
+ ReportEnabled string
+ ActionChannel string
+ ReportChannel string
+ ErrorChannel string
+ LogUnbans string
+ LogBans string
+ LogKicks string
+ LogTimeouts string
+ GiveRoleCmdEnabled string
+ GiveRoleCmdModlog string
+ GiveRoleCmdRoles string
+}{
+ GuildID: "guild_id",
+ CreatedAt: "created_at",
+ UpdatedAt: "updated_at",
+ KickEnabled: "kick_enabled",
+ KickCmdRoles: "kick_cmd_roles",
+ DeleteMessagesOnKick: "delete_messages_on_kick",
+ KickReasonOptional: "kick_reason_optional",
+ KickMessage: "kick_message",
+ BanEnabled: "ban_enabled",
+ BanCmdRoles: "ban_cmd_roles",
+ BanReasonOptional: "ban_reason_optional",
+ BanMessage: "ban_message",
+ DefaultBanDeleteDays: "default_ban_delete_days",
+ TimeoutEnabled: "timeout_enabled",
+ TimeoutCmdRoles: "timeout_cmd_roles",
+ TimeoutReasonOptional: "timeout_reason_optional",
+ TimeoutRemoveReasonOptional: "timeout_remove_reason_optional",
+ TimeoutMessage: "timeout_message",
+ DefaultTimeoutDuration: "default_timeout_duration",
+ MuteEnabled: "mute_enabled",
+ MuteCmdRoles: "mute_cmd_roles",
+ MuteRole: "mute_role",
+ MuteDisallowReactionAdd: "mute_disallow_reaction_add",
+ MuteReasonOptional: "mute_reason_optional",
+ UnmuteReasonOptional: "unmute_reason_optional",
+ MuteManageRole: "mute_manage_role",
+ MuteRemoveRoles: "mute_remove_roles",
+ MuteIgnoreChannels: "mute_ignore_channels",
+ MuteMessage: "mute_message",
+ UnmuteMessage: "unmute_message",
+ DefaultMuteDuration: "default_mute_duration",
+ WarnCommandsEnabled: "warn_commands_enabled",
+ WarnCmdRoles: "warn_cmd_roles",
+ WarnIncludeChannelLogs: "warn_include_channel_logs",
+ WarnSendToModlog: "warn_send_to_modlog",
+ WarnMessage: "warn_message",
+ CleanEnabled: "clean_enabled",
+ ReportEnabled: "report_enabled",
+ ActionChannel: "action_channel",
+ ReportChannel: "report_channel",
+ ErrorChannel: "error_channel",
+ LogUnbans: "log_unbans",
+ LogBans: "log_bans",
+ LogKicks: "log_kicks",
+ LogTimeouts: "log_timeouts",
+ GiveRoleCmdEnabled: "give_role_cmd_enabled",
+ GiveRoleCmdModlog: "give_role_cmd_modlog",
+ GiveRoleCmdRoles: "give_role_cmd_roles",
+}
+
+var ModerationConfigTableColumns = struct {
+ GuildID string
+ CreatedAt string
+ UpdatedAt string
+ KickEnabled string
+ KickCmdRoles string
+ DeleteMessagesOnKick string
+ KickReasonOptional string
+ KickMessage string
+ BanEnabled string
+ BanCmdRoles string
+ BanReasonOptional string
+ BanMessage string
+ DefaultBanDeleteDays string
+ TimeoutEnabled string
+ TimeoutCmdRoles string
+ TimeoutReasonOptional string
+ TimeoutRemoveReasonOptional string
+ TimeoutMessage string
+ DefaultTimeoutDuration string
+ MuteEnabled string
+ MuteCmdRoles string
+ MuteRole string
+ MuteDisallowReactionAdd string
+ MuteReasonOptional string
+ UnmuteReasonOptional string
+ MuteManageRole string
+ MuteRemoveRoles string
+ MuteIgnoreChannels string
+ MuteMessage string
+ UnmuteMessage string
+ DefaultMuteDuration string
+ WarnCommandsEnabled string
+ WarnCmdRoles string
+ WarnIncludeChannelLogs string
+ WarnSendToModlog string
+ WarnMessage string
+ CleanEnabled string
+ ReportEnabled string
+ ActionChannel string
+ ReportChannel string
+ ErrorChannel string
+ LogUnbans string
+ LogBans string
+ LogKicks string
+ LogTimeouts string
+ GiveRoleCmdEnabled string
+ GiveRoleCmdModlog string
+ GiveRoleCmdRoles string
+}{
+ GuildID: "moderation_configs.guild_id",
+ CreatedAt: "moderation_configs.created_at",
+ UpdatedAt: "moderation_configs.updated_at",
+ KickEnabled: "moderation_configs.kick_enabled",
+ KickCmdRoles: "moderation_configs.kick_cmd_roles",
+ DeleteMessagesOnKick: "moderation_configs.delete_messages_on_kick",
+ KickReasonOptional: "moderation_configs.kick_reason_optional",
+ KickMessage: "moderation_configs.kick_message",
+ BanEnabled: "moderation_configs.ban_enabled",
+ BanCmdRoles: "moderation_configs.ban_cmd_roles",
+ BanReasonOptional: "moderation_configs.ban_reason_optional",
+ BanMessage: "moderation_configs.ban_message",
+ DefaultBanDeleteDays: "moderation_configs.default_ban_delete_days",
+ TimeoutEnabled: "moderation_configs.timeout_enabled",
+ TimeoutCmdRoles: "moderation_configs.timeout_cmd_roles",
+ TimeoutReasonOptional: "moderation_configs.timeout_reason_optional",
+ TimeoutRemoveReasonOptional: "moderation_configs.timeout_remove_reason_optional",
+ TimeoutMessage: "moderation_configs.timeout_message",
+ DefaultTimeoutDuration: "moderation_configs.default_timeout_duration",
+ MuteEnabled: "moderation_configs.mute_enabled",
+ MuteCmdRoles: "moderation_configs.mute_cmd_roles",
+ MuteRole: "moderation_configs.mute_role",
+ MuteDisallowReactionAdd: "moderation_configs.mute_disallow_reaction_add",
+ MuteReasonOptional: "moderation_configs.mute_reason_optional",
+ UnmuteReasonOptional: "moderation_configs.unmute_reason_optional",
+ MuteManageRole: "moderation_configs.mute_manage_role",
+ MuteRemoveRoles: "moderation_configs.mute_remove_roles",
+ MuteIgnoreChannels: "moderation_configs.mute_ignore_channels",
+ MuteMessage: "moderation_configs.mute_message",
+ UnmuteMessage: "moderation_configs.unmute_message",
+ DefaultMuteDuration: "moderation_configs.default_mute_duration",
+ WarnCommandsEnabled: "moderation_configs.warn_commands_enabled",
+ WarnCmdRoles: "moderation_configs.warn_cmd_roles",
+ WarnIncludeChannelLogs: "moderation_configs.warn_include_channel_logs",
+ WarnSendToModlog: "moderation_configs.warn_send_to_modlog",
+ WarnMessage: "moderation_configs.warn_message",
+ CleanEnabled: "moderation_configs.clean_enabled",
+ ReportEnabled: "moderation_configs.report_enabled",
+ ActionChannel: "moderation_configs.action_channel",
+ ReportChannel: "moderation_configs.report_channel",
+ ErrorChannel: "moderation_configs.error_channel",
+ LogUnbans: "moderation_configs.log_unbans",
+ LogBans: "moderation_configs.log_bans",
+ LogKicks: "moderation_configs.log_kicks",
+ LogTimeouts: "moderation_configs.log_timeouts",
+ GiveRoleCmdEnabled: "moderation_configs.give_role_cmd_enabled",
+ GiveRoleCmdModlog: "moderation_configs.give_role_cmd_modlog",
+ GiveRoleCmdRoles: "moderation_configs.give_role_cmd_roles",
+}
+
+// Generated where
+
+type whereHelperint64 struct{ field string }
+
+func (w whereHelperint64) EQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperint64) NEQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperint64) LT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperint64) LTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperint64) GT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperint64) GTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperint64) IN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperint64) NIN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+type whereHelpertime_Time struct{ field string }
+
+func (w whereHelpertime_Time) EQ(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.EQ, x)
+}
+func (w whereHelpertime_Time) NEQ(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.NEQ, x)
+}
+func (w whereHelpertime_Time) LT(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpertime_Time) LTE(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpertime_Time) GT(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpertime_Time) GTE(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+type whereHelpernull_Bool struct{ field string }
+
+func (w whereHelpernull_Bool) EQ(x null.Bool) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpernull_Bool) NEQ(x null.Bool) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpernull_Bool) LT(x null.Bool) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpernull_Bool) LTE(x null.Bool) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpernull_Bool) GT(x null.Bool) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpernull_Bool) GTE(x null.Bool) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+func (w whereHelpernull_Bool) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpernull_Bool) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+type whereHelpertypes_Int64Array struct{ field string }
+
+func (w whereHelpertypes_Int64Array) EQ(x types.Int64Array) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpertypes_Int64Array) NEQ(x types.Int64Array) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpertypes_Int64Array) LT(x types.Int64Array) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpertypes_Int64Array) LTE(x types.Int64Array) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpertypes_Int64Array) GT(x types.Int64Array) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpertypes_Int64Array) GTE(x types.Int64Array) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+func (w whereHelpertypes_Int64Array) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpertypes_Int64Array) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+type whereHelpernull_String struct{ field string }
+
+func (w whereHelpernull_String) EQ(x null.String) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpernull_String) NEQ(x null.String) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpernull_String) LT(x null.String) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpernull_String) LTE(x null.String) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpernull_String) GT(x null.String) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpernull_String) GTE(x null.String) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+func (w whereHelpernull_String) LIKE(x null.String) qm.QueryMod {
+ return qm.Where(w.field+" LIKE ?", x)
+}
+func (w whereHelpernull_String) NLIKE(x null.String) qm.QueryMod {
+ return qm.Where(w.field+" NOT LIKE ?", x)
+}
+func (w whereHelpernull_String) ILIKE(x null.String) qm.QueryMod {
+ return qm.Where(w.field+" ILIKE ?", x)
+}
+func (w whereHelpernull_String) NILIKE(x null.String) qm.QueryMod {
+ return qm.Where(w.field+" NOT ILIKE ?", x)
+}
+func (w whereHelpernull_String) IN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelpernull_String) NIN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+func (w whereHelpernull_String) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpernull_String) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+type whereHelpernull_Int64 struct{ field string }
+
+func (w whereHelpernull_Int64) EQ(x null.Int64) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpernull_Int64) NEQ(x null.Int64) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpernull_Int64) LT(x null.Int64) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpernull_Int64) LTE(x null.Int64) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpernull_Int64) GT(x null.Int64) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpernull_Int64) GTE(x null.Int64) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+func (w whereHelpernull_Int64) IN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelpernull_Int64) NIN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+func (w whereHelpernull_Int64) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpernull_Int64) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+var ModerationConfigWhere = struct {
+ GuildID whereHelperint64
+ CreatedAt whereHelpertime_Time
+ UpdatedAt whereHelpertime_Time
+ KickEnabled whereHelpernull_Bool
+ KickCmdRoles whereHelpertypes_Int64Array
+ DeleteMessagesOnKick whereHelpernull_Bool
+ KickReasonOptional whereHelpernull_Bool
+ KickMessage whereHelpernull_String
+ BanEnabled whereHelpernull_Bool
+ BanCmdRoles whereHelpertypes_Int64Array
+ BanReasonOptional whereHelpernull_Bool
+ BanMessage whereHelpernull_String
+ DefaultBanDeleteDays whereHelpernull_Int64
+ TimeoutEnabled whereHelpernull_Bool
+ TimeoutCmdRoles whereHelpertypes_Int64Array
+ TimeoutReasonOptional whereHelpernull_Bool
+ TimeoutRemoveReasonOptional whereHelpernull_Bool
+ TimeoutMessage whereHelpernull_String
+ DefaultTimeoutDuration whereHelpernull_Int64
+ MuteEnabled whereHelpernull_Bool
+ MuteCmdRoles whereHelpertypes_Int64Array
+ MuteRole whereHelpernull_String
+ MuteDisallowReactionAdd whereHelpernull_Bool
+ MuteReasonOptional whereHelpernull_Bool
+ UnmuteReasonOptional whereHelpernull_Bool
+ MuteManageRole whereHelpernull_Bool
+ MuteRemoveRoles whereHelpertypes_Int64Array
+ MuteIgnoreChannels whereHelpertypes_Int64Array
+ MuteMessage whereHelpernull_String
+ UnmuteMessage whereHelpernull_String
+ DefaultMuteDuration whereHelpernull_Int64
+ WarnCommandsEnabled whereHelpernull_Bool
+ WarnCmdRoles whereHelpertypes_Int64Array
+ WarnIncludeChannelLogs whereHelpernull_Bool
+ WarnSendToModlog whereHelpernull_Bool
+ WarnMessage whereHelpernull_String
+ CleanEnabled whereHelpernull_Bool
+ ReportEnabled whereHelpernull_Bool
+ ActionChannel whereHelpernull_String
+ ReportChannel whereHelpernull_String
+ ErrorChannel whereHelpernull_String
+ LogUnbans whereHelpernull_Bool
+ LogBans whereHelpernull_Bool
+ LogKicks whereHelpernull_Bool
+ LogTimeouts whereHelpernull_Bool
+ GiveRoleCmdEnabled whereHelpernull_Bool
+ GiveRoleCmdModlog whereHelpernull_Bool
+ GiveRoleCmdRoles whereHelpertypes_Int64Array
+}{
+ GuildID: whereHelperint64{field: "\"moderation_configs\".\"guild_id\""},
+ CreatedAt: whereHelpertime_Time{field: "\"moderation_configs\".\"created_at\""},
+ UpdatedAt: whereHelpertime_Time{field: "\"moderation_configs\".\"updated_at\""},
+ KickEnabled: whereHelpernull_Bool{field: "\"moderation_configs\".\"kick_enabled\""},
+ KickCmdRoles: whereHelpertypes_Int64Array{field: "\"moderation_configs\".\"kick_cmd_roles\""},
+ DeleteMessagesOnKick: whereHelpernull_Bool{field: "\"moderation_configs\".\"delete_messages_on_kick\""},
+ KickReasonOptional: whereHelpernull_Bool{field: "\"moderation_configs\".\"kick_reason_optional\""},
+ KickMessage: whereHelpernull_String{field: "\"moderation_configs\".\"kick_message\""},
+ BanEnabled: whereHelpernull_Bool{field: "\"moderation_configs\".\"ban_enabled\""},
+ BanCmdRoles: whereHelpertypes_Int64Array{field: "\"moderation_configs\".\"ban_cmd_roles\""},
+ BanReasonOptional: whereHelpernull_Bool{field: "\"moderation_configs\".\"ban_reason_optional\""},
+ BanMessage: whereHelpernull_String{field: "\"moderation_configs\".\"ban_message\""},
+ DefaultBanDeleteDays: whereHelpernull_Int64{field: "\"moderation_configs\".\"default_ban_delete_days\""},
+ TimeoutEnabled: whereHelpernull_Bool{field: "\"moderation_configs\".\"timeout_enabled\""},
+ TimeoutCmdRoles: whereHelpertypes_Int64Array{field: "\"moderation_configs\".\"timeout_cmd_roles\""},
+ TimeoutReasonOptional: whereHelpernull_Bool{field: "\"moderation_configs\".\"timeout_reason_optional\""},
+ TimeoutRemoveReasonOptional: whereHelpernull_Bool{field: "\"moderation_configs\".\"timeout_remove_reason_optional\""},
+ TimeoutMessage: whereHelpernull_String{field: "\"moderation_configs\".\"timeout_message\""},
+ DefaultTimeoutDuration: whereHelpernull_Int64{field: "\"moderation_configs\".\"default_timeout_duration\""},
+ MuteEnabled: whereHelpernull_Bool{field: "\"moderation_configs\".\"mute_enabled\""},
+ MuteCmdRoles: whereHelpertypes_Int64Array{field: "\"moderation_configs\".\"mute_cmd_roles\""},
+ MuteRole: whereHelpernull_String{field: "\"moderation_configs\".\"mute_role\""},
+ MuteDisallowReactionAdd: whereHelpernull_Bool{field: "\"moderation_configs\".\"mute_disallow_reaction_add\""},
+ MuteReasonOptional: whereHelpernull_Bool{field: "\"moderation_configs\".\"mute_reason_optional\""},
+ UnmuteReasonOptional: whereHelpernull_Bool{field: "\"moderation_configs\".\"unmute_reason_optional\""},
+ MuteManageRole: whereHelpernull_Bool{field: "\"moderation_configs\".\"mute_manage_role\""},
+ MuteRemoveRoles: whereHelpertypes_Int64Array{field: "\"moderation_configs\".\"mute_remove_roles\""},
+ MuteIgnoreChannels: whereHelpertypes_Int64Array{field: "\"moderation_configs\".\"mute_ignore_channels\""},
+ MuteMessage: whereHelpernull_String{field: "\"moderation_configs\".\"mute_message\""},
+ UnmuteMessage: whereHelpernull_String{field: "\"moderation_configs\".\"unmute_message\""},
+ DefaultMuteDuration: whereHelpernull_Int64{field: "\"moderation_configs\".\"default_mute_duration\""},
+ WarnCommandsEnabled: whereHelpernull_Bool{field: "\"moderation_configs\".\"warn_commands_enabled\""},
+ WarnCmdRoles: whereHelpertypes_Int64Array{field: "\"moderation_configs\".\"warn_cmd_roles\""},
+ WarnIncludeChannelLogs: whereHelpernull_Bool{field: "\"moderation_configs\".\"warn_include_channel_logs\""},
+ WarnSendToModlog: whereHelpernull_Bool{field: "\"moderation_configs\".\"warn_send_to_modlog\""},
+ WarnMessage: whereHelpernull_String{field: "\"moderation_configs\".\"warn_message\""},
+ CleanEnabled: whereHelpernull_Bool{field: "\"moderation_configs\".\"clean_enabled\""},
+ ReportEnabled: whereHelpernull_Bool{field: "\"moderation_configs\".\"report_enabled\""},
+ ActionChannel: whereHelpernull_String{field: "\"moderation_configs\".\"action_channel\""},
+ ReportChannel: whereHelpernull_String{field: "\"moderation_configs\".\"report_channel\""},
+ ErrorChannel: whereHelpernull_String{field: "\"moderation_configs\".\"error_channel\""},
+ LogUnbans: whereHelpernull_Bool{field: "\"moderation_configs\".\"log_unbans\""},
+ LogBans: whereHelpernull_Bool{field: "\"moderation_configs\".\"log_bans\""},
+ LogKicks: whereHelpernull_Bool{field: "\"moderation_configs\".\"log_kicks\""},
+ LogTimeouts: whereHelpernull_Bool{field: "\"moderation_configs\".\"log_timeouts\""},
+ GiveRoleCmdEnabled: whereHelpernull_Bool{field: "\"moderation_configs\".\"give_role_cmd_enabled\""},
+ GiveRoleCmdModlog: whereHelpernull_Bool{field: "\"moderation_configs\".\"give_role_cmd_modlog\""},
+ GiveRoleCmdRoles: whereHelpertypes_Int64Array{field: "\"moderation_configs\".\"give_role_cmd_roles\""},
+}
+
+// ModerationConfigRels is where relationship names are stored.
+var ModerationConfigRels = struct {
+}{}
+
+// moderationConfigR is where relationships are stored.
+type moderationConfigR struct {
+}
+
+// NewStruct creates a new relationship struct
+func (*moderationConfigR) NewStruct() *moderationConfigR {
+ return &moderationConfigR{}
+}
+
+// moderationConfigL is where Load methods for each relationship are stored.
+type moderationConfigL struct{}
+
+var (
+ moderationConfigAllColumns = []string{"guild_id", "created_at", "updated_at", "kick_enabled", "kick_cmd_roles", "delete_messages_on_kick", "kick_reason_optional", "kick_message", "ban_enabled", "ban_cmd_roles", "ban_reason_optional", "ban_message", "default_ban_delete_days", "timeout_enabled", "timeout_cmd_roles", "timeout_reason_optional", "timeout_remove_reason_optional", "timeout_message", "default_timeout_duration", "mute_enabled", "mute_cmd_roles", "mute_role", "mute_disallow_reaction_add", "mute_reason_optional", "unmute_reason_optional", "mute_manage_role", "mute_remove_roles", "mute_ignore_channels", "mute_message", "unmute_message", "default_mute_duration", "warn_commands_enabled", "warn_cmd_roles", "warn_include_channel_logs", "warn_send_to_modlog", "warn_message", "clean_enabled", "report_enabled", "action_channel", "report_channel", "error_channel", "log_unbans", "log_bans", "log_kicks", "log_timeouts", "give_role_cmd_enabled", "give_role_cmd_modlog", "give_role_cmd_roles"}
+ moderationConfigColumnsWithoutDefault = []string{"guild_id", "created_at", "updated_at"}
+ moderationConfigColumnsWithDefault = []string{"kick_enabled", "kick_cmd_roles", "delete_messages_on_kick", "kick_reason_optional", "kick_message", "ban_enabled", "ban_cmd_roles", "ban_reason_optional", "ban_message", "default_ban_delete_days", "timeout_enabled", "timeout_cmd_roles", "timeout_reason_optional", "timeout_remove_reason_optional", "timeout_message", "default_timeout_duration", "mute_enabled", "mute_cmd_roles", "mute_role", "mute_disallow_reaction_add", "mute_reason_optional", "unmute_reason_optional", "mute_manage_role", "mute_remove_roles", "mute_ignore_channels", "mute_message", "unmute_message", "default_mute_duration", "warn_commands_enabled", "warn_cmd_roles", "warn_include_channel_logs", "warn_send_to_modlog", "warn_message", "clean_enabled", "report_enabled", "action_channel", "report_channel", "error_channel", "log_unbans", "log_bans", "log_kicks", "log_timeouts", "give_role_cmd_enabled", "give_role_cmd_modlog", "give_role_cmd_roles"}
+ moderationConfigPrimaryKeyColumns = []string{"guild_id"}
+ moderationConfigGeneratedColumns = []string{}
+)
+
+type (
+ // ModerationConfigSlice is an alias for a slice of pointers to ModerationConfig.
+ // This should almost always be used instead of []ModerationConfig.
+ ModerationConfigSlice []*ModerationConfig
+
+ moderationConfigQuery struct {
+ *queries.Query
+ }
+)
+
+// Cache for insert, update and upsert
+var (
+ moderationConfigType = reflect.TypeOf(&ModerationConfig{})
+ moderationConfigMapping = queries.MakeStructMapping(moderationConfigType)
+ moderationConfigPrimaryKeyMapping, _ = queries.BindMapping(moderationConfigType, moderationConfigMapping, moderationConfigPrimaryKeyColumns)
+ moderationConfigInsertCacheMut sync.RWMutex
+ moderationConfigInsertCache = make(map[string]insertCache)
+ moderationConfigUpdateCacheMut sync.RWMutex
+ moderationConfigUpdateCache = make(map[string]updateCache)
+ moderationConfigUpsertCacheMut sync.RWMutex
+ moderationConfigUpsertCache = make(map[string]insertCache)
+)
+
+var (
+ // Force time package dependency for automated UpdatedAt/CreatedAt.
+ _ = time.Second
+ // Force qmhelper dependency for where clause generation (which doesn't
+ // always happen)
+ _ = qmhelper.Where
+)
+
+// OneG returns a single moderationConfig record from the query using the global executor.
+func (q moderationConfigQuery) OneG(ctx context.Context) (*ModerationConfig, error) {
+ return q.One(ctx, boil.GetContextDB())
+}
+
+// One returns a single moderationConfig record from the query.
+func (q moderationConfigQuery) One(ctx context.Context, exec boil.ContextExecutor) (*ModerationConfig, error) {
+ o := &ModerationConfig{}
+
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Bind(ctx, exec, o)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: failed to execute a one query for moderation_configs")
+ }
+
+ return o, nil
+}
+
+// AllG returns all ModerationConfig records from the query using the global executor.
+func (q moderationConfigQuery) AllG(ctx context.Context) (ModerationConfigSlice, error) {
+ return q.All(ctx, boil.GetContextDB())
+}
+
+// All returns all ModerationConfig records from the query.
+func (q moderationConfigQuery) All(ctx context.Context, exec boil.ContextExecutor) (ModerationConfigSlice, error) {
+ var o []*ModerationConfig
+
+ err := q.Bind(ctx, exec, &o)
+ if err != nil {
+ return nil, errors.Wrap(err, "models: failed to assign all query results to ModerationConfig slice")
+ }
+
+ return o, nil
+}
+
+// CountG returns the count of all ModerationConfig records in the query using the global executor
+func (q moderationConfigQuery) CountG(ctx context.Context) (int64, error) {
+ return q.Count(ctx, boil.GetContextDB())
+}
+
+// Count returns the count of all ModerationConfig records in the query.
+func (q moderationConfigQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to count moderation_configs rows")
+ }
+
+ return count, nil
+}
+
+// ExistsG checks if the row exists in the table using the global executor.
+func (q moderationConfigQuery) ExistsG(ctx context.Context) (bool, error) {
+ return q.Exists(ctx, boil.GetContextDB())
+}
+
+// Exists checks if the row exists in the table.
+func (q moderationConfigQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return false, errors.Wrap(err, "models: failed to check if moderation_configs exists")
+ }
+
+ return count > 0, nil
+}
+
+// ModerationConfigs retrieves all the records using an executor.
+func ModerationConfigs(mods ...qm.QueryMod) moderationConfigQuery {
+ mods = append(mods, qm.From("\"moderation_configs\""))
+ q := NewQuery(mods...)
+ if len(queries.GetSelect(q)) == 0 {
+ queries.SetSelect(q, []string{"\"moderation_configs\".*"})
+ }
+
+ return moderationConfigQuery{q}
+}
+
+// FindModerationConfigG retrieves a single record by ID.
+func FindModerationConfigG(ctx context.Context, guildID int64, selectCols ...string) (*ModerationConfig, error) {
+ return FindModerationConfig(ctx, boil.GetContextDB(), guildID, selectCols...)
+}
+
+// FindModerationConfig retrieves a single record by ID with an executor.
+// If selectCols is empty Find will return all columns.
+func FindModerationConfig(ctx context.Context, exec boil.ContextExecutor, guildID int64, selectCols ...string) (*ModerationConfig, error) {
+ moderationConfigObj := &ModerationConfig{}
+
+ sel := "*"
+ if len(selectCols) > 0 {
+ sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",")
+ }
+ query := fmt.Sprintf(
+ "select %s from \"moderation_configs\" where \"guild_id\"=$1", sel,
+ )
+
+ q := queries.Raw(query, guildID)
+
+ err := q.Bind(ctx, exec, moderationConfigObj)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: unable to select from moderation_configs")
+ }
+
+ return moderationConfigObj, nil
+}
+
+// InsertG a single record. See Insert for whitelist behavior description.
+func (o *ModerationConfig) InsertG(ctx context.Context, columns boil.Columns) error {
+ return o.Insert(ctx, boil.GetContextDB(), columns)
+}
+
+// Insert a single record using an executor.
+// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts.
+func (o *ModerationConfig) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error {
+ if o == nil {
+ return errors.New("models: no moderation_configs provided for insertion")
+ }
+
+ var err error
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ if o.UpdatedAt.IsZero() {
+ o.UpdatedAt = currTime
+ }
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(moderationConfigColumnsWithDefault, o)
+
+ key := makeCacheKey(columns, nzDefaults)
+ moderationConfigInsertCacheMut.RLock()
+ cache, cached := moderationConfigInsertCache[key]
+ moderationConfigInsertCacheMut.RUnlock()
+
+ if !cached {
+ wl, returnColumns := columns.InsertColumnSet(
+ moderationConfigAllColumns,
+ moderationConfigColumnsWithDefault,
+ moderationConfigColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ cache.valueMapping, err = queries.BindMapping(moderationConfigType, moderationConfigMapping, wl)
+ if err != nil {
+ return err
+ }
+ cache.retMapping, err = queries.BindMapping(moderationConfigType, moderationConfigMapping, returnColumns)
+ if err != nil {
+ return err
+ }
+ if len(wl) != 0 {
+ cache.query = fmt.Sprintf("INSERT INTO \"moderation_configs\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1))
+ } else {
+ cache.query = "INSERT INTO \"moderation_configs\" %sDEFAULT VALUES%s"
+ }
+
+ var queryOutput, queryReturning string
+
+ if len(cache.retMapping) != 0 {
+ queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\""))
+ }
+
+ cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+
+ if err != nil {
+ return errors.Wrap(err, "models: unable to insert into moderation_configs")
+ }
+
+ if !cached {
+ moderationConfigInsertCacheMut.Lock()
+ moderationConfigInsertCache[key] = cache
+ moderationConfigInsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// UpdateG a single ModerationConfig record using the global executor.
+// See Update for more documentation.
+func (o *ModerationConfig) UpdateG(ctx context.Context, columns boil.Columns) (int64, error) {
+ return o.Update(ctx, boil.GetContextDB(), columns)
+}
+
+// Update uses an executor to update the ModerationConfig.
+// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates.
+// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records.
+func (o *ModerationConfig) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) {
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ o.UpdatedAt = currTime
+ }
+
+ var err error
+ key := makeCacheKey(columns, nil)
+ moderationConfigUpdateCacheMut.RLock()
+ cache, cached := moderationConfigUpdateCache[key]
+ moderationConfigUpdateCacheMut.RUnlock()
+
+ if !cached {
+ wl := columns.UpdateColumnSet(
+ moderationConfigAllColumns,
+ moderationConfigPrimaryKeyColumns,
+ )
+
+ if !columns.IsWhitelist() {
+ wl = strmangle.SetComplement(wl, []string{"created_at"})
+ }
+ if len(wl) == 0 {
+ return 0, errors.New("models: unable to update moderation_configs, could not build whitelist")
+ }
+
+ cache.query = fmt.Sprintf("UPDATE \"moderation_configs\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ strmangle.WhereClause("\"", "\"", len(wl)+1, moderationConfigPrimaryKeyColumns),
+ )
+ cache.valueMapping, err = queries.BindMapping(moderationConfigType, moderationConfigMapping, append(wl, moderationConfigPrimaryKeyColumns...))
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, values)
+ }
+ var result sql.Result
+ result, err = exec.ExecContext(ctx, cache.query, values...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update moderation_configs row")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by update for moderation_configs")
+ }
+
+ if !cached {
+ moderationConfigUpdateCacheMut.Lock()
+ moderationConfigUpdateCache[key] = cache
+ moderationConfigUpdateCacheMut.Unlock()
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (q moderationConfigQuery) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return q.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values.
+func (q moderationConfigQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ queries.SetUpdate(q.Query, cols)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all for moderation_configs")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected for moderation_configs")
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (o ModerationConfigSlice) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return o.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values, using an executor.
+func (o ModerationConfigSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ ln := int64(len(o))
+ if ln == 0 {
+ return 0, nil
+ }
+
+ if len(cols) == 0 {
+ return 0, errors.New("models: update all requires at least one column argument")
+ }
+
+ colNames := make([]string, len(cols))
+ args := make([]interface{}, len(cols))
+
+ i := 0
+ for name, value := range cols {
+ colNames[i] = name
+ args[i] = value
+ i++
+ }
+
+ // Append all of the primary key values for each column
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), moderationConfigPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := fmt.Sprintf("UPDATE \"moderation_configs\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, colNames),
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, moderationConfigPrimaryKeyColumns, len(o)))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all in moderationConfig slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all moderationConfig")
+ }
+ return rowsAff, nil
+}
+
+// UpsertG attempts an insert, and does an update or ignore on conflict.
+func (o *ModerationConfig) UpsertG(ctx context.Context, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ return o.Upsert(ctx, boil.GetContextDB(), updateOnConflict, conflictColumns, updateColumns, insertColumns, opts...)
+}
+
+// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
+// See boil.Columns documentation for how to properly use updateColumns and insertColumns.
+func (o *ModerationConfig) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ if o == nil {
+ return errors.New("models: no moderation_configs provided for upsert")
+ }
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ o.UpdatedAt = currTime
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(moderationConfigColumnsWithDefault, o)
+
+ // Build cache key in-line uglily - mysql vs psql problems
+ buf := strmangle.GetBuffer()
+ if updateOnConflict {
+ buf.WriteByte('t')
+ } else {
+ buf.WriteByte('f')
+ }
+ buf.WriteByte('.')
+ for _, c := range conflictColumns {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(updateColumns.Kind))
+ for _, c := range updateColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(insertColumns.Kind))
+ for _, c := range insertColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ for _, c := range nzDefaults {
+ buf.WriteString(c)
+ }
+ key := buf.String()
+ strmangle.PutBuffer(buf)
+
+ moderationConfigUpsertCacheMut.RLock()
+ cache, cached := moderationConfigUpsertCache[key]
+ moderationConfigUpsertCacheMut.RUnlock()
+
+ var err error
+
+ if !cached {
+ insert, _ := insertColumns.InsertColumnSet(
+ moderationConfigAllColumns,
+ moderationConfigColumnsWithDefault,
+ moderationConfigColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ update := updateColumns.UpdateColumnSet(
+ moderationConfigAllColumns,
+ moderationConfigPrimaryKeyColumns,
+ )
+
+ if updateOnConflict && len(update) == 0 {
+ return errors.New("models: unable to upsert moderation_configs, could not build update column list")
+ }
+
+ ret := strmangle.SetComplement(moderationConfigAllColumns, strmangle.SetIntersect(insert, update))
+
+ conflict := conflictColumns
+ if len(conflict) == 0 && updateOnConflict && len(update) != 0 {
+ if len(moderationConfigPrimaryKeyColumns) == 0 {
+ return errors.New("models: unable to upsert moderation_configs, could not build conflict column list")
+ }
+
+ conflict = make([]string, len(moderationConfigPrimaryKeyColumns))
+ copy(conflict, moderationConfigPrimaryKeyColumns)
+ }
+ cache.query = buildUpsertQueryPostgres(dialect, "\"moderation_configs\"", updateOnConflict, ret, update, conflict, insert, opts...)
+
+ cache.valueMapping, err = queries.BindMapping(moderationConfigType, moderationConfigMapping, insert)
+ if err != nil {
+ return err
+ }
+ if len(ret) != 0 {
+ cache.retMapping, err = queries.BindMapping(moderationConfigType, moderationConfigMapping, ret)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+ var returns []interface{}
+ if len(cache.retMapping) != 0 {
+ returns = queries.PtrsFromMapping(value, cache.retMapping)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...)
+ if errors.Is(err, sql.ErrNoRows) {
+ err = nil // Postgres doesn't return anything when there's no update
+ }
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+ if err != nil {
+ return errors.Wrap(err, "models: unable to upsert moderation_configs")
+ }
+
+ if !cached {
+ moderationConfigUpsertCacheMut.Lock()
+ moderationConfigUpsertCache[key] = cache
+ moderationConfigUpsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// DeleteG deletes a single ModerationConfig record.
+// DeleteG will match against the primary key column to find the record to delete.
+func (o *ModerationConfig) DeleteG(ctx context.Context) (int64, error) {
+ return o.Delete(ctx, boil.GetContextDB())
+}
+
+// Delete deletes a single ModerationConfig record with an executor.
+// Delete will match against the primary key column to find the record to delete.
+func (o *ModerationConfig) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if o == nil {
+ return 0, errors.New("models: no ModerationConfig provided for delete")
+ }
+
+ args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), moderationConfigPrimaryKeyMapping)
+ sql := "DELETE FROM \"moderation_configs\" WHERE \"guild_id\"=$1"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete from moderation_configs")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by delete for moderation_configs")
+ }
+
+ return rowsAff, nil
+}
+
+func (q moderationConfigQuery) DeleteAllG(ctx context.Context) (int64, error) {
+ return q.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all matching rows.
+func (q moderationConfigQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if q.Query == nil {
+ return 0, errors.New("models: no moderationConfigQuery provided for delete all")
+ }
+
+ queries.SetDelete(q.Query)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from moderation_configs")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for moderation_configs")
+ }
+
+ return rowsAff, nil
+}
+
+// DeleteAllG deletes all rows in the slice.
+func (o ModerationConfigSlice) DeleteAllG(ctx context.Context) (int64, error) {
+ return o.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all rows in the slice, using an executor.
+func (o ModerationConfigSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if len(o) == 0 {
+ return 0, nil
+ }
+
+ var args []interface{}
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), moderationConfigPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "DELETE FROM \"moderation_configs\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, moderationConfigPrimaryKeyColumns, len(o))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from moderationConfig slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for moderation_configs")
+ }
+
+ return rowsAff, nil
+}
+
+// ReloadG refetches the object from the database using the primary keys.
+func (o *ModerationConfig) ReloadG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: no ModerationConfig provided for reload")
+ }
+
+ return o.Reload(ctx, boil.GetContextDB())
+}
+
+// Reload refetches the object from the database
+// using the primary keys with an executor.
+func (o *ModerationConfig) Reload(ctx context.Context, exec boil.ContextExecutor) error {
+ ret, err := FindModerationConfig(ctx, exec, o.GuildID)
+ if err != nil {
+ return err
+ }
+
+ *o = *ret
+ return nil
+}
+
+// ReloadAllG refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *ModerationConfigSlice) ReloadAllG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: empty ModerationConfigSlice provided for reload all")
+ }
+
+ return o.ReloadAll(ctx, boil.GetContextDB())
+}
+
+// ReloadAll refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *ModerationConfigSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error {
+ if o == nil || len(*o) == 0 {
+ return nil
+ }
+
+ slice := ModerationConfigSlice{}
+ var args []interface{}
+ for _, obj := range *o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), moderationConfigPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "SELECT \"moderation_configs\".* FROM \"moderation_configs\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, moderationConfigPrimaryKeyColumns, len(*o))
+
+ q := queries.Raw(sql, args...)
+
+ err := q.Bind(ctx, exec, &slice)
+ if err != nil {
+ return errors.Wrap(err, "models: unable to reload all in ModerationConfigSlice")
+ }
+
+ *o = slice
+
+ return nil
+}
+
+// ModerationConfigExistsG checks if the ModerationConfig row exists.
+func ModerationConfigExistsG(ctx context.Context, guildID int64) (bool, error) {
+ return ModerationConfigExists(ctx, boil.GetContextDB(), guildID)
+}
+
+// ModerationConfigExists checks if the ModerationConfig row exists.
+func ModerationConfigExists(ctx context.Context, exec boil.ContextExecutor, guildID int64) (bool, error) {
+ var exists bool
+ sql := "select exists(select 1 from \"moderation_configs\" where \"guild_id\"=$1 limit 1)"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, guildID)
+ }
+ row := exec.QueryRowContext(ctx, sql, guildID)
+
+ err := row.Scan(&exists)
+ if err != nil {
+ return false, errors.Wrap(err, "models: unable to check if moderation_configs exists")
+ }
+
+ return exists, nil
+}
+
+// Exists checks if the ModerationConfig row exists.
+func (o *ModerationConfig) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ return ModerationConfigExists(ctx, exec, o.GuildID)
+}
diff --git a/moderation/models/moderation_warnings.go b/moderation/models/moderation_warnings.go
new file mode 100644
index 0000000000..bb433062cc
--- /dev/null
+++ b/moderation/models/moderation_warnings.go
@@ -0,0 +1,889 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/null/v8"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+ "github.com/volatiletech/sqlboiler/v4/queries/qmhelper"
+ "github.com/volatiletech/strmangle"
+)
+
+// ModerationWarning is an object representing the database table.
+type ModerationWarning struct {
+ ID int `boil:"id" json:"id" toml:"id" yaml:"id"`
+ CreatedAt time.Time `boil:"created_at" json:"created_at" toml:"created_at" yaml:"created_at"`
+ UpdatedAt time.Time `boil:"updated_at" json:"updated_at" toml:"updated_at" yaml:"updated_at"`
+ GuildID int64 `boil:"guild_id" json:"guild_id" toml:"guild_id" yaml:"guild_id"`
+ UserID string `boil:"user_id" json:"user_id" toml:"user_id" yaml:"user_id"`
+ AuthorID string `boil:"author_id" json:"author_id" toml:"author_id" yaml:"author_id"`
+ AuthorUsernameDiscrim string `boil:"author_username_discrim" json:"author_username_discrim" toml:"author_username_discrim" yaml:"author_username_discrim"`
+ Message string `boil:"message" json:"message" toml:"message" yaml:"message"`
+ LogsLink null.String `boil:"logs_link" json:"logs_link,omitempty" toml:"logs_link" yaml:"logs_link,omitempty"`
+
+ R *moderationWarningR `boil:"-" json:"-" toml:"-" yaml:"-"`
+ L moderationWarningL `boil:"-" json:"-" toml:"-" yaml:"-"`
+}
+
+var ModerationWarningColumns = struct {
+ ID string
+ CreatedAt string
+ UpdatedAt string
+ GuildID string
+ UserID string
+ AuthorID string
+ AuthorUsernameDiscrim string
+ Message string
+ LogsLink string
+}{
+ ID: "id",
+ CreatedAt: "created_at",
+ UpdatedAt: "updated_at",
+ GuildID: "guild_id",
+ UserID: "user_id",
+ AuthorID: "author_id",
+ AuthorUsernameDiscrim: "author_username_discrim",
+ Message: "message",
+ LogsLink: "logs_link",
+}
+
+var ModerationWarningTableColumns = struct {
+ ID string
+ CreatedAt string
+ UpdatedAt string
+ GuildID string
+ UserID string
+ AuthorID string
+ AuthorUsernameDiscrim string
+ Message string
+ LogsLink string
+}{
+ ID: "moderation_warnings.id",
+ CreatedAt: "moderation_warnings.created_at",
+ UpdatedAt: "moderation_warnings.updated_at",
+ GuildID: "moderation_warnings.guild_id",
+ UserID: "moderation_warnings.user_id",
+ AuthorID: "moderation_warnings.author_id",
+ AuthorUsernameDiscrim: "moderation_warnings.author_username_discrim",
+ Message: "moderation_warnings.message",
+ LogsLink: "moderation_warnings.logs_link",
+}
+
+// Generated where
+
+type whereHelperint struct{ field string }
+
+func (w whereHelperint) EQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperint) NEQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperint) LT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperint) LTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperint) GT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperint) GTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperint) IN(slice []int) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperint) NIN(slice []int) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+type whereHelperstring struct{ field string }
+
+func (w whereHelperstring) EQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperstring) NEQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperstring) LT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperstring) LTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperstring) GT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperstring) GTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperstring) LIKE(x string) qm.QueryMod { return qm.Where(w.field+" LIKE ?", x) }
+func (w whereHelperstring) NLIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT LIKE ?", x) }
+func (w whereHelperstring) ILIKE(x string) qm.QueryMod { return qm.Where(w.field+" ILIKE ?", x) }
+func (w whereHelperstring) NILIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT ILIKE ?", x) }
+func (w whereHelperstring) IN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperstring) NIN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+var ModerationWarningWhere = struct {
+ ID whereHelperint
+ CreatedAt whereHelpertime_Time
+ UpdatedAt whereHelpertime_Time
+ GuildID whereHelperint64
+ UserID whereHelperstring
+ AuthorID whereHelperstring
+ AuthorUsernameDiscrim whereHelperstring
+ Message whereHelperstring
+ LogsLink whereHelpernull_String
+}{
+ ID: whereHelperint{field: "\"moderation_warnings\".\"id\""},
+ CreatedAt: whereHelpertime_Time{field: "\"moderation_warnings\".\"created_at\""},
+ UpdatedAt: whereHelpertime_Time{field: "\"moderation_warnings\".\"updated_at\""},
+ GuildID: whereHelperint64{field: "\"moderation_warnings\".\"guild_id\""},
+ UserID: whereHelperstring{field: "\"moderation_warnings\".\"user_id\""},
+ AuthorID: whereHelperstring{field: "\"moderation_warnings\".\"author_id\""},
+ AuthorUsernameDiscrim: whereHelperstring{field: "\"moderation_warnings\".\"author_username_discrim\""},
+ Message: whereHelperstring{field: "\"moderation_warnings\".\"message\""},
+ LogsLink: whereHelpernull_String{field: "\"moderation_warnings\".\"logs_link\""},
+}
+
+// ModerationWarningRels is where relationship names are stored.
+var ModerationWarningRels = struct {
+}{}
+
+// moderationWarningR is where relationships are stored.
+type moderationWarningR struct {
+}
+
+// NewStruct creates a new relationship struct
+func (*moderationWarningR) NewStruct() *moderationWarningR {
+ return &moderationWarningR{}
+}
+
+// moderationWarningL is where Load methods for each relationship are stored.
+type moderationWarningL struct{}
+
+var (
+ moderationWarningAllColumns = []string{"id", "created_at", "updated_at", "guild_id", "user_id", "author_id", "author_username_discrim", "message", "logs_link"}
+ moderationWarningColumnsWithoutDefault = []string{"created_at", "updated_at", "guild_id", "user_id", "author_id", "author_username_discrim", "message"}
+ moderationWarningColumnsWithDefault = []string{"id", "logs_link"}
+ moderationWarningPrimaryKeyColumns = []string{"id"}
+ moderationWarningGeneratedColumns = []string{}
+)
+
+type (
+ // ModerationWarningSlice is an alias for a slice of pointers to ModerationWarning.
+ // This should almost always be used instead of []ModerationWarning.
+ ModerationWarningSlice []*ModerationWarning
+
+ moderationWarningQuery struct {
+ *queries.Query
+ }
+)
+
+// Cache for insert, update and upsert
+var (
+ moderationWarningType = reflect.TypeOf(&ModerationWarning{})
+ moderationWarningMapping = queries.MakeStructMapping(moderationWarningType)
+ moderationWarningPrimaryKeyMapping, _ = queries.BindMapping(moderationWarningType, moderationWarningMapping, moderationWarningPrimaryKeyColumns)
+ moderationWarningInsertCacheMut sync.RWMutex
+ moderationWarningInsertCache = make(map[string]insertCache)
+ moderationWarningUpdateCacheMut sync.RWMutex
+ moderationWarningUpdateCache = make(map[string]updateCache)
+ moderationWarningUpsertCacheMut sync.RWMutex
+ moderationWarningUpsertCache = make(map[string]insertCache)
+)
+
+var (
+ // Force time package dependency for automated UpdatedAt/CreatedAt.
+ _ = time.Second
+ // Force qmhelper dependency for where clause generation (which doesn't
+ // always happen)
+ _ = qmhelper.Where
+)
+
+// OneG returns a single moderationWarning record from the query using the global executor.
+func (q moderationWarningQuery) OneG(ctx context.Context) (*ModerationWarning, error) {
+ return q.One(ctx, boil.GetContextDB())
+}
+
+// One returns a single moderationWarning record from the query.
+func (q moderationWarningQuery) One(ctx context.Context, exec boil.ContextExecutor) (*ModerationWarning, error) {
+ o := &ModerationWarning{}
+
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Bind(ctx, exec, o)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: failed to execute a one query for moderation_warnings")
+ }
+
+ return o, nil
+}
+
+// AllG returns all ModerationWarning records from the query using the global executor.
+func (q moderationWarningQuery) AllG(ctx context.Context) (ModerationWarningSlice, error) {
+ return q.All(ctx, boil.GetContextDB())
+}
+
+// All returns all ModerationWarning records from the query.
+func (q moderationWarningQuery) All(ctx context.Context, exec boil.ContextExecutor) (ModerationWarningSlice, error) {
+ var o []*ModerationWarning
+
+ err := q.Bind(ctx, exec, &o)
+ if err != nil {
+ return nil, errors.Wrap(err, "models: failed to assign all query results to ModerationWarning slice")
+ }
+
+ return o, nil
+}
+
+// CountG returns the count of all ModerationWarning records in the query using the global executor
+func (q moderationWarningQuery) CountG(ctx context.Context) (int64, error) {
+ return q.Count(ctx, boil.GetContextDB())
+}
+
+// Count returns the count of all ModerationWarning records in the query.
+func (q moderationWarningQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to count moderation_warnings rows")
+ }
+
+ return count, nil
+}
+
+// ExistsG checks if the row exists in the table using the global executor.
+func (q moderationWarningQuery) ExistsG(ctx context.Context) (bool, error) {
+ return q.Exists(ctx, boil.GetContextDB())
+}
+
+// Exists checks if the row exists in the table.
+func (q moderationWarningQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return false, errors.Wrap(err, "models: failed to check if moderation_warnings exists")
+ }
+
+ return count > 0, nil
+}
+
+// ModerationWarnings retrieves all the records using an executor.
+func ModerationWarnings(mods ...qm.QueryMod) moderationWarningQuery {
+ mods = append(mods, qm.From("\"moderation_warnings\""))
+ q := NewQuery(mods...)
+ if len(queries.GetSelect(q)) == 0 {
+ queries.SetSelect(q, []string{"\"moderation_warnings\".*"})
+ }
+
+ return moderationWarningQuery{q}
+}
+
+// FindModerationWarningG retrieves a single record by ID.
+func FindModerationWarningG(ctx context.Context, iD int, selectCols ...string) (*ModerationWarning, error) {
+ return FindModerationWarning(ctx, boil.GetContextDB(), iD, selectCols...)
+}
+
+// FindModerationWarning retrieves a single record by ID with an executor.
+// If selectCols is empty Find will return all columns.
+func FindModerationWarning(ctx context.Context, exec boil.ContextExecutor, iD int, selectCols ...string) (*ModerationWarning, error) {
+ moderationWarningObj := &ModerationWarning{}
+
+ sel := "*"
+ if len(selectCols) > 0 {
+ sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",")
+ }
+ query := fmt.Sprintf(
+ "select %s from \"moderation_warnings\" where \"id\"=$1", sel,
+ )
+
+ q := queries.Raw(query, iD)
+
+ err := q.Bind(ctx, exec, moderationWarningObj)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: unable to select from moderation_warnings")
+ }
+
+ return moderationWarningObj, nil
+}
+
+// InsertG a single record. See Insert for whitelist behavior description.
+func (o *ModerationWarning) InsertG(ctx context.Context, columns boil.Columns) error {
+ return o.Insert(ctx, boil.GetContextDB(), columns)
+}
+
+// Insert a single record using an executor.
+// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts.
+func (o *ModerationWarning) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error {
+ if o == nil {
+ return errors.New("models: no moderation_warnings provided for insertion")
+ }
+
+ var err error
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ if o.UpdatedAt.IsZero() {
+ o.UpdatedAt = currTime
+ }
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(moderationWarningColumnsWithDefault, o)
+
+ key := makeCacheKey(columns, nzDefaults)
+ moderationWarningInsertCacheMut.RLock()
+ cache, cached := moderationWarningInsertCache[key]
+ moderationWarningInsertCacheMut.RUnlock()
+
+ if !cached {
+ wl, returnColumns := columns.InsertColumnSet(
+ moderationWarningAllColumns,
+ moderationWarningColumnsWithDefault,
+ moderationWarningColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ cache.valueMapping, err = queries.BindMapping(moderationWarningType, moderationWarningMapping, wl)
+ if err != nil {
+ return err
+ }
+ cache.retMapping, err = queries.BindMapping(moderationWarningType, moderationWarningMapping, returnColumns)
+ if err != nil {
+ return err
+ }
+ if len(wl) != 0 {
+ cache.query = fmt.Sprintf("INSERT INTO \"moderation_warnings\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1))
+ } else {
+ cache.query = "INSERT INTO \"moderation_warnings\" %sDEFAULT VALUES%s"
+ }
+
+ var queryOutput, queryReturning string
+
+ if len(cache.retMapping) != 0 {
+ queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\""))
+ }
+
+ cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+
+ if err != nil {
+ return errors.Wrap(err, "models: unable to insert into moderation_warnings")
+ }
+
+ if !cached {
+ moderationWarningInsertCacheMut.Lock()
+ moderationWarningInsertCache[key] = cache
+ moderationWarningInsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// UpdateG a single ModerationWarning record using the global executor.
+// See Update for more documentation.
+func (o *ModerationWarning) UpdateG(ctx context.Context, columns boil.Columns) (int64, error) {
+ return o.Update(ctx, boil.GetContextDB(), columns)
+}
+
+// Update uses an executor to update the ModerationWarning.
+// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates.
+// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records.
+func (o *ModerationWarning) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) {
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ o.UpdatedAt = currTime
+ }
+
+ var err error
+ key := makeCacheKey(columns, nil)
+ moderationWarningUpdateCacheMut.RLock()
+ cache, cached := moderationWarningUpdateCache[key]
+ moderationWarningUpdateCacheMut.RUnlock()
+
+ if !cached {
+ wl := columns.UpdateColumnSet(
+ moderationWarningAllColumns,
+ moderationWarningPrimaryKeyColumns,
+ )
+
+ if !columns.IsWhitelist() {
+ wl = strmangle.SetComplement(wl, []string{"created_at"})
+ }
+ if len(wl) == 0 {
+ return 0, errors.New("models: unable to update moderation_warnings, could not build whitelist")
+ }
+
+ cache.query = fmt.Sprintf("UPDATE \"moderation_warnings\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ strmangle.WhereClause("\"", "\"", len(wl)+1, moderationWarningPrimaryKeyColumns),
+ )
+ cache.valueMapping, err = queries.BindMapping(moderationWarningType, moderationWarningMapping, append(wl, moderationWarningPrimaryKeyColumns...))
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, values)
+ }
+ var result sql.Result
+ result, err = exec.ExecContext(ctx, cache.query, values...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update moderation_warnings row")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by update for moderation_warnings")
+ }
+
+ if !cached {
+ moderationWarningUpdateCacheMut.Lock()
+ moderationWarningUpdateCache[key] = cache
+ moderationWarningUpdateCacheMut.Unlock()
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (q moderationWarningQuery) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return q.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values.
+func (q moderationWarningQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ queries.SetUpdate(q.Query, cols)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all for moderation_warnings")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected for moderation_warnings")
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (o ModerationWarningSlice) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return o.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values, using an executor.
+func (o ModerationWarningSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ ln := int64(len(o))
+ if ln == 0 {
+ return 0, nil
+ }
+
+ if len(cols) == 0 {
+ return 0, errors.New("models: update all requires at least one column argument")
+ }
+
+ colNames := make([]string, len(cols))
+ args := make([]interface{}, len(cols))
+
+ i := 0
+ for name, value := range cols {
+ colNames[i] = name
+ args[i] = value
+ i++
+ }
+
+ // Append all of the primary key values for each column
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), moderationWarningPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := fmt.Sprintf("UPDATE \"moderation_warnings\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, colNames),
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, moderationWarningPrimaryKeyColumns, len(o)))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all in moderationWarning slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all moderationWarning")
+ }
+ return rowsAff, nil
+}
+
+// UpsertG attempts an insert, and does an update or ignore on conflict.
+func (o *ModerationWarning) UpsertG(ctx context.Context, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ return o.Upsert(ctx, boil.GetContextDB(), updateOnConflict, conflictColumns, updateColumns, insertColumns, opts...)
+}
+
+// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
+// See boil.Columns documentation for how to properly use updateColumns and insertColumns.
+func (o *ModerationWarning) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ if o == nil {
+ return errors.New("models: no moderation_warnings provided for upsert")
+ }
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ o.UpdatedAt = currTime
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(moderationWarningColumnsWithDefault, o)
+
+ // Build cache key in-line uglily - mysql vs psql problems
+ buf := strmangle.GetBuffer()
+ if updateOnConflict {
+ buf.WriteByte('t')
+ } else {
+ buf.WriteByte('f')
+ }
+ buf.WriteByte('.')
+ for _, c := range conflictColumns {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(updateColumns.Kind))
+ for _, c := range updateColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(insertColumns.Kind))
+ for _, c := range insertColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ for _, c := range nzDefaults {
+ buf.WriteString(c)
+ }
+ key := buf.String()
+ strmangle.PutBuffer(buf)
+
+ moderationWarningUpsertCacheMut.RLock()
+ cache, cached := moderationWarningUpsertCache[key]
+ moderationWarningUpsertCacheMut.RUnlock()
+
+ var err error
+
+ if !cached {
+ insert, _ := insertColumns.InsertColumnSet(
+ moderationWarningAllColumns,
+ moderationWarningColumnsWithDefault,
+ moderationWarningColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ update := updateColumns.UpdateColumnSet(
+ moderationWarningAllColumns,
+ moderationWarningPrimaryKeyColumns,
+ )
+
+ if updateOnConflict && len(update) == 0 {
+ return errors.New("models: unable to upsert moderation_warnings, could not build update column list")
+ }
+
+ ret := strmangle.SetComplement(moderationWarningAllColumns, strmangle.SetIntersect(insert, update))
+
+ conflict := conflictColumns
+ if len(conflict) == 0 && updateOnConflict && len(update) != 0 {
+ if len(moderationWarningPrimaryKeyColumns) == 0 {
+ return errors.New("models: unable to upsert moderation_warnings, could not build conflict column list")
+ }
+
+ conflict = make([]string, len(moderationWarningPrimaryKeyColumns))
+ copy(conflict, moderationWarningPrimaryKeyColumns)
+ }
+ cache.query = buildUpsertQueryPostgres(dialect, "\"moderation_warnings\"", updateOnConflict, ret, update, conflict, insert, opts...)
+
+ cache.valueMapping, err = queries.BindMapping(moderationWarningType, moderationWarningMapping, insert)
+ if err != nil {
+ return err
+ }
+ if len(ret) != 0 {
+ cache.retMapping, err = queries.BindMapping(moderationWarningType, moderationWarningMapping, ret)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+ var returns []interface{}
+ if len(cache.retMapping) != 0 {
+ returns = queries.PtrsFromMapping(value, cache.retMapping)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...)
+ if errors.Is(err, sql.ErrNoRows) {
+ err = nil // Postgres doesn't return anything when there's no update
+ }
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+ if err != nil {
+ return errors.Wrap(err, "models: unable to upsert moderation_warnings")
+ }
+
+ if !cached {
+ moderationWarningUpsertCacheMut.Lock()
+ moderationWarningUpsertCache[key] = cache
+ moderationWarningUpsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// DeleteG deletes a single ModerationWarning record.
+// DeleteG will match against the primary key column to find the record to delete.
+func (o *ModerationWarning) DeleteG(ctx context.Context) (int64, error) {
+ return o.Delete(ctx, boil.GetContextDB())
+}
+
+// Delete deletes a single ModerationWarning record with an executor.
+// Delete will match against the primary key column to find the record to delete.
+func (o *ModerationWarning) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if o == nil {
+ return 0, errors.New("models: no ModerationWarning provided for delete")
+ }
+
+ args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), moderationWarningPrimaryKeyMapping)
+ sql := "DELETE FROM \"moderation_warnings\" WHERE \"id\"=$1"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete from moderation_warnings")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by delete for moderation_warnings")
+ }
+
+ return rowsAff, nil
+}
+
+func (q moderationWarningQuery) DeleteAllG(ctx context.Context) (int64, error) {
+ return q.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all matching rows.
+func (q moderationWarningQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if q.Query == nil {
+ return 0, errors.New("models: no moderationWarningQuery provided for delete all")
+ }
+
+ queries.SetDelete(q.Query)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from moderation_warnings")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for moderation_warnings")
+ }
+
+ return rowsAff, nil
+}
+
+// DeleteAllG deletes all rows in the slice.
+func (o ModerationWarningSlice) DeleteAllG(ctx context.Context) (int64, error) {
+ return o.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all rows in the slice, using an executor.
+func (o ModerationWarningSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if len(o) == 0 {
+ return 0, nil
+ }
+
+ var args []interface{}
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), moderationWarningPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "DELETE FROM \"moderation_warnings\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, moderationWarningPrimaryKeyColumns, len(o))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from moderationWarning slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for moderation_warnings")
+ }
+
+ return rowsAff, nil
+}
+
+// ReloadG refetches the object from the database using the primary keys.
+func (o *ModerationWarning) ReloadG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: no ModerationWarning provided for reload")
+ }
+
+ return o.Reload(ctx, boil.GetContextDB())
+}
+
+// Reload refetches the object from the database
+// using the primary keys with an executor.
+func (o *ModerationWarning) Reload(ctx context.Context, exec boil.ContextExecutor) error {
+ ret, err := FindModerationWarning(ctx, exec, o.ID)
+ if err != nil {
+ return err
+ }
+
+ *o = *ret
+ return nil
+}
+
+// ReloadAllG refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *ModerationWarningSlice) ReloadAllG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: empty ModerationWarningSlice provided for reload all")
+ }
+
+ return o.ReloadAll(ctx, boil.GetContextDB())
+}
+
+// ReloadAll refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *ModerationWarningSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error {
+ if o == nil || len(*o) == 0 {
+ return nil
+ }
+
+ slice := ModerationWarningSlice{}
+ var args []interface{}
+ for _, obj := range *o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), moderationWarningPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "SELECT \"moderation_warnings\".* FROM \"moderation_warnings\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, moderationWarningPrimaryKeyColumns, len(*o))
+
+ q := queries.Raw(sql, args...)
+
+ err := q.Bind(ctx, exec, &slice)
+ if err != nil {
+ return errors.Wrap(err, "models: unable to reload all in ModerationWarningSlice")
+ }
+
+ *o = slice
+
+ return nil
+}
+
+// ModerationWarningExistsG checks if the ModerationWarning row exists.
+func ModerationWarningExistsG(ctx context.Context, iD int) (bool, error) {
+ return ModerationWarningExists(ctx, boil.GetContextDB(), iD)
+}
+
+// ModerationWarningExists checks if the ModerationWarning row exists.
+func ModerationWarningExists(ctx context.Context, exec boil.ContextExecutor, iD int) (bool, error) {
+ var exists bool
+ sql := "select exists(select 1 from \"moderation_warnings\" where \"id\"=$1 limit 1)"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, iD)
+ }
+ row := exec.QueryRowContext(ctx, sql, iD)
+
+ err := row.Scan(&exists)
+ if err != nil {
+ return false, errors.Wrap(err, "models: unable to check if moderation_warnings exists")
+ }
+
+ return exists, nil
+}
+
+// Exists checks if the ModerationWarning row exists.
+func (o *ModerationWarning) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ return ModerationWarningExists(ctx, exec, o.ID)
+}
diff --git a/moderation/models/muted_users.go b/moderation/models/muted_users.go
new file mode 100644
index 0000000000..f69f7bf1b2
--- /dev/null
+++ b/moderation/models/muted_users.go
@@ -0,0 +1,864 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/null/v8"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+ "github.com/volatiletech/sqlboiler/v4/queries/qmhelper"
+ "github.com/volatiletech/sqlboiler/v4/types"
+ "github.com/volatiletech/strmangle"
+)
+
+// MutedUser is an object representing the database table.
+type MutedUser struct {
+ ID int `boil:"id" json:"id" toml:"id" yaml:"id"`
+ CreatedAt time.Time `boil:"created_at" json:"created_at" toml:"created_at" yaml:"created_at"`
+ UpdatedAt time.Time `boil:"updated_at" json:"updated_at" toml:"updated_at" yaml:"updated_at"`
+ ExpiresAt null.Time `boil:"expires_at" json:"expires_at,omitempty" toml:"expires_at" yaml:"expires_at,omitempty"`
+ GuildID int64 `boil:"guild_id" json:"guild_id" toml:"guild_id" yaml:"guild_id"`
+ UserID int64 `boil:"user_id" json:"user_id" toml:"user_id" yaml:"user_id"`
+ AuthorID int64 `boil:"author_id" json:"author_id" toml:"author_id" yaml:"author_id"`
+ Reason string `boil:"reason" json:"reason" toml:"reason" yaml:"reason"`
+ RemovedRoles types.Int64Array `boil:"removed_roles" json:"removed_roles,omitempty" toml:"removed_roles" yaml:"removed_roles,omitempty"`
+
+ R *mutedUserR `boil:"-" json:"-" toml:"-" yaml:"-"`
+ L mutedUserL `boil:"-" json:"-" toml:"-" yaml:"-"`
+}
+
+var MutedUserColumns = struct {
+ ID string
+ CreatedAt string
+ UpdatedAt string
+ ExpiresAt string
+ GuildID string
+ UserID string
+ AuthorID string
+ Reason string
+ RemovedRoles string
+}{
+ ID: "id",
+ CreatedAt: "created_at",
+ UpdatedAt: "updated_at",
+ ExpiresAt: "expires_at",
+ GuildID: "guild_id",
+ UserID: "user_id",
+ AuthorID: "author_id",
+ Reason: "reason",
+ RemovedRoles: "removed_roles",
+}
+
+var MutedUserTableColumns = struct {
+ ID string
+ CreatedAt string
+ UpdatedAt string
+ ExpiresAt string
+ GuildID string
+ UserID string
+ AuthorID string
+ Reason string
+ RemovedRoles string
+}{
+ ID: "muted_users.id",
+ CreatedAt: "muted_users.created_at",
+ UpdatedAt: "muted_users.updated_at",
+ ExpiresAt: "muted_users.expires_at",
+ GuildID: "muted_users.guild_id",
+ UserID: "muted_users.user_id",
+ AuthorID: "muted_users.author_id",
+ Reason: "muted_users.reason",
+ RemovedRoles: "muted_users.removed_roles",
+}
+
+// Generated where
+
+type whereHelpernull_Time struct{ field string }
+
+func (w whereHelpernull_Time) EQ(x null.Time) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpernull_Time) NEQ(x null.Time) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpernull_Time) LT(x null.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpernull_Time) LTE(x null.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpernull_Time) GT(x null.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpernull_Time) GTE(x null.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+func (w whereHelpernull_Time) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpernull_Time) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+var MutedUserWhere = struct {
+ ID whereHelperint
+ CreatedAt whereHelpertime_Time
+ UpdatedAt whereHelpertime_Time
+ ExpiresAt whereHelpernull_Time
+ GuildID whereHelperint64
+ UserID whereHelperint64
+ AuthorID whereHelperint64
+ Reason whereHelperstring
+ RemovedRoles whereHelpertypes_Int64Array
+}{
+ ID: whereHelperint{field: "\"muted_users\".\"id\""},
+ CreatedAt: whereHelpertime_Time{field: "\"muted_users\".\"created_at\""},
+ UpdatedAt: whereHelpertime_Time{field: "\"muted_users\".\"updated_at\""},
+ ExpiresAt: whereHelpernull_Time{field: "\"muted_users\".\"expires_at\""},
+ GuildID: whereHelperint64{field: "\"muted_users\".\"guild_id\""},
+ UserID: whereHelperint64{field: "\"muted_users\".\"user_id\""},
+ AuthorID: whereHelperint64{field: "\"muted_users\".\"author_id\""},
+ Reason: whereHelperstring{field: "\"muted_users\".\"reason\""},
+ RemovedRoles: whereHelpertypes_Int64Array{field: "\"muted_users\".\"removed_roles\""},
+}
+
+// MutedUserRels is where relationship names are stored.
+var MutedUserRels = struct {
+}{}
+
+// mutedUserR is where relationships are stored.
+type mutedUserR struct {
+}
+
+// NewStruct creates a new relationship struct
+func (*mutedUserR) NewStruct() *mutedUserR {
+ return &mutedUserR{}
+}
+
+// mutedUserL is where Load methods for each relationship are stored.
+type mutedUserL struct{}
+
+var (
+ mutedUserAllColumns = []string{"id", "created_at", "updated_at", "expires_at", "guild_id", "user_id", "author_id", "reason", "removed_roles"}
+ mutedUserColumnsWithoutDefault = []string{"created_at", "updated_at", "guild_id", "user_id", "author_id", "reason"}
+ mutedUserColumnsWithDefault = []string{"id", "expires_at", "removed_roles"}
+ mutedUserPrimaryKeyColumns = []string{"id"}
+ mutedUserGeneratedColumns = []string{}
+)
+
+type (
+ // MutedUserSlice is an alias for a slice of pointers to MutedUser.
+ // This should almost always be used instead of []MutedUser.
+ MutedUserSlice []*MutedUser
+
+ mutedUserQuery struct {
+ *queries.Query
+ }
+)
+
+// Cache for insert, update and upsert
+var (
+ mutedUserType = reflect.TypeOf(&MutedUser{})
+ mutedUserMapping = queries.MakeStructMapping(mutedUserType)
+ mutedUserPrimaryKeyMapping, _ = queries.BindMapping(mutedUserType, mutedUserMapping, mutedUserPrimaryKeyColumns)
+ mutedUserInsertCacheMut sync.RWMutex
+ mutedUserInsertCache = make(map[string]insertCache)
+ mutedUserUpdateCacheMut sync.RWMutex
+ mutedUserUpdateCache = make(map[string]updateCache)
+ mutedUserUpsertCacheMut sync.RWMutex
+ mutedUserUpsertCache = make(map[string]insertCache)
+)
+
+var (
+ // Force time package dependency for automated UpdatedAt/CreatedAt.
+ _ = time.Second
+ // Force qmhelper dependency for where clause generation (which doesn't
+ // always happen)
+ _ = qmhelper.Where
+)
+
+// OneG returns a single mutedUser record from the query using the global executor.
+func (q mutedUserQuery) OneG(ctx context.Context) (*MutedUser, error) {
+ return q.One(ctx, boil.GetContextDB())
+}
+
+// One returns a single mutedUser record from the query.
+func (q mutedUserQuery) One(ctx context.Context, exec boil.ContextExecutor) (*MutedUser, error) {
+ o := &MutedUser{}
+
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Bind(ctx, exec, o)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: failed to execute a one query for muted_users")
+ }
+
+ return o, nil
+}
+
+// AllG returns all MutedUser records from the query using the global executor.
+func (q mutedUserQuery) AllG(ctx context.Context) (MutedUserSlice, error) {
+ return q.All(ctx, boil.GetContextDB())
+}
+
+// All returns all MutedUser records from the query.
+func (q mutedUserQuery) All(ctx context.Context, exec boil.ContextExecutor) (MutedUserSlice, error) {
+ var o []*MutedUser
+
+ err := q.Bind(ctx, exec, &o)
+ if err != nil {
+ return nil, errors.Wrap(err, "models: failed to assign all query results to MutedUser slice")
+ }
+
+ return o, nil
+}
+
+// CountG returns the count of all MutedUser records in the query using the global executor
+func (q mutedUserQuery) CountG(ctx context.Context) (int64, error) {
+ return q.Count(ctx, boil.GetContextDB())
+}
+
+// Count returns the count of all MutedUser records in the query.
+func (q mutedUserQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to count muted_users rows")
+ }
+
+ return count, nil
+}
+
+// ExistsG checks if the row exists in the table using the global executor.
+func (q mutedUserQuery) ExistsG(ctx context.Context) (bool, error) {
+ return q.Exists(ctx, boil.GetContextDB())
+}
+
+// Exists checks if the row exists in the table.
+func (q mutedUserQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return false, errors.Wrap(err, "models: failed to check if muted_users exists")
+ }
+
+ return count > 0, nil
+}
+
+// MutedUsers retrieves all the records using an executor.
+func MutedUsers(mods ...qm.QueryMod) mutedUserQuery {
+ mods = append(mods, qm.From("\"muted_users\""))
+ q := NewQuery(mods...)
+ if len(queries.GetSelect(q)) == 0 {
+ queries.SetSelect(q, []string{"\"muted_users\".*"})
+ }
+
+ return mutedUserQuery{q}
+}
+
+// FindMutedUserG retrieves a single record by ID.
+func FindMutedUserG(ctx context.Context, iD int, selectCols ...string) (*MutedUser, error) {
+ return FindMutedUser(ctx, boil.GetContextDB(), iD, selectCols...)
+}
+
+// FindMutedUser retrieves a single record by ID with an executor.
+// If selectCols is empty Find will return all columns.
+func FindMutedUser(ctx context.Context, exec boil.ContextExecutor, iD int, selectCols ...string) (*MutedUser, error) {
+ mutedUserObj := &MutedUser{}
+
+ sel := "*"
+ if len(selectCols) > 0 {
+ sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",")
+ }
+ query := fmt.Sprintf(
+ "select %s from \"muted_users\" where \"id\"=$1", sel,
+ )
+
+ q := queries.Raw(query, iD)
+
+ err := q.Bind(ctx, exec, mutedUserObj)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: unable to select from muted_users")
+ }
+
+ return mutedUserObj, nil
+}
+
+// InsertG a single record. See Insert for whitelist behavior description.
+func (o *MutedUser) InsertG(ctx context.Context, columns boil.Columns) error {
+ return o.Insert(ctx, boil.GetContextDB(), columns)
+}
+
+// Insert a single record using an executor.
+// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts.
+func (o *MutedUser) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error {
+ if o == nil {
+ return errors.New("models: no muted_users provided for insertion")
+ }
+
+ var err error
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ if o.UpdatedAt.IsZero() {
+ o.UpdatedAt = currTime
+ }
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(mutedUserColumnsWithDefault, o)
+
+ key := makeCacheKey(columns, nzDefaults)
+ mutedUserInsertCacheMut.RLock()
+ cache, cached := mutedUserInsertCache[key]
+ mutedUserInsertCacheMut.RUnlock()
+
+ if !cached {
+ wl, returnColumns := columns.InsertColumnSet(
+ mutedUserAllColumns,
+ mutedUserColumnsWithDefault,
+ mutedUserColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ cache.valueMapping, err = queries.BindMapping(mutedUserType, mutedUserMapping, wl)
+ if err != nil {
+ return err
+ }
+ cache.retMapping, err = queries.BindMapping(mutedUserType, mutedUserMapping, returnColumns)
+ if err != nil {
+ return err
+ }
+ if len(wl) != 0 {
+ cache.query = fmt.Sprintf("INSERT INTO \"muted_users\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1))
+ } else {
+ cache.query = "INSERT INTO \"muted_users\" %sDEFAULT VALUES%s"
+ }
+
+ var queryOutput, queryReturning string
+
+ if len(cache.retMapping) != 0 {
+ queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\""))
+ }
+
+ cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+
+ if err != nil {
+ return errors.Wrap(err, "models: unable to insert into muted_users")
+ }
+
+ if !cached {
+ mutedUserInsertCacheMut.Lock()
+ mutedUserInsertCache[key] = cache
+ mutedUserInsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// UpdateG a single MutedUser record using the global executor.
+// See Update for more documentation.
+func (o *MutedUser) UpdateG(ctx context.Context, columns boil.Columns) (int64, error) {
+ return o.Update(ctx, boil.GetContextDB(), columns)
+}
+
+// Update uses an executor to update the MutedUser.
+// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates.
+// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records.
+func (o *MutedUser) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) {
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ o.UpdatedAt = currTime
+ }
+
+ var err error
+ key := makeCacheKey(columns, nil)
+ mutedUserUpdateCacheMut.RLock()
+ cache, cached := mutedUserUpdateCache[key]
+ mutedUserUpdateCacheMut.RUnlock()
+
+ if !cached {
+ wl := columns.UpdateColumnSet(
+ mutedUserAllColumns,
+ mutedUserPrimaryKeyColumns,
+ )
+
+ if !columns.IsWhitelist() {
+ wl = strmangle.SetComplement(wl, []string{"created_at"})
+ }
+ if len(wl) == 0 {
+ return 0, errors.New("models: unable to update muted_users, could not build whitelist")
+ }
+
+ cache.query = fmt.Sprintf("UPDATE \"muted_users\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ strmangle.WhereClause("\"", "\"", len(wl)+1, mutedUserPrimaryKeyColumns),
+ )
+ cache.valueMapping, err = queries.BindMapping(mutedUserType, mutedUserMapping, append(wl, mutedUserPrimaryKeyColumns...))
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, values)
+ }
+ var result sql.Result
+ result, err = exec.ExecContext(ctx, cache.query, values...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update muted_users row")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by update for muted_users")
+ }
+
+ if !cached {
+ mutedUserUpdateCacheMut.Lock()
+ mutedUserUpdateCache[key] = cache
+ mutedUserUpdateCacheMut.Unlock()
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (q mutedUserQuery) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return q.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values.
+func (q mutedUserQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ queries.SetUpdate(q.Query, cols)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all for muted_users")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected for muted_users")
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (o MutedUserSlice) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return o.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values, using an executor.
+func (o MutedUserSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ ln := int64(len(o))
+ if ln == 0 {
+ return 0, nil
+ }
+
+ if len(cols) == 0 {
+ return 0, errors.New("models: update all requires at least one column argument")
+ }
+
+ colNames := make([]string, len(cols))
+ args := make([]interface{}, len(cols))
+
+ i := 0
+ for name, value := range cols {
+ colNames[i] = name
+ args[i] = value
+ i++
+ }
+
+ // Append all of the primary key values for each column
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), mutedUserPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := fmt.Sprintf("UPDATE \"muted_users\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, colNames),
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, mutedUserPrimaryKeyColumns, len(o)))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all in mutedUser slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all mutedUser")
+ }
+ return rowsAff, nil
+}
+
+// UpsertG attempts an insert, and does an update or ignore on conflict.
+func (o *MutedUser) UpsertG(ctx context.Context, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ return o.Upsert(ctx, boil.GetContextDB(), updateOnConflict, conflictColumns, updateColumns, insertColumns, opts...)
+}
+
+// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
+// See boil.Columns documentation for how to properly use updateColumns and insertColumns.
+func (o *MutedUser) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ if o == nil {
+ return errors.New("models: no muted_users provided for upsert")
+ }
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ o.UpdatedAt = currTime
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(mutedUserColumnsWithDefault, o)
+
+ // Build cache key in-line uglily - mysql vs psql problems
+ buf := strmangle.GetBuffer()
+ if updateOnConflict {
+ buf.WriteByte('t')
+ } else {
+ buf.WriteByte('f')
+ }
+ buf.WriteByte('.')
+ for _, c := range conflictColumns {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(updateColumns.Kind))
+ for _, c := range updateColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(insertColumns.Kind))
+ for _, c := range insertColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ for _, c := range nzDefaults {
+ buf.WriteString(c)
+ }
+ key := buf.String()
+ strmangle.PutBuffer(buf)
+
+ mutedUserUpsertCacheMut.RLock()
+ cache, cached := mutedUserUpsertCache[key]
+ mutedUserUpsertCacheMut.RUnlock()
+
+ var err error
+
+ if !cached {
+ insert, _ := insertColumns.InsertColumnSet(
+ mutedUserAllColumns,
+ mutedUserColumnsWithDefault,
+ mutedUserColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ update := updateColumns.UpdateColumnSet(
+ mutedUserAllColumns,
+ mutedUserPrimaryKeyColumns,
+ )
+
+ if updateOnConflict && len(update) == 0 {
+ return errors.New("models: unable to upsert muted_users, could not build update column list")
+ }
+
+ ret := strmangle.SetComplement(mutedUserAllColumns, strmangle.SetIntersect(insert, update))
+
+ conflict := conflictColumns
+ if len(conflict) == 0 && updateOnConflict && len(update) != 0 {
+ if len(mutedUserPrimaryKeyColumns) == 0 {
+ return errors.New("models: unable to upsert muted_users, could not build conflict column list")
+ }
+
+ conflict = make([]string, len(mutedUserPrimaryKeyColumns))
+ copy(conflict, mutedUserPrimaryKeyColumns)
+ }
+ cache.query = buildUpsertQueryPostgres(dialect, "\"muted_users\"", updateOnConflict, ret, update, conflict, insert, opts...)
+
+ cache.valueMapping, err = queries.BindMapping(mutedUserType, mutedUserMapping, insert)
+ if err != nil {
+ return err
+ }
+ if len(ret) != 0 {
+ cache.retMapping, err = queries.BindMapping(mutedUserType, mutedUserMapping, ret)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+ var returns []interface{}
+ if len(cache.retMapping) != 0 {
+ returns = queries.PtrsFromMapping(value, cache.retMapping)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...)
+ if errors.Is(err, sql.ErrNoRows) {
+ err = nil // Postgres doesn't return anything when there's no update
+ }
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+ if err != nil {
+ return errors.Wrap(err, "models: unable to upsert muted_users")
+ }
+
+ if !cached {
+ mutedUserUpsertCacheMut.Lock()
+ mutedUserUpsertCache[key] = cache
+ mutedUserUpsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// DeleteG deletes a single MutedUser record.
+// DeleteG will match against the primary key column to find the record to delete.
+func (o *MutedUser) DeleteG(ctx context.Context) (int64, error) {
+ return o.Delete(ctx, boil.GetContextDB())
+}
+
+// Delete deletes a single MutedUser record with an executor.
+// Delete will match against the primary key column to find the record to delete.
+func (o *MutedUser) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if o == nil {
+ return 0, errors.New("models: no MutedUser provided for delete")
+ }
+
+ args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), mutedUserPrimaryKeyMapping)
+ sql := "DELETE FROM \"muted_users\" WHERE \"id\"=$1"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete from muted_users")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by delete for muted_users")
+ }
+
+ return rowsAff, nil
+}
+
+func (q mutedUserQuery) DeleteAllG(ctx context.Context) (int64, error) {
+ return q.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all matching rows.
+func (q mutedUserQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if q.Query == nil {
+ return 0, errors.New("models: no mutedUserQuery provided for delete all")
+ }
+
+ queries.SetDelete(q.Query)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from muted_users")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for muted_users")
+ }
+
+ return rowsAff, nil
+}
+
+// DeleteAllG deletes all rows in the slice.
+func (o MutedUserSlice) DeleteAllG(ctx context.Context) (int64, error) {
+ return o.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all rows in the slice, using an executor.
+func (o MutedUserSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if len(o) == 0 {
+ return 0, nil
+ }
+
+ var args []interface{}
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), mutedUserPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "DELETE FROM \"muted_users\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, mutedUserPrimaryKeyColumns, len(o))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from mutedUser slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for muted_users")
+ }
+
+ return rowsAff, nil
+}
+
+// ReloadG refetches the object from the database using the primary keys.
+func (o *MutedUser) ReloadG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: no MutedUser provided for reload")
+ }
+
+ return o.Reload(ctx, boil.GetContextDB())
+}
+
+// Reload refetches the object from the database
+// using the primary keys with an executor.
+func (o *MutedUser) Reload(ctx context.Context, exec boil.ContextExecutor) error {
+ ret, err := FindMutedUser(ctx, exec, o.ID)
+ if err != nil {
+ return err
+ }
+
+ *o = *ret
+ return nil
+}
+
+// ReloadAllG refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *MutedUserSlice) ReloadAllG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: empty MutedUserSlice provided for reload all")
+ }
+
+ return o.ReloadAll(ctx, boil.GetContextDB())
+}
+
+// ReloadAll refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *MutedUserSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error {
+ if o == nil || len(*o) == 0 {
+ return nil
+ }
+
+ slice := MutedUserSlice{}
+ var args []interface{}
+ for _, obj := range *o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), mutedUserPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "SELECT \"muted_users\".* FROM \"muted_users\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, mutedUserPrimaryKeyColumns, len(*o))
+
+ q := queries.Raw(sql, args...)
+
+ err := q.Bind(ctx, exec, &slice)
+ if err != nil {
+ return errors.Wrap(err, "models: unable to reload all in MutedUserSlice")
+ }
+
+ *o = slice
+
+ return nil
+}
+
+// MutedUserExistsG checks if the MutedUser row exists.
+func MutedUserExistsG(ctx context.Context, iD int) (bool, error) {
+ return MutedUserExists(ctx, boil.GetContextDB(), iD)
+}
+
+// MutedUserExists checks if the MutedUser row exists.
+func MutedUserExists(ctx context.Context, exec boil.ContextExecutor, iD int) (bool, error) {
+ var exists bool
+ sql := "select exists(select 1 from \"muted_users\" where \"id\"=$1 limit 1)"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, iD)
+ }
+ row := exec.QueryRowContext(ctx, sql, iD)
+
+ err := row.Scan(&exists)
+ if err != nil {
+ return false, errors.Wrap(err, "models: unable to check if muted_users exists")
+ }
+
+ return exists, nil
+}
+
+// Exists checks if the MutedUser row exists.
+func (o *MutedUser) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ return MutedUserExists(ctx, exec, o.ID)
+}
diff --git a/moderation/models/psql_upsert.go b/moderation/models/psql_upsert.go
new file mode 100644
index 0000000000..07602da9c5
--- /dev/null
+++ b/moderation/models/psql_upsert.go
@@ -0,0 +1,99 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/volatiletech/sqlboiler/v4/drivers"
+ "github.com/volatiletech/strmangle"
+)
+
+type UpsertOptions struct {
+ conflictTarget string
+ updateSet string
+}
+
+type UpsertOptionFunc func(o *UpsertOptions)
+
+func UpsertConflictTarget(conflictTarget string) UpsertOptionFunc {
+ return func(o *UpsertOptions) {
+ o.conflictTarget = conflictTarget
+ }
+}
+
+func UpsertUpdateSet(updateSet string) UpsertOptionFunc {
+ return func(o *UpsertOptions) {
+ o.updateSet = updateSet
+ }
+}
+
+// buildUpsertQueryPostgres builds a SQL statement string using the upsertData provided.
+func buildUpsertQueryPostgres(dia drivers.Dialect, tableName string, updateOnConflict bool, ret, update, conflict, whitelist []string, opts ...UpsertOptionFunc) string {
+ conflict = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, conflict)
+ whitelist = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, whitelist)
+ ret = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, ret)
+
+ upsertOpts := &UpsertOptions{}
+ for _, o := range opts {
+ o(upsertOpts)
+ }
+
+ buf := strmangle.GetBuffer()
+ defer strmangle.PutBuffer(buf)
+
+ columns := "DEFAULT VALUES"
+ if len(whitelist) != 0 {
+ columns = fmt.Sprintf("(%s) VALUES (%s)",
+ strings.Join(whitelist, ", "),
+ strmangle.Placeholders(dia.UseIndexPlaceholders, len(whitelist), 1, 1))
+ }
+
+ fmt.Fprintf(
+ buf,
+ "INSERT INTO %s %s ON CONFLICT ",
+ tableName,
+ columns,
+ )
+
+ if upsertOpts.conflictTarget != "" {
+ buf.WriteString(upsertOpts.conflictTarget)
+ } else if len(conflict) != 0 {
+ buf.WriteByte('(')
+ buf.WriteString(strings.Join(conflict, ", "))
+ buf.WriteByte(')')
+ }
+ buf.WriteByte(' ')
+
+ if !updateOnConflict || len(update) == 0 {
+ buf.WriteString("DO NOTHING")
+ } else {
+ buf.WriteString("DO UPDATE SET ")
+
+ if upsertOpts.updateSet != "" {
+ buf.WriteString(upsertOpts.updateSet)
+ } else {
+ for i, v := range update {
+ if len(v) == 0 {
+ continue
+ }
+ if i != 0 {
+ buf.WriteByte(',')
+ }
+ quoted := strmangle.IdentQuote(dia.LQ, dia.RQ, v)
+ buf.WriteString(quoted)
+ buf.WriteString(" = EXCLUDED.")
+ buf.WriteString(quoted)
+ }
+ }
+ }
+
+ if len(ret) != 0 {
+ buf.WriteString(" RETURNING ")
+ buf.WriteString(strings.Join(ret, ", "))
+ }
+
+ return buf.String()
+}
diff --git a/moderation/moderation.go b/moderation/moderation.go
index d2b6a21134..f30186db99 100644
--- a/moderation/moderation.go
+++ b/moderation/moderation.go
@@ -3,12 +3,12 @@ package moderation
import (
"emperror.dev/errors"
"github.com/botlabs-gg/yagpdb/v2/common"
- "github.com/botlabs-gg/yagpdb/v2/common/configstore"
"github.com/botlabs-gg/yagpdb/v2/common/featureflags"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
- "golang.org/x/net/context"
)
+//go:generate sqlboiler --no-hooks psql
+
const (
ActionMuted = "Muted"
ActionUnMuted = "Unmuted"
@@ -48,32 +48,9 @@ func RedisKeyLockedMute(guildID, userID int64) string {
func RegisterPlugin() {
plugin := &Plugin{}
-
common.RegisterPlugin(plugin)
- configstore.RegisterConfig(configstore.SQL, &Config{})
- common.GORM.AutoMigrate(&Config{}, &WarningModel{}, &MuteModel{})
-}
-
-func getConfigIfNotSet(guildID int64, config *Config) (*Config, error) {
- if config == nil {
- var err error
- config, err = GetConfig(guildID)
- if err != nil {
- return nil, err
- }
- }
-
- return config, nil
-}
-
-func GetConfig(guildID int64) (*Config, error) {
- var config Config
- err := configstore.Cached.GetGuildConfig(context.Background(), guildID, &config)
- if err == configstore.ErrNotFound {
- err = nil
- }
- return &config, err
+ common.InitSchemas("moderation", DBSchemas...)
}
var _ featureflags.PluginWithFeatureFlags = (*Plugin)(nil)
@@ -84,17 +61,17 @@ const (
)
func (p *Plugin) UpdateFeatureFlags(guildID int64) ([]string, error) {
- config, err := GetConfig(guildID)
+ config, err := GetCachedConfigOrDefault(guildID)
if err != nil {
return nil, errors.WithStackIf(err)
}
var flags []string
- if config.MuteRole != "" && config.MuteManageRole {
+ if config.MuteRole != 0 && config.MuteManageRole {
flags = append(flags, featureFlagMuteRoleManaged)
}
- if config.MuteRole != "" {
+ if config.MuteRole != 0 {
flags = append(flags, featureFlagMuteEnabled)
}
diff --git a/moderation/modlog.go b/moderation/modlog.go
index c79996a556..6cbd96d1cb 100644
--- a/moderation/modlog.go
+++ b/moderation/modlog.go
@@ -41,8 +41,7 @@ var (
)
func CreateModlogEmbed(config *Config, author *discordgo.User, action ModlogAction, target *discordgo.User, reason, logLink string) error {
- channelID := config.IntActionChannel()
- config.GetGuildID()
+ channelID := config.ActionChannel
if channelID == 0 {
return nil
}
@@ -88,8 +87,8 @@ func CreateModlogEmbed(config *Config, author *discordgo.User, action ModlogActi
if err != nil {
if common.IsDiscordErr(err, discordgo.ErrCodeMissingAccess, discordgo.ErrCodeMissingPermissions, discordgo.ErrCodeUnknownChannel) {
// disable the modlog
- config.ActionChannel = ""
- config.Save(config.GetGuildID())
+ config.ActionChannel = 0
+ SaveConfig(config)
return nil
}
return err
diff --git a/moderation/plugin_bot.go b/moderation/plugin_bot.go
index 09c860ea46..090efcb29b 100644
--- a/moderation/plugin_bot.go
+++ b/moderation/plugin_bot.go
@@ -1,6 +1,8 @@
package moderation
import (
+ "context"
+ "database/sql"
"math/rand"
"strconv"
"strings"
@@ -18,8 +20,10 @@ import (
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/lib/dshardorchestrator"
"github.com/botlabs-gg/yagpdb/v2/lib/dstate"
- "github.com/jinzhu/gorm"
+ "github.com/botlabs-gg/yagpdb/v2/moderation/models"
+ "github.com/karlseguin/ccache"
"github.com/mediocregopher/radix/v3"
+ "github.com/volatiletech/sqlboiler/v4/boil"
)
var (
@@ -43,8 +47,6 @@ func (p *Plugin) AddCommands() {
}
func (p *Plugin) BotInit() {
- // scheduledevents.RegisterEventHandler("unmute", handleUnMuteLegacy)
- // scheduledevents.RegisterEventHandler("mod_unban", handleUnbanLegacy)
scheduledevents2.RegisterHandler("moderation_unmute", ScheduledUnmuteData{}, handleScheduledUnmute)
scheduledevents2.RegisterHandler("moderation_unban", ScheduledUnbanData{}, handleScheduledUnban)
scheduledevents2.RegisterLegacyMigrater("unmute", handleMigrateScheduledUnmute)
@@ -59,10 +61,92 @@ func (p *Plugin) BotInit() {
eventsystem.AddHandlerAsyncLastLegacy(p, bot.ConcurrentEventHandler(HandleGuildCreate), eventsystem.EventGuildCreate)
eventsystem.AddHandlerAsyncLast(p, HandleChannelCreateUpdate, eventsystem.EventChannelCreate, eventsystem.EventChannelUpdate)
+ pubsub.AddHandler("invalidate_moderation_config_cache", handleInvalidateConfigCache, nil)
pubsub.AddHandler("mod_refresh_mute_override", HandleRefreshMuteOverrides, nil)
pubsub.AddHandler("mod_refresh_mute_override_create_role", HandleRefreshMuteOverridesCreateRole, nil)
}
+func SaveConfig(config *Config) error {
+ err := config.ToModel().UpsertG(context.Background(), true, []string{"guild_id"}, boil.Infer(), boil.Infer())
+ if err != nil {
+ return err
+ }
+ pubsub.Publish("invalidate_moderation_config_cache", config.GuildID, nil)
+
+ if err := featureflags.UpdatePluginFeatureFlags(config.GuildID, &Plugin{}); err != nil {
+ return err
+ }
+ pubsub.Publish("mod_refresh_mute_override", config.GuildID, nil)
+ return nil
+}
+
+func GetConfigIfNotSet(guildID int64, config *Config) (*Config, error) {
+ if config == nil {
+ var err error
+ config, err = GetCachedConfigOrDefault(guildID)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return config, nil
+}
+
+var configCache = ccache.New(ccache.Configure().MaxSize(15000))
+
+func GetCachedConfigOrDefault(guildID int64) (*Config, error) {
+ const cacheDuration = 10 * time.Minute
+
+ item, err := configCache.Fetch(cacheKey(guildID), cacheDuration, func() (interface{}, error) {
+ return GetConfig(guildID)
+ })
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return &Config{GuildID: guildID}, nil
+ }
+ return nil, err
+ }
+ return item.Value().(*Config), nil
+}
+
+func handleInvalidateConfigCache(evt *pubsub.Event) {
+ configCache.Delete(cacheKey(evt.TargetGuildInt))
+}
+
+func cacheKey(guildID int64) string {
+ return discordgo.StrID(guildID)
+}
+
+func GetConfig(guildID int64) (*Config, error) {
+ const maxRetries = 1000
+
+ currentRetries := 0
+ for {
+ conf, err := models.FindModerationConfigG(context.Background(), guildID)
+ if err == nil {
+ if currentRetries > 1 {
+ logger.Info("Fetched config after ", currentRetries, " retries")
+ }
+ return configFromModel(conf), nil
+ }
+
+ if err == sql.ErrNoRows {
+ return nil, err
+ }
+
+ if strings.Contains(err.Error(), "sorry, too many clients already") {
+ time.Sleep(time.Millisecond * 10 * time.Duration(rand.Intn(10)))
+ currentRetries++
+ if currentRetries > maxRetries {
+ return nil, err
+ }
+ continue
+ }
+
+ return nil, err
+ }
+}
+
type ScheduledUnmuteData struct {
UserID int64 `json:"user_id"`
}
@@ -118,7 +202,7 @@ func RefreshMuteOverrides(guildID int64, createRole bool) {
return // nothing to do
}
- config, err := GetConfig(guildID)
+ config, err := GetCachedConfigOrDefault(guildID)
if err != nil {
return
}
@@ -131,7 +215,7 @@ func RefreshMuteOverrides(guildID int64, createRole bool) {
return
}
- if config.MuteRole == "" || config.MuteRole == "0" {
+ if config.MuteRole == 0 {
if createRole {
_, err := createMuteRole(config, guildID)
if err != nil {
@@ -149,7 +233,7 @@ func RefreshMuteOverrides(guildID int64, createRole bool) {
return // Still starting up and haven't received the guild yet
}
- if guild.GetRole(config.IntMuteRole()) == nil {
+ if guild.GetRole(config.MuteRole) == nil {
return
}
@@ -175,8 +259,8 @@ func createMuteRole(config *Config, guildID int64) (int64, error) {
return 0, err
}
- config.MuteRole = strconv.FormatInt(r.ID, 10)
- err = config.Save(guildID)
+ config.MuteRole = r.ID
+ err = SaveConfig(config)
if err != nil {
// failed saving config, attempt to delete the role
common.BotSession.GuildRoleDelete(guildID, r.ID)
@@ -202,12 +286,12 @@ func HandleChannelCreateUpdate(evt *eventsystem.EventData) (retry bool, err erro
return false, nil
}
- config, err := GetConfig(channel.GuildID)
+ config, err := GetCachedConfigOrDefault(channel.GuildID)
if err != nil {
return true, errors.WithStackIf(err)
}
- if config.MuteRole == "" || !config.MuteManageRole {
+ if config.MuteRole == 0 || !config.MuteManageRole {
return false, nil
}
@@ -230,7 +314,7 @@ func RefreshMuteOverrideForChannel(config *Config, channel dstate.ChannelState)
// Check for existing override
for _, v := range channel.PermissionOverwrites {
- if v.Type == discordgo.PermissionOverwriteTypeRole && v.ID == config.IntMuteRole() {
+ if v.Type == discordgo.PermissionOverwriteTypeRole && v.ID == config.MuteRole {
override = &v
break
}
@@ -263,7 +347,7 @@ func RefreshMuteOverrideForChannel(config *Config, channel dstate.ChannelState)
}
if changed {
- common.BotSession.ChannelPermissionSet(channel.ID, config.IntMuteRole(), discordgo.PermissionOverwriteTypeRole, allows, denies)
+ common.BotSession.ChannelPermissionSet(channel.ID, config.MuteRole, discordgo.PermissionOverwriteTypeRole, allows, denies)
}
}
@@ -274,13 +358,13 @@ func HandleGuildMemberTimeoutChange(evt *eventsystem.EventData) (retry bool, err
return false, nil
}
- config, err := GetConfig(data.GuildID)
+ config, err := GetCachedConfigOrDefault(data.GuildID)
if err != nil {
return true, errors.WithStackIf(err)
}
// no modlog channel setup
- if config.IntActionChannel() == 0 {
+ if config.ActionChannel == 0 {
return false, nil
}
// If we poll the audit log too fast then there sometimes wont be a audit log entry
@@ -358,13 +442,13 @@ func HandleGuildBanAddRemove(evt *eventsystem.EventData) {
return
}
- config, err := GetConfig(guildID)
+ config, err := GetCachedConfigOrDefault(guildID)
if err != nil {
logger.WithError(err).WithField("guild", guildID).Error("Failed retrieving config")
return
}
- if config.IntActionChannel() == 0 {
+ if config.ActionChannel == 0 {
return
}
@@ -407,12 +491,12 @@ func HandleGuildBanAddRemove(evt *eventsystem.EventData) {
func HandleGuildMemberRemove(evt *eventsystem.EventData) (retry bool, err error) {
data := evt.GuildMemberRemove()
- config, err := GetConfig(data.GuildID)
+ config, err := GetCachedConfigOrDefault(data.GuildID)
if err != nil {
return true, errors.WithStackIf(err)
}
- if config.IntActionChannel() == 0 {
+ if config.ActionChannel == 0 {
return false, nil
}
@@ -468,10 +552,12 @@ func LockMemberMuteMW(next eventsystem.HandlerFunc) eventsystem.HandlerFunc {
guildID := evt.GS.ID
- var currentMute MuteModel
- err = common.GORM.Where(MuteModel{UserID: userID, GuildID: guildID}).First(¤tMute).Error
+ currentMute, err := models.MutedUsers(
+ models.MutedUserWhere.UserID.EQ(userID),
+ models.MutedUserWhere.GuildID.EQ(guildID),
+ ).OneG(evt.Context())
if err != nil {
- if err == gorm.ErrRecordNotFound {
+ if err == sql.ErrNoRows {
return false, nil
}
@@ -479,7 +565,7 @@ func LockMemberMuteMW(next eventsystem.HandlerFunc) eventsystem.HandlerFunc {
}
// Don't bother doing anything if this mute is almost up
- if !currentMute.ExpiresAt.IsZero() && currentMute.ExpiresAt.Sub(time.Now()) < 5*time.Second {
+ if !currentMute.ExpiresAt.Time.IsZero() && time.Until(currentMute.ExpiresAt.Time) < 5*time.Second {
return false, nil
}
@@ -490,16 +576,16 @@ func LockMemberMuteMW(next eventsystem.HandlerFunc) eventsystem.HandlerFunc {
func HandleMemberJoin(evt *eventsystem.EventData) (retry bool, err error) {
c := evt.GuildMemberAdd()
- config, err := GetConfig(c.GuildID)
+ config, err := GetCachedConfigOrDefault(c.GuildID)
if err != nil {
return true, errors.WithStackIf(err)
}
- if config.MuteRole == "" {
+ if config.MuteRole == 0 {
return false, nil
}
- err = common.BotSession.GuildMemberRoleAdd(c.GuildID, c.User.ID, config.IntMuteRole())
+ err = common.BotSession.GuildMemberRoleAdd(c.GuildID, c.User.ID, config.MuteRole)
if err != nil {
return bot.CheckDiscordErrRetry(err), errors.WithStackIf(err)
}
@@ -515,12 +601,12 @@ func HandleGuildMemberUpdate(evt *eventsystem.EventData) (retry bool, err error)
return false, nil
}
- config, err := GetConfig(c.GuildID)
+ config, err := GetCachedConfigOrDefault(c.GuildID)
if err != nil {
return true, errors.WithStackIf(err)
}
- if config.MuteRole == "" {
+ if config.MuteRole == 0 {
return false, nil
}
@@ -530,7 +616,7 @@ func HandleGuildMemberUpdate(evt *eventsystem.EventData) (retry bool, err error)
guild := evt.GS
- role := guild.GetRole(config.IntMuteRole())
+ role := guild.GetRole(config.MuteRole)
if role == nil {
return false, nil // Probably deleted the mute role, do nothing then
}
diff --git a/moderation/plugin_web.go b/moderation/plugin_web.go
index dbf6ca3ca2..45e8132979 100644
--- a/moderation/plugin_web.go
+++ b/moderation/plugin_web.go
@@ -9,6 +9,7 @@ import (
"github.com/botlabs-gg/yagpdb/v2/common"
"github.com/botlabs-gg/yagpdb/v2/common/cplogs"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
+ "github.com/botlabs-gg/yagpdb/v2/moderation/models"
"github.com/botlabs-gg/yagpdb/v2/web"
"goji.io"
"goji.io/pat"
@@ -57,7 +58,7 @@ func HandleModeration(w http.ResponseWriter, r *http.Request) (web.TemplateData,
templateData["DefaultTimeoutDuration"] = int(DefaultTimeoutDuration.Minutes())
if _, ok := templateData["ModConfig"]; !ok {
- config, err := GetConfig(activeGuild.ID)
+ config, err := GetCachedConfigOrDefault(activeGuild.ID)
if err != nil {
return templateData, err
}
@@ -67,19 +68,17 @@ func HandleModeration(w http.ResponseWriter, r *http.Request) (web.TemplateData,
return templateData, nil
}
-// HandlePostModeration update the settings
+// HandlePostModeration updates the settings
func HandlePostModeration(w http.ResponseWriter, r *http.Request) (web.TemplateData, error) {
ctx := r.Context()
activeGuild, templateData := web.GetBaseCPContextData(ctx)
templateData["VisibleURL"] = "/manage/" + discordgo.StrID(activeGuild.ID) + "/moderation/"
newConfig := ctx.Value(common.ContextKeyParsedForm).(*Config)
- newConfig.DefaultMuteDuration.Valid = true
- newConfig.DefaultTimeoutDuration.Valid = true
- newConfig.DefaultBanDeleteDays.Valid = true
templateData["ModConfig"] = newConfig
- err := newConfig.Save(activeGuild.ID)
+ newConfig.GuildID = activeGuild.ID
+ err := SaveConfig(newConfig)
templateData["DefaultDMMessage"] = DefaultDMMessage
@@ -96,12 +95,12 @@ func HandleClearServerWarnings(w http.ResponseWriter, r *http.Request) (web.Temp
activeGuild, templateData := web.GetBaseCPContextData(ctx)
templateData["VisibleURL"] = "/manage/" + discordgo.StrID(activeGuild.ID) + "/moderation/"
- rows := common.GORM.Where("guild_id = ?", activeGuild.ID).Delete(WarningModel{}).RowsAffected
- templateData.AddAlerts(web.SucessAlert("Deleted ", rows, " warnings!"))
+ numDeleted, _ := models.ModerationWarnings(models.ModerationWarningWhere.GuildID.EQ(activeGuild.ID)).DeleteAllG(r.Context())
+ templateData.AddAlerts(web.SucessAlert("Deleted ", numDeleted, " warnings!"))
templateData["DefaultDMMessage"] = DefaultDMMessage
- if rows > 0 {
- go cplogs.RetryAddEntry(web.NewLogEntryFromContext(r.Context(), panelLogKeyClearWarnings, &cplogs.Param{Type: cplogs.ParamTypeInt, Value: rows}))
+ if numDeleted > 0 {
+ go cplogs.RetryAddEntry(web.NewLogEntryFromContext(r.Context(), panelLogKeyClearWarnings, &cplogs.Param{Type: cplogs.ParamTypeInt, Value: numDeleted}))
}
return templateData, nil
@@ -115,7 +114,7 @@ func (p *Plugin) LoadServerHomeWidget(w http.ResponseWriter, r *http.Request) (w
templateData["WidgetTitle"] = "Moderation"
templateData["SettingsPath"] = "/moderation"
- config, err := GetConfig(activeGuild.ID)
+ config, err := GetCachedConfigOrDefault(activeGuild.ID)
if err != nil {
return templateData, err
}
@@ -131,7 +130,7 @@ func (p *Plugin) LoadServerHomeWidget(w http.ResponseWriter, r *http.Request) (w
Warning commands: %s
`
- if config.ReportEnabled || config.CleanEnabled || config.GiveRoleCmdEnabled || config.ActionChannel != "" ||
+ if config.ReportEnabled || config.CleanEnabled || config.GiveRoleCmdEnabled || config.ActionChannel != 0 ||
config.MuteEnabled || config.KickEnabled || config.BanEnabled || config.WarnCommandsEnabled || config.TimeoutEnabled {
templateData["WidgetEnabled"] = true
} else {
diff --git a/moderation/punishments.go b/moderation/punishments.go
index 11da72fdda..544278661c 100644
--- a/moderation/punishments.go
+++ b/moderation/punishments.go
@@ -2,6 +2,7 @@ package moderation
import (
"context"
+ "database/sql"
"fmt"
"strconv"
"strings"
@@ -16,8 +17,9 @@ import (
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/lib/dstate"
"github.com/botlabs-gg/yagpdb/v2/logs"
- "github.com/jinzhu/gorm"
+ "github.com/botlabs-gg/yagpdb/v2/moderation/models"
"github.com/mediocregopher/radix/v3"
+ "github.com/volatiletech/sqlboiler/v4/boil"
"github.com/volatiletech/sqlboiler/v4/queries/qm"
)
@@ -53,7 +55,7 @@ func getMemberWithFallback(gs *dstate.GuildSet, user *discordgo.User) (ms *dstat
// Kick or bans someone, uploading a hasebin log, and sending the report message in the action channel
func punish(config *Config, p Punishment, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, duration time.Duration, variadicBanDeleteDays ...int) error {
- config, err := getConfigIfNotSet(guildID, config)
+ config, err := GetConfigIfNotSet(guildID, config)
if err != nil {
return common.ErrWithCaller(err)
}
@@ -196,8 +198,8 @@ func sendPunishDM(config *Config, dmMsg string, action ModlogAction, gs *dstate.
logger.WithError(err).WithField("guild", gs.ID).Warn("Failed executing punishment DM")
executed = "Failed executing template."
- if config.ErrorChannel != "" {
- _, _, _ = bot.SendMessage(gs.ID, config.IntErrorChannel(), fmt.Sprintf("Failed executing punishment DM (Action: `%s`).\nError: `%v`", ActionMap[action.Prefix], err))
+ if config.ErrorChannel != 0 {
+ _, _, _ = bot.SendMessage(gs.ID, config.ErrorChannel, fmt.Sprintf("Failed executing punishment DM (Action: `%s`).\nError: `%v`", ActionMap[action.Prefix], err))
}
}
@@ -210,7 +212,7 @@ func sendPunishDM(config *Config, dmMsg string, action ModlogAction, gs *dstate.
}
func KickUser(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, del int) error {
- config, err := getConfigIfNotSet(guildID, config)
+ config, err := GetConfigIfNotSet(guildID, config)
if err != nil {
return common.ErrWithCaller(err)
}
@@ -226,10 +228,7 @@ func KickUser(config *Config, guildID int64, channel *dstate.ChannelState, messa
del = 100
}
- if channel != nil {
- _, err = DeleteMessages(guildID, channel.ID, user.ID, del, del)
- }
-
+ _, err = DeleteMessages(guildID, channel.ID, user.ID, del, del)
return err
}
@@ -307,7 +306,7 @@ func BanUser(config *Config, guildID int64, channel *dstate.ChannelState, messag
}
func UnbanUser(config *Config, guildID int64, author *discordgo.User, reason string, user *discordgo.User) (bool, error) {
- config, err := getConfigIfNotSet(guildID, config)
+ config, err := GetConfigIfNotSet(guildID, config)
if err != nil {
return false, common.ErrWithCaller(err)
}
@@ -318,7 +317,7 @@ func UnbanUser(config *Config, guildID int64, author *discordgo.User, reason str
common.LogIgnoreError(err, "[moderation] failed clearing unban events", nil)
//We need details for user only if unban is to be logged in modlog. Thus we can save a potential api call by directly attempting an unban in other cases.
- if config.LogUnbans && config.IntActionChannel() != 0 {
+ if config.LogUnbans && config.ActionChannel != 0 {
// check if they're already banned
guildBan, err := common.BotSession.GuildBan(guildID, user.ID)
if err != nil {
@@ -362,7 +361,7 @@ func TimeoutUser(config *Config, guildID int64, channel *dstate.ChannelState, me
}
func RemoveTimeout(config *Config, guildID int64, author *discordgo.User, reason string, user *discordgo.User) error {
- config, err := getConfigIfNotSet(guildID, config)
+ config, err := GetConfigIfNotSet(guildID, config)
if err != nil {
return common.ErrWithCaller(err)
}
@@ -403,12 +402,12 @@ const (
// Unmut or mute a user, ignore duration if unmuting
// TODO: i don't think we need to track mutes in its own database anymore now with the new scheduled event system
func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, member *dstate.MemberState, duration int) error {
- config, err := getConfigIfNotSet(guildID, config)
+ config, err := GetConfigIfNotSet(guildID, config)
if err != nil {
return common.ErrWithCaller(err)
}
- if config.MuteRole == "" {
+ if config.MuteRole == 0 {
return ErrNoMuteRole
}
@@ -422,16 +421,18 @@ func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.Ch
defer UnlockMute(member.User.ID)
// Look for existing mute
- currentMute := MuteModel{}
- err = common.GORM.Where(&MuteModel{UserID: member.User.ID, GuildID: guildID}).First(¤tMute).Error
- alreadyMuted := err != gorm.ErrRecordNotFound
- if err != nil && err != gorm.ErrRecordNotFound {
+ currentMute, err := models.MutedUsers(
+ models.MutedUserWhere.UserID.EQ(member.User.ID),
+ models.MutedUserWhere.GuildID.EQ(guildID),
+ ).OneG(context.Background())
+ alreadyMuted := err != sql.ErrNoRows
+ if err != nil && err != sql.ErrNoRows {
return common.ErrWithCaller(err)
}
// Insert/update the mute entry in the database
if !alreadyMuted {
- currentMute = MuteModel{
+ currentMute = &models.MutedUser{
UserID: member.User.ID,
GuildID: guildID,
}
@@ -443,7 +444,9 @@ func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.Ch
currentMute.Reason = reason
if duration > 0 {
- currentMute.ExpiresAt = time.Now().Add(time.Minute * time.Duration(duration))
+ currentMute.ExpiresAt.SetValid(time.Now().Add(time.Minute * time.Duration(duration)))
+ } else {
+ currentMute.ExpiresAt.Valid = false // duration <= 0 means no expiry
}
// no matter what, if were unmuting or muting, we wanna make sure we dont have duplicated unmute events
@@ -475,7 +478,7 @@ func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.Ch
currentMute.RemovedRoles = removedRoles
}
- err = common.GORM.Save(¤tMute).Error
+ err = currentMute.UpsertG(context.Background(), true, []string{"id"}, boil.Infer(), boil.Infer())
if err != nil {
return errors.WithMessage(err, "failed inserting/updating mute")
}
@@ -496,7 +499,7 @@ func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.Ch
}
if alreadyMuted {
- common.GORM.Delete(¤tMute)
+ currentMute.DeleteG(context.Background())
common.RedisPool.Do(radix.Cmd(nil, "DEL", RedisKeyMutedUser(guildID, member.User.ID)))
}
}
@@ -532,11 +535,11 @@ func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.Ch
func AddMemberMuteRole(config *Config, id int64, currentRoles []int64) (removedRoles []int64, err error) {
removedRoles = make([]int64, 0, len(config.MuteRemoveRoles))
newMemberRoles := make([]string, 0, len(currentRoles))
- newMemberRoles = append(newMemberRoles, config.MuteRole)
+ newMemberRoles = append(newMemberRoles, discordgo.StrID(config.MuteRole))
hadMuteRole := false
for _, r := range currentRoles {
- if config.IntMuteRole() == r {
+ if r == config.MuteRole {
hadMuteRole = true
continue
}
@@ -557,13 +560,13 @@ func AddMemberMuteRole(config *Config, id int64, currentRoles []int64) (removedR
return
}
-func RemoveMemberMuteRole(config *Config, id int64, currentRoles []int64, mute MuteModel) (err error) {
+func RemoveMemberMuteRole(config *Config, id int64, currentRoles []int64, mute *models.MutedUser) (err error) {
newMemberRoles := decideUnmuteRoles(config, currentRoles, mute)
err = common.BotSession.GuildMemberEdit(config.GuildID, id, newMemberRoles)
return
}
-func decideUnmuteRoles(config *Config, currentRoles []int64, mute MuteModel) []string {
+func decideUnmuteRoles(config *Config, currentRoles []int64, mute *models.MutedUser) []string {
newMemberRoles := make([]string, 0)
gs := bot.State.GetGuild(config.GuildID)
@@ -571,7 +574,7 @@ func decideUnmuteRoles(config *Config, currentRoles []int64, mute MuteModel) []s
if err != nil || botState == nil { // We couldn't find the bot on state, so keep old behaviour
for _, r := range currentRoles {
- if r != config.IntMuteRole() {
+ if r != config.MuteRole {
newMemberRoles = append(newMemberRoles, strconv.FormatInt(r, 10))
}
}
@@ -588,7 +591,7 @@ func decideUnmuteRoles(config *Config, currentRoles []int64, mute MuteModel) []s
yagHighest := bot.MemberHighestRole(gs, botState)
for _, v := range currentRoles {
- if v != config.IntMuteRole() {
+ if v != config.MuteRole {
newMemberRoles = append(newMemberRoles, strconv.FormatInt(v, 10))
}
}
@@ -604,7 +607,7 @@ func decideUnmuteRoles(config *Config, currentRoles []int64, mute MuteModel) []s
}
func WarnUser(config *Config, guildID int64, channel *dstate.ChannelState, msg *discordgo.Message, author *discordgo.User, target *discordgo.User, message string) error {
- warning := &WarningModel{
+ warning := &models.ModerationWarning{
GuildID: guildID,
UserID: discordgo.StrID(target.ID),
AuthorID: discordgo.StrID(author.ID),
@@ -618,17 +621,17 @@ func WarnUser(config *Config, guildID int64, channel *dstate.ChannelState, msg *
channelID = channel.ID
}
- config, err := getConfigIfNotSet(guildID, config)
+ config, err := GetConfigIfNotSet(guildID, config)
if err != nil {
return common.ErrWithCaller(err)
}
if config.WarnIncludeChannelLogs && channelID != 0 {
- warning.LogsLink = CreateLogs(guildID, channelID, author)
+ warning.LogsLink.SetValid(CreateLogs(guildID, channelID, author))
}
// Create the entry in the database
- err = common.GORM.Create(warning).Error
+ err = warning.InsertG(context.Background(), boil.Infer())
if err != nil {
return common.ErrWithCaller(err)
}
@@ -641,8 +644,8 @@ func WarnUser(config *Config, guildID int64, channel *dstate.ChannelState, msg *
// go bot.SendDM(target.ID, fmt.Sprintf("**%s**: You have been warned for: %s", bot.GuildName(guildID), message))
- if config.WarnSendToModlog && config.ActionChannel != "" {
- err = CreateModlogEmbed(config, author, MAWarned, target, message, warning.LogsLink)
+ if config.WarnSendToModlog && config.ActionChannel != 0 {
+ err = CreateModlogEmbed(config, author, MAWarned, target, message, warning.LogsLink.String)
if err != nil {
return common.ErrWithCaller(err)
}
diff --git a/moderation/schema.go b/moderation/schema.go
new file mode 100644
index 0000000000..c2c9e41269
--- /dev/null
+++ b/moderation/schema.go
@@ -0,0 +1,143 @@
+package moderation
+
+var DBSchemas = []string{`
+CREATE TABLE IF NOT EXISTS moderation_configs (
+ guild_id BIGINT PRIMARY KEY,
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL,
+ updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
+
+ -- Many of the following columns should be non-nullable, but were originally
+ -- managed by gorm (which does not add NOT NULL constraints by default) so are
+ -- missing them. Unfortunately, it is unfeasible to retroactively fill missing
+ -- values with defaults and add the constraints as there are simply too many
+ -- rows in production.
+
+ -- For similar legacy reasons, many fields that should have type BIGINT are TEXT.
+
+ kick_enabled BOOLEAN,
+ kick_cmd_roles BIGINT[],
+ delete_messages_on_kick BOOLEAN,
+ kick_reason_optional BOOLEAN,
+ kick_message TEXT,
+
+ ban_enabled BOOLEAN,
+ ban_cmd_roles BIGINT[],
+ ban_reason_optional BOOLEAN,
+ ban_message TEXT,
+ default_ban_delete_days BIGINT DEFAULT 1,
+
+ timeout_enabled BOOLEAN,
+ timeout_cmd_roles BIGINT[],
+ timeout_reason_optional BOOLEAN,
+ timeout_remove_reason_optional BOOLEAN,
+ timeout_message TEXT,
+ default_timeout_duration BIGINT DEFAULT 10,
+
+ mute_enabled BOOLEAN,
+ mute_cmd_roles BIGINT[],
+ mute_role TEXT,
+ mute_disallow_reaction_add BOOLEAN,
+ mute_reason_optional BOOLEAN,
+ unmute_reason_optional BOOLEAN,
+ mute_manage_role BOOLEAN,
+ mute_remove_roles BIGINT[],
+ mute_ignore_channels BIGINT[],
+ mute_message TEXT,
+ unmute_message TEXT,
+ default_mute_duration BIGINT DEFAULT 10,
+
+ warn_commands_enabled BOOLEAN,
+ warn_cmd_roles BIGINT[],
+ warn_include_channel_logs BOOLEAN,
+ warn_send_to_modlog BOOLEAN,
+ warn_message TEXT,
+
+ clean_enabled BOOLEAN,
+ report_enabled BOOLEAN,
+ action_channel TEXT,
+ report_channel TEXT,
+ error_channel TEXT,
+ log_unbans BOOLEAN,
+ log_bans BOOLEAN,
+ log_kicks BOOLEAN DEFAULT TRUE,
+ log_timeouts BOOLEAN,
+
+ give_role_cmd_enabled BOOLEAN,
+ give_role_cmd_modlog BOOLEAN,
+ give_role_cmd_roles BIGINT[]
+);
+`, `
+-- Tables created with gorm have missing NOT NULL constraints for created_at and
+-- updated_at columns; since these columns are never null in existing rows, we can
+-- retraoctively add the constraints without needing to update any data.
+
+ALTER TABLE moderation_configs ALTER COLUMN created_at SET NOT NULL;
+`, `
+ALTER TABLE moderation_configs ALTER COLUMN updated_at SET NOT NULL;
+`, `
+
+CREATE TABLE IF NOT EXISTS moderation_warnings (
+ id SERIAL PRIMARY KEY,
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL,
+ updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
+
+ guild_id BIGINT NOT NULL,
+ user_id TEXT NOT NULL, -- text instead of bigint for legacy compatibility
+ author_id TEXT NOT NULL,
+
+ author_username_discrim TEXT NOT NULL,
+
+ message TEXT NOT NULL,
+ logs_link TEXT
+);
+`, `
+CREATE INDEX IF NOT EXISTS idx_moderation_warnings_guild_id ON moderation_warnings(guild_id);
+`, `
+-- Similar to moderation_warnings.{created_at,updated_at}, there are a number of
+-- fields that are never null in existing data but do not have the proper NOT NULL
+-- constraints if they were created with gorm. Add them in.
+
+ALTER TABLE moderation_warnings ALTER COLUMN created_at SET NOT NULL;
+`, `
+ALTER TABLE moderation_warnings ALTER COLUMN updated_at SET NOT NULL;
+`, `
+ALTER TABLE moderation_warnings ALTER COLUMN guild_id SET NOT NULL;
+`, `
+ALTER TABLE moderation_warnings ALTER COLUMN user_id SET NOT NULL;
+`, `
+ALTER TABLE moderation_warnings ALTER COLUMN author_id SET NOT NULL;
+`, `
+ALTER TABLE moderation_warnings ALTER COLUMN author_username_discrim SET NOT NULL;
+`, `
+ALTER TABLE moderation_warnings ALTER COLUMN message SET NOT NULL;
+`, `
+
+CREATE TABLE IF NOT EXISTS muted_users (
+ id SERIAL PRIMARY KEY,
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL,
+ updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
+
+ expires_at TIMESTAMP WITH TIME ZONE,
+
+ guild_id BIGINT NOT NULL,
+ user_id BIGINT NOT NULL,
+
+ author_id BIGINT NOT NULL,
+ reason TEXT NOT NULL,
+
+ removed_roles BIGINT[]
+);
+`, `
+
+ALTER TABLE muted_users ALTER COLUMN created_at SET NOT NULL;
+`, `
+ALTER TABLE muted_users ALTER COLUMN updated_at SET NOT NULL;
+`, `
+ALTER TABLE muted_users ALTER COLUMN guild_id SET NOT NULL;
+`, `
+ALTER TABLE muted_users ALTER COLUMN user_id SET NOT NULL;
+`, `
+ALTER TABLE muted_users ALTER COLUMN author_id SET NOT NULL;
+`, `
+ALTER TABLE muted_users ALTER COLUMN reason SET NOT NULL;
+`}
diff --git a/moderation/sqlboiler.toml b/moderation/sqlboiler.toml
new file mode 100644
index 0000000000..2136666922
--- /dev/null
+++ b/moderation/sqlboiler.toml
@@ -0,0 +1,27 @@
+add-global-variants = true
+no-hooks = true
+no-tests = true
+
+[psql]
+dbname = "yagpdb"
+host = "localhost"
+user = "postgres"
+pass = "pass"
+sslmode = "disable"
+whitelist = ["moderation_configs", "moderation_warnings", "muted_users"]
+
+[auto-columns]
+created = "created_at"
+updated = "updated_at"
+
+# sqlboiler column name inference capitalizes CMD, so, for instance,
+# kick_cmd_roles becomes KickCMDRoles; manually override the names
+[aliases.tables.moderation_configs.columns]
+kick_cmd_roles = "KickCmdRoles"
+ban_cmd_roles = "BanCmdRoles"
+timeout_cmd_roles = "TimeoutCmdRoles"
+mute_cmd_roles = "MuteCmdRoles"
+warn_cmd_roles = "WarnCmdRoles"
+give_role_cmd_enabled = "GiveRoleCmdEnabled"
+give_role_cmd_modlog = "GiveRoleCmdModlog"
+give_role_cmd_roles = "GiveRoleCmdRoles"
diff --git a/moderation/tmplextensions.go b/moderation/tmplextensions.go
index fb8aa65798..df2c51aac9 100644
--- a/moderation/tmplextensions.go
+++ b/moderation/tmplextensions.go
@@ -1,13 +1,16 @@
package moderation
import (
+ "context"
+ "database/sql"
"fmt"
"time"
- "github.com/botlabs-gg/yagpdb/v2/common"
"github.com/botlabs-gg/yagpdb/v2/common/templates"
+ "github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/logs"
- "github.com/jinzhu/gorm"
+ "github.com/botlabs-gg/yagpdb/v2/moderation/models"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
)
func init() {
@@ -16,33 +19,90 @@ func init() {
})
}
+// Needed to maintain backward compatibility with previous implementation of
+// getWarnings using gorm, in which LogsLink was marked as a string instead of a
+// null.String.
+type TemplatesWarning struct {
+ ID int
+ CreatedAt time.Time
+ UpdatedAt time.Time
+
+ GuildID int64
+ UserID int64
+
+ AuthorID string
+ AuthorUsernameDiscrim string
+
+ Message string
+ LogsLink string
+}
+
+func templatesWarningFromModel(model *models.ModerationWarning) *TemplatesWarning {
+ var logsLink string
+ if model.LogsLink.Valid {
+ logsLink = model.LogsLink.String
+ }
+
+ userID, _ := discordgo.ParseID(model.UserID)
+ return &TemplatesWarning{
+ ID: model.ID,
+ CreatedAt: model.CreatedAt,
+ UpdatedAt: model.UpdatedAt,
+
+ GuildID: model.GuildID,
+ UserID: userID,
+
+ AuthorID: model.AuthorID,
+ AuthorUsernameDiscrim: model.AuthorUsernameDiscrim,
+
+ Message: model.Message,
+ LogsLink: logsLink,
+ }
+}
+
// getWarnings returns a slice of all warnings the target user has.
func tmplGetWarnings(ctx *templates.Context) interface{} {
- return func(target interface{}) ([]*WarningModel, error) {
+ return func(target interface{}) ([]*TemplatesWarning, error) {
if ctx.IncreaseCheckCallCounterPremium("cc_moderation", 5, 10) {
return nil, templates.ErrTooManyCalls
}
- gID := ctx.GS.ID
- var warns []*WarningModel
targetID := templates.TargetUserID(target)
if targetID == 0 {
return nil, fmt.Errorf("could not convert %T to a user ID", target)
}
- err := common.GORM.Where("user_id = ? AND guild_id = ?", targetID, gID).Order("id desc").Find(&warns).Error
- if err != nil && err != gorm.ErrRecordNotFound {
+ warns, err := models.ModerationWarnings(
+ models.ModerationWarningWhere.UserID.EQ(discordgo.StrID(targetID)),
+ models.ModerationWarningWhere.GuildID.EQ(ctx.GS.ID),
+
+ qm.OrderBy("id DESC"),
+ ).AllG(context.Background())
+ if err != nil && err != sql.ErrNoRows {
return nil, err
}
- // Avoid listing expired logs.
- for _, entry := range warns {
- purgedWarnLogs := logs.ConfEnableMessageLogPurge.GetBool() && entry.CreatedAt.Before(time.Now().AddDate(0, 0, -30))
- if entry.LogsLink != "" && purgedWarnLogs {
- entry.LogsLink = ""
- }
+ out := make([]*TemplatesWarning, len(warns))
+ for i, w := range warns {
+ out[i] = templatesWarningFromModel(w)
}
+ return stripExpiredLogLinks(out), nil
+ }
+}
+
+// stripExpiredLogLinks clears the LogLink field for warnings whose logs have
+// expired in-place and returns the input slice.
+func stripExpiredLogLinks(warns []*TemplatesWarning) []*TemplatesWarning {
+ if !logs.ConfEnableMessageLogPurge.GetBool() {
+ return warns
+ }
- return warns, nil
+ const logStorageDuration = 30 * 24 * time.Hour // TODO: does this constant already exist elsewhere?
+
+ for _, entry := range warns {
+ if entry.LogsLink != "" && time.Since(entry.CreatedAt) > logStorageDuration {
+ entry.LogsLink = ""
+ }
}
+ return warns
}
diff --git a/notifications/config.go b/notifications/config.go
new file mode 100644
index 0000000000..bdcbed95b3
--- /dev/null
+++ b/notifications/config.go
@@ -0,0 +1,120 @@
+package notifications
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
+ "github.com/botlabs-gg/yagpdb/v2/notifications/models"
+ "github.com/botlabs-gg/yagpdb/v2/web"
+ "github.com/volatiletech/null/v8"
+)
+
+// For legacy reasons, many columns in the database schema are marked as
+// nullable when they should really be non-nullable, meaning working with
+// models.GeneralNotificationConfig directly is much more annoying than it
+// should be. We therefore wrap it in a Config (which has proper types) and
+// convert to/from only when strictly required.
+
+type Config struct {
+ GuildID int64
+ CreatedAt time.Time
+ UpdatedAt time.Time
+
+ JoinServerEnabled bool `json:"join_server_enabled" schema:"join_server_enabled"`
+ JoinServerChannel int64 `json:"join_server_channel" schema:"join_server_channel" valid:"channel,true"`
+
+ JoinServerMsgs []string `json:"join_server_msgs" schema:"join_server_msgs" valid:"template,5000"`
+ JoinDMEnabled bool `json:"join_dm_enabled" schema:"join_dm_enabled"`
+ JoinDMMsg string `json:"join_dm_msg" schema:"join_dm_msg" valid:"template,5000"`
+
+ LeaveEnabled bool `json:"leave_enabled" schema:"leave_enabled"`
+ LeaveChannel int64 `json:"leave_channel" schema:"leave_channel" valid:"channel,true"`
+ LeaveMsgs []string `json:"leave_msgs" schema:"leave_msgs" valid:"template,5000"`
+
+ TopicEnabled bool `json:"topic_enabled" schema:"topic_enabled"`
+ TopicChannel int64 `json:"topic_channel" schema:"topic_channel" valid:"channel,true"`
+
+ CensorInvites bool `schema:"censor_invites"`
+}
+
+var _ web.CustomValidator = (*Config)(nil)
+
+const MaxResponses = 10
+
+func (c *Config) Validate(tmpl web.TemplateData, _ int64) bool {
+ if len(c.JoinServerMsgs) > MaxResponses {
+ tmpl.AddAlerts(web.ErrorAlert(fmt.Sprintf("Too many join server messages, max %d", MaxResponses)))
+ return false
+ }
+ if len(c.LeaveMsgs) > MaxResponses {
+ tmpl.AddAlerts(web.ErrorAlert(fmt.Sprintf("Too many leave server messages, max %d", MaxResponses)))
+ return false
+ }
+ return true
+}
+
+// For legacy reasons, the JoinServerMsgs and LeaveMsgs columns are not stored
+// as real TEXT[] columns in database but rather single TEXT columns separated
+// by U+001E (INFORMATION SEPARATOR TWO.)
+
+const RecordSeparator = "\x1e"
+
+func readLegacyMultiResponseColumn(s string) []string {
+ return strings.Split(s, RecordSeparator)
+}
+func writeLegacyMultiResponseColumn(responses []string) string {
+ return strings.Join(responses, RecordSeparator)
+}
+
+func (c *Config) ToModel() *models.GeneralNotificationConfig {
+ return &models.GeneralNotificationConfig{
+ GuildID: c.GuildID,
+ CreatedAt: c.CreatedAt,
+ UpdatedAt: c.UpdatedAt,
+
+ JoinServerEnabled: null.BoolFrom(c.JoinServerEnabled),
+ JoinServerChannel: null.StringFrom(discordgo.StrID(c.JoinServerChannel)),
+
+ JoinServerMsgs: null.StringFrom(writeLegacyMultiResponseColumn(c.JoinServerMsgs)),
+ JoinDMEnabled: null.BoolFrom(c.JoinDMEnabled),
+ JoinDMMsg: null.StringFrom(c.JoinDMMsg),
+
+ LeaveEnabled: null.BoolFrom(c.LeaveEnabled),
+ LeaveChannel: null.StringFrom(discordgo.StrID(c.LeaveChannel)),
+ LeaveMsgs: null.StringFrom(writeLegacyMultiResponseColumn(c.LeaveMsgs)),
+
+ TopicEnabled: null.BoolFrom(c.TopicEnabled),
+ TopicChannel: null.StringFrom(discordgo.StrID(c.TopicChannel)),
+
+ CensorInvites: null.BoolFrom(c.CensorInvites),
+ }
+}
+
+func configFromModel(model *models.GeneralNotificationConfig) *Config {
+ joinServerChannel, _ := discordgo.ParseID(model.JoinServerChannel.String)
+ leaveChannel, _ := discordgo.ParseID(model.LeaveChannel.String)
+ topicChannel, _ := discordgo.ParseID(model.TopicChannel.String)
+ return &Config{
+ GuildID: model.GuildID,
+ CreatedAt: model.CreatedAt,
+ UpdatedAt: model.UpdatedAt,
+
+ JoinServerEnabled: model.JoinServerEnabled.Bool,
+ JoinServerChannel: joinServerChannel,
+
+ JoinServerMsgs: readLegacyMultiResponseColumn(model.JoinServerMsgs.String),
+ JoinDMEnabled: model.JoinDMEnabled.Bool,
+ JoinDMMsg: model.JoinDMMsg.String,
+
+ LeaveEnabled: model.LeaveEnabled.Bool,
+ LeaveChannel: leaveChannel,
+ LeaveMsgs: readLegacyMultiResponseColumn(model.LeaveMsgs.String),
+
+ TopicEnabled: model.TopicEnabled.Bool,
+ TopicChannel: topicChannel,
+
+ CensorInvites: model.CensorInvites.Bool,
+ }
+}
diff --git a/notifications/models/boil_queries.go b/notifications/models/boil_queries.go
new file mode 100644
index 0000000000..20c2563fdb
--- /dev/null
+++ b/notifications/models/boil_queries.go
@@ -0,0 +1,38 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "regexp"
+
+ "github.com/volatiletech/sqlboiler/v4/drivers"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+)
+
+var dialect = drivers.Dialect{
+ LQ: 0x22,
+ RQ: 0x22,
+
+ UseIndexPlaceholders: true,
+ UseLastInsertID: false,
+ UseSchema: false,
+ UseDefaultKeyword: true,
+ UseAutoColumns: false,
+ UseTopClause: false,
+ UseOutputClause: false,
+ UseCaseWhenExistsClause: false,
+}
+
+// This is a dummy variable to prevent unused regexp import error
+var _ = ®exp.Regexp{}
+
+// NewQuery initializes a new Query using the passed in QueryMods
+func NewQuery(mods ...qm.QueryMod) *queries.Query {
+ q := &queries.Query{}
+ queries.SetDialect(q, &dialect)
+ qm.Apply(q, mods...)
+
+ return q
+}
diff --git a/notifications/models/boil_table_names.go b/notifications/models/boil_table_names.go
new file mode 100644
index 0000000000..f9897e9812
--- /dev/null
+++ b/notifications/models/boil_table_names.go
@@ -0,0 +1,10 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+var TableNames = struct {
+ GeneralNotificationConfigs string
+}{
+ GeneralNotificationConfigs: "general_notification_configs",
+}
diff --git a/notifications/models/boil_types.go b/notifications/models/boil_types.go
new file mode 100644
index 0000000000..02a6fdfdc5
--- /dev/null
+++ b/notifications/models/boil_types.go
@@ -0,0 +1,52 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "strconv"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/strmangle"
+)
+
+// M type is for providing columns and column values to UpdateAll.
+type M map[string]interface{}
+
+// ErrSyncFail occurs during insert when the record could not be retrieved in
+// order to populate default value information. This usually happens when LastInsertId
+// fails or there was a primary key configuration that was not resolvable.
+var ErrSyncFail = errors.New("models: failed to synchronize data after insert")
+
+type insertCache struct {
+ query string
+ retQuery string
+ valueMapping []uint64
+ retMapping []uint64
+}
+
+type updateCache struct {
+ query string
+ valueMapping []uint64
+}
+
+func makeCacheKey(cols boil.Columns, nzDefaults []string) string {
+ buf := strmangle.GetBuffer()
+
+ buf.WriteString(strconv.Itoa(cols.Kind))
+ for _, w := range cols.Cols {
+ buf.WriteString(w)
+ }
+
+ if len(nzDefaults) != 0 {
+ buf.WriteByte('.')
+ }
+ for _, nz := range nzDefaults {
+ buf.WriteString(nz)
+ }
+
+ str := buf.String()
+ strmangle.PutBuffer(buf)
+ return str
+}
diff --git a/notifications/models/boil_view_names.go b/notifications/models/boil_view_names.go
new file mode 100644
index 0000000000..01504d82bf
--- /dev/null
+++ b/notifications/models/boil_view_names.go
@@ -0,0 +1,7 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+var ViewNames = struct {
+}{}
diff --git a/notifications/models/general_notification_configs.go b/notifications/models/general_notification_configs.go
new file mode 100644
index 0000000000..15ab99d5cd
--- /dev/null
+++ b/notifications/models/general_notification_configs.go
@@ -0,0 +1,992 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/null/v8"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+ "github.com/volatiletech/sqlboiler/v4/queries/qmhelper"
+ "github.com/volatiletech/strmangle"
+)
+
+// GeneralNotificationConfig is an object representing the database table.
+type GeneralNotificationConfig struct {
+ GuildID int64 `boil:"guild_id" json:"guild_id" toml:"guild_id" yaml:"guild_id"`
+ CreatedAt time.Time `boil:"created_at" json:"created_at" toml:"created_at" yaml:"created_at"`
+ UpdatedAt time.Time `boil:"updated_at" json:"updated_at" toml:"updated_at" yaml:"updated_at"`
+ JoinServerEnabled null.Bool `boil:"join_server_enabled" json:"join_server_enabled,omitempty" toml:"join_server_enabled" yaml:"join_server_enabled,omitempty"`
+ JoinServerChannel null.String `boil:"join_server_channel" json:"join_server_channel,omitempty" toml:"join_server_channel" yaml:"join_server_channel,omitempty"`
+ JoinServerMsgs null.String `boil:"join_server_msgs" json:"join_server_msgs,omitempty" toml:"join_server_msgs" yaml:"join_server_msgs,omitempty"`
+ JoinDMEnabled null.Bool `boil:"join_dm_enabled" json:"join_dm_enabled,omitempty" toml:"join_dm_enabled" yaml:"join_dm_enabled,omitempty"`
+ JoinDMMsg null.String `boil:"join_dm_msg" json:"join_dm_msg,omitempty" toml:"join_dm_msg" yaml:"join_dm_msg,omitempty"`
+ LeaveEnabled null.Bool `boil:"leave_enabled" json:"leave_enabled,omitempty" toml:"leave_enabled" yaml:"leave_enabled,omitempty"`
+ LeaveChannel null.String `boil:"leave_channel" json:"leave_channel,omitempty" toml:"leave_channel" yaml:"leave_channel,omitempty"`
+ LeaveMsgs null.String `boil:"leave_msgs" json:"leave_msgs,omitempty" toml:"leave_msgs" yaml:"leave_msgs,omitempty"`
+ TopicEnabled null.Bool `boil:"topic_enabled" json:"topic_enabled,omitempty" toml:"topic_enabled" yaml:"topic_enabled,omitempty"`
+ TopicChannel null.String `boil:"topic_channel" json:"topic_channel,omitempty" toml:"topic_channel" yaml:"topic_channel,omitempty"`
+ CensorInvites null.Bool `boil:"censor_invites" json:"censor_invites,omitempty" toml:"censor_invites" yaml:"censor_invites,omitempty"`
+
+ R *generalNotificationConfigR `boil:"-" json:"-" toml:"-" yaml:"-"`
+ L generalNotificationConfigL `boil:"-" json:"-" toml:"-" yaml:"-"`
+}
+
+var GeneralNotificationConfigColumns = struct {
+ GuildID string
+ CreatedAt string
+ UpdatedAt string
+ JoinServerEnabled string
+ JoinServerChannel string
+ JoinServerMsgs string
+ JoinDMEnabled string
+ JoinDMMsg string
+ LeaveEnabled string
+ LeaveChannel string
+ LeaveMsgs string
+ TopicEnabled string
+ TopicChannel string
+ CensorInvites string
+}{
+ GuildID: "guild_id",
+ CreatedAt: "created_at",
+ UpdatedAt: "updated_at",
+ JoinServerEnabled: "join_server_enabled",
+ JoinServerChannel: "join_server_channel",
+ JoinServerMsgs: "join_server_msgs",
+ JoinDMEnabled: "join_dm_enabled",
+ JoinDMMsg: "join_dm_msg",
+ LeaveEnabled: "leave_enabled",
+ LeaveChannel: "leave_channel",
+ LeaveMsgs: "leave_msgs",
+ TopicEnabled: "topic_enabled",
+ TopicChannel: "topic_channel",
+ CensorInvites: "censor_invites",
+}
+
+var GeneralNotificationConfigTableColumns = struct {
+ GuildID string
+ CreatedAt string
+ UpdatedAt string
+ JoinServerEnabled string
+ JoinServerChannel string
+ JoinServerMsgs string
+ JoinDMEnabled string
+ JoinDMMsg string
+ LeaveEnabled string
+ LeaveChannel string
+ LeaveMsgs string
+ TopicEnabled string
+ TopicChannel string
+ CensorInvites string
+}{
+ GuildID: "general_notification_configs.guild_id",
+ CreatedAt: "general_notification_configs.created_at",
+ UpdatedAt: "general_notification_configs.updated_at",
+ JoinServerEnabled: "general_notification_configs.join_server_enabled",
+ JoinServerChannel: "general_notification_configs.join_server_channel",
+ JoinServerMsgs: "general_notification_configs.join_server_msgs",
+ JoinDMEnabled: "general_notification_configs.join_dm_enabled",
+ JoinDMMsg: "general_notification_configs.join_dm_msg",
+ LeaveEnabled: "general_notification_configs.leave_enabled",
+ LeaveChannel: "general_notification_configs.leave_channel",
+ LeaveMsgs: "general_notification_configs.leave_msgs",
+ TopicEnabled: "general_notification_configs.topic_enabled",
+ TopicChannel: "general_notification_configs.topic_channel",
+ CensorInvites: "general_notification_configs.censor_invites",
+}
+
+// Generated where
+
+type whereHelperint64 struct{ field string }
+
+func (w whereHelperint64) EQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperint64) NEQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperint64) LT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperint64) LTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperint64) GT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperint64) GTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperint64) IN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperint64) NIN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+type whereHelpertime_Time struct{ field string }
+
+func (w whereHelpertime_Time) EQ(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.EQ, x)
+}
+func (w whereHelpertime_Time) NEQ(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.NEQ, x)
+}
+func (w whereHelpertime_Time) LT(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpertime_Time) LTE(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpertime_Time) GT(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpertime_Time) GTE(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+type whereHelpernull_Bool struct{ field string }
+
+func (w whereHelpernull_Bool) EQ(x null.Bool) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpernull_Bool) NEQ(x null.Bool) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpernull_Bool) LT(x null.Bool) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpernull_Bool) LTE(x null.Bool) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpernull_Bool) GT(x null.Bool) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpernull_Bool) GTE(x null.Bool) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+func (w whereHelpernull_Bool) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpernull_Bool) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+type whereHelpernull_String struct{ field string }
+
+func (w whereHelpernull_String) EQ(x null.String) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpernull_String) NEQ(x null.String) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpernull_String) LT(x null.String) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpernull_String) LTE(x null.String) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpernull_String) GT(x null.String) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpernull_String) GTE(x null.String) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+func (w whereHelpernull_String) LIKE(x null.String) qm.QueryMod {
+ return qm.Where(w.field+" LIKE ?", x)
+}
+func (w whereHelpernull_String) NLIKE(x null.String) qm.QueryMod {
+ return qm.Where(w.field+" NOT LIKE ?", x)
+}
+func (w whereHelpernull_String) ILIKE(x null.String) qm.QueryMod {
+ return qm.Where(w.field+" ILIKE ?", x)
+}
+func (w whereHelpernull_String) NILIKE(x null.String) qm.QueryMod {
+ return qm.Where(w.field+" NOT ILIKE ?", x)
+}
+func (w whereHelpernull_String) IN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelpernull_String) NIN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+func (w whereHelpernull_String) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpernull_String) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+var GeneralNotificationConfigWhere = struct {
+ GuildID whereHelperint64
+ CreatedAt whereHelpertime_Time
+ UpdatedAt whereHelpertime_Time
+ JoinServerEnabled whereHelpernull_Bool
+ JoinServerChannel whereHelpernull_String
+ JoinServerMsgs whereHelpernull_String
+ JoinDMEnabled whereHelpernull_Bool
+ JoinDMMsg whereHelpernull_String
+ LeaveEnabled whereHelpernull_Bool
+ LeaveChannel whereHelpernull_String
+ LeaveMsgs whereHelpernull_String
+ TopicEnabled whereHelpernull_Bool
+ TopicChannel whereHelpernull_String
+ CensorInvites whereHelpernull_Bool
+}{
+ GuildID: whereHelperint64{field: "\"general_notification_configs\".\"guild_id\""},
+ CreatedAt: whereHelpertime_Time{field: "\"general_notification_configs\".\"created_at\""},
+ UpdatedAt: whereHelpertime_Time{field: "\"general_notification_configs\".\"updated_at\""},
+ JoinServerEnabled: whereHelpernull_Bool{field: "\"general_notification_configs\".\"join_server_enabled\""},
+ JoinServerChannel: whereHelpernull_String{field: "\"general_notification_configs\".\"join_server_channel\""},
+ JoinServerMsgs: whereHelpernull_String{field: "\"general_notification_configs\".\"join_server_msgs\""},
+ JoinDMEnabled: whereHelpernull_Bool{field: "\"general_notification_configs\".\"join_dm_enabled\""},
+ JoinDMMsg: whereHelpernull_String{field: "\"general_notification_configs\".\"join_dm_msg\""},
+ LeaveEnabled: whereHelpernull_Bool{field: "\"general_notification_configs\".\"leave_enabled\""},
+ LeaveChannel: whereHelpernull_String{field: "\"general_notification_configs\".\"leave_channel\""},
+ LeaveMsgs: whereHelpernull_String{field: "\"general_notification_configs\".\"leave_msgs\""},
+ TopicEnabled: whereHelpernull_Bool{field: "\"general_notification_configs\".\"topic_enabled\""},
+ TopicChannel: whereHelpernull_String{field: "\"general_notification_configs\".\"topic_channel\""},
+ CensorInvites: whereHelpernull_Bool{field: "\"general_notification_configs\".\"censor_invites\""},
+}
+
+// GeneralNotificationConfigRels is where relationship names are stored.
+var GeneralNotificationConfigRels = struct {
+}{}
+
+// generalNotificationConfigR is where relationships are stored.
+type generalNotificationConfigR struct {
+}
+
+// NewStruct creates a new relationship struct
+func (*generalNotificationConfigR) NewStruct() *generalNotificationConfigR {
+ return &generalNotificationConfigR{}
+}
+
+// generalNotificationConfigL is where Load methods for each relationship are stored.
+type generalNotificationConfigL struct{}
+
+var (
+ generalNotificationConfigAllColumns = []string{"guild_id", "created_at", "updated_at", "join_server_enabled", "join_server_channel", "join_server_msgs", "join_dm_enabled", "join_dm_msg", "leave_enabled", "leave_channel", "leave_msgs", "topic_enabled", "topic_channel", "censor_invites"}
+ generalNotificationConfigColumnsWithoutDefault = []string{"guild_id", "created_at", "updated_at"}
+ generalNotificationConfigColumnsWithDefault = []string{"join_server_enabled", "join_server_channel", "join_server_msgs", "join_dm_enabled", "join_dm_msg", "leave_enabled", "leave_channel", "leave_msgs", "topic_enabled", "topic_channel", "censor_invites"}
+ generalNotificationConfigPrimaryKeyColumns = []string{"guild_id"}
+ generalNotificationConfigGeneratedColumns = []string{}
+)
+
+type (
+ // GeneralNotificationConfigSlice is an alias for a slice of pointers to GeneralNotificationConfig.
+ // This should almost always be used instead of []GeneralNotificationConfig.
+ GeneralNotificationConfigSlice []*GeneralNotificationConfig
+
+ generalNotificationConfigQuery struct {
+ *queries.Query
+ }
+)
+
+// Cache for insert, update and upsert
+var (
+ generalNotificationConfigType = reflect.TypeOf(&GeneralNotificationConfig{})
+ generalNotificationConfigMapping = queries.MakeStructMapping(generalNotificationConfigType)
+ generalNotificationConfigPrimaryKeyMapping, _ = queries.BindMapping(generalNotificationConfigType, generalNotificationConfigMapping, generalNotificationConfigPrimaryKeyColumns)
+ generalNotificationConfigInsertCacheMut sync.RWMutex
+ generalNotificationConfigInsertCache = make(map[string]insertCache)
+ generalNotificationConfigUpdateCacheMut sync.RWMutex
+ generalNotificationConfigUpdateCache = make(map[string]updateCache)
+ generalNotificationConfigUpsertCacheMut sync.RWMutex
+ generalNotificationConfigUpsertCache = make(map[string]insertCache)
+)
+
+var (
+ // Force time package dependency for automated UpdatedAt/CreatedAt.
+ _ = time.Second
+ // Force qmhelper dependency for where clause generation (which doesn't
+ // always happen)
+ _ = qmhelper.Where
+)
+
+// OneG returns a single generalNotificationConfig record from the query using the global executor.
+func (q generalNotificationConfigQuery) OneG(ctx context.Context) (*GeneralNotificationConfig, error) {
+ return q.One(ctx, boil.GetContextDB())
+}
+
+// One returns a single generalNotificationConfig record from the query.
+func (q generalNotificationConfigQuery) One(ctx context.Context, exec boil.ContextExecutor) (*GeneralNotificationConfig, error) {
+ o := &GeneralNotificationConfig{}
+
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Bind(ctx, exec, o)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: failed to execute a one query for general_notification_configs")
+ }
+
+ return o, nil
+}
+
+// AllG returns all GeneralNotificationConfig records from the query using the global executor.
+func (q generalNotificationConfigQuery) AllG(ctx context.Context) (GeneralNotificationConfigSlice, error) {
+ return q.All(ctx, boil.GetContextDB())
+}
+
+// All returns all GeneralNotificationConfig records from the query.
+func (q generalNotificationConfigQuery) All(ctx context.Context, exec boil.ContextExecutor) (GeneralNotificationConfigSlice, error) {
+ var o []*GeneralNotificationConfig
+
+ err := q.Bind(ctx, exec, &o)
+ if err != nil {
+ return nil, errors.Wrap(err, "models: failed to assign all query results to GeneralNotificationConfig slice")
+ }
+
+ return o, nil
+}
+
+// CountG returns the count of all GeneralNotificationConfig records in the query using the global executor
+func (q generalNotificationConfigQuery) CountG(ctx context.Context) (int64, error) {
+ return q.Count(ctx, boil.GetContextDB())
+}
+
+// Count returns the count of all GeneralNotificationConfig records in the query.
+func (q generalNotificationConfigQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to count general_notification_configs rows")
+ }
+
+ return count, nil
+}
+
+// ExistsG checks if the row exists in the table using the global executor.
+func (q generalNotificationConfigQuery) ExistsG(ctx context.Context) (bool, error) {
+ return q.Exists(ctx, boil.GetContextDB())
+}
+
+// Exists checks if the row exists in the table.
+func (q generalNotificationConfigQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return false, errors.Wrap(err, "models: failed to check if general_notification_configs exists")
+ }
+
+ return count > 0, nil
+}
+
+// GeneralNotificationConfigs retrieves all the records using an executor.
+func GeneralNotificationConfigs(mods ...qm.QueryMod) generalNotificationConfigQuery {
+ mods = append(mods, qm.From("\"general_notification_configs\""))
+ q := NewQuery(mods...)
+ if len(queries.GetSelect(q)) == 0 {
+ queries.SetSelect(q, []string{"\"general_notification_configs\".*"})
+ }
+
+ return generalNotificationConfigQuery{q}
+}
+
+// FindGeneralNotificationConfigG retrieves a single record by ID.
+func FindGeneralNotificationConfigG(ctx context.Context, guildID int64, selectCols ...string) (*GeneralNotificationConfig, error) {
+ return FindGeneralNotificationConfig(ctx, boil.GetContextDB(), guildID, selectCols...)
+}
+
+// FindGeneralNotificationConfig retrieves a single record by ID with an executor.
+// If selectCols is empty Find will return all columns.
+func FindGeneralNotificationConfig(ctx context.Context, exec boil.ContextExecutor, guildID int64, selectCols ...string) (*GeneralNotificationConfig, error) {
+ generalNotificationConfigObj := &GeneralNotificationConfig{}
+
+ sel := "*"
+ if len(selectCols) > 0 {
+ sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",")
+ }
+ query := fmt.Sprintf(
+ "select %s from \"general_notification_configs\" where \"guild_id\"=$1", sel,
+ )
+
+ q := queries.Raw(query, guildID)
+
+ err := q.Bind(ctx, exec, generalNotificationConfigObj)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: unable to select from general_notification_configs")
+ }
+
+ return generalNotificationConfigObj, nil
+}
+
+// InsertG a single record. See Insert for whitelist behavior description.
+func (o *GeneralNotificationConfig) InsertG(ctx context.Context, columns boil.Columns) error {
+ return o.Insert(ctx, boil.GetContextDB(), columns)
+}
+
+// Insert a single record using an executor.
+// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts.
+func (o *GeneralNotificationConfig) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error {
+ if o == nil {
+ return errors.New("models: no general_notification_configs provided for insertion")
+ }
+
+ var err error
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ if o.UpdatedAt.IsZero() {
+ o.UpdatedAt = currTime
+ }
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(generalNotificationConfigColumnsWithDefault, o)
+
+ key := makeCacheKey(columns, nzDefaults)
+ generalNotificationConfigInsertCacheMut.RLock()
+ cache, cached := generalNotificationConfigInsertCache[key]
+ generalNotificationConfigInsertCacheMut.RUnlock()
+
+ if !cached {
+ wl, returnColumns := columns.InsertColumnSet(
+ generalNotificationConfigAllColumns,
+ generalNotificationConfigColumnsWithDefault,
+ generalNotificationConfigColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ cache.valueMapping, err = queries.BindMapping(generalNotificationConfigType, generalNotificationConfigMapping, wl)
+ if err != nil {
+ return err
+ }
+ cache.retMapping, err = queries.BindMapping(generalNotificationConfigType, generalNotificationConfigMapping, returnColumns)
+ if err != nil {
+ return err
+ }
+ if len(wl) != 0 {
+ cache.query = fmt.Sprintf("INSERT INTO \"general_notification_configs\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1))
+ } else {
+ cache.query = "INSERT INTO \"general_notification_configs\" %sDEFAULT VALUES%s"
+ }
+
+ var queryOutput, queryReturning string
+
+ if len(cache.retMapping) != 0 {
+ queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\""))
+ }
+
+ cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+
+ if err != nil {
+ return errors.Wrap(err, "models: unable to insert into general_notification_configs")
+ }
+
+ if !cached {
+ generalNotificationConfigInsertCacheMut.Lock()
+ generalNotificationConfigInsertCache[key] = cache
+ generalNotificationConfigInsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// UpdateG a single GeneralNotificationConfig record using the global executor.
+// See Update for more documentation.
+func (o *GeneralNotificationConfig) UpdateG(ctx context.Context, columns boil.Columns) (int64, error) {
+ return o.Update(ctx, boil.GetContextDB(), columns)
+}
+
+// Update uses an executor to update the GeneralNotificationConfig.
+// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates.
+// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records.
+func (o *GeneralNotificationConfig) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) {
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ o.UpdatedAt = currTime
+ }
+
+ var err error
+ key := makeCacheKey(columns, nil)
+ generalNotificationConfigUpdateCacheMut.RLock()
+ cache, cached := generalNotificationConfigUpdateCache[key]
+ generalNotificationConfigUpdateCacheMut.RUnlock()
+
+ if !cached {
+ wl := columns.UpdateColumnSet(
+ generalNotificationConfigAllColumns,
+ generalNotificationConfigPrimaryKeyColumns,
+ )
+
+ if !columns.IsWhitelist() {
+ wl = strmangle.SetComplement(wl, []string{"created_at"})
+ }
+ if len(wl) == 0 {
+ return 0, errors.New("models: unable to update general_notification_configs, could not build whitelist")
+ }
+
+ cache.query = fmt.Sprintf("UPDATE \"general_notification_configs\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ strmangle.WhereClause("\"", "\"", len(wl)+1, generalNotificationConfigPrimaryKeyColumns),
+ )
+ cache.valueMapping, err = queries.BindMapping(generalNotificationConfigType, generalNotificationConfigMapping, append(wl, generalNotificationConfigPrimaryKeyColumns...))
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, values)
+ }
+ var result sql.Result
+ result, err = exec.ExecContext(ctx, cache.query, values...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update general_notification_configs row")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by update for general_notification_configs")
+ }
+
+ if !cached {
+ generalNotificationConfigUpdateCacheMut.Lock()
+ generalNotificationConfigUpdateCache[key] = cache
+ generalNotificationConfigUpdateCacheMut.Unlock()
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (q generalNotificationConfigQuery) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return q.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values.
+func (q generalNotificationConfigQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ queries.SetUpdate(q.Query, cols)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all for general_notification_configs")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected for general_notification_configs")
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (o GeneralNotificationConfigSlice) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return o.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values, using an executor.
+func (o GeneralNotificationConfigSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ ln := int64(len(o))
+ if ln == 0 {
+ return 0, nil
+ }
+
+ if len(cols) == 0 {
+ return 0, errors.New("models: update all requires at least one column argument")
+ }
+
+ colNames := make([]string, len(cols))
+ args := make([]interface{}, len(cols))
+
+ i := 0
+ for name, value := range cols {
+ colNames[i] = name
+ args[i] = value
+ i++
+ }
+
+ // Append all of the primary key values for each column
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), generalNotificationConfigPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := fmt.Sprintf("UPDATE \"general_notification_configs\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, colNames),
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, generalNotificationConfigPrimaryKeyColumns, len(o)))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all in generalNotificationConfig slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all generalNotificationConfig")
+ }
+ return rowsAff, nil
+}
+
+// UpsertG attempts an insert, and does an update or ignore on conflict.
+func (o *GeneralNotificationConfig) UpsertG(ctx context.Context, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ return o.Upsert(ctx, boil.GetContextDB(), updateOnConflict, conflictColumns, updateColumns, insertColumns, opts...)
+}
+
+// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
+// See boil.Columns documentation for how to properly use updateColumns and insertColumns.
+func (o *GeneralNotificationConfig) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ if o == nil {
+ return errors.New("models: no general_notification_configs provided for upsert")
+ }
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ o.UpdatedAt = currTime
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(generalNotificationConfigColumnsWithDefault, o)
+
+ // Build cache key in-line uglily - mysql vs psql problems
+ buf := strmangle.GetBuffer()
+ if updateOnConflict {
+ buf.WriteByte('t')
+ } else {
+ buf.WriteByte('f')
+ }
+ buf.WriteByte('.')
+ for _, c := range conflictColumns {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(updateColumns.Kind))
+ for _, c := range updateColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(insertColumns.Kind))
+ for _, c := range insertColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ for _, c := range nzDefaults {
+ buf.WriteString(c)
+ }
+ key := buf.String()
+ strmangle.PutBuffer(buf)
+
+ generalNotificationConfigUpsertCacheMut.RLock()
+ cache, cached := generalNotificationConfigUpsertCache[key]
+ generalNotificationConfigUpsertCacheMut.RUnlock()
+
+ var err error
+
+ if !cached {
+ insert, _ := insertColumns.InsertColumnSet(
+ generalNotificationConfigAllColumns,
+ generalNotificationConfigColumnsWithDefault,
+ generalNotificationConfigColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ update := updateColumns.UpdateColumnSet(
+ generalNotificationConfigAllColumns,
+ generalNotificationConfigPrimaryKeyColumns,
+ )
+
+ if updateOnConflict && len(update) == 0 {
+ return errors.New("models: unable to upsert general_notification_configs, could not build update column list")
+ }
+
+ ret := strmangle.SetComplement(generalNotificationConfigAllColumns, strmangle.SetIntersect(insert, update))
+
+ conflict := conflictColumns
+ if len(conflict) == 0 && updateOnConflict && len(update) != 0 {
+ if len(generalNotificationConfigPrimaryKeyColumns) == 0 {
+ return errors.New("models: unable to upsert general_notification_configs, could not build conflict column list")
+ }
+
+ conflict = make([]string, len(generalNotificationConfigPrimaryKeyColumns))
+ copy(conflict, generalNotificationConfigPrimaryKeyColumns)
+ }
+ cache.query = buildUpsertQueryPostgres(dialect, "\"general_notification_configs\"", updateOnConflict, ret, update, conflict, insert, opts...)
+
+ cache.valueMapping, err = queries.BindMapping(generalNotificationConfigType, generalNotificationConfigMapping, insert)
+ if err != nil {
+ return err
+ }
+ if len(ret) != 0 {
+ cache.retMapping, err = queries.BindMapping(generalNotificationConfigType, generalNotificationConfigMapping, ret)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+ var returns []interface{}
+ if len(cache.retMapping) != 0 {
+ returns = queries.PtrsFromMapping(value, cache.retMapping)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...)
+ if errors.Is(err, sql.ErrNoRows) {
+ err = nil // Postgres doesn't return anything when there's no update
+ }
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+ if err != nil {
+ return errors.Wrap(err, "models: unable to upsert general_notification_configs")
+ }
+
+ if !cached {
+ generalNotificationConfigUpsertCacheMut.Lock()
+ generalNotificationConfigUpsertCache[key] = cache
+ generalNotificationConfigUpsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// DeleteG deletes a single GeneralNotificationConfig record.
+// DeleteG will match against the primary key column to find the record to delete.
+func (o *GeneralNotificationConfig) DeleteG(ctx context.Context) (int64, error) {
+ return o.Delete(ctx, boil.GetContextDB())
+}
+
+// Delete deletes a single GeneralNotificationConfig record with an executor.
+// Delete will match against the primary key column to find the record to delete.
+func (o *GeneralNotificationConfig) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if o == nil {
+ return 0, errors.New("models: no GeneralNotificationConfig provided for delete")
+ }
+
+ args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), generalNotificationConfigPrimaryKeyMapping)
+ sql := "DELETE FROM \"general_notification_configs\" WHERE \"guild_id\"=$1"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete from general_notification_configs")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by delete for general_notification_configs")
+ }
+
+ return rowsAff, nil
+}
+
+func (q generalNotificationConfigQuery) DeleteAllG(ctx context.Context) (int64, error) {
+ return q.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all matching rows.
+func (q generalNotificationConfigQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if q.Query == nil {
+ return 0, errors.New("models: no generalNotificationConfigQuery provided for delete all")
+ }
+
+ queries.SetDelete(q.Query)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from general_notification_configs")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for general_notification_configs")
+ }
+
+ return rowsAff, nil
+}
+
+// DeleteAllG deletes all rows in the slice.
+func (o GeneralNotificationConfigSlice) DeleteAllG(ctx context.Context) (int64, error) {
+ return o.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all rows in the slice, using an executor.
+func (o GeneralNotificationConfigSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if len(o) == 0 {
+ return 0, nil
+ }
+
+ var args []interface{}
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), generalNotificationConfigPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "DELETE FROM \"general_notification_configs\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, generalNotificationConfigPrimaryKeyColumns, len(o))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from generalNotificationConfig slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for general_notification_configs")
+ }
+
+ return rowsAff, nil
+}
+
+// ReloadG refetches the object from the database using the primary keys.
+func (o *GeneralNotificationConfig) ReloadG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: no GeneralNotificationConfig provided for reload")
+ }
+
+ return o.Reload(ctx, boil.GetContextDB())
+}
+
+// Reload refetches the object from the database
+// using the primary keys with an executor.
+func (o *GeneralNotificationConfig) Reload(ctx context.Context, exec boil.ContextExecutor) error {
+ ret, err := FindGeneralNotificationConfig(ctx, exec, o.GuildID)
+ if err != nil {
+ return err
+ }
+
+ *o = *ret
+ return nil
+}
+
+// ReloadAllG refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *GeneralNotificationConfigSlice) ReloadAllG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: empty GeneralNotificationConfigSlice provided for reload all")
+ }
+
+ return o.ReloadAll(ctx, boil.GetContextDB())
+}
+
+// ReloadAll refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *GeneralNotificationConfigSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error {
+ if o == nil || len(*o) == 0 {
+ return nil
+ }
+
+ slice := GeneralNotificationConfigSlice{}
+ var args []interface{}
+ for _, obj := range *o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), generalNotificationConfigPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "SELECT \"general_notification_configs\".* FROM \"general_notification_configs\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, generalNotificationConfigPrimaryKeyColumns, len(*o))
+
+ q := queries.Raw(sql, args...)
+
+ err := q.Bind(ctx, exec, &slice)
+ if err != nil {
+ return errors.Wrap(err, "models: unable to reload all in GeneralNotificationConfigSlice")
+ }
+
+ *o = slice
+
+ return nil
+}
+
+// GeneralNotificationConfigExistsG checks if the GeneralNotificationConfig row exists.
+func GeneralNotificationConfigExistsG(ctx context.Context, guildID int64) (bool, error) {
+ return GeneralNotificationConfigExists(ctx, boil.GetContextDB(), guildID)
+}
+
+// GeneralNotificationConfigExists checks if the GeneralNotificationConfig row exists.
+func GeneralNotificationConfigExists(ctx context.Context, exec boil.ContextExecutor, guildID int64) (bool, error) {
+ var exists bool
+ sql := "select exists(select 1 from \"general_notification_configs\" where \"guild_id\"=$1 limit 1)"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, guildID)
+ }
+ row := exec.QueryRowContext(ctx, sql, guildID)
+
+ err := row.Scan(&exists)
+ if err != nil {
+ return false, errors.Wrap(err, "models: unable to check if general_notification_configs exists")
+ }
+
+ return exists, nil
+}
+
+// Exists checks if the GeneralNotificationConfig row exists.
+func (o *GeneralNotificationConfig) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ return GeneralNotificationConfigExists(ctx, exec, o.GuildID)
+}
diff --git a/notifications/models/psql_upsert.go b/notifications/models/psql_upsert.go
new file mode 100644
index 0000000000..07602da9c5
--- /dev/null
+++ b/notifications/models/psql_upsert.go
@@ -0,0 +1,99 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/volatiletech/sqlboiler/v4/drivers"
+ "github.com/volatiletech/strmangle"
+)
+
+type UpsertOptions struct {
+ conflictTarget string
+ updateSet string
+}
+
+type UpsertOptionFunc func(o *UpsertOptions)
+
+func UpsertConflictTarget(conflictTarget string) UpsertOptionFunc {
+ return func(o *UpsertOptions) {
+ o.conflictTarget = conflictTarget
+ }
+}
+
+func UpsertUpdateSet(updateSet string) UpsertOptionFunc {
+ return func(o *UpsertOptions) {
+ o.updateSet = updateSet
+ }
+}
+
+// buildUpsertQueryPostgres builds a SQL statement string using the upsertData provided.
+func buildUpsertQueryPostgres(dia drivers.Dialect, tableName string, updateOnConflict bool, ret, update, conflict, whitelist []string, opts ...UpsertOptionFunc) string {
+ conflict = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, conflict)
+ whitelist = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, whitelist)
+ ret = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, ret)
+
+ upsertOpts := &UpsertOptions{}
+ for _, o := range opts {
+ o(upsertOpts)
+ }
+
+ buf := strmangle.GetBuffer()
+ defer strmangle.PutBuffer(buf)
+
+ columns := "DEFAULT VALUES"
+ if len(whitelist) != 0 {
+ columns = fmt.Sprintf("(%s) VALUES (%s)",
+ strings.Join(whitelist, ", "),
+ strmangle.Placeholders(dia.UseIndexPlaceholders, len(whitelist), 1, 1))
+ }
+
+ fmt.Fprintf(
+ buf,
+ "INSERT INTO %s %s ON CONFLICT ",
+ tableName,
+ columns,
+ )
+
+ if upsertOpts.conflictTarget != "" {
+ buf.WriteString(upsertOpts.conflictTarget)
+ } else if len(conflict) != 0 {
+ buf.WriteByte('(')
+ buf.WriteString(strings.Join(conflict, ", "))
+ buf.WriteByte(')')
+ }
+ buf.WriteByte(' ')
+
+ if !updateOnConflict || len(update) == 0 {
+ buf.WriteString("DO NOTHING")
+ } else {
+ buf.WriteString("DO UPDATE SET ")
+
+ if upsertOpts.updateSet != "" {
+ buf.WriteString(upsertOpts.updateSet)
+ } else {
+ for i, v := range update {
+ if len(v) == 0 {
+ continue
+ }
+ if i != 0 {
+ buf.WriteByte(',')
+ }
+ quoted := strmangle.IdentQuote(dia.LQ, dia.RQ, v)
+ buf.WriteString(quoted)
+ buf.WriteString(" = EXCLUDED.")
+ buf.WriteString(quoted)
+ }
+ }
+ }
+
+ if len(ret) != 0 {
+ buf.WriteString(" RETURNING ")
+ buf.WriteString(strings.Join(ret, ", "))
+ }
+
+ return buf.String()
+}
diff --git a/notifications/notifications.go b/notifications/notifications.go
index 097427849f..963197c63b 100644
--- a/notifications/notifications.go
+++ b/notifications/notifications.go
@@ -1,19 +1,10 @@
package notifications
import (
- "strconv"
- "strings"
-
- "emperror.dev/errors"
"github.com/botlabs-gg/yagpdb/v2/common"
- "github.com/botlabs-gg/yagpdb/v2/common/configstore"
- "golang.org/x/net/context"
)
-const (
- RecordSeparator = "\x1e"
- MaxUserMessages = 10
-)
+//go:generate sqlboiler --no-hooks psql
var logger = common.GetPluginLogger(&Plugin{})
@@ -23,9 +14,7 @@ func RegisterPlugin() {
plugin := &Plugin{}
common.RegisterPlugin(plugin)
- common.GORM.AutoMigrate(&Config{})
- configstore.RegisterConfig(configstore.SQL, &Config{})
-
+ common.InitSchemas("notifications", DBSchemas...)
}
func (p *Plugin) PluginInfo() *common.PluginInfo {
@@ -35,133 +24,3 @@ func (p *Plugin) PluginInfo() *common.PluginInfo {
Category: common.PluginCategoryFeeds,
}
}
-
-type Config struct {
- configstore.GuildConfigModel
- JoinServerEnabled bool `json:"join_server_enabled" schema:"join_server_enabled"`
- JoinServerChannel string `json:"join_server_channel" schema:"join_server_channel" valid:"channel,true"`
-
- // Implementation note: gorilla/schema currently requires manual index
- // setting in forms to parse sub-objects. GORM has_many is also complicated
- // by manual handling of associations and loss of IDs through the web form
- // (without which Replace() is currently n^2).
- // For strings, we greatly simplify things by flattening for storage.
-
- // TODO: Remove the legacy single-message variant when ready to migrate the
- // database.
- JoinServerMsg string `json:"join_server_msg" valid:"template,5000"`
- JoinServerMsgs []string `json:"join_server_msgs" schema:"join_server_msgs" gorm:"-" valid:"template,5000"`
- // Do Not Use! For persistence only.
- JoinServerMsgs_ string `json:"-"`
-
- JoinDMEnabled bool `json:"join_dm_enabled" schema:"join_dm_enabled"`
- JoinDMMsg string `json:"join_dm_msg" schema:"join_dm_msg" valid:"template,5000"`
-
- LeaveEnabled bool `json:"leave_enabled" schema:"leave_enabled"`
- LeaveChannel string `json:"leave_channel" schema:"leave_channel" valid:"channel,true"`
- LeaveMsg string `json:"leave_msg" schema:"leave_msg" valid:"template,5000"`
- LeaveMsgs []string `json:"leave_msgs" schema:"leave_msgs" gorm:"-" valid:"template,5000"`
- // Do Not Use! For persistence only.
- LeaveMsgs_ string `json:"-"`
-
- TopicEnabled bool `json:"topic_enabled" schema:"topic_enabled"`
- TopicChannel string `json:"topic_channel" schema:"topic_channel" valid:"channel,true"`
-
- CensorInvites bool `schema:"censor_invites"`
-}
-
-func (c *Config) JoinServerChannelInt() (i int64) {
- i, _ = strconv.ParseInt(c.JoinServerChannel, 10, 64)
- return
-}
-
-func (c *Config) LeaveChannelInt() (i int64) {
- i, _ = strconv.ParseInt(c.LeaveChannel, 10, 64)
- return
-}
-
-func (c *Config) TopicChannelInt() (i int64) {
- i, _ = strconv.ParseInt(c.TopicChannel, 10, 64)
- return
-}
-
-func (c *Config) GetName() string {
- return "general_notifications"
-}
-
-func (c *Config) TableName() string {
- return "general_notification_configs"
-}
-
-// GORM BeforeSave hook
-func (c *Config) BeforeSave() (err error) {
- filterAndJoin := func(a []string) string {
- joined := ""
- msgsJoined := 0
- for _, s := range a {
- if s == "" {
- continue
- }
- if msgsJoined >= MaxUserMessages {
- break
- }
- msgsJoined++
-
- if len(joined) > 0 {
- joined += RecordSeparator
- }
-
- joined += s
- }
-
- return joined
- }
-
- c.JoinServerMsgs_ = filterAndJoin(c.JoinServerMsgs)
- c.LeaveMsgs_ = filterAndJoin(c.LeaveMsgs)
-
- return nil
-}
-
-// GORM AfterFind hook
-func (c *Config) AfterFind() (err error) {
- if c.JoinServerMsg != "" {
- c.JoinServerMsgs = append(c.JoinServerMsgs, c.JoinServerMsg)
- c.JoinServerMsg = ""
- }
- if c.JoinServerMsgs_ != "" {
- c.JoinServerMsgs = append(c.JoinServerMsgs, strings.Split(c.JoinServerMsgs_, RecordSeparator)...)
- }
-
- if c.LeaveMsg != "" {
- c.LeaveMsgs = append(c.LeaveMsgs, c.LeaveMsg)
- c.LeaveMsg = ""
- }
- if c.LeaveMsgs_ != "" {
- c.LeaveMsgs = append(c.LeaveMsgs, strings.Split(c.LeaveMsgs_, RecordSeparator)...)
- }
-
- return nil
-}
-
-var DefaultConfig = &Config{}
-
-func GetConfig(guildID int64) (*Config, error) {
- var conf Config
- err := configstore.Cached.GetGuildConfig(context.Background(), guildID, &conf)
- if err == nil {
- return &conf, nil
- }
-
- if err == configstore.ErrNotFound {
- // if err != configstore.ErrNotFound {
- // log.WithError(err).Error("Failed retrieving config")
- // }
- return &Config{
- JoinServerMsgs: []string{"<@{{.User.ID}}> Joined!"},
- LeaveMsgs: []string{"**{{.User.Username}}** Left... :'("},
- }, nil
- }
-
- return nil, errors.WithStackIf(err)
-}
diff --git a/notifications/plugin_bot.go b/notifications/plugin_bot.go
index 80422d57fc..62f0f36395 100644
--- a/notifications/plugin_bot.go
+++ b/notifications/plugin_bot.go
@@ -1,18 +1,25 @@
package notifications
import (
+ "context"
+ "database/sql"
"fmt"
"math/rand"
"strings"
+ "time"
"emperror.dev/errors"
"github.com/botlabs-gg/yagpdb/v2/analytics"
"github.com/botlabs-gg/yagpdb/v2/bot"
"github.com/botlabs-gg/yagpdb/v2/bot/eventsystem"
"github.com/botlabs-gg/yagpdb/v2/common"
+ "github.com/botlabs-gg/yagpdb/v2/common/pubsub"
"github.com/botlabs-gg/yagpdb/v2/common/templates"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/lib/dstate"
+ "github.com/botlabs-gg/yagpdb/v2/notifications/models"
+ "github.com/karlseguin/ccache"
+ "github.com/volatiletech/sqlboiler/v4/boil"
)
var _ bot.BotInitHandler = (*Plugin)(nil)
@@ -21,12 +28,81 @@ func (p *Plugin) BotInit() {
eventsystem.AddHandlerAsyncLast(p, HandleGuildMemberAdd, eventsystem.EventGuildMemberAdd)
eventsystem.AddHandlerAsyncLast(p, HandleGuildMemberRemove, eventsystem.EventGuildMemberRemove)
eventsystem.AddHandlerFirst(p, HandleChannelUpdate, eventsystem.EventChannelUpdate)
+
+ pubsub.AddHandler("invalidate_notifications_config_cache", handleInvalidateConfigCache, nil)
+}
+
+var configCache = ccache.New(ccache.Configure().MaxSize(15000))
+
+func SaveConfig(config *Config) error {
+ err := config.ToModel().UpsertG(context.Background(), true, []string{"guild_id"}, boil.Infer(), boil.Infer())
+ if err != nil {
+ return err
+ }
+ pubsub.Publish("invalidate_notifications_config_cache", config.GuildID, nil)
+ return nil
+}
+
+func GetCachedConfigOrDefault(guildID int64) (*Config, error) {
+ const cacheDuration = 10 * time.Minute
+
+ item, err := configCache.Fetch(cacheKey(guildID), cacheDuration, func() (interface{}, error) {
+ return GetConfig(guildID)
+ })
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return &Config{
+ JoinServerMsgs: []string{"<@{{.User.ID}}> Joined!"},
+ LeaveMsgs: []string{"**{{.User.Username}}** Left... :'("},
+ }, nil
+ }
+ return nil, err
+ }
+ return item.Value().(*Config), nil
+}
+
+func handleInvalidateConfigCache(evt *pubsub.Event) {
+ configCache.Delete(cacheKey(evt.TargetGuildInt))
+}
+
+func cacheKey(guildID int64) string {
+ return discordgo.StrID(guildID)
+}
+
+func GetConfig(guildID int64) (*Config, error) {
+ const maxRetries = 1000
+
+ currentRetries := 0
+ for {
+ conf, err := models.FindGeneralNotificationConfigG(context.Background(), guildID)
+ if err == nil {
+ if currentRetries > 1 {
+ logger.Info("Fetched config after ", currentRetries, " retries")
+ }
+ return configFromModel(conf), nil
+ }
+
+ if err == sql.ErrNoRows {
+ return nil, err
+ }
+
+ if strings.Contains(err.Error(), "sorry, too many clients already") {
+ time.Sleep(time.Millisecond * 10 * time.Duration(rand.Intn(10)))
+ currentRetries++
+ if currentRetries > maxRetries {
+ return nil, err
+ }
+ continue
+ }
+
+ return nil, err
+ }
}
func HandleGuildMemberAdd(evtData *eventsystem.EventData) (retry bool, err error) {
evt := evtData.GuildMemberAdd()
- config, err := GetConfig(evt.GuildID)
+ config, err := GetCachedConfigOrDefault(evt.GuildID)
if err != nil {
return true, errors.WithStackIf(err)
}
@@ -69,7 +145,7 @@ func HandleGuildMemberAdd(evtData *eventsystem.EventData) (retry bool, err error
}
if config.JoinServerEnabled && len(config.JoinServerMsgs) > 0 {
- channel := gs.GetChannel(config.JoinServerChannelInt())
+ channel := gs.GetChannel(config.JoinServerChannel)
if channel == nil {
return
}
@@ -88,7 +164,7 @@ func HandleGuildMemberAdd(evtData *eventsystem.EventData) (retry bool, err error
func HandleGuildMemberRemove(evt *eventsystem.EventData) (retry bool, err error) {
memberRemove := evt.GuildMemberRemove()
- config, err := GetConfig(memberRemove.GuildID)
+ config, err := GetCachedConfigOrDefault(memberRemove.GuildID)
if err != nil {
return true, errors.WithStackIf(err)
}
@@ -102,7 +178,7 @@ func HandleGuildMemberRemove(evt *eventsystem.EventData) (retry bool, err error)
return
}
- channel := gs.GetChannel(config.LeaveChannelInt())
+ channel := gs.GetChannel(config.LeaveChannel)
if channel == nil {
return
}
@@ -230,7 +306,7 @@ func HandleChannelUpdate(evt *eventsystem.EventData) (retry bool, err error) {
return
}
- config, err := GetConfig(cu.GuildID)
+ config, err := GetCachedConfigOrDefault(cu.GuildID)
if err != nil {
return true, errors.WithStackIf(err)
}
@@ -240,8 +316,8 @@ func HandleChannelUpdate(evt *eventsystem.EventData) (retry bool, err error) {
}
topicChannel := cu.Channel.ID
- if config.TopicChannelInt() != 0 {
- c := gs.GetChannel(config.TopicChannelInt())
+ if config.TopicChannel != 0 {
+ c := gs.GetChannel(config.TopicChannel)
if c != nil {
topicChannel = c.ID
}
diff --git a/notifications/plugin_web.go b/notifications/plugin_web.go
index 44a747e304..07b8ee9cce 100644
--- a/notifications/plugin_web.go
+++ b/notifications/plugin_web.go
@@ -7,7 +7,6 @@ import (
"net/http"
"github.com/botlabs-gg/yagpdb/v2/common"
- "github.com/botlabs-gg/yagpdb/v2/common/configstore"
"github.com/botlabs-gg/yagpdb/v2/common/cplogs"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/web"
@@ -45,7 +44,7 @@ func HandleNotificationsGet(w http.ResponseWriter, r *http.Request) interface{}
if ok {
templateData["NotifyConfig"] = formConfig
} else {
- conf, err := GetConfig(activeGuild.ID)
+ conf, err := GetCachedConfigOrDefault(activeGuild.ID)
if err != nil {
web.CtxLogger(r.Context()).WithError(err).Error("failed retrieving config")
}
@@ -64,8 +63,7 @@ func HandleNotificationsPost(w http.ResponseWriter, r *http.Request) (web.Templa
newConfig := ctx.Value(common.ContextKeyParsedForm).(*Config)
newConfig.GuildID = activeGuild.ID
-
- err := configstore.SQL.SetGuildConfig(ctx, newConfig)
+ err := SaveConfig(newConfig)
if err != nil {
return templateData, nil
}
@@ -83,7 +81,7 @@ func (p *Plugin) LoadServerHomeWidget(w http.ResponseWriter, r *http.Request) (w
templateData["WidgetTitle"] = "General notifications"
templateData["SettingsPath"] = "/notifications/general"
- config, err := GetConfig(ag.ID)
+ config, err := GetCachedConfigOrDefault(ag.ID)
if err != nil {
return templateData, err
}
diff --git a/notifications/schema.go b/notifications/schema.go
new file mode 100644
index 0000000000..686a05f85d
--- /dev/null
+++ b/notifications/schema.go
@@ -0,0 +1,78 @@
+package notifications
+
+var DBSchemas = []string{`
+CREATE TABLE IF NOT EXISTS general_notification_configs (
+ guild_id BIGINT PRIMARY KEY,
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL,
+ updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
+
+ -- Many of the following columns should be non-nullable, but were originally
+ -- managed by gorm (which does not add NOT NULL constraints by default) so are
+ -- missing them. Unfortunately, it is unfeasible to retroactively fill missing
+ -- values with defaults and add the constraints as there are simply too many
+ -- rows in production.
+
+ -- For similar legacy reasons, many fields that should have type BIGINT are TEXT.
+
+ join_server_enabled BOOLEAN,
+ join_server_channel TEXT,
+ -- This column should be a TEXT[]. But for legacy reasons, it is instead a single
+ -- TEXT column containing all template responses joined together and delimited by
+ -- the character U+001E (INFORMATION SEPARATOR TWO.)
+ join_server_msgs TEXT,
+ join_dm_enabled BOOLEAN,
+ join_dm_msg TEXT,
+
+ leave_enabled BOOLEAN,
+ leave_channel TEXT,
+ -- Same deal as join_server_msgs.
+ leave_msgs TEXT,
+
+ topic_enabled BOOLEAN,
+ topic_channel TEXT,
+
+ censor_invites BOOLEAN
+);
+`, `
+
+-- Tables created with gorm have missing NOT NULL constraints for created_at and
+-- updated_at columns; since these columns are never null in existing rows, we can
+-- retraoctively add the constraints without needing to update any data.
+
+ALTER TABLE general_notification_configs ALTER COLUMN created_at SET NOT NULL;
+`, `
+ALTER TABLE general_notification_configs ALTER COLUMN updated_at SET NOT NULL;
+`, `
+
+-- Now the more complicated migration. For legacy reasons, the general_notification_configs
+-- table previously contained two pairs of columns for join and leave message:
+-- * join_server_msg, join_server_msgs_
+-- * leave_msg, leave_msgs_
+-- all of type TEXT. (The variants with _ were added when multiple-response support was
+-- implemented and contain the individual responses separated by U+001E as described
+-- previously.)
+
+-- Ideally, we only have one column for each message. We achieve this state with the following
+-- multi-step migration:
+-- 1. Update old records with join_server_msg != '' or leave_msg != '' to use the plural
+-- join_server_msgs_ and leave_msgs_ columns respectively.
+-- 2. Drop the join_server_msg and leave_msg columns.
+-- 3. Rename join_server_msgs_ to join_server_msgs and leave_msgs_ to leave_msgs.
+
+-- Here goes.
+DO $$
+BEGIN
+
+-- only run if general_notifcation_configs.join_server_msg (indicative of legacy table) exists
+IF EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name='general_notification_configs' AND column_name='join_server_msg') THEN
+ UPDATE general_notification_configs SET join_server_msgs_ = join_server_msg WHERE join_server_msg != '';
+ UPDATE general_notification_configs SET leave_msgs_ = leave_msg WHERE leave_msg != '';
+
+ ALTER TABLE general_notification_configs DROP COLUMN join_server_msg;
+ ALTER TABLE general_notification_configs DROP COLUMN leave_msg;
+
+ ALTER TABLE general_notification_configs RENAME COLUMN join_server_msgs_ to join_server_msgs;
+ ALTER TABLE general_notification_configs RENAME COLUMN leave_msgs_ to leave_msgs;
+END IF;
+END $$;
+`}
diff --git a/notifications/sqlboiler.toml b/notifications/sqlboiler.toml
new file mode 100644
index 0000000000..47d4b92185
--- /dev/null
+++ b/notifications/sqlboiler.toml
@@ -0,0 +1,22 @@
+add-global-variants = true
+no-hooks = true
+no-tests = true
+
+[psql]
+dbname = "yagpdb"
+host = "localhost"
+user = "postgres"
+pass = "pass"
+sslmode = "disable"
+whitelist = ["general_notification_configs"]
+
+[auto-columns]
+created = "created_at"
+updated = "updated_at"
+
+# sqlboiler column name inference capitalizes MSG and MSGS so, for instance,
+# leave_msgs becomes LeaveMSGS; manually override the names
+[aliases.tables.general_notification_configs.columns]
+join_server_msgs = "JoinServerMsgs"
+join_dm_msg = "JoinDMMsg"
+leave_msgs = "LeaveMsgs"
diff --git a/reminders/models/boil_queries.go b/reminders/models/boil_queries.go
new file mode 100644
index 0000000000..20c2563fdb
--- /dev/null
+++ b/reminders/models/boil_queries.go
@@ -0,0 +1,38 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "regexp"
+
+ "github.com/volatiletech/sqlboiler/v4/drivers"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+)
+
+var dialect = drivers.Dialect{
+ LQ: 0x22,
+ RQ: 0x22,
+
+ UseIndexPlaceholders: true,
+ UseLastInsertID: false,
+ UseSchema: false,
+ UseDefaultKeyword: true,
+ UseAutoColumns: false,
+ UseTopClause: false,
+ UseOutputClause: false,
+ UseCaseWhenExistsClause: false,
+}
+
+// This is a dummy variable to prevent unused regexp import error
+var _ = ®exp.Regexp{}
+
+// NewQuery initializes a new Query using the passed in QueryMods
+func NewQuery(mods ...qm.QueryMod) *queries.Query {
+ q := &queries.Query{}
+ queries.SetDialect(q, &dialect)
+ qm.Apply(q, mods...)
+
+ return q
+}
diff --git a/reminders/models/boil_table_names.go b/reminders/models/boil_table_names.go
new file mode 100644
index 0000000000..879f7cf0bd
--- /dev/null
+++ b/reminders/models/boil_table_names.go
@@ -0,0 +1,10 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+var TableNames = struct {
+ Reminders string
+}{
+ Reminders: "reminders",
+}
diff --git a/reminders/models/boil_types.go b/reminders/models/boil_types.go
new file mode 100644
index 0000000000..02a6fdfdc5
--- /dev/null
+++ b/reminders/models/boil_types.go
@@ -0,0 +1,52 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "strconv"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/strmangle"
+)
+
+// M type is for providing columns and column values to UpdateAll.
+type M map[string]interface{}
+
+// ErrSyncFail occurs during insert when the record could not be retrieved in
+// order to populate default value information. This usually happens when LastInsertId
+// fails or there was a primary key configuration that was not resolvable.
+var ErrSyncFail = errors.New("models: failed to synchronize data after insert")
+
+type insertCache struct {
+ query string
+ retQuery string
+ valueMapping []uint64
+ retMapping []uint64
+}
+
+type updateCache struct {
+ query string
+ valueMapping []uint64
+}
+
+func makeCacheKey(cols boil.Columns, nzDefaults []string) string {
+ buf := strmangle.GetBuffer()
+
+ buf.WriteString(strconv.Itoa(cols.Kind))
+ for _, w := range cols.Cols {
+ buf.WriteString(w)
+ }
+
+ if len(nzDefaults) != 0 {
+ buf.WriteByte('.')
+ }
+ for _, nz := range nzDefaults {
+ buf.WriteString(nz)
+ }
+
+ str := buf.String()
+ strmangle.PutBuffer(buf)
+ return str
+}
diff --git a/reminders/models/boil_view_names.go b/reminders/models/boil_view_names.go
new file mode 100644
index 0000000000..01504d82bf
--- /dev/null
+++ b/reminders/models/boil_view_names.go
@@ -0,0 +1,7 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+var ViewNames = struct {
+}{}
diff --git a/reminders/models/psql_upsert.go b/reminders/models/psql_upsert.go
new file mode 100644
index 0000000000..07602da9c5
--- /dev/null
+++ b/reminders/models/psql_upsert.go
@@ -0,0 +1,99 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/volatiletech/sqlboiler/v4/drivers"
+ "github.com/volatiletech/strmangle"
+)
+
+type UpsertOptions struct {
+ conflictTarget string
+ updateSet string
+}
+
+type UpsertOptionFunc func(o *UpsertOptions)
+
+func UpsertConflictTarget(conflictTarget string) UpsertOptionFunc {
+ return func(o *UpsertOptions) {
+ o.conflictTarget = conflictTarget
+ }
+}
+
+func UpsertUpdateSet(updateSet string) UpsertOptionFunc {
+ return func(o *UpsertOptions) {
+ o.updateSet = updateSet
+ }
+}
+
+// buildUpsertQueryPostgres builds a SQL statement string using the upsertData provided.
+func buildUpsertQueryPostgres(dia drivers.Dialect, tableName string, updateOnConflict bool, ret, update, conflict, whitelist []string, opts ...UpsertOptionFunc) string {
+ conflict = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, conflict)
+ whitelist = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, whitelist)
+ ret = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, ret)
+
+ upsertOpts := &UpsertOptions{}
+ for _, o := range opts {
+ o(upsertOpts)
+ }
+
+ buf := strmangle.GetBuffer()
+ defer strmangle.PutBuffer(buf)
+
+ columns := "DEFAULT VALUES"
+ if len(whitelist) != 0 {
+ columns = fmt.Sprintf("(%s) VALUES (%s)",
+ strings.Join(whitelist, ", "),
+ strmangle.Placeholders(dia.UseIndexPlaceholders, len(whitelist), 1, 1))
+ }
+
+ fmt.Fprintf(
+ buf,
+ "INSERT INTO %s %s ON CONFLICT ",
+ tableName,
+ columns,
+ )
+
+ if upsertOpts.conflictTarget != "" {
+ buf.WriteString(upsertOpts.conflictTarget)
+ } else if len(conflict) != 0 {
+ buf.WriteByte('(')
+ buf.WriteString(strings.Join(conflict, ", "))
+ buf.WriteByte(')')
+ }
+ buf.WriteByte(' ')
+
+ if !updateOnConflict || len(update) == 0 {
+ buf.WriteString("DO NOTHING")
+ } else {
+ buf.WriteString("DO UPDATE SET ")
+
+ if upsertOpts.updateSet != "" {
+ buf.WriteString(upsertOpts.updateSet)
+ } else {
+ for i, v := range update {
+ if len(v) == 0 {
+ continue
+ }
+ if i != 0 {
+ buf.WriteByte(',')
+ }
+ quoted := strmangle.IdentQuote(dia.LQ, dia.RQ, v)
+ buf.WriteString(quoted)
+ buf.WriteString(" = EXCLUDED.")
+ buf.WriteString(quoted)
+ }
+ }
+ }
+
+ if len(ret) != 0 {
+ buf.WriteString(" RETURNING ")
+ buf.WriteString(strings.Join(ret, ", "))
+ }
+
+ return buf.String()
+}
diff --git a/reminders/models/reminders.go b/reminders/models/reminders.go
new file mode 100644
index 0000000000..dd68b9f533
--- /dev/null
+++ b/reminders/models/reminders.go
@@ -0,0 +1,998 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/null/v8"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+ "github.com/volatiletech/sqlboiler/v4/queries/qmhelper"
+ "github.com/volatiletech/strmangle"
+)
+
+// Reminder is an object representing the database table.
+type Reminder struct {
+ ID int `boil:"id" json:"id" toml:"id" yaml:"id"`
+ CreatedAt time.Time `boil:"created_at" json:"created_at" toml:"created_at" yaml:"created_at"`
+ UpdatedAt time.Time `boil:"updated_at" json:"updated_at" toml:"updated_at" yaml:"updated_at"`
+ DeletedAt null.Time `boil:"deleted_at" json:"deleted_at,omitempty" toml:"deleted_at" yaml:"deleted_at,omitempty"`
+ UserID string `boil:"user_id" json:"user_id" toml:"user_id" yaml:"user_id"`
+ ChannelID string `boil:"channel_id" json:"channel_id" toml:"channel_id" yaml:"channel_id"`
+ GuildID int64 `boil:"guild_id" json:"guild_id" toml:"guild_id" yaml:"guild_id"`
+ Message string `boil:"message" json:"message" toml:"message" yaml:"message"`
+ When int64 `boil:"when" json:"when" toml:"when" yaml:"when"`
+
+ R *reminderR `boil:"-" json:"-" toml:"-" yaml:"-"`
+ L reminderL `boil:"-" json:"-" toml:"-" yaml:"-"`
+}
+
+var ReminderColumns = struct {
+ ID string
+ CreatedAt string
+ UpdatedAt string
+ DeletedAt string
+ UserID string
+ ChannelID string
+ GuildID string
+ Message string
+ When string
+}{
+ ID: "id",
+ CreatedAt: "created_at",
+ UpdatedAt: "updated_at",
+ DeletedAt: "deleted_at",
+ UserID: "user_id",
+ ChannelID: "channel_id",
+ GuildID: "guild_id",
+ Message: "message",
+ When: "when",
+}
+
+var ReminderTableColumns = struct {
+ ID string
+ CreatedAt string
+ UpdatedAt string
+ DeletedAt string
+ UserID string
+ ChannelID string
+ GuildID string
+ Message string
+ When string
+}{
+ ID: "reminders.id",
+ CreatedAt: "reminders.created_at",
+ UpdatedAt: "reminders.updated_at",
+ DeletedAt: "reminders.deleted_at",
+ UserID: "reminders.user_id",
+ ChannelID: "reminders.channel_id",
+ GuildID: "reminders.guild_id",
+ Message: "reminders.message",
+ When: "reminders.when",
+}
+
+// Generated where
+
+type whereHelperint struct{ field string }
+
+func (w whereHelperint) EQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperint) NEQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperint) LT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperint) LTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperint) GT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperint) GTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperint) IN(slice []int) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperint) NIN(slice []int) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+type whereHelpertime_Time struct{ field string }
+
+func (w whereHelpertime_Time) EQ(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.EQ, x)
+}
+func (w whereHelpertime_Time) NEQ(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.NEQ, x)
+}
+func (w whereHelpertime_Time) LT(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpertime_Time) LTE(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpertime_Time) GT(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpertime_Time) GTE(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+type whereHelpernull_Time struct{ field string }
+
+func (w whereHelpernull_Time) EQ(x null.Time) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpernull_Time) NEQ(x null.Time) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpernull_Time) LT(x null.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpernull_Time) LTE(x null.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpernull_Time) GT(x null.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpernull_Time) GTE(x null.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+func (w whereHelpernull_Time) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpernull_Time) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+type whereHelperstring struct{ field string }
+
+func (w whereHelperstring) EQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperstring) NEQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperstring) LT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperstring) LTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperstring) GT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperstring) GTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperstring) LIKE(x string) qm.QueryMod { return qm.Where(w.field+" LIKE ?", x) }
+func (w whereHelperstring) NLIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT LIKE ?", x) }
+func (w whereHelperstring) ILIKE(x string) qm.QueryMod { return qm.Where(w.field+" ILIKE ?", x) }
+func (w whereHelperstring) NILIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT ILIKE ?", x) }
+func (w whereHelperstring) IN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperstring) NIN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+type whereHelperint64 struct{ field string }
+
+func (w whereHelperint64) EQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperint64) NEQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperint64) LT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperint64) LTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperint64) GT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperint64) GTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperint64) IN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperint64) NIN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+var ReminderWhere = struct {
+ ID whereHelperint
+ CreatedAt whereHelpertime_Time
+ UpdatedAt whereHelpertime_Time
+ DeletedAt whereHelpernull_Time
+ UserID whereHelperstring
+ ChannelID whereHelperstring
+ GuildID whereHelperint64
+ Message whereHelperstring
+ When whereHelperint64
+}{
+ ID: whereHelperint{field: "\"reminders\".\"id\""},
+ CreatedAt: whereHelpertime_Time{field: "\"reminders\".\"created_at\""},
+ UpdatedAt: whereHelpertime_Time{field: "\"reminders\".\"updated_at\""},
+ DeletedAt: whereHelpernull_Time{field: "\"reminders\".\"deleted_at\""},
+ UserID: whereHelperstring{field: "\"reminders\".\"user_id\""},
+ ChannelID: whereHelperstring{field: "\"reminders\".\"channel_id\""},
+ GuildID: whereHelperint64{field: "\"reminders\".\"guild_id\""},
+ Message: whereHelperstring{field: "\"reminders\".\"message\""},
+ When: whereHelperint64{field: "\"reminders\".\"when\""},
+}
+
+// ReminderRels is where relationship names are stored.
+var ReminderRels = struct {
+}{}
+
+// reminderR is where relationships are stored.
+type reminderR struct {
+}
+
+// NewStruct creates a new relationship struct
+func (*reminderR) NewStruct() *reminderR {
+ return &reminderR{}
+}
+
+// reminderL is where Load methods for each relationship are stored.
+type reminderL struct{}
+
+var (
+ reminderAllColumns = []string{"id", "created_at", "updated_at", "deleted_at", "user_id", "channel_id", "guild_id", "message", "when"}
+ reminderColumnsWithoutDefault = []string{"created_at", "updated_at", "user_id", "channel_id", "guild_id", "message", "when"}
+ reminderColumnsWithDefault = []string{"id", "deleted_at"}
+ reminderPrimaryKeyColumns = []string{"id"}
+ reminderGeneratedColumns = []string{}
+)
+
+type (
+ // ReminderSlice is an alias for a slice of pointers to Reminder.
+ // This should almost always be used instead of []Reminder.
+ ReminderSlice []*Reminder
+
+ reminderQuery struct {
+ *queries.Query
+ }
+)
+
+// Cache for insert, update and upsert
+var (
+ reminderType = reflect.TypeOf(&Reminder{})
+ reminderMapping = queries.MakeStructMapping(reminderType)
+ reminderPrimaryKeyMapping, _ = queries.BindMapping(reminderType, reminderMapping, reminderPrimaryKeyColumns)
+ reminderInsertCacheMut sync.RWMutex
+ reminderInsertCache = make(map[string]insertCache)
+ reminderUpdateCacheMut sync.RWMutex
+ reminderUpdateCache = make(map[string]updateCache)
+ reminderUpsertCacheMut sync.RWMutex
+ reminderUpsertCache = make(map[string]insertCache)
+)
+
+var (
+ // Force time package dependency for automated UpdatedAt/CreatedAt.
+ _ = time.Second
+ // Force qmhelper dependency for where clause generation (which doesn't
+ // always happen)
+ _ = qmhelper.Where
+)
+
+// OneG returns a single reminder record from the query using the global executor.
+func (q reminderQuery) OneG(ctx context.Context) (*Reminder, error) {
+ return q.One(ctx, boil.GetContextDB())
+}
+
+// One returns a single reminder record from the query.
+func (q reminderQuery) One(ctx context.Context, exec boil.ContextExecutor) (*Reminder, error) {
+ o := &Reminder{}
+
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Bind(ctx, exec, o)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: failed to execute a one query for reminders")
+ }
+
+ return o, nil
+}
+
+// AllG returns all Reminder records from the query using the global executor.
+func (q reminderQuery) AllG(ctx context.Context) (ReminderSlice, error) {
+ return q.All(ctx, boil.GetContextDB())
+}
+
+// All returns all Reminder records from the query.
+func (q reminderQuery) All(ctx context.Context, exec boil.ContextExecutor) (ReminderSlice, error) {
+ var o []*Reminder
+
+ err := q.Bind(ctx, exec, &o)
+ if err != nil {
+ return nil, errors.Wrap(err, "models: failed to assign all query results to Reminder slice")
+ }
+
+ return o, nil
+}
+
+// CountG returns the count of all Reminder records in the query using the global executor
+func (q reminderQuery) CountG(ctx context.Context) (int64, error) {
+ return q.Count(ctx, boil.GetContextDB())
+}
+
+// Count returns the count of all Reminder records in the query.
+func (q reminderQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to count reminders rows")
+ }
+
+ return count, nil
+}
+
+// ExistsG checks if the row exists in the table using the global executor.
+func (q reminderQuery) ExistsG(ctx context.Context) (bool, error) {
+ return q.Exists(ctx, boil.GetContextDB())
+}
+
+// Exists checks if the row exists in the table.
+func (q reminderQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return false, errors.Wrap(err, "models: failed to check if reminders exists")
+ }
+
+ return count > 0, nil
+}
+
+// Reminders retrieves all the records using an executor.
+func Reminders(mods ...qm.QueryMod) reminderQuery {
+ mods = append(mods, qm.From("\"reminders\""), qmhelper.WhereIsNull("\"reminders\".\"deleted_at\""))
+ q := NewQuery(mods...)
+ if len(queries.GetSelect(q)) == 0 {
+ queries.SetSelect(q, []string{"\"reminders\".*"})
+ }
+
+ return reminderQuery{q}
+}
+
+// FindReminderG retrieves a single record by ID.
+func FindReminderG(ctx context.Context, iD int, selectCols ...string) (*Reminder, error) {
+ return FindReminder(ctx, boil.GetContextDB(), iD, selectCols...)
+}
+
+// FindReminder retrieves a single record by ID with an executor.
+// If selectCols is empty Find will return all columns.
+func FindReminder(ctx context.Context, exec boil.ContextExecutor, iD int, selectCols ...string) (*Reminder, error) {
+ reminderObj := &Reminder{}
+
+ sel := "*"
+ if len(selectCols) > 0 {
+ sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",")
+ }
+ query := fmt.Sprintf(
+ "select %s from \"reminders\" where \"id\"=$1 and \"deleted_at\" is null", sel,
+ )
+
+ q := queries.Raw(query, iD)
+
+ err := q.Bind(ctx, exec, reminderObj)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: unable to select from reminders")
+ }
+
+ return reminderObj, nil
+}
+
+// InsertG a single record. See Insert for whitelist behavior description.
+func (o *Reminder) InsertG(ctx context.Context, columns boil.Columns) error {
+ return o.Insert(ctx, boil.GetContextDB(), columns)
+}
+
+// Insert a single record using an executor.
+// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts.
+func (o *Reminder) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error {
+ if o == nil {
+ return errors.New("models: no reminders provided for insertion")
+ }
+
+ var err error
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ if o.UpdatedAt.IsZero() {
+ o.UpdatedAt = currTime
+ }
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(reminderColumnsWithDefault, o)
+
+ key := makeCacheKey(columns, nzDefaults)
+ reminderInsertCacheMut.RLock()
+ cache, cached := reminderInsertCache[key]
+ reminderInsertCacheMut.RUnlock()
+
+ if !cached {
+ wl, returnColumns := columns.InsertColumnSet(
+ reminderAllColumns,
+ reminderColumnsWithDefault,
+ reminderColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ cache.valueMapping, err = queries.BindMapping(reminderType, reminderMapping, wl)
+ if err != nil {
+ return err
+ }
+ cache.retMapping, err = queries.BindMapping(reminderType, reminderMapping, returnColumns)
+ if err != nil {
+ return err
+ }
+ if len(wl) != 0 {
+ cache.query = fmt.Sprintf("INSERT INTO \"reminders\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1))
+ } else {
+ cache.query = "INSERT INTO \"reminders\" %sDEFAULT VALUES%s"
+ }
+
+ var queryOutput, queryReturning string
+
+ if len(cache.retMapping) != 0 {
+ queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\""))
+ }
+
+ cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+
+ if err != nil {
+ return errors.Wrap(err, "models: unable to insert into reminders")
+ }
+
+ if !cached {
+ reminderInsertCacheMut.Lock()
+ reminderInsertCache[key] = cache
+ reminderInsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// UpdateG a single Reminder record using the global executor.
+// See Update for more documentation.
+func (o *Reminder) UpdateG(ctx context.Context, columns boil.Columns) (int64, error) {
+ return o.Update(ctx, boil.GetContextDB(), columns)
+}
+
+// Update uses an executor to update the Reminder.
+// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates.
+// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records.
+func (o *Reminder) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) {
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ o.UpdatedAt = currTime
+ }
+
+ var err error
+ key := makeCacheKey(columns, nil)
+ reminderUpdateCacheMut.RLock()
+ cache, cached := reminderUpdateCache[key]
+ reminderUpdateCacheMut.RUnlock()
+
+ if !cached {
+ wl := columns.UpdateColumnSet(
+ reminderAllColumns,
+ reminderPrimaryKeyColumns,
+ )
+
+ if !columns.IsWhitelist() {
+ wl = strmangle.SetComplement(wl, []string{"created_at"})
+ }
+ if len(wl) == 0 {
+ return 0, errors.New("models: unable to update reminders, could not build whitelist")
+ }
+
+ cache.query = fmt.Sprintf("UPDATE \"reminders\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ strmangle.WhereClause("\"", "\"", len(wl)+1, reminderPrimaryKeyColumns),
+ )
+ cache.valueMapping, err = queries.BindMapping(reminderType, reminderMapping, append(wl, reminderPrimaryKeyColumns...))
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, values)
+ }
+ var result sql.Result
+ result, err = exec.ExecContext(ctx, cache.query, values...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update reminders row")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by update for reminders")
+ }
+
+ if !cached {
+ reminderUpdateCacheMut.Lock()
+ reminderUpdateCache[key] = cache
+ reminderUpdateCacheMut.Unlock()
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (q reminderQuery) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return q.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values.
+func (q reminderQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ queries.SetUpdate(q.Query, cols)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all for reminders")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected for reminders")
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (o ReminderSlice) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return o.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values, using an executor.
+func (o ReminderSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ ln := int64(len(o))
+ if ln == 0 {
+ return 0, nil
+ }
+
+ if len(cols) == 0 {
+ return 0, errors.New("models: update all requires at least one column argument")
+ }
+
+ colNames := make([]string, len(cols))
+ args := make([]interface{}, len(cols))
+
+ i := 0
+ for name, value := range cols {
+ colNames[i] = name
+ args[i] = value
+ i++
+ }
+
+ // Append all of the primary key values for each column
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), reminderPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := fmt.Sprintf("UPDATE \"reminders\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, colNames),
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, reminderPrimaryKeyColumns, len(o)))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all in reminder slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all reminder")
+ }
+ return rowsAff, nil
+}
+
+// UpsertG attempts an insert, and does an update or ignore on conflict.
+func (o *Reminder) UpsertG(ctx context.Context, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ return o.Upsert(ctx, boil.GetContextDB(), updateOnConflict, conflictColumns, updateColumns, insertColumns, opts...)
+}
+
+// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
+// See boil.Columns documentation for how to properly use updateColumns and insertColumns.
+func (o *Reminder) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ if o == nil {
+ return errors.New("models: no reminders provided for upsert")
+ }
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ o.UpdatedAt = currTime
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(reminderColumnsWithDefault, o)
+
+ // Build cache key in-line uglily - mysql vs psql problems
+ buf := strmangle.GetBuffer()
+ if updateOnConflict {
+ buf.WriteByte('t')
+ } else {
+ buf.WriteByte('f')
+ }
+ buf.WriteByte('.')
+ for _, c := range conflictColumns {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(updateColumns.Kind))
+ for _, c := range updateColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(insertColumns.Kind))
+ for _, c := range insertColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ for _, c := range nzDefaults {
+ buf.WriteString(c)
+ }
+ key := buf.String()
+ strmangle.PutBuffer(buf)
+
+ reminderUpsertCacheMut.RLock()
+ cache, cached := reminderUpsertCache[key]
+ reminderUpsertCacheMut.RUnlock()
+
+ var err error
+
+ if !cached {
+ insert, _ := insertColumns.InsertColumnSet(
+ reminderAllColumns,
+ reminderColumnsWithDefault,
+ reminderColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ update := updateColumns.UpdateColumnSet(
+ reminderAllColumns,
+ reminderPrimaryKeyColumns,
+ )
+
+ if updateOnConflict && len(update) == 0 {
+ return errors.New("models: unable to upsert reminders, could not build update column list")
+ }
+
+ ret := strmangle.SetComplement(reminderAllColumns, strmangle.SetIntersect(insert, update))
+
+ conflict := conflictColumns
+ if len(conflict) == 0 && updateOnConflict && len(update) != 0 {
+ if len(reminderPrimaryKeyColumns) == 0 {
+ return errors.New("models: unable to upsert reminders, could not build conflict column list")
+ }
+
+ conflict = make([]string, len(reminderPrimaryKeyColumns))
+ copy(conflict, reminderPrimaryKeyColumns)
+ }
+ cache.query = buildUpsertQueryPostgres(dialect, "\"reminders\"", updateOnConflict, ret, update, conflict, insert, opts...)
+
+ cache.valueMapping, err = queries.BindMapping(reminderType, reminderMapping, insert)
+ if err != nil {
+ return err
+ }
+ if len(ret) != 0 {
+ cache.retMapping, err = queries.BindMapping(reminderType, reminderMapping, ret)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+ var returns []interface{}
+ if len(cache.retMapping) != 0 {
+ returns = queries.PtrsFromMapping(value, cache.retMapping)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...)
+ if errors.Is(err, sql.ErrNoRows) {
+ err = nil // Postgres doesn't return anything when there's no update
+ }
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+ if err != nil {
+ return errors.Wrap(err, "models: unable to upsert reminders")
+ }
+
+ if !cached {
+ reminderUpsertCacheMut.Lock()
+ reminderUpsertCache[key] = cache
+ reminderUpsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// DeleteG deletes a single Reminder record.
+// DeleteG will match against the primary key column to find the record to delete.
+func (o *Reminder) DeleteG(ctx context.Context, hardDelete bool) (int64, error) {
+ return o.Delete(ctx, boil.GetContextDB(), hardDelete)
+}
+
+// Delete deletes a single Reminder record with an executor.
+// Delete will match against the primary key column to find the record to delete.
+func (o *Reminder) Delete(ctx context.Context, exec boil.ContextExecutor, hardDelete bool) (int64, error) {
+ if o == nil {
+ return 0, errors.New("models: no Reminder provided for delete")
+ }
+
+ var (
+ sql string
+ args []interface{}
+ )
+ if hardDelete {
+ args = queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), reminderPrimaryKeyMapping)
+ sql = "DELETE FROM \"reminders\" WHERE \"id\"=$1"
+ } else {
+ currTime := time.Now().In(boil.GetLocation())
+ o.DeletedAt = null.TimeFrom(currTime)
+ wl := []string{"deleted_at"}
+ sql = fmt.Sprintf("UPDATE \"reminders\" SET %s WHERE \"id\"=$2",
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ )
+ valueMapping, err := queries.BindMapping(reminderType, reminderMapping, append(wl, reminderPrimaryKeyColumns...))
+ if err != nil {
+ return 0, err
+ }
+ args = queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), valueMapping)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete from reminders")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by delete for reminders")
+ }
+
+ return rowsAff, nil
+}
+
+func (q reminderQuery) DeleteAllG(ctx context.Context, hardDelete bool) (int64, error) {
+ return q.DeleteAll(ctx, boil.GetContextDB(), hardDelete)
+}
+
+// DeleteAll deletes all matching rows.
+func (q reminderQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor, hardDelete bool) (int64, error) {
+ if q.Query == nil {
+ return 0, errors.New("models: no reminderQuery provided for delete all")
+ }
+
+ if hardDelete {
+ queries.SetDelete(q.Query)
+ } else {
+ currTime := time.Now().In(boil.GetLocation())
+ queries.SetUpdate(q.Query, M{"deleted_at": currTime})
+ }
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from reminders")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for reminders")
+ }
+
+ return rowsAff, nil
+}
+
+// DeleteAllG deletes all rows in the slice.
+func (o ReminderSlice) DeleteAllG(ctx context.Context, hardDelete bool) (int64, error) {
+ return o.DeleteAll(ctx, boil.GetContextDB(), hardDelete)
+}
+
+// DeleteAll deletes all rows in the slice, using an executor.
+func (o ReminderSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor, hardDelete bool) (int64, error) {
+ if len(o) == 0 {
+ return 0, nil
+ }
+
+ var (
+ sql string
+ args []interface{}
+ )
+ if hardDelete {
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), reminderPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+ sql = "DELETE FROM \"reminders\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, reminderPrimaryKeyColumns, len(o))
+ } else {
+ currTime := time.Now().In(boil.GetLocation())
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), reminderPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ obj.DeletedAt = null.TimeFrom(currTime)
+ }
+ wl := []string{"deleted_at"}
+ sql = fmt.Sprintf("UPDATE \"reminders\" SET %s WHERE "+
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 2, reminderPrimaryKeyColumns, len(o)),
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ )
+ args = append([]interface{}{currTime}, args...)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from reminder slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for reminders")
+ }
+
+ return rowsAff, nil
+}
+
+// ReloadG refetches the object from the database using the primary keys.
+func (o *Reminder) ReloadG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: no Reminder provided for reload")
+ }
+
+ return o.Reload(ctx, boil.GetContextDB())
+}
+
+// Reload refetches the object from the database
+// using the primary keys with an executor.
+func (o *Reminder) Reload(ctx context.Context, exec boil.ContextExecutor) error {
+ ret, err := FindReminder(ctx, exec, o.ID)
+ if err != nil {
+ return err
+ }
+
+ *o = *ret
+ return nil
+}
+
+// ReloadAllG refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *ReminderSlice) ReloadAllG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: empty ReminderSlice provided for reload all")
+ }
+
+ return o.ReloadAll(ctx, boil.GetContextDB())
+}
+
+// ReloadAll refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *ReminderSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error {
+ if o == nil || len(*o) == 0 {
+ return nil
+ }
+
+ slice := ReminderSlice{}
+ var args []interface{}
+ for _, obj := range *o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), reminderPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "SELECT \"reminders\".* FROM \"reminders\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, reminderPrimaryKeyColumns, len(*o)) +
+ "and \"deleted_at\" is null"
+
+ q := queries.Raw(sql, args...)
+
+ err := q.Bind(ctx, exec, &slice)
+ if err != nil {
+ return errors.Wrap(err, "models: unable to reload all in ReminderSlice")
+ }
+
+ *o = slice
+
+ return nil
+}
+
+// ReminderExistsG checks if the Reminder row exists.
+func ReminderExistsG(ctx context.Context, iD int) (bool, error) {
+ return ReminderExists(ctx, boil.GetContextDB(), iD)
+}
+
+// ReminderExists checks if the Reminder row exists.
+func ReminderExists(ctx context.Context, exec boil.ContextExecutor, iD int) (bool, error) {
+ var exists bool
+ sql := "select exists(select 1 from \"reminders\" where \"id\"=$1 and \"deleted_at\" is null limit 1)"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, iD)
+ }
+ row := exec.QueryRowContext(ctx, sql, iD)
+
+ err := row.Scan(&exists)
+ if err != nil {
+ return false, errors.Wrap(err, "models: unable to check if reminders exists")
+ }
+
+ return exists, nil
+}
+
+// Exists checks if the Reminder row exists.
+func (o *Reminder) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ return ReminderExists(ctx, exec, o.ID)
+}
diff --git a/reminders/plugin_bot.go b/reminders/plugin_bot.go
index 83af5579b0..354237b70a 100644
--- a/reminders/plugin_bot.go
+++ b/reminders/plugin_bot.go
@@ -1,12 +1,12 @@
package reminders
import (
+ "context"
+ "database/sql"
"errors"
"fmt"
- "strconv"
"strings"
"time"
- "unicode/utf8"
"github.com/botlabs-gg/yagpdb/v2/bot"
"github.com/botlabs-gg/yagpdb/v2/commands"
@@ -16,7 +16,8 @@ import (
"github.com/botlabs-gg/yagpdb/v2/lib/dcmd"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/lib/dstate"
- "github.com/jinzhu/gorm"
+ "github.com/botlabs-gg/yagpdb/v2/reminders/models"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
)
var logger = common.GetPluginLogger(&Plugin{})
@@ -29,11 +30,17 @@ func (p *Plugin) AddCommands() {
}
func (p *Plugin) BotInit() {
- // scheduledevents.RegisterEventHandler("reminders_check_user", checkUserEvtHandlerLegacy)
scheduledevents2.RegisterHandler("reminders_check_user", int64(0), checkUserScheduledEvent)
scheduledevents2.RegisterLegacyMigrater("reminders_check_user", migrateLegacyScheduledEvents)
}
+const (
+ MaxReminders = 25
+
+ MaxReminderOffset = time.Hour * 24 * 366
+ MaxReminderOffsetExceededMsg = "Can be max 1 year from now..."
+)
+
// Reminder management commands
var cmds = []*commands.YAGCommand{
{
@@ -52,23 +59,19 @@ var cmds = []*commands.YAGCommand{
SlashCommandEnabled: true,
DefaultEnabled: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
- currentReminders, _ := GetUserReminders(parsed.Author.ID)
- if len(currentReminders) >= 25 {
- return "You can have a maximum of 25 active reminders, list all your reminders with the `reminders` command in DM, doing it in a server will only show reminders set in the server", nil
+ uid := discordgo.StrID(parsed.Author.ID)
+ count, _ := models.Reminders(models.ReminderWhere.UserID.EQ(uid)).CountG(parsed.Context())
+ if count >= MaxReminders {
+ return fmt.Sprintf("You can have a maximum of %d active reminders; list all your reminders with the `reminders` command in DM, doing it in a server will only show reminders set in the server", MaxReminders), nil
}
if parsed.Author.Bot {
- return nil, errors.New("cannot create reminder for Bots, you're most likely trying to use `execAdmin` to create a reminder, use `exec` instead")
+ return nil, errors.New("cannot create reminder for bots; you're likely trying to use `execAdmin` to create a reminder (use `exec` instead)")
}
- fromNow := parsed.Args[0].Value.(time.Duration)
-
- durString := common.HumanizeDuration(common.DurationPrecisionSeconds, fromNow)
- when := time.Now().Add(fromNow)
- tUnix := fmt.Sprint(when.Unix())
-
- if when.After(time.Now().Add(time.Hour * 24 * 366)) {
- return "Can be max 365 days from now...", nil
+ offsetFromNow := parsed.Args[0].Value.(time.Duration)
+ if offsetFromNow > MaxReminderOffset {
+ return MaxReminderOffsetExceededMsg, nil
}
id := parsed.ChannelID
@@ -77,7 +80,7 @@ var cmds = []*commands.YAGCommand{
hasPerms, err := bot.AdminOrPermMS(parsed.GuildData.GS.ID, id, parsed.GuildData.MS, discordgo.PermissionSendMessages|discordgo.PermissionViewChannel)
if err != nil {
- return "Failed checking permissions, please try again or join the support server.", err
+ return "Failed checking permissions; please try again or join the support server.", err
}
if !hasPerms {
@@ -85,12 +88,14 @@ var cmds = []*commands.YAGCommand{
}
}
+ when := time.Now().Add(offsetFromNow)
_, err := NewReminder(parsed.Author.ID, parsed.GuildData.GS.ID, id, parsed.Args[1].Str(), when)
if err != nil {
return nil, err
}
- return "Set a reminder in " + durString + " from now ()\nView reminders with the `reminders` command", nil
+ durString := common.HumanizeDuration(common.DurationPrecisionSeconds, offsetFromNow)
+ return fmt.Sprintf("Set a reminder in %s from now ()\nView reminders with the `reminders` command", durString, when.Unix()), nil
},
},
{
@@ -102,28 +107,29 @@ var cmds = []*commands.YAGCommand{
IsResponseEphemeral: true,
RunInDM: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
+ uid := discordgo.StrID(parsed.Author.ID)
+ qms := []qm.QueryMod{models.ReminderWhere.UserID.EQ(uid)}
+
+ // if command used in server, only show reminders in that server
+ var inServerSuffix string
+ if inServer := parsed.GuildData != nil; inServer {
+ inServerSuffix = " in this server"
- var currentReminders []*Reminder
- var err error
- //command was used in DM
- inServerString := ""
- if parsed.GuildData == nil {
- currentReminders, err = GetUserReminders(parsed.Author.ID)
- } else {
- inServerString = " in this server"
- currentReminders, err = GetGuildUserReminder(parsed.Author.ID, parsed.GuildData.GS.ID)
+ guildID := parsed.GuildData.GS.ID
+ qms = append(qms, models.ReminderWhere.GuildID.EQ(guildID))
}
+ currentReminders, err := models.Reminders(qms...).AllG(parsed.Context())
if err != nil {
return nil, err
}
if len(currentReminders) == 0 {
- return fmt.Sprintf("You have no reminders%s. Create reminders with the `remindme` command.", inServerString), nil
+ return fmt.Sprintf("You have no reminders%s. Create reminders with the `remindme` command", inServerSuffix), nil
}
- out := fmt.Sprintf("Your reminders%s:\n", inServerString)
- out += stringReminders(currentReminders, false)
+ out := fmt.Sprintf("Your reminders%s:\n", inServerSuffix)
+ out += DisplayReminders(currentReminders, ModeDisplayUserReminders)
out += "\nRemove a reminder with `delreminder/rmreminder (id)` where id is the first number for each reminder above.\nTo clear all reminders, use `delreminder` with the `-a` switch."
return out, nil
},
@@ -132,20 +138,14 @@ var cmds = []*commands.YAGCommand{
CmdCategory: commands.CategoryTool,
Name: "CReminders",
Aliases: []string{"channelreminders"},
- Description: "Lists reminders in channel, only users with 'manage channel' permissions can use this.",
+ Description: "Lists reminders in channel",
+ RequireDiscordPerms: []int64{discordgo.PermissionManageChannels},
SlashCommandEnabled: true,
DefaultEnabled: true,
IsResponseEphemeral: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
- ok, err := bot.AdminOrPermMS(parsed.GuildData.GS.ID, parsed.ChannelID, parsed.GuildData.MS, discordgo.PermissionManageChannels)
- if err != nil {
- return nil, err
- }
- if !ok {
- return "You do not have access to this command (requires manage channel permission)", nil
- }
-
- currentReminders, err := GetChannelReminders(parsed.ChannelID)
+ cid := discordgo.StrID(parsed.ChannelID)
+ currentReminders, err := models.Reminders(models.ReminderWhere.ChannelID.EQ(cid)).AllG(parsed.Context())
if err != nil {
return nil, err
}
@@ -155,7 +155,7 @@ var cmds = []*commands.YAGCommand{
}
out := "Reminders in this channel:\n"
- out += stringReminders(currentReminders, true)
+ out += DisplayReminders(currentReminders, ModeDisplayChannelReminders)
out += "\nRemove a reminder with `delreminder/rmreminder (id)` where id is the first number for each reminder above"
return out, nil
},
@@ -177,17 +177,13 @@ var cmds = []*commands.YAGCommand{
DefaultEnabled: true,
IsResponseEphemeral: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
- var reminder Reminder
-
- clearAll := parsed.Switch("a").Value != nil && parsed.Switch("a").Value.(bool)
- if clearAll {
- db := common.GORM.Where("user_id = ?", parsed.Author.ID).Delete(&reminder)
- err := db.Error
+ if clearAll := parsed.Switch("a").Bool(); clearAll {
+ uid := discordgo.StrID(parsed.Author.ID)
+ count, err := models.Reminders(models.ReminderWhere.UserID.EQ(uid)).DeleteAllG(parsed.Context(), false /* hardDelete */)
if err != nil {
return "Error clearing reminders", err
}
- count := db.RowsAffected
if count == 0 {
return "No reminders to clear", nil
}
@@ -198,20 +194,22 @@ var cmds = []*commands.YAGCommand{
return "No reminder ID provided", nil
}
- err := common.GORM.Where(parsed.Args[0].Int()).First(&reminder).Error
+ reminder, err := models.FindReminderG(parsed.Context(), parsed.Args[0].Int())
if err != nil {
- if err == gorm.ErrRecordNotFound {
- return "No reminder by that id found", nil
+ if err == sql.ErrNoRows {
+ return "No reminder by that ID found", nil
}
return "Error retrieving reminder", err
}
- // Check perms
+ // check perms
if reminder.UserID != discordgo.StrID(parsed.Author.ID) {
if reminder.GuildID != parsed.GuildData.GS.ID {
return "You can only delete reminders that are not your own in the guild the reminder was originally created", nil
}
- ok, err := bot.AdminOrPermMS(reminder.GuildID, reminder.ChannelIDInt(), parsed.GuildData.MS, discordgo.PermissionManageChannels)
+
+ cid, _ := discordgo.ParseID(reminder.ChannelID)
+ ok, err := bot.AdminOrPermMS(reminder.GuildID, cid, parsed.GuildData.MS, discordgo.PermissionManageChannels)
if err != nil {
return nil, err
}
@@ -220,70 +218,33 @@ var cmds = []*commands.YAGCommand{
}
}
- // Do the actual deletion
- err = common.GORM.Delete(reminder).Error
- if err != nil {
- return nil, err
- }
-
- // Check if we should remove the scheduled event
- currentReminders, err := GetUserReminders(reminder.UserIDInt())
+ // just deleting from database is enough; we need not delete the
+ // scheduled event since the handler will check database
+ _, err = reminder.DeleteG(parsed.Context(), false /* hardDelete */)
if err != nil {
return nil, err
}
- delMsg := fmt.Sprintf("Deleted reminder **#%d**: '%s'", reminder.ID, limitString(reminder.Message))
-
- // If there is another reminder with the same timestamp, do not remove the scheduled event
- for _, v := range currentReminders {
- if v.When == reminder.When {
- return delMsg, nil
- }
- }
-
- return delMsg, nil
+ return fmt.Sprintf("Deleted reminder **#%d**: '%s'", reminder.ID, CutReminderShort(reminder.Message)), nil
},
},
}
-func stringReminders(reminders []*Reminder, displayUsernames bool) string {
- out := ""
- for _, v := range reminders {
- parsedCID, _ := strconv.ParseInt(v.ChannelID, 10, 64)
-
- t := time.Unix(v.When, 0)
- tUnix := t.Unix()
- timeFromNow := common.HumanizeTime(common.DurationPrecisionMinutes, t)
- if !displayUsernames {
- channel := "<#" + discordgo.StrID(parsedCID) + ">"
- out += fmt.Sprintf("**%d**: %s: '%s' - %s from now ()\n", v.ID, channel, limitString(v.Message), timeFromNow, tUnix)
- } else {
- member, _ := bot.GetMember(v.GuildID, v.UserIDInt())
- username := "Unknown user"
- if member != nil {
- username = member.User.Username
- }
- out += fmt.Sprintf("**%d**: %s: '%s' - %s from now ()\n", v.ID, username, limitString(v.Message), timeFromNow, tUnix)
- }
- }
- return out
-}
-
func checkUserScheduledEvent(evt *seventsmodels.ScheduledEvent, data interface{}) (retry bool, err error) {
- // !important! the evt.GuildID can be 1 in cases where it was migrated from the legacy scheduled event system
+ // IMPORTANT: evt.GuildID can be 1 in cases where it was migrated from the
+ // legacy scheduled event system.
- userID := *data.(*int64)
-
- reminders, err := GetUserReminders(userID)
+ userID := discordgo.StrID(*data.(*int64))
+ reminders, err := models.Reminders(models.ReminderWhere.UserID.EQ(userID)).AllG(context.Background())
if err != nil {
return true, err
}
- now := time.Now()
- nowUnix := now.Unix()
- for _, v := range reminders {
- if v.When <= nowUnix {
- err := v.Trigger()
+ // TODO: can we move this filtering step into the database query?
+ nowUnix := time.Now().Unix()
+ for _, r := range reminders {
+ if r.When <= nowUnix {
+ err := TriggerReminder(r)
if err != nil {
// possibly try again
return scheduledevents2.CheckDiscordErrRetry(err), err
@@ -295,22 +256,12 @@ func checkUserScheduledEvent(evt *seventsmodels.ScheduledEvent, data interface{}
}
func migrateLegacyScheduledEvents(t time.Time, data string) error {
- split := strings.Split(data, ":")
- if len(split) < 2 {
+ _, userID, ok := strings.Cut(data, ":")
+ if !ok {
logger.Error("invalid check user scheduled event: ", data)
return nil
}
- parsed, _ := strconv.ParseInt(split[1], 10, 64)
-
+ parsed, _ := discordgo.ParseID(userID)
return scheduledevents2.ScheduleEvent("reminders_check_user", 1, t, parsed)
}
-
-func limitString(s string) string {
- if utf8.RuneCountInString(s) < 50 {
- return s
- }
-
- runes := []rune(s)
- return string(runes[:47]) + "..."
-}
diff --git a/reminders/reminders.go b/reminders/reminders.go
index 1b8bcbcd2b..425554ba84 100644
--- a/reminders/reminders.go
+++ b/reminders/reminders.go
@@ -1,27 +1,30 @@
package reminders
import (
- "strconv"
+ "context"
+ "fmt"
+ "strings"
"time"
+ "github.com/botlabs-gg/yagpdb/v2/bot"
"github.com/botlabs-gg/yagpdb/v2/common"
"github.com/botlabs-gg/yagpdb/v2/common/mqueue"
"github.com/botlabs-gg/yagpdb/v2/common/scheduledevents2"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
- "github.com/jinzhu/gorm"
+ "github.com/botlabs-gg/yagpdb/v2/reminders/models"
"github.com/sirupsen/logrus"
+ "github.com/volatiletech/sqlboiler/v4/boil"
)
+//go:generate sqlboiler --no-hooks --add-soft-deletes psql
+
type Plugin struct{}
func RegisterPlugin() {
- err := common.GORM.AutoMigrate(&Reminder{}).Error
- if err != nil {
- panic(err)
- }
-
p := &Plugin{}
common.RegisterPlugin(p)
+
+ common.InitSchemas("reminders", DBSchemas...)
}
func (p *Plugin) PluginInfo() *common.PluginInfo {
@@ -32,31 +35,8 @@ func (p *Plugin) PluginInfo() *common.PluginInfo {
}
}
-type Reminder struct {
- gorm.Model
- UserID string
- ChannelID string
- GuildID int64
- Message string
- When int64
-}
-
-func (r *Reminder) UserIDInt() (i int64) {
- i, _ = strconv.ParseInt(r.UserID, 10, 64)
- return
-}
-
-func (r *Reminder) ChannelIDInt() (i int64) {
- i, _ = strconv.ParseInt(r.ChannelID, 10, 64)
- return
-}
-
-func (r *Reminder) Trigger() error {
- // remove the actual reminder
- rows := common.GORM.Delete(r).RowsAffected
- if rows < 1 {
- logger.Info("Tried to execute multiple reminders at once")
- }
+func TriggerReminder(r *models.Reminder) error {
+ r.DeleteG(context.Background(), false /* hardDelete */)
logger.WithFields(logrus.Fields{"channel": r.ChannelID, "user": r.UserID, "message": r.Message, "id": r.ID}).Info("Triggered reminder")
embed := &discordgo.MessageEmbed{
@@ -64,62 +44,76 @@ func (r *Reminder) Trigger() error {
Description: common.ReplaceServerInvites(r.Message, r.GuildID, "(removed-invite)"),
}
- mqueue.QueueMessage(&mqueue.QueuedElement{
+ channelID, _ := discordgo.ParseID(r.ChannelID)
+ userID, _ := discordgo.ParseID(r.UserID)
+ return mqueue.QueueMessage(&mqueue.QueuedElement{
Source: "reminder",
SourceItemID: "",
GuildID: r.GuildID,
- ChannelID: r.ChannelIDInt(),
+ ChannelID: channelID,
MessageEmbed: embed,
MessageStr: "**Reminder** for <@" + r.UserID + ">",
AllowedMentions: discordgo.AllowedMentions{
- Users: []int64{r.UserIDInt()},
+ Users: []int64{userID},
},
Priority: 10, // above all feeds
})
- return nil
-}
-
-func GetGuildUserReminder(userID, guildID int64) (results []*Reminder, err error) {
- err = common.GORM.Where(&Reminder{UserID: discordgo.StrID(userID), GuildID: guildID}).Find(&results).Error
- if err == gorm.ErrRecordNotFound {
- err = nil
- }
- return
}
-func GetUserReminders(userID int64) (results []*Reminder, err error) {
- err = common.GORM.Where(&Reminder{UserID: discordgo.StrID(userID)}).Find(&results).Error
- if err == gorm.ErrRecordNotFound {
- err = nil
- }
- return
-}
-
-func GetChannelReminders(channel int64) (results []*Reminder, err error) {
- err = common.GORM.Where(&Reminder{ChannelID: discordgo.StrID(channel)}).Find(&results).Error
- if err == gorm.ErrRecordNotFound {
- err = nil
- }
- return
-}
-
-func NewReminder(userID int64, guildID int64, channelID int64, message string, when time.Time) (*Reminder, error) {
- whenUnix := when.Unix()
- reminder := &Reminder{
+func NewReminder(userID int64, guildID int64, channelID int64, message string, when time.Time) (*models.Reminder, error) {
+ reminder := &models.Reminder{
UserID: discordgo.StrID(userID),
ChannelID: discordgo.StrID(channelID),
Message: message,
- When: whenUnix,
+ When: when.Unix(),
GuildID: guildID,
}
- err := common.GORM.Create(reminder).Error
+ err := reminder.InsertG(context.Background(), boil.Infer())
if err != nil {
return nil, err
}
err = scheduledevents2.ScheduleEvent("reminders_check_user", guildID, when, userID)
- // err = scheduledevents.ScheduleEvent("reminders_check_user:"+strconv.FormatInt(whenUnix, 10), discordgo.StrID(userID), when)
return reminder, err
}
+
+type DisplayRemindersMode int
+
+const (
+ ModeDisplayChannelReminders DisplayRemindersMode = iota
+ ModeDisplayUserReminders
+)
+
+func DisplayReminders(reminders models.ReminderSlice, mode DisplayRemindersMode) string {
+ var out strings.Builder
+ for _, r := range reminders {
+ t := time.Unix(r.When, 0)
+ timeFromNow := common.HumanizeTime(common.DurationPrecisionMinutes, t)
+
+ switch mode {
+ case ModeDisplayChannelReminders:
+ // don't show the channel; do show the user
+ uid, _ := discordgo.ParseID(r.UserID)
+ member, _ := bot.GetMember(r.GuildID, uid)
+ username := "Unknown user"
+ if member != nil {
+ username = member.User.Username
+ }
+
+ fmt.Fprintf(&out, "**%d**: %s: '%s' - %s from now ()\n", r.ID, username, CutReminderShort(r.Message), timeFromNow, t.Unix())
+
+ case ModeDisplayUserReminders:
+ // do show the channel; don't show the user
+ channel := "<#" + r.ChannelID + ">"
+ fmt.Fprintf(&out, "**%d**: %s: '%s' - %s from now ()\n", r.ID, channel, CutReminderShort(r.Message), timeFromNow, t.Unix())
+ }
+ }
+
+ return out.String()
+}
+
+func CutReminderShort(msg string) string {
+ return common.CutStringShort(msg, 50)
+}
diff --git a/reminders/schema.go b/reminders/schema.go
new file mode 100644
index 0000000000..a6990b2bde
--- /dev/null
+++ b/reminders/schema.go
@@ -0,0 +1,57 @@
+package reminders
+
+var DBSchemas = []string{`
+CREATE TABLE IF NOT EXISTS reminders (
+ id SERIAL PRIMARY KEY,
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL,
+ updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
+ deleted_at TIMESTAMP WITH TIME ZONE,
+
+ -- text instead of bigint for legacy compatibility
+ user_id TEXT NOT NULL,
+ channel_id TEXT NOT NULL,
+ guild_id BIGINT NOT NULL,
+ message TEXT NOT NULL,
+ "when" BIGINT NOT NULL
+);
+`, `
+CREATE INDEX IF NOT EXISTS idx_reminders_deleted_at ON reminders(deleted_at);
+`, `
+-- Previous versions of the reputation module used gorm instead of sqlboiler,
+-- which does not add NOT NULL constraints by default. Therefore, ensure the
+-- NOT NULL constraints are present in existing tables as well.
+
+-- The first few columns below have always been set since the reminders plugin was
+-- added, so barring the presence of invalid entries, we can safely add NOT NULL
+-- constraints without error.
+
+ALTER TABLE reminders ALTER COLUMN created_at SET NOT NULL;
+`, `
+ALTER TABLE reminders ALTER COLUMN updated_at SET NOT NULL;
+`, `
+ALTER TABLE reminders ALTER COLUMN user_id SET NOT NULL;
+`, `
+ALTER TABLE reminders ALTER COLUMN channel_id SET NOT NULL;
+`, `
+ALTER TABLE reminders ALTER COLUMN message SET NOT NULL;
+`, `
+ALTER TABLE reminders ALTER COLUMN "when" SET NOT NULL;
+`, `
+DO $$
+BEGIN
+
+-- The guild_id column is more annoying to deal with. When the reminders plugin
+-- was first created, the reminders table did not have a guild_id column -- it
+-- was added later, in October 2018 (9f5ef28). So reminders before then could
+-- plausibly have guild_id = NULL, meaning directly adding the NOT NULL
+-- constraint would fail. But since the maximum offset of a reminder is 1 year,
+-- all such reminders have now expired and so we can just delete them before
+-- adding the constraint.
+
+-- Only run if we haven't added the NOT NULL constraint yet.
+IF EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name='reminders' AND column_name='guild_id' AND is_nullable='YES') THEN
+ DELETE FROM reminders WHERE guild_id IS NULL;
+ ALTER TABLE reminders ALTER COLUMN guild_id SET NOT NULL;
+END IF;
+END $$;
+`}
diff --git a/reminders/sqlboiler.toml b/reminders/sqlboiler.toml
new file mode 100644
index 0000000000..cc4cee83ad
--- /dev/null
+++ b/reminders/sqlboiler.toml
@@ -0,0 +1,15 @@
+add-global-variants = true
+no-hooks = true
+no-tests = true
+
+[psql]
+dbname = "yagpdb"
+host = "localhost"
+user = "postgres"
+pass = "pass"
+sslmode = "disable"
+whitelist = ["reminders"]
+
+[auto-columns]
+created = "created_at"
+updated = "updated_at"
diff --git a/soundboard/transcoder.go b/soundboard/transcoder.go
index cc100581df..810d605d6e 100644
--- a/soundboard/transcoder.go
+++ b/soundboard/transcoder.go
@@ -16,6 +16,7 @@ import (
"github.com/botlabs-gg/yagpdb/v2/common/backgroundworkers"
"github.com/botlabs-gg/yagpdb/v2/lib/dca"
"github.com/botlabs-gg/yagpdb/v2/soundboard/models"
+ "github.com/volatiletech/sqlboiler/v4/boil"
"goji.io/pat"
)
@@ -120,10 +121,14 @@ func handleQueueItem(item string) error {
err = transcodeSound(sound)
if err != nil {
logger.WithError(err).WithField("sound", sound.ID).Error("Failed transcoding sound")
- common.GORM.Model(&sound).Update("Status", TranscodingStatusFailedOther)
+
+ sound.Status = int(TranscodingStatusFailedOther)
+ sound.UpdateG(context.Background(), boil.Whitelist("status"))
+
os.Remove(SoundFilePath(sound.ID, TranscodingStatusReady))
} else {
- common.GORM.Model(&sound).Update("Status", TranscodingStatusReady)
+ sound.Status = int(TranscodingStatusReady)
+ sound.UpdateG(context.Background(), boil.Whitelist("status"))
}
err = os.Remove(SoundFilePath(sound.ID, TranscodingStatusQueued))
diff --git a/stdcommands/topcommands/topcommands.go b/stdcommands/topcommands/topcommands.go
index 657f1d5aa0..75141b45b5 100644
--- a/stdcommands/topcommands/topcommands.go
+++ b/stdcommands/topcommands/topcommands.go
@@ -26,17 +26,31 @@ func cmdFuncTopCommands(data *dcmd.Data) (interface{}, error) {
hours := data.Args[0].Int()
within := time.Now().Add(time.Duration(-hours) * time.Hour)
- var results []*TopCommandsResult
- err := common.GORM.Table(common.LoggedExecutedCommand{}.TableName()).Select("command, COUNT(id)").Where("created_at > ?", within).Group("command").Order("count(id) desc").Scan(&results).Error
+ const q = `
+SELECT command, COUNT(id)
+FROM executed_commands
+WHERE created_at > $1
+GROUP BY command
+ORDER BY COUNT(id) DESC;
+`
+ rows, err := common.PQ.Query(q, within)
if err != nil {
return nil, err
}
+ defer rows.Close()
out := fmt.Sprintf("```\nCommand stats from now to %d hour(s) ago\n# Total - Command\n", hours)
total := 0
- for k, result := range results {
- out += fmt.Sprintf("#%02d: %5d - %s\n", k+1, result.Count, result.Command)
- total += result.Count
+ for k := 1; rows.Next(); k++ {
+ var command string
+ var count int
+ err = rows.Scan(&command, &count)
+ if err != nil {
+ return nil, err
+ }
+
+ out += fmt.Sprintf("#%02d: %5d - %s\n", k, count, command)
+ total += count
}
cpm := float64(total) / float64(hours) / 60
@@ -46,8 +60,3 @@ func cmdFuncTopCommands(data *dcmd.Data) (interface{}, error) {
return out, nil
}
-
-type TopCommandsResult struct {
- Command string
- Count int
-}
diff --git a/web/handlers_general.go b/web/handlers_general.go
index 0cfb63cc92..8209a65a91 100644
--- a/web/handlers_general.go
+++ b/web/handlers_general.go
@@ -386,17 +386,12 @@ var commandsRanToday = new(int64)
func pollCommandsRan() {
t := time.NewTicker(time.Minute)
for {
- var result struct {
- Count int64
- }
-
within := time.Now().Add(-24 * time.Hour)
-
- err := common.GORM.Table(common.LoggedExecutedCommand{}.TableName()).Select("COUNT(*)").Where("created_at > ?", within).Scan(&result).Error
+ count, err := models.ExecutedCommands(models.ExecutedCommandWhere.CreatedAt.GT(within)).CountG(context.Background())
if err != nil {
logger.WithError(err).Error("failed counting commands ran today")
} else {
- atomic.StoreInt64(commandsRanToday, result.Count)
+ atomic.StoreInt64(commandsRanToday, count)
}
<-t.C
diff --git a/web/middleware.go b/web/middleware.go
index 013524ba19..faca58e5a2 100644
--- a/web/middleware.go
+++ b/web/middleware.go
@@ -24,6 +24,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/sirupsen/logrus"
+ "github.com/volatiletech/null/v8"
"goji.io/pat"
)
@@ -552,6 +553,12 @@ func FormParserMW(inner http.Handler, dst interface{}) http.Handler {
// Decode the form into the destination struct
decoded := reflect.New(typ).Interface()
decoder := schema.NewDecoder()
+ decoder.RegisterConverter(null.Int64{}, func(value string) reflect.Value {
+ if v, err := strconv.ParseInt(value, 10, 64); err == nil {
+ return reflect.ValueOf(null.Int64From(v))
+ }
+ return reflect.Value{}
+ })
decoder.IgnoreUnknownKeys(true)
err = decoder.Decode(decoded, r.Form)
diff --git a/web/validation.go b/web/validation.go
index 832243bb95..d60d869763 100644
--- a/web/validation.go
+++ b/web/validation.go
@@ -25,7 +25,6 @@ package web
//
// if the struct also implements CustomValidator then that will also be ran
import (
- "database/sql"
"errors"
"fmt"
"reflect"
@@ -40,6 +39,8 @@ import (
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/lib/dstate"
"github.com/lib/pq"
+ "github.com/volatiletech/null/v8"
+ "github.com/volatiletech/sqlboiler/v4/types"
)
type CustomValidator interface {
@@ -122,12 +123,11 @@ func ValidateForm(guild *dstate.GuildSet, tmpl TemplateData, form interface{}) b
if err == nil && !keep {
vField.SetInt(0)
}
- case sql.NullInt64:
+ case null.Int64:
var keep bool
- var newNullInt sql.NullInt64
keep, err = ValidateIntField(cv.Int64, validationTag, guild, false)
if err == nil && !keep {
- vField.Set(reflect.ValueOf(newNullInt))
+ vField.Set(reflect.ValueOf(null.Int64{}))
}
case float64:
min, max, onlyMin := readMinMax(validationTag)
@@ -171,6 +171,14 @@ func ValidateForm(guild *dstate.GuildSet, tmpl TemplateData, form interface{}) b
}
vField.Set(reflect.ValueOf(pq.Int64Array(newSlice)))
+ case types.Int64Array:
+ newSlice, e := ValidateIntSliceField(cv, validationTag, guild)
+ if e != nil {
+ err = e
+ break
+ }
+
+ vField.Set(reflect.ValueOf(types.Int64Array(newSlice)))
default:
// Recurse if it's another struct
switch tField.Type.Kind() {
diff --git a/youtube/bot.go b/youtube/bot.go
index 08c0a224e9..c8ab0a27a8 100644
--- a/youtube/bot.go
+++ b/youtube/bot.go
@@ -1,39 +1,39 @@
package youtube
import (
+ "context"
"fmt"
"github.com/botlabs-gg/yagpdb/v2/common"
+ "github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
+ "github.com/botlabs-gg/yagpdb/v2/youtube/models"
"github.com/mediocregopher/radix/v3"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
)
func (p *Plugin) Status() (string, string) {
var unique int
common.RedisPool.Do(radix.Cmd(&unique, "ZCARD", RedisKeyWebSubChannels))
- var numChannels int
- common.GORM.Model(&ChannelSubscription{}).Count(&numChannels)
+ total, _ := models.YoutubeChannelSubscriptions().CountG(context.Background())
- return "Unique/Total", fmt.Sprintf("%d/%d", unique, numChannels)
+ return "Unique/Total", fmt.Sprintf("%d/%d", unique, total)
}
func (p *Plugin) OnRemovedPremiumGuild(guildID int64) error {
- logger.WithField("guild_id", guildID).Infof("Removed Excess Youtube Feeds")
- feeds := make([]ChannelSubscription, 0)
- err := common.GORM.Model(&ChannelSubscription{}).Where(`guild_id = ? and enabled = ?`, guildID, common.BoolToPointer(true)).Offset(GuildMaxFeeds).Order(
- "id desc",
- ).Find(&feeds).Error
+ numDisabled, err := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.GuildID.EQ(discordgo.StrID(guildID)),
+ models.YoutubeChannelSubscriptionWhere.Enabled.EQ(true),
+
+ qm.Offset(GuildMaxFeeds),
+ qm.OrderBy("id DESC"),
+ ).UpdateAllG(context.Background(), models.M{"enabled": false})
+
if err != nil {
- logger.WithError(err).Errorf("failed getting feed ids for guild_id %d", guildID)
+ logger.WithError(err).WithField("guild", guildID).Error("failed disabling excess feeds")
return err
}
- if len(feeds) > 0 {
- err = common.GORM.Model(&feeds).Update(ChannelSubscription{Enabled: common.BoolToPointer(false)}).Error
- if err != nil {
- logger.WithError(err).Errorf("failed getting feed ids for guild_id %d", guildID)
- return err
- }
- }
+ logger.WithField("guild", guildID).Infof("disabled %d excess feeds", numDisabled)
return nil
}
diff --git a/youtube/feed.go b/youtube/feed.go
index 7ca7dc37ca..78974f4125 100644
--- a/youtube/feed.go
+++ b/youtube/feed.go
@@ -2,6 +2,7 @@ package youtube
import (
"context"
+ "database/sql"
"errors"
"fmt"
"math"
@@ -19,9 +20,10 @@ import (
"github.com/botlabs-gg/yagpdb/v2/feeds"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/web/discorddata"
- "github.com/jinzhu/gorm"
+ "github.com/botlabs-gg/yagpdb/v2/youtube/models"
"github.com/mediocregopher/radix/v3"
"github.com/prometheus/client_golang/prometheus"
+ "github.com/volatiletech/sqlboiler/v4/boil"
"google.golang.org/api/option"
"google.golang.org/api/youtube/v3"
)
@@ -185,11 +187,10 @@ func (p *Plugin) syncWebSubs() {
}))
}
-func (p *Plugin) sendNewVidMessage(sub *ChannelSubscription, video *youtube.Video) {
+func (p *Plugin) sendNewVidMessage(sub *models.YoutubeChannelSubscription, video *youtube.Video) {
parsedChannel, _ := strconv.ParseInt(sub.ChannelID, 10, 64)
parsedGuild, _ := strconv.ParseInt(sub.GuildID, 10, 64)
videoUrl := "https://www.youtube.com/watch?v=" + video.Id
- var announcement YoutubeAnnouncements
var content string
switch video.Snippet.LiveBroadcastContent {
@@ -204,11 +205,11 @@ func (p *Plugin) sendNewVidMessage(sub *ChannelSubscription, video *youtube.Vide
}
parseMentions := []discordgo.AllowedMentionType{}
- err := common.GORM.Model(&YoutubeAnnouncements{}).Where("guild_id = ?", parsedGuild).First(&announcement).Error
+ announcement, err := models.FindYoutubeAnnouncementG(context.Background(), parsedGuild)
hasCustomAnnouncement := true
if err != nil {
hasCustomAnnouncement = false
- if errors.Is(err, gorm.ErrRecordNotFound) {
+ if err == sql.ErrNoRows {
logger.WithError(err).Debugf("Custom announcement doesn't exist for guild_id %d", parsedGuild)
} else {
logger.WithError(err).Errorf("Failed fetching custom announcement for guild_id %d", parsedGuild)
@@ -217,7 +218,7 @@ func (p *Plugin) sendNewVidMessage(sub *ChannelSubscription, video *youtube.Vide
var publishAnnouncement bool
- if hasCustomAnnouncement && *announcement.Enabled && len(announcement.Message) > 0 {
+ if hasCustomAnnouncement && announcement.Enabled && len(announcement.Message) > 0 {
guildState, err := discorddata.GetFullGuild(parsedGuild)
if err != nil {
logger.WithError(err).Errorf("Failed to get guild state for guild_id %d", parsedGuild)
@@ -301,9 +302,10 @@ var (
ErrIDNotFound = errors.New("ID not found")
)
-func SubsForChannel(channel string) (result []*ChannelSubscription, err error) {
- err = common.GORM.Where("youtube_channel_id = ?", channel).Find(&result).Error
- return
+func SubsForChannel(channel string) (models.YoutubeChannelSubscriptionSlice, error) {
+ return models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.YoutubeChannelID.EQ(channel),
+ ).AllG(context.Background())
}
var (
@@ -447,19 +449,19 @@ func (p *Plugin) parseYtVideoID(parse string) (id ytChannelID, err error) {
}
}
-func (p *Plugin) AddFeed(guildID, discordChannelID int64, ytChannel *youtube.Channel, mentionEveryone bool, publishLivestream bool, publishShorts bool, mentionRoles []int64) (*ChannelSubscription, error) {
+func (p *Plugin) AddFeed(guildID, discordChannelID int64, ytChannel *youtube.Channel, mentionEveryone bool, publishLivestream bool, publishShorts bool, mentionRoles []int64) (*models.YoutubeChannelSubscription, error) {
if mentionEveryone && len(mentionRoles) > 0 {
mentionRoles = make([]int64, 0)
}
- sub := &ChannelSubscription{
+ sub := &models.YoutubeChannelSubscription{
GuildID: discordgo.StrID(guildID),
ChannelID: discordgo.StrID(discordChannelID),
MentionEveryone: mentionEveryone,
MentionRoles: mentionRoles,
- PublishLivestream: &publishLivestream,
- PublishShorts: &publishShorts,
- Enabled: common.BoolToPointer(true),
+ PublishLivestream: publishLivestream,
+ PublishShorts: publishShorts,
+ Enabled: true,
}
sub.YoutubeChannelName = ytChannel.Snippet.Title
@@ -471,7 +473,7 @@ func (p *Plugin) AddFeed(guildID, discordChannelID int64, ytChannel *youtube.Cha
}
defer common.UnlockRedisKey(RedisChannelsLockKey)
- err = common.GORM.Create(sub).Error
+ err = sub.InsertG(context.Background(), boil.Whitelist("guild_id", "channel_id", "mention_everyone", "mention_roles", "publish_livestream", "publish_shorts", "enabled"))
if err != nil {
return nil, err
}
@@ -488,8 +490,9 @@ func (p *Plugin) MaybeRemoveChannelWatch(channel string) {
}
defer common.UnlockRedisKey(RedisChannelsLockKey)
- var count int
- err = common.GORM.Model(&ChannelSubscription{}).Where("youtube_channel_id = ?", channel).Count(&count).Error
+ count, err := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.YoutubeChannelID.EQ(channel),
+ ).CountG(context.Background())
if err != nil || count > 0 {
if err != nil {
logger.WithError(err).WithField("yt_channel", channel).Error("Failed getting sub count")
@@ -650,7 +653,7 @@ func (p *Plugin) isShortsRedirect(videoId string) bool {
return resp.StatusCode == 200
}
-func (p *Plugin) postVideo(subs []*ChannelSubscription, publishedAt time.Time, video *youtube.Video, channelID string) error {
+func (p *Plugin) postVideo(subs models.YoutubeChannelSubscriptionSlice, publishedAt time.Time, video *youtube.Video, channelID string) error {
// add video to list of published videos
err := common.RedisPool.Do(radix.FlatCmd(nil, "ZADD", RedisKeyPublishedVideoList, publishedAt.Unix(), video.Id))
if err != nil {
@@ -666,13 +669,13 @@ func (p *Plugin) postVideo(subs []*ChannelSubscription, publishedAt time.Time, v
isShorts := false
for _, sub := range subs {
- if *sub.Enabled {
- if (isLivestream || isUpcoming) && !*sub.PublishLivestream {
+ if sub.Enabled {
+ if (isLivestream || isUpcoming) && !sub.PublishLivestream {
continue
}
//no need to check for shorts for a livestream
- if !(isLivestream || isUpcoming) && !*sub.PublishShorts {
+ if !(isLivestream || isUpcoming) && !sub.PublishShorts {
//check if a video is a short only when seeing the first shorts disabled subscription
//and cache in "isShorts" to reduce requests to youtube to check for shorts.
if !isShortsCheckDone {
@@ -691,9 +694,10 @@ func (p *Plugin) postVideo(subs []*ChannelSubscription, publishedAt time.Time, v
return nil
}
-func (p *Plugin) getRemoveSubs(channelID string) ([]*ChannelSubscription, error) {
- var subs []*ChannelSubscription
- err := common.GORM.Where("youtube_channel_id = ?", channelID).Find(&subs).Error
+func (p *Plugin) getRemoveSubs(channelID string) (models.YoutubeChannelSubscriptionSlice, error) {
+ subs, err := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.YoutubeChannelID.EQ(channelID),
+ ).AllG(context.Background())
if err != nil {
return subs, err
}
diff --git a/youtube/models/boil_queries.go b/youtube/models/boil_queries.go
new file mode 100644
index 0000000000..20c2563fdb
--- /dev/null
+++ b/youtube/models/boil_queries.go
@@ -0,0 +1,38 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "regexp"
+
+ "github.com/volatiletech/sqlboiler/v4/drivers"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+)
+
+var dialect = drivers.Dialect{
+ LQ: 0x22,
+ RQ: 0x22,
+
+ UseIndexPlaceholders: true,
+ UseLastInsertID: false,
+ UseSchema: false,
+ UseDefaultKeyword: true,
+ UseAutoColumns: false,
+ UseTopClause: false,
+ UseOutputClause: false,
+ UseCaseWhenExistsClause: false,
+}
+
+// This is a dummy variable to prevent unused regexp import error
+var _ = ®exp.Regexp{}
+
+// NewQuery initializes a new Query using the passed in QueryMods
+func NewQuery(mods ...qm.QueryMod) *queries.Query {
+ q := &queries.Query{}
+ queries.SetDialect(q, &dialect)
+ qm.Apply(q, mods...)
+
+ return q
+}
diff --git a/youtube/models/boil_table_names.go b/youtube/models/boil_table_names.go
new file mode 100644
index 0000000000..27d63986a8
--- /dev/null
+++ b/youtube/models/boil_table_names.go
@@ -0,0 +1,12 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+var TableNames = struct {
+ YoutubeAnnouncements string
+ YoutubeChannelSubscriptions string
+}{
+ YoutubeAnnouncements: "youtube_announcements",
+ YoutubeChannelSubscriptions: "youtube_channel_subscriptions",
+}
diff --git a/youtube/models/boil_types.go b/youtube/models/boil_types.go
new file mode 100644
index 0000000000..02a6fdfdc5
--- /dev/null
+++ b/youtube/models/boil_types.go
@@ -0,0 +1,52 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "strconv"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/strmangle"
+)
+
+// M type is for providing columns and column values to UpdateAll.
+type M map[string]interface{}
+
+// ErrSyncFail occurs during insert when the record could not be retrieved in
+// order to populate default value information. This usually happens when LastInsertId
+// fails or there was a primary key configuration that was not resolvable.
+var ErrSyncFail = errors.New("models: failed to synchronize data after insert")
+
+type insertCache struct {
+ query string
+ retQuery string
+ valueMapping []uint64
+ retMapping []uint64
+}
+
+type updateCache struct {
+ query string
+ valueMapping []uint64
+}
+
+func makeCacheKey(cols boil.Columns, nzDefaults []string) string {
+ buf := strmangle.GetBuffer()
+
+ buf.WriteString(strconv.Itoa(cols.Kind))
+ for _, w := range cols.Cols {
+ buf.WriteString(w)
+ }
+
+ if len(nzDefaults) != 0 {
+ buf.WriteByte('.')
+ }
+ for _, nz := range nzDefaults {
+ buf.WriteString(nz)
+ }
+
+ str := buf.String()
+ strmangle.PutBuffer(buf)
+ return str
+}
diff --git a/youtube/models/boil_view_names.go b/youtube/models/boil_view_names.go
new file mode 100644
index 0000000000..01504d82bf
--- /dev/null
+++ b/youtube/models/boil_view_names.go
@@ -0,0 +1,7 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+var ViewNames = struct {
+}{}
diff --git a/youtube/models/psql_upsert.go b/youtube/models/psql_upsert.go
new file mode 100644
index 0000000000..07602da9c5
--- /dev/null
+++ b/youtube/models/psql_upsert.go
@@ -0,0 +1,99 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/volatiletech/sqlboiler/v4/drivers"
+ "github.com/volatiletech/strmangle"
+)
+
+type UpsertOptions struct {
+ conflictTarget string
+ updateSet string
+}
+
+type UpsertOptionFunc func(o *UpsertOptions)
+
+func UpsertConflictTarget(conflictTarget string) UpsertOptionFunc {
+ return func(o *UpsertOptions) {
+ o.conflictTarget = conflictTarget
+ }
+}
+
+func UpsertUpdateSet(updateSet string) UpsertOptionFunc {
+ return func(o *UpsertOptions) {
+ o.updateSet = updateSet
+ }
+}
+
+// buildUpsertQueryPostgres builds a SQL statement string using the upsertData provided.
+func buildUpsertQueryPostgres(dia drivers.Dialect, tableName string, updateOnConflict bool, ret, update, conflict, whitelist []string, opts ...UpsertOptionFunc) string {
+ conflict = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, conflict)
+ whitelist = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, whitelist)
+ ret = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, ret)
+
+ upsertOpts := &UpsertOptions{}
+ for _, o := range opts {
+ o(upsertOpts)
+ }
+
+ buf := strmangle.GetBuffer()
+ defer strmangle.PutBuffer(buf)
+
+ columns := "DEFAULT VALUES"
+ if len(whitelist) != 0 {
+ columns = fmt.Sprintf("(%s) VALUES (%s)",
+ strings.Join(whitelist, ", "),
+ strmangle.Placeholders(dia.UseIndexPlaceholders, len(whitelist), 1, 1))
+ }
+
+ fmt.Fprintf(
+ buf,
+ "INSERT INTO %s %s ON CONFLICT ",
+ tableName,
+ columns,
+ )
+
+ if upsertOpts.conflictTarget != "" {
+ buf.WriteString(upsertOpts.conflictTarget)
+ } else if len(conflict) != 0 {
+ buf.WriteByte('(')
+ buf.WriteString(strings.Join(conflict, ", "))
+ buf.WriteByte(')')
+ }
+ buf.WriteByte(' ')
+
+ if !updateOnConflict || len(update) == 0 {
+ buf.WriteString("DO NOTHING")
+ } else {
+ buf.WriteString("DO UPDATE SET ")
+
+ if upsertOpts.updateSet != "" {
+ buf.WriteString(upsertOpts.updateSet)
+ } else {
+ for i, v := range update {
+ if len(v) == 0 {
+ continue
+ }
+ if i != 0 {
+ buf.WriteByte(',')
+ }
+ quoted := strmangle.IdentQuote(dia.LQ, dia.RQ, v)
+ buf.WriteString(quoted)
+ buf.WriteString(" = EXCLUDED.")
+ buf.WriteString(quoted)
+ }
+ }
+ }
+
+ if len(ret) != 0 {
+ buf.WriteString(" RETURNING ")
+ buf.WriteString(strings.Join(ret, ", "))
+ }
+
+ return buf.String()
+}
diff --git a/youtube/models/youtube_announcements.go b/youtube/models/youtube_announcements.go
new file mode 100644
index 0000000000..9429a96304
--- /dev/null
+++ b/youtube/models/youtube_announcements.go
@@ -0,0 +1,831 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+ "github.com/volatiletech/sqlboiler/v4/queries/qmhelper"
+ "github.com/volatiletech/strmangle"
+)
+
+// YoutubeAnnouncement is an object representing the database table.
+type YoutubeAnnouncement struct {
+ GuildID int64 `boil:"guild_id" json:"guild_id" toml:"guild_id" yaml:"guild_id"`
+ Message string `boil:"message" json:"message" toml:"message" yaml:"message"`
+ Enabled bool `boil:"enabled" json:"enabled" toml:"enabled" yaml:"enabled"`
+
+ R *youtubeAnnouncementR `boil:"-" json:"-" toml:"-" yaml:"-"`
+ L youtubeAnnouncementL `boil:"-" json:"-" toml:"-" yaml:"-"`
+}
+
+var YoutubeAnnouncementColumns = struct {
+ GuildID string
+ Message string
+ Enabled string
+}{
+ GuildID: "guild_id",
+ Message: "message",
+ Enabled: "enabled",
+}
+
+var YoutubeAnnouncementTableColumns = struct {
+ GuildID string
+ Message string
+ Enabled string
+}{
+ GuildID: "youtube_announcements.guild_id",
+ Message: "youtube_announcements.message",
+ Enabled: "youtube_announcements.enabled",
+}
+
+// Generated where
+
+type whereHelperint64 struct{ field string }
+
+func (w whereHelperint64) EQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperint64) NEQ(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperint64) LT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperint64) LTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperint64) GT(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperint64) GTE(x int64) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperint64) IN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperint64) NIN(slice []int64) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+type whereHelperstring struct{ field string }
+
+func (w whereHelperstring) EQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperstring) NEQ(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperstring) LT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperstring) LTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperstring) GT(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperstring) GTE(x string) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperstring) LIKE(x string) qm.QueryMod { return qm.Where(w.field+" LIKE ?", x) }
+func (w whereHelperstring) NLIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT LIKE ?", x) }
+func (w whereHelperstring) ILIKE(x string) qm.QueryMod { return qm.Where(w.field+" ILIKE ?", x) }
+func (w whereHelperstring) NILIKE(x string) qm.QueryMod { return qm.Where(w.field+" NOT ILIKE ?", x) }
+func (w whereHelperstring) IN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperstring) NIN(slice []string) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+type whereHelperbool struct{ field string }
+
+func (w whereHelperbool) EQ(x bool) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperbool) NEQ(x bool) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperbool) LT(x bool) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperbool) LTE(x bool) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperbool) GT(x bool) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperbool) GTE(x bool) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+
+var YoutubeAnnouncementWhere = struct {
+ GuildID whereHelperint64
+ Message whereHelperstring
+ Enabled whereHelperbool
+}{
+ GuildID: whereHelperint64{field: "\"youtube_announcements\".\"guild_id\""},
+ Message: whereHelperstring{field: "\"youtube_announcements\".\"message\""},
+ Enabled: whereHelperbool{field: "\"youtube_announcements\".\"enabled\""},
+}
+
+// YoutubeAnnouncementRels is where relationship names are stored.
+var YoutubeAnnouncementRels = struct {
+}{}
+
+// youtubeAnnouncementR is where relationships are stored.
+type youtubeAnnouncementR struct {
+}
+
+// NewStruct creates a new relationship struct
+func (*youtubeAnnouncementR) NewStruct() *youtubeAnnouncementR {
+ return &youtubeAnnouncementR{}
+}
+
+// youtubeAnnouncementL is where Load methods for each relationship are stored.
+type youtubeAnnouncementL struct{}
+
+var (
+ youtubeAnnouncementAllColumns = []string{"guild_id", "message", "enabled"}
+ youtubeAnnouncementColumnsWithoutDefault = []string{"guild_id", "message"}
+ youtubeAnnouncementColumnsWithDefault = []string{"enabled"}
+ youtubeAnnouncementPrimaryKeyColumns = []string{"guild_id"}
+ youtubeAnnouncementGeneratedColumns = []string{}
+)
+
+type (
+ // YoutubeAnnouncementSlice is an alias for a slice of pointers to YoutubeAnnouncement.
+ // This should almost always be used instead of []YoutubeAnnouncement.
+ YoutubeAnnouncementSlice []*YoutubeAnnouncement
+
+ youtubeAnnouncementQuery struct {
+ *queries.Query
+ }
+)
+
+// Cache for insert, update and upsert
+var (
+ youtubeAnnouncementType = reflect.TypeOf(&YoutubeAnnouncement{})
+ youtubeAnnouncementMapping = queries.MakeStructMapping(youtubeAnnouncementType)
+ youtubeAnnouncementPrimaryKeyMapping, _ = queries.BindMapping(youtubeAnnouncementType, youtubeAnnouncementMapping, youtubeAnnouncementPrimaryKeyColumns)
+ youtubeAnnouncementInsertCacheMut sync.RWMutex
+ youtubeAnnouncementInsertCache = make(map[string]insertCache)
+ youtubeAnnouncementUpdateCacheMut sync.RWMutex
+ youtubeAnnouncementUpdateCache = make(map[string]updateCache)
+ youtubeAnnouncementUpsertCacheMut sync.RWMutex
+ youtubeAnnouncementUpsertCache = make(map[string]insertCache)
+)
+
+var (
+ // Force time package dependency for automated UpdatedAt/CreatedAt.
+ _ = time.Second
+ // Force qmhelper dependency for where clause generation (which doesn't
+ // always happen)
+ _ = qmhelper.Where
+)
+
+// OneG returns a single youtubeAnnouncement record from the query using the global executor.
+func (q youtubeAnnouncementQuery) OneG(ctx context.Context) (*YoutubeAnnouncement, error) {
+ return q.One(ctx, boil.GetContextDB())
+}
+
+// One returns a single youtubeAnnouncement record from the query.
+func (q youtubeAnnouncementQuery) One(ctx context.Context, exec boil.ContextExecutor) (*YoutubeAnnouncement, error) {
+ o := &YoutubeAnnouncement{}
+
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Bind(ctx, exec, o)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: failed to execute a one query for youtube_announcements")
+ }
+
+ return o, nil
+}
+
+// AllG returns all YoutubeAnnouncement records from the query using the global executor.
+func (q youtubeAnnouncementQuery) AllG(ctx context.Context) (YoutubeAnnouncementSlice, error) {
+ return q.All(ctx, boil.GetContextDB())
+}
+
+// All returns all YoutubeAnnouncement records from the query.
+func (q youtubeAnnouncementQuery) All(ctx context.Context, exec boil.ContextExecutor) (YoutubeAnnouncementSlice, error) {
+ var o []*YoutubeAnnouncement
+
+ err := q.Bind(ctx, exec, &o)
+ if err != nil {
+ return nil, errors.Wrap(err, "models: failed to assign all query results to YoutubeAnnouncement slice")
+ }
+
+ return o, nil
+}
+
+// CountG returns the count of all YoutubeAnnouncement records in the query using the global executor
+func (q youtubeAnnouncementQuery) CountG(ctx context.Context) (int64, error) {
+ return q.Count(ctx, boil.GetContextDB())
+}
+
+// Count returns the count of all YoutubeAnnouncement records in the query.
+func (q youtubeAnnouncementQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to count youtube_announcements rows")
+ }
+
+ return count, nil
+}
+
+// ExistsG checks if the row exists in the table using the global executor.
+func (q youtubeAnnouncementQuery) ExistsG(ctx context.Context) (bool, error) {
+ return q.Exists(ctx, boil.GetContextDB())
+}
+
+// Exists checks if the row exists in the table.
+func (q youtubeAnnouncementQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return false, errors.Wrap(err, "models: failed to check if youtube_announcements exists")
+ }
+
+ return count > 0, nil
+}
+
+// YoutubeAnnouncements retrieves all the records using an executor.
+func YoutubeAnnouncements(mods ...qm.QueryMod) youtubeAnnouncementQuery {
+ mods = append(mods, qm.From("\"youtube_announcements\""))
+ q := NewQuery(mods...)
+ if len(queries.GetSelect(q)) == 0 {
+ queries.SetSelect(q, []string{"\"youtube_announcements\".*"})
+ }
+
+ return youtubeAnnouncementQuery{q}
+}
+
+// FindYoutubeAnnouncementG retrieves a single record by ID.
+func FindYoutubeAnnouncementG(ctx context.Context, guildID int64, selectCols ...string) (*YoutubeAnnouncement, error) {
+ return FindYoutubeAnnouncement(ctx, boil.GetContextDB(), guildID, selectCols...)
+}
+
+// FindYoutubeAnnouncement retrieves a single record by ID with an executor.
+// If selectCols is empty Find will return all columns.
+func FindYoutubeAnnouncement(ctx context.Context, exec boil.ContextExecutor, guildID int64, selectCols ...string) (*YoutubeAnnouncement, error) {
+ youtubeAnnouncementObj := &YoutubeAnnouncement{}
+
+ sel := "*"
+ if len(selectCols) > 0 {
+ sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",")
+ }
+ query := fmt.Sprintf(
+ "select %s from \"youtube_announcements\" where \"guild_id\"=$1", sel,
+ )
+
+ q := queries.Raw(query, guildID)
+
+ err := q.Bind(ctx, exec, youtubeAnnouncementObj)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: unable to select from youtube_announcements")
+ }
+
+ return youtubeAnnouncementObj, nil
+}
+
+// InsertG a single record. See Insert for whitelist behavior description.
+func (o *YoutubeAnnouncement) InsertG(ctx context.Context, columns boil.Columns) error {
+ return o.Insert(ctx, boil.GetContextDB(), columns)
+}
+
+// Insert a single record using an executor.
+// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts.
+func (o *YoutubeAnnouncement) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error {
+ if o == nil {
+ return errors.New("models: no youtube_announcements provided for insertion")
+ }
+
+ var err error
+
+ nzDefaults := queries.NonZeroDefaultSet(youtubeAnnouncementColumnsWithDefault, o)
+
+ key := makeCacheKey(columns, nzDefaults)
+ youtubeAnnouncementInsertCacheMut.RLock()
+ cache, cached := youtubeAnnouncementInsertCache[key]
+ youtubeAnnouncementInsertCacheMut.RUnlock()
+
+ if !cached {
+ wl, returnColumns := columns.InsertColumnSet(
+ youtubeAnnouncementAllColumns,
+ youtubeAnnouncementColumnsWithDefault,
+ youtubeAnnouncementColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ cache.valueMapping, err = queries.BindMapping(youtubeAnnouncementType, youtubeAnnouncementMapping, wl)
+ if err != nil {
+ return err
+ }
+ cache.retMapping, err = queries.BindMapping(youtubeAnnouncementType, youtubeAnnouncementMapping, returnColumns)
+ if err != nil {
+ return err
+ }
+ if len(wl) != 0 {
+ cache.query = fmt.Sprintf("INSERT INTO \"youtube_announcements\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1))
+ } else {
+ cache.query = "INSERT INTO \"youtube_announcements\" %sDEFAULT VALUES%s"
+ }
+
+ var queryOutput, queryReturning string
+
+ if len(cache.retMapping) != 0 {
+ queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\""))
+ }
+
+ cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+
+ if err != nil {
+ return errors.Wrap(err, "models: unable to insert into youtube_announcements")
+ }
+
+ if !cached {
+ youtubeAnnouncementInsertCacheMut.Lock()
+ youtubeAnnouncementInsertCache[key] = cache
+ youtubeAnnouncementInsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// UpdateG a single YoutubeAnnouncement record using the global executor.
+// See Update for more documentation.
+func (o *YoutubeAnnouncement) UpdateG(ctx context.Context, columns boil.Columns) (int64, error) {
+ return o.Update(ctx, boil.GetContextDB(), columns)
+}
+
+// Update uses an executor to update the YoutubeAnnouncement.
+// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates.
+// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records.
+func (o *YoutubeAnnouncement) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) {
+ var err error
+ key := makeCacheKey(columns, nil)
+ youtubeAnnouncementUpdateCacheMut.RLock()
+ cache, cached := youtubeAnnouncementUpdateCache[key]
+ youtubeAnnouncementUpdateCacheMut.RUnlock()
+
+ if !cached {
+ wl := columns.UpdateColumnSet(
+ youtubeAnnouncementAllColumns,
+ youtubeAnnouncementPrimaryKeyColumns,
+ )
+
+ if !columns.IsWhitelist() {
+ wl = strmangle.SetComplement(wl, []string{"created_at"})
+ }
+ if len(wl) == 0 {
+ return 0, errors.New("models: unable to update youtube_announcements, could not build whitelist")
+ }
+
+ cache.query = fmt.Sprintf("UPDATE \"youtube_announcements\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ strmangle.WhereClause("\"", "\"", len(wl)+1, youtubeAnnouncementPrimaryKeyColumns),
+ )
+ cache.valueMapping, err = queries.BindMapping(youtubeAnnouncementType, youtubeAnnouncementMapping, append(wl, youtubeAnnouncementPrimaryKeyColumns...))
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, values)
+ }
+ var result sql.Result
+ result, err = exec.ExecContext(ctx, cache.query, values...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update youtube_announcements row")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by update for youtube_announcements")
+ }
+
+ if !cached {
+ youtubeAnnouncementUpdateCacheMut.Lock()
+ youtubeAnnouncementUpdateCache[key] = cache
+ youtubeAnnouncementUpdateCacheMut.Unlock()
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (q youtubeAnnouncementQuery) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return q.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values.
+func (q youtubeAnnouncementQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ queries.SetUpdate(q.Query, cols)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all for youtube_announcements")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected for youtube_announcements")
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (o YoutubeAnnouncementSlice) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return o.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values, using an executor.
+func (o YoutubeAnnouncementSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ ln := int64(len(o))
+ if ln == 0 {
+ return 0, nil
+ }
+
+ if len(cols) == 0 {
+ return 0, errors.New("models: update all requires at least one column argument")
+ }
+
+ colNames := make([]string, len(cols))
+ args := make([]interface{}, len(cols))
+
+ i := 0
+ for name, value := range cols {
+ colNames[i] = name
+ args[i] = value
+ i++
+ }
+
+ // Append all of the primary key values for each column
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), youtubeAnnouncementPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := fmt.Sprintf("UPDATE \"youtube_announcements\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, colNames),
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, youtubeAnnouncementPrimaryKeyColumns, len(o)))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all in youtubeAnnouncement slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all youtubeAnnouncement")
+ }
+ return rowsAff, nil
+}
+
+// UpsertG attempts an insert, and does an update or ignore on conflict.
+func (o *YoutubeAnnouncement) UpsertG(ctx context.Context, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ return o.Upsert(ctx, boil.GetContextDB(), updateOnConflict, conflictColumns, updateColumns, insertColumns, opts...)
+}
+
+// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
+// See boil.Columns documentation for how to properly use updateColumns and insertColumns.
+func (o *YoutubeAnnouncement) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ if o == nil {
+ return errors.New("models: no youtube_announcements provided for upsert")
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(youtubeAnnouncementColumnsWithDefault, o)
+
+ // Build cache key in-line uglily - mysql vs psql problems
+ buf := strmangle.GetBuffer()
+ if updateOnConflict {
+ buf.WriteByte('t')
+ } else {
+ buf.WriteByte('f')
+ }
+ buf.WriteByte('.')
+ for _, c := range conflictColumns {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(updateColumns.Kind))
+ for _, c := range updateColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(insertColumns.Kind))
+ for _, c := range insertColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ for _, c := range nzDefaults {
+ buf.WriteString(c)
+ }
+ key := buf.String()
+ strmangle.PutBuffer(buf)
+
+ youtubeAnnouncementUpsertCacheMut.RLock()
+ cache, cached := youtubeAnnouncementUpsertCache[key]
+ youtubeAnnouncementUpsertCacheMut.RUnlock()
+
+ var err error
+
+ if !cached {
+ insert, _ := insertColumns.InsertColumnSet(
+ youtubeAnnouncementAllColumns,
+ youtubeAnnouncementColumnsWithDefault,
+ youtubeAnnouncementColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ update := updateColumns.UpdateColumnSet(
+ youtubeAnnouncementAllColumns,
+ youtubeAnnouncementPrimaryKeyColumns,
+ )
+
+ if updateOnConflict && len(update) == 0 {
+ return errors.New("models: unable to upsert youtube_announcements, could not build update column list")
+ }
+
+ ret := strmangle.SetComplement(youtubeAnnouncementAllColumns, strmangle.SetIntersect(insert, update))
+
+ conflict := conflictColumns
+ if len(conflict) == 0 && updateOnConflict && len(update) != 0 {
+ if len(youtubeAnnouncementPrimaryKeyColumns) == 0 {
+ return errors.New("models: unable to upsert youtube_announcements, could not build conflict column list")
+ }
+
+ conflict = make([]string, len(youtubeAnnouncementPrimaryKeyColumns))
+ copy(conflict, youtubeAnnouncementPrimaryKeyColumns)
+ }
+ cache.query = buildUpsertQueryPostgres(dialect, "\"youtube_announcements\"", updateOnConflict, ret, update, conflict, insert, opts...)
+
+ cache.valueMapping, err = queries.BindMapping(youtubeAnnouncementType, youtubeAnnouncementMapping, insert)
+ if err != nil {
+ return err
+ }
+ if len(ret) != 0 {
+ cache.retMapping, err = queries.BindMapping(youtubeAnnouncementType, youtubeAnnouncementMapping, ret)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+ var returns []interface{}
+ if len(cache.retMapping) != 0 {
+ returns = queries.PtrsFromMapping(value, cache.retMapping)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...)
+ if errors.Is(err, sql.ErrNoRows) {
+ err = nil // Postgres doesn't return anything when there's no update
+ }
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+ if err != nil {
+ return errors.Wrap(err, "models: unable to upsert youtube_announcements")
+ }
+
+ if !cached {
+ youtubeAnnouncementUpsertCacheMut.Lock()
+ youtubeAnnouncementUpsertCache[key] = cache
+ youtubeAnnouncementUpsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// DeleteG deletes a single YoutubeAnnouncement record.
+// DeleteG will match against the primary key column to find the record to delete.
+func (o *YoutubeAnnouncement) DeleteG(ctx context.Context) (int64, error) {
+ return o.Delete(ctx, boil.GetContextDB())
+}
+
+// Delete deletes a single YoutubeAnnouncement record with an executor.
+// Delete will match against the primary key column to find the record to delete.
+func (o *YoutubeAnnouncement) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if o == nil {
+ return 0, errors.New("models: no YoutubeAnnouncement provided for delete")
+ }
+
+ args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), youtubeAnnouncementPrimaryKeyMapping)
+ sql := "DELETE FROM \"youtube_announcements\" WHERE \"guild_id\"=$1"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete from youtube_announcements")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by delete for youtube_announcements")
+ }
+
+ return rowsAff, nil
+}
+
+func (q youtubeAnnouncementQuery) DeleteAllG(ctx context.Context) (int64, error) {
+ return q.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all matching rows.
+func (q youtubeAnnouncementQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if q.Query == nil {
+ return 0, errors.New("models: no youtubeAnnouncementQuery provided for delete all")
+ }
+
+ queries.SetDelete(q.Query)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from youtube_announcements")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for youtube_announcements")
+ }
+
+ return rowsAff, nil
+}
+
+// DeleteAllG deletes all rows in the slice.
+func (o YoutubeAnnouncementSlice) DeleteAllG(ctx context.Context) (int64, error) {
+ return o.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all rows in the slice, using an executor.
+func (o YoutubeAnnouncementSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if len(o) == 0 {
+ return 0, nil
+ }
+
+ var args []interface{}
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), youtubeAnnouncementPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "DELETE FROM \"youtube_announcements\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, youtubeAnnouncementPrimaryKeyColumns, len(o))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from youtubeAnnouncement slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for youtube_announcements")
+ }
+
+ return rowsAff, nil
+}
+
+// ReloadG refetches the object from the database using the primary keys.
+func (o *YoutubeAnnouncement) ReloadG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: no YoutubeAnnouncement provided for reload")
+ }
+
+ return o.Reload(ctx, boil.GetContextDB())
+}
+
+// Reload refetches the object from the database
+// using the primary keys with an executor.
+func (o *YoutubeAnnouncement) Reload(ctx context.Context, exec boil.ContextExecutor) error {
+ ret, err := FindYoutubeAnnouncement(ctx, exec, o.GuildID)
+ if err != nil {
+ return err
+ }
+
+ *o = *ret
+ return nil
+}
+
+// ReloadAllG refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *YoutubeAnnouncementSlice) ReloadAllG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: empty YoutubeAnnouncementSlice provided for reload all")
+ }
+
+ return o.ReloadAll(ctx, boil.GetContextDB())
+}
+
+// ReloadAll refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *YoutubeAnnouncementSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error {
+ if o == nil || len(*o) == 0 {
+ return nil
+ }
+
+ slice := YoutubeAnnouncementSlice{}
+ var args []interface{}
+ for _, obj := range *o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), youtubeAnnouncementPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "SELECT \"youtube_announcements\".* FROM \"youtube_announcements\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, youtubeAnnouncementPrimaryKeyColumns, len(*o))
+
+ q := queries.Raw(sql, args...)
+
+ err := q.Bind(ctx, exec, &slice)
+ if err != nil {
+ return errors.Wrap(err, "models: unable to reload all in YoutubeAnnouncementSlice")
+ }
+
+ *o = slice
+
+ return nil
+}
+
+// YoutubeAnnouncementExistsG checks if the YoutubeAnnouncement row exists.
+func YoutubeAnnouncementExistsG(ctx context.Context, guildID int64) (bool, error) {
+ return YoutubeAnnouncementExists(ctx, boil.GetContextDB(), guildID)
+}
+
+// YoutubeAnnouncementExists checks if the YoutubeAnnouncement row exists.
+func YoutubeAnnouncementExists(ctx context.Context, exec boil.ContextExecutor, guildID int64) (bool, error) {
+ var exists bool
+ sql := "select exists(select 1 from \"youtube_announcements\" where \"guild_id\"=$1 limit 1)"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, guildID)
+ }
+ row := exec.QueryRowContext(ctx, sql, guildID)
+
+ err := row.Scan(&exists)
+ if err != nil {
+ return false, errors.Wrap(err, "models: unable to check if youtube_announcements exists")
+ }
+
+ return exists, nil
+}
+
+// Exists checks if the YoutubeAnnouncement row exists.
+func (o *YoutubeAnnouncement) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ return YoutubeAnnouncementExists(ctx, exec, o.GuildID)
+}
diff --git a/youtube/models/youtube_channel_subscriptions.go b/youtube/models/youtube_channel_subscriptions.go
new file mode 100644
index 0000000000..a8daf14031
--- /dev/null
+++ b/youtube/models/youtube_channel_subscriptions.go
@@ -0,0 +1,928 @@
+// Code generated by SQLBoiler 4.16.2 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
+// This file is meant to be re-generated in place and/or deleted at any time.
+
+package models
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/friendsofgo/errors"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/sqlboiler/v4/queries"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
+ "github.com/volatiletech/sqlboiler/v4/queries/qmhelper"
+ "github.com/volatiletech/sqlboiler/v4/types"
+ "github.com/volatiletech/strmangle"
+)
+
+// YoutubeChannelSubscription is an object representing the database table.
+type YoutubeChannelSubscription struct {
+ ID int `boil:"id" json:"id" toml:"id" yaml:"id"`
+ CreatedAt time.Time `boil:"created_at" json:"created_at" toml:"created_at" yaml:"created_at"`
+ UpdatedAt time.Time `boil:"updated_at" json:"updated_at" toml:"updated_at" yaml:"updated_at"`
+ GuildID string `boil:"guild_id" json:"guild_id" toml:"guild_id" yaml:"guild_id"`
+ ChannelID string `boil:"channel_id" json:"channel_id" toml:"channel_id" yaml:"channel_id"`
+ YoutubeChannelID string `boil:"youtube_channel_id" json:"youtube_channel_id" toml:"youtube_channel_id" yaml:"youtube_channel_id"`
+ YoutubeChannelName string `boil:"youtube_channel_name" json:"youtube_channel_name" toml:"youtube_channel_name" yaml:"youtube_channel_name"`
+ MentionEveryone bool `boil:"mention_everyone" json:"mention_everyone" toml:"mention_everyone" yaml:"mention_everyone"`
+ MentionRoles types.Int64Array `boil:"mention_roles" json:"mention_roles,omitempty" toml:"mention_roles" yaml:"mention_roles,omitempty"`
+ PublishLivestream bool `boil:"publish_livestream" json:"publish_livestream" toml:"publish_livestream" yaml:"publish_livestream"`
+ PublishShorts bool `boil:"publish_shorts" json:"publish_shorts" toml:"publish_shorts" yaml:"publish_shorts"`
+ Enabled bool `boil:"enabled" json:"enabled" toml:"enabled" yaml:"enabled"`
+
+ R *youtubeChannelSubscriptionR `boil:"-" json:"-" toml:"-" yaml:"-"`
+ L youtubeChannelSubscriptionL `boil:"-" json:"-" toml:"-" yaml:"-"`
+}
+
+var YoutubeChannelSubscriptionColumns = struct {
+ ID string
+ CreatedAt string
+ UpdatedAt string
+ GuildID string
+ ChannelID string
+ YoutubeChannelID string
+ YoutubeChannelName string
+ MentionEveryone string
+ MentionRoles string
+ PublishLivestream string
+ PublishShorts string
+ Enabled string
+}{
+ ID: "id",
+ CreatedAt: "created_at",
+ UpdatedAt: "updated_at",
+ GuildID: "guild_id",
+ ChannelID: "channel_id",
+ YoutubeChannelID: "youtube_channel_id",
+ YoutubeChannelName: "youtube_channel_name",
+ MentionEveryone: "mention_everyone",
+ MentionRoles: "mention_roles",
+ PublishLivestream: "publish_livestream",
+ PublishShorts: "publish_shorts",
+ Enabled: "enabled",
+}
+
+var YoutubeChannelSubscriptionTableColumns = struct {
+ ID string
+ CreatedAt string
+ UpdatedAt string
+ GuildID string
+ ChannelID string
+ YoutubeChannelID string
+ YoutubeChannelName string
+ MentionEveryone string
+ MentionRoles string
+ PublishLivestream string
+ PublishShorts string
+ Enabled string
+}{
+ ID: "youtube_channel_subscriptions.id",
+ CreatedAt: "youtube_channel_subscriptions.created_at",
+ UpdatedAt: "youtube_channel_subscriptions.updated_at",
+ GuildID: "youtube_channel_subscriptions.guild_id",
+ ChannelID: "youtube_channel_subscriptions.channel_id",
+ YoutubeChannelID: "youtube_channel_subscriptions.youtube_channel_id",
+ YoutubeChannelName: "youtube_channel_subscriptions.youtube_channel_name",
+ MentionEveryone: "youtube_channel_subscriptions.mention_everyone",
+ MentionRoles: "youtube_channel_subscriptions.mention_roles",
+ PublishLivestream: "youtube_channel_subscriptions.publish_livestream",
+ PublishShorts: "youtube_channel_subscriptions.publish_shorts",
+ Enabled: "youtube_channel_subscriptions.enabled",
+}
+
+// Generated where
+
+type whereHelperint struct{ field string }
+
+func (w whereHelperint) EQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.EQ, x) }
+func (w whereHelperint) NEQ(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.NEQ, x) }
+func (w whereHelperint) LT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LT, x) }
+func (w whereHelperint) LTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.LTE, x) }
+func (w whereHelperint) GT(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GT, x) }
+func (w whereHelperint) GTE(x int) qm.QueryMod { return qmhelper.Where(w.field, qmhelper.GTE, x) }
+func (w whereHelperint) IN(slice []int) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereIn(fmt.Sprintf("%s IN ?", w.field), values...)
+}
+func (w whereHelperint) NIN(slice []int) qm.QueryMod {
+ values := make([]interface{}, 0, len(slice))
+ for _, value := range slice {
+ values = append(values, value)
+ }
+ return qm.WhereNotIn(fmt.Sprintf("%s NOT IN ?", w.field), values...)
+}
+
+type whereHelpertime_Time struct{ field string }
+
+func (w whereHelpertime_Time) EQ(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.EQ, x)
+}
+func (w whereHelpertime_Time) NEQ(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.NEQ, x)
+}
+func (w whereHelpertime_Time) LT(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpertime_Time) LTE(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpertime_Time) GT(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpertime_Time) GTE(x time.Time) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+type whereHelpertypes_Int64Array struct{ field string }
+
+func (w whereHelpertypes_Int64Array) EQ(x types.Int64Array) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, false, x)
+}
+func (w whereHelpertypes_Int64Array) NEQ(x types.Int64Array) qm.QueryMod {
+ return qmhelper.WhereNullEQ(w.field, true, x)
+}
+func (w whereHelpertypes_Int64Array) LT(x types.Int64Array) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LT, x)
+}
+func (w whereHelpertypes_Int64Array) LTE(x types.Int64Array) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.LTE, x)
+}
+func (w whereHelpertypes_Int64Array) GT(x types.Int64Array) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GT, x)
+}
+func (w whereHelpertypes_Int64Array) GTE(x types.Int64Array) qm.QueryMod {
+ return qmhelper.Where(w.field, qmhelper.GTE, x)
+}
+
+func (w whereHelpertypes_Int64Array) IsNull() qm.QueryMod { return qmhelper.WhereIsNull(w.field) }
+func (w whereHelpertypes_Int64Array) IsNotNull() qm.QueryMod { return qmhelper.WhereIsNotNull(w.field) }
+
+var YoutubeChannelSubscriptionWhere = struct {
+ ID whereHelperint
+ CreatedAt whereHelpertime_Time
+ UpdatedAt whereHelpertime_Time
+ GuildID whereHelperstring
+ ChannelID whereHelperstring
+ YoutubeChannelID whereHelperstring
+ YoutubeChannelName whereHelperstring
+ MentionEveryone whereHelperbool
+ MentionRoles whereHelpertypes_Int64Array
+ PublishLivestream whereHelperbool
+ PublishShorts whereHelperbool
+ Enabled whereHelperbool
+}{
+ ID: whereHelperint{field: "\"youtube_channel_subscriptions\".\"id\""},
+ CreatedAt: whereHelpertime_Time{field: "\"youtube_channel_subscriptions\".\"created_at\""},
+ UpdatedAt: whereHelpertime_Time{field: "\"youtube_channel_subscriptions\".\"updated_at\""},
+ GuildID: whereHelperstring{field: "\"youtube_channel_subscriptions\".\"guild_id\""},
+ ChannelID: whereHelperstring{field: "\"youtube_channel_subscriptions\".\"channel_id\""},
+ YoutubeChannelID: whereHelperstring{field: "\"youtube_channel_subscriptions\".\"youtube_channel_id\""},
+ YoutubeChannelName: whereHelperstring{field: "\"youtube_channel_subscriptions\".\"youtube_channel_name\""},
+ MentionEveryone: whereHelperbool{field: "\"youtube_channel_subscriptions\".\"mention_everyone\""},
+ MentionRoles: whereHelpertypes_Int64Array{field: "\"youtube_channel_subscriptions\".\"mention_roles\""},
+ PublishLivestream: whereHelperbool{field: "\"youtube_channel_subscriptions\".\"publish_livestream\""},
+ PublishShorts: whereHelperbool{field: "\"youtube_channel_subscriptions\".\"publish_shorts\""},
+ Enabled: whereHelperbool{field: "\"youtube_channel_subscriptions\".\"enabled\""},
+}
+
+// YoutubeChannelSubscriptionRels is where relationship names are stored.
+var YoutubeChannelSubscriptionRels = struct {
+}{}
+
+// youtubeChannelSubscriptionR is where relationships are stored.
+type youtubeChannelSubscriptionR struct {
+}
+
+// NewStruct creates a new relationship struct
+func (*youtubeChannelSubscriptionR) NewStruct() *youtubeChannelSubscriptionR {
+ return &youtubeChannelSubscriptionR{}
+}
+
+// youtubeChannelSubscriptionL is where Load methods for each relationship are stored.
+type youtubeChannelSubscriptionL struct{}
+
+var (
+ youtubeChannelSubscriptionAllColumns = []string{"id", "created_at", "updated_at", "guild_id", "channel_id", "youtube_channel_id", "youtube_channel_name", "mention_everyone", "mention_roles", "publish_livestream", "publish_shorts", "enabled"}
+ youtubeChannelSubscriptionColumnsWithoutDefault = []string{"created_at", "updated_at", "guild_id", "channel_id", "youtube_channel_id", "youtube_channel_name", "mention_everyone"}
+ youtubeChannelSubscriptionColumnsWithDefault = []string{"id", "mention_roles", "publish_livestream", "publish_shorts", "enabled"}
+ youtubeChannelSubscriptionPrimaryKeyColumns = []string{"id"}
+ youtubeChannelSubscriptionGeneratedColumns = []string{}
+)
+
+type (
+ // YoutubeChannelSubscriptionSlice is an alias for a slice of pointers to YoutubeChannelSubscription.
+ // This should almost always be used instead of []YoutubeChannelSubscription.
+ YoutubeChannelSubscriptionSlice []*YoutubeChannelSubscription
+
+ youtubeChannelSubscriptionQuery struct {
+ *queries.Query
+ }
+)
+
+// Cache for insert, update and upsert
+var (
+ youtubeChannelSubscriptionType = reflect.TypeOf(&YoutubeChannelSubscription{})
+ youtubeChannelSubscriptionMapping = queries.MakeStructMapping(youtubeChannelSubscriptionType)
+ youtubeChannelSubscriptionPrimaryKeyMapping, _ = queries.BindMapping(youtubeChannelSubscriptionType, youtubeChannelSubscriptionMapping, youtubeChannelSubscriptionPrimaryKeyColumns)
+ youtubeChannelSubscriptionInsertCacheMut sync.RWMutex
+ youtubeChannelSubscriptionInsertCache = make(map[string]insertCache)
+ youtubeChannelSubscriptionUpdateCacheMut sync.RWMutex
+ youtubeChannelSubscriptionUpdateCache = make(map[string]updateCache)
+ youtubeChannelSubscriptionUpsertCacheMut sync.RWMutex
+ youtubeChannelSubscriptionUpsertCache = make(map[string]insertCache)
+)
+
+var (
+ // Force time package dependency for automated UpdatedAt/CreatedAt.
+ _ = time.Second
+ // Force qmhelper dependency for where clause generation (which doesn't
+ // always happen)
+ _ = qmhelper.Where
+)
+
+// OneG returns a single youtubeChannelSubscription record from the query using the global executor.
+func (q youtubeChannelSubscriptionQuery) OneG(ctx context.Context) (*YoutubeChannelSubscription, error) {
+ return q.One(ctx, boil.GetContextDB())
+}
+
+// One returns a single youtubeChannelSubscription record from the query.
+func (q youtubeChannelSubscriptionQuery) One(ctx context.Context, exec boil.ContextExecutor) (*YoutubeChannelSubscription, error) {
+ o := &YoutubeChannelSubscription{}
+
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Bind(ctx, exec, o)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: failed to execute a one query for youtube_channel_subscriptions")
+ }
+
+ return o, nil
+}
+
+// AllG returns all YoutubeChannelSubscription records from the query using the global executor.
+func (q youtubeChannelSubscriptionQuery) AllG(ctx context.Context) (YoutubeChannelSubscriptionSlice, error) {
+ return q.All(ctx, boil.GetContextDB())
+}
+
+// All returns all YoutubeChannelSubscription records from the query.
+func (q youtubeChannelSubscriptionQuery) All(ctx context.Context, exec boil.ContextExecutor) (YoutubeChannelSubscriptionSlice, error) {
+ var o []*YoutubeChannelSubscription
+
+ err := q.Bind(ctx, exec, &o)
+ if err != nil {
+ return nil, errors.Wrap(err, "models: failed to assign all query results to YoutubeChannelSubscription slice")
+ }
+
+ return o, nil
+}
+
+// CountG returns the count of all YoutubeChannelSubscription records in the query using the global executor
+func (q youtubeChannelSubscriptionQuery) CountG(ctx context.Context) (int64, error) {
+ return q.Count(ctx, boil.GetContextDB())
+}
+
+// Count returns the count of all YoutubeChannelSubscription records in the query.
+func (q youtubeChannelSubscriptionQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to count youtube_channel_subscriptions rows")
+ }
+
+ return count, nil
+}
+
+// ExistsG checks if the row exists in the table using the global executor.
+func (q youtubeChannelSubscriptionQuery) ExistsG(ctx context.Context) (bool, error) {
+ return q.Exists(ctx, boil.GetContextDB())
+}
+
+// Exists checks if the row exists in the table.
+func (q youtubeChannelSubscriptionQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ var count int64
+
+ queries.SetSelect(q.Query, nil)
+ queries.SetCount(q.Query)
+ queries.SetLimit(q.Query, 1)
+
+ err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
+ if err != nil {
+ return false, errors.Wrap(err, "models: failed to check if youtube_channel_subscriptions exists")
+ }
+
+ return count > 0, nil
+}
+
+// YoutubeChannelSubscriptions retrieves all the records using an executor.
+func YoutubeChannelSubscriptions(mods ...qm.QueryMod) youtubeChannelSubscriptionQuery {
+ mods = append(mods, qm.From("\"youtube_channel_subscriptions\""))
+ q := NewQuery(mods...)
+ if len(queries.GetSelect(q)) == 0 {
+ queries.SetSelect(q, []string{"\"youtube_channel_subscriptions\".*"})
+ }
+
+ return youtubeChannelSubscriptionQuery{q}
+}
+
+// FindYoutubeChannelSubscriptionG retrieves a single record by ID.
+func FindYoutubeChannelSubscriptionG(ctx context.Context, iD int, selectCols ...string) (*YoutubeChannelSubscription, error) {
+ return FindYoutubeChannelSubscription(ctx, boil.GetContextDB(), iD, selectCols...)
+}
+
+// FindYoutubeChannelSubscription retrieves a single record by ID with an executor.
+// If selectCols is empty Find will return all columns.
+func FindYoutubeChannelSubscription(ctx context.Context, exec boil.ContextExecutor, iD int, selectCols ...string) (*YoutubeChannelSubscription, error) {
+ youtubeChannelSubscriptionObj := &YoutubeChannelSubscription{}
+
+ sel := "*"
+ if len(selectCols) > 0 {
+ sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",")
+ }
+ query := fmt.Sprintf(
+ "select %s from \"youtube_channel_subscriptions\" where \"id\"=$1", sel,
+ )
+
+ q := queries.Raw(query, iD)
+
+ err := q.Bind(ctx, exec, youtubeChannelSubscriptionObj)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, sql.ErrNoRows
+ }
+ return nil, errors.Wrap(err, "models: unable to select from youtube_channel_subscriptions")
+ }
+
+ return youtubeChannelSubscriptionObj, nil
+}
+
+// InsertG a single record. See Insert for whitelist behavior description.
+func (o *YoutubeChannelSubscription) InsertG(ctx context.Context, columns boil.Columns) error {
+ return o.Insert(ctx, boil.GetContextDB(), columns)
+}
+
+// Insert a single record using an executor.
+// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts.
+func (o *YoutubeChannelSubscription) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error {
+ if o == nil {
+ return errors.New("models: no youtube_channel_subscriptions provided for insertion")
+ }
+
+ var err error
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ if o.UpdatedAt.IsZero() {
+ o.UpdatedAt = currTime
+ }
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(youtubeChannelSubscriptionColumnsWithDefault, o)
+
+ key := makeCacheKey(columns, nzDefaults)
+ youtubeChannelSubscriptionInsertCacheMut.RLock()
+ cache, cached := youtubeChannelSubscriptionInsertCache[key]
+ youtubeChannelSubscriptionInsertCacheMut.RUnlock()
+
+ if !cached {
+ wl, returnColumns := columns.InsertColumnSet(
+ youtubeChannelSubscriptionAllColumns,
+ youtubeChannelSubscriptionColumnsWithDefault,
+ youtubeChannelSubscriptionColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ cache.valueMapping, err = queries.BindMapping(youtubeChannelSubscriptionType, youtubeChannelSubscriptionMapping, wl)
+ if err != nil {
+ return err
+ }
+ cache.retMapping, err = queries.BindMapping(youtubeChannelSubscriptionType, youtubeChannelSubscriptionMapping, returnColumns)
+ if err != nil {
+ return err
+ }
+ if len(wl) != 0 {
+ cache.query = fmt.Sprintf("INSERT INTO \"youtube_channel_subscriptions\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1))
+ } else {
+ cache.query = "INSERT INTO \"youtube_channel_subscriptions\" %sDEFAULT VALUES%s"
+ }
+
+ var queryOutput, queryReturning string
+
+ if len(cache.retMapping) != 0 {
+ queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\""))
+ }
+
+ cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+
+ if err != nil {
+ return errors.Wrap(err, "models: unable to insert into youtube_channel_subscriptions")
+ }
+
+ if !cached {
+ youtubeChannelSubscriptionInsertCacheMut.Lock()
+ youtubeChannelSubscriptionInsertCache[key] = cache
+ youtubeChannelSubscriptionInsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// UpdateG a single YoutubeChannelSubscription record using the global executor.
+// See Update for more documentation.
+func (o *YoutubeChannelSubscription) UpdateG(ctx context.Context, columns boil.Columns) (int64, error) {
+ return o.Update(ctx, boil.GetContextDB(), columns)
+}
+
+// Update uses an executor to update the YoutubeChannelSubscription.
+// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates.
+// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records.
+func (o *YoutubeChannelSubscription) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) {
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ o.UpdatedAt = currTime
+ }
+
+ var err error
+ key := makeCacheKey(columns, nil)
+ youtubeChannelSubscriptionUpdateCacheMut.RLock()
+ cache, cached := youtubeChannelSubscriptionUpdateCache[key]
+ youtubeChannelSubscriptionUpdateCacheMut.RUnlock()
+
+ if !cached {
+ wl := columns.UpdateColumnSet(
+ youtubeChannelSubscriptionAllColumns,
+ youtubeChannelSubscriptionPrimaryKeyColumns,
+ )
+
+ if !columns.IsWhitelist() {
+ wl = strmangle.SetComplement(wl, []string{"created_at"})
+ }
+ if len(wl) == 0 {
+ return 0, errors.New("models: unable to update youtube_channel_subscriptions, could not build whitelist")
+ }
+
+ cache.query = fmt.Sprintf("UPDATE \"youtube_channel_subscriptions\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, wl),
+ strmangle.WhereClause("\"", "\"", len(wl)+1, youtubeChannelSubscriptionPrimaryKeyColumns),
+ )
+ cache.valueMapping, err = queries.BindMapping(youtubeChannelSubscriptionType, youtubeChannelSubscriptionMapping, append(wl, youtubeChannelSubscriptionPrimaryKeyColumns...))
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, values)
+ }
+ var result sql.Result
+ result, err = exec.ExecContext(ctx, cache.query, values...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update youtube_channel_subscriptions row")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by update for youtube_channel_subscriptions")
+ }
+
+ if !cached {
+ youtubeChannelSubscriptionUpdateCacheMut.Lock()
+ youtubeChannelSubscriptionUpdateCache[key] = cache
+ youtubeChannelSubscriptionUpdateCacheMut.Unlock()
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (q youtubeChannelSubscriptionQuery) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return q.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values.
+func (q youtubeChannelSubscriptionQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ queries.SetUpdate(q.Query, cols)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all for youtube_channel_subscriptions")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected for youtube_channel_subscriptions")
+ }
+
+ return rowsAff, nil
+}
+
+// UpdateAllG updates all rows with the specified column values.
+func (o YoutubeChannelSubscriptionSlice) UpdateAllG(ctx context.Context, cols M) (int64, error) {
+ return o.UpdateAll(ctx, boil.GetContextDB(), cols)
+}
+
+// UpdateAll updates all rows with the specified column values, using an executor.
+func (o YoutubeChannelSubscriptionSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
+ ln := int64(len(o))
+ if ln == 0 {
+ return 0, nil
+ }
+
+ if len(cols) == 0 {
+ return 0, errors.New("models: update all requires at least one column argument")
+ }
+
+ colNames := make([]string, len(cols))
+ args := make([]interface{}, len(cols))
+
+ i := 0
+ for name, value := range cols {
+ colNames[i] = name
+ args[i] = value
+ i++
+ }
+
+ // Append all of the primary key values for each column
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), youtubeChannelSubscriptionPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := fmt.Sprintf("UPDATE \"youtube_channel_subscriptions\" SET %s WHERE %s",
+ strmangle.SetParamNames("\"", "\"", 1, colNames),
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, youtubeChannelSubscriptionPrimaryKeyColumns, len(o)))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to update all in youtubeChannelSubscription slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all youtubeChannelSubscription")
+ }
+ return rowsAff, nil
+}
+
+// UpsertG attempts an insert, and does an update or ignore on conflict.
+func (o *YoutubeChannelSubscription) UpsertG(ctx context.Context, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ return o.Upsert(ctx, boil.GetContextDB(), updateOnConflict, conflictColumns, updateColumns, insertColumns, opts...)
+}
+
+// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
+// See boil.Columns documentation for how to properly use updateColumns and insertColumns.
+func (o *YoutubeChannelSubscription) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns, opts ...UpsertOptionFunc) error {
+ if o == nil {
+ return errors.New("models: no youtube_channel_subscriptions provided for upsert")
+ }
+ if !boil.TimestampsAreSkipped(ctx) {
+ currTime := time.Now().In(boil.GetLocation())
+
+ if o.CreatedAt.IsZero() {
+ o.CreatedAt = currTime
+ }
+ o.UpdatedAt = currTime
+ }
+
+ nzDefaults := queries.NonZeroDefaultSet(youtubeChannelSubscriptionColumnsWithDefault, o)
+
+ // Build cache key in-line uglily - mysql vs psql problems
+ buf := strmangle.GetBuffer()
+ if updateOnConflict {
+ buf.WriteByte('t')
+ } else {
+ buf.WriteByte('f')
+ }
+ buf.WriteByte('.')
+ for _, c := range conflictColumns {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(updateColumns.Kind))
+ for _, c := range updateColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ buf.WriteString(strconv.Itoa(insertColumns.Kind))
+ for _, c := range insertColumns.Cols {
+ buf.WriteString(c)
+ }
+ buf.WriteByte('.')
+ for _, c := range nzDefaults {
+ buf.WriteString(c)
+ }
+ key := buf.String()
+ strmangle.PutBuffer(buf)
+
+ youtubeChannelSubscriptionUpsertCacheMut.RLock()
+ cache, cached := youtubeChannelSubscriptionUpsertCache[key]
+ youtubeChannelSubscriptionUpsertCacheMut.RUnlock()
+
+ var err error
+
+ if !cached {
+ insert, _ := insertColumns.InsertColumnSet(
+ youtubeChannelSubscriptionAllColumns,
+ youtubeChannelSubscriptionColumnsWithDefault,
+ youtubeChannelSubscriptionColumnsWithoutDefault,
+ nzDefaults,
+ )
+
+ update := updateColumns.UpdateColumnSet(
+ youtubeChannelSubscriptionAllColumns,
+ youtubeChannelSubscriptionPrimaryKeyColumns,
+ )
+
+ if updateOnConflict && len(update) == 0 {
+ return errors.New("models: unable to upsert youtube_channel_subscriptions, could not build update column list")
+ }
+
+ ret := strmangle.SetComplement(youtubeChannelSubscriptionAllColumns, strmangle.SetIntersect(insert, update))
+
+ conflict := conflictColumns
+ if len(conflict) == 0 && updateOnConflict && len(update) != 0 {
+ if len(youtubeChannelSubscriptionPrimaryKeyColumns) == 0 {
+ return errors.New("models: unable to upsert youtube_channel_subscriptions, could not build conflict column list")
+ }
+
+ conflict = make([]string, len(youtubeChannelSubscriptionPrimaryKeyColumns))
+ copy(conflict, youtubeChannelSubscriptionPrimaryKeyColumns)
+ }
+ cache.query = buildUpsertQueryPostgres(dialect, "\"youtube_channel_subscriptions\"", updateOnConflict, ret, update, conflict, insert, opts...)
+
+ cache.valueMapping, err = queries.BindMapping(youtubeChannelSubscriptionType, youtubeChannelSubscriptionMapping, insert)
+ if err != nil {
+ return err
+ }
+ if len(ret) != 0 {
+ cache.retMapping, err = queries.BindMapping(youtubeChannelSubscriptionType, youtubeChannelSubscriptionMapping, ret)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ value := reflect.Indirect(reflect.ValueOf(o))
+ vals := queries.ValuesFromMapping(value, cache.valueMapping)
+ var returns []interface{}
+ if len(cache.retMapping) != 0 {
+ returns = queries.PtrsFromMapping(value, cache.retMapping)
+ }
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, cache.query)
+ fmt.Fprintln(writer, vals)
+ }
+ if len(cache.retMapping) != 0 {
+ err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...)
+ if errors.Is(err, sql.ErrNoRows) {
+ err = nil // Postgres doesn't return anything when there's no update
+ }
+ } else {
+ _, err = exec.ExecContext(ctx, cache.query, vals...)
+ }
+ if err != nil {
+ return errors.Wrap(err, "models: unable to upsert youtube_channel_subscriptions")
+ }
+
+ if !cached {
+ youtubeChannelSubscriptionUpsertCacheMut.Lock()
+ youtubeChannelSubscriptionUpsertCache[key] = cache
+ youtubeChannelSubscriptionUpsertCacheMut.Unlock()
+ }
+
+ return nil
+}
+
+// DeleteG deletes a single YoutubeChannelSubscription record.
+// DeleteG will match against the primary key column to find the record to delete.
+func (o *YoutubeChannelSubscription) DeleteG(ctx context.Context) (int64, error) {
+ return o.Delete(ctx, boil.GetContextDB())
+}
+
+// Delete deletes a single YoutubeChannelSubscription record with an executor.
+// Delete will match against the primary key column to find the record to delete.
+func (o *YoutubeChannelSubscription) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if o == nil {
+ return 0, errors.New("models: no YoutubeChannelSubscription provided for delete")
+ }
+
+ args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), youtubeChannelSubscriptionPrimaryKeyMapping)
+ sql := "DELETE FROM \"youtube_channel_subscriptions\" WHERE \"id\"=$1"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args...)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete from youtube_channel_subscriptions")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by delete for youtube_channel_subscriptions")
+ }
+
+ return rowsAff, nil
+}
+
+func (q youtubeChannelSubscriptionQuery) DeleteAllG(ctx context.Context) (int64, error) {
+ return q.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all matching rows.
+func (q youtubeChannelSubscriptionQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if q.Query == nil {
+ return 0, errors.New("models: no youtubeChannelSubscriptionQuery provided for delete all")
+ }
+
+ queries.SetDelete(q.Query)
+
+ result, err := q.Query.ExecContext(ctx, exec)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from youtube_channel_subscriptions")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for youtube_channel_subscriptions")
+ }
+
+ return rowsAff, nil
+}
+
+// DeleteAllG deletes all rows in the slice.
+func (o YoutubeChannelSubscriptionSlice) DeleteAllG(ctx context.Context) (int64, error) {
+ return o.DeleteAll(ctx, boil.GetContextDB())
+}
+
+// DeleteAll deletes all rows in the slice, using an executor.
+func (o YoutubeChannelSubscriptionSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
+ if len(o) == 0 {
+ return 0, nil
+ }
+
+ var args []interface{}
+ for _, obj := range o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), youtubeChannelSubscriptionPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "DELETE FROM \"youtube_channel_subscriptions\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, youtubeChannelSubscriptionPrimaryKeyColumns, len(o))
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, args)
+ }
+ result, err := exec.ExecContext(ctx, sql, args...)
+ if err != nil {
+ return 0, errors.Wrap(err, "models: unable to delete all from youtubeChannelSubscription slice")
+ }
+
+ rowsAff, err := result.RowsAffected()
+ if err != nil {
+ return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for youtube_channel_subscriptions")
+ }
+
+ return rowsAff, nil
+}
+
+// ReloadG refetches the object from the database using the primary keys.
+func (o *YoutubeChannelSubscription) ReloadG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: no YoutubeChannelSubscription provided for reload")
+ }
+
+ return o.Reload(ctx, boil.GetContextDB())
+}
+
+// Reload refetches the object from the database
+// using the primary keys with an executor.
+func (o *YoutubeChannelSubscription) Reload(ctx context.Context, exec boil.ContextExecutor) error {
+ ret, err := FindYoutubeChannelSubscription(ctx, exec, o.ID)
+ if err != nil {
+ return err
+ }
+
+ *o = *ret
+ return nil
+}
+
+// ReloadAllG refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *YoutubeChannelSubscriptionSlice) ReloadAllG(ctx context.Context) error {
+ if o == nil {
+ return errors.New("models: empty YoutubeChannelSubscriptionSlice provided for reload all")
+ }
+
+ return o.ReloadAll(ctx, boil.GetContextDB())
+}
+
+// ReloadAll refetches every row with matching primary key column values
+// and overwrites the original object slice with the newly updated slice.
+func (o *YoutubeChannelSubscriptionSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error {
+ if o == nil || len(*o) == 0 {
+ return nil
+ }
+
+ slice := YoutubeChannelSubscriptionSlice{}
+ var args []interface{}
+ for _, obj := range *o {
+ pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), youtubeChannelSubscriptionPrimaryKeyMapping)
+ args = append(args, pkeyArgs...)
+ }
+
+ sql := "SELECT \"youtube_channel_subscriptions\".* FROM \"youtube_channel_subscriptions\" WHERE " +
+ strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, youtubeChannelSubscriptionPrimaryKeyColumns, len(*o))
+
+ q := queries.Raw(sql, args...)
+
+ err := q.Bind(ctx, exec, &slice)
+ if err != nil {
+ return errors.Wrap(err, "models: unable to reload all in YoutubeChannelSubscriptionSlice")
+ }
+
+ *o = slice
+
+ return nil
+}
+
+// YoutubeChannelSubscriptionExistsG checks if the YoutubeChannelSubscription row exists.
+func YoutubeChannelSubscriptionExistsG(ctx context.Context, iD int) (bool, error) {
+ return YoutubeChannelSubscriptionExists(ctx, boil.GetContextDB(), iD)
+}
+
+// YoutubeChannelSubscriptionExists checks if the YoutubeChannelSubscription row exists.
+func YoutubeChannelSubscriptionExists(ctx context.Context, exec boil.ContextExecutor, iD int) (bool, error) {
+ var exists bool
+ sql := "select exists(select 1 from \"youtube_channel_subscriptions\" where \"id\"=$1 limit 1)"
+
+ if boil.IsDebug(ctx) {
+ writer := boil.DebugWriterFrom(ctx)
+ fmt.Fprintln(writer, sql)
+ fmt.Fprintln(writer, iD)
+ }
+ row := exec.QueryRowContext(ctx, sql, iD)
+
+ err := row.Scan(&exists)
+ if err != nil {
+ return false, errors.Wrap(err, "models: unable to check if youtube_channel_subscriptions exists")
+ }
+
+ return exists, nil
+}
+
+// Exists checks if the YoutubeChannelSubscription row exists.
+func (o *YoutubeChannelSubscription) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
+ return YoutubeChannelSubscriptionExists(ctx, exec, o.ID)
+}
diff --git a/youtube/schema.go b/youtube/schema.go
new file mode 100644
index 0000000000..92f887d48c
--- /dev/null
+++ b/youtube/schema.go
@@ -0,0 +1,76 @@
+package youtube
+
+var DBSchemas = []string{`
+CREATE TABLE IF NOT EXISTS youtube_channel_subscriptions (
+ id SERIAL PRIMARY KEY,
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL,
+ updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
+
+ guild_id TEXT NOT NULL,
+ channel_id TEXT NOT NULL,
+ youtube_channel_id TEXT NOT NULL,
+ youtube_channel_name TEXT NOT NULL,
+
+ mention_everyone BOOLEAN NOT NULL,
+ mention_roles BIGINT[],
+ publish_livestream BOOLEAN NOT NULL DEFAULT TRUE,
+ publish_shorts BOOLEAN NOT NULL DEFAULT TRUE,
+ enabled BOOLEAN NOT NULL DEFAULT TRUE
+);
+`, `
+
+-- Old tables managed with gorm are missing NOT NULL constraints on some columns
+-- that are never null in existing records; add them as needed.
+
+ALTER TABLE youtube_channel_subscriptions ALTER COLUMN created_at SET NOT NULL;
+`, `
+ALTER TABLE youtube_channel_subscriptions ALTER COLUMN updated_at SET NOT NULL;
+`, `
+ALTER TABLE youtube_channel_subscriptions ALTER COLUMN guild_id SET NOT NULL;
+`, `
+ALTER TABLE youtube_channel_subscriptions ALTER COLUMN channel_id SET NOT NULL;
+`, `
+ALTER TABLE youtube_channel_subscriptions ALTER COLUMN youtube_channel_id SET NOT NULL;
+`, `
+ALTER TABLE youtube_channel_subscriptions ALTER COLUMN youtube_channel_name SET NOT NULL;
+`, `
+ALTER TABLE youtube_channel_subscriptions ALTER COLUMN mention_everyone SET NOT NULL;
+
+-- Can't add a NOT NULL constraint to mention_roles because too many records in
+-- production have it set to null.
+`, `
+
+-- The migration for the publish_livestream, publish_shorts, and enabled columns is
+-- more involved. These columns were added later and so it is possible that they are
+-- null in some older records. Therefore, we first replace these missing values with
+-- defaults before adding the NOT NULL constraint.
+
+DO $$
+BEGIN
+
+-- only run if we haven't added the NOT NULL constraint yet
+IF EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name='youtube_channel_subscriptions' AND column_name='publish_livestream' AND is_nullable='yes') THEN
+ UPDATE youtube_channel_subscriptions SET publish_livestream = TRUE WHERE publish_livestream IS NULL;
+ UPDATE youtube_channel_subscriptions SET publish_shorts = TRUE WHERE publish_shorts IS NULL;
+ UPDATE youtube_channel_subscriptions SET enabled = TRUE WHERE enabled IS NULL;
+
+ ALTER TABLE youtube_channel_subscriptions ALTER COLUMN publish_livestream SET NOT NULL;
+ ALTER TABLE youtube_channel_subscriptions ALTER COLUMN publish_shorts SET NOT NULL;
+ ALTER TABLE youtube_channel_subscriptions ALTER COLUMN enabled SET NOT NULL;
+END IF;
+END $$;
+`, `
+
+CREATE TABLE IF NOT EXISTS youtube_announcements (
+ guild_id BIGINT PRIMARY KEY,
+ message TEXT NOT NULL,
+ enabled BOOLEAN NOT NULL DEFAULT FALSE
+);
+`, `
+
+ALTER TABLE youtube_announcements ALTER COLUMN guild_id SET NOT NULL;
+`, `
+ALTER TABLE youtube_announcements ALTER COLUMN message SET NOT NULL;
+`, `
+ALTER TABLE youtube_announcements ALTER COLUMN enabled SET NOT NULL;
+`}
diff --git a/youtube/sqlboiler.toml b/youtube/sqlboiler.toml
new file mode 100644
index 0000000000..5de144e45f
--- /dev/null
+++ b/youtube/sqlboiler.toml
@@ -0,0 +1,15 @@
+add-global-variants = true
+no-hooks = true
+no-tests = true
+
+[psql]
+dbname = "yagpdb"
+host = "localhost"
+user = "postgres"
+pass = "pass"
+sslmode = "disable"
+whitelist = ["youtube_channel_subscriptions", "youtube_announcements"]
+
+[auto-columns]
+created = "created_at"
+updated = "updated_at"
diff --git a/youtube/web.go b/youtube/web.go
index b4af046886..a89589e19c 100644
--- a/youtube/web.go
+++ b/youtube/web.go
@@ -2,6 +2,7 @@ package youtube
import (
"context"
+ "database/sql"
_ "embed"
"encoding/xml"
"errors"
@@ -18,8 +19,10 @@ import (
"github.com/botlabs-gg/yagpdb/v2/common/cplogs"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/web"
- "github.com/jinzhu/gorm"
+ "github.com/botlabs-gg/yagpdb/v2/youtube/models"
"github.com/mediocregopher/radix/v3"
+ "github.com/volatiletech/sqlboiler/v4/boil"
+ "github.com/volatiletech/sqlboiler/v4/queries/qm"
"goji.io"
"goji.io/pat"
)
@@ -94,45 +97,49 @@ func (p *Plugin) InitWeb() {
func (p *Plugin) HandleYoutube(w http.ResponseWriter, r *http.Request) (web.TemplateData, error) {
ctx := r.Context()
- ag, templateData := web.GetBaseCPContextData(ctx)
+ activeGuild, templateData := web.GetBaseCPContextData(ctx)
- var subs []*ChannelSubscription
- err := common.GORM.Where("guild_id = ?", ag.ID).Order("id desc").Find(&subs).Error
- if err != nil && err != gorm.ErrRecordNotFound {
+ subs, err := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.GuildID.EQ(discordgo.StrID(activeGuild.ID)),
+ qm.OrderBy("id DESC"),
+ ).AllG(ctx)
+ if err != nil && err != sql.ErrNoRows {
return templateData, err
}
- var announcement YoutubeAnnouncements
- err = common.GORM.Model(&YoutubeAnnouncements{}).Where("guild_id = ?", ag.ID).First(&announcement).Error
+ announcement, err := models.FindYoutubeAnnouncementG(ctx, activeGuild.ID)
if err != nil {
- announcement.Message = "{{.ChannelName}} published a new video! {{.URL}}"
- announcement.Enabled = common.BoolToPointer(false)
+ announcement = &models.YoutubeAnnouncement{
+ GuildID: activeGuild.ID,
+ Message: "{{.ChannelName}} published a new video! {{.URL}}",
+ Enabled: false,
+ }
}
templateData["Announcement"] = announcement
templateData["Subs"] = subs
- templateData["VisibleURL"] = "/manage/" + discordgo.StrID(ag.ID) + "/youtube"
-
+ templateData["VisibleURL"] = "/manage/" + discordgo.StrID(activeGuild.ID) + "/youtube"
return templateData, nil
}
func (p *Plugin) HandleYoutubeAnnouncement(w http.ResponseWriter, r *http.Request) (templateData web.TemplateData, err error) {
ctx := r.Context()
- guild, templateData := web.GetBaseCPContextData(ctx)
- data := ctx.Value(common.ContextKeyParsedForm).(*YoutubeAnnouncementForm)
-
- var announcement YoutubeAnnouncements
- announcement.Message = data.Message
- announcement.Enabled = &data.Enabled
- announcement.GuildID = guild.ID
+ activeGuild, templateData := web.GetBaseCPContextData(ctx)
+ form := ctx.Value(common.ContextKeyParsedForm).(*YoutubeAnnouncementForm)
- err = common.GORM.Model(&YoutubeAnnouncements{}).Where("guild_id = ?", guild.ID).Save(&announcement).Error
+ announcement := &models.YoutubeAnnouncement{
+ GuildID: activeGuild.ID,
+ Message: form.Message,
+ Enabled: form.Enabled,
+ }
+ err = announcement.UpsertG(ctx, true, []string{"guild_id"},
+ boil.Whitelist("message", "enabled"), /* updateColumns */
+ boil.Whitelist("guild_id", "message", "enabled") /* insertColumns */)
if err != nil {
return templateData, err
}
go cplogs.RetryAddEntry(web.NewLogEntryFromContext(r.Context(), panelLogKeyAnnouncement, &cplogs.Param{}))
-
return templateData, nil
}
@@ -140,10 +147,10 @@ func (p *Plugin) HandleNew(w http.ResponseWriter, r *http.Request) (web.Template
ctx := r.Context()
activeGuild, templateData := web.GetBaseCPContextData(ctx)
- // limit it to max 25 feeds
- var count int
- common.GORM.Model(&ChannelSubscription{}).Where("guild_id = ?", activeGuild.ID).Count(&count)
- if count >= MaxFeedsForContext(ctx) {
+ count, _ := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.GuildID.EQ(discordgo.StrID(activeGuild.ID)),
+ ).CountG(ctx)
+ if int(count) >= MaxFeedsForContext(ctx) {
return templateData.AddAlerts(web.ErrorAlert(fmt.Sprintf("Max %d youtube feeds allowed (%d for premium servers)", GuildMaxFeeds, GuildMaxFeedsPremium))), nil
}
@@ -183,7 +190,6 @@ func (p *Plugin) HandleNew(w http.ResponseWriter, r *http.Request) (web.Template
}
go cplogs.RetryAddEntry(web.NewLogEntryFromContext(r.Context(), panelLogKeyAddedFeed, &cplogs.Param{Type: cplogs.ParamTypeString, Value: sub.YoutubeChannelName}))
-
return templateData, nil
}
@@ -198,11 +204,13 @@ func BaseEditHandler(inner web.ControllerHandlerFunc) web.ControllerHandlerFunc
ctx := r.Context()
activeGuild, templateData := web.GetBaseCPContextData(ctx)
- id := pat.Param(r, "item")
+ id, err := strconv.Atoi(pat.Param(r, "item"))
+ if err != nil {
+ return templateData.AddAlerts(web.ErrorAlert("Invalid feed ID")), err
+ }
// Get the actual watch item from the config
- var sub ChannelSubscription
- err := common.GORM.Model(&ChannelSubscription{}).Where("id = ?", id).First(&sub).Error
+ sub, err := models.FindYoutubeChannelSubscriptionG(ctx, id)
if err != nil {
return templateData.AddAlerts(web.ErrorAlert("Failed retrieving that feed item")), err
}
@@ -212,50 +220,51 @@ func BaseEditHandler(inner web.ControllerHandlerFunc) web.ControllerHandlerFunc
}
ctx = context.WithValue(ctx, ContextKeySub, &sub)
-
return inner(w, r.WithContext(ctx))
}
}
func (p *Plugin) HandleEdit(w http.ResponseWriter, r *http.Request) (templateData web.TemplateData, err error) {
ctx := r.Context()
- _, templateData = web.GetBaseCPContextData(ctx)
-
- sub := ctx.Value(ContextKeySub).(*ChannelSubscription)
- data := ctx.Value(common.ContextKeyParsedForm).(*YoutubeFeedForm)
+ activeGuild, templateData := web.GetBaseCPContextData(ctx)
- sub.MentionEveryone = data.MentionEveryone
- sub.MentionRoles = data.MentionRoles
- sub.PublishLivestream = &data.PublishLivestream
- sub.PublishShorts = &data.PublishShorts
- sub.ChannelID = discordgo.StrID(data.DiscordChannel)
- sub.Enabled = &data.Enabled
- count := 0
- common.GORM.Model(&ChannelSubscription{}).Where("guild_id = ? and enabled = ?", sub.GuildID, common.BoolToPointer(true)).Count(&count)
- if count >= MaxFeedsForContext(ctx) {
- var currFeed ChannelSubscription
- err := common.GORM.Model(&ChannelSubscription{}).Where("id = ?", sub.ID).First(&currFeed)
+ updatedSub := ctx.Value(ContextKeySub).(*models.YoutubeChannelSubscription)
+ form := ctx.Value(common.ContextKeyParsedForm).(*YoutubeFeedForm)
+
+ updatedSub.MentionEveryone = form.MentionEveryone
+ updatedSub.MentionRoles = form.MentionRoles
+ updatedSub.PublishLivestream = form.PublishLivestream
+ updatedSub.PublishShorts = form.PublishShorts
+ updatedSub.ChannelID = discordgo.StrID(form.DiscordChannel)
+ updatedSub.Enabled = form.Enabled
+
+ numEnabled, _ := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.GuildID.EQ(discordgo.StrID(activeGuild.ID)),
+ models.YoutubeChannelSubscriptionWhere.Enabled.EQ(true),
+ ).CountG(ctx)
+ if int(numEnabled) >= MaxFeedsForContext(ctx) {
+ curSub, err := models.FindYoutubeChannelSubscriptionG(ctx, updatedSub.ID)
if err != nil {
- logger.WithError(err.Error).Errorf("Failed getting feed %d", sub.ID)
+ logger.WithError(err).Errorf("Failed getting feed %d", updatedSub.ID)
}
- if !*currFeed.Enabled && *sub.Enabled {
+ if !curSub.Enabled && updatedSub.Enabled {
return templateData.AddAlerts(web.ErrorAlert(fmt.Sprintf("Max %d enabled youtube feeds allowed (%d for premium servers)", GuildMaxFeeds, GuildMaxFeedsPremium))), nil
}
}
- err = common.GORM.Save(sub).Error
+ _, err = updatedSub.UpdateG(ctx, boil.Infer())
if err == nil {
- go cplogs.RetryAddEntry(web.NewLogEntryFromContext(r.Context(), panelLogKeyUpdatedFeed, &cplogs.Param{Type: cplogs.ParamTypeString, Value: sub.YoutubeChannelName}))
+ go cplogs.RetryAddEntry(web.NewLogEntryFromContext(r.Context(), panelLogKeyUpdatedFeed, &cplogs.Param{Type: cplogs.ParamTypeString, Value: updatedSub.YoutubeChannelName}))
}
- return
+ return templateData, err
}
func (p *Plugin) HandleRemove(w http.ResponseWriter, r *http.Request) (templateData web.TemplateData, err error) {
ctx := r.Context()
_, templateData = web.GetBaseCPContextData(ctx)
- sub := ctx.Value(ContextKeySub).(*ChannelSubscription)
- err = common.GORM.Delete(sub).Error
+ sub := ctx.Value(ContextKeySub).(*models.YoutubeChannelSubscription)
+ _, err = sub.DeleteG(ctx)
if err != nil {
return
}
@@ -349,13 +358,14 @@ func (p *Plugin) ValidateSubscription(w http.ResponseWriter, r *http.Request, qu
var _ web.PluginWithServerHomeWidget = (*Plugin)(nil)
func (p *Plugin) LoadServerHomeWidget(w http.ResponseWriter, r *http.Request) (web.TemplateData, error) {
- ag, templateData := web.GetBaseCPContextData(r.Context())
+ activeGuild, templateData := web.GetBaseCPContextData(r.Context())
templateData["WidgetTitle"] = "Youtube feeds"
templateData["SettingsPath"] = "/youtube"
- var numFeeds int64
- result := common.GORM.Model(&ChannelSubscription{}).Where("guild_id = ?", ag.ID).Count(&numFeeds)
+ numFeeds, err := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.GuildID.EQ(discordgo.StrID(activeGuild.ID)),
+ ).CountG(r.Context())
if numFeeds > 0 {
templateData["WidgetEnabled"] = true
} else {
@@ -365,5 +375,5 @@ func (p *Plugin) LoadServerHomeWidget(w http.ResponseWriter, r *http.Request) (w
const format = `Active Youtube feeds: %d
`
templateData["WidgetBody"] = template.HTML(fmt.Sprintf(format, numFeeds))
- return templateData, result.Error
+ return templateData, err
}
diff --git a/youtube/youtube.go b/youtube/youtube.go
index 3f7cd8afbb..c591cd9180 100644
--- a/youtube/youtube.go
+++ b/youtube/youtube.go
@@ -11,11 +11,14 @@ import (
"github.com/botlabs-gg/yagpdb/v2/common"
"github.com/botlabs-gg/yagpdb/v2/common/config"
"github.com/botlabs-gg/yagpdb/v2/common/mqueue"
+ "github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
"github.com/botlabs-gg/yagpdb/v2/premium"
- "github.com/lib/pq"
+ "github.com/botlabs-gg/yagpdb/v2/youtube/models"
"google.golang.org/api/youtube/v3"
)
+//go:generate sqlboiler --no-hooks psql
+
const (
RedisChannelsLockKey = "youtube_subbed_channel_lock"
RedisKeyPublishedVideoList = "youtube_published_videos"
@@ -49,8 +52,6 @@ func (p *Plugin) PluginInfo() *common.PluginInfo {
func RegisterPlugin() {
p := &Plugin{}
- common.GORM.AutoMigrate(ChannelSubscription{}, YoutubeAnnouncements{})
-
mqueue.RegisterSource("youtube", p)
err := p.SetupClient()
@@ -59,29 +60,8 @@ func RegisterPlugin() {
return
}
common.RegisterPlugin(p)
-}
-
-type ChannelSubscription struct {
- common.SmallModel
- GuildID string
- ChannelID string
- YoutubeChannelID string
- YoutubeChannelName string
- MentionEveryone bool
- MentionRoles pq.Int64Array `gorm:"type:bigint[]" valid:"role,true"`
- PublishLivestream *bool `sql:"DEFAULT:true"`
- PublishShorts *bool `sql:"DEFAULT:true"`
- Enabled *bool `sql:"DEFAULT:true"`
-}
-
-func (c *ChannelSubscription) TableName() string {
- return "youtube_channel_subscriptions"
-}
-type YoutubeAnnouncements struct {
- GuildID int64 `gorm:"primary_key" sql:"AUTO_INCREMENT:false"`
- Message string
- Enabled *bool `sql:"DEFAULT:false"`
+ common.InitSchemas("youtube", DBSchemas...)
}
var _ mqueue.PluginWithSourceDisabler = (*Plugin)(nil)
@@ -92,36 +72,38 @@ func (p *Plugin) DisableFeed(elem *mqueue.QueuedElement, err error) {
}
func (p *Plugin) DisableChannelFeeds(channelID int64) error {
- err := common.GORM.Model(&ChannelSubscription{}).Where("channel_id = ?", channelID).Updates(ChannelSubscription{Enabled: common.BoolToPointer(false)}).Error
+ numDisabled, err := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.ChannelID.EQ(discordgo.StrID(channelID)),
+ ).UpdateAllG(context.Background(), models.M{"enabled": false})
if err != nil {
- logger.WithError(err).Errorf("failed removing non-existant channel for channel_id %d", channelID)
+ logger.WithError(err).WithField("channel", channelID).Error("failed removing feeds in nonexistent channel")
return err
- } else {
- logger.WithField("channel", channelID).Info("Disabled youtube feed to non-existant channel")
}
+
+ logger.WithField("channel", channelID).Infof("disabled %d feeds in nonexistent channel", numDisabled)
return nil
}
func (p *Plugin) DisableGuildFeeds(guildID int64) error {
- err := common.GORM.Model(&ChannelSubscription{}).Where("guild_id = ?", guildID).Updates(ChannelSubscription{Enabled: common.BoolToPointer(false)}).Error
+ numDisabled, err := models.YoutubeChannelSubscriptions(
+ models.YoutubeChannelSubscriptionWhere.GuildID.EQ(discordgo.StrID(guildID)),
+ ).UpdateAllG(context.Background(), models.M{"enabled": false})
if err != nil {
- logger.WithError(err).Errorf("failed removing non-existant guild for guild_id %d", guildID)
+ logger.WithError(err).WithField("guild", guildID).Error("failed removing feeds in nonexistent guild")
return err
- } else {
- logger.WithField("guild", guildID).Info("Disabled youtube feed to non-existant guild")
}
+
+ logger.WithField("guild", guildID).Infof("disabled %d feeds in nonexistent guild", numDisabled)
return nil
}
func (p *Plugin) WebSubSubscribe(ytChannelID string) error {
-
values := url.Values{
"hub.callback": {"https://" + common.ConfHost.GetString() + "/yt_new_upload/" + confWebsubVerifytoken.GetString()},
"hub.topic": {"https://www.youtube.com/xml/feeds/videos.xml?channel_id=" + ytChannelID},
"hub.verify": {"sync"},
"hub.mode": {"subscribe"},
"hub.verify_token": {confWebsubVerifytoken.GetString()},
- // "hub.lease_seconds": {"60"},
}
resp, err := http.PostForm(GoogleWebsubHub, values)
@@ -132,16 +114,14 @@ func (p *Plugin) WebSubSubscribe(ytChannelID string) error {
if resp.StatusCode < 200 || resp.StatusCode > 299 {
body, _ := io.ReadAll(resp.Body)
- return fmt.Errorf("go bad status code: %d (%s) %s", resp.StatusCode, resp.Status, string(body))
+ return fmt.Errorf("bad status code: %d (%s) %s", resp.StatusCode, resp.Status, string(body))
}
logger.Info("Websub: Subscribed to channel ", ytChannelID)
-
return nil
}
func (p *Plugin) WebSubUnsubscribe(ytChannelID string) error {
-
values := url.Values{
"hub.callback": {"https://" + common.ConfHost.GetString() + "/yt_new_upload/" + confWebsubVerifytoken.GetString()},
"hub.topic": {"https://www.youtube.com/xml/feeds/videos.xml?channel_id=" + ytChannelID},
@@ -156,11 +136,10 @@ func (p *Plugin) WebSubUnsubscribe(ytChannelID string) error {
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
- return fmt.Errorf("go bad status code: %d (%s)", resp.StatusCode, resp.Status)
+ return fmt.Errorf("bad status code: %d (%s)", resp.StatusCode, resp.Status)
}
- logger.Info("Websub: UnSubscribed to channel ", ytChannelID)
-
+ logger.Info("Websub: Unsubscribed from channel ", ytChannelID)
return nil
}